private void OnCLEMInitialiseActivity(object sender, EventArgs e) { people = Resources.Labour(); food = Resources.HumanFoodStore(); bankAccount = Resources.GetResourceItem(this, AccountName, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as FinanceType; Market = FindMarket(); }
/// <summary> /// Model each pool in the HumanFoodStore /// </summary> public IEnumerable <HumanFoodStoreType> GetHumanStoreTypes(HumanFoodStore store) { List <HumanFoodStoreType> types = new List <HumanFoodStoreType>(); // Add grain products to the store foreach (int id in GrainIDs) { // Check if the crop is stored at home double home_storage = CropSpecs.GetData <double>(id + 1, 1); if (home_storage <= 0) { continue; } // Add the grain type to the store types.Add(new HumanFoodStoreType(store) { Name = CropSpecs.RowNames[id + 1] }); } // Add milk products to the store foreach (int id in RumIDs) { // Check if milk is stored at home double home_milk = RumSpecs.GetData <double>(18, id); if (home_milk <= 0) { continue; } // Add the milk type to the store types.Add(new HumanFoodStoreType(store) { Name = RumSpecs.ColumnNames[id] + "_Milk" }); } return(types); }
/// <summary> /// Method to determine resources required for this activity in the current month /// </summary> /// <returns>List of required resource requests</returns> public override List <ResourceRequest> GetResourcesNeededForActivity() { if (people is null | food is null) { return(null); } List <LabourType> peopleList = people.Items.Where(a => IncludeHiredLabour || a.Hired == false).ToList(); peopleList.Select(a => a.FeedToTargetIntake == 0); // determine AEs to be fed double aE = peopleList.Sum(a => a.AdultEquivalent); if (aE <= 0) { return(null); } int daysInMonth = DateTime.DaysInMonth(Clock.Today.Year, Clock.Today.Month); // determine feed limits (max kg per AE per day * AEs * days) double intakeLimit = DailyIntakeLimit * aE * daysInMonth; // remove previous consumption double otherIntake = this.DailyIntakeOtherSources * aE * daysInMonth; otherIntake += peopleList.Sum(a => a.GetAmountConsumed()); List <LabourActivityFeedTarget> labourActivityFeedTargets = this.FindAllChildren <LabourActivityFeedTarget>().Cast <LabourActivityFeedTarget>().ToList(); // determine targets foreach (LabourActivityFeedTarget target in labourActivityFeedTargets) { // calculate target target.Target = target.TargetValue * aE * daysInMonth; // set initial level based on off store inputs target.CurrentAchieved = target.OtherSourcesValue * aE * daysInMonth; // calculate current level from previous intake this month (LabourActivityFeed) target.CurrentAchieved += people.GetDietaryValue(target.Metric, IncludeHiredLabour, true) * aE * daysInMonth; // add sources outside of this activity to peoples' diets if (target.OtherSourcesValue > 0) { foreach (var person in peopleList) { LabourDietComponent outsideEat = new LabourDietComponent(); outsideEat.AddOtherSource(target.Metric, target.OtherSourcesValue * person.AdultEquivalent * daysInMonth); person.AddIntake(outsideEat); } } } // get max months before spoiling of all food stored (will be zero for non perishable food) int maxFoodAge = food.FindAllChildren <HumanFoodStoreType>().Cast <HumanFoodStoreType>().Max(a => a.Pools.Select(b => a.UseByAge - b.Age).DefaultIfEmpty(0).Max()); // create list of all food parcels List <HumanFoodParcel> foodParcels = new List <HumanFoodParcel>(); foreach (HumanFoodStoreType foodStore in food.FindAllChildren <HumanFoodStoreType>().Cast <HumanFoodStoreType>().ToList()) { foreach (HumanFoodStorePool pool in foodStore.Pools) { foodParcels.Add(new HumanFoodParcel() { FoodStore = foodStore, Pool = pool, Expires = ((foodStore.UseByAge == 0) ? maxFoodAge + 1: foodStore.UseByAge - pool.Age) }); } } foodParcels = foodParcels.OrderBy(a => a.Expires).ToList(); // if a market exists add the available market produce to the list below that ordered above. // order market food by price ascending // this will include market available food in the decisions. // will need to purchase this food before taking it if cost associated. // We can check if the parent of the human food store used is a market and charge accordingly. // for each market List <HumanFoodParcel> marketFoodParcels = new List <HumanFoodParcel>(); ResourcesHolder resources = Resources.FoundMarket.Resources; if (resources != null) { HumanFoodStore food = resources.HumanFoodStore(); if (food != null) { foreach (HumanFoodStoreType foodStore in food.FindAllChildren <HumanFoodStoreType>()) { foreach (HumanFoodStorePool pool in foodStore.Pools) { marketFoodParcels.Add(new HumanFoodParcel() { FoodStore = foodStore, Pool = pool, Expires = ((foodStore.UseByAge == 0) ? maxFoodAge + 1 : foodStore.UseByAge - pool.Age) }); } } } } foodParcels.AddRange(marketFoodParcels.OrderBy(a => a.FoodStore.Price(PurchaseOrSalePricingStyleType.Purchase).PricePerPacket)); double fundsAvailable = double.PositiveInfinity; if (bankAccount != null) { fundsAvailable = bankAccount.FundsAvailable; } int parcelIndex = 0; double intake = otherIntake; // start eating food from list from that about to expire first while (parcelIndex < foodParcels.Count) { foodParcels[parcelIndex].Proportion = 0; if (intake < intakeLimit & (labourActivityFeedTargets.Where(a => !a.TargetMet).Count() > 0 | foodParcels[parcelIndex].Expires == 0)) { // still able to eat and target not met or food about to expire this timestep // reduce by amout that can be eaten double propCanBeEaten = Math.Min(1, (intakeLimit - intake) / (foodParcels[parcelIndex].FoodStore.EdibleProportion * foodParcels[parcelIndex].Pool.Amount)); // reduce to target limits double propToTarget = 1; if (foodParcels[parcelIndex].Expires != 0) { // if the food is not going to spoil // then adjust what can be eaten up to target otherwise allow over target consumption to avoid waste LabourActivityFeedTarget targetUnfilled = labourActivityFeedTargets.Where(a => !a.TargetMet).FirstOrDefault(); if (targetUnfilled != null) { // calculate reduction to metric target double metricneeded = Math.Max(0, targetUnfilled.Target - targetUnfilled.CurrentAchieved); double amountneeded = metricneeded / foodParcels[parcelIndex].FoodStore.ConversionFactor(targetUnfilled.Metric); propToTarget = Math.Min(1, amountneeded / (foodParcels[parcelIndex].FoodStore.EdibleProportion * foodParcels[parcelIndex].Pool.Amount)); } } foodParcels[parcelIndex].Proportion = Math.Min(propCanBeEaten, propToTarget); // work out if there will be a cost limitation, only if a price structure exists for the resource double propToPrice = 1; if (foodParcels[parcelIndex].FoodStore.PricingExists(PurchaseOrSalePricingStyleType.Purchase)) { ResourcePricing price = foodParcels[parcelIndex].FoodStore.Price(PurchaseOrSalePricingStyleType.Purchase); double cost = (foodParcels[parcelIndex].Pool.Amount * foodParcels[parcelIndex].Proportion) / price.PacketSize * price.PricePerPacket; if (cost > 0) { propToPrice = Math.Min(1, fundsAvailable / cost); // remove cost from running check tally fundsAvailable = Math.Max(0, fundsAvailable - (cost * propToPrice)); // real finance transactions will happen in the do activity as stuff is allocated // there should not be shortfall as all the checks and reductions have happened here } } foodParcels[parcelIndex].Proportion *= propToPrice; // update intake double newIntake = (foodParcels[parcelIndex].FoodStore.EdibleProportion * foodParcels[parcelIndex].Pool.Amount * foodParcels[parcelIndex].Proportion); intake += newIntake; // update metrics foreach (LabourActivityFeedTarget target in labourActivityFeedTargets) { target.CurrentAchieved += newIntake * foodParcels[parcelIndex].FoodStore.ConversionFactor(target.Metric); } } else if (intake >= intakeLimit && labourActivityFeedTargets.Where(a => !a.TargetMet).Count() > 1) { // full but could still reach target with some substitution // but can substitute to remove a previous target // does the current parcel have better target values than any previous non age 0 pool of a different food type } else { break; } parcelIndex++; } // fill resource requests List <ResourceRequest> requests = new List <ResourceRequest>(); foreach (var item in foodParcels.GroupBy(a => a.FoodStore)) { double amount = item.Sum(a => a.Pool.Amount * a.Proportion); if (amount > 0) { double financeLimit = 1; // if obtained from the market make financial transaction before taking ResourcePricing price = item.Key.Price(PurchaseOrSalePricingStyleType.Sale); if (bankAccount != null && item.Key.Parent.Parent.Parent == Market && price.PricePerPacket > 0) { // if shortfall reduce purchase ResourceRequest marketRequest = new ResourceRequest { ActivityModel = this, Required = amount / price.PacketSize * price.PricePerPacket, AllowTransmutation = false, Category = "Food purchase", MarketTransactionMultiplier = 1 }; bankAccount.Remove(marketRequest); } requests.Add(new ResourceRequest() { Resource = item.Key, ResourceType = typeof(HumanFoodStore), AllowTransmutation = false, Required = amount * financeLimit, ResourceTypeName = item.Key.Name, ActivityModel = this, Category = "Consumption" }); } } // if still hungry and funds available, try buy food in excess of what stores (private or market) offered using transmutation if present. // This will force the market or private sources to purchase more food to meet demand if transmutation available. // if no market is present it will look to transmutating from its own stores if possible. // this means that other than a purchase from market (above) this activity doesn't need to worry about financial tranactions. if (intake < intakeLimit && (labourActivityFeedTargets.Where(a => !a.TargetMet).Count() > 0) && fundsAvailable > 0) { ResourcesHolder resourcesHolder = Resources; // if market is present point to market to find the resource if (Market != null) { resourcesHolder = Market.FindChild <ResourcesHolder>(); } // don't worry about money anymore. The over request will be handled by the transmutation. // move through specified purchase list foreach (LabourActivityFeedTargetPurchase purchase in this.FindAllChildren <LabourActivityFeedTargetPurchase>().Cast <LabourActivityFeedTargetPurchase>().ToList()) { HumanFoodStoreType foodtype = resourcesHolder.GetResourceItem(this, purchase.FoodStoreName, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as HumanFoodStoreType; if (foodtype != null && (foodtype.TransmutationDefined & intake < intakeLimit)) { LabourActivityFeedTarget targetUnfilled = labourActivityFeedTargets.Where(a => !a.TargetMet).FirstOrDefault(); if (targetUnfilled != null) { // calculate reduction to metric target double metricneeded = Math.Max(0, (targetUnfilled.Target - targetUnfilled.CurrentAchieved)); double amountneeded = metricneeded / foodtype.ConversionFactor(targetUnfilled.Metric); if (intake + amountneeded > intakeLimit) { amountneeded = intakeLimit - intake; } double amountfood = amountneeded / foodtype.EdibleProportion; // update intake intake += amountfood; // find in requests or create a new one ResourceRequest foodRequestFound = requests.Find(a => a.Resource == foodtype) as ResourceRequest; if (foodRequestFound is null) { requests.Add(new ResourceRequest() { Resource = foodtype, ResourceType = typeof(HumanFoodStore), AllowTransmutation = true, Required = amountfood, ResourceTypeName = purchase.FoodStoreName.Split('.')[1], ActivityModel = this, Category = "Consumption" }); } else { foodRequestFound.Required += amountneeded; foodRequestFound.AllowTransmutation = true; } } } } // NOTE: proportions of purchased food are not modified if the sum does not add up to 1 or some of the food types are not available. } return(requests); }
/// <inheritdoc/> public override List <ResourceRequest> GetResourcesNeededForActivity() { if (people is null | food is null) { return(null); } List <LabourType> peopleList = people.Items.Where(a => IncludeHiredLabour || a.Hired == false).ToList(); peopleList.Select(a => { a.FeedToTargetIntake = 0; return(a); }).ToList(); // determine AEs to be fed double aE = peopleList.Sum(a => a.TotalAdultEquivalents); if (aE <= 0) { return(null); } int daysInMonth = DateTime.DaysInMonth(clock.Today.Year, clock.Today.Month); // determine feed limits (max kg per AE per day * AEs * days) double intakeLimit = DailyIntakeLimit * aE * daysInMonth; // remove previous consumption double otherIntake = this.DailyIntakeOtherSources * aE * daysInMonth; otherIntake += peopleList.Sum(a => a.GetAmountConsumed()); List <LabourActivityFeedTarget> labourActivityFeedTargets = this.FindAllChildren <LabourActivityFeedTarget>().ToList(); // determine targets foreach (LabourActivityFeedTarget target in labourActivityFeedTargets) { // calculate target target.Target = target.TargetValue * aE * daysInMonth; // calculate target maximum target.TargetMaximum = target.TargetMaximumValue * aE * daysInMonth; // set initial level based on off store inputs target.CurrentAchieved = target.OtherSourcesValue * aE * daysInMonth; // calculate current level from previous intake this month (LabourActivityFeed) target.CurrentAchieved += people.GetDietaryValue(target.Metric, IncludeHiredLabour, false); // * aE; // * daysInMonth; // add sources outside of this activity to peoples' diets if (target.OtherSourcesValue > 0) { foreach (var person in peopleList) { LabourDietComponent outsideEat = new LabourDietComponent(); // TODO: might need to add consumed here outsideEat.AmountConsumed = this.DailyIntakeOtherSources * person.TotalAdultEquivalents * daysInMonth; outsideEat.AddOtherSource(target.Metric, target.OtherSourcesValue * person.TotalAdultEquivalents * daysInMonth); // track this consumption by people here. person.AddIntake(outsideEat); person.FeedToTargetIntake += outsideEat.AmountConsumed; } } } // get max months before spoiling of all food stored (will be zero for non perishable food) int maxFoodAge = food.FindAllChildren <HumanFoodStoreType>().Max(a => a.Pools.Select(b => a.UseByAge - b.Age).DefaultIfEmpty(0).Max()); // create list of all food parcels List <HumanFoodParcel> foodParcels = new List <HumanFoodParcel>(); foreach (HumanFoodStoreType foodStore in food.FindAllChildren <HumanFoodStoreType>().ToList()) { foreach (HumanFoodStorePool pool in foodStore.Pools.Where(a => a.Amount > 0)) { foodParcels.Add(new HumanFoodParcel() { FoodStore = foodStore, Pool = pool, Expires = ((foodStore.UseByAge == 0) ? maxFoodAge + 1: foodStore.UseByAge - pool.Age) }); } } foodParcels = foodParcels.OrderBy(a => a.Expires).ToList(); // if a market exists add the available market produce to the list below that ordered above. // order market food by price ascending // this will include market available food in the decisions. // will need to purchase this food before taking it if cost associated. // We can check if the parent of the human food store used is a market and charge accordingly. // for each market List <HumanFoodParcel> marketFoodParcels = new List <HumanFoodParcel>(); ResourcesHolder resources = Market?.Resources; if (resources != null) { HumanFoodStore food = resources.FindResourceGroup <HumanFoodStore>(); if (food != null) { foreach (HumanFoodStoreType foodStore in food.FindAllChildren <HumanFoodStoreType>()) { foreach (HumanFoodStorePool pool in foodStore.Pools.Where(a => a.Amount > 0)) { marketFoodParcels.Add(new HumanFoodParcel() { FoodStore = foodStore, Pool = pool, Expires = ((foodStore.UseByAge == 0) ? maxFoodAge + 1 : foodStore.UseByAge - pool.Age) }); } } } } foodParcels.AddRange(marketFoodParcels.OrderBy(a => a.FoodStore.Price(PurchaseOrSalePricingStyleType.Purchase).PricePerPacket)); double fundsAvailable = double.PositiveInfinity; if (bankAccount != null) { fundsAvailable = bankAccount.FundsAvailable; } int parcelIndex = 0; double metricneeded = 0; double intake = otherIntake; // start eating food from list from that about to expire first // food from household can be eaten up to target maximum // food from market can only be eaten up to target while (parcelIndex < foodParcels.Count) { foodParcels[parcelIndex].Proportion = 0; var isHousehold = foodParcels[parcelIndex].FoodStore.CLEMParentName == this.CLEMParentName; if (intake < intakeLimit & (labourActivityFeedTargets.Where(a => ((isHousehold)? !a.TargetMaximumAchieved: !a.TargetAchieved)).Count() > 0 | foodParcels[parcelIndex].Expires == 0)) { // still able to eat and target not met or food about to expire this timestep // reduce by amout that can be eaten double propCanBeEaten = Math.Min(1, (intakeLimit - intake) / (foodParcels[parcelIndex].FoodStore.EdibleProportion * foodParcels[parcelIndex].Pool.Amount)); // reduce to target limits double propToTarget = 1; if (foodParcels[parcelIndex].Expires != 0) { // if the food is not going to spoil // then adjust what can be eaten up to target otherwise allow over target consumption to avoid waste LabourActivityFeedTarget targetUnfilled = labourActivityFeedTargets.Where(a => ((isHousehold) ? !a.TargetMaximumAchieved : !a.TargetAchieved)).FirstOrDefault(); if (targetUnfilled != null) { // calculate reduction to metric target metricneeded = Math.Max(0, (isHousehold ? targetUnfilled.TargetMaximum : targetUnfilled.Target) - targetUnfilled.CurrentAchieved); double amountneeded = metricneeded / foodParcels[parcelIndex].FoodStore.ConversionFactor(targetUnfilled.Metric); propToTarget = Math.Min(1, amountneeded / (foodParcels[parcelIndex].FoodStore.EdibleProportion * foodParcels[parcelIndex].Pool.Amount)); } } foodParcels[parcelIndex].Proportion = Math.Min(propCanBeEaten, propToTarget); // work out if there will be a cost limitation, only if a price structure exists for the resource // no charge for household consumption double propToPrice = 1; if (!isHousehold && foodParcels[parcelIndex].FoodStore.PricingExists(PurchaseOrSalePricingStyleType.Purchase)) { ResourcePricing price = foodParcels[parcelIndex].FoodStore.Price(PurchaseOrSalePricingStyleType.Purchase); double cost = (foodParcels[parcelIndex].Pool.Amount * foodParcels[parcelIndex].Proportion) / price.PacketSize * price.PricePerPacket; // TODO: sell cattle based on selling groups till run out of cattle or meet shortfall // adjust fundsAvailable with new money // if cost > 0 and cost > funds available if (cost > 0) { propToPrice = Math.Min(1, fundsAvailable / cost); // remove cost from running check tally fundsAvailable = Math.Max(0, fundsAvailable - (cost * propToPrice)); // real finance transactions will happen in the do activity as stuff is allocated // there should not be shortfall as all the checks and reductions have happened here } } foodParcels[parcelIndex].Proportion *= propToPrice; // update intake double newIntake = (foodParcels[parcelIndex].FoodStore.EdibleProportion * foodParcels[parcelIndex].Pool.Amount * foodParcels[parcelIndex].Proportion); intake += newIntake; // update metrics foreach (LabourActivityFeedTarget target in labourActivityFeedTargets) { target.CurrentAchieved += newIntake * foodParcels[parcelIndex].FoodStore.ConversionFactor(target.Metric); } } else if (intake >= intakeLimit && labourActivityFeedTargets.Where(a => ((isHousehold) ? !a.TargetMaximumAchieved : !a.TargetAchieved)).Count() > 1) { // full but could still reach target with some substitution // but can substitute to remove a previous target // does the current parcel have better target values than any previous non age 0 pool of a different food type } else { break; } parcelIndex++; } // fill resource requests List <ResourceRequest> requests = new List <ResourceRequest>(); foreach (var item in foodParcels.GroupBy(a => a.FoodStore)) { double amount = item.Sum(a => a.Pool.Amount * a.Proportion); if (amount > 0) { double financeLimit = 1; // if obtained from the market make financial transaction before taking ResourcePricing price = item.Key.Price(PurchaseOrSalePricingStyleType.Sale); bool marketIsSource = item.Key.Parent.Parent.Parent == Market; if (bankAccount != null && marketIsSource && price.PricePerPacket > 0) { // finance transaction to buy food from market ResourceRequest marketRequest = new ResourceRequest { ActivityModel = this, Required = amount / price.PacketSize * price.PricePerPacket, AllowTransmutation = false, Category = $"{TransactionCategory}.PurchaseFood", MarketTransactionMultiplier = 1, RelatesToResource = item.Key.NameWithParent }; bankAccount.Remove(marketRequest); } // is this a market requests.Add(new ResourceRequest() { Resource = item.Key, ResourceType = typeof(HumanFoodStore), AllowTransmutation = false, Required = amount * financeLimit, ResourceTypeName = item.Key.NameWithParent, ActivityModel = this, Category = $"{TransactionCategory}{(marketIsSource?".FromMarket":".FromHousehold")}" }); } } // if still hungry and funds available, try buy food in excess of what stores (private or market) offered using transmutation if present. // This will force the market or private sources to purchase more food to meet demand if transmutation available. // if no market is present it will look to transmutating from its own stores if possible. // this means that other than a purchase from market (above) this activity doesn't need to worry about financial tranactions. int testType = 0; // test is limited to 1 for now so only to metric target NOT intake limit as we use maximum and target values now while (testType < 1 && intake < intakeLimit && (labourActivityFeedTargets.Where(a => !a.TargetAchieved).Any()) && fundsAvailable > 0) { // don't worry about money anymore. The over request will be handled by the transmutation. // move through specified purchase list // 1. to assign based on energy // 2. if still need food assign based on intake still needed metricneeded = 0; LabourActivityFeedTarget targetUnfilled = labourActivityFeedTargets.Where(a => !a.TargetAchieved).FirstOrDefault(); if (targetUnfilled != null) { metricneeded = Math.Max(0, (targetUnfilled.Target - targetUnfilled.CurrentAchieved)); double amountToFull = intakeLimit - intake; foreach (LabourActivityFeedTargetPurchase purchase in this.FindAllChildren <LabourActivityFeedTargetPurchase>()) { HumanFoodStoreType foodtype = purchase.FoodStore; if (purchase.ProportionToPurchase > 0 && foodtype != null && (foodtype.TransmutationDefined & intake < intakeLimit)) { double amountEaten = 0; if (testType == 0) { // metric target based on purchase proportion amountEaten = metricneeded / foodtype.ConversionFactor(targetUnfilled.Metric) * purchase.ProportionToPurchase; } else { // amount to satisfy limited by proportion of purchases amountEaten = amountToFull * purchase.ProportionToPurchase; } if (intake + amountEaten > intakeLimit) { amountEaten = intakeLimit - intake; } if (amountEaten > 0) { targetUnfilled.CurrentAchieved += amountEaten * foodtype.ConversionFactor(targetUnfilled.Metric); double amountPurchased = amountEaten / foodtype.EdibleProportion; // update intake.. needed is the amount edible, not the amount purchased. intake += amountEaten; // add financial transactions to purchase from market // if obtained from the market make financial transaction before taking ResourcePricing price = foodtype.Price(PurchaseOrSalePricingStyleType.Sale); if (bankAccount != null) { if (price.PricePerPacket > 0) { ResourceRequest marketRequest = new ResourceRequest { ActivityModel = this, Required = amountPurchased / price.PacketSize * price.PricePerPacket, AllowTransmutation = false, Category = "Import", MarketTransactionMultiplier = 1, RelatesToResource = foodtype.NameWithParent }; bankAccount.Remove(marketRequest); } else { string warn = $"No price set [{price.PricePerPacket}] for [r={foodtype.Name}] at time of transaction for [a={this.Name}]{Environment.NewLine}No financial transactions will occur.{Environment.NewLine}Ensure price is set or resource pricing file contains entries before this transaction or start of simulation."; Warnings.CheckAndWrite(warn, Summary, this, MessageType.Warning); } } // find in requests or create a new one ResourceRequest foodRequestFound = requests.Find(a => a.Resource == foodtype); if (foodRequestFound is null) { requests.Add(new ResourceRequest() { Resource = foodtype, ResourceType = typeof(HumanFoodStore), AllowTransmutation = true, Required = amountPurchased, ResourceTypeName = purchase.FoodStoreName, ActivityModel = this, Category = $"{TransactionCategory}.FromImports" }); } else { foodRequestFound.Required += amountPurchased; foodRequestFound.AllowTransmutation = true; } } } } testType++; } } return(requests); }
private void OnCLEMInitialiseActivity(object sender, EventArgs e) { people = Resources.FindResourceGroup <Labour>(); food = Resources.FindResourceGroup <HumanFoodStore>(); bankAccount = Resources.FindResourceType <Finance, FinanceType>(this, AccountName, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore); Market = food.FindAncestor <ResourcesHolder>().FoundMarket; resourcesHolder = base.Resources; // if market is present point to market to find the resource if (Market != null) { resourcesHolder = Market.FindChild <ResourcesHolder>(); } // set the food store linked in any TargetPurchase if target proportion set > 0 // check that all purchase resources have transmutation or recalulate the proportion var targetPurchases = this.FindAllChildren <LabourActivityFeedTargetPurchase>().Where(a => a.TargetProportion > 0).ToList(); if (targetPurchases.Any()) { double checkPropAvailable = 0; double totPropAvailable = 0; bool adjusted = false; foreach (var item in targetPurchases) { checkPropAvailable += item.TargetProportion; item.FoodStore = resourcesHolder.FindResourceType <HumanFoodStore, HumanFoodStoreType>(this, item.FoodStoreName, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore); if (item.FoodStore.TransmutationDefined) { totPropAvailable += item.TargetProportion; item.ProportionToPurchase = item.TargetProportion; } else { string warn = $"The HumanFoodStoreType [r={item.FoodStore.FullPath}] does not have a Transmutation required to be a LabourActivityFeedTargetPurchase [a={item.FullPath}] of [a={this.FullPath}]{Environment.NewLine}This HumanFoodStore will not be allocated and the remaining purchase proportions have been adjusted"; Warnings.CheckAndWrite(warn, Summary, this, MessageType.Warning); adjusted = true; item.ProportionToPurchase = 0; } } if (Math.Abs(1 - checkPropAvailable) < 0.0001) { if (!adjusted) { string warn = $"The TargetProportions provided for [a=LabourActivityFeedTargetPurchase] provided for [a={this.FullPath}] do not sum to 1.{Environment.NewLine}These purchase proportions have been adjusted"; Warnings.CheckAndWrite(warn, Summary, this, MessageType.Warning); } adjusted = true; } // recalculate proportions to buy based on transmuation of resource allowed if (adjusted) { foreach (var item in targetPurchases.Where(a => a.FoodStore.TransmutationDefined)) { item.ProportionToPurchase = item.TargetProportion / totPropAvailable; } } } }
private void OnCLEMInitialiseActivity(object sender, EventArgs e) { people = Resources.GetResourceGroupByType(typeof(Labour)) as Labour; food = Resources.GetResourceGroupByType(typeof(HumanFoodStore)) as HumanFoodStore; }
private void OnCLEMInitialiseActivity(object sender, EventArgs e) { people = Resources.FindResourceGroup <Labour>(); food = Resources.FindResourceGroup <HumanFoodStore>(); bankAccount = Resources.FindResourceType <Finance, FinanceType>(this, AccountName, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore); }
private void OnCLEMInitialiseActivity(object sender, EventArgs e) { people = Resources.GetResourceGroupByType(typeof(Labour)) as Labour; food = Resources.GetResourceGroupByType(typeof(HumanFoodStore)) as HumanFoodStore; bankAccount = Resources.GetResourceItem(this, AccountName, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as FinanceType; }
public IEnumerable <HumanFoodStoreType> GetHumanStoreTypes(HumanFoodStore store) { return(null); }