public EruptionValues(Eruption erupt, Wind[] wind, Config config) { Guard.NotNull(erupt, "erupt"); Guard.NotNull(wind, "wind"); Guard.NotNull(config, "config"); _config = config; SetEruptionValues(erupt, wind, config); }
private static void PrintWind(Wind[][] wind) { Console.WriteLine("Wind:"); Console.WriteLine("\tDays: " + wind.Length); for (var i = 0; i < wind.Length; i++) { Console.WriteLine("\t\tDay: " + i); Console.WriteLine("\t\tLevels: " + wind[i].Length); } }
private Wind[][] GetWindArray(Config config) { var winds = new Wind[config.WindDays][]; for (var i = 0; i < config.WindDays; i++) { winds[i] = new Wind[config.ColumnIntegrationSteps + 1]; for (var j = 0; j <= config.ColumnIntegrationSteps; j++) { winds[i][j] = new Wind(); } } return winds; }
// void set_eruption_values(ERUPTION *erupt, WIND *wind) { /* set_eruption_values */ private void SetEruptionValues(Eruption erupt, Wind[] wind, Config config) { //PART_STEPS = (erupt->max_phi - erupt->min_phi) * 10; PartSteps = (int)Math.Abs((erupt.MaxPhi - erupt.MinPhi) * 10); //threshold = erupt->vent_height + (PLUME_RATIO * (erupt->max_plume_height - erupt->vent_height)); Threshold = erupt.VentHeight + (config.Plume.Ratio * (erupt.MaxPlumeHeight - erupt.VentHeight)); //SQRT_TWO_PI = sqrt(2.0 * pi); /* new line, 12-2-2010 */ SqrtTwoPi = Math.Sqrt(2.0 * Config.Pi); //BETA_x_SQRT_TWO_PI = erupt->column_beta * SQRT_TWO_PI; BetaSqrtTwoPi = erupt.ColumnBeta * SqrtTwoPi; //TWO_BETA_SQRD = 2.0 * erupt->column_beta * erupt->column_beta; TwoBetaSqrd = 2.0 * erupt.ColumnBeta * erupt.ColumnBeta; //PDF_GRAINSIZE_DEMON1 = 1.0 / (2.506628 * erupt->sigma_phi); /* changed 12-02-2010 */ PdfGrainSizeDemon1 = 1.0 / (2.506628 * erupt.SigmaPhi); //TWO_x_PART_SIGMA_SIZE = 2.0 * erupt->sigma_phi * erupt->sigma_phi; TwoPartSigmaSize = 2.0 * erupt.SigmaPhi * erupt.SigmaPhi; /*define the limits of integration */ //ht_section_width = erupt->max_plume_height - erupt->vent_height; var htSectionWidth = erupt.MaxPlumeHeight - erupt.VentHeight; //part_section_width = erupt->max_phi - erupt->min_phi; var partSectionWidth = erupt.MaxPhi - erupt.MinPhi; //ht_step_width = ht_section_width / (double)COL_STEPS; var htStepWidth = htSectionWidth / config.ColumnIntegrationSteps; //part_step_width = part_section_width / (double)PART_STEPS; var partStepWidth = partSectionWidth / PartSteps; /* steps for nomalization of probabilities */ var totalPCol = GetTotalPCol(erupt, config, htSectionWidth, htStepWidth); var totalPPart = GetTotalPPart(erupt, partStepWidth); /* Normalization constant */ var totalP = GetTotalP(totalPCol, totalPPart); /* End of normalization steps */ /* Dynamically allocated table for storing integration data. * Used in the double integration steps below for each point considered. * */ _table = CreateTableArray(); double pmin = 10e6, pmax = 0.0; Logger.InfoFormat("\tpmax={0}", pmax); Logger.InfoFormat("\tpmin={0}", pmin); /* Start with the maximum particle size */ //y = (erupt)->min_phi var y = erupt.MinPhi; for (var i = 0; i < PartSteps; i++) { /* PART_STEPS_LOOP */ var partStepTable = _table[i, 0]; //T[i][0].part_density = ParticleDensity(y); partStepTable.SetPartDensity(ParticleDensity(y)); //T[i][0].ashdiam = phi2m(y); partStepTable.SetAshDiam(Phi2M(y)); /* the expected fraction of particles of this size based on given mean and std deviation */ var partProb = pdf_grainsize(erupt.MeanPhi, y, partStepWidth); var cumFallTime = 0.0; var windX = 0.0; var windY = 0.0; /* Start at the height of the vent */ var particleHt = erupt.VentHeight; for (var j = 0; j < config.ColumnIntegrationSteps; j++) { /* COL_STEPS_LOOP */ var table = _table[i, j]; /* define the small slice dz */ particleHt += htStepWidth; /* * Calculate the time it takes a particle to fall from its release point * in the column to the next column release point. * */ //T[i][j].fall_time = PartFallTime(particle_ht, ht_step_width, T[i][0].ashdiam, T[i][0].part_density); table.SetFallTime(PartFallTime(particleHt, htStepWidth, partStepTable.GetAshDiam(), partStepTable.GetPartDensity())); /* Particle diffusion time (seconds) */ //ht_above_vent = particle_ht - erupt->vent_height; var htAboveVent = particleHt - erupt.VentHeight; var temp = 0.2 * htAboveVent * htAboveVent; //T[i][j].plume_diffusion_fine_particle = pow(temp, 0.4); /* 0.4 = 2.0/5.0 */ table.SetPlumeDiffusionFineParticle(Math.Pow(temp, 0.4)); //T[i][j].plume_diffusion_coarse_particle = 0.0032 * (ht_above_vent * ht_above_vent) / DIFFUSION_COEFFICIENT; table.SetPlumeDiffusionCoarseParticle(0.0032 * (htAboveVent * htAboveVent) / config.DiffusionCoefficient); /* * Sum the windspeed and wind_direction for each particle size * falling from each level. In the wind array, the first wind level * gives wind speed and direction at the vent height. * Start with the next wind level, * so that we are using the wind speed and direction * starting from one step above the vent. * */ var windNextLevel = wind[j + 1]; //wind_x += T[i][j].fall_time * wind[j+1].windspeed * cos(wind[j+1].wind_dir); windX += table.GetFallTime() * windNextLevel.GetWindSpeed() * Math.Cos(windNextLevel.GetWindDir()); //wind_y += T[i][j].fall_time * wind[j+1].windspeed * sin(wind[j+1].wind_dir); windY += table.GetFallTime() * windNextLevel.GetWindSpeed() * Math.Sin(windNextLevel.GetWindDir()); //T[i][j].wind_sum_x = wind_x; table.SetWindSumX(windX); //T[i][j].wind_sum_y = wind_y; table.SetWindSumY(windY); /* * Accumulate the time it takes each particle size to descend * from its release point down * to its final resting place.This part of the code just * calculates the fall_time from the release point to the * height of the vent. * The time it takes a particle to fall from the vent height * to a grid cell will be calculated later. * */ //cum_fall_time += T[i][j].fall_time; cumFallTime += table.GetFallTime(); //T[i][j].total_fall_time = cum_fall_time; table.SetTotalFallTime(cumFallTime); //if (T[i][j].total_fall_time > pmax) pmax = T[i][j].total_fall_time; if (cumFallTime > pmax) { pmax = table.GetTotalFallTime(); } else //if (T[i][j].total_fall_time < pmin) pmin = T[i][j].total_fall_time; if (cumFallTime < pmin) { pmin = table.GetTotalFallTime(); } /* the probability that a given grainsize will be released from a given height */ //col_prob = (*pdf)(particle_ht, j, erupt->column_beta, erupt->max_plume_height); var colProb = config.Plume.PlumeModel == PlumeModel.UniformDistribution ? plume_pdf0(particleHt, j) : PlumePdf1(particleHt, j, erupt.ColumnBeta, erupt.MaxPlumeHeight); /* Normalization is now done here */ //T[i][j].demon1 = (erupt->total_ash_mass * col_prob * part_prob)/total_P; table.SetDemon1((erupt.TotalAshMass * colProb * partProb) / totalP); //T[i][j].particle_ht = particle_ht; table.SetParticleHt(particleHt); Logger.InfoFormat("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}\t{11}", new[] { i, j, table.GetParticleHt(), table.GetAshDiam(), table.GetPartDensity(), table.GetFallTime(), table.GetPlumeDiffusionFineParticle(), table.GetPlumeDiffusionCoarseParticle(), table.GetTotalFallTime(), table.GetWindSumX(), table.GetWindSumY(), table.GetDemon1() }); /* fprintf(log_file, "%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\n", T[i][j].particle_ht, T[i][j].ashdiam, T[i][j].part_density, T[i][j].fall_time, T[i][j].plume_diffusion_fine_particle, T[i][j].plume_diffusion_coarse_particle, T[i][j].total_fall_time, T[i][j].wind_sum_x, T[i][j].wind_sum_y, T[i][j].demon1); */ } /* END COL_STEPS_LOOP */ Logger.Info(" "); /* fprintf(log_file, "\n"); */ y += partStepWidth; /* moved from beg of loop 12-02-2010 */ } /* END PART_STEPS_LOOP */ /* fprintf(log_file, "OUT\n"); */ // fprintf(stderr, "MIN particle fall time = %.1f\n", pmin); Logger.Info("MIN particle fall time = " + pmin); // fprintf(stderr, "MAX particle fall time = %.1f\n", pmax); Logger.Info("MAX particle fall time = " + pmax); }
/* * --------------------------------------------------------------------- * FUNCTION:tephra_calc.c * * Purpose: This function calculates and returns the expected accumulation * of volcanic ash (kg/m2) at a specific geogrphic location (x,y) due to an * eruption with specific input parameters. These points may be random or on * a UTM grid (m) * * This implementation accounts for variation in wind velocity with height. * The model is discretized w.r.t. height and particle size. * * This function is called for each point (x,y,) If more than one eruption * is involved, for example in a probabilistic analysis, the function is * called for each set of eruption parameters. * * INPUTS: ERUPTION *erupt: pointer to array of eruption parameters POINT * *pt: pointer to an array of location specific parameters, WIND *level: * pointer to a day of wind data : height asl in m; wind speed in ms-1 wind * direction in degrees N * * OUTPUTs: the value of the mass accumulated at the input location * (northing, easting) in kg/m2 * * a distribution of particle sizes the exact number of binss (i.e. sizes) * and phi size used per bin is an integer and is determined by * (erupt->max_phi - erupt->min_phi) each bin accumulates phi sizes up to * its integer size ex. bin[0] holds grainsizes [min_phi to min_phi+1) * ************************************************************************* */ //void tephra_calc(ERUPTION *erupt, POINT *pt, WIND *level, STATS *stats) { /* tephra_calc starts ... */ // TODO : I have added EruptionValues, could replace Eruption with EruptionValues only? public void Calculate(Eruption erupt, Point pt, Wind[] level, Stats stats, EruptionValues eruptionValues) { //logger.info("IN tephra_calc ..."); /* Initialize mass to zero */ pt.SetMass(0.0); //wind_sum_x = 0.0; //wind_sum_y = 0.0; /* Transform the volcano location coordinate to 0,0 */ var newXspace = pt.GetNorthing() - erupt.VolcanoNorthing; var newYspace = pt.GetEasting() - erupt.VolcanoEasting; /* Interpolate to find the wind speed and direction below the height of the vent. * Find one average wind speed and wind direction between vent and grid elevation point. * The first values in the wind array give the wind speed and direction at the * vent height. * */ var layer = erupt.VentHeight - pt.GetElevation(); var windspeed = (level[0].GetWindSpeed() * pt.GetElevation()) / erupt.VentHeight; var cosWind = Math.Cos(level[0].GetWindDir()) * windspeed; var sinWind = Math.Sin(level[0].GetWindDir()) * windspeed; var bin = -1; double min = 10e6, max = 0.0; //logger.info("Beginning integration loops ..."); //for (i = 0; i < PART_STEPS; i++) { /* PART_STEPS_LOOP */ for (var i = 0; i < eruptionValues.PartSteps; i++) { /* PART_STEPS_LOOP */ //fall_time_adj = 0.0; var fallTimeAdj = 0.0; /* Accumulate the particle sizes into bins of whole numbered phi sizes */ //if (!(i % 10)) { if ((i % 10) == 0) { bin++; //fprintf(log_file, "PART_STEP=%d phi[%d] = %g\n", i, bin, pt->phi[bin]); //logger.debug("PART_STEP=" + i + " phi[" + bin + "] = " + pt.getPhi()[bin]); } /* * Modify the total fall time of each particle size (i) * by the time that it takes particle size (i) to descend from vent height to the grid cell. * This is only necessary when the elevation of the grid cell < elevation of the vent. * */ if (layer > 0) { //fall_time_adj = PartFallTime(erupt->vent_height, layer, T[i][0].ashdiam, T[i][0].part_density); fallTimeAdj = eruptionValues.PartFallTime(erupt.VentHeight, layer, eruptionValues.GetT()[i, 0].GetAshDiam(), eruptionValues.GetT()[i, 0].GetPartDensity()); //fprintf(log_file, "%d %g %g\n", i, layer, fall_time_adj) ; //logger.debug("\tS=" + i + " layer=" + layer + " fall_time_adj=" + fall_time_adj); } //for (j = 0; j < COL_STEPS; j++) { /* COL_STEPS_LOOP */ for (var j = 0; j < _config.ColumnIntegrationSteps; j++) { /* COL_STEPS_LOOP */ //total_fall_time = T[i][j].total_fall_time + fall_time_adj; var totalFallTime = eruptionValues.GetT()[i, j].GetTotalFallTime() + fallTimeAdj; //logger.debug("\tS=" + i + ","+ j + " total_fall_time=" + total_fall_time); // fprintf(stderr, "%g %g %g ", T[i][j].total_fall_time, total_fall_time, fall_time_adj); //logger.debug("\tPART_STEP=" + i + " layer=" + layer + " fall_time_adj=" + fall_time_adj); /* Sum the adjustments (windspeed and wind_direction) * for each particle size falling from each level. */ /* removed 2 lines, 12-2-2010 wind_sum_x = cos_wind * fall_time_adj * windspeed; wind_sum_y = sin_wind * fall_time_adj * windspeed; */ /* change 2 lines, 12-2-2010 */ var windSumX = cosWind * fallTimeAdj; var windSumY = sinWind * fallTimeAdj; //logger.debug("\tPART_STEP=" + i + " wind_sum_x=" + wind_sum_x + " wind_sum_y=" + wind_sum_y); /* Now add the summed adjustments to the already summed * windspeeds and directions * and * Account for the wind: * Find the average windspeed in the x and y directions * over the total fall time. * */ //average_windspeed_x = (T[i][j].wind_sum_x + wind_sum_x)/total_fall_time; var averageWindspeedX = (eruptionValues.GetT()[i, j].GetWindSumX() + windSumX) / totalFallTime; //average_windspeed_y = (T[i][j].wind_sum_y + wind_sum_y)/total_fall_time; var averageWindspeedY = (eruptionValues.GetT()[i, j].GetWindSumY() + windSumY) / totalFallTime; /* If zero, make windspeed a very small value (cannot divide by zero in next step) */ //if (!average_windspeed_x) average_windspeed_x = .001; if (averageWindspeedX == 0) averageWindspeedX = .001; //if (!average_windspeed_y) average_windspeed_y = .001; if (averageWindspeedY == 0) averageWindspeedY = .001; double averageWindDirection; /* Find the average wind direction (direction of the velocity vector) */ if (averageWindspeedX < 0) { //average_wind_direction = atan(average_windspeed_y/average_windspeed_x ) + pi; averageWindDirection = Math.Atan(averageWindspeedY / averageWindspeedX) + Config.Pi; } else { //average_wind_direction = atan(average_windspeed_y/average_windspeed_x); averageWindDirection = Math.Atan(averageWindspeedY / averageWindspeedX); } //logger.debug("\tPART_STEP=" + i + " average_wind_direction=" + average_wind_direction); /* Find the average windspeed ( magnitude of the velocity vector) */ //average_windspeed = sqrt(average_windspeed_x*average_windspeed_x + average_windspeed_y*average_windspeed_y); var averageWindspeed = Math.Sqrt(averageWindspeedX * averageWindspeedX + averageWindspeedY * averageWindspeedY); //logger.debug("\tPART_STEP=" + i + " average_windspeed=" + average_windspeed); if (totalFallTime > max) max = totalFallTime; if (totalFallTime < min) min = totalFallTime; /* calculate the value of sigma (dispersion) based on total_fall_time * to acct for the change in the shape of the column with ht - increasing radius */ //ht_above_vent = T[i][j].particle_ht - erupt->vent_height; //double ht_above_vent = eruptionValues.getT()[i][j].getParticleHt() - erupt.getVentHeight(); double sigma; /* falltime for fine particles */ //if (total_fall_time >= FALL_TIME_THRESHOLD) { if (totalFallTime >= _config.FallTimeThreshold) { //sigma = EDDY_CONST_x_8_div_5 * pow((total_fall_time + T[i][j].plume_diffusion_fine_particle), 2.5); sigma = (8.0 * _config.EddyDiff / 5.0) * Math.Pow((totalFallTime + eruptionValues.GetT()[i, j].GetPlumeDiffusionFineParticle()), 2.5); //fprintf(stderr,"f"); } else { /* falltime for coarse particles */ //sigma = 4.0 * DIFFUSION_COEFFICIENT * (total_fall_time + T[i][j].plume_diffusion_coarse_particle); sigma = 4.0 * _config.DiffusionCoefficient * (totalFallTime + eruptionValues.GetT()[i, j].GetPlumeDiffusionCoarseParticle()); //fprintf(stderr, "c"); } var demon2 = Config.Pi * sigma; /* Modify fall time by the variation of wind velocity with height */ // demon3 = // strat_average( average_wind_direction, // average_windspeed, // new_xspace, new_yspace, // total_fall_time, // sigma); var demon3 = strat_average(averageWindDirection, averageWindspeed, newXspace, newYspace, totalFallTime, sigma); /* if (!demon2 || isnan(demon2) || isinf(demon2) || isnan(demon3) || isinf(demon3)) { fprintf(stderr, "[%d][%d] layer= %.1f totalfalltime=%g [falltimeadj=%g] demon1=%g demon2=%g demon3=%g sigma=%g\n", i,j, layer,total_fall_time, fall_time_adj, T[i][j].demon1, demon2, demon3, sigma); exit(-1); } */ //ash_fall = (T[i][j].demon1 / demon2) * demon3; var ashFall = (eruptionValues.GetT()[i, j].GetDemon1() / demon2) * demon3; //pt->mass += ash_fall; pt.SetMass(pt.GetMass() + ashFall); //pt->phi[bin] += ash_fall; pt.GetPhi()[bin] += ashFall; //fprintf(stderr, "\n"); //logger.debug("\tS=" + i + ", " + j + " layer=" + layer + "d1=" + eruptionValues.getT()[i][j].getDemon1() + " d2=" + demon2 + " d3=" + demon3 + " sigma=" + sigma + " ash_fall=" + ash_fall); } //logger.debug("S=" + i + " mass=" + pt.getMass() + " phi[" + bin + "]=" + pt.getPhi()[bin]); } // #ifdef _PRINT // fprintf(log_file, "PART_STEP=%d phi[%d] = %g\n", i, bin, pt->phi[bin]); // fprintf(log_file, "OUT\n"); // #endif //stats->min_falltime = min; stats.SetMinFallTime(min); //stats->max_falltime = max; stats.SetMaxFallTime(max); }