private void OnSimulationCommencing(object sender, EventArgs e) { Items = new List <GrazeFoodStoreType>(); List <IModel> childNodes = Apsim.Children(this, typeof(IModel)); foreach (IModel childModel in childNodes) { //cast the generic IModel to a specfic model. GrazeFoodStoreType grazefood = childModel as GrazeFoodStoreType; Items.Add(grazefood); } }
private void OnWFFeedAllocation(object sender, EventArgs e) { // if no requests end if (requests.Count() == 0) { return; } // month needed for montly pasture limits. int month = Clock.Today.Month; // get list of unique priorities provided in requests List <int> priorityList = requests.OrderBy(b => b.FeedActivity.FeedPriority).Select(a => a.FeedActivity.FeedPriority).Distinct().ToList(); foreach (int priority in priorityList) { // group by feed types requested with each priority var feedGrouping = requests.Where(a => a.FeedActivity.FeedPriority == priority).GroupBy(a => a.FeedActivity.FeedType); foreach (var feedTypeGroup in feedGrouping) { IFeedType feedType = feedTypeGroup.Key as IFeedType; // determine the total requested for each feedtype double amountRequested = feedTypeGroup.Sum(a => Math.Min(a.Amount, (a.Requestor.PotentialIntake - a.Requestor.Intake) * 30.4) * a.Requestor.Number); // if something requested and something available if (amountRequested > 0 & feedType.Amount > 0) { // determine if shortfall double deficit = Math.Min(1.0, feedType.Amount / amountRequested); if (deficit < 1.0) { // TODO: work out what do do. // Buy fodder // Use common land // use Animal Food Stores. } // prepare to take available from resource store amountRequested *= deficit; // group requests by ruminant breed to allow calculations of limits var breedGrouping = feedTypeGroup.GroupBy(a => a.Requestor.BreedParams.Name); foreach (var breedGroup in breedGrouping) { // If feeding on pasture calculate limits based on proportion green // This needs to be done for pasture/breed combinations each month // So cannot be done for Ruminants or Pasture seperately at start of month if (feedType.GetType().Name == "PastureType") { GrazeFoodStoreType pasture = feedType as GrazeFoodStoreType; double total = 0; foreach (var pool in pasture.Pools) { pool.Limit = 1.0; total += pool.Amount; } // if Jan-March then user first three months otherwise use 2 int greenage = 2; if (month <= 3) { greenage = 3; } double green = pasture.Pools.Where(a => (a.Age <= greenage)).Sum(b => b.Amount); double propgreen = green / total; double greenlimit = breedGroup.FirstOrDefault().Requestor.BreedParams.GreenDietMax *(1 - Math.Exp(-breedGroup.FirstOrDefault().Requestor.BreedParams.GreenDietCoefficient *((propgreen * 100.0) - breedGroup.FirstOrDefault().Requestor.BreedParams.GreenDietZero))); greenlimit = Math.Max(0.0, greenlimit); if (propgreen > 90) { greenlimit = 100; } foreach (var pool in pasture.Pools.Where(a => a.Age <= greenage)) { pool.Limit = greenlimit / 100.0; } } // update Ruminants Intake, ProteinConcentration and DietDryMatterDigestibility foreach (var request in feedTypeGroup) { switch (request.FeedActivity.FeedType.GetType().Name) { case "GrazeFoodStoreType": // take from pools as specified for the individual GrazeFoodStoreType pasture = request.FeedActivity.FeedType as GrazeFoodStoreType; double amountRequired = (request.Requestor.PotentialIntake - request.Requestor.Intake) * 30.4; int index = 0; bool secondTakeFromPools = request.Requestor.BreedParams.StrictFeedingLimits; while (amountRequired > 0) { // limiter obtained from filter group or unlimited if second take of pools double limiter = 1.0; if (!secondTakeFromPools) { limiter = pasture.Pools[index].Limit; } double amountToRemove = Math.Min(pasture.Pools[index].Amount, amountRequired * limiter); amountRequired -= amountToRemove; request.Amount = amountToRemove; pasture.Pools[index].Remove(request); index++; if (index >= pasture.Pools.Count) { // if we've already given second chance to get food so finish without full satisfying individual // or strict feeding limits are enforced if (secondTakeFromPools) { break; } // if not strict limits allow a second request for food from previously limited pools. secondTakeFromPools = true; index = 0; } } break; case "AnimalFoodStoreType": // take directly from store if available request.Amount *= deficit; feedTypeGroup.FirstOrDefault().FeedActivity.FeedType.Remove(request); break; default: string error = String.Format("Unrecognised feed type {0} in {1} of name {2}", request.GetType().ToString(), this.GetType().ToString(), this.Name); Summary.WriteWarning(this, error); throw new Exception("Unrecognised Feedtype found in feed request"); } } } } } } }