private void OnSimulationCommencing(object sender, EventArgs e) { // locate FeedType resource bool resourceAvailable = false; FeedType = Resources.GetResourceItem("AnimalFoodStore", FeedTypeName, out resourceAvailable) as IFeedType; FoodSource = FeedType; if (LabourRequired > 0) { // check for and assign labour filter group LabourFilterList = this.Children.Where(a => a.GetType() == typeof(LabourFilterGroup)).Cast <object>().ToList(); // if not present assume can use any labour and report if (LabourFilterList == null) { Summary.WriteWarning(this, String.Format("No labour filter details provided for feeding activity ({0}). Assuming any labour type can be used", this.Name)); LabourFilterGroup lfg = new LabourFilterGroup(); LabourFilter lf = new LabourFilter() { Operator = FilterOperators.GreaterThanOrEqual, Value = "0", Parameter = LabourFilterParameters.Age }; lfg.Children.Add(lf); LabourFilterList = new List <object>(); LabourFilterList.Add(lfg); } } }
public RuminantActivityGrazeAll(Node parent) : base(parent) { Name = "GrazeAll"; OnPartialResourcesAvailableAction = 2; var labour = new LabourRequirement(this); var group = new LabourFilterGroup(labour); var filter = new LabourFilter(group) { Parameter = 0, Operator = 0, Value = "Male" }; group.Add(filter); labour.Add(group); }
/// <summary> /// Validate this object /// </summary> /// <param name="validationContext"></param> /// <returns></returns> public IEnumerable <ValidationResult> Validate(ValidationContext validationContext) { var results = new List <ValidationResult>(); // ensure labour resource added Labour lab = Resources.GetResourceGroupByType(typeof(Labour)) as Labour; if (lab == null) { Summary.WriteWarning(this, "[a=" + this.Parent.Name + "][f=" + this.Name + "] No labour resorces in simulation. Labour requirement will be ignored."); } else { if (lab.Children.Count <= 0) { Summary.WriteWarning(this, "[a=" + this.Parent.Name + "][f=" + this.Name + "] No labour resorce types are provided in the labour resource. Labour requirement will be ignored."); } } // check filter groups present if (this.Children.OfType <LabourFilterGroup>().Count() == 0) { Summary.WriteWarning(this, "No LabourFilterGroup is supplied with the LabourRequirement for [a=" + this.Parent.Name + "]. No labour will be used for this activity."); } // check for individual nesting. foreach (LabourFilterGroup fg in this.Children.OfType <LabourFilterGroup>()) { LabourFilterGroup currentfg = fg; while (currentfg != null && currentfg.Children.OfType <LabourFilterGroup>().Count() >= 1) { if (currentfg.Children.OfType <LabourFilterGroup>().Count() > 1) { string[] memberNames = new string[] { "Labour requirement" }; results.Add(new ValidationResult(String.Format("Invalid nested labour filter groups in [f={0}] for [a={1}]. Only one nested filter group is permitted each branch. Additional filtering will be ignored.", currentfg.Name, this.Name), memberNames)); } currentfg = currentfg.Children.OfType <LabourFilterGroup>().FirstOrDefault(); } } return(results); }
private void OnStartOfSimulation(object sender, EventArgs e) { // This needs to happen after all manage pasture activities have been initialised on commencing // Therefore we use StartOfSimulation event // link to pasture to muster to pasture = Activities.GetByName(ManagedPastureName) as PastureActivityManage; if (pasture == null) { Summary.WriteWarning(this, String.Format("Could not find manage pasture activity named \"{0}\" for {1}", ManagedPastureName, this.Name)); throw new Exception(String.Format("Invalid pasture name ({0}) provided for mustering activity {1}", ManagedPastureName, this.Name)); } if (LabourRequired > 0) { // check for and assign labour filter group LabourFilterList = this.Children.Where(a => a.GetType() == typeof(LabourFilterGroup)).Cast <object>().ToList(); // if not present assume can use any labour and report if (LabourFilterList == null) { Summary.WriteWarning(this, String.Format("No labour filter details provided for feeding activity ({0}). Assuming any labour type can be used", this.Name)); LabourFilterGroup lfg = new LabourFilterGroup(); LabourFilter lf = new LabourFilter() { Operator = FilterOperators.GreaterThanOrEqual, Value = "0", Parameter = LabourFilterParameters.Age }; lfg.Children.Add(lf); LabourFilterList = new List <object>(); LabourFilterList.Add(lfg); } } if (PerformAtStartOfSimulation) { Muster(); } }
private void OnSimulationCommencing(object sender, EventArgs e) { // check payment interval > 0 if (BreedInterval <= 0) { Summary.WriteWarning(this, String.Format("Controlled mating interval must be greater than 1 ({0})", this.Name)); throw new Exception(String.Format("Invalid controlled mating interval supplied for overhead {0}", this.Name)); } if (MonthDue >= Clock.StartDate.Month) { NextDueDate = new DateTime(Clock.StartDate.Year, MonthDue, Clock.StartDate.Day); } else { NextDueDate = new DateTime(Clock.StartDate.Year, MonthDue, Clock.StartDate.Day); while (Clock.StartDate > NextDueDate) { NextDueDate = NextDueDate.AddMonths(BreedInterval); } } // check for and assign labour filter group LabourFilterList = this.Children.Where(a => a.GetType() == typeof(LabourFilterGroup)).Cast <object>().ToList(); // if not present assume can use any labour and report if (LabourFilterList == null) { Summary.WriteWarning(this, String.Format("No labour filter details provided for controlled mating settings ({0}). Assuming any labour type can be used", this.Name)); LabourFilterGroup lfg = new LabourFilterGroup(); LabourFilter lf = new LabourFilter() { Operator = FilterOperators.GreaterThanOrEqual, Value = "0", Parameter = LabourFilterParameters.Age }; lfg.Children.Add(lf); LabourFilterList = new List <object>(); LabourFilterList.Add(lfg); } }
/// <summary> /// Method to determine available labour based on filters and take it if requested. /// </summary> /// <param name="request">Resource request details</param> /// <param name="removeFromResource">Determines if only calculating available labour or labour removed</param> /// <param name="callingModel">Model calling this method</param> /// <param name="resourceHolder">Location of resource holder</param> /// <param name="partialAction">Action on partial resources available</param> /// <returns></returns> public static double TakeLabour(ResourceRequest request, bool removeFromResource, IModel callingModel, ResourcesHolder resourceHolder, OnPartialResourcesAvailableActionTypes partialAction) { double amountProvided = 0; double amountNeeded = request.Required; LabourFilterGroup current = request.FilterDetails.OfType <LabourFilterGroup>().FirstOrDefault() as LabourFilterGroup; LabourRequirement lr; if (current != null) { if (current.Parent is LabourRequirement) { lr = current.Parent as LabourRequirement; } else { // coming from Transmutation request lr = new LabourRequirement() { ApplyToAll = false, MaximumPerPerson = 1000, MinimumPerPerson = 0 }; } } else { lr = Apsim.Children(callingModel, typeof(LabourRequirement)).FirstOrDefault() as LabourRequirement; } int currentIndex = 0; if (current == null) { // no filtergroup provided so assume any labour current = new LabourFilterGroup(); } request.ResourceTypeName = "Labour"; ResourceRequest removeRequest = new ResourceRequest() { ActivityID = request.ActivityID, ActivityModel = request.ActivityModel, AdditionalDetails = request.AdditionalDetails, AllowTransmutation = request.AllowTransmutation, Available = request.Available, FilterDetails = request.FilterDetails, Provided = request.Provided, Reason = request.Reason, Required = request.Required, Resource = request.Resource, ResourceType = request.ResourceType, ResourceTypeName = request.ResourceTypeName }; // start with top most LabourFilterGroup while (current != null && amountProvided < amountNeeded) { List <LabourType> items = (resourceHolder.GetResourceGroupByType(request.ResourceType) as Labour).Items; items = items.Where(a => (a.LastActivityRequestID != request.ActivityID) || (a.LastActivityRequestID == request.ActivityID && a.LastActivityRequestAmount < lr.MaximumPerPerson)).ToList(); items = items.Filter(current as Model); // search for people who can do whole task first while (amountProvided < amountNeeded && items.Where(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumPerPerson) >= request.Required).Count() > 0) { // get labour least available but with the amount needed LabourType lt = items.Where(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumPerPerson) >= request.Required).OrderBy(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumPerPerson)).FirstOrDefault(); double amount = Math.Min(amountNeeded - amountProvided, lt.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumPerPerson)); // limit to max allowed per person amount = Math.Min(amount, lr.MaximumPerPerson); // limit to min per person to do activity if (amount < lr.MinimumPerPerson) { request.Reason = "Min labour limit"; return(amountProvided); } amountProvided += amount; removeRequest.Required = amount; if (removeFromResource) { lt.LastActivityRequestID = request.ActivityID; lt.LastActivityRequestAmount = amount; lt.Remove(removeRequest); request.Provided += removeRequest.Provided; request.Value += request.Provided * lt.PayRate(); } } // if still needed and allow partial resource use. if (partialAction == OnPartialResourcesAvailableActionTypes.UseResourcesAvailable) { if (amountProvided < amountNeeded) { // then search for those that meet criteria and can do part of task foreach (LabourType item in items.Where(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumPerPerson) >= 0).OrderByDescending(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumPerPerson))) { if (amountProvided >= amountNeeded) { break; } double amount = Math.Min(amountNeeded - amountProvided, item.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumPerPerson)); // limit to max allowed per person amount = Math.Min(amount, lr.MaximumPerPerson); // limit to min per person to do activity if (amount >= lr.MinimumPerPerson) { amountProvided += amount; removeRequest.Required = amount; if (removeFromResource) { if (item.LastActivityRequestID != request.ActivityID) { item.LastActivityRequestAmount = 0; } item.LastActivityRequestID = request.ActivityID; item.LastActivityRequestAmount += amount; item.Remove(removeRequest); request.Provided += removeRequest.Provided; request.Value += request.Provided * item.PayRate(); } } else { currentIndex = request.FilterDetails.Count; } } } } currentIndex++; if (current.Children.OfType <LabourFilterGroup>().Count() > 0) { current = current.Children.OfType <LabourFilterGroup>().FirstOrDefault(); } else { current = null; } } // report amount gained. return(amountProvided); }
/// <summary> /// Method to determine available labour based on filters and take it if requested. /// </summary> /// <param name="request">Resource request details</param> /// <param name="removeFromResource">Determines if only calculating available labour or labour removed</param> /// <param name="callingModel">Model calling this method</param> /// <param name="resourceHolder">Location of resource holder</param> /// <param name="partialAction">Action on partial resources available</param> /// <returns></returns> public static double TakeLabour(ResourceRequest request, bool removeFromResource, IModel callingModel, ResourcesHolder resourceHolder, OnPartialResourcesAvailableActionTypes partialAction) { double amountProvided = 0; double amountNeeded = request.Required; LabourFilterGroup current = request.FilterDetails.OfType <LabourFilterGroup>().FirstOrDefault(); LabourRequirement lr; if (current != null) { if (current.Parent is LabourRequirement) { lr = current.Parent as LabourRequirement; } else { // coming from Transmutation request lr = new LabourRequirement() { LimitStyle = LabourLimitType.AsDaysRequired, ApplyToAll = false, MaximumPerGroup = 10000, MaximumPerPerson = 1000, MinimumPerPerson = 0 } }; } else { lr = callingModel.FindAllChildren <LabourRequirement>().FirstOrDefault(); } lr.CalculateLimits(amountNeeded); amountNeeded = Math.Min(amountNeeded, lr.MaximumDaysPerGroup); request.Required = amountNeeded; // may need to reduce request here or shortfalls will be triggered int currentIndex = 0; if (current == null) { // no filtergroup provided so assume any labour current = new LabourFilterGroup(); } request.ResourceTypeName = "Labour"; ResourceRequest removeRequest = new ResourceRequest() { ActivityID = request.ActivityID, ActivityModel = request.ActivityModel, AdditionalDetails = request.AdditionalDetails, AllowTransmutation = request.AllowTransmutation, Available = request.Available, FilterDetails = request.FilterDetails, Provided = request.Provided, Category = request.Category, RelatesToResource = request.RelatesToResource, Required = request.Required, Resource = request.Resource, ResourceType = request.ResourceType, ResourceTypeName = (request.Resource is null? "":(request.Resource as CLEMModel).NameWithParent) }; // start with top most LabourFilterGroup while (current != null && amountProvided < amountNeeded) { IEnumerable <LabourType> items = resourceHolder.FindResource <Labour>().Items; items = items.Where(a => (a.LastActivityRequestID != request.ActivityID) || (a.LastActivityRequestID == request.ActivityID && a.LastActivityRequestAmount < lr.MaximumDaysPerPerson)); items = current.Filter(items); // search for people who can do whole task first while (amountProvided < amountNeeded && items.Where(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumDaysPerPerson) >= request.Required).Any()) { // get labour least available but with the amount needed LabourType lt = items.Where(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumDaysPerPerson) >= request.Required).OrderBy(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumDaysPerPerson)).FirstOrDefault(); double amount = Math.Min(amountNeeded - amountProvided, lt.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumDaysPerPerson)); // limit to max allowed per person amount = Math.Min(amount, lr.MaximumDaysPerPerson); // limit to min per person to do activity if (amount < lr.MinimumPerPerson) { request.Category = "Min labour limit"; return(amountProvided); } amountProvided += amount; removeRequest.Required = amount; if (removeFromResource) { lt.LastActivityRequestID = request.ActivityID; lt.LastActivityRequestAmount = amount; lt.Remove(removeRequest); request.Provided += removeRequest.Provided; request.Value += request.Provided * lt.PayRate(); } } // if still needed and allow partial resource use. if (partialAction == OnPartialResourcesAvailableActionTypes.UseResourcesAvailable) { if (amountProvided < amountNeeded) { // then search for those that meet criteria and can do part of task foreach (LabourType item in items.Where(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumDaysPerPerson) >= 0).OrderByDescending(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumDaysPerPerson))) { if (amountProvided >= amountNeeded) { break; } double amount = Math.Min(amountNeeded - amountProvided, item.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumDaysPerPerson)); // limit to max allowed per person amount = Math.Min(amount, lr.MaximumDaysPerPerson); // limit to min per person to do activity if (amount >= lr.MinimumDaysPerPerson) { amountProvided += amount; removeRequest.Required = amount; if (removeFromResource) { if (item.LastActivityRequestID != request.ActivityID) { item.LastActivityRequestAmount = 0; } item.LastActivityRequestID = request.ActivityID; item.LastActivityRequestAmount += amount; item.Remove(removeRequest); request.Provided += removeRequest.Provided; request.Value += request.Provided * item.PayRate(); } } else { currentIndex = request.FilterDetails.Count; } } } } currentIndex++; var currentFilterGroups = current.FindAllChildren <LabourFilterGroup>(); if (currentFilterGroups.Any()) { current = currentFilterGroups.FirstOrDefault(); } else { current = null; } } // report amount gained. return(amountProvided); }