public static void processPlant(ref Plant plant)
    {
        // calculate the tolerances, optimum levels, and sequestration rates
        float age    = plant.age;
        float volume = (plant.rootDepth * plant.rootWidth) * 0.5f + plant.foliageHeight * plant.foliageWidth; //revise this, a cone has different volume


        // TODO: these two foreach loops can be merged at some point
        foreach (KeyValuePair <string, PlantNutrientManager> nutrient in plant.plantNutrientManagers)
        {
            nutrient.Value.assignNutrientTolerancesAndRates(volume, age);
            nutrient.Value.calculateSequestrationRates();
        }

        sequestNutrient(ref plant);

        float limitingGrowthFactor = float.PositiveInfinity;
        float growthFactor;

        foreach (string name in plant.plantNutrientManagers.Keys)
        {
            PlantNutrientManager nutrient = plant.plantNutrientManagers[name];
            setGrowthFactor(ref nutrient, ref plant, out growthFactor); //healthy, unhealthy etc
            if (growthFactor < limitingGrowthFactor)
            {
                limitingGrowthFactor = growthFactor;
            }
        }

        grow(limitingGrowthFactor, ref plant);
    }
    private static void sequestNutrient(ref Plant plant)
    {
        Segment     segment     = plant.segment;
        float       rootDepth   = plant.rootDepth; //might overwrite, but shouldn't
        float       rootRadius  = plant.rootWidth / 2;
        SoilProfile soilProfile = segment.soilProfile;

        foreach (SoilHorizon soilHorizon in soilProfile.soilHorizons)
        {
            float x1 = Mathf.Abs(soilHorizon.upperBound);
            float x2 = Mathf.Abs(soilHorizon.lowerBound);
            x2 = x2 > rootDepth ? x2 : rootDepth;
            float volume = volumeInDiagonalSubsection(x1, x2, rootRadius, rootDepth);
            foreach (string name in plant.plantNutrientManagers.Keys)
            {
                PlantNutrientManager nutrient = plant.plantNutrientManagers[name];
                nutrient.sequestNutrients(name, soilHorizon, volume);
            }
        }
    }
    // TODO: optimize this method. Too much stuff in the if statements.
    private static void setGrowthFactor(ref PlantNutrientManager nutrient, ref Plant plant, out float growthFactor)
    {
        // TODO: currently a linear first approximation
        // consider changing this to gaussian distance
        // optimal growth factor is 1.
        float a, b;
        bool  belowOptimal = nutrient.currentLevel < nutrient.optimalLevel;


        if (nutrient.currentLevel < nutrient.minAliveTolerance || nutrient.currentLevel > nutrient.maxAliveTolerance)
        {
            growthFactor  = -1;
            plant.isAlive = false;
            return;
        }

        // if the current level is between the healthy levels, then the growth is positive
        if (belowOptimal && nutrient.currentLevel > nutrient.minHealthyTolerance)
        {
            a = 1 / (nutrient.optimalLevel - nutrient.minHealthyTolerance);
            b = -1 * a * nutrient.minHealthyTolerance;
            float value = a * nutrient.currentLevel + b;
            nutrient.setNutrientGrowthFactor(value);
            growthFactor = value;
        }
        else if (!belowOptimal && nutrient.currentLevel < nutrient.maxHealthyTolerance)
        {
            a = 1 / (nutrient.optimalLevel - nutrient.maxHealthyTolerance);
            b = -1 * a * nutrient.maxHealthyTolerance;
            float value = a * nutrient.currentLevel + b;
            nutrient.setNutrientGrowthFactor(value);
            growthFactor = value;
        }
        else
        {
            // if the current levels are outside the bounds then the growth rates are zero.
            nutrient.setNutrientGrowthFactor(0);
            growthFactor = 0;
        }
    }