Subversion Repositories public iLand

Rev

Rev 1220 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/********************************************************************************************
**    iLand - an individual based forest landscape and disturbance model
**    http://iland.boku.ac.at
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
**
**    This program is free software: you can redistribute it and/or modify
**    it under the terms of the GNU General Public License as published by
**    the Free Software Foundation, either version 3 of the License, or
**    (at your option) any later version.
**
**    This program is distributed in the hope that it will be useful,
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**    GNU General Public License for more details.
**
**    You should have received a copy of the GNU General Public License
**    along with this program.  If not, see <http://www.gnu.org/licenses/>.
********************************************************************************************/


#ifndef SNAG_H
#define SNAG_H
#include <QList>
#include <QVariant>
class Tree; // forward
class Species; // forward
class ResourceUnit; // forward

/** CNPair stores a duple of carbon and nitrogen (kg/ha)
    use addBiomass(biomass, cnratio) to add biomass; use operators (+, +=, *, *=) for simple operations. */

class CNPair
{
public:
    CNPair(): C(0.), N(0.) {}
    static void setCFraction(const double fraction) { biomassCFraction = fraction; } ///< set the global fraction of carbon of biomass
    CNPair(const double c, const double n) {C=c; N=n; }
    bool isEmpty() const { return C==0.; } ///< returns true if pool is empty
    bool isValid() const { return C>=0. && N>=0.; } ///< return true if pool is valid (content of C or N >=0)
    double C; // carbon pool (kg C/ha)
    double N; // nitrogen pool (kg N/ha)
    double CN() { return N>0?C/N:0.; } ///< current CN ratio
    void clear() {C=0.; N=0.; }
    /// retrieve the amount of biomass (kg/ha). Uses the global C-fraciton. Soil pools are in t/ha!!!
    double biomass() const {return C / biomassCFraction; }
    /// add biomass to the pool (kg dry mass/ha); CNratio is used to calculate the N-Content, the global C-Fraction of biomass is used to
    /// calculate the amount of carbon of 'biomass'.
    void addBiomass(const double biomass, const double CNratio) { C+=biomass*biomassCFraction; N+=biomass*biomassCFraction/CNratio; }
    // some simple operators
    void operator+=(const CNPair &s) { C+=s.C; N+=s.N; } ///< add contents of a pool
    void operator*=(const double factor) { C*=factor; N*=factor; } ///< Multiply pool with 'factor'
    const CNPair operator+(const CNPair &p2) const { return CNPair(C+p2.C, N+p2.N); } ///< return the sum of two pools
    const CNPair operator-(const CNPair &p2) const { return CNPair(C-p2.C, N-p2.N); } ///< return the difference of two pools
    const CNPair operator*(const double factor) const { return CNPair(C*factor, N*factor); } ///< return the pool multiplied with 'factor'
protected:
    static double biomassCFraction;
};

/** CNPool provides (in addition to CNPair) also a weighted parameter value (e.g. a decay rate) */
class CNPool: public CNPair
{
public:
    CNPool(): CNPair(), mParameter(0.) {}
    CNPool(const double c, const double n, const double param_value) {C=c; N=n; mParameter=param_value; }
    double parameter() const { return mParameter; } ///< get weighting parameter
    double parameter(const CNPool &s) const; ///< 'simulate' weighting (get weighted param value of 's' with the current content)
    void clear() { CNPair::clear(); mParameter=0.; }

    /// add biomass with a specific 'CNRatio' and 'parameter_value'
    void addBiomass(const double biomass, const double CNratio, const double parameter_value);
    void add(const CNPair &s, const double parameter_value) { operator+=(CNPool(s.C, s.N, parameter_value));} ///< convenience function
    void setParameter(const double value) { mParameter = value; }

    void operator+=(const CNPool &s);
    const CNPool operator*(const double factor) const { return CNPool(C*factor, N*factor, mParameter); } ///< return the pool multiplied with 'factor'
private:
    double mParameter;
};

class Snag
{
public:
    Snag();
    static void setupThresholds(const double lower, const double upper); ///< setup class thresholds, needs to be called only once... (static)
    void setup( const ResourceUnit *ru); ///< initial setup routine.
    void scaleInitialState(); ///< used to scale the input to the actual area of the resource unit
    void newYear(); ///< to be executed at the beginning of a simulation year. This cleans up the transfer pools.
    void calculateYear(); ///< to be called at the end of the year (after tree growth, harvesting). Calculates flow to the soil.
    // access
    bool isStateEmpty() const { return mTotalSnagCarbon == 0.; }
    bool isEmpty() const { return mLabileFlux.isEmpty() && mRefractoryFlux.isEmpty() && isStateEmpty(); }
    const CNPool &labileFlux() const { return mLabileFlux; } ///< litter flux to the soil (kg/ha)
    const CNPool &refractoryFlux() const {return  mRefractoryFlux; } ///< deadwood flux to the soil (kg/ha)
    double climateFactor() const { return mClimateFactor; } ///< the 're' climate factor to modify decay rates (also used in ICBM/2N model)
    double totalCarbon() const { return mTotalSnagCarbon; } ///< total carbon in snags (kg/ha)
    const CNPair &totalSWD() const { return mTotalSWD; } ///< sum of C and N in SWD pools (stems) kg/ha
    const CNPair &totalOtherWood() const { return mTotalOther; } ///< sum of C and N in other woody pools (branches + coarse roots) kg/ha
    const CNPair &fluxToAtmosphere() const { return mTotalToAtm; } ///< total kg/ha heterotrophic respiration / flux to atm
    const CNPair &fluxToExtern() const { return mTotalToExtern; } ///< total kg/ha harvests
    const CNPair &fluxToDisturbance() const { return mTotalToDisturbance; } ///< total kg/ha due to disturbance (e.g. fire)
    // actions
    /// add for a tree with diameter
    void addTurnoverLitter(const Species *species, const double litter_foliage, const double litter_fineroot);
    void addTurnoverWood(const Species *species, const double woody_biomass);

    /// adds the 'tree' to the appropriate Snag pools.
    void addMortality(const Tree* tree);

    /// add residual biomass of 'tree' after harvesting.
    /// remove_(stem, branch, foliage)_pct: percentage of biomass compartment that is removed by the harvest operation.
    /// the harvested biomass is collected.
    void addHarvest(const Tree* tree, const double remove_stem_pct, const double remove_branch_pct, const double remove_foliage_pct );

    /// a tree dies and the biomass of the tree is split between snags/soils/removals
    /// @param tree the tree to process
    /// @param stem_to_snag fraction (0..1) of the stem biomass that should be moved to a standing snag
    /// @param stem_to_soil fraction (0..1) of the stem biomass that should go directly to the soil
    /// @param branch_to_snag fraction (0..1) of the branch biomass that should be moved to a standing snag
    /// @param branch_to_soil fraction (0..1) of the branch biomass that should go directly to the soil
    /// @param foliage_to_soil fraction (0..1) of the foliage biomass that should go directly to the soil
    void addDisturbance(const Tree *tree, const double stem_to_snag, const double stem_to_soil,
                        const double branch_to_snag, const double branch_to_soil,
                        const double foliage_to_soil) { addBiomassPools(tree, stem_to_snag, stem_to_soil, branch_to_snag, branch_to_soil, foliage_to_soil);}

    /// add (died) biomass from the regeneration layer
    void addToSoil(const Species *species, const CNPair &woody_pool, const CNPair &litter_pool);

    /// disturbance function: remove the fraction of 'factor' of biomass from the SWD pools; 0: remove nothing, 1: remove all
    void removeCarbon(const double factor);
    /// cut down swd and move to soil pools
    void management(const double factor);
    QList<QVariant> debugList(); ///< return a debug output
private:
    /// split the biomass of a tree into snag pools or move part of the tree directly to the soil
    void addBiomassPools(const Tree *tree, const double stem_to_snag, const double stem_to_soil, const double branch_to_snag, const double branch_to_soil, const double foliage_to_soil);
    double calculateClimateFactors(); ///< calculate climate factor 're' for the current year
    double mClimateFactor; ///< current mean climate factor (influenced by temperature and soil water content)
    const ResourceUnit *mRU; ///< link to resource unit
    /// access SWDPool as function of diameter (cm)
    int poolIndex(const float dbh) { if (dbh<mDBHLower) return 0; if (dbh>mDBHHigher) return 2; return 1;}
    CNPool mSWD[3]; ///< standing woody debris pool (0: smallest dimater class, e.g. <10cm, 1: medium, 2: largest class (e.g. >30cm)) kg/ha
    CNPair mTotalSWD; ///< sum of mSWD[x]
    double mNumberOfSnags[3]; ///< number of snags in diameter class
    double mAvgDbh[3]; ///< average diameter in class (cm)
    double mAvgHeight[3]; ///< average height in class (m)
    double mAvgVolume[3]; ///< average volume in class (m3)
    double mTimeSinceDeath[3]; ///< time since death: mass-weighted age of the content of the snag pool
    double mKSW[3]; ///< standing woody debris decay rate (weighted average of species values)
    double mCurrentKSW[3]; ///< swd decay rate (average for trees of the current year)
    double mHalfLife[3]; ///< half-life values (yrs) (averaged)
    CNPool mToSWD[3]; ///< transfer pool; input of the year is collected here (for each size class)
    CNPool mLabileFlux; ///< flux to labile soil pools (kg/ha)
    CNPool mRefractoryFlux; ///< flux to the refractory soil pool (kg/ha)
    CNPool mOtherWood[5]; ///< pool for branch biomass and coarse root biomass
    CNPair mTotalOther; ///< sum of mOtherWood[x]
    int mBranchCounter; ///< index which of the branch pools should be emptied
    double mTotalSnagCarbon; ///< sum of carbon content in all snag compartments (kg/ha)
    CNPair mTotalIn; ///< total input to the snag state (i.e. mortality/harvest and litter)
    CNPair mSWDtoSoil; ///< total flux from standing dead wood (book-keeping) -> soil (kg/ha)
    CNPair mTotalToAtm; ///< flux to atmosphere (kg/ha)
    CNPair mTotalToExtern; ///< total flux of masses removed from the site (i.e. harvesting) kg/ha
    CNPair mTotalToDisturbance; ///< fluxes due to disturbance
    static double mDBHLower, mDBHHigher; ///< thresholds used to classify to SWD-Pools
    static double mCarbonThreshold[3]; ///< carbon content thresholds that are used to decide if the SWD-pool should be emptied

    friend class Snapshot;
};

#endif // SNAG_H