// TODO: DYNAMIC component data adding for all factories /// <summary> /// Retrieve the components specified in the data and add them to the projectiles /// </summary> /// <param name="entity"></param> /// <param name="data"></param> private static void AddExtraComponentData(ref Entity entity, ComponentDataStruct data) { switch (data.componentType) { case EComponentType.HeadShot: EntityManager.AddComponentData(entity, (HeadShotMultiplier)data.GetComponentData()); return; case EComponentType.MultiHit: EntityManager.AddComponentData(entity, (MultiHit)data.GetComponentData()); return; case EComponentType.EMP: Debug.LogWarning("EMP is not yet implemented."); return; case EComponentType.SuperCombine: EntityManager.AddComponentData(entity, (SuperCombine)data.GetComponentData()); return; case EComponentType.Tracking: EntityManager.AddComponentData(entity, (TrackPlayer)data.GetComponentData()); return; case EComponentType.Explosive: EntityManager.AddComponentData(entity, (Explosive)data.GetComponentData()); return; case EComponentType.NotImplemented: Debug.Log("Not yet immplemented."); return; } }
/*/// <summary> * /// Register presence of slurp * /// </summary> * [EventSubscribe("StartSlurp")] * private void OnStartSlurp(object sender, EventArgs e) * { * Slurp newSlurp = sender as Slurp; * * int senderIdx = FindComponentIndex(newSlurp.Name); * * // If sender is unknown, add it to the list * if (senderIdx == -1) * throw new ApsimXException(FullPath, "Cannot find MicroClimate definition for Slurp"); * ComponentData[senderIdx].Name = newSlurp.Name; * ComponentData[senderIdx].Type = newSlurp.CropType; * Clear(ComponentData[senderIdx]); * } */ /// <summary>Clears the specified componentdata</summary> /// <param name="c">The c.</param> private void Clear(ComponentDataStruct c) { c.CoverGreen = 0; c.CoverTot = 0; c.Depth = 0; c.Frgr = 0; c.Height = 0; c.K = 0; c.Ktot = 0; c.LAI = 0; c.LAItot = 0; Util.ZeroArray(c.layerLAI); Util.ZeroArray(c.layerLAItot); Util.ZeroArray(c.Ftot); Util.ZeroArray(c.Fgreen); Util.ZeroArray(c.Rs); Util.ZeroArray(c.Rl); Util.ZeroArray(c.Rsoil); Util.ZeroArray(c.Gc); Util.ZeroArray(c.Ga); Util.ZeroArray(c.PET); Util.ZeroArray(c.PETr); Util.ZeroArray(c.PETa); Util.ZeroArray(c.Omega); Util.ZeroArray(c.interception); }
/// <summary>Calculate light extinction parameters</summary> /// <exception cref="System.Exception">Unrealistically high cover value in MicroMet i.e. > -.9999</exception> private void LightExtinction() { // Calculate effective K from LAI and cover // ========================================= for (int j = 0; j <= ComponentData.Count - 1; j++) { ComponentDataStruct componentData = ComponentData[j]; if (MathUtilities.FloatsAreEqual(ComponentData[j].CoverGreen, 1.0, 1E-05)) { throw new Exception("Unrealistically high cover value in MicroMet i.e. > -.9999"); } componentData.K = MathUtilities.Divide(-Math.Log(1.0 - componentData.CoverGreen), componentData.LAI, 0.0); componentData.Ktot = MathUtilities.Divide(-Math.Log(1.0 - componentData.CoverTot), componentData.LAItot, 0.0); } // Calculate extinction for individual layers // ============================================ for (int i = 0; i <= numLayers - 1; i++) { layerKtot[i] = 0.0; for (int j = 0; j <= ComponentData.Count - 1; j++) { ComponentDataStruct componentData = ComponentData[j]; layerKtot[i] += componentData.Ftot[i] * componentData.Ktot; } } }
/// <summary>Calculate the Penman-Monteith water demand</summary> private void CalculatePM() { // zero a few things, and sum a few others double sumRl = 0.0; double sumRsoil = 0.0; double sumInterception = 0.0; double freeEvapGa = 0.0; for (int i = 0; i <= numLayers - 1; i++) { for (int j = 0; j <= ComponentData.Count - 1; j++) { ComponentDataStruct componentData = ComponentData[j]; componentData.PET[i] = 0.0; componentData.PETr[i] = 0.0; componentData.PETa[i] = 0.0; sumRl += componentData.Rl[i]; sumRsoil += componentData.Rsoil[i]; sumInterception += componentData.interception[i]; freeEvapGa += componentData.Ga[i]; } } double netRadiation = ((1.0 - _albedo) * sumRs + sumRl + sumRsoil) * 1000000.0; // MJ/J netRadiation = Math.Max(0.0, netRadiation); double freeEvapGc = freeEvapGa * 1000000.0; // =infinite surface conductance double freeEvap = CalcPenmanMonteith(netRadiation, mint, maxt, vp, air_pressure, dayLength, freeEvapGa, freeEvapGc); dryleaffraction = 1.0 - MathUtilities.Divide(sumInterception * (1.0 - night_interception_fraction), freeEvap, 0.0); dryleaffraction = Math.Max(0.0, dryleaffraction); for (int i = 0; i <= numLayers - 1; i++) { for (int j = 0; j <= ComponentData.Count - 1; j++) { ComponentDataStruct componentData = ComponentData[j]; netRadiation = 1000000.0 * ((1.0 - _albedo) * componentData.Rs[i] + componentData.Rl[i] + componentData.Rsoil[i]); // MJ/J netRadiation = Math.Max(0.0, netRadiation); if (j == 39) { netRadiation += 0.0; } componentData.PETr[i] = CalcPETr(netRadiation * dryleaffraction, mint, maxt, air_pressure, componentData.Ga[i], componentData.Gc[i]); componentData.PETa[i] = CalcPETa(mint, maxt, vp, air_pressure, dayLength * dryleaffraction, componentData.Ga[i], componentData.Gc[i]); componentData.PET[i] = componentData.PETr[i] + componentData.PETa[i]; } } }
/// <summary>Calculate the aerodynamic decoupling for system compartments</summary> private void CalculateOmega() { for (int i = 0; i <= numLayers - 1; i++) { for (int j = 0; j <= ComponentData.Count - 1; j++) { ComponentDataStruct componentData = ComponentData[j]; componentData.Omega[i] = CalcOmega(mint, maxt, air_pressure, componentData.Ga[i], componentData.Gc[i]); } } }
/// <summary>Setups the crop types.</summary> /// <param name="Name">The name.</param> /// <param name="Type">The type.</param> private void SetupCropTypes(string Name, string Type) { ComponentDataStruct CropType = new ComponentDataStruct(); CropType.Name = Name; //Set defalst CropType.Albedo = 0.15; CropType.Gsmax = 0.01; CropType.Emissivity = 0.96; CropType.R50 = 200; //Override type specific values if (Type.Equals("Crop")) { CropType.Albedo = 0.26; CropType.Gsmax = 0.011; } if (Type.Equals("Potato")) { CropType.Albedo = 0.26; CropType.Gsmax = 0.03; } else if (Type.Equals("Grass")) { CropType.Albedo = 0.23; } else if (Type.Equals("C4grass")) { CropType.Albedo = 0.23; CropType.Gsmax = 0.015; CropType.R50 = 150; } else if (Type.Equals("Tree")) { CropType.Albedo = 0.15; CropType.Gsmax = 0.005; } else if (Type.Equals("Tree2")) { CropType.Albedo = 0.15; CropType.R50 = 100; } else if (Type.Equals("Pasture") || Type.Equals("Legume") || Type.Equals("Forage")) { // added by rcichota when spliting species in agpasture, still setting all parameters the same, will change in the future CropType.Albedo = 0.26; CropType.Gsmax = 0.011; } ComponentDataDefinitions.Add(CropType); }
/// <summary>Break the components into layers</summary> private void DivideComponents() { double[] Ld = new double[ComponentData.Count]; for (int j = 0; j <= ComponentData.Count - 1; j++) { ComponentDataStruct componentData = ComponentData[j]; componentData.layerLAI = new double[numLayers]; componentData.layerLAItot = new double[numLayers]; Ld[j] = MathUtilities.Divide(componentData.LAItot, componentData.Depth, 0.0); } double top = 0.0; double bottom = 0.0; for (int i = 0; i <= numLayers - 1; i++) { bottom = top; top = top + DeltaZ[i]; layerLAIsum[i] = 0.0; // Calculate LAI for layer i and component j // =========================================== for (int j = 0; j <= ComponentData.Count - 1; j++) { ComponentDataStruct componentData = ComponentData[j]; if ((componentData.Height > bottom) && (componentData.Height - componentData.Depth < top)) { componentData.layerLAItot[i] = Ld[j] * DeltaZ[i]; componentData.layerLAI[i] = componentData.layerLAItot[i] * MathUtilities.Divide(componentData.LAI, componentData.LAItot, 0.0); layerLAIsum[i] += componentData.layerLAItot[i]; } } // Calculate fractional contribution for layer i and component j // ==================================================================== for (int j = 0; j <= ComponentData.Count - 1; j++) { ComponentDataStruct componentData = ComponentData[j]; componentData.Ftot[i] = MathUtilities.Divide(componentData.layerLAItot[i], layerLAIsum[i], 0.0); // Note: Sum of Fgreen will be < 1 as it is green over total componentData.Fgreen[i] = MathUtilities.Divide(componentData.layerLAI[i], layerLAIsum[i], 0.0); } } }
/// <summary>Send an energy balance event</summary> private void SendEnergyBalanceEvent() { for (int j = 0; j <= ComponentData.Count - 1; j++) { ComponentDataStruct componentData = ComponentData[j]; if (componentData.Canopy != null) { CanopyEnergyBalanceInterceptionlayerType[] lightProfile = new CanopyEnergyBalanceInterceptionlayerType[numLayers]; double totalPotentialEp = 0; double totalInterception = 0.0; for (int i = 0; i <= numLayers - 1; i++) { lightProfile[i] = new CanopyEnergyBalanceInterceptionlayerType(); lightProfile[i].thickness = Convert.ToSingle(DeltaZ[i]); lightProfile[i].amount = Convert.ToSingle(componentData.Rs[i] * RadnGreenFraction(j)); totalPotentialEp += componentData.PET[i]; totalInterception += componentData.interception[i]; } componentData.Canopy.PotentialEP = totalPotentialEp; componentData.Canopy.LightProfile = lightProfile; } else if (componentData.Crop2 != null) { CanopyEnergyBalanceInterceptionlayerType[] lightProfile = new CanopyEnergyBalanceInterceptionlayerType[numLayers]; double totalPotentialEp = 0; double totalInterception = 0.0; for (int i = 0; i <= numLayers - 1; i++) { lightProfile[i] = new CanopyEnergyBalanceInterceptionlayerType(); lightProfile[i].thickness = Convert.ToSingle(DeltaZ[i]); lightProfile[i].amount = Convert.ToSingle(componentData.Rs[i] * RadnGreenFraction(j)); totalPotentialEp += componentData.PET[i]; totalInterception += componentData.interception[i]; } componentData.Crop2.demandWater = totalPotentialEp; componentData.Crop2.LightProfile = lightProfile; } } }
/// <summary>Calculate the canopy conductance for system compartments</summary> private void CalculateGc() { double Rin = radn; for (int i = numLayers - 1; i >= 0; i += -1) { double Rflux = Rin * 1000000.0 / (dayLength * hr2s) * (1.0 - _albedo); double Rint = 0.0; for (int j = 0; j <= ComponentData.Count - 1; j++) { ComponentDataStruct componentData = ComponentData[j]; componentData.Gc[i] = CanopyConductance(componentData.Gsmax, componentData.R50, componentData.Frgr, componentData.Fgreen[i], layerKtot[i], layerLAIsum[i], Rflux); Rint += componentData.Rs[i]; } // Calculate Rin for the next layer down Rin -= Rint; } }
/// <summary>Gets all canopies in simulation</summary> private void GetAllCanopies() { foreach (ICanopy canopy in Apsim.FindAll(this.Parent, typeof(ICanopy))) { ComponentDataStruct componentData = ComponentData.Find(c => c.Name == canopy.CanopyType); if (componentData == null) { componentData = CreateNewComonentData(canopy.CanopyType); Clear(componentData); } componentData.Name = canopy.CanopyType; componentData.Type = canopy.CanopyType; componentData.Canopy = canopy; componentData.LAI = canopy.LAI; componentData.LAItot = canopy.LAITotal; componentData.CoverGreen = canopy.CoverGreen; componentData.CoverTot = canopy.CoverTotal; componentData.Height = Math.Round(canopy.Height, 5) / 1000.0; // Round off a bit and convert mm to m componentData.Depth = Math.Round(canopy.Depth, 5) / 1000.0; // Round off a bit and convert mm to m componentData.Canopy = canopy; } }
/*/// <summary> /// Register presence of slurp /// </summary> [EventSubscribe("StartSlurp")] private void OnStartSlurp(object sender, EventArgs e) { Slurp newSlurp = sender as Slurp; int senderIdx = FindComponentIndex(newSlurp.Name); // If sender is unknown, add it to the list if (senderIdx == -1) throw new ApsimXException(FullPath, "Cannot find MicroClimate definition for Slurp"); ComponentData[senderIdx].Name = newSlurp.Name; ComponentData[senderIdx].Type = newSlurp.CropType; Clear(ComponentData[senderIdx]); } */ /// <summary>Clears the specified componentdata</summary> /// <param name="c">The c.</param> private void Clear(ComponentDataStruct c) { c.CoverGreen = 0; c.CoverTot = 0; c.Depth = 0; c.Frgr = 0; c.Height = 0; c.K = 0; c.Ktot = 0; c.LAI = 0; c.LAItot = 0; Util.ZeroArray(c.layerLAI); Util.ZeroArray(c.layerLAItot); Util.ZeroArray(c.Ftot); Util.ZeroArray(c.Fgreen); Util.ZeroArray(c.Rs); Util.ZeroArray(c.Rl); Util.ZeroArray(c.Rsoil); Util.ZeroArray(c.Gc); Util.ZeroArray(c.Ga); Util.ZeroArray(c.PET); Util.ZeroArray(c.PETr); Util.ZeroArray(c.PETa); Util.ZeroArray(c.Omega); Util.ZeroArray(c.interception); }
/// <summary>Setups the crop types.</summary> /// <param name="Name">The name.</param> /// <param name="Type">The type.</param> private void SetupCropTypes(string Name, string Type) { ComponentDataStruct CropType = new ComponentDataStruct(); CropType.Name = Name; //Set defalst CropType.Albedo = 0.15; CropType.Gsmax = 0.01; CropType.Emissivity = 0.96; CropType.R50 = 200; //Override type specific values if (Type.Equals("Crop")) { CropType.Albedo = 0.26; CropType.Gsmax=0.011; } if (Type.Equals("Potato")) { CropType.Albedo = 0.26; CropType.Gsmax = 0.03; } else if (Type.Equals("Grass")) { CropType.Albedo = 0.23; } else if (Type.Equals("C4grass")) { CropType.Albedo = 0.23; CropType.Gsmax = 0.015; CropType.R50 = 150; } else if (Type.Equals("Tree")) { CropType.Albedo = 0.15; CropType.Gsmax = 0.005; } else if (Type.Equals("Tree2")) { CropType.Albedo = 0.15; CropType.R50 = 100; } else if (Type.Equals("Pasture") || Type.Equals("Legume") || Type.Equals("Forage")) { // added by rcichota when spliting species in agpasture, still setting all parameters the same, will change in the future CropType.Albedo = 0.26; CropType.Gsmax = 0.011; } ComponentDataDefinitions.Add(CropType); }