Ejemplo n.º 1
0
        /// <summary>Relatives the allocation.</summary>
        /// <param name="Organs">The organs.</param>
        /// <param name="TotalSupply">The total supply.</param>
        /// <param name="TotalAllocated">The total allocated.</param>
        /// <param name="BAT">The bat.</param>
        public void DoAllocation(IArbitration[] Organs, double TotalSupply, ref double TotalAllocated, BiomassArbitrationType BAT)
        {
            double NotAllocated = TotalSupply;

            ////allocate to all pools based on their relative demands
            for (int i = 0; i < Organs.Length; i++)
            {
                double StructuralRequirement = Math.Max(0, BAT.StructuralDemand[i] - BAT.StructuralAllocation[i]); //N needed to get to Minimum N conc and satisfy structural and metabolic N demands
                double MetabolicRequirement  = Math.Max(0, BAT.MetabolicDemand[i] - BAT.MetabolicAllocation[i]);
                double StorageRequirement    = Math.Max(0, BAT.StorageDemand[i] - BAT.StorageAllocation[i]);
                if ((StructuralRequirement + MetabolicRequirement + StorageRequirement) > 0.0)
                {
                    double StructuralAllocation = Math.Min(StructuralRequirement, TotalSupply * MathUtilities.Divide(BAT.StructuralDemand[i], BAT.TotalPlantDemand, 0));
                    double MetabolicAllocation  = Math.Min(MetabolicRequirement, TotalSupply * MathUtilities.Divide(BAT.MetabolicDemand[i], BAT.TotalPlantDemand, 0));
                    double StorageAllocation    = Math.Min(StorageRequirement, TotalSupply * MathUtilities.Divide(BAT.StorageDemand[i], BAT.TotalPlantDemand, 0));

                    BAT.StructuralAllocation[i] += StructuralAllocation;
                    BAT.MetabolicAllocation[i]  += MetabolicAllocation;
                    BAT.StorageAllocation[i]    += StorageAllocation;
                    NotAllocated   -= (StructuralAllocation + MetabolicAllocation + StorageAllocation);
                    TotalAllocated += (StructuralAllocation + MetabolicAllocation + StorageAllocation);
                }
            }
        }
Ejemplo n.º 2
0
        private void ExportAnimationGroups(GLTF gltf, BabylonScene babylonScene)
        {
            // Retreive and parse animation group data
            var animationGroupList  = babylonScene.animationGroups;
            var animationGroupCount = animationGroupList == null ? 0 : animationGroupList.Count;

            gltf.AnimationsList.Clear();
            gltf.AnimationsList.Capacity = Math.Max(gltf.AnimationsList.Capacity, animationGroupCount);

            if (animationGroupCount <= 0)
            {
                logger.RaiseMessage("GLTFExporter.Animation | No AnimationGroups: exporting all animations together.", 1);
                GLTFAnimation gltfAnimation = new GLTFAnimation();
                gltfAnimation.name = "All Animations";

                int startFrame = babylonScene.TimelineStartFrame;
                int endFrame   = babylonScene.TimelineEndFrame;

                foreach (var pair in nodeToGltfNodeMap)
                {
                    BabylonNode node                             = pair.Key;
                    GLTFNode    gltfNode                         = pair.Value;
                    bool        nodeHasAnimations                = node.animations != null && node.animations.Length > 0 && node.animations[0] != null;
                    bool        nodeHasExtraAnimations           = node.extraAnimations != null && node.extraAnimations.Count > 0 && node.extraAnimations[0] != null;
                    BabylonMesh meshNode                         = node as BabylonMesh;
                    BabylonMorphTargetManager morphTargetManager = null;
                    bool nodeHasAnimatedMorphTargets             = false;
                    if (meshNode != null && meshNode.morphTargetManagerId != null)
                    {
                        morphTargetManager = GetBabylonMorphTargetManager(babylonScene, meshNode);
                        if (morphTargetManager != null)
                        {
                            nodeHasAnimatedMorphTargets = morphTargetManager.targets.Any(target => target.animations != null && target.animations.Length > 0 && target.animations[0] != null);
                        }
                    }

                    if (!nodeHasAnimations && !nodeHasExtraAnimations && !nodeHasAnimatedMorphTargets)
                    {
                        continue;
                    }
                    if (nodeHasAnimations && node.animations[0].property == "_matrix")
                    {
                        ExportBoneAnimation(gltfAnimation, startFrame, endFrame, gltf, node, pair.Value);
                    }
                    else
                    {
                        ExportNodeAnimation(gltfAnimation, startFrame, endFrame, gltf, node, gltfNode, babylonScene);
                    }

                    if (nodeHasAnimatedMorphTargets)
                    {
                        ExportMorphTargetWeightAnimation(morphTargetManager, gltf, gltfNode, gltfAnimation.ChannelList, gltfAnimation.SamplerList, startFrame, endFrame, babylonScene);
                    }
                }

                if (gltfAnimation.ChannelList.Count > 0)
                {
                    gltf.AnimationsList.Add(gltfAnimation);
                }
                else
                {
                    logger.RaiseMessage("GLTFExporter.Animation | No animation data for this animation, it is ignored.", 2);
                }
            }
            else
            {
                foreach (BabylonAnimationGroup animGroup in animationGroupList)
                {
                    logger.RaiseMessage("GLTFExporter.Animation | " + animGroup.name, 1);

                    GLTFAnimation gltfAnimation = new GLTFAnimation();
                    gltfAnimation.name = animGroup.name;

                    int startFrame = MathUtilities.RoundToInt(animGroup.from);
                    int endFrame   = MathUtilities.RoundToInt(animGroup.to);

                    var uniqueNodeIds = animGroup.targetedAnimations.Select(targetAnim => targetAnim.targetId).Distinct();
                    foreach (var id in uniqueNodeIds)
                    {
                        BabylonNode babylonNode = babylonNodes.Find(node => node.id.Equals(id));
                        GLTFNode    gltfNode    = null;
                        // search the babylon scene id map for the babylon node that matches this id
                        if (babylonNode != null)
                        {
                            BabylonMorphTargetManager morphTargetManager = null;

                            // search our babylon->gltf node mapping to see if this node is included in the exported gltf scene
                            if (!nodeToGltfNodeMap.TryGetValue(babylonNode, out gltfNode))
                            {
                                continue;
                            }

                            bool nodeHasAnimations      = babylonNode.animations != null && babylonNode.animations.Length > 0 && babylonNode.animations[0] != null;
                            bool nodeHasExtraAnimations = babylonNode.extraAnimations != null && babylonNode.extraAnimations.Count > 0 && babylonNode.extraAnimations[0] != null;
                            if (!nodeHasAnimations && !nodeHasExtraAnimations)
                            {
                                continue;
                            }

                            if (nodeHasAnimations && babylonNode.animations[0].property == "_matrix") //TODO: Is this check accurate for deciphering between bones and nodes?
                            {
                                ExportBoneAnimation(gltfAnimation, startFrame, endFrame, gltf, babylonNode, gltfNode);
                            }
                            else
                            {
                                ExportNodeAnimation(gltfAnimation, startFrame, endFrame, gltf, babylonNode, gltfNode, babylonScene);
                            }
                        }
                        else
                        {
                            // if the node isn't found in the scene id map, check if it is the id for a morph target
                            BabylonMorphTargetManager morphTargetManager = babylonScene.morphTargetManagers.FirstOrDefault(mtm => mtm.targets.Any(target => target.animations != null && target.animations.Length > 0 && target.animations[0] != null));
                            if (morphTargetManager != null)
                            {
                                BabylonMesh mesh = morphTargetManager.sourceMesh;
                                if (mesh != null && nodeToGltfNodeMap.TryGetValue(mesh, out gltfNode))
                                {
                                    ExportMorphTargetWeightAnimation(morphTargetManager, gltf, gltfNode, gltfAnimation.ChannelList, gltfAnimation.SamplerList, startFrame, endFrame, babylonScene);
                                }
                            }
                        }
                    }

                    if (gltfAnimation.ChannelList.Count > 0)
                    {
                        gltf.AnimationsList.Add(gltfAnimation);
                    }
                    else
                    {
                        logger.RaiseMessage("No data exported for this animation, it is ignored.", 2);
                    }
                    // clear the exported morph target cache, since we are exporting a new animation group. //TODO: we should probably do this more elegantly.
                    exportedMorphTargets.Clear();
                }
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Ensures an offset value is within the value range.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The coerced value.</returns>
        private double CoerceOffset(double value)
        {
            var max = Math.Max(ExtentValue - ViewportValue, 0);

            return(MathUtilities.Clamp(value, 0, max));
        }
Ejemplo n.º 4
0
        /// <summary>Do the initial setup and calculations - this is also used onReset</summary>
        private void InitCalc()
        {
            int nLayers = dlayer.Length;

            // Factor to distribute fom over the soil profile. Uses a exponential function and goes till the especified depth
            double[] fom_FracLayer = new double[nLayers];
            double   cum_depth     = 0.0;
            int      deepest_layer = getCumulativeIndex(iniFomDepth, dlayer);

            for (int layer = 0; layer <= deepest_layer; layer++)
            {
                fom_FracLayer[layer] = Math.Exp(-3.0 * Math.Min(1.0, MathUtilities.Divide(cum_depth + dlayer[layer], iniFomDepth, 0.0))) *
                                       Math.Min(1.0, MathUtilities.Divide(iniFomDepth - cum_depth, dlayer[layer], 0.0));
                cum_depth += dlayer[layer];
            }
            double fom_FracLayer_tot = SumDoubleArray(fom_FracLayer);

            // ensure initial OC has a value for each layer
            Array.Resize(ref OC_reset, nLayers);

            // Distribute an convert C an N values over the profile
            double convFact = 0.0;
            double newValue = 0.0;

            for (int layer = 0; layer < nLayers; layer++)
            {
                convFact = convFactor_kgha2ppm(layer);
                // check and distribute the mineral nitrogen
                if (ureappm_reset != null)
                {
                    newValue = MathUtilities.Divide(ureappm_reset[layer], convFact, 0.0);       //Convert from ppm to kg/ha
                    for (int k = 0; k < Patch.Count; k++)
                    {
                        Patch[k].urea[layer] = newValue;
                    }
                }
                newValue = MathUtilities.Divide(nh4ppm_reset[layer], convFact, 0.0);       //Convert from ppm to kg/ha
                for (int k = 0; k < Patch.Count; k++)
                {
                    Patch[k].nh4[layer] = newValue;
                }
                newValue = MathUtilities.Divide(no3ppm_reset[layer], convFact, 0.0);       //Convert from ppm to kg/ha
                for (int k = 0; k < Patch.Count; k++)
                {
                    Patch[k].no3[layer] = newValue;
                }

                // calculate total soil C
                double Soil_OC = OC_reset[layer] * 10000;                       // = (oc/100)*1000000 - convert from % to ppm
                Soil_OC = MathUtilities.Divide(Soil_OC, convFact, 0.0);         //Convert from ppm to kg/ha

                // calculate inert soil C
                double InertC = finert[layer] * Soil_OC;

                // calculate microbial biomass C and N
                double BiomassC = MathUtilities.Divide((Soil_OC - InertC) * fbiom[layer], 1.0 + fbiom[layer], 0.0);
                double BiomassN = MathUtilities.Divide(BiomassC, biom_cn, 0.0);

                // calculate C and N values for active humus
                double HumusC = Soil_OC - BiomassC;
                double HumusN = MathUtilities.Divide(HumusC, hum_cn, 0.0);

                // distribute and calculate the fom N and C
                double fom = MathUtilities.Divide(iniFomWt * fom_FracLayer[layer], fom_FracLayer_tot, 0.0);

                for (int k = 0; k < Patch.Count; k++)
                {
                    Patch[k].inert_c[layer]     = InertC;
                    Patch[k].biom_c[layer]      = BiomassC;
                    Patch[k].biom_n[layer]      = BiomassN;
                    Patch[k].hum_c[layer]       = HumusC;
                    Patch[k].hum_n[layer]       = HumusN;
                    Patch[k].fom_c_pool1[layer] = fom * fract_carb[0] * c_in_fom;
                    Patch[k].fom_c_pool2[layer] = fom * fract_cell[0] * c_in_fom;
                    Patch[k].fom_c_pool3[layer] = fom * fract_lign[0] * c_in_fom;
                    Patch[k].fom_n_pool1[layer] = MathUtilities.Divide(Patch[k].fom_c_pool1[layer], fomPoolsCNratio[0], 0.0);
                    Patch[k].fom_n_pool2[layer] = MathUtilities.Divide(Patch[k].fom_c_pool2[layer], fomPoolsCNratio[1], 0.0);
                    Patch[k].fom_n_pool3[layer] = MathUtilities.Divide(Patch[k].fom_c_pool3[layer], fomPoolsCNratio[2], 0.0);
                }

                // store today's values
                for (int k = 0; k < Patch.Count; k++)
                {
                    Patch[k].InitCalc();
                }
            }

            // Calculations for NEW sysbal component
            dailyInitialC = SumDoubleArray(TotalC);
            dailyInitialN = SumDoubleArray(TotalN);

            // Initialise the inhibitor factors
            if (InhibitionFactor_Nitrification == null)
            {
                InhibitionFactor_Nitrification = new double[dlayer.Length];
            }

            initDone = true;
        }
Ejemplo n.º 5
0
        /// <summary>Method to read one days met data in from file</summary>
        /// <param name="date">the date to read met data</param>
        private DailyMetDataFromFile GetMetData(DateTime date)
        {
            if (this.doSeek)
            {
                if (!this.OpenDataFile())
                {
                    throw new ApsimXException(this, "Cannot find weather file '" + this.FileName + "'");
                }

                this.doSeek = false;
                this.reader.SeekToDate(date);
            }

            object[] values;

            DailyMetDataFromFile readMetData = new DailyMetDataFromFile();

            try
            {
                values = this.reader.GetNextLineOfData();
            }
            catch (IndexOutOfRangeException err)
            {
                throw new Exception($"Unable to retrieve weather data on {date.ToString("yyy-MM-dd")} in file {FileName}", err);
            }

            if (date != this.reader.GetDateFromValues(values))
            {
                throw new Exception("Non consecutive dates found in file: " + this.FileName + ".  Another posibility is that you have two clock objects in your simulation, there should only be one");
            }

            if (this.radiationIndex != -1)
            {
                readMetData.Radn = Convert.ToSingle(values[this.radiationIndex], CultureInfo.InvariantCulture);
            }
            else
            {
                readMetData.Radn = this.reader.ConstantAsDouble("radn");
            }

            if (this.maximumTemperatureIndex != -1)
            {
                readMetData.MaxT = Convert.ToSingle(values[this.maximumTemperatureIndex], CultureInfo.InvariantCulture);
            }
            else
            {
                readMetData.MaxT = this.reader.ConstantAsDouble("maxt");
            }

            if (this.minimumTemperatureIndex != -1)
            {
                readMetData.MinT = Convert.ToSingle(values[this.minimumTemperatureIndex], CultureInfo.InvariantCulture);
            }
            else
            {
                readMetData.MinT = this.reader.ConstantAsDouble("mint");
            }

            if (this.rainIndex != -1)
            {
                readMetData.Rain = Convert.ToSingle(values[this.rainIndex], CultureInfo.InvariantCulture);
            }
            else
            {
                readMetData.Rain = this.reader.ConstantAsDouble("rain");
            }

            if (this.evaporationIndex == -1)
            {
                readMetData.PanEvap = double.NaN;
            }
            else
            {
                readMetData.PanEvap = Convert.ToSingle(values[this.evaporationIndex], CultureInfo.InvariantCulture);
            }

            if (this.rainfallHoursIndex == -1)
            {
                readMetData.RainfallHours = double.NaN;
            }
            else
            {
                readMetData.RainfallHours = Convert.ToSingle(values[this.rainfallHoursIndex], CultureInfo.InvariantCulture);
            }

            if (this.vapourPressureIndex == -1)
            {
                readMetData.VP = Math.Max(0, MetUtilities.svp(readMetData.MinT));
            }
            else
            {
                readMetData.VP = Convert.ToSingle(values[this.vapourPressureIndex], CultureInfo.InvariantCulture);
            }

            if (this.windIndex == -1)
            {
                readMetData.Wind = 3.0;
            }
            else
            {
                readMetData.Wind = Convert.ToSingle(values[this.windIndex], CultureInfo.InvariantCulture);
            }

            if (co2Index != -1)
            {
                readMetData.CO2 = Convert.ToDouble(values[co2Index], CultureInfo.InvariantCulture);
            }

            if (this.DiffuseFractionIndex == -1)
            {
                // Estimate Diffuse Fraction using the Approach of Bristow and Campbell
                double Qmax = MetUtilities.QMax(clock.Today.DayOfYear + 1, Latitude, MetUtilities.Taz, MetUtilities.Alpha, 0.0); // Radiation for clear and dry sky (ie low humidity)
                double Q0   = MetUtilities.Q0(clock.Today.DayOfYear + 1, Latitude);
                double B    = Qmax / Q0;
                double Tt   = MathUtilities.Bound(readMetData.Radn / Q0, 0, 1);
                if (Tt > B)
                {
                    Tt = B;
                }
                readMetData.DiffuseFraction = (1 - Math.Exp(0.6 * (1 - B / Tt) / (B - 0.4)));
                if (Tt > 0.5 && readMetData.DiffuseFraction < 0.1)
                {
                    readMetData.DiffuseFraction = 0.1;
                }
            }
            else
            {
                readMetData.DiffuseFraction = Convert.ToSingle(values[this.DiffuseFractionIndex], CultureInfo.InvariantCulture);
            }

            if (this.dayLengthIndex == -1)  // Daylength is not a column - check for a constant
            {
                if (this.reader.Constant("daylength") != null)
                {
                    readMetData.DayLength = this.reader.ConstantAsDouble("daylength");
                }
                else
                {
                    readMetData.DayLength = -1;
                }
            }
            else
            {
                readMetData.DayLength = Convert.ToSingle(values[this.dayLengthIndex], CultureInfo.InvariantCulture);
            }

            return(readMetData);
        }
Ejemplo n.º 6
0
        public static QuoteSystem Guess <T>(ICharacterVerseInfo cvInfo, List <T> bookList, ScrVers versification, out bool certain, BackgroundWorker worker = null) where T : IScrBook
        {
            certain = false;
            var bookCount = bookList.Count();

            if (bookCount == 0)
            {
                ReportProgressComplete(worker);
                return(QuoteSystem.Default);
            }
            var scores = QuoteSystem.UniquelyGuessableSystems.ToDictionary(s => s, s => 0);
            var quotationDashCounts = QuoteSystem.UniquelyGuessableSystems.Where(s => !String.IsNullOrEmpty(s.QuotationDashMarker))
                                      .ToDictionary(s => s, s => 0);
            var viableSystems       = scores.Keys.ToList();
            int totalVersesAnalyzed = 0;
            int totalDialoqueQuoteVersesAnalyzed = 0;
            int maxNonDialogueSamplesPerBook     = BCVRef.LastBook * kMinSample / bookCount;
            int booksProcessed = 0;

            int  bestScore     = 0;
            bool foundEndQuote = false;
            bool foundSecondLevelQuoteCloser = false;

            int kVerseValue = Math.Min(kStartQuoteValue + kEndQuoteValue, kQuotationDashValue);

            List <string> followingVerses = new List <string>(kMaxFollowingVersesToSearchForEndQuote);

            var stopwatch = new Stopwatch();

            stopwatch.Start();

            // Start with the New Testament because that's where most of the dialogue quotes are, and it makes guessing A LOT faster!
            foreach (var book in bookList.SkipWhile(b => BCVRef.BookToNumber(b.BookId) < 40).Union(bookList.TakeWhile(b => BCVRef.BookToNumber(b.BookId) < 40)))
            {
                if (worker != null)
                {
                    worker.ReportProgress(MathUtilities.Percent(++booksProcessed, bookCount));
                }

                int versesAnalyzedForCurrentBook = 0;
                int prevQuoteChapter             = -1;
                int prevQuoteVerse = -1;

                foreach (var quote in cvInfo.GetAllQuoteInfo(book.BookId).Where(q => q.IsExpected))
                {
                    if (versesAnalyzedForCurrentBook > maxNonDialogueSamplesPerBook && !quote.IsDialogue)
                    {
                        continue;
                    }

                    if (quote.Chapter == prevQuoteChapter && (quote.Verse == prevQuoteVerse || quote.Verse == prevQuoteVerse + 1))
                    {
                        prevQuoteVerse = quote.Verse;
                        continue;
                    }
                    var text = book.GetVerseText(quote.Chapter, quote.Verse);
                    followingVerses.Clear();
                    int maxFollowingVersesToSearch = kMaxFollowingVersesToSearchForEndQuote;
#if SHOWTESTINFO
                    if (quote.IsDialogue)
                    {
                        Debug.WriteLine("Evaluating {0} {1}:{2} - contents (DIALOGUE=TRUE): {3}", book.BookId, quote.Chapter, quote.Verse, text);
                    }
                    else
                    {
                        Debug.WriteLine("Evaluating {0} {1}:{2} - contents: {3}", book.BookId, quote.Chapter, quote.Verse, text);
                    }
#endif
                    foreach (var quoteSystem in viableSystems)
                    {
                        int ichStartQuote = text.IndexOf(quoteSystem.FirstLevel.Open, StringComparison.Ordinal);
                        int i2            = -1;

                        if (quote.IsDialogue && !string.IsNullOrEmpty(quoteSystem.QuotationDashMarker))
                        {
                            int i = text.IndexOf(quoteSystem.QuotationDashMarker, StringComparison.Ordinal);
                            if (i >= 0 && (ichStartQuote < 0 || i < ichStartQuote))
                            {
                                // Found a dialogue quote marker earlier in the text.
                                IncrementScore(scores, quoteSystem, kQuotationDashValue, ref bestScore);
                                quotationDashCounts[quoteSystem]++;
                                continue;
                            }
                        }
                        if (ichStartQuote >= 0 && ichStartQuote < text.Length - 2)
                        {
                            IncrementScore(scores, quoteSystem, kStartQuoteValue, ref bestScore);

                            if (quoteSystem.NormalLevels.Count() > 1)
                            {
                                i2 = text.IndexOf(quoteSystem.NormalLevels[1].Open, ichStartQuote + 1, StringComparison.Ordinal);
                                if (i2 > ichStartQuote)
                                {
#if SHOWTESTINFO
                                    Debug.WriteLine("Found 2nd-level opener (" + quoteSystem.NormalLevels[1].Open + ") for system " + quoteSystem);
#endif
                                    IncrementScore(scores, quoteSystem, kStartLevel2QuoteValue, ref bestScore);
                                    if (i2 < text.Length - 2 && text.IndexOf(quoteSystem.NormalLevels[1].Close, i2 + 1, StringComparison.Ordinal) > i2)
                                    {
#if SHOWTESTINFO
                                        Debug.WriteLine("Found 2nd-level closer (" + quoteSystem.NormalLevels[1].Close + ") for system " + quoteSystem);
#endif
                                        foundSecondLevelQuoteCloser = true;
                                        IncrementScore(scores, quoteSystem, kEndLevel2QuoteValue, ref bestScore);
                                    }
                                }
                            }

                            if (text.IndexOf(quoteSystem.FirstLevel.Close, ichStartQuote + 1, StringComparison.Ordinal) > ichStartQuote)
                            {
                                foundEndQuote = true;
                                IncrementScore(scores, quoteSystem, kEndQuoteValue, ref bestScore);
                            }
                            else
                            {
                                for (int i = 1; i <= maxFollowingVersesToSearch; i++)
                                {
                                    if (!cvInfo.GetCharacters(book.BookId, quote.Chapter, quote.Verse + i, versification: versification).Any())
                                    {
                                        break;
                                    }
                                    string followingText;
                                    if (followingVerses.Count >= i)
                                    {
                                        followingText = followingVerses[i - 1];
                                    }
                                    else
                                    {
                                        followingText = book.GetVerseText(quote.Chapter, quote.Verse + i);
                                        followingVerses.Add(followingText);
                                    }
                                    if (i2 >= 0 && followingText.IndexOf(quoteSystem.NormalLevels[1].Close, StringComparison.Ordinal) >= 0)
                                    {
#if SHOWTESTINFO
                                        Debug.WriteLine("Found 2nd-level closer (" + quoteSystem.NormalLevels[1].Close + ") in subsequent verse for system " + quoteSystem);
#endif
                                        foundSecondLevelQuoteCloser = true;
                                        IncrementScore(scores, quoteSystem, kEndLevel2QuoteValue, ref bestScore);
                                    }
                                    if (followingText.IndexOf(quoteSystem.FirstLevel.Close, StringComparison.Ordinal) > 0)
                                    {
                                        foundEndQuote = true;
                                        IncrementScore(scores, quoteSystem, kEndQuoteValue, ref bestScore);
                                        break;
                                    }
                                }
                            }
                            maxFollowingVersesToSearch = followingVerses.Count;
                        }
                    }
                    totalVersesAnalyzed++;
                    if (quote.IsDialogue)
                    {
                        totalDialoqueQuoteVersesAnalyzed++;
                    }
                    versesAnalyzedForCurrentBook++;

                    if (totalVersesAnalyzed >= kMinSample && foundEndQuote &&
                        (totalDialoqueQuoteVersesAnalyzed >= kMinQuotationDashSample ||
                         viableSystems.TrueForAll(s => String.IsNullOrEmpty(s.QuotationDashMarker))) &&
                        (foundSecondLevelQuoteCloser || (totalVersesAnalyzed - totalDialoqueQuoteVersesAnalyzed) >= kMinSampleToAttemptToGetSecondLevel || viableSystems.TrueForAll(s => s.NormalLevels.Count == 1)))
                    {
                        var minViabilityScore = Math.Max(totalVersesAnalyzed * kVerseValue * kMinPercent,
                                                         bestScore * kMaxCompetitorPercent);
                        var competitors = viableSystems.Where(system => scores[system] > minViabilityScore).ToList();

                        if (competitors.Any())
                        {
#if SHOWTESTINFO
                            Debug.WriteLine("STATISTICS:");
                            foreach (var system in competitors)
                            {
                                Debug.WriteLine(system.Name + "(" + system + ")\tScore: " + scores[system]);
                                if (!String.IsNullOrEmpty(system.QuotationDashMarker))
                                {
                                    Debug.WriteLine("\tPercentage matches of total Dialogue quotes analyzed: " +
                                                    (100.0 * quotationDashCounts[system]) / totalDialoqueQuoteVersesAnalyzed);
                                }
                            }
#endif

                            if (competitors.Count == 1)
                            {
                                certain = true;
                                ReportProgressComplete(worker);
                                return(competitors[0]);
                            }

                            viableSystems = viableSystems.Where(competitors.Contains).ToList();
                            if (competitors.TrueForAll(c => c.FirstLevel.Open == competitors[0].FirstLevel.Open &&
                                                       c.FirstLevel.Close == competitors[0].FirstLevel.Close))
                            {
                                var contendersWithQDash        = competitors.Where(c => !String.IsNullOrEmpty(c.QuotationDashMarker)).ToList();
                                var failureThresholdForQDCount = kQuotationDashFailPercent * totalDialoqueQuoteVersesAnalyzed;
                                if (contendersWithQDash.TrueForAll(c => quotationDashCounts[c] < failureThresholdForQDCount))
                                {
#if SHOWTESTINFO
                                    Debug.Write("No systems with QD over minimum threshold (" + failureThresholdForQDCount +
                                                "). Competitors reduced from " + competitors.Count);
#endif
                                    competitors = competitors.Where(c => String.IsNullOrEmpty(c.QuotationDashMarker)).ToList();
#if SHOWTESTINFO
                                    Debug.WriteLine(" to " + competitors.Count);
#endif

                                    // We're probably (unless we reset this to false below) down to either a single contender (in
                                    // which case we can be pretty certain) or two contenders, in which case we can safely use the
                                    // one with multiple levels filled in (since there will be no harm done even if the data only
                                    // has 1st-level quotes).
                                    certain = true;
                                }
                                else
                                {
#if SHOWTESTINFO
                                    Debug.WriteLine("Only considering contenders with QD. Of " + competitors.Count + " competitors, there are " +
                                                    contendersWithQDash.Count + " contenders with QD count over minimum threshold (" +
                                                    failureThresholdForQDCount + ").");
#endif
                                    var minQDCount = kMinQuotationDashPercent * totalDialoqueQuoteVersesAnalyzed;
                                    competitors = contendersWithQDash.Where(c => scores[c] == bestScore &&
                                                                            quotationDashCounts[c] >= minQDCount).ToList();
#if SHOWTESTINFO
                                    switch (competitors.Count)
                                    {
                                    case 0:
                                        Debug.WriteLine("Of those, none had the best score (" + bestScore +
                                                        ") and had a QD count above the minimum (" + minQDCount + ")");
                                        break;

                                    case 1:
                                        Debug.WriteLine("Of those, one had the best score (" + bestScore + ") and had a QD count above the minimum (" +
                                                        minQDCount + ")");
                                        break;

                                    default:
                                        Debug.WriteLine("Of those, " + competitors.Count + " were tied for the best score (" + bestScore +
                                                        ") and had a QD count above the minimum (" + minQDCount + ")");
                                        break;
                                    }
#endif
                                }

                                if (competitors.Any())
                                {
                                    // If there are multiple systems with 2nd and 3rd levels specified, discard those options since
                                    // we didn't find anything in the data to help us choose among the options.
                                    if (competitors.Count(qs => qs.NormalLevels.Count > 1) > 1)
                                    {
                                        var bestSystems = competitors.Where(c => scores[c] == bestScore).ToList();
                                        if (bestSystems.Count == 1)
                                        {
#if SHOWTESTINFO
                                            Debug.Write("Multiple systems with 2nd and 3rd levels specified. Taking system with best score: " + bestSystems[0]);
#endif
                                            competitors = bestSystems;
                                        }
                                        else
                                        {
#if SHOWTESTINFO
                                            Debug.Write("Multiple systems with 2nd and 3rd levels specified. Competitors reduced from " +
                                                        competitors.Count);
#endif
                                            competitors = competitors.Where(qs => qs.NormalLevels.Count() == 1).ToList();
#if SHOWTESTINFO
                                            Debug.WriteLine(" to " + competitors.Count);
#endif

                                            certain = false;
                                        }
                                    }

                                    if (competitors.Any())
                                    {
                                        ReportProgressComplete(worker);

                                        if (competitors.Count == 1)
                                        {
                                            return(competitors[0]);
                                        }
#if SHOWTESTINFO
                                        Debug.WriteLine("SURVIVORS:");
                                        foreach (var system in competitors)
                                        {
                                            Debug.WriteLine(system.Name + "(" + system + ")\tScore: " + scores[system]);
                                        }
#endif
                                        return(competitors.FirstOrDefault(qs => qs.NormalLevels.Count() > 1) ?? competitors.First());
                                    }
                                }
                            }
                            // Still have multiple systems in contention with different first-level start & end markers;
                            // we haven't seen enough evidence to pick a clear winner.
                        }
#if SHOWTESTINFO
                        else
                        {
                            Debug.WriteLine("NO COMPETITORS. Total verses analyzed = " + totalVersesAnalyzed + ". Best Score = " + bestScore +
                                            ". Minimum viability score = " + minViabilityScore);
                        }
#endif
                    }

                    if (stopwatch.ElapsedMilliseconds > kMaxTimeLimit)
                    {
#if SHOWTESTINFO
                        Debug.WriteLine("Time-out guessing quote system.");
#endif
                        ReportProgressComplete(worker);
                        return(BestGuess(viableSystems, scores, bestScore, foundEndQuote));
                    }

                    prevQuoteChapter = quote.Chapter;
                    prevQuoteVerse   = quote.Verse;
                }
            }
            ReportProgressComplete(worker);
            return(BestGuess(viableSystems, scores, bestScore, foundEndQuote));
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Calculate the potential N uptake for today. Should return null if crop is not in the ground.
        /// </summary>
        public virtual List <Soils.Arbitrator.ZoneWaterAndN> GetNitrogenUptakeEstimates(SoilState soilstate)
        {
            if (Plant.IsEmerged)
            {
                double NSupply = 0;//NOTE: This is in kg, not kg/ha, to arbitrate N demands for spatial simulations.

                for (int i = 0; i < Organs.Count; i++)
                {
                    N.UptakeSupply[i] = 0;
                }

                List <ZoneWaterAndN> zones = new List <ZoneWaterAndN>();
                foreach (ZoneWaterAndN zone in soilstate.Zones)
                {
                    ZoneWaterAndN UptakeDemands = new ZoneWaterAndN(zone);

                    UptakeDemands.NO3N = new double[zone.NO3N.Length];
                    UptakeDemands.NH4N = new double[zone.NH4N.Length];
                    UptakeDemands.PlantAvailableNO3N = new double[zone.NO3N.Length];
                    UptakeDemands.PlantAvailableNH4N = new double[zone.NO3N.Length];
                    UptakeDemands.Water = new double[UptakeDemands.NO3N.Length];

                    //Get Nuptake supply from each organ and set the PotentialUptake parameters that are passed to the soil arbitrator
                    for (int i = 0; i < Organs.Count; i++)
                    {
                        if (Organs[i] is IWaterNitrogenUptake)
                        {
                            double[] organNO3Supply = new double[zone.NO3N.Length];
                            double[] organNH4Supply = new double[zone.NH4N.Length];
                            (Organs[i] as IWaterNitrogenUptake).CalculateNitrogenSupply(zone, ref organNO3Supply, ref organNH4Supply);
                            UptakeDemands.NO3N = MathUtilities.Add(UptakeDemands.NO3N, organNO3Supply); //Add uptake supply from each organ to the plants total to tell the Soil arbitrator
                            UptakeDemands.NH4N = MathUtilities.Add(UptakeDemands.NH4N, organNH4Supply);
                            N.UptakeSupply[i] += (MathUtilities.Sum(organNH4Supply) + MathUtilities.Sum(organNO3Supply)) * kgha2gsm * zone.Zone.Area / Plant.Zone.Area;
                            NSupply           += (MathUtilities.Sum(organNH4Supply) + MathUtilities.Sum(organNO3Supply)) * zone.Zone.Area;
                        }
                    }
                    zones.Add(UptakeDemands);
                }

                double NDemand = (N.TotalPlantDemand - N.TotalReallocation) / kgha2gsm * Plant.Zone.Area; //NOTE: This is in kg, not kg/ha, to arbitrate N demands for spatial simulations.

                if (NSupply > NDemand)
                {
                    //Reduce the PotentialUptakes that we pass to the soil arbitrator
                    double ratio = Math.Min(1.0, NDemand / NSupply);
                    foreach (ZoneWaterAndN UptakeDemands in zones)
                    {
                        UptakeDemands.NO3N = MathUtilities.Multiply_Value(UptakeDemands.NO3N, ratio);
                        UptakeDemands.NH4N = MathUtilities.Multiply_Value(UptakeDemands.NH4N, ratio);
                    }
                }
                return(zones);
            }
            return(null);
        }
        /// <summary>Relatives the allocation.</summary>
        /// <param name="Organs">The organs.</param>
        /// <param name="TotalSupply">The total supply.</param>
        /// <param name="TotalAllocated">The total allocated.</param>
        /// <param name="BAT">The bat.</param>
        public void DoAllocation(IArbitration[] Organs, double TotalSupply, ref double TotalAllocated, BiomassArbitrationType BAT)
        {
            double NotAllocated = TotalSupply;

            ////First time round allocate to met priority demands of each organ
            for (int i = 0; i < Organs.Length; i++)
            {
                double StructuralRequirement = Math.Max(0.0, BAT.StructuralDemand[i] - BAT.StructuralAllocation[i]); //N needed to get to Minimum N conc and satisfy structural and metabolic N demands
                double MetabolicRequirement  = Math.Max(0.0, BAT.MetabolicDemand[i] - BAT.MetabolicAllocation[i]);
                if ((StructuralRequirement + MetabolicRequirement) > 0.0)
                {
                    double StructuralFraction   = BAT.StructuralDemand[i] / (BAT.StructuralDemand[i] + BAT.MetabolicDemand[i]);
                    double StructuralAllocation = Math.Min(StructuralRequirement, NotAllocated * StructuralFraction);
                    double MetabolicAllocation  = Math.Min(MetabolicRequirement, NotAllocated * (1 - StructuralFraction));
                    BAT.StructuralAllocation[i] += StructuralAllocation;
                    BAT.MetabolicAllocation[i]  += MetabolicAllocation;
                    NotAllocated   -= (StructuralAllocation + MetabolicAllocation);
                    TotalAllocated += (StructuralAllocation + MetabolicAllocation);
                }
            }
            // Second time round if there is still N to allocate let organs take N up to their Maximum
            double FirstPassNotallocated = NotAllocated;

            for (int i = 0; i < Organs.Length; i++)
            {
                double NonStructuralRequirement = Math.Max(0.0, BAT.NonStructuralDemand[i] - BAT.NonStructuralAllocation[i]); //N needed to take organ up to maximum N concentration, Structural, Metabolic and Luxury N demands
                if (NonStructuralRequirement > 0.0)
                {
                    double NonStructuralAllocation = Math.Min(FirstPassNotallocated * MathUtilities.Divide(BAT.NonStructuralDemand[i], BAT.TotalNonStructuralDemand, 0), NonStructuralRequirement);
                    BAT.NonStructuralAllocation[i] += Math.Max(0, NonStructuralAllocation);
                    NotAllocated   -= NonStructuralAllocation;
                    TotalAllocated += NonStructuralAllocation;
                }
            }
        }
Ejemplo n.º 9
0
 public void AddKgHaDelta(SoluteSetterType callingModelType, double[] delta)
 {
     kgha = MathUtilities.Add(kgha, delta);
 }
Ejemplo n.º 10
0
        void UpdatePrecision()
        {
            curDir     = rotation * Vector3.forward;
            dirDelta   = curDir - lastDir;
            preciseDir = preciseRotation * Vector3.forward;
            averageVel = Mathf.Lerp(averageVel, dirDelta.magnitude / Time.deltaTime, velAvgRate);

            if (PrecisionMode == EPrecisionMode.Smoothed)
            {
                preciseRotation = MathUtilities.DynamicExpDecay(preciseRotation, rotation, 3f);
            }
            else if (PrecisionMode == EPrecisionMode.Velocity)
            {
                // Determine aimScale by the current speed of real direction
                float velP     = Mathf.InverseLerp(velRange.x, velRange.y, averageVel);
                float aimScale = Mathf.Lerp(preciseScale, 1f, velP);

                Quaternion startPrecise = preciseRotation;

                // Apply relative delta, scaled down by aimScale
                PreciseApplyRotDeltaScaled(aimScale);

                // Do some slerping to real dir when moving fast, since it's bad to
                if (aimScale > 0.9f)
                {
                    PreciseSlerpToCurrent(Mathf.Lerp(0, 0.3f, Mathf.InverseLerp(0.9f, 1f, aimScale)));
                }

                preciseRotation = MathUtilities.DynamicExpDecay(startPrecise, preciseRotation, 3f);
            }
            else if (PrecisionMode == EPrecisionMode.VelocityAlignedScale)
            {
                // Determine aimScale by the current speed of real direction
                float velP     = Mathf.InverseLerp(velRange.x, velRange.y, averageVel);
                float aimScale = Mathf.Lerp(preciseScale, 1f, velP);

                float finalCatchupAmt = Mathf.InverseLerp(0.1f, 1f, velP);

                // Also apply a max angle limit
                float zoneScale = GetZoneScale(curDir, preciseDir, new Vector2(0, 1f));
                if (zoneScale > 0.9f)
                {
                    float zoneAmt = Mathf.InverseLerp(0.9f, 1f, zoneScale);
                    finalCatchupAmt = Mathf.Max(zoneAmt, finalCatchupAmt);
                }

                PreciseApplyRotDeltaCatchupScaled(aimScale, finalCatchupAmt);

                // Do some slerping to real dir when moving fast, since it's bad to get too far away
                if (aimScale > 0.9f)
                {
                    PreciseSlerpToCurrent(Mathf.Lerp(0, 0.3f, Mathf.InverseLerp(0.9f, 1f, aimScale)));
                }
            }
            else if (PrecisionMode == EPrecisionMode.Zone)
            {
                float zoneScale = GetZoneScale(curDir, preciseDir, new Vector2(preciseScale, 1f));

                PreciseApplyRotDeltaCatchupScaled(zoneScale, Mathf.InverseLerp(0.8f, 1f, zoneScale));
            }
            else if (PrecisionMode == EPrecisionMode.MovingZone)
            {
                // Update avgPreciseDir
                avgPreciseDir = Vector3.Slerp(avgPreciseDir, preciseDir, Time.deltaTime * avgPreciseDirRate);

                float zoneScale = GetZoneScale(curDir, avgPreciseDir, new Vector2(preciseScale, 1f));

                PreciseApplyRotDeltaCatchupScaled(zoneScale, Mathf.InverseLerp(0.8f, 1f, zoneScale));
            }

            lastDir = curDir;
            prevRot = rotation;
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Run tests
        /// </summary>
        /// <param name="accept">If true, the stats from this run will be written to file as the accepted stats.</param>
        /// <param name="GUIrun">If true, do not raise an exception on test failure.</param>
        public void Test(bool accept = false, bool GUIrun = false)
        {
            PredictedObserved PO = Parent as PredictedObserved;

            if (PO == null)
            {
                return;
            }
            IDataStore DS = PO.Parent as IDataStore;

            MathUtilities.RegrStats[] stats;
            List <string>             statNames = (new MathUtilities.RegrStats()).GetType().GetFields().Select(f => f.Name).ToList(); // use reflection, get names of stats available
            DataTable     POtable = DS.Reader.GetData(PO.Name);
            List <string> columnNames;
            string        sigIdent = "X";

            if (POtable == null)
            {
                object sim = PO.Parent;
                while (sim as Simulations == null)
                {
                    sim = ((Model)sim).Parent;
                }

                throw new ApsimXException(this, "Could not find PO table in " + (sim != null ? ((Simulations)sim).FileName : "<unknown>") + ". Has the simulation been run?");
            }
            columnNames = POtable.Columns.Cast <DataColumn>().Select(c => c.ColumnName).ToList(); //get list of column names
            columnNames = columnNames.Where(c => c.Contains("Observed")).ToList();                //filter names that are not pred/obs pairs
            for (int i = 0; i < columnNames.Count; i++)
            {
                columnNames[i] = columnNames[i].Replace("Observed.", "");
            }
            columnNames.Sort(); //ensure column names are always in the same order
            columnNames.Remove("CheckpointID");
            stats = new MathUtilities.RegrStats[columnNames.Count];
            List <double> x = new List <double>();
            List <double> y = new List <double>();
            string        xstr, ystr;
            double        xres;
            double        yres;

            for (int c = 0; c < columnNames.Count; c++) //on each P/O column pair
            {
                string observedFieldName  = "Observed." + columnNames[c];
                string predictedFieldName = "Predicted." + columnNames[c];
                if (POtable.Columns.Contains(observedFieldName) &&
                    POtable.Columns.Contains(predictedFieldName))
                {
                    x.Clear();
                    y.Clear();
                    foreach (DataRow row in POtable.Rows)
                    {
                        xstr = row[observedFieldName].ToString();
                        ystr = row[predictedFieldName].ToString();
                        if (Double.TryParse(xstr, out xres) && Double.TryParse(ystr, out yres))
                        {
                            x.Add(xres);
                            y.Add(yres);
                        }
                    }
                    if (x.Count == 0 || y.Count == 0)
                    {
                        continue;
                    }

                    stats[c] = MathUtilities.CalcRegressionStats(columnNames[c], y, x);
                }
            }

            //remove any null stats which can occur from non-numeric columns such as dates
            List <MathUtilities.RegrStats> list = new List <MathUtilities.RegrStats>(stats);

            list.RemoveAll(l => l == null);
            stats = list.ToArray();

            //remove entries from column names
            for (int i = columnNames.Count() - 1; i >= 0; i--)
            {
                bool found = false;
                for (int j = 0; j < stats.Count(); j++)
                {
                    if (columnNames[i] == stats[j].Name)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    columnNames.RemoveAt(i);
                }
            }

            //turn stats array into a DataTable
            //first, check if there is already an AcceptedStats array, create if not.
            //If the names don't match, then use current stats as user has dragged
            //an already existing Test to a new node.
            if (AcceptedStats == null || POName != PO.Name)
            {
                POName            = PO.Name;
                AcceptedStats     = stats;
                AcceptedStatsName = StringUtilities.Build(statNames, " ");
            }

            //then make sure the names and order of the accepted stats are the same as the new ones.
            if (StringUtilities.Build(statNames, " ") != AcceptedStatsName)
            {
                throw new ApsimXException(this, "Names, number or order of accepted stats do not match class MathUtilities.RegrStats. The class has probably changed.");
            }

            Table = new DataTable("StatTests");
            Table.Columns.Add("Name", typeof(string));
            Table.Columns.Add("Variable", typeof(string));
            Table.Columns.Add("Test", typeof(string));
            Table.Columns.Add("Accepted", typeof(double));
            Table.Columns.Add("Current", typeof(double));
            Table.Columns.Add("Difference", typeof(double));
            Table.Columns.Add("Fail?", typeof(string));

            double    accepted;
            double    current;
            DataTable AcceptedTable             = Table.Copy();
            DataTable CurrentTable              = Table.Copy();

            //accepted table
            for (int i = 0; i < AcceptedStats.Count(); i++)
            {
                for (int j = 1; j < statNames.Count; j++) //start at 1; we don't want Name field.
                {
                    accepted = Convert.ToDouble(AcceptedStats[i].GetType().GetField(statNames[j]).GetValue(AcceptedStats[i]),
                                                System.Globalization.CultureInfo.InvariantCulture);
                    AcceptedTable.Rows.Add(PO.Name,
                                           AcceptedStats[i].Name,
                                           statNames[j],
                                           accepted,
                                           null,
                                           null,
                                           null);
                }
            }

            //current table
            Table = AcceptedTable.Copy();
            int rowIndex = 0;

            for (int i = 0; i < stats.Count(); i++)
            {
                for (int j = 1; j < statNames.Count; j++) //start at 1; we don't want Name field.
                {
                    current = Convert.ToDouble(stats[i].GetType().GetField(statNames[j]).GetValue(stats[i]),
                                               System.Globalization.CultureInfo.InvariantCulture);
                    CurrentTable.Rows.Add(PO.Name,
                                          stats[i].Name,
                                          statNames[j],
                                          null,
                                          current,
                                          null,
                                          null);
                    if (Table.Rows.Count > rowIndex)
                    {
                        Table.Rows[rowIndex]["Current"] = current;
                    }
                    else
                    {
                        // The row for this particular variable/stat doesn't exist in the accepted table.
                        Table.Rows.Add(PO.Name,
                                       stats[i].Name,
                                       statNames[j],
                                       null,
                                       current,
                                       null,
                                       null);
                    }
                    rowIndex++;
                }
            }

            //Merge overwrites rows, so add the correct data back in
            foreach (DataRow row in Table.Rows)
            {
                DataRow[] rowAccepted = AcceptedTable.Select("Name = '" + row["Name"] + "' AND Variable = '" + row["Variable"] + "' AND Test = '" + row["Test"] + "'");
                DataRow[] rowCurrent  = CurrentTable.Select("Name = '" + row["Name"] + "' AND Variable = '" + row["Variable"] + "' AND Test = '" + row["Test"] + "'");

                if (rowAccepted.Count() == 0)
                {
                    row["Accepted"] = DBNull.Value;
                }
                else
                {
                    row["Accepted"] = rowAccepted[0]["Accepted"];
                }

                if (rowCurrent.Count() == 0)
                {
                    row["Current"] = DBNull.Value;
                }
                else
                {
                    row["Current"] = rowCurrent[0]["Current"];
                }

                if (row["Accepted"] != DBNull.Value && row["Current"] != DBNull.Value)
                {
                    row["Difference"] = Convert.ToDouble(row["Current"],
                                                         System.Globalization.CultureInfo.InvariantCulture) -
                                        Convert.ToDouble(row["Accepted"], System.Globalization.CultureInfo.InvariantCulture);
                    row["Fail?"] = Math.Abs(Convert.ToDouble(row["Difference"], System.Globalization.CultureInfo.InvariantCulture))
                                   > Math.Abs(Convert.ToDouble(row["Accepted"], System.Globalization.CultureInfo.InvariantCulture)) * 0.01 ? sigIdent : " ";
                }
                else
                {
                    row["Difference"] = DBNull.Value;
                    row["Fail?"]      = sigIdent;
                }
            }
            //Tables could be large so free the memory.
            AcceptedTable = null;
            CurrentTable  = null;

            if (accept)
            {
                AcceptedStats = stats;
            }
            else
            {
                foreach (DataRow row in Table.Rows)
                {
                    if (row["Fail?"].ToString().Equals(sigIdent))
                    {
                        if (!GUIrun)
                        {
                            object sim = PO.Parent;
                            while (sim as Simulations == null)
                            {
                                sim = ((Model)sim).Parent;
                            }

                            throw new ApsimXException(this, "Significant differences found during regression testing of " + PO.Name + " in " + (sim != null ? ((Simulations)sim).FileName : "<unknown>"));
                        }
                    }
                }
            }
        }
Ejemplo n.º 12
0
        /// <summary>Convert a table of soils data into a list of soils.</summary>
        public static List <Soil> ToSoils(DataTable table)
        {
            var soils = new List <Soil>();

            // Loop through all blocks of rows in datatable, create a
            // soil and store soil in correct location in the AllSoils XML.
            int row = 0;

            while (row < table.Rows.Count)
            {
                // Find the end of this soil i.e. the row that has a different value for 'Name'
                // to the current row.
                int endRow = row + 1;
                while (endRow < table.Rows.Count &&
                       table.Rows[endRow]["Name"].ToString() == table.Rows[row]["Name"].ToString())
                {
                    endRow++;
                }
                int numLayers = endRow - row;

                var soil = new Soil();
                soil.Name              = table.Rows[row]["Name"].ToString();
                soil.Country           = GetStringValue(table, row, "Country");
                soil.State             = GetStringValue(table, row, "State");
                soil.Region            = GetStringValue(table, row, "Region");
                soil.NearestTown       = GetStringValue(table, row, "NearestTown");
                soil.Site              = GetStringValue(table, row, "Site");
                soil.ApsoilNumber      = GetStringValue(table, row, "APSoilNumber");
                soil.SoilType          = GetStringValue(table, row, "Texture");
                soil.LocalName         = GetStringValue(table, row, "LocalName");
                soil.ASCOrder          = GetStringValue(table, row, "ASC_Order");
                soil.ASCSubOrder       = GetStringValue(table, row, "ASC_Sub-order");
                soil.Latitude          = GetDoubleValue(table, row, "Latitude");
                soil.Longitude         = GetDoubleValue(table, row, "Longitude");
                soil.LocationAccuracy  = GetStringValue(table, row, "LocationAccuracy");
                soil.YearOfSampling    = GetStringValue(table, row, "YearOfSampling");
                soil.DataSource        = GetStringValue(table, row, "DataSource");
                soil.Comments          = GetStringValue(table, row, "Comments");
                soil.NaturalVegetation = GetStringValue(table, row, "NaturalVegetation");
                soil.RecordNumber      = GetIntegerValue(table, row, "RecordNo");

                var physical = new Physical();
                soil.Children.Add(physical);
                physical.Thickness                = MathUtilities.RemoveMissingValuesFromBottom(GetDoubleValues(table, "Thickness (mm)", row, numLayers));
                physical.BD                       = GetDoubleValues(table, "BD", row, numLayers);
                physical.BDMetadata               = GetCodeValues(table, "BDCode", row, numLayers);
                physical.SAT                      = GetDoubleValues(table, "SAT (mm/mm)", row, numLayers);
                physical.SATMetadata              = GetCodeValues(table, "SATCode", row, numLayers);
                physical.DUL                      = GetDoubleValues(table, "DUL (mm/mm)", row, numLayers);
                physical.DULMetadata              = GetCodeValues(table, "DULCode", row, numLayers);
                physical.LL15                     = GetDoubleValues(table, "LL15 (mm/mm)", row, numLayers);
                physical.LL15Metadata             = GetCodeValues(table, "LL15Code", row, numLayers);
                physical.AirDry                   = GetDoubleValues(table, "Airdry (mm/mm)", row, numLayers);
                physical.AirDryMetadata           = GetCodeValues(table, "AirdryCode", row, numLayers);
                physical.KS                       = GetDoubleValues(table, "KS (mm/day)", row, numLayers);
                physical.KSMetadata               = GetCodeValues(table, "KSCode", row, numLayers);
                physical.Rocks                    = GetDoubleValues(table, "Rocks (%)", row, numLayers);
                physical.RocksMetadata            = GetCodeValues(table, "RocksCode", row, numLayers);
                physical.Texture                  = GetStringValues(table, "Texture", row, numLayers);
                physical.TextureMetadata          = GetCodeValues(table, "TextureCode", row, numLayers);
                physical.ParticleSizeSand         = GetDoubleValues(table, "ParticleSizeSand (%)", row, numLayers);
                physical.ParticleSizeSandMetadata = GetCodeValues(table, "ParticleSizeSandCode", row, numLayers);
                physical.ParticleSizeSilt         = GetDoubleValues(table, "ParticleSizeSilt (%)", row, numLayers);
                physical.ParticleSizeSiltMetadata = GetCodeValues(table, "ParticleSizeSiltCode", row, numLayers);
                physical.ParticleSizeClay         = GetDoubleValues(table, "ParticleSizeClay (%)", row, numLayers);
                physical.ParticleSizeClayMetadata = GetCodeValues(table, "ParticleSizeClayCode", row, numLayers);

                var soilWater = new WaterBalance();
                soilWater.ResourceName = "WaterBalance";
                soil.Children.Add(soilWater);
                soilWater.Thickness   = physical.Thickness;
                soilWater.SummerU     = GetDoubleValue(table, row, "SummerU");
                soilWater.SummerCona  = GetDoubleValue(table, row, "SummerCona");
                soilWater.WinterU     = GetDoubleValue(table, row, "WinterU");
                soilWater.WinterCona  = GetDoubleValue(table, row, "WinterCona");
                soilWater.SummerDate  = GetStringValue(table, row, "SummerDate");
                soilWater.WinterDate  = GetStringValue(table, row, "WinterDate");
                soilWater.Salb        = GetDoubleValue(table, row, "Salb");
                soilWater.DiffusConst = GetDoubleValue(table, row, "DiffusConst");
                soilWater.DiffusSlope = GetDoubleValue(table, row, "DiffusSlope");
                soilWater.CN2Bare     = GetDoubleValue(table, row, "Cn2Bare");
                soilWater.CNRed       = GetDoubleValue(table, row, "CnRed");
                soilWater.CNCov       = GetDoubleValue(table, row, "CnCov");
                soilWater.SWCON       = GetDoubleValues(table, "SWCON (0-1)", row, numLayers);

                var organic = new Organic();
                soil.Children.Add(organic);
                organic.Thickness      = physical.Thickness;
                organic.FOMCNRatio     = GetDoubleValue(table, row, "RootCN");
                organic.FOM            = MathUtilities.CreateArrayOfValues(GetDoubleValue(table, row, "RootWt"), numLayers);
                organic.SoilCNRatio    = GetDoubleValues(table, "SoilCN", row, numLayers);
                organic.FBiom          = GetDoubleValues(table, "FBIOM (0-1)", row, numLayers);
                organic.FInert         = GetDoubleValues(table, "FINERT (0-1)", row, numLayers);
                organic.Carbon         = GetDoubleValues(table, "OC", row, numLayers);
                organic.CarbonMetadata = GetCodeValues(table, "OCCode", row, numLayers);

                var chemical = new Chemical();
                soil.Children.Add(chemical);
                chemical.Thickness   = physical.Thickness;
                chemical.EC          = GetDoubleValues(table, "EC (1:5 dS/m)", row, numLayers);
                chemical.ECMetadata  = GetCodeValues(table, "ECCode", row, numLayers);
                chemical.PH          = GetDoubleValues(table, "PH", row, numLayers);
                chemical.PHMetadata  = GetCodeValues(table, "PHCode", row, numLayers);
                chemical.CL          = GetDoubleValues(table, "CL (mg/kg)", row, numLayers);
                chemical.CLMetadata  = GetCodeValues(table, "CLCode", row, numLayers);
                chemical.ESP         = GetDoubleValues(table, "ESP (%)", row, numLayers);
                chemical.ESPMetadata = GetCodeValues(table, "ESPCode", row, numLayers);

                // Add in some necessary models.
                var soilTemp = new CERESSoilTemperature();
                soil.Children.Add(soilTemp);
                var nutrient = new Nutrients.Nutrient();
                nutrient.ResourceName = "Nutrient";
                soil.Children.Add(nutrient);
                var initialWater = new InitialWater();
                soil.Children.Add(initialWater);

                // crops
                foreach (DataColumn Col in table.Columns)
                {
                    if (Col.ColumnName.ToLower().Contains(" ll"))
                    {
                        var nameBits = Col.ColumnName.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        if (nameBits.Length == 3)
                        {
                            string   cropName = nameBits[0];
                            SoilCrop crop     = new SoilCrop();
                            crop.Name       = cropName + "Soil";
                            crop.LL         = GetDoubleValues(table, cropName + " ll (mm/mm)", row, numLayers);
                            crop.LLMetadata = GetCodeValues(table, cropName + " llCode", row, numLayers);
                            crop.KL         = GetDoubleValues(table, cropName + " kl (/day)", row, numLayers);
                            crop.XF         = GetDoubleValues(table, cropName + " xf (0-1)", row, numLayers);
                            if (MathUtilities.ValuesInArray(crop.LL) ||
                                MathUtilities.ValuesInArray(crop.KL))
                            {
                                physical.Children.Add(crop);
                            }
                        }
                    }
                }

                soils.Add(soil);

                row += numLayers;
            }

            return(soils);
        }
Ejemplo n.º 13
0
        private void MnuActionExport_Click(object sender, EventArgs e)
        {
            sfd.AddExtension                 = true;
            sfd.AutoUpgradeEnabled           = true;
            sfd.DereferenceLinks             = true;
            sfd.Filter                       = "Text Files (*.txt)|*.txt|All Files (*)|*";
            sfd.OverwritePrompt              = true;
            sfd.SupportMultiDottedExtensions = true;
            sfd.ValidateNames                = true;

            var r = sfd.ShowDialog(this);

            if (r == DialogResult.Cancel)
            {
                return;
            }

            var manifest = Manifest;

            using (var fileStream = File.Open(sfd.FileName, FileMode.Create, FileAccess.Write, FileShare.Write)) {
                using (var writer = new StreamWriter(fileStream, MltdConstants.Utf8WithoutBom)) {
                    writer.WriteLine("Asset count: {0}", manifest.Assets.Count.ToString());

                    foreach (var asset in manifest.Assets)
                    {
                        writer.WriteLine();
                        writer.WriteLine("Resource name: {0}", asset.ResourceName);
                        writer.WriteLine("Resource hash: {0}", asset.ContentHash);
                        writer.WriteLine("Remote name: {0}", asset.RemoteName);
                        writer.WriteLine("File size: {0} ({1})", asset.Size.ToString(), MathUtilities.GetHumanReadableFileSize(asset.Size));
                    }
                }
            }

            MessageBox.Show($"Info exported to '{sfd.FileName}'.", ApplicationHelper.GetApplicationTitle(), MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
Ejemplo n.º 14
0
        /// <summary>Main run method for performing our calculations and storing data.</summary>
        /// <param name="dataStore">The data store.</param>
        /// <exception cref="ApsimXException">
        /// Could not find model data table:  + PredictedTableName
        /// or
        /// Could not find observed data table:  + ObservedTableName
        /// </exception>
        public void Run(IDataStore dataStore)
        {
            if (PredictedTableName != null && ObservedTableName != null)
            {
                IEnumerable <string> predictedDataNames = dataStore.Reader.ColumnNames(PredictedTableName);
                IEnumerable <string> observedDataNames  = dataStore.Reader.ColumnNames(ObservedTableName);

                if (predictedDataNames == null)
                {
                    throw new ApsimXException(this, "Could not find model data table: " + PredictedTableName);
                }

                if (observedDataNames == null)
                {
                    throw new ApsimXException(this, "Could not find observed data table: " + ObservedTableName);
                }

                // get the common columns between these lists of columns
                IEnumerable <string> commonCols = predictedDataNames.Intersect(observedDataNames);

                IStorageReader reader         = dataStore.Reader;
                string         match1ObsShort = reader.BriefColumnName(ObservedTableName, FieldNameUsedForMatch);
                string         match2ObsShort = reader.BriefColumnName(ObservedTableName, FieldName2UsedForMatch);
                string         match3ObsShort = reader.BriefColumnName(ObservedTableName, FieldName3UsedForMatch);

                string match1PredShort = reader.BriefColumnName(PredictedTableName, FieldNameUsedForMatch);
                string match2PredShort = reader.BriefColumnName(PredictedTableName, FieldName2UsedForMatch);
                string match3PredShort = reader.BriefColumnName(PredictedTableName, FieldName3UsedForMatch);

                StringBuilder query = new StringBuilder("SELECT ");
                foreach (string s in commonCols)
                {
                    string obsColShort  = reader.BriefColumnName(ObservedTableName, s);
                    string predColShort = reader.BriefColumnName(PredictedTableName, s);
                    if (s == FieldNameUsedForMatch || s == FieldName2UsedForMatch || s == FieldName3UsedForMatch)
                    {
                        query.Append("O.[" + obsColShort + "], ");
                    }
                    else
                    {
                        query.Append("O.[" + obsColShort + "] AS [Observed." + obsColShort + "], P.[" + predColShort + "] AS [Predicted." + predColShort + "], ");
                    }
                }

                query.Append("FROM [" + ObservedTableName + "] O INNER JOIN [" + PredictedTableName + "] P USING ([SimulationID]) WHERE O.[" + match1ObsShort + "] = P.[" + match1PredShort + "]");
                if (FieldName2UsedForMatch != null && FieldName2UsedForMatch != string.Empty)
                {
                    query.Append(" AND O.[" + match2ObsShort + "] = P.[" + match2PredShort + "]");
                }
                if (FieldName3UsedForMatch != null && FieldName3UsedForMatch != string.Empty)
                {
                    query.Append(" AND O.[" + match3ObsShort + "] = P.[" + match3PredShort + "]");
                }

                int checkpointID = dataStore.Writer.GetCheckpointID("Current");
                query.Append(" AND P.[CheckpointID] = " + checkpointID);
                query.Replace(", FROM", " FROM"); // get rid of the last comma
                query.Replace("O.[SimulationID] AS [Observed.SimulationID], P.[SimulationID] AS [Predicted.SimulationID]", "O.[SimulationID] AS [SimulationID]");

                if (Parent is Folder)
                {
                    // Limit it to particular simulations in scope.
                    List <string> simulationNames = new List <string>();
                    foreach (Experiment experiment in Apsim.FindAll(this, typeof(Experiment)))
                    {
                        var names = experiment.GenerateSimulationDescriptions().Select(s => s.Name);
                        simulationNames.AddRange(names);
                    }

                    foreach (Simulation simulation in Apsim.FindAll(this, typeof(Simulation)))
                    {
                        if (!(simulation.Parent is Experiment))
                        {
                            simulationNames.Add(simulation.Name);
                        }
                    }

                    query.Append(" AND O.[SimulationID] in (");
                    foreach (string simulationName in simulationNames)
                    {
                        if (simulationName != simulationNames[0])
                        {
                            query.Append(',');
                        }
                        query.Append(dataStore.Writer.GetSimulationID(simulationName, null));
                    }
                    query.Append(")");
                }

                DataTable predictedObservedData = reader.GetDataUsingSql(query.ToString());

                if (predictedObservedData != null)
                {
                    foreach (DataColumn column in predictedObservedData.Columns)
                    {
                        if (column.ColumnName.StartsWith("Predicted."))
                        {
                            string shortName = column.ColumnName.Substring("Predicted.".Length);
                            column.ColumnName = "Predicted." + reader.FullColumnName(PredictedTableName, shortName);
                        }
                        else if (column.ColumnName.StartsWith("Observed."))
                        {
                            string shortName = column.ColumnName.Substring("Observed.".Length);
                            column.ColumnName = "Observed." + reader.FullColumnName(ObservedTableName, shortName);
                        }
                        else if (column.ColumnName.Equals(match1ObsShort) || column.ColumnName.Equals(match2ObsShort) || column.ColumnName.Equals(match3ObsShort))
                        {
                            column.ColumnName = reader.FullColumnName(ObservedTableName, column.ColumnName);
                        }
                    }

                    // Add in error columns for each data column.
                    foreach (string columnName in commonCols)
                    {
                        if (predictedObservedData.Columns.Contains("Predicted." + columnName) &&
                            predictedObservedData.Columns["Predicted." + columnName].DataType == typeof(double))
                        {
                            var predicted = DataTableUtilities.GetColumnAsDoubles(predictedObservedData, "Predicted." + columnName);
                            var observed  = DataTableUtilities.GetColumnAsDoubles(predictedObservedData, "Observed." + columnName);
                            if (predicted.Length > 0 && predicted.Length == observed.Length)
                            {
                                var errorData       = MathUtilities.Subtract(predicted, observed);
                                var errorColumnName = "Pred-Obs." + columnName;
                                var errorColumn     = predictedObservedData.Columns.Add(errorColumnName, typeof(double));
                                DataTableUtilities.AddColumn(predictedObservedData, errorColumnName, errorData);
                                predictedObservedData.Columns[errorColumnName].SetOrdinal(predictedObservedData.Columns["Predicted." + columnName].Ordinal + 1);
                            }
                        }
                    }

                    // Write table to datastore.
                    predictedObservedData.TableName = this.Name;
                    dataStore.Writer.WriteTable(predictedObservedData);

                    List <string> unitFieldNames = new List <string>();
                    List <string> unitNames      = new List <string>();

                    // write units to table.
                    reader.Refresh();

                    foreach (string fieldName in commonCols)
                    {
                        string units = reader.Units(PredictedTableName, fieldName);
                        if (units != null && units != "()")
                        {
                            string unitsMinusBrackets = units.Replace("(", "").Replace(")", "");
                            unitFieldNames.Add("Predicted." + fieldName);
                            unitNames.Add(unitsMinusBrackets);
                            unitFieldNames.Add("Observed." + fieldName);
                            unitNames.Add(unitsMinusBrackets);
                        }
                    }

                    if (unitNames.Count > 0)
                    {
                        // The Writer replaces tables, rather than appends to them,
                        // so we actually need to re-write the existing units table values
                        // Is there a better way to do this?
                        DataView allUnits = new DataView(reader.GetData("_Units"));
                        allUnits.Sort = "TableName";
                        DataTable tableNames = allUnits.ToTable(true, "TableName");
                        foreach (DataRow row in tableNames.Rows)
                        {
                            string        tableName = row["TableName"] as string;
                            List <string> colNames  = new List <string>();
                            List <string> unitz     = new List <string>();
                            foreach (DataRowView rowView in allUnits.FindRows(tableName))
                            {
                                colNames.Add(rowView["ColumnHeading"].ToString());
                                unitz.Add(rowView["Units"].ToString());
                            }
                            dataStore.Writer.AddUnits(tableName, colNames, unitz);
                        }
                        dataStore.Writer.AddUnits(Name, unitFieldNames, unitNames);
                    }
                }
                else
                {
                    // Determine what went wrong.
                    DataTable predictedData = reader.GetDataUsingSql("SELECT * FROM [" + PredictedTableName + "]");
                    DataTable observedData  = reader.GetDataUsingSql("SELECT * FROM [" + ObservedTableName + "]");
                    if (predictedData == null || predictedData.Rows.Count == 0)
                    {
                        throw new Exception(Name + ": Cannot find any predicted data.");
                    }
                    else if (observedData == null || observedData.Rows.Count == 0)
                    {
                        throw new Exception(Name + ": Cannot find any observed data in node: " + ObservedTableName + ". Check for missing observed file or move " + ObservedTableName + " to top of child list under DataStore (order is important!)");
                    }
                    else
                    {
                        throw new Exception(Name + ": Observed data was found but didn't match the predicted values. Make sure the values in the SimulationName column match the simulation names in the user interface. Also ensure column names in the observed file match the APSIM report column names.");
                    }
                }
            }
        }
Ejemplo n.º 15
0
        private void StoreWaterVariablesForNitrogenUptake(ZoneWaterAndN zoneWater)
        {
            ZoneState myZone = root.Zones.Find(z => z.Name == zoneWater.Zone.Name);

            if (myZone != null)
            {
                //store Water variables for N Uptake calculation
                //Old sorghum doesn't do actualUptake of Water until end of day
                myZone.StartWater           = new double[myZone.soil.Thickness.Length];
                myZone.AvailableSW          = new double[myZone.soil.Thickness.Length];
                myZone.PotentialAvailableSW = new double[myZone.soil.Thickness.Length];
                myZone.Supply = new double[myZone.soil.Thickness.Length];

                var      soilCrop = Soil.Crop(Plant.Name);
                double[] kl       = soilCrop.KL;

                double[] llDep = MathUtilities.Multiply(soilCrop.LL, myZone.soil.Thickness);

                if (root.Depth != myZone.Depth)
                {
                    myZone.Depth += 0; // wtf??
                }
                var currentLayer           = myZone.soil.LayerIndexOfDepth(myZone.Depth);
                var currentLayerProportion = myZone.soil.ProportionThroughLayer(currentLayer, myZone.Depth);
                for (int layer = 0; layer <= currentLayer; ++layer)
                {
                    myZone.StartWater[layer] = myZone.soil.Water[layer];

                    myZone.AvailableSW[layer]          = Math.Max(myZone.soil.Water[layer] - llDep[layer], 0);
                    myZone.PotentialAvailableSW[layer] = myZone.soil.DULmm[layer] - llDep[layer];

                    if (layer == currentLayer)
                    {
                        myZone.AvailableSW[layer]          *= currentLayerProportion;
                        myZone.PotentialAvailableSW[layer] *= currentLayerProportion;
                    }

                    var proportion = root.rootProportionInLayer(layer, myZone);
                    myZone.Supply[layer] = Math.Max(myZone.AvailableSW[layer] * kl[layer] * proportion, 0.0);
                }
                var totalAvail    = myZone.AvailableSW.Sum();
                var totalAvailPot = myZone.PotentialAvailableSW.Sum();
                var totalSupply   = myZone.Supply.Sum();
                WatSupply = totalSupply;

                // Set reporting variables.
                Avail         = myZone.AvailableSW;
                PotAvail      = myZone.PotentialAvailableSW;
                TotalAvail    = myZone.AvailableSW.Sum();
                TotalPotAvail = myZone.PotentialAvailableSW.Sum();

                //used for SWDef PhenologyStress table lookup
                SWAvailRatio = MathUtilities.Bound(MathUtilities.Divide(totalAvail, totalAvailPot, 1.0), 0.0, 10.0);

                //used for SWDef ExpansionStress table lookup
                SDRatio = MathUtilities.Bound(MathUtilities.Divide(totalSupply, WDemand, 1.0), 0.0, 10);

                //used for SwDefPhoto Stress
                PhotoStress = MathUtilities.Bound(MathUtilities.Divide(totalSupply, WDemand, 1.0), 0.0, 1.0);
            }
        }
Ejemplo n.º 16
0
        private void OnDoSoilOrganicMatter(object sender, EventArgs e)
        {
            NutrientPool source = Parent as NutrientPool;

            double[] NH4 = solutes.GetSolute("NH4");
            double[] NO3 = solutes.GetSolute("NO3");

            for (int i = 0; i < source.C.Length; i++)
            {
                double carbonFlowFromSource   = Rate.Value(i) * source.C[i];
                double nitrogenFlowFromSource = MathUtilities.Divide(carbonFlowFromSource, source.CNRatio[i], 0);

                double[] carbonFlowToDestination   = new double[destinations.Count];
                double[] nitrogenFlowToDestination = new double[destinations.Count];

                for (int j = 0; j < destinations.Count; j++)
                {
                    carbonFlowToDestination[j]   = carbonFlowFromSource * CO2Efficiency.Value(i) * destinationFraction[j];
                    nitrogenFlowToDestination[j] = MathUtilities.Divide(carbonFlowToDestination[j], destinations[j].CNRatio[i], 0.0);
                }

                double TotalNitrogenFlowToDestinations = MathUtilities.Sum(nitrogenFlowToDestination);
                double NSupply = nitrogenFlowFromSource + NO3[i] + NH4[i];

                if (MathUtilities.Sum(nitrogenFlowToDestination) > NSupply)
                {
                    double NSupplyFactor = MathUtilities.Bound(MathUtilities.Divide(NO3[i] + NH4[i], TotalNitrogenFlowToDestinations - nitrogenFlowFromSource, 1.0), 0.0, 1.0);

                    for (int j = 0; j < destinations.Count; j++)
                    {
                        carbonFlowToDestination[j]   *= NSupplyFactor;
                        nitrogenFlowToDestination[j] *= NSupplyFactor;
                        if (nitrogenFlowToDestination[j] > 0.5)
                        {
                        }
                    }
                    TotalNitrogenFlowToDestinations *= NSupplyFactor;

                    carbonFlowFromSource   *= NSupplyFactor;
                    nitrogenFlowFromSource *= NSupplyFactor;
                }

                source.C[i] -= carbonFlowFromSource;
                source.N[i] -= nitrogenFlowFromSource;
                for (int j = 0; j < destinations.Count; j++)
                {
                    destinations[j].C[i] += carbonFlowToDestination[j];
                    destinations[j].N[i] += nitrogenFlowToDestination[j];
                }


                if (TotalNitrogenFlowToDestinations <= nitrogenFlowFromSource)
                {
                    NH4[i] += nitrogenFlowFromSource - TotalNitrogenFlowToDestinations;
                }
                else
                {
                    double NDeficit          = TotalNitrogenFlowToDestinations - nitrogenFlowFromSource;
                    double NH4Immobilisation = Math.Min(NH4[i], NDeficit);
                    NH4[i]   -= NH4Immobilisation;
                    NDeficit -= NH4Immobilisation;

                    double NO3Immobilisation = Math.Min(NO3[i], NDeficit);
                    NO3[i]   -= NO3Immobilisation;
                    NDeficit -= NO3Immobilisation;

                    if (MathUtilities.IsGreaterThan(NDeficit, 0.0))
                    {
                        throw new Exception("Insufficient mineral N for immobilisation demand for C flow " + Name);
                    }
                }
            }
            solutes.SetSolute("NH4", SoluteManager.SoluteSetterType.Soil, NH4);
            solutes.SetSolute("NO3", SoluteManager.SoluteSetterType.Soil, NO3);
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Calculate the potential N uptake for today. Should return null if crop is not in the ground (this is not true for old sorghum).
        /// </summary>
        public override List <Soils.Arbitrator.ZoneWaterAndN> GetNitrogenUptakeEstimates(SoilState soilstate)
        {
            if (Plant.IsEmerged)
            {
                var nSupply = 0.0;//NOTE: This is in kg, not kg/ha, to arbitrate N demands for spatial simulations.

                //this function is called 4 times as part of estimates
                //shouldn't set public variables in here

                var grainIndex = 0;
                var rootIndex  = 1;
                var leafIndex  = 2;
                var stemIndex  = 4;

                var rootDemand  = N.StructuralDemand[rootIndex] + N.MetabolicDemand[rootIndex];
                var stemDemand  = /*N.StructuralDemand[stemIndex] + */ N.MetabolicDemand[stemIndex];
                var leafDemand  = N.MetabolicDemand[leafIndex];
                var grainDemand = N.StructuralDemand[grainIndex] + N.MetabolicDemand[grainIndex];
                //have to correct the leaf demand calculation
                var leaf           = Organs[leafIndex] as SorghumLeaf;
                var leafAdjustment = leaf.calculateClassicDemandDelta();

                //double NDemand = (N.TotalPlantDemand - N.TotalReallocation) / kgha2gsm * Plant.Zone.Area; //NOTE: This is in kg, not kg/ha, to arbitrate N demands for spatial simulations.
                //old sorghum uses g/m^2 - need to convert after it is used to calculate actual diffusion
                // leaf adjustment is not needed here because it is an adjustment for structural demand - we only look at metabolic here.

                // dh - In old sorghum, root only has one type of NDemand - it doesn't have a structural/metabolic division.
                // In new apsim, root only uses structural, metabolic is always 0. Therefore, we have to include root's structural
                // NDemand in this calculation.

                // dh - In old sorghum, totalDemand is metabolic demand for all organs. However in new apsim, grain has no metabolic
                // demand, so we must include its structural demand in this calculation.
                double totalDemand         = N.TotalMetabolicDemand + N.StructuralDemand[rootIndex] + N.StructuralDemand[grainIndex];
                double nDemand             = Math.Max(0, totalDemand - grainDemand); // to replicate calcNDemand in old sorghum
                List <ZoneWaterAndN> zones = new List <ZoneWaterAndN>();

                foreach (ZoneWaterAndN zone in soilstate.Zones)
                {
                    ZoneWaterAndN UptakeDemands = new ZoneWaterAndN(zone.Zone);

                    UptakeDemands.NO3N = new double[zone.NO3N.Length];
                    UptakeDemands.NH4N = new double[zone.NH4N.Length];
                    UptakeDemands.PlantAvailableNO3N = new double[zone.NO3N.Length];
                    UptakeDemands.PlantAvailableNH4N = new double[zone.NO3N.Length];
                    UptakeDemands.Water = new double[UptakeDemands.NO3N.Length];

                    //only using Root to get Nitrogen from - temporary code for sorghum
                    var root = Organs[rootIndex] as Root;

                    //Get Nuptake supply from each organ and set the PotentialUptake parameters that are passed to the soil arbitrator

                    //at present these 2arrays arenot being used within the CalculateNitrogenSupply function
                    //sorghum uses Diffusion & Massflow variables currently
                    double[] organNO3Supply = new double[zone.NO3N.Length]; //kg/ha - dltNo3 in old apsim
                    double[] organNH4Supply = new double[zone.NH4N.Length];

                    ZoneState myZone = root.Zones.Find(z => z.Name == zone.Zone.Name);
                    if (myZone != null)
                    {
                        CalculateNitrogenSupply(myZone, zone);

                        //new code
                        double[] diffnAvailable = new double[myZone.Diffusion.Length];
                        for (var i = 0; i < myZone.Diffusion.Length; ++i)
                        {
                            diffnAvailable[i] = myZone.Diffusion[i] - myZone.MassFlow[i];
                        }
                        var totalMassFlow  = MathUtilities.Sum(myZone.MassFlow); //g/m^2
                        var totalDiffusion = MathUtilities.Sum(diffnAvailable);  //g/m^2

                        var potentialSupply   = totalMassFlow + totalDiffusion;
                        var actualDiffusion   = 0.0;
                        var actualMassFlow    = DltTT > 0 ? totalMassFlow : 0.0;
                        var maxDiffusionConst = root.MaxDiffusion.Value();

                        double NUptakeCease = (Apsim.Find(this, "NUptakeCease") as Functions.IFunction).Value();
                        if (TTFMFromFlowering > NUptakeCease)
                        {
                            totalMassFlow = 0;
                        }
                        actualMassFlow = totalMassFlow;

                        if (totalMassFlow < nDemand && TTFMFromFlowering < NUptakeCease) // fixme && ttElapsed < nUptakeCease
                        {
                            actualDiffusion = MathUtilities.Bound(nDemand - totalMassFlow, 0.0, totalDiffusion);
                            actualDiffusion = MathUtilities.Divide(actualDiffusion, maxDiffusionConst, 0.0);

                            var nsupplyFraction = root.NSupplyFraction.Value();
                            var maxRate         = root.MaxNUptakeRate.Value();

                            var maxUptakeRateFrac = Math.Min(1.0, (potentialSupply / root.NSupplyFraction.Value())) * root.MaxNUptakeRate.Value();
                            var maxUptake         = Math.Max(0, maxUptakeRateFrac * DltTT - actualMassFlow);
                            actualDiffusion = Math.Min(actualDiffusion, maxUptake);
                        }

                        NDiffusionSupply = actualDiffusion;
                        NMassFlowSupply  = actualMassFlow;

                        //adjust diffusion values proportionally
                        //make sure organNO3Supply is in kg/ha
                        for (int layer = 0; layer < organNO3Supply.Length; layer++)
                        {
                            var massFlowLayerFraction  = MathUtilities.Divide(myZone.MassFlow[layer], totalMassFlow, 0.0);
                            var diffusionLayerFraction = MathUtilities.Divide(diffnAvailable[layer], totalDiffusion, 0.0);
                            //organNH4Supply[layer] = massFlowLayerFraction * root.MassFlow[layer];
                            organNO3Supply[layer] = (massFlowLayerFraction * actualMassFlow +
                                                     diffusionLayerFraction * actualDiffusion) / kgha2gsm; //convert to kg/ha
                        }
                    }
                    //originalcode
                    UptakeDemands.NO3N = MathUtilities.Add(UptakeDemands.NO3N, organNO3Supply); //Add uptake supply from each organ to the plants total to tell the Soil arbitrator
                    if (UptakeDemands.NO3N.Any(n => MathUtilities.IsNegative(n)))
                    {
                        throw new Exception("-ve no3 uptake demand");
                    }
                    UptakeDemands.NH4N = MathUtilities.Add(UptakeDemands.NH4N, organNH4Supply);

                    N.UptakeSupply[rootIndex] += MathUtilities.Sum(organNO3Supply) * kgha2gsm * zone.Zone.Area / Plant.Zone.Area;  //g/m2
                    if (MathUtilities.IsNegative(N.UptakeSupply[rootIndex]))
                    {
                        throw new Exception($"-ve uptake supply for organ {(Organs[rootIndex] as IModel).Name}");
                    }
                    nSupply += MathUtilities.Sum(organNO3Supply) * zone.Zone.Area;
                    zones.Add(UptakeDemands);
                }

                return(zones);
            }
            return(null);
        }
Ejemplo n.º 18
0
    public void DoBuild(Tile t)
    {
        if (buildMode == BuildMode.FURNITURE)
        {
            // Create the Furniture and assign it to the tile
            // Can we build the furniture in the selected tile?
            // Run the ValidPlacement function!
            string furnitureType = buildModeObjectType;

            if (
                WorldController.Instance.World.IsFurniturePlacementValid(furnitureType, t) &&
                DoesBuildJobOverlapExistingBuildJob(t, furnitureType) == false)
            {
                // This tile position is valid for this furniture

                // Check if there is existing furniture in this tile. If so delete it.
                // TODO Possibly return resources. Will the Deconstruct() method handle that? If so what will happen if resources drop ontop of new non-passable structure.
                if (t.Furniture != null)
                {
                    t.Furniture.Deconstruct();
                }

                // Create a job for it to be build
                Job j;

                if (PrototypeManager.FurnitureJob.HasPrototype(furnitureType))
                {
                    // Make a clone of the job prototype
                    j = PrototypeManager.FurnitureJob.GetPrototype(furnitureType).Clone();

                    // Assign the correct tile.
                    j.tile = t;
                }
                else
                {
                    Debug.ULogErrorChannel("BuildModeController", "There is no furniture job prototype for '" + furnitureType + "'");
                    j = new Job(t, furnitureType, FurnitureActions.JobComplete_FurnitureBuilding, 0.1f, null, Job.JobPriority.High);
                    j.JobDescription = "job_build_" + furnitureType + "_desc";
                }

                j.furniturePrototype = PrototypeManager.Furniture.GetPrototype(furnitureType);

                // Add the job to the queue or build immediately if in dev mode
                if (Settings.GetSetting("DialogBoxSettings_developerModeToggle", false))
                {
                    WorldController.Instance.World.PlaceFurniture(j.JobObjectType, j.tile);
                }
                else
                {
                    for (int x_off = t.X; x_off < (t.X + j.furniturePrototype.Width); x_off++)
                    {
                        for (int y_off = t.Y; y_off < (t.Y + j.furniturePrototype.Height); y_off++)
                        {
                            // FIXME: I don't like having to manually and explicitly set
                            // flags that preven conflicts. It's too easy to forget to set/clear them!
                            Tile offsetTile = WorldController.Instance.World.GetTileAt(x_off, y_off, t.Z);
                            offsetTile.PendingBuildJob = j;
                            j.OnJobStopped            += (theJob) =>
                            {
                                offsetTile.PendingBuildJob = null;
                            };
                        }
                    }

                    WorldController.Instance.World.jobQueue.Enqueue(j);
                }
            }
        }
        else if (buildMode == BuildMode.FLOOR)
        {
            // We are in tile-changing mode.
            ////t.Type = buildModeTile;

            TileType tileType = buildModeTile;

            if (
                t.Type != tileType &&
                t.Furniture == null &&
                t.PendingBuildJob == null &&
                CanBuildTileTypeHere(t, tileType))
            {
                // This tile position is valid tile type

                // Create a job for it to be build
                Job j = TileType.GetConstructionJobPrototype(tileType);

                j.tile = t;

                // Add the job to the queue or build immediately if in dev mode
                if (Settings.GetSetting("DialogBoxSettings_developerModeToggle", false))
                {
                    j.tile.Type = j.JobTileType;
                }
                else
                {
                    // FIXME: I don't like having to manually and explicitly set
                    // flags that preven conflicts. It's too easy to forget to set/clear them!
                    t.PendingBuildJob = j;
                    j.OnJobStopped   += (theJob) =>
                    {
                        theJob.tile.PendingBuildJob = null;
                    };

                    WorldController.Instance.World.jobQueue.Enqueue(j);
                }
            }
        }
        else if (buildMode == BuildMode.DECONSTRUCT)
        {
            // TODO
            if (t.Furniture != null)
            {
                // check if this is a WALL neighbouring a pressured and pressureless environ & if so bail
                if (t.Furniture.HasTypeTag("Wall"))
                {
                    Tile[] neighbors          = t.GetNeighbours(); // diagOkay??
                    int    pressuredNeighbors = 0;
                    int    vacuumNeighbors    = 0;
                    foreach (Tile neighbor in neighbors)
                    {
                        if (neighbor != null && neighbor.Room != null)
                        {
                            if ((neighbor.Room == World.Current.GetOutsideRoom()) || MathUtilities.IsZero(neighbor.Room.GetTotalGasPressure()))
                            {
                                vacuumNeighbors++;
                            }
                            else
                            {
                                pressuredNeighbors++;
                            }
                        }
                    }

                    if (vacuumNeighbors > 0 && pressuredNeighbors > 0)
                    {
                        Debug.ULogChannel("BuildModeController", "Someone tried to deconstruct a wall between a pressurised room and vacuum!");
                        return;
                    }
                }

                t.Furniture.Deconstruct();
            }
            else if (t.PendingBuildJob != null)
            {
                t.PendingBuildJob.CancelJob();
            }
        }
        else
        {
            Debug.ULogErrorChannel("BuildModeController", "UNIMPLEMENTED BUILD MODE");
        }
    }
Ejemplo n.º 19
0
        /// <summary>
        /// Calculate the potential sw uptake for today
        /// </summary>
        public List <ZoneWaterAndN> GetWaterUptakeEstimates(SoilState soilstate)
        {
            if (Plant.IsAlive)
            {
                // Get all water supplies.
                double waterSupply = 0;  //NOTE: This is in L, not mm, to arbitrate water demands for spatial simulations.

                List <double[]>      supplies = new List <double[]>();
                List <ZoneWaterAndN> zones    = new List <ZoneWaterAndN>();
                foreach (ZoneWaterAndN zone in soilstate.Zones)
                {
                    foreach (IOrgan o in Organs)
                    {
                        if (o is IWaterNitrogenUptake)
                        {
                            double[] organSupply = (o as IWaterNitrogenUptake).CalculateWaterSupply(zone);
                            if (organSupply != null)
                            {
                                supplies.Add(organSupply);
                                zones.Add(zone);
                                waterSupply += MathUtilities.Sum(organSupply) * zone.Zone.Area;
                            }
                        }
                    }
                }

                // Calculate total water demand.
                double waterDemand = 0; //NOTE: This is in L, not mm, to arbitrate water demands for spatial simulations.

                foreach (IHasWaterDemand WD in WaterDemands)
                {
                    waterDemand += WD.CalculateWaterDemand() * Plant.Zone.Area;
                }

                // Calculate demand / supply ratio.
                double fractionUsed = 0;
                if (waterSupply > 0)
                {
                    fractionUsed = Math.Min(1.0, waterDemand / waterSupply);
                }

                // Apply demand supply ratio to each zone and create a ZoneWaterAndN structure
                // to return to caller.
                List <ZoneWaterAndN> ZWNs = new List <ZoneWaterAndN>();
                for (int i = 0; i < supplies.Count; i++)
                {
                    // Just send uptake from my zone
                    ZoneWaterAndN uptake = new ZoneWaterAndN(zones[i]);
                    uptake.Water = MathUtilities.Multiply_Value(supplies[i], fractionUsed);
                    uptake.NO3N  = new double[uptake.Water.Length];
                    uptake.NH4N  = new double[uptake.Water.Length];
                    uptake.PlantAvailableNO3N = new double[uptake.Water.Length];
                    uptake.PlantAvailableNH4N = new double[uptake.Water.Length];
                    ZWNs.Add(uptake);
                }
                return(ZWNs);
            }
            else
            {
                return(null);
            }
        }
Ejemplo n.º 20
0
        /// <summary>calculate actual evaporation from soil surface (es)</summary>
        public void CalcEs()
        {
            //es          -> ! (output) actual evaporation (mm)
            //eos         -> ! (input) potential rate of evaporation (mm/day)
            //avail_sw_top -> ! (input) upper limit of soil evaporation (mm/day)  !sv- now calculated in here, not passed in as a argument.

            // Most es takes place in two stages: the constant rate stage
            // and the falling rate stage (philip, 1957).  in the constant
            // rate stage (stage 1), the soil is sufficiently wet for water
            // be transported to the surface at a rate at least equal to the
            // evaporation potential (eos).
            // in the falling rate stage (stage 2), the surface soil water
            // content has decreased below a threshold value, so that es
            // depends on the flux of water through the upper layer of soil
            // to the evaporating site near the surface.

            // This changes globals - sumes1/2 and t.

            Es = 0.0;

            // Calculate available soil water in top layer for actual soil evaporation (mm)
            double avail_sw_top = soil.Water[0] - soil.Properties.Water.AirDry[0];

            avail_sw_top = MathUtilities.Bound(avail_sw_top, 0.0, Eo);

            // Calculate actual soil water evaporation
            double esoil1;     // actual soil evap in stage 1
            double esoil2;     // actual soil evap in stage 2

            // if infiltration, reset sumes1
            // reset sumes2 if infil exceeds sumes1
            if (soil.Infiltration > 0.0)
            {
                sumes2 = Math.Max(0.0, (sumes2 - Math.Max(0.0, soil.Infiltration - sumes1)));
                sumes1 = Math.Max(0.0, sumes1 - soil.Infiltration);

                // update t (incase sumes2 changed)
                t = MathUtilities.Sqr(MathUtilities.Divide(sumes2, CONA, 0.0));
            }
            else
            {
                // no infiltration, no re-set.
            }

            // are we in stage1 ?
            if (sumes1 < U)
            {
                // we are in stage1
                // set esoil1 = potential, or limited by u.
                esoil1 = Math.Min(Eos, U - sumes1);

                if ((Eos > esoil1) && (esoil1 < avail_sw_top))
                {
                    // eos not satisfied by 1st stage drying,
                    // & there is evaporative sw excess to air_dry, allowing for esoil1.
                    // need to calc. some stage 2 drying(esoil2).

                    if (sumes2 > 0.0)
                    {
                        t      = t + 1.0;
                        esoil2 = Math.Min((Eos - esoil1), (CONA * Math.Pow(t, 0.5) - sumes2));
                    }
                    else
                    {
                        esoil2 = 0.6 * (Eos - esoil1);
                    }
                }
                else
                {
                    // no deficit (or esoil1 = eos_max) no esoil2 on this day
                    esoil2 = 0.0;
                }

                // check any esoil2 with lower limit of evaporative sw.
                esoil2 = Math.Min(esoil2, avail_sw_top - esoil1);


                // update 1st and 2nd stage soil evaporation.
                sumes1 = sumes1 + esoil1;
                sumes2 = sumes2 + esoil2;
                t      = MathUtilities.Sqr(MathUtilities.Divide(sumes2, CONA, 0.0));
            }
            else
            {
                // no 1st stage drying. calc. 2nd stage
                esoil1 = 0.0;

                t      = t + 1.0;
                esoil2 = Math.Min(Eos, (CONA * Math.Pow(t, 0.5) - sumes2));

                // check with lower limit of evaporative sw.
                esoil2 = Math.Min(esoil2, avail_sw_top);

                //   update 2nd stage soil evaporation.
                sumes2 = sumes2 + esoil2;
            }

            Es = esoil1 + esoil2;

            // make sure we are within bounds
            Es = MathUtilities.Bound(Es, 0.0, Eos);
            Es = MathUtilities.Bound(Es, 0.0, avail_sw_top);
        }
Ejemplo n.º 21
0
 public bool ShouldSerializetransmissionFactor()
 {
     return(this.transmissionFactor != null && !MathUtilities.IsAlmostEqualTo(this.transmissionFactor.Value, 0f, float.Epsilon));
 }
Ejemplo n.º 22
0
        IEnumerator State()
        {
            y_push = sprite.Height;
            player.grid_entrance = MapUtilities.GetRoomUpperLeftPos(GlobalState.CurrentMapGrid) + Vector2.One * 20;

            GlobalState.SpawnEntity(new VolumeEvent(0, 3));

            while (MapUtilities.GetInGridPosition(player.Position).X < 48)
            {
                yield return(null);
            }

            GlobalState.Dialogue = Dialogue.DialogueManager.GetDialogue("redboss", "before_fight");

            float push_timer = 0f;

            loopSFX = true;
            while (!GlobalState.LastDialogueFinished)
            {
                push_timer += GameTimes.DeltaTime;
                if (push_timer >= push_tick_max)
                {
                    push_timer = 0f;
                    if (y_push > 0)
                    {
                        GlobalState.screenShake.Shake(0.021f, 0.1f);
                        y_push--;
                    }
                }
                yield return(null);
            }
            loopSFX = false;

            SoundManager.PlaySong("redcave-boss");
            Play("bob");

            IState state = new StateMachineBuilder()
                           .State <SplashState>("Splash")
                           .Enter((s) => amp = 5)
                           .Event("Splash", (s) =>
            {
                splash_bullets.Spawn(b => b.Spawn(), 4);
            })
                           .Event("Tentacles", (s) =>
            {
                SpawnTentacles();
                if (proximity_hits != Touching.NONE)
                {
                    s.got_too_close++;
                    if (s.got_too_close == 2)
                    {
                        s.got_too_close = 0;
                        s.Parent.ChangeState("Stun");
                    }
                }
            })
                           .End()
                           .State <DashState>("Dash")
                           .Enter((s) =>
            {
                amp      = 0;
                velocity = new Vector2(30, 20);
                Play("bob");
            })
                           .Update((s, _) =>
            {
                Drawing.Effects.ScreenShake.Directions dirs = new();
                Vector2 tl = MapUtilities.GetInGridPosition(Position);
                Vector2 br = MapUtilities.GetInGridPosition(Position + new Vector2(width, height));
                if (tl.Y < 2 * 16)
                {
                    velocity.Y = 60;
                    dirs      |= Drawing.Effects.ScreenShake.Directions.Vertical;
                }
                else if (br.Y > 16 * 8)
                {
                    velocity.Y = -60;
                    dirs      |= Drawing.Effects.ScreenShake.Directions.Vertical;
                }

                if (tl.X < 2 * 16)
                {
                    velocity.X = 60;
                    dirs      |= Drawing.Effects.ScreenShake.Directions.Horizontal;
                }
                else if (br.X > 16 * 8)
                {
                    velocity.X = -60;
                    dirs      |= Drawing.Effects.ScreenShake.Directions.Horizontal;
                }
                GlobalState.screenShake.Shake(0.05f, 0.1f, dirs);
            })
                           .Event("Tentacles", (s) =>
            {
                SpawnTentacles();
                if (proximity_hits != Touching.NONE)
                {
                    s.got_too_close++;
                    if (s.got_too_close == 2)
                    {
                        s.got_too_close = 0;
                        s.Parent.ChangeState("Splash");
                    }
                }
            })
                           .Event("EndDash", (s) =>
            {
                s.Parent.ChangeState("Stun");
            })
                           .Exit((s) => velocity = Vector2.Zero)
                           .End()
                           .State <StunState>("Stun")
                           .Enter((s) => s.stateLogic = StunStateLogic())
                           .Update((s, _) =>
            {
                if (!s.stateLogic.MoveNext())
                {
                    s.Parent.ChangeState("Dash");
                }
            })
                           .End()
                           .Build();

            state.ChangeState("Splash");
            state.TriggerEvent("Splash"); //First time instantly fires splash bullets

            while (health > 0)
            {
                state.Update(GameTimes.DeltaTime);

                pushdown_timer += GameTimes.DeltaTime * 3;
                y_push          = (int)(amp + MathF.Sin(pushdown_timer) * amp);
                yield return(null);
            }

            velocity = Vector2.Zero;

            SoundManager.StopSong();
            GlobalState.Dialogue = Dialogue.DialogueManager.GetDialogue("redboss", "after_fight");
            GlobalState.screenShake.Shake(0.05f, 0.1f);
            GlobalState.flash.Flash(1f, Color.Red);

            while (!GlobalState.LastDialogueFinished)
            {
                yield return(null);
            }

            Play("die");
            SoundManager.PlaySoundEffect("redboss_death");
            GlobalState.wave.active = true;

            y_push = 0;

            while (y_push < sprite.Height)
            {
                MathUtilities.MoveTo(ref ripple.opacity, 0, 0.3f);

                push_timer += GameTimes.DeltaTime;
                if (push_timer >= push_tick_max)
                {
                    push_timer = 0f;
                    y_push++;
                }
                yield return(null);
            }

            float final_timer = 2f;

            while (final_timer > 0f)
            {
                final_timer -= GameTimes.DeltaTime;
                yield return(null);
            }

            preset.Alive            = exists = false;
            GlobalState.wave.active = false;
            SoundManager.PlaySong("redcave");
            GlobalState.events.BossDefeated.Add("REDCAVE");
            yield break;
        }
Ejemplo n.º 23
0
        /// <summary>
        /// Finds a large inscribed rectangle. Tries to be maximal but this is
        /// best effort. The algorithm used was inspired by the blog post
        /// https://d3plus.org/blog/behind-the-scenes/2014/07/08/largest-rect/
        /// Random points within the polygon are chosen, and then 2 lines are
        /// drawn through those points. The midpoints of those lines are
        /// used as the center of various rectangles, using a binary search to
        /// vary the size, until the largest fit-able rectangle is found.
        /// This is then repeated for predefined angles (0-180 in steps of 15)
        /// and aspect ratios (1 to 15 in steps of 0.5).
        /// </summary>
        /// <param name="geometryEdges">The boundary geometry.</param>
        /// <param name="randomSeed">Random number generator seed.</param>
        /// <remarks>
        /// For the most reproducible results, use the same randomSeed value
        /// each time this method is called.
        /// </remarks>
        public InscribedRectangle(Edge[] geometryEdges, int randomSeed)
        {
            // Clear previous rectangle
            Center = EdgeUtilities.InvalidPoint;
            Width  = 0;
            Height = 0;
            Angle  = 0;

            float minX = EdgeUtilities.maxWidth;
            float minY = EdgeUtilities.maxWidth;
            float maxX = -EdgeUtilities.maxWidth;
            float maxY = -EdgeUtilities.maxWidth;

            // Find min x, min y, max x, max y
            for (int i = 0; i < geometryEdges.Length; i++)
            {
                Edge edge = geometryEdges[i];

                if ((edge.PointA.x < minX) || (edge.PointB.x < minX))
                {
                    minX = Mathf.Min(edge.PointA.x, edge.PointB.x);
                }

                if ((edge.PointA.y < minY) || (edge.PointB.y < minY))
                {
                    minY = Mathf.Min(edge.PointA.y, edge.PointB.y);
                }

                if ((edge.PointA.x > maxX) || (edge.PointB.x > maxX))
                {
                    maxX = Mathf.Max(edge.PointA.x, edge.PointB.x);
                }

                if ((edge.PointA.y > maxY) || (edge.PointB.y > maxY))
                {
                    maxY = Mathf.Min(edge.PointA.y, edge.PointB.y);
                }
            }

            // Generate random points until we have randomPointCount starting points
            Vector2[] startingPoints = new Vector2[randomPointCount];
            {
                System.Random random = new System.Random(randomSeed);
                for (int i = 0; i < startingPoints.Length; i++)
                {
                    Vector2 candidatePoint;

                    do
                    {
                        candidatePoint.x = ((float)random.NextDouble() * (maxX - minX)) + minX;
                        candidatePoint.y = ((float)random.NextDouble() * (maxY - minY)) + minY;
                    }while (!EdgeUtilities.IsInsideBoundary(geometryEdges, candidatePoint));

                    startingPoints[i] = candidatePoint;
                }
            }

            for (int angleIndex = 0; angleIndex < fitAngles.Length; angleIndex++)
            {
                for (int pointIndex = 0; pointIndex < startingPoints.Length; pointIndex++)
                {
                    float angleRadians = MathUtilities.DegreesToRadians(fitAngles[angleIndex]);

                    // Find the collision point of a cross through the given point at the given angle.
                    // Note, we are ignoring the return value as we are checking each point's validity
                    // individually.
                    FindSurroundingCollisionPoints(
                        geometryEdges,
                        startingPoints[pointIndex],
                        angleRadians,
                        out Vector2 topCollisionPoint,
                        out Vector2 bottomCollisionPoint,
                        out Vector2 leftCollisionPoint,
                        out Vector2 rightCollisionPoint);

                    float newWidth;
                    float newHeight;

                    if (EdgeUtilities.IsValidPoint(topCollisionPoint) && EdgeUtilities.IsValidPoint(bottomCollisionPoint))
                    {
                        float aX = topCollisionPoint.x;
                        float aY = topCollisionPoint.y;
                        float bX = bottomCollisionPoint.x;
                        float bY = bottomCollisionPoint.y;

                        // Calculate the midpoint between the top and bottom collision points.
                        Vector2 verticalMidpoint = new Vector2((aX + bX) * 0.5f, (aY + bY) * 0.5f);
                        if (TryFixMaximumRectangle(
                                geometryEdges,
                                verticalMidpoint,
                                angleRadians,
                                Width * Height,
                                out newWidth,
                                out newHeight))
                        {
                            Center = verticalMidpoint;
                            Angle  = fitAngles[angleIndex];
                            Width  = newWidth;
                            Height = newHeight;
                        }
                    }

                    if (EdgeUtilities.IsValidPoint(leftCollisionPoint) && EdgeUtilities.IsValidPoint(rightCollisionPoint))
                    {
                        float aX = leftCollisionPoint.x;
                        float aY = leftCollisionPoint.y;
                        float bX = rightCollisionPoint.x;
                        float bY = rightCollisionPoint.y;

                        // Calculate the midpoint between the left and right collision points.
                        Vector2 horizontalMidpoint = new Vector2((aX + bX) * 0.5f, (aY + bY) * 0.5f);
                        if (TryFixMaximumRectangle(
                                geometryEdges,
                                horizontalMidpoint,
                                angleRadians,
                                Width * Height,
                                out newWidth,
                                out newHeight))
                        {
                            Center = horizontalMidpoint;
                            Angle  = fitAngles[angleIndex];
                            Width  = newWidth;
                            Height = newHeight;
                        }
                    }
                }
            }
        }
Ejemplo n.º 24
0
        IEnumerator StunStateLogic()
        {
            Play("warn");

            amp = 5;

            Vector2 target = MapUtilities.GetRoomUpperLeftPos(GlobalState.CurrentMapGrid) + new Vector2(6, 4) * 16;

            small_wave.Rise();

            while (!(MathUtilities.MoveTo(ref Position.X, target.X, 30) & MathUtilities.MoveTo(ref Position.Y, target.Y, 30)))
            {
                yield return(null);
            }

            while (y_push != 0)
            {
                yield return(null);
            }

            loopSFX = true;
            amp     = 13;

            while (y_push < amp)
            {
                yield return(null);
            }

            small_wave.Launch();

            while (y_push != 0)
            {
                yield return(null);
            }

            amp = 20;

            while (y_push < 18)
            {
                yield return(null);
            }

            big_wave.Rise();

            while (big_wave.velocity == Vector2.Zero)
            {
                yield return(null);
            }

            Play("close_eyes");

            while (y_push > 2)
            {
                yield return(null);
            }

            amp = 5;

            while (small_wave.exists || big_wave.exists)
            {
                yield return(null);
            }

            target -= Vector2.UnitX * 16;

            while (!(MathUtilities.MoveTo(ref Position.X, target.X, 30) & MathUtilities.MoveTo(ref Position.Y, target.Y, 30)))
            {
                yield return(null);
            }

            loopSFX = false;

            yield break;
        }
Ejemplo n.º 25
0
        /// <summary>Relatives the allocation.</summary>
        /// <param name="Organs">The organs.</param>
        /// <param name="TotalSupply">The total supply.</param>
        /// <param name="TotalAllocated">The total allocated.</param>
        /// <param name="BAT">The bat.</param>
        public void DoAllocation(IArbitration[] Organs, double TotalSupply, ref double TotalAllocated, BiomassArbitrationType BAT)
        {
            double NotAllocated = TotalSupply;

            // Save Totals for use inside the for loops below
            double totalStructuralDemand = BAT.TotalStructuralDemand;
            double totalMetabolicDemand  = BAT.TotalMetabolicDemand;
            double totalStorageDemand    = BAT.TotalStorageDemand;


            ////allocate to structural and metabolic Biomass first
            for (int i = 0; i < Organs.Length; i++)
            {
                double StructuralRequirement = Math.Max(0, BAT.StructuralDemand[i] - BAT.StructuralAllocation[i]); //N needed to get to Minimum N conc and satisfy structural and metabolic N demands
                double MetabolicRequirement  = Math.Max(0, BAT.MetabolicDemand[i] - BAT.MetabolicAllocation[i]);
                if ((StructuralRequirement + MetabolicRequirement) > 0.0)
                {
                    double StructuralFraction   = totalStructuralDemand / (totalStructuralDemand + totalMetabolicDemand);
                    double StructuralAllocation = Math.Min(StructuralRequirement, TotalSupply * StructuralFraction * MathUtilities.Divide(BAT.StructuralDemand[i], totalStructuralDemand, 0));
                    double MetabolicAllocation  = Math.Min(MetabolicRequirement, TotalSupply * (1 - StructuralFraction) * MathUtilities.Divide(BAT.MetabolicDemand[i], totalMetabolicDemand, 0));
                    BAT.StructuralAllocation[i] += StructuralAllocation;
                    BAT.MetabolicAllocation[i]  += MetabolicAllocation;
                    NotAllocated   -= (StructuralAllocation + MetabolicAllocation);
                    TotalAllocated += (StructuralAllocation + MetabolicAllocation);
                }
            }
            // Second time round if there is still Biomass to allocate let organs take N up to their Maximum
            double FirstPassNotAllocated = NotAllocated;

            for (int i = 0; i < Organs.Length; i++)
            {
                double StorageRequirement = Math.Max(0.0, BAT.StorageDemand[i] - BAT.StorageAllocation[i]); //N needed to take organ up to maximum N concentration, Structural, Metabolic and Luxury N demands
                if (StorageRequirement > 0.0)
                {
                    double StorageAllocation = Math.Min(FirstPassNotAllocated * MathUtilities.Divide(BAT.StorageDemand[i], totalStorageDemand, 0), StorageRequirement);
                    BAT.StorageAllocation[i] += Math.Max(0, StorageAllocation);
                    NotAllocated             -= StorageAllocation;
                    TotalAllocated           += StorageAllocation;
                }
            }
            //Set the amount of biomass not allocated.  Note, that this value is overwritten following by each arbitration step so if it is to be used correctly
            //it must be caught in that step.  Currently only using to catch DM not allocated so we can report as sink limitaiton
            BAT.NotAllocated = NotAllocated;
        }
Ejemplo n.º 26
0
 public override void Collided(Entity other)
 {
     MathUtilities.MoveTo(ref other.Position.X, 0, 30);
 }
Ejemplo n.º 27
0
        /// <summary>
        /// The keys of each BabylonMorphTarget animation ARE NOT assumed to be identical.
        /// This function merges together all keys and binds to each an influence value for all targets.
        /// A target influence value is automatically computed when necessary.
        /// Computation rules are:
        /// - linear interpolation between target key range
        /// - constant value outside target key range
        /// </summary>
        /// <example>
        /// When:
        /// animation1.keys = {0, 25, 50, 100}
        /// animation2.keys = {50, 75, 100}
        ///
        /// Gives:
        /// mergedKeys = {0, 25, 50, 100, 75}
        /// range1=[0, 100]
        /// range2=[50, 100]
        /// for animation1, the value associated to key=75 is the interpolation of its values between 50 and 100
        /// for animation2, the value associated to key=0 is equal to the one at key=50 since 0 is out of range [50, 100] (same for key=25)</example>
        /// <param name="babylonMorphTargetManager"></param>
        /// <returns>A map which for each frame, gives the influence value of all targets</returns>
        private Dictionary <float, List <float> > _getTargetManagerAnimationsData(BabylonMorphTargetManager babylonMorphTargetManager)
        {
            // Merge all keys into a single set (no duplicated frame)
            var mergedFrames = new HashSet <float>();

            foreach (var babylonMorphTarget in babylonMorphTargetManager.targets)
            {
                if (babylonMorphTarget.animations != null)
                {
                    var animation = babylonMorphTarget.animations[0];
                    foreach (BabylonAnimationKey animationKey in animation.keys)
                    {
                        mergedFrames.Add(animationKey.frame);
                    }
                }
            }

            // For each frame, gives the influence value of all targets (gltf structure)
            var influencesPerFrame = new Dictionary <float, List <float> >();

            foreach (var frame in mergedFrames)
            {
                influencesPerFrame.Add(frame, new List <float>());
            }
            foreach (var babylonMorphTarget in babylonMorphTargetManager.targets)
            {
                // For a given target, for each frame, gives the influence value of the target (babylon structure)
                var influencePerFrameForTarget = new Dictionary <float, float>();

                if (babylonMorphTarget.animations != null && babylonMorphTarget.animations.Length > 0)
                {
                    var animation = babylonMorphTarget.animations[0];

                    if (animation.keys.Length == 1)
                    {
                        // Same influence for all frames
                        var influence = animation.keys[0].values[0];
                        foreach (var frame in mergedFrames)
                        {
                            influencePerFrameForTarget.Add(frame, influence);
                        }
                    }
                    else
                    {
                        // Retreive target animation key range [min, max]
                        var babylonAnimationKeys = new List <BabylonAnimationKey>(animation.keys);
                        babylonAnimationKeys.Sort();
                        var minAnimationKey = babylonAnimationKeys[0];
                        var maxAnimationKey = babylonAnimationKeys[babylonAnimationKeys.Count - 1];

                        foreach (var frame in mergedFrames)
                        {
                            // Surround the current frame with closest keys available for the target
                            BabylonAnimationKey lowerAnimationKey = minAnimationKey;
                            BabylonAnimationKey upperAnimationKey = maxAnimationKey;
                            foreach (BabylonAnimationKey animationKey in animation.keys)
                            {
                                if (lowerAnimationKey.frame < animationKey.frame && animationKey.frame <= frame)
                                {
                                    lowerAnimationKey = animationKey;
                                }
                                if (frame <= animationKey.frame && animationKey.frame < upperAnimationKey.frame)
                                {
                                    upperAnimationKey = animationKey;
                                }
                            }

                            // In case the target has a key for this frame
                            // or the current frame is out of target animation key range
                            if (lowerAnimationKey.frame == upperAnimationKey.frame)
                            {
                                influencePerFrameForTarget.Add(frame, lowerAnimationKey.values[0]);
                            }
                            else
                            {
                                // Interpolate influence values
                                var t         = 1.0f * (frame - lowerAnimationKey.frame) / (upperAnimationKey.frame - lowerAnimationKey.frame);
                                var influence = MathUtilities.Lerp(lowerAnimationKey.values[0], upperAnimationKey.values[0], t);
                                influencePerFrameForTarget.Add(frame, influence);
                            }
                        }
                    }
                }
                else
                {
                    // Target is not animated
                    // Fill all frames with 0
                    foreach (var frame in mergedFrames)
                    {
                        influencePerFrameForTarget.Add(frame, 0);
                    }
                }

                // Switch from babylon to gltf storage representation
                foreach (var frame in mergedFrames)
                {
                    List <float> influences = influencesPerFrame[frame];
                    influences.Add(influencePerFrameForTarget[frame]);
                }
            }

            return(influencesPerFrame);
        }
Ejemplo n.º 28
0
        /// <summary>
        /// This is basically one giant hack to calculate the equivalent
        /// of phenology's daysTotal variable in the old sorghum model.
        ///
        /// This should be refactored out at some point.
        /// </summary>
        /// <param name="calcNewStage"></param>
        private void IncrementDaysTotal(bool calcNewStage)
        {
            if (doIncrement)
            {
                double newStage = phenology.Stage;
                if (calcNewStage)
                {
                    newStage = Math.Floor(newStage) + 1; // 😭
                }
                int phaseIndex = Convert.ToInt32(Math.Floor(newStage));
                while (DaysTotal.Count <= phaseIndex)
                {
                    DaysTotal.Add(0);
                }

                if (phaseIndex == Convert.ToInt32(Math.Floor(stage)))
                {
                    DaysTotal[phaseIndex]++;
                }
                else if (previousPhase is GenericPhase phase)
                {
                    double dltTT    = phase.ProgressionForTimeStep;
                    double potDltTT = DltTT;

                    // TT proportions should be based on dlt in prev phase / total daily dlTT.
                    // If after flowering, use dltTTFM instead. If on day of flowering, we want
                    // to mimic a bug in old apsim where the proportion is still based on dltTT.
                    if (phenology.Between("Flowering", "Maturity") && phaseIndex != 7)
                    {
                        potDltTT = (double?)Apsim.Get(this, "[Phenology].DltTTFM.Value()") ?? (double)Apsim.Get(this, "[Phenology].ThermalTime.Value()");
                    }

                    // Amount of TT which goes to next phase = total TT - amount allocated to previous phase.
                    double portionInNew = Math.Max(0, potDltTT - dltTT);

                    double propInNew = MathUtilities.Divide(portionInNew, potDltTT, 0);
                    double propInOld = 1 - propInNew;

                    DaysTotal[phaseIndex] += propInNew;
                    if (phaseIndex > 0)
                    {
                        DaysTotal[phaseIndex - 1] += propInOld;
                    }
                }
                else if (previousPhase is EmergingPhase emerg)
                {
                    double dltTT    = emerg.TTForTimeStep;
                    double potDltTT = DltTT;

                    // Amount of TT which goes to next phase = total TT - amount allocated to previous phase.
                    double portionInNew = Math.Max(0, potDltTT - dltTT);
                    double propInNew    = MathUtilities.Divide(portionInNew, potDltTT, 0);
                    double propInOld    = 1 - propInNew;

                    DaysTotal[phaseIndex] += propInNew;
                    if (phaseIndex > 0)
                    {
                        DaysTotal[phaseIndex - 1] += propInOld;
                    }
                }
                else
                {
                    double propInOld = phaseIndex - stage;
                    double propInNew = 1 - propInOld;
                    DaysTotal[phaseIndex]     += propInNew;
                    DaysTotal[phaseIndex - 1] += propInOld;
                }

                stage         = newStage;
                previousPhase = phenology.CurrentPhase;
                doIncrement   = false;
            }
        }
Ejemplo n.º 29
0
        /// <summary>
        /// Draw ticks.
        /// Ticks can be draw in 8 different ways depends on Placement property and IsDirectionReversed property.
        ///
        /// This function also draw selection-tick(s) if IsSelectionRangeEnabled is 'true' and
        /// SelectionStart and SelectionEnd are valid.
        ///
        /// The primary ticks (for Minimum and Maximum value) height will be 100% of TickBar's render size (use Width or Height
        /// depends on Placement property).
        ///
        /// The secondary ticks (all other ticks, including selection-tics) height will be 75% of TickBar's render size.
        ///
        /// Brush that use to fill ticks is specified by Fill property.
        /// </summary>
        public override void Render(DrawingContext dc)
        {
            var size              = new Size(Bounds.Width, Bounds.Height);
            var range             = Maximum - Minimum;
            var tickLen           = 0.0d; // Height for Primary Tick (for Minimum and Maximum value)
            var tickLen2          = 0.0d; // Height for Secondary Tick
            var logicalToPhysical = 1.0;
            var startPoint        = new Point();
            var endPoint          = new Point();
            var rSpace            = Orientation == Orientation.Horizontal ? ReservedSpace.Width : ReservedSpace.Height;

            // Take Thumb size in to account
            double halfReservedSpace = rSpace * 0.5;

            switch (Placement)
            {
            case TickBarPlacement.Top:
                if (MathUtilities.GreaterThanOrClose(rSpace, size.Width))
                {
                    return;
                }
                size              = new Size(size.Width - rSpace, size.Height);
                tickLen           = -size.Height;
                startPoint        = new Point(halfReservedSpace, size.Height);
                endPoint          = new Point(halfReservedSpace + size.Width, size.Height);
                logicalToPhysical = size.Width / range;
                break;

            case TickBarPlacement.Bottom:
                if (MathUtilities.GreaterThanOrClose(rSpace, size.Width))
                {
                    return;
                }
                size              = new Size(size.Width - rSpace, size.Height);
                tickLen           = size.Height;
                startPoint        = new Point(halfReservedSpace, 0d);
                endPoint          = new Point(halfReservedSpace + size.Width, 0d);
                logicalToPhysical = size.Width / range;
                break;

            case TickBarPlacement.Left:
                if (MathUtilities.GreaterThanOrClose(rSpace, size.Height))
                {
                    return;
                }
                size = new Size(size.Width, size.Height - rSpace);

                tickLen           = -size.Width;
                startPoint        = new Point(size.Width, size.Height + halfReservedSpace);
                endPoint          = new Point(size.Width, halfReservedSpace);
                logicalToPhysical = size.Height / range * -1;
                break;

            case TickBarPlacement.Right:
                if (MathUtilities.GreaterThanOrClose(rSpace, size.Height))
                {
                    return;
                }
                size              = new Size(size.Width, size.Height - rSpace);
                tickLen           = size.Width;
                startPoint        = new Point(0d, size.Height + halfReservedSpace);
                endPoint          = new Point(0d, halfReservedSpace);
                logicalToPhysical = size.Height / range * -1;
                break;
            }
            ;

            tickLen2 = tickLen * 0.75;

            // Invert direction of the ticks
            if (IsDirectionReversed)
            {
                logicalToPhysical *= -1;

                // swap startPoint & endPoint
                var pt = startPoint;
                startPoint = endPoint;
                endPoint   = pt;
            }

            var pen = new ImmutablePen(Fill?.ToImmutable(), 1.0d);

            // Is it Vertical?
            if (Placement == TickBarPlacement.Left || Placement == TickBarPlacement.Right)
            {
                // Reduce tick interval if it is more than would be visible on the screen
                double interval = TickFrequency;
                if (interval > 0.0)
                {
                    double minInterval = (Maximum - Minimum) / size.Height;
                    if (interval < minInterval)
                    {
                        interval = minInterval;
                    }
                }

                // Draw Min & Max tick
                dc.DrawLine(pen, startPoint, new Point(startPoint.X + tickLen, startPoint.Y));
                dc.DrawLine(pen, new Point(startPoint.X, endPoint.Y),
                            new Point(startPoint.X + tickLen, endPoint.Y));

                // This property is rarely set so let's try to avoid the GetValue
                // caching of the mutable default value
                var ticks = Ticks ?? null;

                // Draw ticks using specified Ticks collection
                if (ticks?.Count > 0)
                {
                    for (int i = 0; i < ticks.Count; i++)
                    {
                        if (MathUtilities.LessThanOrClose(ticks[i], Minimum) || MathUtilities.GreaterThanOrClose(ticks[i], Maximum))
                        {
                            continue;
                        }

                        double adjustedTick = ticks[i] - Minimum;

                        double y = adjustedTick * logicalToPhysical + startPoint.Y;
                        dc.DrawLine(pen,
                                    new Point(startPoint.X, y),
                                    new Point(startPoint.X + tickLen2, y));
                    }
                }
                // Draw ticks using specified TickFrequency
                else if (interval > 0.0)
                {
                    for (double i = interval; i < range; i += interval)
                    {
                        double y = i * logicalToPhysical + startPoint.Y;

                        dc.DrawLine(pen,
                                    new Point(startPoint.X, y),
                                    new Point(startPoint.X + tickLen2, y));
                    }
                }
            }
            else  // Placement == Top || Placement == Bottom
            {
                // Reduce tick interval if it is more than would be visible on the screen
                double interval = TickFrequency;
                if (interval > 0.0)
                {
                    double minInterval = (Maximum - Minimum) / size.Width;
                    if (interval < minInterval)
                    {
                        interval = minInterval;
                    }
                }

                // Draw Min & Max tick
                dc.DrawLine(pen, startPoint, new Point(startPoint.X, startPoint.Y + tickLen));
                dc.DrawLine(pen, new Point(endPoint.X, startPoint.Y),
                            new Point(endPoint.X, startPoint.Y + tickLen));

                // This property is rarely set so let's try to avoid the GetValue
                // caching of the mutable default value
                var ticks = Ticks ?? null;

                // Draw ticks using specified Ticks collection
                if (ticks?.Count > 0)
                {
                    for (int i = 0; i < ticks.Count; i++)
                    {
                        if (MathUtilities.LessThanOrClose(ticks[i], Minimum) || MathUtilities.GreaterThanOrClose(ticks[i], Maximum))
                        {
                            continue;
                        }
                        double adjustedTick = ticks[i] - Minimum;

                        double x = adjustedTick * logicalToPhysical + startPoint.X;
                        dc.DrawLine(pen,
                                    new Point(x, startPoint.Y),
                                    new Point(x, startPoint.Y + tickLen2));
                    }
                }
                // Draw ticks using specified TickFrequency
                else if (interval > 0.0)
                {
                    for (double i = interval; i < range; i += interval)
                    {
                        double x = i * logicalToPhysical + startPoint.X;
                        dc.DrawLine(pen,
                                    new Point(x, startPoint.Y),
                                    new Point(x, startPoint.Y + tickLen2));
                    }
                }
            }
        }
Ejemplo n.º 30
0
 /// <summary>
 /// Validates/coerces the <see cref="Value"/> property.
 /// </summary>
 /// <param name="sender">The RangeBase control.</param>
 /// <param name="value">The value.</param>
 /// <returns>The coerced value.</returns>
 private static double ValidateValue(RangeBase sender, double value)
 {
     ValidateDouble(value, "Value");
     return(MathUtilities.Clamp(value, sender.Minimum, sender.Maximum));
 }