FFSM++  1.1.0
French Forest Sector Model ++
Carbon.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2015 by Laboratoire d'Economie Forestière *
3  * http://ffsm-project.org *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 3 of the License, or *
8  * (at your option) any later version, given the compliance with the *
9  * exceptions listed in the file COPYING that is distribued together *
10  * with this file. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program; if not, write to the *
19  * Free Software Foundation, Inc., *
20  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21  ***************************************************************************/
22 
23 #include <math.h> /* log */
24 
25 #include "Carbon.h"
26 #include "ThreadManager.h"
27 #include "ModelData.h"
28 #include "Scheduler.h"
29 
30 
31 
33  MTHREAD=MTHREAD_h;
34 }
35 
37 }
38 
39 
40 // ################# GET FUNCTIONS ################
41 /**
42  * @param reg
43  * @param stock_type
44  * @return the Carbon stocked in a given sink
45  *
46  * For product sink:
47  * - for primary products it includes the primary products exported out of the country, but not those exported to other regions or used in the region as
48  * these are assumed to be totally transformed to secondary products;
49  * - for secondary products it includes those produced in the region from locally or regionally imported primary product plus those secondary products
50  * imported from other regions, less those exported to other regions. It doesn't include the secondary products imported from abroad the country.
51  */
52 double
53 Carbon::getStock(const int & regId, const int & stock_type) const{
54  double toReturn = 0.0;
55  int currentYear = MTHREAD->SCD->getYear();
56  int initialYear = MTHREAD->MD->getIntSetting("initialYear");
57  switch (stock_type){
58  case STOCK_PRODUCTS: {
59  vector <string> priProducts = MTHREAD->MD->getStringVectorSetting("priProducts");
60  vector <string> secProducts = MTHREAD->MD->getStringVectorSetting("secProducts");
61  vector <string> allProducts = priProducts;
62  allProducts.insert( allProducts.end(), secProducts.begin(), secProducts.end() );
63  for(uint i=0;i<allProducts.size();i++){
64  double coeff = MTHREAD->MD->getProdData("co2content_products",regId,allProducts[i],DATA_NOW,""); // [kg CO2/m^3 wood]
65  double life = MTHREAD->MD->getProdData("avgLife_products",regId,allProducts[i],DATA_NOW,"");
66  //for(int y=currentYear;y>currentYear-life;y--){ // ok
67  // iiskey key(y,regId,allProducts[i]);
68  // toReturn += findMap(products,key,MSG_NO_MSG,0.0)*coeff/1000;
69  //}
70  for(int y=(initialYear-100);y<=currentYear;y++){
71  iiskey key(y,regId,allProducts[i]);
72  double originalStock = findMap(products,key,MSG_NO_MSG,0.0);
73  double remainingStock = getRemainingStock(originalStock,life,currentYear-y);
74  toReturn += remainingStock*coeff/1000;
75  }
76  }
77  break;
78  }
79  case STOCK_INV:{
80  vector <string> fTypes = MTHREAD->MD->getForTypeIds();
81  for(uint i=0;i<fTypes.size();i++){
82  // units:
83  // co2content_inventory: [Kg CO2 / m^3 wood]
84  // co2content_extra: [Kg CO2 / m^3 inventaried wood]
85  double coeff = MTHREAD->MD->getForData("co2content_inventory",regId,fTypes[i],"",DATA_NOW); // [kg CO2/m^3 wood]
86  double life = MTHREAD->MD->getForData("avgLive_deathBiomass_inventory",regId,fTypes[i],"",DATA_NOW);
87  // PART A: from death biomass..
88  //for(int y=currentYear;y>currentYear-life;y--){ // ok
89  // iiskey key(y,regId,fTypes[i]);
90  // toReturn += findMap(deathBiomassInventory,key,MSG_NO_MSG)*coeff/1000;
91  //}
92  for(int y=(initialYear-100);y<=currentYear;y++){
93  iiskey key(y,regId,fTypes[i]);
94  double originalStock = findMap(deathBiomassInventory,key,MSG_NO_MSG,0.0);
95  double remainingStock = getRemainingStock(originalStock,life,currentYear-y);
96  toReturn += remainingStock*coeff/1000;
97  }
98 
99  // PART B: from inventory volumes
100  toReturn += MTHREAD->MD->getForData("vol",regId,fTypes[i],DIAM_ALL,DATA_NOW)*coeff/1000;
101  }
102  break;
103 
104  }
105  case STOCK_EXTRA:{
106  vector <string> fTypes = MTHREAD->MD->getForTypeIds();
107  for(uint i=0;i<fTypes.size();i++){
108  // units:
109  // co2content_inventory: [Kg CO2 / m^3 wood]
110  // co2content_extra: [Kg CO2 / m^3 inventaried wood]
111  double coeff = MTHREAD->MD->getForData("co2content_extra",regId,fTypes[i],"",DATA_NOW); // [kg CO2/m^3 wood]
112  double life = MTHREAD->MD->getForData("avgLive_deathBiomass_extra",regId,fTypes[i],"",DATA_NOW);
113  // PART A: from death biomass..
114  //for(int y=currentYear;y>currentYear-life;y--){ // ok
115  // iiskey key(y,regId,fTypes[i]);
116  // toReturn += findMap(deathBiomassExtra,key,MSG_NO_MSG),0.0*coeff/1000;
117  //}
118  for(int y=(initialYear-100);y<=currentYear;y++){
119  iiskey key(y,regId,fTypes[i]);
120  double originalStock = findMap(deathBiomassExtra,key,MSG_NO_MSG,0.0);
121  double remainingStock = getRemainingStock(originalStock,life,currentYear-y);
122  toReturn += remainingStock*coeff/1000;
123  }
124  // PART B: from inventory volumes
125  double extraBiomass_ratio = MTHREAD->MD->getForData("extraBiomass_ratio",regId,fTypes[i],"",DATA_NOW);
126  toReturn += MTHREAD->MD->getForData("vol",regId,fTypes[i],DIAM_ALL,DATA_NOW)*extraBiomass_ratio*coeff/1000;
127  }
128  break;
129  }
130  default:
131  msgOut(MSG_CRITICAL_ERROR,"Unexpected stock_type in function getStock");
132  }
133  return toReturn;
134 }
135 
136 
137 double
138 Carbon::getCumSavedEmissions(const int & regId, const int & em_type) const{
139  switch (em_type){
140  case EM_ENSUB:
141  return findMap(cumSubstitutedEnergy, regId);
142  break;
143  case EM_MATSUB:
144  return findMap(cumSubstitutedMaterial, regId);
145  break;
146  case EM_FOROP:
147  return -findMap(cumEmittedForOper, regId);
148  break;
149  default:
150  msgOut(MSG_CRITICAL_ERROR,"Unexpected em_type in function getCumSavedEmissions");
151  }
152  return 0.0;
153 }
154 
155 // ################# INITIALISE FUNCTIONS ################
156 
157 void
159  vector<int> regIds = MTHREAD->MD->getRegionIds(2);
160  for (uint i=0;i<regIds.size();i++){
161  pair<int,double> mypair(regIds[i],0.0);
162  cumSubstitutedEnergy.insert(mypair);
163  cumSubstitutedMaterial.insert(mypair);
164  cumEmittedForOper.insert(mypair);
165  }
166 }
167 
168 void
169 Carbon::initialiseDeathBiomassStocks(const vector<double> & deathByFt, const int & regId){
170  // it must initialize in the past the death biomass taking the value of the first year
171  vector <string> fTypes = MTHREAD->MD->getForTypeIds();
172  if(fTypes.size() != deathByFt.size()) {msgOut(MSG_CRITICAL_ERROR,"deathByFt and fTypes have different lenght!");}
173  int currentYear = MTHREAD->SCD->getYear();
174  //int initialYear = MD->getIntSetting("initialYear");
175 
176  for(uint i=0;i<fTypes.size();i++){
177 // double life_inventory = MTHREAD->MD->getForData("avgLive_deathBiomass_inventory",regId,fTypes[i],"",DATA_NOW);
178 // double life_extra = MTHREAD->MD->getForData("avgLive_deathBiomass_extra",regId,fTypes[i],"",DATA_NOW);
179  double extraBiomass_ratio = MTHREAD->MD->getForData("extraBiomass_ratio",regId,fTypes[i],"",DATA_NOW);
180 
181 // for(int y=currentYear;y>currentYear-life_inventory;y--){
182 // iiskey key(y,regId,fTypes[i]);
183 // pair<iiskey,double> mypair(key,deathByFt.at(i));
184 // deathBiomassInventory.insert(mypair);
185 // }
186 // for(int y=currentYear;y>currentYear-life_extra;y--){
187 // iiskey key(y,regId,fTypes[i]);
188 // pair<iiskey,double> mypair(key,deathByFt.at(i)*extraBiomass_ratio);
189 // deathBiomassExtra.insert(mypair);
190 // }
191 
192  for(int y=currentYear;y>currentYear-100;y--){
193  iiskey key(y,regId,fTypes[i]);
194  pair<iiskey,double> mypairInventory(key,deathByFt.at(i));
195  pair<iiskey,double> mypairExtra(key,deathByFt.at(i)*extraBiomass_ratio);
196  deathBiomassInventory.insert(mypairInventory);
197  deathBiomassExtra.insert(mypairExtra);
198  }
199  }
200 }
201 
202 void
203 Carbon::initialiseProductsStocks(const vector<double> & qByProduct, const int & regId){
204  // it must initialize in the past the products taking the value of the first year
205  vector <string> priProducts = MTHREAD->MD->getStringVectorSetting("priProducts");
206  vector <string> secProducts = MTHREAD->MD->getStringVectorSetting("secProducts");
207  vector <string> allProducts = priProducts;
208  allProducts.insert( allProducts.end(), secProducts.begin(), secProducts.end() );
209  if(allProducts.size() != qByProduct.size()) {msgOut(MSG_CRITICAL_ERROR,"allProducts and qByProduct have different lenght!");}
210  int currentYear = MTHREAD->SCD->getYear();
211  for(uint i=0;i<allProducts.size();i++){
212  double life = MTHREAD->MD->getProdData("avgLife_products",regId,allProducts[i],DATA_NOW);
213  //for(int y=currentYear;y>currentYear-life;y--){
214  for(int y=currentYear;y>currentYear-100;y--){
215  iiskey key(y,regId,allProducts[i]);
216  pair<iiskey,double> mypair(key,qByProduct.at(i));
217  products.insert(mypair);
218  }
219  }
220  //cout << "" << endl;
221 }
222 
223 // ################# REGISTER FUNCTIONS ################
224 void
225 Carbon::registerHarvesting(const double & value, const int & regId, const string & fType){
226  double convCoeff = MTHREAD->MD->getForData("forOperEmissions",regId,fType,""); // Kg of CO2 emitted per cubic meter of forest operations
227  // units:
228  // value: Mm^3
229  // convCoeff: Kg CO2/m^3 wood
230  // desidered output: Mt CO2
231  // ==> I must divide by 1000
232  addSavedEmissions(-convCoeff*value/1000,regId,EM_FOROP);
233  // Add the extraBiomass associated to the harvested volumes to the deathBiomassExtra pool
234  int year = MTHREAD->SCD->getYear();
235  double extraBiomass_ratio = MTHREAD->MD->getForData("extraBiomass_ratio",regId,fType,"",DATA_NOW);
236  double newDeathBiomass = value*extraBiomass_ratio;
237  iiskey key(year,regId,fType);
238  incrOrAddMapValue(deathBiomassExtra, key, newDeathBiomass);
239 }
240 
241 
242 void
243 Carbon::registerDeathBiomass(const double &value, const int & regId, const string & fType){
244  int year = MTHREAD->SCD->getYear();
245  iiskey key(year,regId,fType);
246  double extraBiomass_ratio = MTHREAD->MD->getForData("extraBiomass_ratio",regId,fType,"",DATA_NOW);
247  //pair<iiskey,double> mypairInventory(key,value);
248  //pair<iiskey,double> mypairExtra(key,value*extraBiomass_ratio);
250  incrOrAddMapValue(deathBiomassExtra, key, value*extraBiomass_ratio);
251  //deathBiomassInventory.insert(mypairInventory);
252  //deathBiomassExtra.insert(mypairExtra);
253 
254 }
255 
256 void
257 Carbon::registerProducts(const double &value, const int & regId, const string & productName){
258  // Registering the CO2 stock embedded in the product...
259  int year = MTHREAD->SCD->getYear();
260  iiskey key(year,regId,productName);
261  pair<iiskey,double> mypair(key,value);
262  products.insert(mypair);
263  // registering the substituted CO2 for energy and material..
264  double subEnergyCoeff = MTHREAD->MD->getProdData("co2sub_energy",regId,productName,DATA_NOW,"");
265  double subMaterialCoeff = MTHREAD->MD->getProdData("co2sub_material",regId,productName,DATA_NOW,"");
266  // units:
267  // value: Mm^3
268  // subEnergyCoeff and subMaterialCoeff: [kgCO2/m^3 wood]
269  // desidered output: Mt CO2
270  // ==> I must divide by 1000
271  addSavedEmissions(subMaterialCoeff*value/1000,regId,EM_MATSUB); // EM_ENSUB are now included in eol2energy, instantaneous for fuelwoods
272 }
273 
274 
275 
276 void
277 Carbon::registerTransports(const double &distQ, const int & regId){
278  // units:
279  // distQ: km*Mm^3
280  // transportEmissionsCoeff: [Kg CO2 / (km*m^3) ]
281  // desidered output: Mt CO2
282  // ==> I must divide by 1000
283  double transportEmissionsCoeff = MTHREAD->MD->getDoubleSetting("transportEmissionsCoeff",DATA_NOW);
284  addSavedEmissions(-transportEmissionsCoeff*distQ/1000,regId,EM_FOROP);
285 }
286 
287 void
289 
290  int currentYear = MTHREAD->SCD->getYear();
291  int initialYear = MTHREAD->MD->getIntSetting("initialYear");
292  vector <string> priProducts = MTHREAD->MD->getStringVectorSetting("priProducts");
293  vector <string> secProducts = MTHREAD->MD->getStringVectorSetting("secProducts");
294  vector <string> allProducts = priProducts;
295  allProducts.insert( allProducts.end(), secProducts.begin(), secProducts.end() );
296 
297  vector<int> regIds = MTHREAD->MD->getRegionIds(2);
298  for (uint r=0;r<regIds.size();r++){
299  double regId = regIds[r];
300  for(uint i=0;i<allProducts.size();i++){
301  string pr = allProducts[i];
302  double life = MTHREAD->MD->getProdData("avgLife_products",regId,pr,DATA_NOW,"");
303  double eol2e_share = MTHREAD->MD->getProdData("eol2e_share",regId,pr,DATA_NOW,"");
304  double subEnergyCoeff = MTHREAD->MD->getProdData("co2sub_energy",regId,pr,DATA_NOW,"");
305  if(eol2e_share > 0 && subEnergyCoeff>0){
306  for(int y=(initialYear-100);y<currentYear;y++){ // notice the minor operator and not minor equal: energy substitution for products produced this year assigned to the following year, otherwise double counring in the process of making dicrete the exponential function
307  iiskey key(y,regId,pr);
308  double originalStock = findMap(products,key,MSG_NO_MSG,0.0);
309  double remainingStockLastYear = getRemainingStock(originalStock,life,currentYear-y-1);
310  double remainingStockThisYear = getRemainingStock(originalStock,life,currentYear-y);
311  double eofThisYear = remainingStockLastYear-remainingStockThisYear;
312  addSavedEmissions(subEnergyCoeff*eofThisYear*eol2e_share/1000,regId,EM_ENSUB);
313  }
314  }
315  }
316  }
317 
318 }
319 
320 
321 // ################# UTILITY (PRIVATE) FUNCTIONS ################
322 
323 void
324 Carbon::addSavedEmissions(const double & value, const int & regId, const int & em_type){
325  switch (em_type){
326  case EM_ENSUB:
327  incrMapValue(cumSubstitutedEnergy, regId, value);
328  break;
329  case EM_MATSUB:
330  incrMapValue(cumSubstitutedMaterial, regId, value);
331  break;
332  case EM_FOROP:
333  incrMapValue(cumEmittedForOper, regId, -value);
334  break;
335  default:
336  msgOut(MSG_CRITICAL_ERROR,"Unexpected em_type in function getCumSavedEmissions");
337  }
338 }
339 
340 double
341 Carbon::getRemainingStock(const double & initialValue, const double & halfLife, const double & years) const{
342  // // TODO: remove this test
343  //if(years>0) return 0.0;
344  //return initialValue;
345 
346  double k = log(2)/halfLife;
347  return initialValue*exp(-k*years);
348 }
349 
map< int, double > cumEmittedForOper
Map that store emissions for forest operations, including transport, by l2_region [Mt CO2]...
Definition: Carbon.h:78
void addSavedEmissions(const double &value, const int &regId, const int &em_type)
Increases the value to the saved emissions for a given type and region.
Definition: Carbon.cpp:324
map< iiskey, double > products
Map that register the production of a given product by year, l2_region and product [Mm^3 wood]...
Definition: Carbon.h:75
The required data is for the current year.
Definition: BaseClass.h:73
Class to provide a simple integer-integer-string key in std maps.
Definition: BaseClass.h:195
void initialiseDeathBiomassStocks(const vector< double > &deathByFt, const int &regId)
Initialises the stocks of death biomass for the avgLive_* years before the simulation starts...
Definition: Carbon.cpp:169
int getIntSetting(const string &name_h, int position=0, int reg=WORLD) const
Definition: ModelData.cpp:1105
Do not actually output any message.
Definition: BaseClass.h:57
ThreadManager * MTHREAD
Pointer to the Thread manager.
Definition: BaseClass.h:467
~Carbon()
Definition: Carbon.cpp:36
ModelData * MD
the model data object
Definition: ThreadManager.h:72
double getCumSavedEmissions(const int &regId, const int &em_type) const
Returns the current cumulative saved emissions by type [Mt CO2].
Definition: Carbon.cpp:138
double getStock(const int &regId, const int &stock_type) const
Returns the current stock of carbon [Mt CO2].
Definition: Carbon.cpp:53
map< int, double > cumSubstitutedMaterial
Map that store the cumulative CO2 substituted using less energivory material, by l2_region [Mt CO2]...
Definition: Carbon.h:77
Scheduler * SCD
the scheduler object (simulation-loops scheduler)
Definition: ThreadManager.h:75
void msgOut(const int &msgCode_h, const string &msg_h, const bool &refreshGUI_h=true) const
Overloaded function to print the output log.
Definition: BaseClass.cpp:50
Thread manager. Responsable to manage the main thread and "speak" with the GUI.
Definition: ThreadManager.h:65
void incrMapValue(map< K, V > &mymap, const K &key, const V &value, const int &error_level=MSG_CRITICAL_ERROR)
Increments a value stored in a map of the specified value, given the key.
Definition: BaseClass.h:312
vector< string > getStringVectorSetting(const string &name_h, int reg=WORLD) const
Definition: ModelData.cpp:1129
Material substitution.
Definition: BaseClass.h:111
const double getProdData(const string &type_h, const int &regId_h, const string &prodId_h, const int &year=DATA_NOW, const string &freeDim_h="")
Definition: ModelData.cpp:1216
void registerTransports(const double &distQ, const int &regId)
Registers the quantities emitted by transport of wood FROM a given region.
Definition: Carbon.cpp:277
Print an error message and stop the model.
Definition: BaseClass.h:62
void registerDeathBiomass(const double &value, const int &regId, const string &fType)
Registers the "death" of a given amount of biomass, storing it in the deathBiomass map...
Definition: Carbon.cpp:243
Flow from forest operations.
Definition: BaseClass.h:112
const double getForData(const string &type_h, const int &regId_h, const string &forType_h, const string &freeDim_h, const int &year=DATA_NOW)
Definition: ModelData.cpp:1281
int getYear()
Definition: Scheduler.h:49
void initialiseProductsStocks(const vector< double > &qByProduct, const int &regId)
Initialises the stocks of products for the avgLive_* years before the simulation starts.
Definition: Carbon.cpp:203
Invetoried biomass (live and death tree logs)
Definition: BaseClass.h:104
Extra biomass (soils, branches..)
Definition: BaseClass.h:105
void registerHarvesting(const double &value, const int &regId, const string &fType)
Registers the harvesting of trees increasing the value of cumEmittedForOper.
Definition: Carbon.cpp:225
vector< string > getForTypeIds(bool all=false)
By default it doesn&#39;t return forTypes used only as input.
Definition: ModelData.cpp:430
V findMap(const map< K, V > &mymap, const K &key, const int &error_level=MSG_CRITICAL_ERROR, const V &notFoundValue=numeric_limits< V >::min()) const
Lookup a map for a value. Return the value starting from the key.
Definition: BaseClass.h:286
map< iiskey, double > deathBiomassInventory
Map that register the death of biomass by year, l2_region and forest type (inventoried)[Mm^3 wood]...
Definition: Carbon.h:73
void incrOrAddMapValue(map< K, V > &mymap, const K &key, const V &value)
Increments a value stored in a map of the specified value, given the key.
Definition: BaseClass.h:325
void initialiseEmissionCounters()
Initialises the emission counters to zero.
Definition: Carbon.cpp:158
Carbon(ThreadManager *MTHREAD_h)
Constructor.
Definition: Carbon.cpp:32
Energy substitution.
Definition: BaseClass.h:110
vector< int > getRegionIds(int level_h, bool excludeResidual=true)
Definition: ModelData.cpp:366
void HWP_eol2energy()
Computes the energy substitution for the quota of HWP that reachs end of life and doesn&#39;t go to landf...
Definition: Carbon.cpp:288
double getDoubleSetting(const string &name_h, int position=0, int reg=WORLD) const
Definition: ModelData.cpp:1109
map< iiskey, double > deathBiomassExtra
Map that register the death of biomass by year, l2_region and forest type (non-inventoried biomass: b...
Definition: Carbon.h:74
map< int, double > cumSubstitutedEnergy
Map that store the cumulative CO2 substituted for energy consumption, by l2_region [Mt CO2]...
Definition: Carbon.h:76
double getRemainingStock(const double &initialValue, const double &halfLife, const double &years) const
Apply a single exponential decay model to retrieve the remining stock given the initial stock...
Definition: Carbon.cpp:341
Biomass in forest products (sawns, pannels..)
Definition: BaseClass.h:106
#define DIAM_ALL
All diameter classes.
Definition: BaseClass.h:157
void registerProducts(const double &value, const int &regId, const string &productName)
Registers the production of a given amount of products, storing it in the products maps...
Definition: Carbon.cpp:257