/// <summary> /// The main stock management function that handles a number of events. /// </summary> /// <param name="Model"></param> /// <param name="stockEvent">The event parameters</param> /// <param name="dtToday"></param> /// <param name="fLatitude"></param> public void doStockManagement(TStockList Model, IStockEvent stockEvent, int dtToday = 0, double fLatitude = -35.0) { TCohortsInfo CohortsInfo = new TCohortsInfo(); TPurchaseInfo PurchaseInfo = new TPurchaseInfo(); List<string> sClosed; string sParam; int iParam1; int iParam3; double fValue; int iTag; int iGroups; if (stockEvent != null) { if (stockEvent.GetType() == typeof(TStockAdd)) // add_animals { TStockAdd stockInfo = (TStockAdd)stockEvent; CohortsInfo.sGenotype = stockInfo.genotype; CohortsInfo.iNumber = Math.Max(0, stockInfo.number); if (!ParseRepro(stockInfo.sex, ref CohortsInfo.ReproClass)) throw new Exception("Event ADD does not support sex='" + stockInfo.sex + "'"); if (dtToday > 0) CohortsInfo.iAgeOffsetDays = DaysFromDOY365(stockInfo.birth_day, dtToday); else CohortsInfo.iAgeOffsetDays = 0; CohortsInfo.iMinYears = stockInfo.min_years; CohortsInfo.iMaxYears = stockInfo.max_years; CohortsInfo.fMeanLiveWt = stockInfo.mean_weight; CohortsInfo.fCondScore = stockInfo.cond_score; CohortsInfo.fMeanGFW = stockInfo.mean_fleece_wt; if (dtToday > 0) CohortsInfo.iFleeceDays = DaysFromDOY365(stockInfo.shear_day, dtToday); else CohortsInfo.iFleeceDays = 0; CohortsInfo.sMatedTo = stockInfo.mated_to; CohortsInfo.iDaysPreg = stockInfo.pregnant; CohortsInfo.fFoetuses = stockInfo.foetuses; CohortsInfo.iDaysLact = stockInfo.lactating; CohortsInfo.fOffspring = stockInfo.offspring; CohortsInfo.fOffspringWt = stockInfo.young_wt; CohortsInfo.fOffspringCS = stockInfo.young_cond_score; CohortsInfo.fLambGFW = stockInfo.young_fleece_wt; if (CohortsInfo.iNumber > 0) Model.AddCohorts(CohortsInfo, 1 + DaysFromDOY365(1, dtToday), fLatitude, null); } else if (stockEvent.GetType() == typeof(TStockBuy)) { TStockBuy stockInfo = (TStockBuy)stockEvent; PurchaseInfo.sGenotype = stockInfo.genotype; PurchaseInfo.Number = Math.Max(0, stockInfo.number); if (!ParseRepro(stockInfo.sex, ref PurchaseInfo.Repro)) throw new Exception("Event BUY does not support sex='" + stockInfo.sex + "'"); PurchaseInfo.AgeDays = Convert.ToInt32(Math.Round(MONTH2DAY * stockInfo.age)); // Age in months PurchaseInfo.LiveWt = stockInfo.weight; PurchaseInfo.GFW = stockInfo.fleece_wt; PurchaseInfo.fCondScore = stockInfo.cond_score; PurchaseInfo.sMatedTo = stockInfo.mated_to; PurchaseInfo.Preg = stockInfo.pregnant; PurchaseInfo.Lact = stockInfo.lactating; PurchaseInfo.NYoung = stockInfo.no_young; if ((PurchaseInfo.Preg > 0) || (PurchaseInfo.Lact > 0)) PurchaseInfo.NYoung = Math.Max(1, PurchaseInfo.NYoung); PurchaseInfo.YoungWt = stockInfo.young_wt; if ((PurchaseInfo.Lact == 0) || (PurchaseInfo.YoungWt == 0.0)) // Can't use MISSING as default owing PurchaseInfo.YoungWt = StdMath.DMISSING; // to double-to-single conversion PurchaseInfo.YoungGFW = stockInfo.young_fleece_wt; iTag = stockInfo.usetag; if (PurchaseInfo.Number > 0) { Model.Buy(PurchaseInfo); if (iTag > 0) Model.setTag(Model.Count(), iTag); } } //_ buy _ //sell a number from a group of animals else if (stockEvent.GetType() == typeof(TStockSell)) { TStockSell stockInfo = (TStockSell)stockEvent; Model.Sell(stockInfo.group, stockInfo.number); } //sell a number of animals tagged with a specific tag else if (stockEvent.GetType() == typeof(TStockSellTag)) { TStockSellTag stockInfo = (TStockSellTag)stockEvent; Model.SellTag(stockInfo.tag, stockInfo.number); } else if (stockEvent.GetType() == typeof(TStockShear)) { TStockShear stockInfo = (TStockShear)stockEvent; sParam = stockInfo.sub_group.ToLower(); Model.Shear(stockInfo.group, ((sParam == "adults") || (sParam == "both") || (sParam == "")), ((sParam == "lambs") || (sParam == "both"))); } else if (stockEvent.GetType() == typeof(TStockMove)) { TStockMove stockInfo = (TStockMove)stockEvent; iParam1 = stockInfo.group; if ((iParam1 >= 1) && (iParam1 <= Model.Count())) Model.setInPadd(iParam1, stockInfo.paddock); else throw new Exception("Invalid group number in MOVE event"); } else if (stockEvent.GetType() == typeof(TStockJoin)) { TStockJoin stockInfo = (TStockJoin)stockEvent; Model.Join(stockInfo.group, stockInfo.mate_to, stockInfo.mate_days); } else if (stockEvent.GetType() == typeof(TStockCastrate)) { TStockCastrate stockInfo = (TStockCastrate)stockEvent; Model.Castrate(stockInfo.group, stockInfo.number); } else if (stockEvent.GetType() == typeof(TStockWean)) { TStockWean stockInfo = (TStockWean)stockEvent; iParam1 = stockInfo.group; sParam = stockInfo.sex.ToLower(); iParam3 = stockInfo.number; if (sParam == "males") Model.Wean(iParam1, iParam3, false, true); else if (sParam == "females") Model.Wean(iParam1, iParam3, true, false); else if ((sParam == "all") || (sParam == "")) Model.Wean(iParam1, iParam3, true, true); else throw new Exception("Invalid offspring type \"" + sParam + "\" in WEAN event"); } else if (stockEvent.GetType() == typeof(TStockDryoff)) { TStockDryoff stockInfo = (TStockDryoff)stockEvent; Model.DryOff(stockInfo.group, stockInfo.number); } //split off the requested animals from all groups else if (stockEvent.GetType() == typeof(TStockSplitAll)) { TStockSplitAll stockInfo = (TStockSplitAll)stockEvent; iGroups = Model.Count(); //get pre-split count of groups for (iParam1 = 1; iParam1 <= iGroups; iParam1++) { sParam = stockInfo.type.ToLower(); fValue = stockInfo.value; iTag = stockInfo.othertag; if (sParam == "age") Model.SplitAge(iParam1, Convert.ToInt32(Math.Round(fValue))); else if (sParam == "weight") Model.SplitWeight(iParam1, fValue); else if (sParam == "young") Model.SplitYoung(iParam1); else if (sParam == "number") Model.Split(iParam1, Convert.ToInt32(Math.Round(fValue))); else throw new Exception("Stock: invalid keyword (" + sParam + ") in \"split\" event"); if ((iTag > 0) && (Model.Count() > iGroups)) //if a tag for any new group is given Model.setTag(Model.Count(), iTag); } } //split off the requested animals from one group else if (stockEvent.GetType() == typeof(TStockSplit)) { TStockSplit stockInfo = (TStockSplit)stockEvent; iGroups = Model.Count(); //get pre-split count of groups iParam1 = stockInfo.group; sParam = stockInfo.type.ToLower(); fValue = stockInfo.value; iTag = stockInfo.othertag; if ((iParam1 < 1) && (iParam1 > Model.Count())) throw new Exception("Invalid group number in SPLIT event"); else if (sParam == "age") Model.SplitAge(iParam1, Convert.ToInt32(Math.Round(fValue))); else if (sParam == "weight") Model.SplitWeight(iParam1, fValue); else if (sParam == "young") Model.SplitYoung(iParam1); else if (sParam == "number") Model.Split(iParam1, Convert.ToInt32(Math.Round(fValue))); else throw new Exception("Stock: invalid keyword (" + sParam + ") in \"split\" event"); if ((iTag > 0) && (Model.Count() > iGroups)) //if a tag for the new group is given Model.setTag(Model.Count(), iTag); } else if (stockEvent.GetType() == typeof(TStockTag)) { TStockTag stockInfo = (TStockTag)stockEvent; iParam1 = stockInfo.group; if ((iParam1 >= 1) && (iParam1 <= Model.Count())) Model.setTag(iParam1, stockInfo.value); else throw new Exception("Invalid group number in TAG event"); } else if (stockEvent.GetType() == typeof(TStockSort)) { Model.Sort(); } else if (stockEvent.GetType() == typeof(TStockPrioritise)) { TStockPrioritise stockInfo = (TStockPrioritise)stockEvent; iParam1 = stockInfo.group; if ((iParam1 >= 1) && (iParam1 <= Model.Count())) Model.setPriority(iParam1, stockInfo.value); else throw new Exception("Invalid group number in PRIORITISE event"); } else if (stockEvent.GetType() == typeof(TStockDraft)) { TStockDraft stockInfo = (TStockDraft)stockEvent; sClosed = new List<string>(stockInfo.closed); Model.Draft(sClosed); } else throw new Exception("Event not recognised in STOCK"); } }
/// <summary> /// Populate the dry matter pool /// </summary> /// <param name="Model"></param> /// <param name="iCode"></param> /// <param name="bUseYoung"></param> /// <param name="bUseAll"></param> /// <param name="bUseTag"></param> /// <param name="aValue"></param> /// <returns></returns> public static bool PopulateDMPoolValue(TStockList Model, int iCode, bool bUseYoung, bool bUseAll, bool bUseTag, ref TDMPoolHead[] aValue) { int iNoPasses; TAnimalGroup aGroup; GrazType.DM_Pool Pool = new GrazType.DM_Pool(); GrazType.DM_Pool TotalPool = new GrazType.DM_Pool(); int iDenom; int iPass, Idx; bool Result = true; for (int i = 0; i < aValue.Length; i++) aValue[i] = new TDMPoolHead(); if (bUseTag) iNoPasses = aValue.Length; else iNoPasses = 1; for (iPass = 1; iPass <= iNoPasses; iPass++) { GrazType.ZeroDMPool(ref TotalPool); iDenom = 0; for (Idx = 1; Idx <= Model.Count(); Idx++) { if (!bUseTag || (Model.getTag(Idx) == iPass)) { if (!bUseYoung) aGroup = Model.At(Idx); else aGroup = Model.At(Idx).Young; GrazType.ZeroDMPool(ref Pool); if (aGroup != null) { int N = (int)GrazType.TOMElement.N; int P = (int)GrazType.TOMElement.P; int S = (int)GrazType.TOMElement.S; switch (iCode) { case StockProps.prpINTAKE: Pool.DM = aGroup.AnimalState.DM_Intake.Total; Pool.Nu[N] = aGroup.AnimalState.CP_Intake.Total / GrazType.N2Protein; Pool.Nu[P] = aGroup.AnimalState.Phos_Intake.Total; Pool.Nu[S] = aGroup.AnimalState.Sulf_Intake.Total; Pool.AshAlk = aGroup.AnimalState.PaddockIntake.AshAlkalinity * aGroup.AnimalState.PaddockIntake.Biomass + aGroup.AnimalState.SuppIntake.AshAlkalinity * aGroup.AnimalState.SuppIntake.Biomass; break; case StockProps.prpINTAKE_PAST: Pool.DM = aGroup.AnimalState.DM_Intake.Herbage; Pool.Nu[N] = aGroup.AnimalState.CP_Intake.Herbage / GrazType.N2Protein; Pool.Nu[P] = aGroup.AnimalState.Phos_Intake.Herbage; Pool.Nu[S] = aGroup.AnimalState.Sulf_Intake.Herbage; Pool.AshAlk = aGroup.AnimalState.PaddockIntake.AshAlkalinity * aGroup.AnimalState.PaddockIntake.Biomass; break; case StockProps.prpINTAKE_SUPP: Pool.DM = aGroup.AnimalState.DM_Intake.Supp; Pool.Nu[N] = aGroup.AnimalState.CP_Intake.Supp / GrazType.N2Protein; Pool.Nu[P] = aGroup.AnimalState.Phos_Intake.Supp; Pool.Nu[S] = aGroup.AnimalState.Sulf_Intake.Supp; Pool.AshAlk = aGroup.AnimalState.SuppIntake.AshAlkalinity * aGroup.AnimalState.SuppIntake.Biomass; break; case StockProps.prpFAECES: GrazType.AddDMPool(aGroup.AnimalState.OrgFaeces, Pool); GrazType.AddDMPool(aGroup.AnimalState.InOrgFaeces, Pool); break; case StockProps.prpINORG_FAECES: GrazType.AddDMPool(aGroup.AnimalState.InOrgFaeces, Pool); break; default: Result = false; break; } } if (!bUseTag && !bUseAll) { DMPool2Value(Pool, aValue[Idx - 1], (iCode == StockProps.prpINORG_FAECES)); } else if (aGroup != null) { GrazType.AddDMPool(GrazType.MultiplyDMPool(Pool, aGroup.NoAnimals), TotalPool); iDenom = iDenom + aGroup.NoAnimals; } } } //_ loop over animal groups _ if (bUseTag || bUseAll) { if (iDenom > 0) TotalPool = GrazType.PoolFraction(TotalPool, 1.0 / iDenom); if (bUseAll) { DMPool2Value(TotalPool, aValue[0], (iCode == StockProps.prpINORG_FAECES)); } else { DMPool2Value(TotalPool, aValue[iPass - 1], (iCode == StockProps.prpINORG_FAECES)); } } } return Result; }
/// <summary> /// Populate the numbers array for the type of output required /// </summary> /// <param name="Model"></param> /// <param name="code"></param> /// <param name="bUseYoung"></param> /// <param name="bUseAll"></param> /// <param name="bUseTag"></param> /// <param name="numbers"></param> /// <returns></returns> public static bool PopulateNumberValue(TStockList Model, CountType code, bool bUseYoung, bool bUseAll, bool bUseTag, ref int[] numbers) { int iNoPasses; TAnimalGroup aGroup; int iValue; int iTotal; int iPass, Idx; bool Result = true; Array.Clear(numbers, 0, numbers.Length); if (bUseTag) iNoPasses = numbers.Length; else iNoPasses = 1; for (iPass = 1; iPass <= iNoPasses; iPass++) { iTotal = 0; for (Idx = 1; Idx <= Model.Count(); Idx++) if (!bUseTag || (Model.getTag(Idx) == iPass)) { if (!bUseYoung) aGroup = Model.At(Idx); else aGroup = Model.At(Idx).Young; iValue = 0; if (aGroup != null) { switch (code) { case CountType.eBoth: iValue = aGroup.NoAnimals; break; case CountType.eFemale: iValue = aGroup.FemaleNo; break; case CountType.eMale: iValue = aGroup.MaleNo; break; default: Result = false; break; } } if (!bUseTag && !bUseAll) numbers[Idx - 1] = iValue; else iTotal = iTotal + iValue; } // _ loop over animal groups if (bUseAll) numbers[0] = iTotal; else if (bUseTag) numbers[iPass - 1] = iTotal; } //_ loop over passes _ return Result; }
/// <summary> /// Fill the double[] with values from the model. /// </summary> /// <param name="Model"></param> /// <param name="varCode"></param> /// <param name="bUseYoung"></param> /// <param name="bUseAll"></param> /// <param name="bUseTag"></param> /// <param name="aValue"></param> /// <returns></returns> public static bool PopulateRealValue(TStockList Model, int varCode, bool bUseYoung, bool bUseAll, bool bUseTag, ref double[] aValue) { int iNoPasses; TAnimalGroup aGroup; double dValue; double dTotal; int iDenom; int iPass, Idx; bool Result = true; Array.Clear(aValue, 0, aValue.Length); if (bUseTag) iNoPasses = aValue.Length; else iNoPasses = 1; for (iPass = 1; iPass <= iNoPasses; iPass++) { dTotal = 0.0; iDenom = 0; for (Idx = 1; Idx <= Model.Count(); Idx++) { if (!bUseTag || (Model.getTag(Idx) == iPass)) { if (!bUseYoung) aGroup = Model.At(Idx); else aGroup = Model.At(Idx).Young; dValue = 0.0; if (aGroup != null) { int N = (int)GrazType.TOMElement.N; int P = (int)GrazType.TOMElement.P; int S = (int)GrazType.TOMElement.S; switch (varCode) { case StockProps.prpAGE: dValue = aGroup.AgeDays; break; case StockProps.prpAGE_MONTHS: dValue = aGroup.AgeDays / MONTH2DAY; break; case StockProps.prpLIVE_WT: dValue = aGroup.LiveWeight; break; case StockProps.prpBASE_WT: dValue = aGroup.BaseWeight; break; case StockProps.prpCOND_SCORE: dValue = aGroup.fConditionScore(TAnimalParamSet.TCond_System.csSYSTEM1_5); break; case StockProps.prpMAX_PREV_WT: dValue = aGroup.MaxPrevWeight; break; case StockProps.prpFLEECE_WT: dValue = aGroup.FleeceCutWeight; break; case StockProps.prpCFLEECE_WT: dValue = aGroup.CleanFleeceWeight; break; case StockProps.prpFIBRE_DIAM: dValue = aGroup.FibreDiam; break; case StockProps.prpPREGNANT: dValue = aGroup.Pregnancy; break; case StockProps.prpLACTATING: dValue = aGroup.Lactation; break; case StockProps.prpNO_FOETUSES: dValue = aGroup.NoFoetuses; break; case StockProps.prpNO_SUCKLING: dValue = aGroup.NoOffspring; break; case StockProps.prpBIRTH_CS: dValue = aGroup.BirthCondition; break; case StockProps.prpDSE: dValue = aGroup.DrySheepEquivs; break; case StockProps.prpWT_CHANGE: dValue = aGroup.WeightChange; break; case StockProps.prpME_INTAKE: dValue = aGroup.AnimalState.ME_Intake.Total; break; case StockProps.prpCPI_INTAKE: dValue = aGroup.AnimalState.CP_Intake.Total; break; case StockProps.prpCFLEECE_GROWTH: dValue = aGroup.CleanFleeceGrowth; break; case StockProps.prpDAY_FIBRE_DIAM: dValue = aGroup.DayFibreDiam; break; case StockProps.prpMILK_WT: dValue = aGroup.MilkYield; break; case StockProps.prpMILK_ME: dValue = aGroup.MilkEnergy; break; case StockProps.prpRETAINED_N: dValue = aGroup.AnimalState.CP_Intake.Total / GrazType.N2Protein - (aGroup.AnimalState.InOrgFaeces.Nu[N] + aGroup.AnimalState.OrgFaeces.Nu[N] + aGroup.AnimalState.Urine.Nu[N]); break; case StockProps.prpRETAINED_P: dValue = aGroup.AnimalState.Phos_Intake.Total - (aGroup.AnimalState.InOrgFaeces.Nu[P] + aGroup.AnimalState.OrgFaeces.Nu[P] + aGroup.AnimalState.Urine.Nu[P]); break; case StockProps.prpRETAINED_S: dValue = aGroup.AnimalState.Sulf_Intake.Total - (aGroup.AnimalState.InOrgFaeces.Nu[S] + aGroup.AnimalState.OrgFaeces.Nu[S] + aGroup.AnimalState.Urine.Nu[S]); break; case StockProps.prpURINE_N: dValue = aGroup.AnimalState.Urine.Nu[N]; break; case StockProps.prpURINE_P: dValue = aGroup.AnimalState.Urine.Nu[P]; break; case StockProps.prpURINE_S: dValue = aGroup.AnimalState.Urine.Nu[S]; break; case StockProps.prpCH4_OUTPUT: dValue = 0.001 * aGroup.MethaneWeight; // Convert g/d to kg/d break; case StockProps.prpRDPI: dValue = aGroup.AnimalState.RDP_Intake; break; case StockProps.prpRDPR: dValue = aGroup.AnimalState.RDP_Reqd; break; case StockProps.prpRDP_EFFECT: dValue = aGroup.AnimalState.RDP_IntakeEffect; break; case StockProps.prpINTAKE_MOD: dValue = aGroup.IntakeModifier; break; default: Result = false; break; } } if (!bUseTag && !bUseAll) aValue[Idx - 1] = dValue; else if (varCode == StockProps.prpDSE) // Sum DSE's; take a weighted average of dTotal = dTotal + dValue; // all other values else if (aGroup != null) { dTotal = dTotal + aGroup.NoAnimals * dValue; iDenom = iDenom + aGroup.NoAnimals; } } //_ loop over animal groups _ } if ((varCode != StockProps.prpDSE) && (iDenom > 0)) dTotal = dTotal / iDenom; if (bUseAll) aValue[0] = dTotal; else if (bUseTag) aValue[iPass - 1] = dTotal; } //_ loop over passes _ return Result; }
/// <summary> /// /// </summary> /// <param name="Model"></param> /// <param name="Animal"></param> /// <param name="aValue"></param> public static void MakeCattleValue(TStockList Model, GrazType.AnimalType Animal, ref TCattleInit[] aValue) { TAnimalGroup aGroup; int iCount; int Idx, Jdx; iCount = 0; for (Idx = 1; Idx <= Model.Count(); Idx++) if (Model.At(Idx).Genotype.Animal == Animal) iCount++; Array.Resize(ref aValue, iCount); Jdx = 0; for (Idx = 1; Idx <= Model.Count(); Idx++) { if (Model.At(Idx).Genotype.Animal == Animal) { aGroup = Model.At(Idx); aValue[Jdx] = new TCattleInit(); aValue[Jdx].genotype = aGroup.Genotype.sName; aValue[Jdx].number = aGroup.NoAnimals; aValue[Jdx].sex = Model.SexString(Idx, false); aValue[Jdx].age = aGroup.AgeDays; aValue[Jdx].weight = aGroup.LiveWeight; aValue[Jdx].max_prev_wt = aGroup.MaxPrevWeight; aValue[Jdx].pregnant = aGroup.Pregnancy; aValue[Jdx].lactating = aGroup.Lactation; /*if (Animal == GrazType.AnimalType.Sheep) { aValue[Jdx].fleece_wt = aGroup.FleeceCutWeight; aValue[Jdx].fibre_diam = aGroup.FibreDiam; aValue[Jdx].no_young = Math.Max(aGroup.NoFoetuses, aGroup.NoOffspring); } else*/ if (Animal == GrazType.AnimalType.Cattle) { aValue[Jdx].no_foetuses = aGroup.NoFoetuses; aValue[Jdx].no_suckling = aGroup.NoOffspring; } if (aGroup.Lactation > 0) aValue[Jdx].birth_cs = aGroup.BirthCondition; if ((aGroup.Pregnancy > 0) || (aGroup.Young != null)) { if (aGroup.MatedTo != null) aValue[Jdx].mated_to = aGroup.MatedTo.sName; else aValue[Jdx].mated_to = ""; } else aValue[Jdx].mated_to = ""; if (aGroup.Young != null) { /*if (Animal == GrazType.AnimalType.Sheep) { aValue[Jdx].lamb_wt = aGroup.Young.LiveWeight; aValue[Jdx].lamb_fleece_wt = aGroup.Young.FleeceCutWeight; } else*/ if (Animal == GrazType.AnimalType.Cattle) aValue[Jdx].calf_wt = aGroup.Young.LiveWeight; aValue[Jdx].paddock = Model.getInPadd(Idx); aValue[Jdx].tag = Model.getTag(Idx); aValue[Jdx].priority = Model.getPriority(Idx); } } Jdx++; } // next animal }