Ejemplo n.º 1
0
 /// <summary>
 /// Constructor with all parameters.
 /// </summary>
 /// <param name="wpnName">Weapon Name</param>
 /// <param name="agentName">Agent Name</param>
 /// <param name="qkg">Fill weight in kilograms</param>
 /// <param name="ukts">Windspeed in knots</param>
 /// <param name="psc">Pasquill Stability Category</param>
 /// <param name="tst">Target Surface Type</param>
 public TotalDosagePattern(string wpnName, string agentName, double qkg, double ukts, PasquillStabilityCategory psc, TargetSurfaceType tst)
 {
     WeaponName = wpnName;
     AgentName  = agentName;
     Qkg        = qkg;
     UKts       = ukts;
     Psc        = psc;
     Tst        = tst;
     Tolerance  = .02;    // .02 mg.min/m3
     Patterns   = new List <DosageField>();
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Calculate total dosage given along-wind coordinates, windspeed, source strength, surface type and stability.
        /// </summary>
        /// <param name="x">Downwind distance from release in meters.</param>
        /// <param name="y">Crosswind distance from release in meters.</param>
        /// <param name="uKts">Wind speed in knots.</param>
        /// <param name="qKg">Source Strength of release in kilograms.</param>
        /// <param name="ts">Target surface type, Land or Sea</param>
        /// <param name="s">Pasquill stability category</param>
        /// <returns>Total Dosage value at x,y</returns>
        public static double TotalDosage(double x, double y, double uKts, double qKg, TargetSurfaceType ts, PasquillStabilityCategory s)
        {
            double windSpeedMetersPerSecond = uKts * KtsToMetersPerSecondFactor;
            double sourceStrengthMilligrams = qKg * KilogramsToMilligramsFactor;

            // the enum is zero-based, so add one
            double stabilityCategory = (int)s + 1;

            // set up constants from Suffield Memorandum No. 1275

            // Land constants first

            // Scalar used in calculation of instantaneous sigma y
            double F1Scalar = 0.2997 * Math.Exp(0.2621 * stabilityCategory);

            // exponent of downwind distance used in calculation of sigma y
            double F1Exponent = 0.89 - (.07 * stabilityCategory);

            // scalar used in calculation of instantaneous sizma z
            double GScalar = 0.1229 * Math.Exp(0.3295 * stabilityCategory);

            // exponent used in calculation of instantaneous sigma z
            double GExponent = 0.97 - (0.09 * stabilityCategory);

            // scalar used in calculation of meander sigma y
            double FMScalar;

            if (uKts < 10.0)
            {
                FMScalar = 1.577;
            }
            else
            {
                FMScalar = 1.130;
            }

            // exponent used in calculation of meander sigma y
            // same for land or sea
            double FMExponent = 0.7;

            double velocityDeposition = 0.004;

            // if we're at sea, set up the constants that change at sea
            if (ts == TargetSurfaceType.Sea)
            {
                F1Scalar   = 0.4570 * Math.Exp(-0.0863 * stabilityCategory);
                F1Exponent = 0.7;
                GScalar    = 0.9740 * Math.Exp(0.1750 * stabilityCategory);
                GExponent  = 0.68 - (0.06 * stabilityCategory);

                if (uKts < 10.0)
                {
                    FMScalar = 1.538;
                }
                else
                {
                    FMScalar = 1.038;
                }

                velocityDeposition = 0.003;
            }

            // calcualte standard deviations of plume
            double sigmaY_instantaneous = F1Scalar * Math.Pow(x, F1Exponent);

            double sigmaY_meander = FMScalar * Math.Pow(x, FMExponent);

            double sigmaY = Math.Sqrt(Math.Pow(sigmaY_instantaneous, 2) + Math.Pow(sigmaY_meander, 2));

            double sigmaZ = GScalar * Math.Pow(x, GExponent);

            // upper limit of error function integral
            double gamma = velocityDeposition * x / (Math.Sqrt(2) * windSpeedMetersPerSecond * GExponent * sigmaZ);

            double area = Gauss(0.0, gamma, 15);

            double erf = (2.0 / Math.Sqrt(Math.PI)) * area;

            double erfC = 1.0 - erf;

            double term1 = sourceStrengthMilligrams / (Math.PI * windSpeedMetersPerSecond * sigmaY * sigmaZ * 60.0);

            double term2 = Math.Exp(-Math.Pow(y, 2) / (2 * Math.Pow(sigmaY, 2)));

            double term3 = 1.0 - Math.Sqrt(Math.PI) * gamma * Math.Exp(Math.Pow(gamma, 2)) * erfC;

            double dosage = term1 * term2 * term3;

            return(dosage);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Computes the crosswind distance Y for a dosage threshold with tolerance.
        /// </summary>
        /// <param name="xDistance">Downwind distance of interest</param>
        /// <param name="qKg">Fill weight in kilograms</param>
        /// <param name="uKts">Windspeed in knots</param>
        /// <param name="endPointThreshold">Dosage of interest in mg.min/m^3</param>
        /// <param name="tolerance">Tolerance for bisection in mg.min/m^3</param>
        /// <param name="tst">Target Surface Type, Land or Sea</param>
        /// <param name="psc">Pasquill Stability Category</param>
        /// <returns>DosageValue object</returns>
        public DosageValue FindYLimitForDosage(double xDistance, double qKg, double uKts, double endPointThreshold, double tolerance,
                                               TargetSurfaceType tst, PasquillStabilityCategory psc)
        {
            // sanity check on tolerance
            if (tolerance <= 0)
            {
                tolerance = endPointThreshold / 20;
            }

            // set the tolerance limits, depending on what we were passed.
            _toleranceLowerLimit = endPointThreshold - tolerance;
            _toleranceUpperLimit = endPointThreshold + tolerance;

            DosageValue retVal = new DosageValue();

            // initialX and initialY are .Net Tuple types
            // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-tuples

            // set the initial Y at 1 meter
            var initialY = (distance : 1.0, dosage : 0.0);

            // twice that for limitY
            var limitY = (distance : initialY.distance * 2, dosage : 0.0);

            // the dosage at the initial distance
            initialY.dosage = Dosage.TotalDosage(xDistance, initialY.distance, uKts, qKg, tst, psc);

            // the dosage at the limit distance
            limitY.dosage = Dosage.TotalDosage(xDistance, limitY.distance, uKts, qKg, tst, psc);

            // adjust the limitX.distance until limitY.dosage drops below _toleranceLowerLimit
            while (limitY.dosage > _toleranceLowerLimit)
            {
                // move the initialY.distance up
                initialY.distance = limitY.distance;
                initialY.dosage   = limitY.dosage;

                // double the distance
                limitY.distance *= 2;   // double it

                // test it again
                limitY.dosage = Dosage.TotalDosage(xDistance, limitY.distance, uKts, qKg, tst, psc);
            }

            // we now have a condition where the distance we want is between the initialY.distance
            // and the limitY.distance

            double oldDistance;
            double oldDosage;

            // converge to a distance within tolerance limits
            while (!WithinToleranceLimits(initialY.dosage))
            {
                // save the initialY data
                oldDistance = initialY.distance;
                oldDosage   = initialY.dosage;

                // adjust and compute new dosage
                initialY.distance = (initialY.distance + limitY.distance) / 2;
                initialY.dosage   = Dosage.TotalDosage(xDistance, initialY.distance, uKts, qKg, tst, psc);

                if (BelowToleranceLimits(initialY.dosage))
                {
                    // we're too high, so adjust it down
                    limitY.distance = initialY.distance;
                    limitY.dosage   = initialY.dosage;

                    // restore the old numbers, a new initialY will be computed next pass
                    // using the new limitY.distance
                    initialY.distance = oldDistance;
                    initialY.dosage   = oldDosage;
                }
            }

            // set the return value if within tolerance limits
            if (WithinToleranceLimits(initialY.dosage))
            {
                retVal.Dosage  = initialY.dosage;
                retVal.XMeters = 0;
                retVal.YMeters = initialY.distance;
            }

            return(retVal);
        }