void AddTank(double value)
        {
            log.dbg("Adding tank from API {0} amount: {1}", name, value);
            // The following is for unmanaged resource; if such a resource is defined then we probably shouldn't be here....
            ModuleFuelTanks.UnmanagedResource unmanagedResource = null;
            double unmanagedAmount    = 0;
            double unmanagedMaxAmount = 0;

            if (module != null && module.unmanagedResources != null)
            {
                module.unmanagedResources.TryGetValue(name, out unmanagedResource);
            }
            if (unmanagedResource != null)
            {
                unmanagedAmount    = unmanagedResource.amount;
                unmanagedMaxAmount = unmanagedResource.maxAmount;
            }



            var resDef = PartResourceLibrary.Instance.GetDefinition(name);
            var res    = part.Resources[name];

            if (res == null)
            {
                res = new PartResource(part);
            }
            res.resourceName = name;
            res.SetInfo(resDef);
            res.amount      = value + unmanagedAmount;
            res.maxAmount   = value + unmanagedMaxAmount;
            res._flowState  = true;
            res.isTweakable = resDef.isTweakable;
            res.isVisible   = resDef.isVisible;
            res.hideFlow    = false;
            res._flowMode   = PartResource.FlowMode.Both;
            part.Resources.dict.Add(resDef.id, res);
            log.dbg("AddTank {0} {1} {2} {3} {4} {5} {6} {7}", res.resourceName, res.amount, res.maxAmount, res.flowState, res.isTweakable, res.isVisible, res.hideFlow, res.flowMode);

            module.RaiseResourceListChanged();

            // Update symmetry counterparts.
            if (HighLogic.LoadedSceneIsEditor && propagate)
            {
                foreach (Part sym in part.symmetryCounterparts)
                {
                    sym.Resources.dict.Add(resDef.id, new PartResource(res));
                }
            }
            if (HighLogic.LoadedSceneIsEditor && propagate)
            {
                foreach (Part sym in part.symmetryCounterparts)
                {
                    sym.Resources.dict.Add(resDef.id, new PartResource(res));
                    RaiseResourceListChanged(sym);
                }
            }
        }
        void UpdateTank(double value)
        {
            PartResource partResource = resource;

            ModuleFuelTanks.UnmanagedResource unmanagedResource = null;
            double unmanagedAmount    = 0;
            double unmanagedMaxAmount = 0;

            if (module.unmanagedResources != null)
            {
                module.unmanagedResources.TryGetValue(partResource.resourceName, out unmanagedResource);
            }

            if (unmanagedResource != null)
            {
                unmanagedAmount    = unmanagedResource.amount;
                unmanagedMaxAmount = unmanagedResource.maxAmount;
            }


            if (value > partResource.maxAmount)
            {
                // If expanding, modify it to be less than overfull
                double maxQty = (module.AvailableVolume * utilization) + partResource.maxAmount - unmanagedMaxAmount;
                if (maxQty < value)
                {
                    value = maxQty;
                }
            }

            // Do nothing if unchanged
            if (value + unmanagedMaxAmount == partResource.maxAmount)
            {
                return;
            }

            //log.warn ("Updating tank from API " + name + " amount: " + value);
            maxAmountExpression = null;

            // Keep the same fill fraction
            double newAmount = value * fillFraction;

            partResource.maxAmount = value + unmanagedMaxAmount;
            module.RaiseResourceMaxChanged(partResource, value);
            //log.dbg ("Set new maxAmount");

            if (newAmount + unmanagedAmount != partResource.amount)
            {
                partResource.amount = newAmount + unmanagedAmount;
                module.RaiseResourceInitialChanged(partResource, newAmount);
            }

            // Update symmetry counterparts.
            if (HighLogic.LoadedSceneIsEditor && propagate)
            {
                foreach (Part sym in part.symmetryCounterparts)
                {
                    PartResource symResc = sym.Resources[name];
                    symResc.maxAmount = value + unmanagedMaxAmount;
                    RaiseResourceMaxChanged(sym, symResc, value);

                    if (newAmount != symResc.amount)
                    {
                        symResc.amount = newAmount + unmanagedAmount;
                        RaiseResourceInitialChanged(sym, symResc, newAmount);
                    }
                }
            }

            //log.dbg ("Symmetry set");
        }
        void DeleteTank()
        {
            PartResource partResource = resource;

            // Delete it
            //log.warn ("Deleting tank from API " + name);
            maxAmountExpression = null;
            ModuleFuelTanks.UnmanagedResource unmanagedResource = null;

            if (module.unmanagedResources != null)
            {
                module.unmanagedResources.TryGetValue(partResource.resourceName, out unmanagedResource);
            }

            if (unmanagedResource == null)
            {
                // there are no unmanaged resources of this type so, business as usual
                part.Resources.Remove(partResource);
#if KSP150
                part.SimulationResources.Remove(partResource);
#endif
            }
            else if (part.Resources.Contains(partResource.resourceName))
            {
                // part has a quantity of this resource which are unmanaged by MFT
                part.Resources[partResource.resourceName].amount    = unmanagedResource.amount;
                part.Resources[partResource.resourceName].maxAmount = unmanagedResource.maxAmount;
            }
            else
            {
                // probably shouldn't GET here since the part should already have this resource and we should always have left the unmanaged portion remaining.
                ConfigNode node = new ConfigNode("RESOURCE");
                node.AddValue("name", unmanagedResource.name);
                node.AddValue("amount", unmanagedResource.amount);
                node.AddValue("maxAmount", unmanagedResource.maxAmount);
                part.AddResource(node);
            }
            module.RaiseResourceListChanged();
            //log.dbg ("Removed.");

            // Update symmetry counterparts.
            if (HighLogic.LoadedSceneIsEditor && propagate)
            {
                foreach (Part sym in part.symmetryCounterparts)
                {
                    if (unmanagedResource == null)
                    {
                        PartResource symResc = sym.Resources[name];
                        sym.Resources.Remove(symResc);
#if KSP150
                        sym.SimulationResources.Remove(symResc);
#endif
                    }
                    else if (part.Resources.Contains(partResource.resourceName))
                    {
                        sym.Resources[partResource.resourceName].amount    = unmanagedResource.amount;
                        sym.Resources[partResource.resourceName].maxAmount = unmanagedResource.maxAmount;
                    }
                    else
                    {
                        // probably shouldn't GET here since the part should already have this resource and we should always have left the unmanaged portion remaining.
                        ConfigNode node = new ConfigNode("RESOURCE");
                        node.AddValue("name", unmanagedResource.name);
                        node.AddValue("amount", unmanagedResource.amount);
                        node.AddValue("maxAmount", unmanagedResource.maxAmount);
                        sym.AddResource(node);
                    }
                    RaiseResourceListChanged(sym);
                }
            }
            //print ("Sym removed");
        }