public SingleProcessStatistics(BioProcess process, float keepSnapshotTime = Constants.DEFAULT_PROCESS_STATISTICS_AVERAGE_INTERVAL) { this.keepSnapshotTime = keepSnapshotTime; Process = process; computedStatistics = new AverageProcessStatistics(this); }
private void RunProcess(float delta, BioProcess processData, CompoundBag bag, TweakedProcess process, SingleProcessStatistics currentProcessStatistics, float inverseDelta) { // Can your cell do the process bool canDoProcess = true; // Loop through to make sure you can follow through with your // whole process so nothing gets wasted as that would be // frustrating. float environmentModifier = 1.0f; // First check the environmental compounds so that we can build the right environment modifier for accurate // check of normal compound input amounts foreach (var entry in processData.Inputs) { // Set used compounds to be useful, we dont want to purge // those bag.SetUseful(entry.Key); if (!entry.Key.IsEnvironmental) { continue; } var dissolved = GetDissolved(entry.Key); // currentProcessStatistics?.AddInputAmount(entry.Key, entry.Value * inverseDelta); currentProcessStatistics?.AddInputAmount(entry.Key, dissolved); // do environmental modifier here, and save it for later environmentModifier *= dissolved / entry.Value; if (environmentModifier <= MathUtils.EPSILON) { currentProcessStatistics?.AddLimitingFactor(entry.Key); } } if (environmentModifier <= MathUtils.EPSILON) { canDoProcess = false; } foreach (var entry in processData.Inputs) { if (entry.Key.IsEnvironmental) { continue; } var inputRemoved = entry.Value * process.Rate * delta; currentProcessStatistics?.AddInputAmount(entry.Key, inputRemoved * inverseDelta); // currentProcessStatistics?.AddInputAmount(entry.Key, 0); // If not enough compound we can't do the process if (bag.GetCompoundAmount(entry.Key) < inputRemoved) { canDoProcess = false; currentProcessStatistics?.AddLimitingFactor(entry.Key); } } // Output // This is now always looped (even when we can't do the process) // because the is useful part is needs to be always be done foreach (var entry in processData.Outputs) { // For now lets assume compounds we produce are also // useful bag.SetUseful(entry.Key); // Apply the general modifiers and // apply the environmental modifier var outputAdded = entry.Value * process.Rate * delta * environmentModifier; currentProcessStatistics?.AddOutputAmount(entry.Key, outputAdded * inverseDelta); // currentProcessStatistics?.AddOutputAmount(entry.Key, 0); // If no space we can't do the process, and if environmental // right now this isn't released anywhere if (entry.Key.IsEnvironmental) { continue; } if (bag.GetCompoundAmount(entry.Key) + outputAdded > bag.Capacity) { canDoProcess = false; currentProcessStatistics?.AddCapacityProblem(entry.Key); } } // Only carry out this process if you have all the required // ingredients and enough space for the outputs if (!canDoProcess) { return; } if (currentProcessStatistics != null) { currentProcessStatistics.CurrentSpeed = process.Rate * environmentModifier; } // Consume inputs foreach (var entry in processData.Inputs) { if (entry.Key.IsEnvironmental) { continue; } var inputRemoved = entry.Value * process.Rate * delta * environmentModifier; currentProcessStatistics?.AddInputAmount(entry.Key, inputRemoved * inverseDelta); // This should always succeed (due to the earlier check) so // it is always assumed here that the process succeeded bag.TakeCompound(entry.Key, inputRemoved); } // Add outputs foreach (var entry in processData.Outputs) { if (entry.Key.IsEnvironmental) { continue; } var outputGenerated = entry.Value * process.Rate * delta * environmentModifier; currentProcessStatistics?.AddOutputAmount(entry.Key, outputGenerated * inverseDelta); bag.AddCompound(entry.Key, outputGenerated); } }
public TweakedProcess(BioProcess process, float rate = 1.0f) { Rate = rate; Process = process; }
public ProcessSpeedInformation(BioProcess process) { Process = process; }
private void RunProcess(float delta, BioProcess processData, CompoundBag bag, TweakedProcess process, SingleProcessStatistics currentProcessStatistics, float inverseDelta) { // Can your cell do the process bool canDoProcess = true; float environmentModifier = 1.0f; // This modifies the process overall speed to allow really fast processes to run, for example if there are // a ton of one organelle it might consume 100 glucose per go, which might be unlikely for the cell to have // so if there is *some* but not enough space for results (and also inputs) this can run the process as // fraction of the speed to allow the cell to still function well float spaceConstraintModifier = 1.0f; // First check the environmental compounds so that we can build the right environment modifier for accurate // check of normal compound input amounts foreach (var entry in processData.Inputs) { // Set used compounds to be useful, we dont want to purge those bag.SetUseful(entry.Key); if (!entry.Key.IsEnvironmental) { continue; } var dissolved = GetDissolved(entry.Key); // currentProcessStatistics?.AddInputAmount(entry.Key, entry.Value * inverseDelta); currentProcessStatistics?.AddInputAmount(entry.Key, dissolved); // do environmental modifier here, and save it for later environmentModifier *= dissolved / entry.Value; if (environmentModifier <= MathUtils.EPSILON) { currentProcessStatistics?.AddLimitingFactor(entry.Key); } } if (environmentModifier <= MathUtils.EPSILON) { canDoProcess = false; } // Compute spaceConstraintModifier before updating the final use and input amounts foreach (var entry in processData.Inputs) { if (entry.Key.IsEnvironmental) { continue; } var inputRemoved = entry.Value * process.Rate * environmentModifier; // currentProcessStatistics?.AddInputAmount(entry.Key, 0); // We don't multiply by delta here because we report the per-second values anyway. In the actual process // output numbers (computed after testing the speed), we need to multiply by inverse delta currentProcessStatistics?.AddInputAmount(entry.Key, inputRemoved); inputRemoved = inputRemoved * delta * spaceConstraintModifier; // If not enough we can't run the process unless we can lower spaceConstraintModifier enough var availableAmount = bag.GetCompoundAmount(entry.Key); if (availableAmount < inputRemoved) { bool canRun = false; if (availableAmount > MathUtils.EPSILON) { var neededModifier = availableAmount / inputRemoved; if (neededModifier > Constants.MINIMUM_RUNNABLE_PROCESS_FRACTION) { spaceConstraintModifier = neededModifier; canRun = true; // Due to rounding errors there can be very small disparity here between the amount available // and what we will take with the modifiers. See the comment in outputs for more details } } if (!canRun) { canDoProcess = false; currentProcessStatistics?.AddLimitingFactor(entry.Key); } } } foreach (var entry in processData.Outputs) { // For now lets assume compounds we produce are also useful bag.SetUseful(entry.Key); var outputAdded = entry.Value * process.Rate * environmentModifier; // currentProcessStatistics?.AddOutputAmount(entry.Key, 0); currentProcessStatistics?.AddOutputAmount(entry.Key, outputAdded); outputAdded = outputAdded * delta * spaceConstraintModifier; // if environmental right now this isn't released anywhere if (entry.Key.IsEnvironmental) { continue; } // If no space we can't do the process, if we can't adjust the space constraint modifier enough var remainingSpace = bag.Capacity - bag.GetCompoundAmount(entry.Key); if (outputAdded > remainingSpace) { bool canRun = false; if (remainingSpace > MathUtils.EPSILON) { var neededModifier = remainingSpace / outputAdded; if (neededModifier > Constants.MINIMUM_RUNNABLE_PROCESS_FRACTION) { spaceConstraintModifier = neededModifier; canRun = true; } // With all of the modifiers we can lose a tiny bit of compound that won't fit due to rounding // errors, but we ignore that here } if (!canRun) { canDoProcess = false; currentProcessStatistics?.AddCapacityProblem(entry.Key); } } } // Only carry out this process if you have all the required ingredients and enough space for the outputs if (!canDoProcess) { if (currentProcessStatistics != null) { currentProcessStatistics.CurrentSpeed = 0; } return; } float totalModifier = process.Rate * delta * environmentModifier * spaceConstraintModifier; if (currentProcessStatistics != null) { currentProcessStatistics.CurrentSpeed = process.Rate * environmentModifier * spaceConstraintModifier; } // Consume inputs foreach (var entry in processData.Inputs) { if (entry.Key.IsEnvironmental) { continue; } var inputRemoved = entry.Value * totalModifier; currentProcessStatistics?.AddInputAmount(entry.Key, inputRemoved * inverseDelta); // This should always succeed (due to the earlier check) so it is always assumed here that this succeeded bag.TakeCompound(entry.Key, inputRemoved); } // Add outputs foreach (var entry in processData.Outputs) { if (entry.Key.IsEnvironmental) { continue; } var outputGenerated = entry.Value * totalModifier; currentProcessStatistics?.AddOutputAmount(entry.Key, outputGenerated * inverseDelta); bag.AddCompound(entry.Key, outputGenerated); } }