Esempio n. 1
0
        void AddTank(FuelTank tank)
        {
            GUILayout.Label(addLabelCache[tank.name], GUILayout.Width(150));

            if (GUILayout.Button("Add", GUILayout.Width(120)))
            {
                tank.maxAmount = tank_module.AvailableVolume * tank.utilization;
                tank.amount    = tank.fillable ? tank.maxAmount : 0;

                tank.maxAmountExpression = tank.maxAmount.ToString();
                GameEvents.onEditorShipModified.Fire(EditorLogic.fetch.ship);
                tank_module.MarkWindowDirty();
                log.dbg("Adding tank {0} maxAmount: {1}", tank.name, tank.maxAmountExpression);
            }
        }
Esempio n. 2
0
        protected void ChangeResources(double volumeRatio, bool propagate = false)
        {
            // The used volume will rescale automatically when setting maxAmount
            for (int i = 0; i < tankList.Count; i++)
            {
                FuelTank tank = tankList[i];

                bool save_propagate = tank.propagate;
                tank.propagate = propagate;

                tank.maxAmount *= volumeRatio;

                tank.propagate = save_propagate;
            }
        }
        private bool CalculateLowestTankTemperature()
        {
            bool result = false;

            lowestTankTemperature = 300;
            for (int i = tankList.Count - 1; i >= 0; --i)
            {
                FuelTank tank = tankList[i];
                if (tank.maxAmount > 0d && (tank.vsp > 0.0 || tank.loss_rate > 0d))
                {
                    lowestTankTemperature = Math.Min(lowestTankTemperature, tank.temperature);
                    result = true;
                }
            }
            return(result);
        }
Esempio n. 4
0
        void RecordTankTypeResources(HashSet <string> resources, string type)
        {
            TankDefinition def;

            if (!MFSSettings.tankDefinitions.Contains(type))
            {
                return;
            }
            def = MFSSettings.tankDefinitions[type];

            for (int i = 0; i < def.tankList.Count; i++)
            {
                FuelTank tank = def.tankList[i];
                resources.Add(tank.name);
            }
        }
        internal FuelTank CreateCopy(ModuleFuelTanks toModule, ConfigNode overNode, bool initializeAmounts)
        {
            FuelTank clone = (FuelTank)MemberwiseClone();

            clone.module = toModule;

            if (overNode != null)
            {
                clone.Load(overNode);
            }
            if (initializeAmounts)
            {
                clone.InitializeAmounts();
            }
            else
            {
                clone.amountExpression = clone.maxAmountExpression = null;
            }
            clone.GetDensity();
            return(clone);
        }
Esempio n. 6
0
        void EditTank(FuelTank tank)
        {
            GUILayout.Label(" ", GUILayout.Width(5));

            GUIStyle style = unchanged;

            if (tank.maxAmountExpression == null)
            {
                tank.maxAmountExpression = tank.maxAmount.ToString();
                //log.warn("Adding tank from API " + tank.name + " amount: " + tank.maxAmountExpression ?? "null");
            }
            else if (tank.maxAmountExpression.Length > 0 && tank.maxAmountExpression != tank.maxAmount.ToString())
            {
                style = changed;
            }

            tank.maxAmountExpression = GUILayout.TextField(tank.maxAmountExpression, style, GUILayout.Width(127));

            UpdateTank(tank);
            RemoveTank(tank);
        }
Esempio n. 7
0
        public override string GetInfo()
        {
            if (!compatible)
            {
                return("");
            }

            UpdateTankType();

            StringBuilder info = new StringBuilder();

            info.AppendLine("Modular Fuel Tank:");
            info.Append("	Max Volume: ").AppendLine(KSPUtil.PrintSI(volume, MFSSettings.unitLabel));
            info.AppendLine("	Tank can hold:");
            for (int i = 0; i < tankList.Count; i++)
            {
                FuelTank tank = tankList[i];
                info.Append("		").Append(tank).Append(" ").AppendLine(tank.note);
            }
            return(info.ToString());
        }
        partial void OnStartRF(StartState state)
        {
            GameEvents.onVesselWasModified.Add(OnVesselWasModified);
            GameEvents.onEditorShipModified.Add(OnEditorShipModified);
            GameEvents.onPartDestroyed.Add(OnPartDestroyed);
            if (HighLogic.LoadedSceneIsFlight)
            {
                for (int i = 0; i < vessel.vesselModules.Count; i++)
                {
                    if (vessel.vesselModules[i] is FlightIntegrator)
                    {
                        _flightIntegrator = vessel.vesselModules[i] as FlightIntegrator;
                    }
                }
            }

            // Wait to calculate tank area because it depends on drag cubes
            // MLI depends on tank area so mass will also be recalculated
            IEnumerator WaitAndRecalculateMass()
            {
                yield return(null);

                yield return(null);

                yield return(null);

                CalculateTankArea();
                massDirty = true;
                CalculateMass();
            }

            if (HighLogic.LoadedSceneIsFlight)
            {
                StartCoroutine(WaitAndRecalculateMass());
            }

            for (int i = tankList.Count - 1; i >= 0; --i)
            {
                FuelTank tank = tankList[i];
                if (tank.maxAmount > 0.0 && (tank.vsp > 0.0 || tank.loss_rate > 0.0))
                {
                    supportsBoiloff = true;
                    break;
                }
            }

            if (state == StartState.Editor)
            {
                if (maxMLILayers > 0)
                {
                    ((UI_FloatRange)Fields[nameof(_numberOfAddedMLILayers)].uiControlEditor).maxValue = maxMLILayers;
                }
                else
                {
                    Fields[nameof(_numberOfAddedMLILayers)].guiActiveEditor = false;
                }

                Fields[nameof(_numberOfAddedMLILayers)].uiControlEditor.onFieldChanged = delegate(BaseField field, object value)
                {
                    massDirty = true;
                    CalculateMass();
                };
            }

            Fields[nameof(debug0Display)].guiActive = this.supportsBoiloff && (RFSettings.Instance.debugBoilOff || RFSettings.Instance.debugBoilOffPAW);
            Fields[nameof(debug1Display)].guiActive = this.supportsBoiloff && (RFSettings.Instance.debugBoilOff || RFSettings.Instance.debugBoilOffPAW);
            Fields[nameof(debug2Display)].guiActive = this.supportsBoiloff && (RFSettings.Instance.debugBoilOff || RFSettings.Instance.debugBoilOffPAW);

            //numberOfAddedMLILayers = Mathf.Round(numberOfAddedMLILayers);
            //CalculateInsulation();
        }
        public void CalculateTankArea()
        {
            // TODO: Codify a more accurate tank area calculator.
            // Thought: cube YN/YP can be used to find the part diameter / circumference... X or Z finds the length
            // Also should try to determine if tank has a common bulkhead - and adjust heat flux into individual tanks accordingly
#if DEBUG
            log.dbg("CalculateTankArea() running");
#endif

            if (HighLogic.LoadedSceneIsEditor)
            {
                if (!this.part.DragCubes.None && this.oldTotalVolume != this.totalVolume)
                {
                    if (this.IsProcedural())
                    {
                        bool origProceduralValue = this.part.DragCubes.Procedural;
                        this.part.DragCubes.Procedural = true;
                        this.part.DragCubes.ForceUpdate(true, true, true);
                        this.part.DragCubes.SetDragWeights();
                        this.part.DragCubes.RequestOcclusionUpdate();
                        this.part.DragCubes.SetPartOcclusion();
                        this.part.DragCubes.Procedural = origProceduralValue;
                        this.oldTotalVolume            = this.totalVolume;
                    }
                }
            }

            totalTankArea = 0f;

            for (int i = 0; i < 6; ++i)
            {
                totalTankArea += part.DragCubes.WeightedArea[i];
            }
#if DEBUG
            log.info("Part WeightedArea: {0} = {1:0.00}", part.name, totalTankArea);
            log.info("Part Area: {0} = {1:0.00}", part.name, part.DragCubes.Area);
#endif
            // This allows a rough guess as to individual tank surface area based on ratio of tank volume to total volume but it breaks down at very small fractions
            // So use greater of spherical calculation and tank ratio of total area.
            // if for any reason our totalTankArea is still 0 (no drag cubes available yet or analytic temp routines executed first)
            // then we're going to be defaulting to spherical calculation
            double tankMaxAmount;
            double tempTotal = 0;

            if (RFSettings.Instance.debugBoilOff)
            {
                log.info("Initializing {0}.totalTankArea as {1}", part.name, totalTankArea);
            }

            for (int i = tankList.Count - 1; i >= 0; --i)
            {
                FuelTank tank = tankList[i];
                if (tank.maxAmount > 0.0)
                {
                    tankMaxAmount = tank.maxAmount;

                    if (tank.utilization > 1.0)
                    {
                        tankMaxAmount /= tank.utilization;
                    }

                    tank.tankRatio = tankMaxAmount / volume;

                    tank.totalArea = Math.Max(Math.Pow(Math.PI, 1.0 / 3.0) * Math.Pow((tankMaxAmount / 1000.0) * 6, 2.0 / 3.0), totalTankArea * tank.tankRatio);
                    tempTotal     += tank.totalArea;

                    if (RFSettings.Instance.debugBoilOff)
                    {
                        log.detail("{0}.tankRatio = {1}", tank.name, tank.tankRatio);
                        log.detail("{0}.maxAmount = {1}", tank.name, tankMaxAmount);
                        log.detail("{0}.totalTankArea = {1}", part.name, totalTankArea);
                        log.detail("Tank surface area = {0}", tank.totalArea);
                        log.dbg("tank Dewar status = {0}", tank.isDewar);
                    }
                }
            }
            if (!(totalTankArea > 0) || tempTotal > totalTankArea)
            {
                totalTankArea = tempTotal;
            }
            if (RFSettings.Instance.debugBoilOff)
            {
                log.info("{0}.totalTankArea = {1}", part.name, totalTankArea);
                log.info("{0}.GetModuleSize() = {1:0.00}" + part.name, part.GetModuleSize(Vector3.zero));
            }
        }
        private IEnumerator CalculateTankBoiloff(double deltaTime, bool analyticalMode = false)
        {
            // Need to ensure that all heat compensation (radiators, heat pumps, etc) run first.
            if (totalTankArea <= 0)
            {
                CalculateTankArea();
            }

            if (!analyticalMode)
            {
                yield return(new WaitForFixedUpdate());
            }

            boiloffMass = 0d;

            previewInternalFluxAdjust = 0;

            bool hasCryoFuels = CalculateLowestTankTemperature();

            if (tankList.Count > 0 && lowestTankTemperature < 300d && MFSSettings.radiatorMinTempMult >= 0d)
            {
                part.radiatorMax = (lowestTankTemperature * MFSSettings.radiatorMinTempMult) / part.maxTemp;
            }

            if (fueledByLaunchClamp)
            {
                if (hasCryoFuels)
                {
                    part.temperature     = lowestTankTemperature;
                    part.skinTemperature = lowestTankTemperature;
                }
                fueledByLaunchClamp = false;
                yield break;
            }

            if (!double.IsNaN(part.temperature))
            {
                partPrevTemperature = part.temperature;
            }
            else
            {
                part.temperature = partPrevTemperature;
            }

            if (deltaTime > 0)
            {
                double deltaTimeRecip = 1d / deltaTime;
                log.detail("internalFlux = {0}, thermalInternalFluxPrevious = {1}, analytic internal flux = {2}", part.thermalInternalFlux, part.thermalInternalFluxPrevious, previewInternalFluxAdjust);

                if (RFSettings.Instance.debugBoilOff || RFSettings.Instance.debugBoilOffPAW)
                {
                    string MLIText = totalMLILayers > 0 ? GetMLITransferRate(part.skinTemperature, part.temperature).ToString("F4") : "No MLI";
                    debug0Display = part.temperature.ToString("F4") + "(" + MLIText + " * " + (part.radiativeArea * part.skinExposedAreaFrac).ToString("F2") + "m2)";
                }


                double cooling = 0;

                if (analyticalMode)
                {
                    if (part.thermalInternalFlux < 0)
                    {
                        cooling = part.thermalInternalFlux;
                    }
                    else if (part.thermalInternalFluxPrevious < 0)
                    {
                        cooling = part.thermalInternalFluxPrevious;
                    }

                    if (cooling < 0)
                    {
                        // in analytic mode, MFTRF interprets this as an attempt to cool the tanks
                        analyticInternalTemp += cooling * part.thermalMassReciprocal * deltaTime;
                        // because of what we're doing in CalculateAnalyticInsulationFactor(), it will take too much time to reach that temperature so
                        part.temperature += cooling * part.thermalMassReciprocal * deltaTime;
                    }
                }

                debug3Display = Utilities.FormatFlux(cooling);

                for (int i = tankList.Count - 1; i >= 0; --i)
                {
                    FuelTank tank = tankList[i];
                    if (tank.amount <= 0)
                    {
                        continue;
                    }

                    if (tank.vsp > 0.0 && tank.totalArea > 0)
                    {
                        // Opposite of original boil off code. Finds massLost first.
                        double massLost = 0.0;
                        double deltaTemp;
                        double hotTemp   = part.temperature;
                        double tankRatio = tank.maxAmount / volume;

                        if (RFSettings.Instance.ferociousBoilOff)
                        {
                            hotTemp = Math.Max(((hotTemp * part.thermalMass) - (tank.temperature * part.resourceThermalMass)) / (part.thermalMass - part.resourceThermalMass), part.temperature);
                        }

                        deltaTemp = hotTemp - tank.temperature;

                        if (RFSettings.Instance.debugBoilOff || RFSettings.Instance.debugBoilOffPAW)
                        {
                            if (debug2Display != "")
                            {
                                debug2Display += " / ";
                            }

                            if (debug1Display != "")
                            {
                                debug1Display += " / ";
                            }
                        }

                        double Q = 0;
                        if (deltaTemp > 0)
                        {
#if DEBUG
                            if (analyticalMode)
                            {
                                log.dbg("Tank {0} surface area = {1}", tank.name, tank.totalArea);
                            }
#endif

                            double wettedArea = tank.totalArea; // disabled until proper wetted vs ullage conduction can be done (tank.amount / tank.maxAmount);

                            if (tank.isDewar)
                            {
                                Q = GetDewarTransferRate(hotTemp, tank.temperature, tank.totalArea);
                            }
                            else
                            {
                                Q = deltaTemp /
                                    ((tank.wallThickness / (tank.wallConduction * wettedArea))
                                     + (tank.insulationThickness / (tank.insulationConduction * wettedArea))
                                     + (tank.resourceConductivity > 0 ? (0.01 / (tank.resourceConductivity * wettedArea)) : 0));
                            }

                            Q *= 0.001d; // convert to kilowatts

                            if (!double.IsNaN(Q))
                            {
                                massLost = Q / tank.vsp;
                            }
                            else
                            {
                                log.dbg("Q = NaN! W - T - F!!!");
                            }

                            if (RFSettings.Instance.debugBoilOff || RFSettings.Instance.debugBoilOffPAW)
                            {
                                // Only do debugging displays if debugging enabled in RFSettings

                                debug1Display += Utilities.FormatFlux(Q);
                                debug2Display += (massLost * 1000 * 3600).ToString("F4") + "kg/hr";
                            }
                            massLost *= deltaTime; // Frame scaling
                        }

                        double lossAmount = massLost / tank.density;

                        if (double.IsNaN(lossAmount))
                        {
                            log.dbg("{0} lossAmount is NaN!", tank.name);
                        }
                        else
                        {
                            if (lossAmount > tank.amount)
                            {
                                if (!CheatOptions.InfinitePropellant)
                                {
                                    tank.amount = 0d;
                                }
                            }
                            else
                            {
                                if (!CheatOptions.InfinitePropellant)
                                {
                                    tank.amount -= lossAmount;
                                }

                                // See if there is boiloff byproduct and see if any other parts want to accept it.
                                if (tank.boiloffProductResource != null)
                                {
                                    double boiloffProductAmount = -(massLost / tank.boiloffProductResource.density);
                                    double retainedAmount       = part.RequestResource(tank.boiloffProductResource.id, boiloffProductAmount, ResourceFlowMode.STAGE_PRIORITY_FLOW);
                                    massLost -= retainedAmount * tank.boiloffProductResource.density;
                                }

                                boiloffMass += massLost;
                            }
                            // subtract heat from boiloff
                            // subtracting heat in analytic mode is tricky: Analytic flux handling is 'cheaty' and tricky to predict.
                            // scratch sheet: example
                            // [ModularFuelSystem.ModuleFuelTankRF] proceduralTankRealFuels Analytic Temp = 256.679360297684, Analytic Internal = 256.679360297684, Analytic Skin = 256.679360297684
                            // [ModularFuelSystem.ModuleFuelTankRF] proceduralTankRealFuels deltaTime = 17306955.5092776, heat lost = 6638604.21227684, thermalMassReciprocal = 0.00444787360733243

                            if (!double.IsNaN(Q))
                            {
                                double heatLost = -Q;
                                if (!analyticalMode)
                                {
                                    part.AddThermalFlux(heatLost);
                                }
                                else
                                {
                                    analyticInternalTemp = analyticInternalTemp + (heatLost * part.thermalMassReciprocal * deltaTime);
                                    // Don't try to adjust flux if significant time has passed; it never works out.
                                    // Analytic mode flux only gets applied if timewarping AND analytic mode was set.
                                    if (TimeWarp.CurrentRate > 1)
                                    {
                                        previewInternalFluxAdjust += heatLost;
                                    }
                                    else
                                    {
                                        log.dbg("boiloff function running with delta time of {0} (vessel.lastUT = {1} seconds ago)", deltaTime, (Planetarium.GetUniversalTime() - vessel.lastUT).ToString("F4"));
                                    }
#if DEBUG
                                    if (deltaTime > 0)
                                    {
                                        log.dbg("{0} deltaTime = {1}, heat lost = {2}, thermalMassReciprocal = {3}", part.name, deltaTime, heatLost, part.thermalMassReciprocal);
                                    }
#endif
                                }
                            }
                            else
                            {
                                log.dbg("WHO WOULD WIN? Some Well Written Code or One Misplaced NaN?");
                                log.dbg("heatLost = {0}", Q);
                                log.dbg("deltaTime = {0}", deltaTime);
                                log.dbg("deltaTimeRecip = {0}", deltaTimeRecip);
                                log.dbg("massLost = {0}" + massLost);
                                log.dbg("tank.vsp = {0}" + tank.vsp);
                            }
                        }
                    }
                    else if (tank.loss_rate > 0 && tank.amount > 0)
                    {
                        double deltaTemp = part.temperature - tank.temperature;
                        if (deltaTemp > 0)
                        {
                            double lossAmount = tank.maxAmount * tank.loss_rate * deltaTemp * deltaTime;
                            if (lossAmount > tank.amount)
                            {
                                lossAmount  = -tank.amount;
                                tank.amount = 0d;
                            }
                            else
                            {
                                lossAmount   = -lossAmount;
                                tank.amount += lossAmount;
                            }
                            double massLost = tank.density * lossAmount;
                            boiloffMass += massLost;
                        }
                    }
                }
            }
        }
Esempio n. 11
0
        private void FillAttachedTanks(double deltaTime)
        {
            // sanity check
            if (deltaTime <= 0)
            {
                return;
            }

            // now, let's look at what we're connected to.
            foreach (Part p in vessel.parts)  // look through all parts
            {
                Tanks.ModuleFuelTanks m = p.FindModuleImplementing <Tanks.ModuleFuelTanks>();
                if (m != null)
                {
                    m.fueledByLaunchClamp = true;
                    // look through all tanks inside this part
                    for (int j = m.tankList.Count - 1; j >= 0; --j)
                    {
                        Tanks.FuelTank tank = m.tankList[j];
                        // if a tank isn't full, start filling it.

                        if (tank.maxAmount <= 0)
                        {
                            continue;
                        }

                        PartResource r = tank.resource;
                        if (r == null)
                        {
                            continue;
                        }

                        PartResourceDefinition d = PartResourceLibrary.Instance.GetDefinition(r.resourceName);
                        if (d == null)
                        {
                            continue;
                        }

                        if (tank.amount < tank.maxAmount && tank.fillable && r.flowMode != PartResource.FlowMode.None && d.resourceTransferMode == ResourceTransferMode.PUMP && r.flowState)
                        {
                            double amount = Math.Min(deltaTime * pump_rate * tank.utilization, tank.maxAmount - tank.amount);
                            Game   game   = HighLogic.CurrentGame;

                            if (d.unitCost > 0 && game.Mode == Game.Modes.CAREER && Funding.Instance != null)
                            {
                                double funds = Funding.Instance.Funds;
                                double cost  = amount * d.unitCost;
                                if (cost > funds)
                                {
                                    amount = funds / d.unitCost;
                                    cost   = funds;
                                }
                                Funding.Instance.AddFunds(-cost, TransactionReasons.VesselRollout);
                            }
                            //tank.amount = tank.amount + amount;
                            p.TransferResource(r, amount, this.part);
                        }
                    }
                }
                else
                {
                    for (int j = p.Resources.Count - 1; j >= 0; --j)
                    {
                        PartResource partResource = p.Resources[j];
                        if (partResource.info.name == "ElectricCharge")
                        {
                            if (partResource.flowMode != PartResource.FlowMode.None && partResource.info.resourceTransferMode == ResourceTransferMode.PUMP && partResource.flowState)
                            {
                                double amount = deltaTime * pump_rate;
                                amount = Math.Min(amount, partResource.maxAmount - partResource.amount);
                                p.TransferResource(partResource, amount, this.part);
                            }
                        }
                    }
                }
            }
        }
Esempio n. 12
0
        public void CalculateMass()
        {
            if (tankList == null || !massDirty)
            {
                return;
            }
            massDirty = false;

            double basemass = basemassConst + basemassPV * (MFSSettings.basemassUseTotalVolume ? totalVolume : volume);

            CalculateMassRF(ref basemass);

            if (basemass >= 0)
            {
                double tankDryMass = 0;
                for (int i = 0; i < tankList.Count; i++)
                {
                    FuelTank tank = tankList[i];
                    tankDryMass += tank.maxAmount * tank.mass / tank.utilization;
                }
                mass = (float)((basemass + tankDryMass) * MassMult);

                // compute massDelta based on prefab, if available.
                if (part.partInfo == null || part.partInfo.partPrefab == null)
                {
                    part.mass = mass;
                    massDelta = 0;
                }
                else
                {
                    massDelta = mass - part.partInfo.partPrefab.mass;
                }
            }
            else
            {
                mass      = part.mass;            // display dry mass even in this case.
                massDelta = 0f;
            }

            if (isEditor)
            {
                UsedVolume = tankList
                             .Where(fuel => fuel.maxAmount > 0 && fuel.utilization > 0)
                             .Sum(fuel => fuel.maxAmount / fuel.utilization);

                double availRounded = AvailableVolume;
                if (Math.Abs(availRounded) < 0.001d)
                {
                    availRounded = 0d;
                }
                string availVolStr = KSPUtil.PrintSI(availRounded, MFSSettings.unitLabel);
                string volStr      = KSPUtil.PrintSI(volume, MFSSettings.unitLabel);
                volumeDisplay = "Avail: " + availVolStr + " / Tot: " + volStr;

                double resourceMass = part.Resources.Cast <PartResource> ().Sum(partResource => partResource.maxAmount * partResource.info.density);

                double wetMass = mass + resourceMass;
                massDisplay = "Dry: " + FormatMass(mass) + " / Wet: " + FormatMass((float)wetMass);

                UpdateTweakableMenu();
            }
        }
Esempio n. 13
0
        private void UpdateTankType(bool initializeAmounts = true)
        {
            if (oldType == type || type == null)
            {
                return;
            }

            // Copy the tank list from the tank definitiion
            TankDefinition def;

            if (!MFSSettings.tankDefinitions.Contains(type))
            {
                log.error("Unable to find tank definition for type \"{0}\" reverting.", type);
                type = oldType;
                return;
            }
            def = MFSSettings.tankDefinitions[type];
            if (!def.canHave)
            {
                type = oldType;
                if (!string.IsNullOrEmpty(oldType)) // we have an old type
                {
                    def = MFSSettings.tankDefinitions[type];
                    if (def.canHave)
                    {
                        return; // go back to old type
                    }
                }
                // else find one that does work
                if (typesAvailable != null)
                {
                    for (int i = 0; i < typesAvailable.Count(); i++)
                    {
                        string         tn     = typesAvailable[i];
                        TankDefinition newDef = MFSSettings.tankDefinitions.Contains(tn) ? MFSSettings.tankDefinitions[tn] : null;
                        if (newDef != null && newDef.canHave)
                        {
                            def  = newDef;
                            type = newDef.name;
                            break;
                        }
                    }
                }
                if (type == oldType) // if we didn't find a new one
                {
                    log.error("Unable to find a type that is tech-available for part {0}", part.name);
                    return;
                }
            }

            oldType = type;

            // Build the new tank list.
            tankList = new FuelTankList();
            for (int i = 0; i < def.tankList.Count; i++)
            {
                FuelTank tank = def.tankList[i];
                // Pull the override from the list of overrides
                ConfigNode overNode = MFSSettings.GetOverrideList(part).FirstOrDefault(n => n.GetValue("name") == tank.name);

                tankList.Add(tank.CreateCopy(this, overNode, initializeAmounts));
            }
            tankList.TechAmounts(); // update for current techs

            // Destroy any managed resources that are not in the new type.
            HashSet <string> managed     = MFSSettings.managedResources[part.name];             // if this throws, we have some big fish to fry
            bool             needsMesage = false;

            for (int i = part.Resources.Count - 1; i >= 0; --i)
            {
                PartResource partResource = part.Resources[i];
                string       resname      = partResource.resourceName;
                if (!managed.Contains(resname) || tankList.Contains(resname) || unmanagedResources.ContainsKey(resname))
                {
                    continue;
                }
                part.Resources.Remove(partResource.info.id);
#if KSP150
                part.SimulationResources.Remove(partResource.info.id);
#endif
                needsMesage = true;
            }
            if (needsMesage)
            {
                RaiseResourceListChanged();
            }
            if (!basemassOverride)
            {
                ParseBaseMass(def.basemass);
            }
            if (!baseCostOverride)
            {
                ParseBaseCost(def.baseCost);
            }


            if (!isDatabaseLoad)
            {
                // being called in the SpaceCenter scene is assumed to be a database reload
                //FIXME is this really needed?

                massDirty = true;
            }

            UpdateTankTypeRF(def);
            UpdateTestFlight();
        }