Subversion Repositories public iLand

Rev

Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
671 werner 1
/********************************************************************************************
2
**    iLand - an individual based forest landscape and disturbance model
3
**    http://iland.boku.ac.at
4
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
5
**
6
**    This program is free software: you can redistribute it and/or modify
7
**    it under the terms of the GNU General Public License as published by
8
**    the Free Software Foundation, either version 3 of the License, or
9
**    (at your option) any later version.
10
**
11
**    This program is distributed in the hope that it will be useful,
12
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
**    GNU General Public License for more details.
15
**
16
**    You should have received a copy of the GNU General Public License
17
**    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
********************************************************************************************/
19
 
605 werner 20
#include "carbonflowout.h"
21
#include "globalsettings.h"
22
#include "model.h"
23
#include "resourceunit.h"
608 werner 24
#include "resourceunitspecies.h"
25
#include "production3pg.h"
609 werner 26
#include "soil.h"
605 werner 27
 
28
CarbonFlowOut::CarbonFlowOut()
29
{
30
 
1157 werner 31
    setName("Carbon fluxes per RU or landscape/yr", "carbonflow");
32
    setDescription("Carbon fluxes per resource unit and year and/or aggregated for the full landscape. All values are reported on a per hectare basis (use the area provided in carbon or stand outputs to scale to realized values on the respective resource unit). " \
33
                   "For results limited to the project area, the data values need to be scaled to the stockable area.\n" \
34
                   "For landsacpe level outputs, data is always given per ha of (stockable) project area (i.e. scaling with stockable area is already included).\n" \
35
                   "Furthermore, the following sign convention is used in iLand: fluxes "\
36
                   "from the atmosphere to the ecosystem are positive, while C leaving the ecosystem is reported as negative C flux.\n" \
37
                   "You can specify a 'condition' to limit output execution to specific years (variable 'year'). " \
38
                   "The 'conditionRU' can be used to suppress resource-unit-level details; eg. specifying 'in(year,100,200,300)' limits output on reosurce unit level to the years 100,200,300 " \
39
                   "(leaving 'conditionRU' blank enables details per default).");
40
 
41
 
605 werner 42
    columns() << OutputColumn::year() << OutputColumn::ru() << OutputColumn::id()
1157 werner 43
              << OutputColumn("area_ha", "total stockable area of the resource unit (or landscape) (ha)", OutDouble)
44
              << OutputColumn("GPP", "actually realized gross primary production, kg C; ((primary production|GPP)) including " \
45
                                         "the effect of decreasing productivity with age; note that a rough estimate of "\
46
                                         "((sapling growth and competition|#sapling C and N dynamics|sapling GPP)) is added to the GPP of adult trees here.", OutDouble)
47
              << OutputColumn("NPP", "net primary production, kg C; calculated as NPP=GPP-Ra; Ra, the autotrophic respiration (kg C/ha) is calculated as"\
48
                                     " a fixed fraction of GPP in iLand (see ((primary production|here)) for details). ", OutDouble)
49
              << OutputColumn("Rh", "heterotrophic respiration, kg C; sum of C released to the atmosphere from detrital pools, i.e."\
50
                                    " ((snag dynamics|#Snag decomposition|snags)), ((soil C and N cycling|downed deadwood, litter, and mineral soil)).", OutDouble)
51
              << OutputColumn("dist_loss", "disturbance losses, kg C; C that leaves the ecosystem as a result of disturbances, e.g. fire consumption", OutDouble)
52
              << OutputColumn("mgmt_loss", "management losses, kg C; C that leaves the ecosystem as a result of management interventions, e.g. harvesting", OutDouble)
53
              << OutputColumn("NEP", "net ecosytem productivity kg C, NEP=NPP - Rh - disturbance losses - management losses. "\
54
                                     "Note that NEP is also equal to the total net changes over all ecosystem C pools, as reported in the "\
55
                                     "carbon output (cf. [http://www.jstor.org/stable/3061028|Randerson et al. 2002])", OutDouble)
56
              << OutputColumn("cumNPP", "cumulative NPP, kg C. This is a running sum of NPP (including tree NPP and sapling carbon gain).", OutDouble)
57
              << OutputColumn("cumRh", "cumulative flux to atmosphere (heterotrophic respiration), kg C. This is a running sum of Rh.", OutDouble)
58
              << OutputColumn("cumNEP", "cumulative NEP (net ecosystem productivity), kg C. This is a running sum of NEP (positive values: carbon gain, negative values: carbon loss).", OutDouble);
605 werner 59
}
60
 
61
void CarbonFlowOut::setup()
62
{
1157 werner 63
    // use a condition for to control execuation for the current year
64
    QString condition = settings().value(".condition", "");
65
    mCondition.setExpression(condition);
66
 
67
    condition = settings().value(".conditionRU", "");
68
    mConditionDetails.setExpression(condition);
69
 
605 werner 70
}
71
 
72
 
73
void CarbonFlowOut::exec()
74
{
75
    Model *m = GlobalSettings::instance()->model();
1157 werner 76
 
77
    // global condition
78
    if (!mCondition.isEmpty() && mCondition.calculate(GlobalSettings::instance()->currentYear())==0.)
79
        return;
80
 
81
    bool ru_level = true;
82
    // switch off details if this is indicated in the conditionRU option
83
    if (!mConditionDetails.isEmpty() && mConditionDetails.calculate(GlobalSettings::instance()->currentYear())==0.)
84
        ru_level = false;
85
 
86
    double npp = 0.;
87
    int ru_count = 0;
88
    QVector<double> v(10, 0.); // 11 data values
89
    QVector<double>::iterator vit;
90
 
605 werner 91
    foreach(ResourceUnit *ru, m->ruList()) {
92
        if (ru->id()==-1)
93
            continue; // do not include if out of project area
609 werner 94
        if (!ru->soil() || !ru->snag()) {
95
            qDebug() << "CarbonFlowOut::exec: resource unit without soil or snags module - no output generated.";
96
            continue;
97
        }
605 werner 98
 
608 werner 99
 
1157 werner 100
        npp = 0.;
101
        double area_factor = ru->stockableArea() / cRUArea; //conversion factor
102
        npp += ru->statistics().npp() * biomassCFraction; // kg C/ha
103
        npp += ru->statistics().nppSaplings() * biomassCFraction; // kgC/ha
1202 werner 104
        // Snag pools are not scaled per ha (but refer to the stockable RU), soil pools and biomass statistics (NPP, ...) are scaled.
1157 werner 105
        double to_atm = ru->snag()->fluxToAtmosphere().C / area_factor; // from snags, kg/ha
106
        to_atm += ru->soil()->fluxToAtmosphere().C * cRUArea/10.; // soil: t/ha -> t/m2 -> kg/ha
609 werner 107
 
1157 werner 108
        double to_dist = ru->snag()->fluxToDisturbance().C / area_factor; // convert to kgC/ha
109
        to_dist += ru->soil()->fluxToDisturbance().C * cRUArea/10.; // kgC/ha
609 werner 110
 
1157 werner 111
        double to_harvest = ru->snag()->fluxToExtern().C / area_factor; // kgC/ha
609 werner 112
 
1157 werner 113
        double nep = npp - to_atm - to_harvest - to_dist; // kgC/ha
605 werner 114
 
1157 werner 115
        if (ru_level) {
116
            *this << currentYear() << ru->index() << ru->id() << area_factor; // keys
117
            *this <<  npp / cAutotrophicRespiration // GPP_act
118
                    << npp // NPP
119
                    << -to_atm // rh
120
                    << -to_dist // disturbance
121
                    << -to_harvest // management loss
122
                    << nep; // nep
123
            *this << ru->resouceUnitVariables().cumCarbonUptake << ru->resouceUnitVariables().cumCarbonToAtm << ru->resouceUnitVariables().cumNEP;
124
 
125
            writeRow();
126
        }
127
        // landscape level
128
        ++ru_count;
129
        vit = v.begin();
130
        *vit++ += area_factor; // total area in ha
131
        *vit++ += npp / cAutotrophicRespiration * area_factor; // GPP_act
132
        *vit++ += npp * area_factor; // NPP
133
        *vit++ += -to_atm * area_factor; // rh
134
        *vit++ += -to_dist * area_factor; // disturbance
135
        *vit++ += -to_harvest * area_factor; // management loss
136
        *vit++ += nep *area_factor; // net ecosystem productivity
137
        *vit++ += ru->resouceUnitVariables().cumCarbonUptake * area_factor; // cum. NPP
138
        *vit++ += ru->resouceUnitVariables().cumCarbonToAtm * area_factor; // cum. Rh
139
        *vit++ += ru->resouceUnitVariables().cumNEP * area_factor; // cum. NEP
140
 
605 werner 141
    }
142
 
1157 werner 143
    // write landscape sums
144
    double total_stockable_area = v[0]; // total ha of stockable area
145
    if (ru_count==0. || total_stockable_area==0.)
146
        return;
147
    *this << currentYear() << -1 << -1; // codes -1/-1 for landscape level
148
    *this << v[0]; // stockable area [m2]
149
    for (int i=1;i<v.size();++i)
150
        *this << v[i] / total_stockable_area;
151
    writeRow();
152
 
153
 
605 werner 154
}
155