Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        public void Main(
            [Aliases("c")]
            [Description("Configuration File")]
            [DefaultValue(@".\Samples\CerroNegro.conf")]
            [Required]
            string configFileName,
            [Aliases("p")]
            [Description("Point File")]
            [DefaultValue(@".\Samples\CerroNegro.pos")]
            [Required]
            string pointFileName,
            [Aliases("w")]
            [Description("Wind File")]
            [DefaultValue(@".\Samples\CerroNegro.wind")]
            [Required]
            string windFileName)
        {
            _configFileInfo = new FileInfo(configFileName);
            _pointFileInfo = new FileInfo(pointFileName);
            _windFileInfo = new FileInfo(windFileName);

            var config = getConfiguration();
            PrintConfig(config);
            var points = GetPoints(_pointFileInfo);
            PrintPoints(points);
            var wind = GetWind(config, _windFileInfo);
            PrintWind(wind);

            var eruption = new Eruption(config);
            PrintEruption(eruption);

            var eruptionValues = new EruptionValues(eruption, wind[0], config);

            /* Calculating an accumulation map */
            var calc = new TephraCalc(config);

            //for (i = 0;i < local_n; i++) {  /* For each location */
            for (var i = 0; i < points.Length; i++)
            {  /* For each location */
               //  /* Note: W[j]  means that if there are multiple eruptions, 
               //  there should be multiple WIND_DAYS in the wind.in file, 
               //  1 WIND_DAY for each eruption line */
               //  tephra_calc(erupt+j, pt+i, W[j], &stats);
                Logger.InfoFormat("points[{0} of {1}] ...", i, points.Length);
                var stats = new Stats(); // TODO : There seems no point to this object!!
                var pt = points[i];
                calc.Calculate(eruption, pt, wind[0], stats, eruptionValues);
                //  (pt+i)->cum_mass += (pt+i)->mass;
                pt.SetAccumulateMass(pt.GetAccumulateMass() + pt.GetMass());
                //}
            }
            CreateResultFile(eruption, points);
        }
 public void TestInitialize()
 {
     _eruption = new Eruption(Config);
 }
Esempio n. 4
0
        private static void CreateResultFile(Eruption eruption, Point[] points)
        {
            /* Here I am assuming that each eruptive senario has the same min and max particle size range
               So, the grainsize distribution contains the same number of bins. The amount in each bin accumulates
               between eruptive senarios.
            */
            try
            {
                var outFile = new FileInfo("tephra2_output.txt");
                if (outFile.Exists)
                {
                    outFile.Delete();
                }
                //PrintWriter output = new PrintWriter(new BufferedWriter(new FileWriter(outFile, true)));
                using (var output = outFile.CreateText())
                {
                    //phi_bins = (int)((erupt+j)->max_phi - (erupt+j)->min_phi);
                    var phiBins = (int)(eruption.MaxPhi - eruption.MinPhi);
                    //fprintf(stdout, "#Easting Northing Elev. Mass/Area  ");
                    Console.Write("#Easting Northing Elev. Mass/Area  ");
                    output.Write("#Easting Northing Elev. Mass/Area  ");
                    //for (bin = 0; bin < phi_bins; bin++) 
                    for (var bin = 0; bin < phiBins; bin++)
                    {
                        //  fprintf(stdout,"[%d->%d) ", 
                        //	(int)((erupt+j)->min_phi)+bin, 
                        //	(int)((erupt+j)->min_phi)+bin+1);
                        Console.Write("[" + ((int)(eruption.MinPhi) + bin) + "->" + ((int)(eruption.MinPhi) + bin + 1) + ") ");
                        output.Write("[" + ((int)(eruption.MinPhi) + bin) + "->" + ((int)(eruption.MinPhi) + bin + 1) + ") ");
                    }
                    //fprintf(stdout,"\n");
                    Console.WriteLine();
                    output.WriteLine();

                    //
                    ////		fprintf(stderr, "\nPART_STEPS=%d phi_bins=%d\n", PART_STEPS, phi_bins);
                    //for (i=0; i < num_pts; i++) {
                    foreach (var pt in points)
                    {
                        //  fprintf(stdout, "%.0f %.0f %.0f %.2g  ", 
                        //	(pt+i)->easting, 				
                        Console.Write("{0:0}", pt.GetEasting());
                        output.Write("{0:0}", pt.GetEasting());
                        Console.Write(" ");
                        output.Write(" ");
                        //	(pt+i)->northing,
                        Console.Write("{0:0}", pt.GetNorthing());
                        output.Write("{0:0}", pt.GetNorthing());
                        Console.Write(" ");
                        output.Write(" ");
                        //	(pt+i)->elevation, 
                        Console.Write("{0:0}", pt.GetElevation());
                        output.Write("{0:0}", pt.GetElevation());
                        Console.Write(" ");
                        output.Write(" ");
                        //	(pt+i)->cum_mass);
                        Console.Write("{0:G2}", pt.GetAccumulateMass());
                        output.Write("{0:G2}", pt.GetAccumulateMass());
                        Console.Write(" ");
                        output.Write(" ");
                        //  for (bin=0; bin < phi_bins; bin++) {
                        for (var bin = 0; bin < phiBins; bin++)
                        {
                            //  	val = ((pt+i)->phi[bin]/(pt+i)->cum_mass) * 100.0;
                            var val = (pt.GetPhi()[bin] / pt.GetAccumulateMass()) * 100.0;
                            //    fprintf(stdout, "%.2g ", val);
                            if (val == 0)
                            {
                                Console.Write("0.0");
                                output.Write("0.0");
                            }
                            else
                            {
                                Console.Write("{0:G2}", val);
                                output.Write("{0:G2}", val);
                            }
                            Console.Write(" ");
                            output.Write(" ");
                            //  }
                        }
                        //  fprintf(stdout, "\n");
                        Console.WriteLine();
                        output.WriteLine();
                    }
                }
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                //e.printStackTrace();
                Logger.Error("Error generating output file", e);
            }
        }
Esempio n. 5
0
 private static void PrintEruption(Eruption eruption)
 {
     Console.WriteLine("Eruption:");
     Console.WriteLine("\tVolcanoEasting: " + eruption.VolcanoEasting);
     Console.WriteLine("\tVolcanoNorthing: " + eruption.VolcanoNorthing);
     Console.WriteLine("\tTotalAshMass: " + eruption.TotalAshMass);
     Console.WriteLine("\tMinPhi: " + eruption.MinPhi);
     Console.WriteLine("\tMaxPhi: " + eruption.MaxPhi);
     Console.WriteLine("\tMeanPhi: " + eruption.MeanPhi);
     Console.WriteLine("\tSigmaPhi: " + eruption.SigmaPhi);
     Console.WriteLine("\tVentHeight: " + eruption.VentHeight);
     Console.WriteLine("\tMaxPlumeHeight: " + eruption.MaxPlumeHeight);
 }
        public static void ClassInitialize(TestContext ctx) 
        {
            _eruption = new Eruption(Config);

            _eruptionValues = new EruptionValues(_eruption, Wind[0], Config);
        }
Esempio n. 7
0
        // 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);
        }
Esempio n. 8
0
        public double GetTotalPCol(Eruption erupt, Config config, double htSectionWidth, double htStepWidth)
        {
            var cumProbCol = 0.0;
            //x = erupt->vent_height;
            var x = erupt.VentHeight;

            //for (i=0; i < COL_STEPS; i++) {
            for (var i = 0; i < config.ColumnIntegrationSteps; i++)
            {
                x += htStepWidth;
                double prob;
                //prob = (*pdf)(x, (double)i, ht_section_width, erupt->max_plume_height);
                if (config.Plume.PlumeModel == PlumeModel.UniformDistribution)
                {
                    prob = plume_pdf0(x, i);
                }
                else {
                    // TODO : I can't see how this can be used anywhere as beta is never set!
                    // TwoBetaSqrd & BetaSqrtTwoPi is not valid as beta is always 0.
                    Debug.Assert(Math.Abs(TwoBetaSqrd) > 0.0000001 || Math.Abs(BetaSqrtTwoPi) > 0.0000001);
                    prob = PlumePdf1(x, i, htSectionWidth, erupt.MaxPlumeHeight);
                }
                cumProbCol += prob;
            }
            return cumProbCol;
        }
Esempio n. 9
0
 public double GetTotalPPart(Eruption erupt, double partStepWidth)
 {
     var cumProbPart = 0.0;
     var y = erupt.MinPhi;
     for (var i = 0; i < PartSteps; i++)
     {
         var prob = pdf_grainsize(erupt.MeanPhi, y, partStepWidth);
         cumProbPart += prob;
         //fprintf(log_file, " grain_size=%g, prob=%g, cum_prob=%g\n", y, prob, cum_prob_part);
         //logger.debug(" grain_size={}, prob={}, cum_prob_part={}", new Object[] {y, prob, cum_prob_part});
         y += partStepWidth;
     }
     return cumProbPart;
 }
Esempio n. 10
0
        /*
         * ---------------------------------------------------------------------
         * 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);
        }