public override FlowResponseData getFlowDriverSourcePossibleValues(FlowCalculationData baseData, FlowDriverModifier modifier) { pumpingPercent = 1.0; FlowResponseData normalResponse = base.getFlowDriverSourcePossibleValues(baseData, modifier); lastSourcePossibleValue = normalResponse; return normalResponse; }
public FlowResponseData clone() { FlowResponseData ret = new FlowResponseData(); ret.flowPercent = flowPercent; ret.flowVolume = flowVolume; ret.backPressure = backPressure; ret.fluidTypeMap = PhysTools.DictionaryCloner<FluidType, double>.cloneDictionary(fluidTypeMap); return ret; }
public override FlowResponseData getDeliveryPossibleValues(FlowCalculationData baseData, FlowComponent caller, double flowPercent, double pressurePercent) { FlowResponseData ret = new FlowResponseData(); ret.backPressure = tankPressure; if (isSealed) { double deltaPressure = baseData.pressure - tankPressure; if(deltaPressure < 0.0) { //There is too much back-pressure for this pump to overcome it. Thus, nothing will flow in. ret.flowPercent = 0.0; } else if(deltaPressure > normalPressureDelta || normalPressureDelta == 0.0) //Don't allow else to divide by 0 { //We don't add any restriction, since the dP is greater than our defined 'normal'. ret.flowPercent = flowPercent; } else { //Here we need to do a linear interpolation between deltaPressure = normalPressure meaning 1, and deltaPressure = 0 meaning 0. //Thus, at normalPressure, we get full flow, and at no pressure difference, we get no flow. ret.flowPercent = deltaPressure / normalPressureDelta * flowPercent; } } else { if (currentVolume < double.MaxValue) //TODO: Make it so that tanks can't overflow, especially sealed tanks... Right now, it will pretty much always accept any flow that we want to put into it... { ret.flowPercent = flowPercent; //Allow everything that they are asking for, since we don't do restrictions inside the tank. } else { ret.flowPercent = 0.0; } } ret.flowVolume = flowPercent * baseData.desiredFlowVolume; ret.fluidTypeMap = currentFluidTypeMap; outletPressure = ret.backPressure; return ret; }
public bool updateStateRequiresNewSolution(FlowResponseData sourceAbility, FlowResponseData deliveryAbility) { bool needsNewSolution = false; this.sourceAbility = sourceAbility; this.deliveryAbility = deliveryAbility; double minFlowAbility = Math.Min(sourceAbility.flowPercent, deliveryAbility.flowPercent); if (minFlowAbility < flowPercent) { flowPercent = minFlowAbility; needsNewSolution = true; } if (sourceAbility.flowPercent < minSourceFlowPercent) minSourceFlowPercent = sourceAbility.flowPercent; if (deliveryAbility.flowPercent < minDeliveryFlowPercent) minDeliveryFlowPercent = deliveryAbility.flowPercent; return needsNewSolution; }
public override FlowResponseData getSourcePossibleValues(FlowCalculationData baseData, FlowComponent caller, double flowPercent, double pressurePercent) { FlowResponseData ret = new FlowResponseData(); if(currentVolume > 0.0) { ret.flowPercent = flowPercent; //Allow everything that they are asking for, since we don't do restrictions inside the tank. } else { ret.flowPercent = 0.0f; } ret.flowVolume = flowPercent * baseData.desiredFlowVolume; ret.backPressure = tankPressure; ret.fluidTypeMap = currentFluidTypeMap; outletPressure = ret.backPressure; return ret; }
private double[] modifyPreferenceBasedOnBackPressures(double[] preferredFlowPercent, FlowResponseData[] responses, FlowCalculationData baseData) { if (baseData.pressure == 0.0) return preferredFlowPercent; //We don't want to have a divide by zero down below. //1.0 - backpressure/mcr-pressure seems to be a good starting guess for a scaler. double sumBeforeModification = 0.0; for(int i = 0; i < preferredFlowPercent.Length; i++) { sumBeforeModification += preferredFlowPercent[i]; double modifier = Math.Max(1.0 - (responses[i].backPressure / baseData.pressure), 0.000001); //Don't let the number go completely to zero. preferredFlowPercent[i] *= modifier; } return PhysTools.normalizePercentArray(preferredFlowPercent, sumBeforeModification); }
private FlowResponseData calculateSplittingFunctionality(FlowCalculationData baseData, double flowPercent, FlowComponent[] nodes, bool isDeliverySide, double pressurePercent) { FlowResponseData[] responses = new FlowResponseData[nodes.Length]; bool foundNull = false; double maxBackPressure = 0.0; for (int attempt = 0; attempt < 2; attempt++) { //Most of the time, we will need to ask twice, because some will be null the first time. foundNull = false; for (int i = 0; i < nodes.Length; i++) { if (responses[i] == null) { if (isDeliverySide) responses[i] = nodes[i].getDeliveryPossibleValues(baseData, this, Math.Min(flowPercent, maxWeights[i]), pressurePercent); else responses[i] = nodes[i].getSourcePossibleValues(baseData, this, Math.Min(flowPercent, maxWeights[i]), pressurePercent); } if (responses[i] == null) foundNull = true; else if (responses[i].backPressure > maxBackPressure) maxBackPressure = responses[i].backPressure; } if (!foundNull) break; } if (foundNull) { return null; //We weren't able to get everything, and this is probably because there is another splitter up stream that will retry us again. } if (!flowPercentageSolutions.ContainsKey(baseData.flowDriver.name)) flowPercentageSolutions[baseData.flowDriver.name] = new double[nodes.Length]; //If we get here, then we have all the info we should need to solve ourselves. double desiredPercent = flowPercent; double[] maxFlowPercent = new double[nodes.Length]; double[] preferredFlowPercent = new double[nodes.Length]; double percentToReturn = 0.0; double sumOfMaxFlow = 0; double currentSum = 0.0; if (linkedCombiner != null) { desiredPercent = Math.Min(linkedCombiner.lastCombinePercent, flowPercent); //All are equal... grab first. This is the combiner's maxFlow double[] flowPercentToCombiner; //NOTE: Both solutions with both divisors gave the same answer, and I found the bug elsewhere... //TODO: Determing what divisor we actually want to use. if (linkedCombiner.combinerMap.ContainsKey(baseData.flowDriver.name)) flowPercentToCombiner = linkedCombiner.combinerMap[baseData.flowDriver.name]; else { flowPercentToCombiner = new double[nodes.Length]; for (int i = 0; i < nodes.Length; i++) flowPercentToCombiner[i] = responses[i].flowPercent; //This was my original solution, but the map is better. } double tempSum = 0.0; for (int i = 0; i < nodes.Length; i++) { maxFlowPercent[i] = Math.Min(maxWeights[i], flowPercentToCombiner[i]); preferredFlowPercent[i] = Math.Min(normalWeights[i], maxFlowPercent[i]) * desiredPercent; tempSum += preferredFlowPercent[i]; } bool modifySplitBasedOnBackPressures = true; //I can foresee this wanting to be an optional parameter, sometimes doing it, and sometimes not. if (modifySplitBasedOnBackPressures) { preferredFlowPercent = modifyPreferenceBasedOnBackPressures(preferredFlowPercent, responses, baseData); } preferredFlowPercent = fixPercents(preferredFlowPercent, maxFlowPercent, desiredPercent); //Normalize preferredFlowPercent (since we know the final flow as desiredPercent, we can safely do so in this case) for (int i = 0; i < nodes.Length; i++) { currentSum += preferredFlowPercent[i]; percentToReturn += preferredFlowPercent[i]; sumOfMaxFlow += maxFlowPercent[i]; } } else { desiredPercent = flowPercent; for (int i = 0; i < nodes.Length; i++) { maxFlowPercent[i] = Math.Min(maxWeights[i], responses[i].flowPercent); preferredFlowPercent[i] = Math.Min(normalWeights[i], maxFlowPercent[i]) * desiredPercent; currentSum += preferredFlowPercent[i]; percentToReturn += preferredFlowPercent[i]; sumOfMaxFlow += maxFlowPercent[i]; } } //TODO: Find better way to handle this. The 0.000000001 is there to handle rounding errors, when the sum really is the same number, but it rounds to slightly less... if (currentSum < desiredPercent - 0.000000001 && sumOfMaxFlow > 0.0) //sum > 0.0 helps us avoid a divide by 0 below. Also, if we can't push anything, then 0 is the right answer { percentToReturn = 0; for (int i = 0; i < nodes.Length; i++) { double trueFlowPercent; if (sumOfMaxFlow == 0.0) trueFlowPercent = 0.0; else trueFlowPercent = desiredPercent * (maxFlowPercent[i] / sumOfMaxFlow); trueFlowPercent = Math.Min(trueFlowPercent, maxWeights[i]); //Probably don't need this one, since the one right below is better. trueFlowPercent = Math.Min(trueFlowPercent, maxFlowPercent[i]); flowPercentageSolutions[baseData.flowDriver.name][i] = trueFlowPercent; percentToReturn += trueFlowPercent; } } else { for (int i = 0; i < nodes.Length; i++) { double trueFlowPercent = preferredFlowPercent[i]; //It all works out with preferred values. flowPercentageSolutions[baseData.flowDriver.name][i] = trueFlowPercent; } } //Need to normalize the flowPercenageSolutions, so that they sum to 1.0, so that when we set values, we are spliting 100 % of the smaller portion that is coming down to us(and don't double-limit things). if (percentToReturn != 0.0) { for (int i = 0; i < nodes.Length; i++) flowPercentageSolutions[baseData.flowDriver.name][i] /= percentToReturn; } FlowResponseData ret = new FlowResponseData(); ret.flowPercent = percentToReturn; ret.flowVolume = percentToReturn * baseData.desiredFlowVolume; ret.backPressure = maxBackPressure; setPressures(baseData.pressure, ret.backPressure, pressurePercent, isDeliverySide); return ret; }
public override void resetState() { base.resetState(); lastSourcePossibleValue = null; }