#pragma warning (disable:4786) 

#include <stdio.h>
#include <math.h>
#include <vector>
#include <algorithm>

#include "LeafPhotosynthesis.h"
#include "CSCE_UA.H"

using namespace std;

const int MAX_NUM = 255;

// ********************************************************************************
// setting
// ********************************************************************************
const double g_dSaturatedLightRatio = 0.7;	// 0.0 -1.0 for light saturation of GFP
int g_iOptimizedPrm = 0;					// 0 for GPP, 1 for Transpiration
int g_iSequentialOpt = 1;					// 0 : not applied, 1 : applied
int g_iBlockWindow = 0;						// 0 : moving window, 1 : block window
int g_iRunPerDay = 48;						// Run per day
int g_iWindowSize = 8;						// day
int g_iWindowSize_Oren = 30;				// day
int g_iLeuningModel = 0;					// 0 : Ball-Berry model, 1 : Leuning model (stomatal conductance model)
int g_iCanopyStructure = 0;					// 0 : Big-Leaf model, 1 : Sun/Shade model
                                            // 2 : Multi-Layer model (big-leaf), 3 : Multi-Layer model (sun/shade model)
double g_dMultiLayerSplit = 1.0;			// LAI width of each layer for multi layer model (m2 m-2)
int g_iPhotosynthesisFunctions = 0;			// 0 : de Pury & Farquhar, 1 : Bernacchi, 2 : von Caemmerer, 3 : Collatz, 4 : Kosugi, 5: Kattge
											// 10 : C4 photosynthesis
int g_iC3 = 1;								// 1 : C3, 0 : C4 photosynthesis
int g_iSoilEvaporation = 1;					// 0 : neglect bare soil evaporation, 1 : potential evaporation
											// 2 : potential evaporation with dryness, 3 : grassland, 4 : rice paddy
int g_iImbalanceCorrection = 0;				// energy balance correction
											// 0 : no correction, 1 : corrected to H, 2 : corrected to LE, 3 : corrected to Rn, 4 : corrected using Bowen Ratio
int g_iUseAPAR = 3;							// for calculating APAR; 0 : APPFD = PPFD 1 : use PPFD_ref, 2 : use FPAR, 3 : use radiative transfer model, 4 : se radiative transfer model but neglecting trasmittanced PAR 
int g_iUseKB_inverse = 1;					// use kB-1 for calculating boundary layer conductance
int g_iSceUaItteration = 1;					// number of itteration for SCE-UA
int g_iSceUaItteration_each = 1;			// number of itteration for SCE-UA for applying window
int g_iFilling = 1;							// filling ga (using u* or U ) or Ts (using Ta)
bool g_bPeriod = false;						// apply period 
int g_iPrecipitationFilter = 2;				// rejecting data after the rainfall conditions; negative numbers is set when this filtering is not applied.
int g_iForwarmdMode = 0;					// 0 : inverse application, 1 : forward application, 2 : forward application with coupled model

double g_dUstarThreshold = 0.1;
double g_dCanopyHeight = 3.0;
double g_dMeasurementHeight = g_dCanopyHeight * 2.0;


// constant for radiative transfer model
const double g_dKai = 0.0;						// an empirical parameter describing the leaf angle distribution (Wang and Leuning. 1998 AFM)
const double g_dRow_reflectance = 0.1;			// leaf reflectance coefficient for PAR
const double g_dTaw_transmittance = 0.05;		// leaf transmissivity to PAR
double g_dSigma_scattering = g_dRow_reflectance + g_dTaw_transmittance;	// leaf scattering coefficient
const double g_dKdd = 0.719;					// diffuse and scattered diffuse PAR extinction coefficient
const double g_dRow_cd = 0.036;					// canopy relfection coefficient for beam PAR
double g_dLeaf_scattering_nir = 0.55;			// leaf scattering coefficient for NIR (Ryu et al., 2011GBC)
double g_dSoilReflectance_ppfd = 0.11;			// Soil reflectance for PAR (Ryu et al., 2011GBC)
double g_dSoilReflectance_nir = 0.23;			// Soil reflectance for PAR (Ryu et al., 2011GBC)

int g_iOmegaOptimization = 0;				// 0 : Omega is constant, 1 : Omega changed with optimization 
double g_dOmega = 0.55;						// clumping factor
int g_iShape = 0;							// 0 : Spherical, 1 : Planophile, 2 : Erectrophile

double g_dKn = -1.0;						// foliage nitrogen decay coefficient

// physical constant
const double c_dStefanBoltzman = 5.670367 * pow(10, -8);	// Stefan Boltzmann constant (W m-2 K-4)
const double c_dSpecificHeat = 1004.0;						// specific heat (1004 J K-1 kg -1)
const double c_dPI = 3.14159265359;

// ********************************************************************************
// site specific constant for radiative transfer model
// ********************************************************************************
double g_dLatitude = 64.866;					// degree	UAF site
double g_dLongitude = -147.8555306;				// degree	UAF site
double g_dElevation = 166.0;					// m		UAF site

// ********************************************************************************
// FILE name
// ********************************************************************************
char strInFile[MAX_NUM] = "C:\\00_DATA\\00-OPU\\XX-Program\\InvBigLeaf\\Debug\\scein.prm.dat";
char strInCsvFile[MAX_NUM] = "C:\\00_DATA\\00-OPU\\XX-Program\\InvBigLeaf\\Debug\\UAF.test.csv";
char strOutDirectory[MAX_NUM] = "C:\\00_DATA\\00-OPU\\XX-Program\\InvBigLeaf\\Debug";
char strInForwardParameterFile[MAX_NUM] = "C:\\test.txt";

char g_strOutPhysiologicalFile30[MAX_NUM];
char g_strOutPhysicalFile30[MAX_NUM];
char g_strOutFile_AnnualPrm[MAX_NUM]; 
char g_strOutFile_WindowPrm[MAX_NUM];
char g_strOutFile_LeafPrm[MAX_NUM];
char g_strOutFile_OrenPrm[MAX_NUM];
char g_strOutFile_Statistics[MAX_NUM];
const char g_strOutFile[]    = "";

// error related variable
const double c_dError = -99999.9;
const double c_dMinU  = 0.1;			// (m s-1)
const double c_dMaxGb = 2.0;			// (m s-1)
const double c_dMinGb = 0.01;			// (m s-1)
const double c_dMaxGc = 0.1;			// (m s-1)
const double c_dMinGc = 0.001;			// (m s-1)
const double c_dMaxDiff_Ts = 20.0;		// (degree C)

// column number for input file
const int c_iWindSpeed   = 1;
const int c_iPPFD        = 2;
const int c_iPPFD_ref    = 3;
const int c_iTemperature = 4;
const int c_iRH          = 5;
const int c_iRain        = 6;
const int c_iPressure    = 7;
const int c_iCO2         = 8;
const int c_iRn          = 9;
const int c_iG           = 10;
const int c_iUs          = 11;
const int c_iH           = 12;
const int c_iLE          = 13;
const int c_iGPP         = 14;
const int c_iTg          = 15;
const int c_iFPAR        = 16;
const int c_iLAI         = 17;
// const int c_ikn          = 18;

// column number for input/output parameter file
const int c_iVcmax25	= 1;
const int c_iJmax25		= 2;
const int c_iOmega		= 3;
const int c_iM			= 4;
const int c_iB			= 5;
const int c_iD0			= 6;

// column number for sce-ua optimization
const int c_iCO2_sce = 0;
const int c_iPPFD_sce = 1;
const int c_iAirTemperature_sce = 2;
const int c_iLeafTemperature_sce = 3;
const int c_iVPD_sce = 4;
const int c_iVP_air_sce = 5;
const int c_iVP_leaf_sce = 6;
const int c_iPressure_sce = 7;
const int c_iGc_sce = 8;
const int c_iGb_sce = 9;
const int c_iTg_sce = 10;
const int c_iUpscalingFactor_sce = 11;
const int c_iPPFD_sun_sce = 12;
const int c_iPPFD_shade_sce = 13;
const int c_iLAI_sun_sce = 14;
const int c_iLAI_shade_sce = 15;
const int c_iWeight_sun_sce = 16;
const int c_iWeight_shade_sce = 17;
const int c_iGPP_sce = 18;

const int c_iPPFD_direct_sce = 19;
const int c_idPPFD_diffuse_sce = 20;
const int c_iKb_sce = 21;
const int c_iKb2_sce = 22;
const int c_iRow_cb_sce = 23;
const int c_iRow_cd_sce = 24;

struct CData{
	vector<std::string> m_aryDate;
	vector<double>      m_aryDate_double;

	// input variables for foward model
	vector<double> m_aryTa;				// air temperature (degree C)
	vector<double> m_aryTg;				// growth temperature (degree C)
	vector<double> m_aryTs;				// radiative temperature (degree C)
	vector<double> m_aryRH;				// relative humidity (%)
	vector<double> m_aryVPD;			// vapor pressure difict (hPa)
	vector<double> m_aryUs;				// friction velocity (m s-1)
	vector<double> m_aryU;				// horizontal wind spped (m s-1)
	vector<double> m_aryPressure;		// atmospheric pressure (hPa)
	vector<double> m_aryRain;			// Rainfall (mm)

	// variable for photosynthesis model
	vector<double> m_aryPPFD;			// photosynthetically active radiation (umol m-2 s-1)
	vector<double> m_aryPPFD_ref;		// reflected photosynthetically active radiation (umol m-2 s-1)
	vector<double> m_aryAPPFD;			// absorbed photosynthetically active radiation (umol m-2 s-1)
	vector<double> m_aryCO2;			// CO2 concentration (ppm)
	vector<double> m_aryFPAR;			// fraction of PPFD (--)
	vector<double> m_aryLAI;			// leaf are index (m2 m-2)
//	vector<double> m_aryKn;				// extinction coefficient for canopy eneryg transfer

	// input variables for inverse model
	vector<double> m_aryH;				// sensible heat flux (W m-2)
	vector<double> m_aryLE;				// latent heat flux (W m-2)
	vector<double> m_aryRn;				// net radiation (W m-2)
	vector<double> m_aryG;				// ground heat flux (W m-2)
	vector<double> m_aryGPP;			// gross primary productivity (umol m-2 s-1)
	vector<double> m_aryLE_mg;			// latent heat flux (mg m-2 s-1)

	// estimated variables from extended Big leaf model
	vector<double> m_aryVcmax_eBL;		// maximum carboxylation (umol m-2 s-1)
	vector<double> m_aryVcmax25_eBL;	// maximum carboxylation at 25oC (umol m-2 s-1)
	vector<double> m_aryCi_eBL;			// CO2 concentration within interceller (ppm)

	// estimated variables
	vector<double> m_aryGb;				// boundary layer conductance (s m-1)
	vector<double> m_aryGb_h;			// boundary layer conductance for sensible heat (s m-1)
	vector<double> m_aryGc;				// surface conductance from Penman-Monteith equation (s m-1)
	vector<double> m_aryBeta;			// moisture availability (ratio of bulk coefficient; Ce / Ch)
	vector<double> m_aryLE_eq;			// equilibrium evaporation rate (W m-2)
	vector<double> m_aryLE_imp;			// imposed evapotranspiration rate (W m-2)
	vector<double> m_aryOmega;			// decoupling coefficient
	vector<double> m_arySVP;			// staturated vapor pressure (hPa)
	vector<double> m_aryVP_air;			// atmospheric vapor pressure (hPa)
	vector<double> m_aryVP_leaf;		// vapor pressure at leaf (hPa)
	vector<double> m_aryD0;				// effective vapor pressure deficit (hPa)
	vector<double> m_aryB_inv;			// dimensionless bulk parameter B-1 for correcting excess resistance
	vector<double> m_aryWUE;			// water use efficiency (umol CO2 per mmol H2O)
	vector<double> m_aryLUE;			// light use efficiency (umol CO2 per umol PPFD)

	vector<double> m_aryRn_soil;			// bare soil net radiation (W m-2)
	vector<double> m_aryE_soil;				// bare soil evaporation (W m-2)
	vector<double> m_aryTranspiration_obs;	// transpiration (evapotranspiration - bare soil evaporation) (W m-2)

	vector<double> m_aryD;					// zero-plane displacement (m)
	vector<double> m_aryZ0;					// roughness length (m)
	vector<double> m_aryCanopyHeight;		// canopy height (m)

	vector<double> m_aryCi;					// CO2 concentration within interceller (ppm)
	vector<double> m_aryGs;					// stomatal conductance (umol m-2 s-1)
	vector<double> m_aryVcmax;				// maximum carboxylation (umol m-2 s-1)
	vector<double> m_aryJmax;				// maximum electron transport rate (umol m-2 s-1)
	vector<double> m_aryPhotosynthesis;		// leaf photosynthesis (umol m-2 s-1)
	vector<double> m_aryTranspiration;		// leaf trasnpiration (umol m-2 s-1)
//	vector<double> m_aryQstar;				// absorbed PAR (q*) when j leaf photosythesis is co-limited by Vcmax and Jmax (umol m-2 s-1)

	vector<double> m_aryCi_window;				// CO2 concentration within interceller (ppm)
	vector<double> m_aryGs_window;				// stomatal conductance (umol m-2 s-1)
	vector<double> m_aryVcmax_window;			// maximum carboxylation (umol m-2 s-1)
	vector<double> m_aryJmax_window;			// maximum electron transport rate (umol m-2 s-1)
	vector<double> m_aryPhotosynthesis_window;	// leaf photosynthesis using window (umol m-2 s-1)
	vector<double> m_aryAsun_window;			// leaf photosynthesis by sunlit leaf using window (umol m-2 s-1)
	vector<double> m_aryAshade_window;			// leaf photosynthesis by shaded leaf using window (umol m-2 s-1)
	vector<double> m_aryTranspiration_window;	// leaf trasnpiration using window (umol m-2 s-1)
	vector<double> m_aryQstar_window;			// absorbed PAR (q*) when j leaf photosythesis is co-limited by Vcmax and Jmax (umol m-2 s-1)
	vector<double> m_aryA_gs_window;			// Leaf photosnythesis when stomatal conductance does not limt difussion  (umol m-2 s-1)
	vector<double> m_aryA_gs_ga_window;			// Leaf photosnythesis when stomatal and boundary layer conductance does not limt difussion  (umol m-2 s-1)
	vector<double> m_aryA_gs_ga_ts_window;		// Leaf photosnythesis when stomatal and boundary layer conductance does not limt difussion at air temperature  (umol m-2 s-1)
	vector<double> m_aryAv_window;				// Rubisco-limited Leaf photosnythesis (umol m-2 s-1)
	vector<double> m_aryAj_window;				// Electron-tranport limited Leaf photosnythesis (umol m-2 s-1)

	vector<double> m_aryRs_toa;	        // solar radiation at the top of the atmosphere (W m-2)
	vector<double> m_aryPPFD_direct;	// direct photosynthetically active radiation (umol m-2 s-1)
	vector<double> m_aryPPFD_diffuse;	// diffuse photosynthetically active radiation (umol m-2 s-1)
	vector<double> m_aryLAI_sun;		// leaf area index for sunlit leaf (m2 m-2)
	vector<double> m_aryLAI_shade;		// leaf area index for shade leaf (m2 m-2)
	vector<double> m_aryWeight_sun;		// weighting factor of sunlit leaf  (Wang and Leuning, 1998AFM)
	vector<double> m_aryWeight_shade;	// weighting factor of shade leaf   (Wang and Leuning, 1998AFM)
	vector<double> m_aryPPFD_sun;		// PPFD for sun leaf (umol m-2 s-1)
	vector<double> m_aryPPFD_shade;		// PPFD for shade leaf (umol m-2 s-1)
	vector<double> m_aryKb;				// extinction coefficient of a canopy of black leaves for direct beam radiation (Wang and Leuning, 1998AFM)
	vector<double> m_aryKb2;			// extinction coefficient
	vector<double> m_aryRow_cb;			// relfectance of beam irradiance, uniform leaf-angle distribution (A19; de Pury and Farquhar, 1997PCE)
	vector<double> m_aryRow_cd;			// relfectance of diffuse irradiance, uniform leaf-angle distribution

//	vector<double> m_aryWeight_sun_top;		// weighting factor of sunlit leaf at the top layer  (Wang and Leuning, 1998AFM)
//	vector<double> m_aryWeight_sun_top_day;	// weighting factor of sunlit leaf at the top layer  (Wang and Leuning, 1998AFM)

//	vector<double> m_aryLAI_sun_day;		// leaf area index for sunlit leaf (m2 m-2)
//	vector<double> m_aryLAI_shade_day;		// leaf area index for shade leaf (m2 m-2)
//	vector<double> m_aryWeight_sun_day;		// weighting factor of sunlit leaf  (Wang and Leuning, 1998AFM)
//	vector<double> m_aryWeight_shade_day;	// weighting factor of shade leaf   (Wang and Leuning, 1998AFM)
//	vector<double> m_aryKb_day;				// extinction coefficient of a canopy of black leaves for direct beam radiation

	vector<double> m_aryF;					// energy redistribution efficiency (dimensionless)
	vector<double> m_aryRamda0;				// temperature sensitivity resulting from the longwave radiation feedback (K m2 W-1)

	vector<int>    m_aryPeriod;			// period
};

struct CDailyData{
	vector<double>		m_aryFPAR;					// Fraction of absorbed PAR
	vector<double>      m_aryWeight_sun;			// weighting factor of sunlit leaf  (Wang and Leuning, 1998AFM)
	vector<double>      m_aryWeight_shade;			// weighting factor of shade leaf   (Wang and Leuning, 1998AFM)
	vector<double>		m_aryWeight_sun_top;		// weighting factor of sunlit leaf at the top layer
	vector<double>      m_aryLAI_sun;				// leaf area index for sunlit leaf (m2 m-2)
	vector<double>      m_aryLAI_shade;				// leaf area index for shade leaf (m2 m-2)
	vector<double>      m_aryKn;                    // nitrogen extinction coefficient (--)

	vector<double>		m_aryVcmax25;				// Big Leaf Vcmax25 (umol m-2(area) s-1)
	vector<double>		m_aryVcmax25_leaf;			// Big Leaf Vcmax25 at top of the canopy (umol m-2(area) s-1)
	vector<double>		m_aryVcmax25_sun;			// Big Leaf Vcmax25 (umol m-2(area) s-1)
	vector<double>		m_aryVcmax25_shade;			// Big Leaf Vcmax25 (umol m-2(area) s-1)
	vector<double>		m_aryVcmax25_sun_leaf;		// Big Leaf Vcmax25 (umol m-2(leaf) s-1)
	vector<double>		m_aryVcmax25_shade_leaf;	// Big Leaf Vcmax25 (umol m-2(leaf) s-1)

	vector<double>		m_aryJmax25;				// Big Leaf Jmax25  (umol m-2 s-1)
	vector<double>		m_aryJmax25_leaf;			// Big Leaf Jmax25 at top of the canopy  (umol m-2(area) s-1)
	vector<double>		m_aryJmax25_sun;			// Big Leaf Jmax25  (umol m-2(area) s-1)
	vector<double>		m_aryJmax25_shade;			// Big Leaf Jmax25  (umol m-2(area) s-1)
	vector<double>		m_aryJmax25_sun_leaf;		// Big Leaf Jmax25  (umol m-2(leaf) s-1)
	vector<double>		m_aryJmax25_shade_leaf;		// Big Leaf Jmax25  (umol m-2(leaf) s-1)

	vector<double>		m_aryM_bb;					// m for Ball-Berry model (--)
	vector<double>		m_aryB_bb;					// b for Ball-Berry model (umol m-2(area) s-1)
	vector<double>		m_aryB_bb_leaf;				// b for Ball-Berry model at top of the canopy  (umol m-2(leaf) s-1)
	vector<double>		m_aryB_bb_sun;				// b for Ball-Berry model (umol m-2(area) s-1)
	vector<double>		m_aryB_bb_shade;			// b for Ball-Berry model (umol m-2(area) s-1)
	vector<double>		m_aryB_bb_sun_leaf;			// b for Ball-Berry model (umol m-2(leaf) s-1)
	vector<double>		m_aryB_bb_shade_leaf;		// b for Ball-Berry model (umol m-2(leaf) s-1)

	vector<double>      m_aryOmega;

	vector<double>		m_aryGs_ref;				// referenced stomatal conductance by Oren et al. (1999) (mmol m-2 s-1)
	vector<double>		m_aryM;						// sensitivity to VPD by Oren et al. (1999) (mmol m-2 s-1 per ln(kPa)-2)
	vector<double>		m_aryR2_Oren;				// R2 value by the Oren model (1999) (dimensionless)

	vector<double>		m_aryWUE;					// water use efficiency (umol CO2 per mmol H2O)
	vector<double>		m_aryLUE;					// light use efficiency (umol CO2 per ummol PPFD)

	vector<double>		m_aryD;						// zero-plane displacement (m)
	vector<double>		m_aryZ0;					// roughness length (m)
	vector<double>		m_aryCanopyHeight;			// canopy height (m)
	vector<double>		m_aryStandDensity;			// stand density (trees ha-1)
};

struct CStatistics{
	double dSlopeA;		// Obs = dSlopeA * Model + dOffset
	double dOffsetA;	// Obs = dSlopeA * Model + dOffset
	double dSlopeB;		// Model = dSlopeB * Obs + dOffset
	double dOffsetB;	// Model = dSlopeB * Obs + dOffset
	double dR;			// correlation coefficient of the linear regression

	double dSlope0A;	// Obs = dSlopeA * Model
	double dR20a;		// correlation coefficient of the linear regression assuming offest = 0.
	double dSlope0B;	// Model = dSlopeB * Obs
	double dR20b;		// correlation coefficient of the linear regression assuming offest = 0.

	double dRMSE;		// root mean square error
	double dME;			// mean error (Model - Obs)
	int    iNumber;		// sample number
};

void set_vector(CData& data, int iColmunNum);
void reject_rainfall_condition(CData& data);
void energy_balance_correction(CData& data, const int iCorrection);

void calculate_roughness_length_zero_plane_displacement(CData& data, CDailyData& daily);
double calculate_stand_density(const double dD, const double dCanopyHeight, const double dLAI);

double calculate_rate_change_saturation_vapor_pressure(const double& dT, const double& dPressure);
double calculate_psychrometric_constant(const double& dT, const double& dPressure);
double Goff_Gratch(const double& dT_degreeC, const double& dPressure);
double calculate_latent_heat(const double& dT);
double calculate_air_density(const double& dT, const double& dP, const double& dRH, const int& bMol);
double calculate_stability(double dZ, double& dH, double& dUstar, double& dT, double& dP, double& dRH);

void calculate_APAR(std::vector<double>& m_aryPPFD, std::vector<double>& aryPPFD_ref, std::vector<double>& aryFPAR, std::vector<double>& aryAPPFD, int iUseFPAR );
void radiation_transfer(CData& data, CDailyData& daily);
void get_G_function(double& dG, const double& dRad, const int& iShape);
void daily_parameters(CData& data, CDailyData& daily, std::vector< std::vector<double> >& aryBestParametersWindow);
double calculate_kn(const double& dVcmax, const double& dLAI, const double& dKb, int iCanopyStructure);
void mean_parameters_window(CData& data);

void calculating_kB_inverse(double& dLAI, double& dK_inv);
void calculate_boundary_layer_conductance(std::vector<double>& aryUs, std::vector<double>& aryU, std::vector<double>& aryLAI, std::vector<double>& aryGb, std::vector<double>& aryGb_h  );
void calculate_radiative_temperature(CData& data, int& iUseKB_inverse);
void calculate_surface_conductance_Penman_Monteith(CData& data, int& iUseKB_inverse);
void calculate_decoupling_coefficient(CData& data, int& iUseKB_inverse);
void calculate_bare_soil_evaporation(CData& data);
void calculate_effective_vpd(CData& data, int& iUseKB_inverse);
void calculate_vapor_pressure(std::vector<double>& aryTa, std::vector<double>& aryRH, std::vector<double>& aryVPD, std::vector<double>& aryTs, std::vector<double>& aryPressure, std::vector<double>& aryVP_air, std::vector<double>& aryVP_leaf, std::vector<double>& arySVP);
void calculate_energy_redistribution_efficiency(CData& data);
void calculate_photosynthetic_variables(CData& data, std::vector< std::vector<double> >& aryBestParameterSet, std::vector<double>& aryBestFunction, double& dRMSE_GPP, double& dRMSE_LE, int& iUseKB_inverse);
void calculate_photosynthetic_variables_window(CData& data, std::vector< std::vector<double> >& aryBestParameterSet, std::vector< std::vector<double> >& aryRMSE, int& iUseKB_inverse);
void apply_extended_big_leaf_model(CData& data, const double& dSaturationLightRatio, int& iUseKB_inverse);
double get_light_saturation_point(std::vector<double>& aryGPP, std::vector<double>& aryPPFD, double dSaturationLightRatio);

void interpolate_parameter_block_window(CData& data, std::vector< std::vector<double> >& aryBestParametersWindow, std::vector< std::vector<double> >& aryStdevParametersWindow, std::vector< std::vector<double> >& aryRMSE);
void quality_control_parameter(std::vector< std::vector<double> >& aryBestParametersWindow, std::vector< std::vector<double> >& aryStdevParametersWindow, std::vector< std::vector<double> >& aryRMSE);
void get_annual_paramters(std::vector< std::vector<double> >& aryBestParameterSet, std::vector<double>& aryBestFunction, std::vector<double>& aryAnnualBestPrm, std::vector<double>& aryAnnualBestPrmStdev);

// modeling stomatal conductance_Oren1999;
void model_stomatal_conductance_Oren1999(CData& data, CDailyData& daily);
void model_stomatal_conductance_Oren1999(std::vector<double>& aryGc, std::vector<double>& aryVPD, std::vector<double>& aryTa, std::vector<double>&  aryPressure, std::vector<double>& aryRH, double& dGs_ref, double& dM, double& dR2);
void remove_out_linear_Dixon(std::vector<double>& aryTargetData, std::vector<double>& aryPairedData);
double look_up_Dixon_table(const int& n);
void average_stdev(const std::vector<double>& x, double& average, double& stdev);

void calculate_water_light_use_efficiency(CData& data, CDailyData& daily);

// gap-filling
void linear_regression(std::vector<double>& aryY, std::vector<double>& aryX, double& dSlope, double& dOffset, double& dR2);

// for sce-ua method
void optimize_photosynthesis_stomatal_conductance_model(CSCE_UA& cSCE_UA, model_input& cModel, CData& data, vector< vector<double> >& aryBestParameterSet, vector<double>& aryBestFunction, int nrun);
void optimize_photosynthesis_stomatal_conductance_model_window(CSCE_UA& cSCE_UA, model_input& cModel, CData& data, vector< vector<double> >& aryBestParameterSet, vector< vector<double> >& aryStdevParameterSet, vector< vector<double> >& aryRMSE, int nrun);
void optimize_photosynthesis_stomatal_conductance_model_each(CSCE_UA& cSCE_UA, model_input& cModel, CData& data, vector< vector<double> >& aryBestParameterSet, vector< vector<double> >& aryStdevParameterSet, vector< vector<double> >& aryRMSE, int nrun);
void set_parameter_range(CSCE_UA& cSCE_UA, int iIndex, double& dBestPrm, double& dStdev);
void set_parameter_range(CSCE_UA& cSCE_UA, int iIndex, double& dBestPrm, double& dLow, double& dHigh );
void search_best_stdev(const std::vector< std::vector<double> >& aryBestParameters, const std::vector<double>& aryBestFunction, int iIndex, int& iBestIndex, double& dStdev);

void create_output_filename(const char strOutDirectory[]);
bool input_csv_file(CSCE_UA& cSCE_UA, CData& data);
bool input_forward_parameter_file(vector< vector<double> >& aryBestParametersWindow);
bool sce_setting_input(CSCE_UA& cSCE_UA, model_input& cModel);
void photosynthesis_model(std::vector<double>& parameters, const std::vector< std::vector<double> >& input,  std::vector< std::vector<double> >& output);
void stomatal_model(std::vector<double>& parameters, const std::vector< std::vector<double> >& input,  std::vector< std::vector<double> >& output);
void DeleteHeadSpace(string &buf);
int max(int iA, int iB);

// quality control
void quality_control(CData& data, std::vector<double>& aryData);
void QualityControl_MAD(std::vector<double>& aryData, std::vector<int>& aryQC_flg, const double& dZvalue);
void MedianOfAbsoluteDeviation(const std::vector<double>& aryNoGapData, std::vector<int>& aryQC_flag, const double& dZvalue);
double Median(std::vector<double> aryDouble);

// statistics
void calculate_statistics(CStatistics& cStatistics, std::vector<double> aryObservation, std::vector<double> aryModel, std::vector<double> aryCi, const double &dUpperLimit, const double &dLowerLimit);

// output data
bool output_30hour_physiological_variable(std::vector<string>& aryDate, CData& data);
bool output_30hour_physical_variable(CData& data);
bool output_estimated_paramters(std::vector< std::vector<double> >& aryBestParameterSet, std::vector<double>& aryBestFunction, double& dRmseGPP);
bool output_estimated_paramters_window(std::vector< std::vector<double> >& aryBestParametersWindow, std::vector< std::vector<double> >& aryStdevParametersWindow, vector< vector<double> >& aryRMSE, std::vector<double>& aryAnnualBestPrm, std::vector<double>& aryAnnualBestPrmStdev, double& dRmseGPP, double& dRmseLE);
bool output_leaf_paramters_window(CDailyData& daily);
bool output_daily_paramters_window(CDailyData& daily);
bool output_statistics(const CStatistics& cStatistics_GPP, const CStatistics& cStatistics_LE);

int read_setting_file(const char strInSettingFile[] );

// ********************************************************************************
// START Main program
// ********************************************************************************
void main(int argc,char *argv[])
{
	CData data;
	CDailyData daily;

	vector< vector<double> > aryBestParameterSet;
	vector<double> aryBestFunction;
	vector<double> aryAnnualBestPrm;
	vector<double> aryAnnualBestPrmStdev;

	// read setting file
	char strSettingFile[MAX_NUM] = ""; //C:\\00_DATA\\00-OPU\\XX-Program\\InvBigLeaf\\input\\00-Alaska\\UAF\\setting\\00-Test.txt";
	// char strSettingFile[MAX_NUM] = "C:\\00_DATA\\Big-Leaf\\input\\01-AsiaFlux\\BNS\\setting\\ABNS.2003.test.txt";
	// char strSettingFile[MAX_NUM] = "C:\\00_DATA\\00-OPU\\XX-Program\\InvBigLeaf\\input\\00-Alaska\\UAF\\setting\\00-Test.txt";
	// char strSettingFile[MAX_NUM] = "C:\\00_DATA\\00-OPU\\XX-Program\\InvBigLeaf\\input\\test\\DLS_03.Setting.txt";
	// char strSettingFile[MAX_NUM] = "C:\\00_DATA\\Big-Leaf\\input\\01-AsiaFlux\\KBU\\setting\\KBU.2004.10t.lai.co2.Setting_fw.txt";

	if(argc == 2){
		strcpy(strSettingFile, argv[1]);
		if(read_setting_file(strSettingFile) == false){
			printf("Input setting by argv was not opened.\n");
			return;
		}
	}

	// create output file name
	create_output_filename(strOutDirectory);

	// read input data
	CSCE_UA cSCE_UA(c_dError);
	cSCE_UA.m_iOptimizedPrm = g_iOptimizedPrm;
	model_input cModel;
	if(input_csv_file(cSCE_UA, data) == false){
		printf("error in sce_data_input.\n");
		return;
	}

	// set flag for C3 or C4 photosynthesis
	if(g_iPhotosynthesisFunctions == 10){
		g_iC3 = 0;
	}
	else{
		g_iC3 = 1;
	}

	// set vector
	set_vector(data, data.m_aryPeriod.size());

	// reject rainy data
	reject_rainfall_condition(data);

	// energy balance correction
	energy_balance_correction(data, g_iImbalanceCorrection);

	// calculating absorbed photosynthetically active radiation
	calculate_APAR(data.m_aryPPFD, data.m_aryPPFD_ref, data.m_aryFPAR, data.m_aryAPPFD, g_iUseAPAR );

	// roughness length and zero-plane displacement
	calculate_roughness_length_zero_plane_displacement(data, daily);

	// radiative transfer
	radiation_transfer(data, daily);

	// calculating boundary layer conductance
	calculate_boundary_layer_conductance(data.m_aryUs, data.m_aryU, data.m_aryLAI, data.m_aryGb, data.m_aryGb_h );

	// calculating radiative surface temperature using Bulk model
	// quality control of Ga using sensible heat flux
	calculate_radiative_temperature(data, g_iUseKB_inverse);
	quality_control(data, data.m_aryTs);

	// calculating vapor pressure
	calculate_vapor_pressure(data.m_aryTa, data.m_aryRH, data.m_aryVPD, data.m_aryTs, data.m_aryPressure, data.m_aryVP_air, data.m_aryVP_leaf, data.m_arySVP);

	// calculating Gc, Omega, Eimp, Eeq
	//  using Penman-Monteith 
	calculate_surface_conductance_Penman_Monteith(data, g_iUseKB_inverse);
	quality_control(data, data.m_aryGc);

	// calculating decoupling coefficient
	calculate_decoupling_coefficient(data, g_iUseKB_inverse);
	quality_control(data, data.m_aryLE_imp);

	// calculating bare soil evaporation
	calculate_bare_soil_evaporation(data);

	// calculating effecitve vapor pressure deficit
	calculate_effective_vpd(data, g_iUseKB_inverse);
	// calculate_effective_vpd(data.m_aryGb, data.m_aryTa, data.m_aryVPD, data.m_aryPressure, data.m_aryLE_eq, data.m_aryLE, data.m_aryD0);

	// calculating energy redistribution efficiency
	calculate_energy_redistribution_efficiency(data);

	// modelling stomatal conductance and water use efficiency
	if(g_iForwarmdMode == 0){
		// modelling stomatal conductance based on Oren et al. (1999)
		model_stomatal_conductance_Oren1999(data, daily);

		// calculating water use efficiency
		calculate_water_light_use_efficiency(data, daily);
		quality_control(data, data.m_aryWUE);
		quality_control(data, data.m_aryLUE);

		output_daily_paramters_window(daily);
	}

	// calculating Vcmax, Ci, and Vcmax25 using an extended Big-Leaf model by Kosugi et al. (2005)
	apply_extended_big_leaf_model(data, g_dSaturatedLightRatio, g_iUseKB_inverse);

	if(g_iForwarmdMode == 0){
		// inverse mode
		// set stomatal conductance model
		CLeafPhotosynthesis cStomatalModel(c_dError);
		cStomatalModel.m_iLeuningModel = g_iLeuningModel;
		cStomatalModel.m_iPhotosynthesisFunctions = g_iPhotosynthesisFunctions;
		cStomatalModel.m_iC3 = g_iC3;
		cStomatalModel.m_iCanopyStructure = g_iCanopyStructure;
		cStomatalModel.m_dMultiLayerSplit = g_dMultiLayerSplit;
		cStomatalModel.m_dSigma_scattering = g_dSigma_scattering;
		cStomatalModel.m_dSoilReflectance_ppfd = g_dSoilReflectance_ppfd;
		cStomatalModel.m_dKdd = g_dKdd;
		cStomatalModel.m_iOmegaOptimization = g_iOmegaOptimization;
		cStomatalModel.m_dOmega = g_dOmega;
		cStomatalModel.m_dKn = g_dKn;

		// ********************************************************************************
		// calculating eco-physiological variables using a coupled Farquhar and Ball-Berry model
		//  for specifing window size
		// ********************************************************************************
		vector< vector<double> > aryBestParametersWindow, aryStdevParametersWindow, aryRMSE;
		optimize_photosynthesis_stomatal_conductance_model_window(cSCE_UA, cModel, data, aryBestParametersWindow, aryStdevParametersWindow, aryRMSE, g_iSceUaItteration_each);

		if(g_iBlockWindow){
			interpolate_parameter_block_window(data, aryBestParametersWindow, aryStdevParametersWindow, aryRMSE);
		}
		quality_control_parameter(aryBestParametersWindow, aryStdevParametersWindow, aryRMSE);
		calculate_photosynthetic_variables_window(data, aryBestParametersWindow, aryRMSE, g_iUseKB_inverse);

		// ********************************************************************************
		// downscaling big-leaf parameters to leaf parameters
		// ********************************************************************************
		daily_parameters(data, daily, aryBestParametersWindow);		

		// ********************************************************************************
		// calculating eco-physiological variables using a coupled Farquhar and Ball-Berry model
		//  for annual window size
		// ********************************************************************************
		optimize_photosynthesis_stomatal_conductance_model(cSCE_UA, cModel, data, aryBestParameterSet, aryBestFunction, g_iSceUaItteration);

		// calculate gs, Ci, Vcmax, Jmax using optimized parameters
		double dRMSE_GPP, dRMSE_LE;
		calculate_photosynthetic_variables(data, aryBestParameterSet, aryBestFunction, dRMSE_GPP, dRMSE_LE, g_iUseKB_inverse);

		// get best parameter statistics
		get_annual_paramters(aryBestParameterSet, aryBestFunction, aryAnnualBestPrm, aryAnnualBestPrmStdev);

		// ********************************************************************************
		// Output data
		// ********************************************************************************
		// output 30-hour dataset for all data
		output_30hour_physiological_variable(cModel.m_aryDate, data);
		// output_estimated_paramters(aryBestParameterSet, aryBestFunction, dRmseGPP);
		output_estimated_paramters_window(aryBestParametersWindow, aryStdevParametersWindow, aryRMSE, aryAnnualBestPrm, aryAnnualBestPrmStdev, dRMSE_GPP, dRMSE_LE);
		output_leaf_paramters_window(daily);
	}
	else{
		// forward mode
		// set stomatal conductance model
		CLeafPhotosynthesis cStomatalModel(c_dError);
		cStomatalModel.m_iLeuningModel = g_iLeuningModel;
		cStomatalModel.m_iPhotosynthesisFunctions = g_iPhotosynthesisFunctions;
		cStomatalModel.m_dMultiLayerSplit = g_dMultiLayerSplit;
		cStomatalModel.m_dSigma_scattering = g_dSigma_scattering;
		cStomatalModel.m_dSoilReflectance_ppfd = g_dSoilReflectance_ppfd;
		cStomatalModel.m_dKdd = g_dKdd;
		cStomatalModel.m_iOmegaOptimization = g_iOmegaOptimization;
		cStomatalModel.m_dOmega = g_dOmega;
		cStomatalModel.m_dKn = g_dKn;
		cStomatalModel.m_iC3 = g_iC3;

		vector< vector<double> > aryBestParametersWindow;
		if(input_forward_parameter_file(aryBestParametersWindow) == false){
			return;
		}

		vector< vector<double> > aryRMSE;
		calculate_photosynthetic_variables_window(data, aryBestParametersWindow, aryRMSE, g_iUseKB_inverse);

		// output 30-hour dataset for all data
		output_30hour_physiological_variable(cModel.m_aryDate, data);
	}

	// output physical variable
	output_30hour_physical_variable(data);

	// calculate and output statistics
	CStatistics cGPP_statistics, cLE_statistics;
	const double dUpperLimitGPP = 100.0;		// umol m-2 -s1
	const double dLowerLimitGPP = 0.0;			// umol m-2 -s1
	const double dUpperLimitLE = 900.0;			// W m-2
	const double dLowerLimitLE = 0.0;			// W m-2
	calculate_statistics(cGPP_statistics, data.m_aryGPP, data.m_aryPhotosynthesis_window, data.m_aryCi_window, dUpperLimitGPP, dLowerLimitGPP);
	calculate_statistics(cLE_statistics,  data.m_aryTranspiration_obs, data.m_aryTranspiration_window, data.m_aryCi_window, dUpperLimitLE, dLowerLimitLE);
	output_statistics(cGPP_statistics, cLE_statistics);

}

void set_vector(CData& data, int iColmunNum)
{
	// estimated variables
	data.m_aryD.assign(iColmunNum);
	data.m_aryZ0.assign(iColmunNum);
	data.m_aryCanopyHeight.assign(iColmunNum);

	data.m_aryAPPFD.assign(iColmunNum);
	data.m_aryTs.assign(iColmunNum);
	data.m_aryGb.assign(iColmunNum);
	data.m_aryGb_h.assign(iColmunNum);
	data.m_aryGc.assign(iColmunNum);
	data.m_aryBeta.assign(iColmunNum);
	data.m_aryLE_eq.assign(iColmunNum);
	data.m_aryLE_imp.assign(iColmunNum);
	data.m_aryOmega.assign(iColmunNum);
	data.m_arySVP.assign(iColmunNum);
	data.m_aryVP_air.assign(iColmunNum);
	data.m_aryVP_leaf.assign(iColmunNum);
	data.m_aryD0.assign(iColmunNum);
	data.m_aryB_inv.assign(iColmunNum);
	data.m_aryWUE.assign(iColmunNum);
	data.m_aryLUE.assign(iColmunNum);

	data.m_aryRn_soil.assign(iColmunNum);
	data.m_aryE_soil.assign(iColmunNum);
	data.m_aryTranspiration_obs.assign(iColmunNum);

	data.m_aryCi.assign(iColmunNum);
	data.m_aryGs.assign(iColmunNum);
	data.m_aryVcmax.assign(iColmunNum);
	data.m_aryJmax.assign(iColmunNum);
	data.m_aryPhotosynthesis.assign(iColmunNum);
	data.m_aryTranspiration.assign(iColmunNum);
//	data.m_aryQstar.assign(iColmunNum);

	data.m_aryCi_window.assign(iColmunNum);
	data.m_aryGs_window.assign(iColmunNum);
	data.m_aryVcmax_window.assign(iColmunNum);
	data.m_aryJmax_window.assign(iColmunNum);
	data.m_aryPhotosynthesis_window.assign(iColmunNum);
	data.m_aryAsun_window.assign(iColmunNum);
	data.m_aryAshade_window.assign(iColmunNum);
	data.m_aryTranspiration_window.assign(iColmunNum);
	data.m_aryQstar_window.assign(iColmunNum);
	data.m_aryA_gs_window.assign(iColmunNum);
	data.m_aryA_gs_ga_window.assign(iColmunNum);
	data.m_aryA_gs_ga_ts_window.assign(iColmunNum);
	data.m_aryAv_window.assign(iColmunNum);
	data.m_aryAj_window.assign(iColmunNum);

	data.m_aryVcmax_eBL.assign(iColmunNum);
	data.m_aryVcmax25_eBL.assign(iColmunNum);
	data.m_aryCi_eBL.assign(iColmunNum);

	data.m_aryRs_toa.assign(iColmunNum);
	data.m_aryPPFD_direct.assign(iColmunNum);
	data.m_aryPPFD_diffuse.assign(iColmunNum);
	data.m_aryLAI_sun.assign(iColmunNum);
	data.m_aryLAI_shade.assign(iColmunNum);
	data.m_aryWeight_sun.assign(iColmunNum);
	data.m_aryWeight_shade.assign(iColmunNum);
	data.m_aryPPFD_sun.assign(iColmunNum);
	data.m_aryPPFD_shade.assign(iColmunNum);
	data.m_aryKb.assign(iColmunNum);
	data.m_aryKb2.assign(iColmunNum);
	data.m_aryRow_cb.assign(iColmunNum);
	data.m_aryRow_cd.assign(iColmunNum);

//	data.m_aryWeight_sun_top.assign(iColmunNum);
//	data.m_aryWeight_sun_top_day.assign(iColmunNum);

//	data.m_aryLAI_sun_day.assign(iColmunNum);
//	data.m_aryLAI_shade_day.assign(iColmunNum);
//	data.m_aryWeight_sun_day.assign(iColmunNum);
//	data.m_aryWeight_shade_day.assign(iColmunNum);
//	data.m_aryKb_day.assign(iColmunNum);

	data.m_aryF.assign(iColmunNum);
	data.m_aryRamda0.assign(iColmunNum);
}

void calculate_roughness_length_zero_plane_displacement(CData& data, CDailyData& daily)
{
	// d & z0 by
	//   Raupach (1994) Simplified expressions for vegetation roughness length and zero-plane displacement as functions of canopy height and area index, Boundary-Layer Meteorology, 71, 211-216. 
	// canopy height by
	//   Pennypacker & Baldocchi (2015) Seeing the field and forests: Application of surface-layer theory & flux-tower data to calculating vegetation canopy height, Boundary-Layer Meteorology, doi::10.1007/s10546-015-0090-0.
	const double dCd1 = 7.5;
	const double dUstarThes = 0.1;		// m s-1
	const int iLoopMax = 10;
	double dD, dZ0, dCw, dFai_h, dzL;
	vector<double> aryLAI_daily;

	for(int i = 0; i < data.m_aryDate.size(); i++){	
		data.m_aryCanopyHeight[i] = g_dCanopyHeight;
	}

	for(int iNum = 0; iNum < iLoopMax; iNum++){
		for(i = 0; i < data.m_aryDate.size(); i++){	
			if(data.m_aryLAI[i] != c_dError){
				// calculating zero-plane displacement by Eq. 8
				dD = - ( (1.0 - exp( -sqrt( dCd1 * data.m_aryLAI[i] ) ) ) / sqrt( dCd1 * data.m_aryLAI[i] ) - 1.0) * data.m_aryCanopyHeight[i];

				// calculating roughness length
				dCw = (g_dMeasurementHeight - dD) / (data.m_aryCanopyHeight[i] - dD);
				dFai_h = log(dCw) - 1.0 + pow(dCw, -1);																		// Eq. 5
				dZ0 = exp( -0.4 * 0.3 - dFai_h ) * ( 1.0 - dD / data.m_aryCanopyHeight[i] ) * data.m_aryCanopyHeight[i];	// Eq. 4

				// calculating stability
				dzL = calculate_stability(g_dMeasurementHeight - dD, data.m_aryH[i], data.m_aryUs[i], data.m_aryTa[i], data.m_aryPressure[i], data.m_aryRH[i]);

				// calculating canopy height using Eq.3 by Pennypacker & Baldocchi (2015)
				data.m_aryCanopyHeight[i] = g_dMeasurementHeight / (dD / data.m_aryCanopyHeight[i] + dZ0 / data.m_aryCanopyHeight[i] * exp(0.4 * data.m_aryU[i] / data.m_aryUs[i]) );
				if(data.m_aryU[i] == c_dError || data.m_aryUs[i] < dUstarThes || fabs(dzL) > 0.1){
					data.m_aryCanopyHeight[i] = c_dError; 
				}
			}
			else{
				data.m_aryD[i]  = c_dError;
				data.m_aryZ0[i] = c_dError;
			}
			data.m_aryD[i] = dD;
			data.m_aryZ0[i] = dZ0;
		}

		// calculate daily canopy height
		vector<double> aryCanopyHeightDaily;
		for(int iCurrent = 0; iCurrent < data.m_aryDate.size(); iCurrent++){
			if( iCurrent % g_iRunPerDay == 0){
				// iPeriod = data.m_aryPeriod[iCurrent];

				int iWindowSize = (g_iWindowSize - 1) / 2;
				int iStart = iCurrent - iWindowSize * g_iRunPerDay;
				int iEnd   = iCurrent + (iWindowSize + 1) * g_iRunPerDay;
				if(iStart < 0){
					iStart = 0;
				}
				if(iEnd > data.m_aryPeriod.size()){
					iEnd = data.m_aryPeriod.size();
				}

				int iCount_height = 0;
				double dCanopyHeight = 0.0;
				for(int iMoving = iStart; iMoving < iEnd; iMoving++){
					if(data.m_aryCanopyHeight[iMoving] != c_dError){
						iCount_height++;
						dCanopyHeight += data.m_aryCanopyHeight[iMoving];
					}
				}

				if(iCount_height != 0){
					dCanopyHeight /= iCount_height;
				}
				else{
					dCanopyHeight = c_dError;
				}
				aryCanopyHeightDaily.push_back(dCanopyHeight);

				if(iNum == iLoopMax - 1){
					daily.m_aryD.push_back(data.m_aryD[iCurrent]);
					daily.m_aryZ0.push_back(data.m_aryZ0[iCurrent]);
					daily.m_aryCanopyHeight.push_back(dCanopyHeight);
					aryLAI_daily.push_back(data.m_aryLAI[iCurrent]);
				}
			}
		}		

		if(iNum != iLoopMax - 1){
			for(i = 0; i < data.m_aryDate.size(); i++){	
				if(aryCanopyHeightDaily[i / g_iRunPerDay] != c_dError){
					data.m_aryCanopyHeight[i] = aryCanopyHeightDaily[i / g_iRunPerDay];
				}
				else{
					data.m_aryCanopyHeight[i] = g_dCanopyHeight;
				}
			}
			aryCanopyHeightDaily.clear();
		}
	}

	// calculating annual average
	double dStandDensity_daily, dLAI = 0;
	double dD_day = 0, dZ0_day = 0, dCanopyHeight = 0, dStandDensity = 0;
	int    iD = 0, iZ0 = 0, iCanopyHeight = 0, iStandDensity = 0;
	for(i = 0; i < daily.m_aryD.size(); i++){
		if(daily.m_aryD[i] != c_dError){
			dD_day += daily.m_aryD[i];
			iD++;
		}
		if(daily.m_aryZ0[i] != c_dError){
			dZ0_day += daily.m_aryZ0[i];
			iZ0++;
		}
		if(daily.m_aryCanopyHeight[i] != c_dError){
			dCanopyHeight += daily.m_aryCanopyHeight[i];
			iCanopyHeight++;
		}

		// calculating stand density
		dLAI = aryLAI_daily[i];
		dStandDensity_daily = calculate_stand_density(daily.m_aryD[i], daily.m_aryCanopyHeight[i], dLAI);
		daily.m_aryStandDensity.push_back(dStandDensity_daily);
		if(dStandDensity_daily != c_dError){
			dStandDensity += dStandDensity_daily;
			iStandDensity++;
		}
	}
	if(iD != 0){
		dD_day /= iD;
	}
	else{
		dD_day = c_dError;
	}
	daily.m_aryD.push_back(dD_day);

	if(iZ0 != 0){
		dZ0_day /= iZ0;
	}
	else{
		dZ0 = c_dError;
	}
	daily.m_aryZ0.push_back(dZ0_day);

	if(iCanopyHeight != 0){
		dCanopyHeight /= iCanopyHeight;
	}
	else{
		dCanopyHeight = c_dError;
	}
	daily.m_aryCanopyHeight.push_back(dCanopyHeight);

	if(iStandDensity != 0){
		dStandDensity /= iStandDensity;
	}
	else{
		dStandDensity = c_dError;
	}
	daily.m_aryStandDensity.push_back(dStandDensity);
}

double calculate_stand_density(const double dD, const double dCanopyHeight, const double dLAI)
{
	// Nakai T. (2008) Parameterisation of aerodynamic roughness over boreal, cool- and warm-temperate forests. Agricultural and Forest Meterology, 148, 1916-1935.
	const double dAlfa = 0.000724;
	const double dBeta = 0.273;
	const double dEPS = 10.0;		// allowable error for estimating stand density (trees ha-1)
	const int iMaxCount = 20;		// maximum for loop
	double dStandDensity;			// stand density (trees ha-1)
	double dStandDensity_old;
	double dLaiTerm;				// Eq. 16 in Nakai et al. (2008)
	int iCount = 0;
	bool bLoop = true;

	if(dD == c_dError || dCanopyHeight == c_dError || dLAI == c_dError || dD / dCanopyHeight >= 0.9){
		return c_dError;
	}	

	dLaiTerm = ( 1.0 - exp(- dBeta * dLAI) ) / dBeta / dLAI;
	dStandDensity = 1000.0;			// initializing stand density

	while(bLoop){
		iCount++;
		dStandDensity_old = dStandDensity;
		dStandDensity = dLaiTerm / dAlfa * (1.0 - exp(-dAlfa * dStandDensity_old) ) / (1.0 - dD / dCanopyHeight );

		if(iCount == iMaxCount || fabs(dStandDensity_old - dStandDensity) < dEPS ){
			bLoop = false;
		}
	}

	return dStandDensity;
}

void calculate_APAR(std::vector<double>& aryPPFD, std::vector<double>& aryPPFD_ref, std::vector<double>& aryFPAR, std::vector<double>& aryAPPFD, int iUseFPAR )
{
	// for calculating APAR; 0 : APPFD = PPFD 1 : use PPFD_ref, 2 : use FPAR
	double dAPPFD;
	for(int i = 0; i < aryPPFD.size(); i++){
		if(iUseFPAR == 0){
			dAPPFD = aryPPFD[i];
		}
		else if (iUseFPAR == 1){
			dAPPFD = aryPPFD[i] - aryPPFD_ref[i];
			if(aryPPFD_ref[i] == c_dError){
				dAPPFD = aryPPFD[i];
			}
		}
		else if (iUseFPAR == 2){
			dAPPFD = aryPPFD[i] * aryFPAR[i];
			if(aryFPAR[i] == c_dError){
				dAPPFD = aryPPFD[i];
			}
		}
		else if (iUseFPAR == 3){
			// later, APAR is updated based on radiative transfer model
			dAPPFD = aryPPFD[i];
		}

		if(dAPPFD < 0.0){
			dAPPFD = 0.0;
		}
		if(dAPPFD > aryPPFD[i]){
			dAPPFD = aryPPFD[i];
		}

		aryAPPFD[i] = dAPPFD;
	}
}

void reject_rainfall_condition(CData& data)
{
	// g_iPrecipitationFilter
	int iRain = 0;

	if(g_iPrecipitationFilter < 0) return;

	for(int i = 0; i < data.m_aryDate.size(); i++){
		if(data.m_aryRain[i] != 0){
			iRain = g_iPrecipitationFilter + 1;
		}

		if(iRain != 0){
			data.m_aryLE[i] = c_dError;
		}
		iRain--;
		if(iRain < 0) iRain = 0;
	}
}

void energy_balance_correction(CData& data, const int iCorrection)
{
	// iCorrection = 0 : no energy balance correction
	// iCorrection = 1 : imbalance corrected to H
	// iCorrection = 2 : imbalance corrected to LE
	// iCorrection = 3 : imbalance corrected to Rn - G (available energy)
	// iCorrection = 4 : imbalance corrected to H & LE with holding Bowen ratio
	const double dRn_threshold = 50.0;
	double dImbalanceRatio = 1.0;
	double dImbalance = 0.0;

	if(iCorrection == 0) return;

	for(int i = 0; i < data.m_aryDate.size(); i++){
		if(data.m_aryRn[i] == c_dError || data.m_aryG[i] == c_dError || data.m_aryH[i] == c_dError || data.m_aryLE[i] == c_dError){
			continue;
		}

		if(fabs(data.m_aryRn[i]) < dRn_threshold) continue;

		dImbalance = (data.m_aryRn[i] - data.m_aryG[i]) - ( data.m_aryH[i] + data.m_aryLE[i] );

		if(iCorrection == 1){
			// iCorrection = 1 : imbalance corrected to H
			data.m_aryH[i] += dImbalance;
		}

		if(iCorrection == 2){
			// iCorrection = 2 : imbalance corrected to LE
			data.m_aryLE[i] += dImbalance;
		}

		if(iCorrection == 3){
			// iCorrection = 3 : imbalance corrected to Rn - G (available energy)
			data.m_aryRn[i] -= dImbalance;
		}

		if(iCorrection == 4){
			// iCorrection = 4 : imbalance corrected to H & LE with holding Bowen ratio
			dImbalanceRatio = ( data.m_aryH[i] + data.m_aryLE[i] ) / (data.m_aryRn[i] - data.m_aryG[i]);
			data.m_aryH[i] /= dImbalanceRatio;
			data.m_aryLE[i] /= dImbalanceRatio;
		}
	}


}

double calculate_air_density(const double& dT, const double& dP, const double& dRH, const int& bMol)
{
	// dT	: air temperature (degree C)
	// dP   : atmospheric pressure (hPa)
	// dRH	: relative humidity (%)
	// bMol	: 0 = kg m-3, 1 = mol m-3

	// saturation vapor pressure (hPa)
	double dSVP = Goff_Gratch(dT, dP);

	// vapor pressure (hPa)
	double dVP = dSVP * dRH / 100.0;

	// air density
	double dRow = 1.293 * dP / 1013.25 / (1.0 + dT / 273.15);	// kg m-3
//	if(dRH != c_dError){
//		// dRow *= ( 1.0 - (0.378 * dVP / 1013.25) / (dP / 1013.25) );
//		dRow *= ( (dP -dVP)  / 1013.25) / (dP / 1013.25);
//	}

	if(bMol == 1){
		dRow *= 1000.0 / 28.96;
	}

	if(dT == c_dError || dP == c_dError){
		dRow = c_dError;
	}

	return dRow;
}

double calculate_stability(double dZ, double& dH, double& dUstar, double& dT, double& dP, double& dRH)
{
	// dZ		: nomalized height (z - d) (m)
	// dH		: sensible heat flux (W m-2)
	// dT		: air temperature (degree C)
	double dRow;				// air density
	double dObukhovLength;		// Obukhov Length (m)
	double dzL;					// (z-d) / L (--)

	dRow = calculate_air_density(dT, dP, dRH, 0);
	dObukhovLength = - dUstar * dUstar * dUstar * (dT + 273.15) * dRow * c_dSpecificHeat / 0.4 / 9.8 / dH;
	dzL = dZ / dObukhovLength;

	if(dUstar == c_dError || dH == c_dError || dRow == c_dError){
		dzL = c_dError;
	}

	return dzL;
}

void calculate_boundary_layer_conductance(std::vector<double>& aryUs, std::vector<double>& aryU, std::vector<double>& aryLAI, std::vector<double>& aryGb, std::vector<double>& aryGb_h )
{
	// calculating boundary layer conductance
	// aryUs : friction velocity (m s-1)
	// aryU  : horizontal wind spped (m s-1)
	// aryGb : boundary layer conductance (m s-1)

	double dK_inv;

	for(int i = 0; i < aryUs.size(); i++){
		if(aryU[i] != c_dError && aryUs[i] != c_dError && aryU[i] > c_dMinU && aryUs[i] > g_dUstarThreshold){
			aryGb[i] = aryUs[i] * aryUs[i] / aryU[i];

			calculating_kB_inverse(aryLAI[i], dK_inv);
			aryGb_h[i] = 1.0 / (1.0 / aryGb[i] + dK_inv / aryUs[i]);
		}
		else{
			aryGb[i] = c_dError;
			aryGb_h[i] = c_dError;
		}
		if(aryGb[i] > c_dMaxGb){
			aryGb[i] = c_dError;
			aryGb_h[i] = c_dError;
		}
	}

	// filling Gb using windspeed or friction velocity using linear regression
	if( g_iFilling == 1 ){
		int iStart, iEnd;
		double dSlope_u, dOffset_u, dR2_u;
		double dSlope_us, dOffset_us, dR2_us;
		vector<double> _aryUs, _aryU, _aryGb;
		
		for(int i = 0; i < aryUs.size(); i++){
			if(aryGb[i] == c_dError && (aryUs[i] != c_dError || aryU[i] != c_dError) ){
				iStart = i - g_iRunPerDay;
				iEnd = i + g_iRunPerDay;
				if(iStart < 0) iStart = 0;
				if(iEnd >= aryUs.size()) iEnd = aryUs.size() - 1;

				for(int j = iStart; j < iEnd; j++){
					if(aryGb[j] != c_dError && aryUs[j] != c_dError && aryU[j] != c_dError ){
						_aryUs.push_back(aryUs[j]);
						_aryU.push_back(aryU[j]);
						_aryGb.push_back(aryGb[j]);
					}
				}

				if(_aryUs.size() > 1){
					linear_regression(_aryGb, _aryUs, dSlope_us, dOffset_us, dR2_us);
					linear_regression(_aryGb, _aryU, dSlope_u, dOffset_u, dR2_u);

					if(aryUs[i] != c_dError && dR2_us > 0.6){
						aryGb[i] = dSlope_us * aryUs[i] + dOffset_us;
						aryGb_h[i] = 1.0 / (1.0 / aryGb[i] + dK_inv / aryUs[i] );
					}
					else if(aryU[i] != c_dError && dR2_u > 0.6){
						aryGb[i] = dSlope_u * aryU[i] + dOffset_u;
						calculating_kB_inverse(aryLAI[i], dK_inv);
						aryGb_h[i] = 1.0 / (1.0 / aryGb[i] + dK_inv / sqrt( aryGb[i] * aryU[i] ) );
					}
				}
			}
			_aryUs.clear();
			_aryU.clear();
			_aryGb.clear();
		}
	}
}

void calculating_kB_inverse(double& dLAI, double& dK_inv)
{
	// calculating B-1 (Lhomme et al., 2000; Boundary-Layer Meteorology, 97, 431-457)
	// Sensible heat flux-radiometric surface temperature relationship over sparse vegetation: parameterizing B-1
	const double dA0 = 8.9667;		// table 3 in Lhomme et al., 2000
	const double dA1 = 16.127;		// table 3 in Lhomme et al., 2000
	const double dA2 = -36.403;		// table 3 in Lhomme et al., 2000
	const double dA3 = 27.343;		// table 3 in Lhomme et al., 2000
	const double dA4 = -9.9967;		// table 3 in Lhomme et al., 2000
	const double dA5 = 1.8013;		// table 3 in Lhomme et al., 2000
	const double dA6 = -0.128;		// table 3 in Lhomme et al., 2000
	const double dMin = 1.0;

	dK_inv = dA6 * pow(dLAI, 6) + dA5 * pow(dLAI, 5) + dA4 * pow(dLAI, 4) + dA3 * pow(dLAI, 3) + dA2 * pow(dLAI, 2) + dA1 * dLAI + dA0;

	if(dK_inv < dMin || dLAI == c_dError){
		dK_inv = dMin;
	}
}

void calculate_energy_redistribution_efficiency(CData& data)
{
	// Lee et al. 2011. Observed increase in local cooling effect of deforestration at higher latitudes, Nature, 479, 384-387.
	// Bright et al. 2015. Quantifying surface albedo and other direct biogeophysical climate forcings of forestry activities, Global Change Biology, 21, 3246-3266.
	double dRamda0;						// temperature sensitivity resulting from the longwave radiation feedback (K m2 W-1)
	double dF;							// energy redistribution efficiency (dimensionless)
	double dRow;						// air density (kg m-3)
	double dLeafTemperature_K;			// leaf temperature (K)
	const double c_dEmissivity = 1.0;	// emissivity
	double dTerm;						// for quality control (dRamda0 / (1.0 + dF))
	vector<double> aryTerm;				// for quality control

	for(int i = 0; i < data.m_aryTa.size(); i++){
		// calculating air density
		dRow = calculate_air_density(data.m_aryTa[i], data.m_aryPressure[i], data.m_aryRH[i], 0);

		dLeafTemperature_K = data.m_aryTs[i] + 273.15;

		// calculating energy redistribution efficiency (dimensionless)
		if(dRow == c_dError || data.m_aryGb_h[i] == c_dError || data.m_aryTs[i] == c_dError || 
			data.m_aryLE[i] == c_dError || data.m_aryH[i] == c_dError || fabs(data.m_aryH[i]) < 5.0){
			dF = c_dError;
		}
		else{
			dF = dRow * c_dSpecificHeat / 4.0 / (1.0 / data.m_aryGb_h[i]) / c_dStefanBoltzman / pow(dLeafTemperature_K, 3);
			dF *= ( 1.0 + data.m_aryLE[i] / data.m_aryH[i] );
						
			// additional quality control
			if(fabs(dF + 1.0) < 0.2){
				dF = c_dError;
			}
		}
		data.m_aryF[i] = dF;

		// calculating temperature sensitivity resulting from the longwave radiation feedback (K m2 W-1)
		if(data.m_aryTs[i] != c_dError){
			dRamda0 = 1.0 / 4.0 / c_dEmissivity / c_dStefanBoltzman / pow(dLeafTemperature_K, 3);
		}
		else{
			dRamda0 = c_dError;
		}
		data.m_aryRamda0[i] = dRamda0;

		if(dF != c_dError){
			dTerm = dRamda0 / (1.0 + dF);
		}
		else{
			dTerm = c_dError;
		}
		aryTerm.push_back( dTerm );
	}

	// quality control of energy redistribution efficiency
	quality_control(data, aryTerm);
	for(i = 0; i < data.m_aryTa.size(); i++){
		if(aryTerm[i] == c_dError) data.m_aryF[i] = dF;
	}


}

void linear_regression(std::vector<double>& aryY, std::vector<double>& aryX, double& dSlope, double& dOffset, double& dR2)
{
	// linear regression analysis
    double Sxx = 0, Syy = 0, Sxy = 0;
	double x = 0, y = 0, Tx = 0, Txx = 0, Ty = 0, Tyy = 0, Txy = 0;
	const int iSize = aryX.size();

    for(int i = 0; i < iSize; i++)
    {
    	x = aryX[i];
		y = aryY[i];
        Tx += x;
        Txx += x * x;
        Ty += y;
		Tyy += y * y;
        Txy += x * y;
    }
	Sxx = Txx - Tx * Tx / iSize;
	Syy = Tyy - Ty * Ty / iSize;
	Sxy = Txy - Tx * Ty / iSize;

	dSlope = Sxy / Sxx;
	dOffset = Ty / iSize - Tx / iSize * dSlope;
	dR2 = Sxy * Sxy / Sxx / Syy;
}

void calculate_radiative_temperature(CData& data, int& iUseKB_inverse)
{
	// m_aryTa :	air temperature (degree C)
	// m_aryTs :	radiative temperature (degree C)
	// m_aryH  :	sensible heat flux (W m-2)
	// m_aryGb :	boundary layer conductance (m s-1)

	double dRow;	// air density (kg m-3)
	double dGb;		// boundary layer conductance (m s-1)

	for(int i = 0; i < data.m_aryTa.size(); i++){
		// dRow = 1.293 / (1.0 + 0.00367 * data.m_aryTa[i] );
		dRow = calculate_air_density(data.m_aryTa[i], data.m_aryPressure[i], data.m_aryRH[i], 0);
		if(iUseKB_inverse){
			dGb = data.m_aryGb_h[i];
		}
		else{
			dGb = data.m_aryGb[i];
		}
		data.m_aryTs[i] = (data.m_aryH[i] / c_dSpecificHeat / dRow / dGb + data.m_aryTa[i] );

		if(data.m_aryTa[i] == c_dError || data.m_aryH[i] == c_dError || dGb == c_dError || fabs(data.m_aryTs[i] - data.m_aryTa[i]) > c_dMaxDiff_Ts){
			data.m_aryTs[i] = c_dError;
			data.m_aryGb[i] = c_dError;
			data.m_aryGb_h[i] = c_dError;
		}
	}
}

void calculate_surface_conductance_Penman_Monteith(CData& data, int& iUseKB_inverse)
{
	// aryVPD : vapor pressure deficit (hPa)
	double dRc;		// surface resistance (s m-1)
	double dSlope;	// rate of change of saturation vapor pressure with temperature (hPa K-1)
	double dGamma;	// psychrometric constant (hPa K-1)
	double dRow;	// air density (kg m-3)
	double dGb;		// boundary layer conductance (m s-1)

	for(int i = 0; i < data.m_aryTa.size(); i++){
		if(g_iUseKB_inverse){
			dGb = data.m_aryGb_h[i];
		}
		else{
			dGb = data.m_aryGb[i];
		}

		if(data.m_aryTa[i]  == c_dError || data.m_aryPressure[i] == c_dError || data.m_aryH[i] == c_dError ||  data.m_aryLE[i] == c_dError || dGb == c_dError){
			data.m_aryGc[i] = c_dError;
			data.m_aryBeta[i] = c_dError;
			continue;
		}

		dSlope = calculate_rate_change_saturation_vapor_pressure(data.m_aryTa[i], data.m_aryPressure[i]);
		dGamma = calculate_psychrometric_constant(data.m_aryTa[i], data.m_aryPressure[i]);
		// dRow = 1.293 / (1.0 + 0.00367 * data.m_aryTa[i] );
		dRow = calculate_air_density(data.m_aryTa[i], data.m_aryPressure[i], data.m_aryRH[i], 0);

		dRc = (dSlope / dGamma * data.m_aryH[i] / data.m_aryLE[i] - 1.0) * (1.0 / dGb);
		dRc += dRow * c_dSpecificHeat * data.m_aryVPD[i] / dGamma / data.m_aryLE[i];
		data.m_aryGc[i] = 1.0 / dRc;

		data.m_aryBeta[i] = (1.0 / (1.0 / dGb + 1.0 / data.m_aryGc[i]) ) / dGb;

		if(data.m_aryGc[i] > c_dMaxGc){
			data.m_aryGc[i] = c_dError;
			data.m_aryBeta[i] = c_dError;
		}
		if(data.m_aryGc[i] < c_dMinGc || dGb < c_dMinGb){
			data.m_aryBeta[i] = c_dError;
		}
	}
}

void calculate_decoupling_coefficient(CData& data, int& iUseKB_inverse)
{
	// m_aryGc        : surface conductance (m s-1)
	// m_aryGb        : boundary layer conductance (m s-1)
	// m_aryTs        : leaf temperature (degree C)
	// m_aryPressure  : atmospheric pressure (hPa)
	// m_aryVPD       : vapor pressure deficit (hPa)
	double dSlope;	// rate of change of saturation vapor pressure with temperature (hPa K-1)
	double dGamma;	// psychrometric constant (hPa K-1)
	double dRow;	// air density (kg m-3)
	double dAE;		// available energy (Rn - G) (W m-2)
	double dGb;		// boundary layer conductance (m s-1)

	for(int i = 0; i < data.m_aryTa.size(); i++){
		if(g_iUseKB_inverse){
			dGb = data.m_aryGb_h[i];
		}
		else{
			dGb = data.m_aryGb[i];
		}

		if(data.m_aryTa[i]  == c_dError || data.m_aryPressure[i] == c_dError || data.m_aryVPD[i] == c_dError || data.m_aryRn[i] == c_dError || data.m_aryG[i] == c_dError || dGb == c_dError || data.m_aryGc[i] == c_dError){
			data.m_aryLE_eq[i] = c_dError;
			data.m_aryLE_imp[i] = c_dError;
			data.m_aryOmega[i] = c_dError;
			continue;
		}

		dSlope = calculate_rate_change_saturation_vapor_pressure(data.m_aryTa[i], data.m_aryPressure[i]);
		dGamma = calculate_psychrometric_constant(data.m_aryTa[i], data.m_aryPressure[i]);
		// dRow = 1.293 / (1.0 + 0.00367 * data.m_aryTa[i] );
		dRow = calculate_air_density(data.m_aryTa[i], data.m_aryPressure[i], data.m_aryRH[i], 0);
		dAE = data.m_aryRn[i] - data.m_aryG[i];

		data.m_aryLE_eq[i] = dSlope / (dSlope + dGamma) * dAE;
		data.m_aryLE_imp[i] = dRow * c_dSpecificHeat * data.m_aryVPD[i] * data.m_aryGc[i] / dGamma;
		data.m_aryOmega[i] = ( dSlope + dGamma ) / (dSlope + dGamma * (1.0 + dGb / data.m_aryGc[i]) );

		if(data.m_aryOmega[i] > 1.0 || data.m_aryOmega[i] < 0.0){
			data.m_aryOmega[i] = c_dError;
			data.m_aryLE_imp[i] = c_dError;
			data.m_aryGc[i] = c_dError;
		}
	}
}

void calculate_bare_soil_evaporation(CData& data)
{
	double dSlope;				// rate of change of saturation vapor pressure with temperature (hPa K-1)
	double dGamma;				// psychrometric constant (hPa K-1)
	double dSinceRain = 0.0;	// number of days since last rain event (day)
	double dDryness = 1.0;		// dryness factor (Thornton et al., 2002AFM) (--)
	
	double dDate;				// Day of Year
	double dPeakDay;			// DOY when maximum LAI is observed (day)
	double dS;					// plant growing stage function (Wang et al., 2014GRL)
	const double a = -0.1769;	// emprical constant in Wang et al. (2014GRL)
	const double b = -0.4427;	// emprical constant in Wang et al. (2014GRL)
	const double c = -0.6126;	// emprical constant in Wang et al. (2014GRL)

	// search day when maximum LAI is observed
	if(g_iSoilEvaporation == 13){
		double dLAI_max = - 1.0;
		for(int i = 0; i < data.m_aryTa.size(); i++){
			if(dLAI_max < data.m_aryLAI[i]){
				dLAI_max = data.m_aryLAI[i];
				dPeakDay = 1.0 + static_cast<double>(i) / g_iRunPerDay;
			}
		}
	}

	// calculate bare soil evaporation
	for(int i = 0; i < data.m_aryTa.size(); i++){
		if(g_iSoilEvaporation == 0){
			// neglecting bare soil evaporation
			data.m_aryE_soil[i] = 0.0;
		}
		if(g_iSoilEvaporation == 1 || g_iSoilEvaporation == 2){
			// calculated as potential evaporation
			dSlope = calculate_rate_change_saturation_vapor_pressure(data.m_aryTa[i], data.m_aryPressure[i]);
			dGamma = calculate_psychrometric_constant(data.m_aryTa[i], data.m_aryPressure[i]);

			data.m_aryE_soil[i] = dSlope / (dSlope + dGamma) * (data.m_aryRn_soil[i] - data.m_aryG[i]);

			if(data.m_aryTa[i] == c_dError || data.m_aryPressure[i] == c_dError || data.m_aryRn_soil[i] == c_dError || data.m_aryG[i] == c_dError ){
				data.m_aryE_soil[i] = c_dError;
			}

			// calculating soil dryness using days since last rain event (Thornton et al., 2002AFM; Biome-BGC)
			if(data.m_aryRain[i] > 0.0){
				dSinceRain = 0.0;
			}
			else{
				dSinceRain += 1.0 / g_iRunPerDay;
			}

			if(data.m_aryE_soil[i] != c_dError && g_iSoilEvaporation == 2){
				if(dSinceRain != 0.0){
					dDryness = 0.3 / pow(dSinceRain, 2.0);
				}
				else{
					dDryness = 1.0;
				}
				if(dDryness > 1.0) dDryness = 1.0;
				data.m_aryE_soil[i] *= dDryness;
			}

			if(data.m_aryE_soil[i] != c_dError && data.m_aryE_soil[i] < 0.0){
				data.m_aryE_soil[i] = 0.0;
			}
		}
		if(g_iSoilEvaporation == 3){
			// dry grassland
			// Hu et al. (2009) Partitioning of evapotranspiration and its controls in four grassland ecosystems: Application of a two-source model, Agric. For. Meterol., 149, 1410-1420
			if(data.m_aryLE[i] != c_dError && data.m_aryLAI[i] != c_dError ){
				// empirical equation based on Fig 7 in Hu et al. (2009)
				data.m_aryE_soil[i] = data.m_aryLE[i] * exp(-0.57 * data.m_aryLAI[i]);
			}
			else{
				data.m_aryE_soil[i] = c_dError;
			}

			if(data.m_aryE_soil[i] != c_dError && data.m_aryE_soil[i] < 0.0){
				data.m_aryE_soil[i] = 0.0;
			}
		}
		if(g_iSoilEvaporation == 4){
			// rice paddy
			// Sakuratani & Horie (1985) Studies on evapotranspiration from crops (1) on seasonal changes, vertical differences and the simplifed methods of estimate in evapotranspiration of paddy rice, J. Agric. Meteorol., 41, 45-55.
			if(data.m_aryLE[i] != c_dError && data.m_aryLAI[i] != c_dError ){
				data.m_aryE_soil[i] = data.m_aryLE[i] * exp(-0.40 * data.m_aryLAI[i]);
			}
			else{
				data.m_aryE_soil[i] = c_dError;
			}

			if(data.m_aryE_soil[i] != c_dError && data.m_aryE_soil[i] < 0.0){
				data.m_aryE_soil[i] = 0.0;
			}
		}

		
		if(g_iSoilEvaporation == 11 || g_iSoilEvaporation == 12 || g_iSoilEvaporation == 13){
			// Wang et al. (2014) Global synthesis of vegetation control on evapotranspiration partitioning, GLR
			if(data.m_aryLE[i] != c_dError && data.m_aryLAI[i] != c_dError ){
				if(g_iSoilEvaporation == 11) data.m_aryE_soil[i] = data.m_aryLE[i] * ( 1.0 - 0.77 * pow( data.m_aryLAI[i], 0.10 ) );	// for natural systems
				if(g_iSoilEvaporation == 12) data.m_aryE_soil[i] = data.m_aryLE[i] * ( 1.0 - 0.91 * pow( data.m_aryLAI[i], 0.07 ) );	// for agricultural systems
				if(g_iSoilEvaporation == 13){
					// for global using two vairables					
					dDate = 1.0 + static_cast<double>(i) / g_iRunPerDay;
					dS = sin( c_dPI / 2.0 * (dDate - dPeakDay) / 365.0 );
					data.m_aryE_soil[i] = data.m_aryLE[i] * exp( a * data.m_aryLAI[i] + b * dS + c) ;
				}
			}
			else{
				data.m_aryE_soil[i] = c_dError;
			}

			if(data.m_aryE_soil[i] != c_dError && data.m_aryE_soil[i] < 0.0){
				data.m_aryE_soil[i] = 0.0;
			}
		}

		if(g_iSoilEvaporation != 0 && data.m_aryLE[i] > 0.0 && data.m_aryE_soil[i] != c_dError &&  data.m_aryLE[i] < data.m_aryE_soil[i]){
			data.m_aryE_soil[i] = data.m_aryLE[i];
		}

		// update tranpiration after evapotranspiration
		if(data.m_aryLE[i] != c_dError && data.m_aryE_soil[i] != c_dError && data.m_aryTa[i] != c_dError){
			data.m_aryTranspiration_obs[i] = data.m_aryLE[i] - data.m_aryE_soil[i];
			data.m_aryLE_mg[i] = data.m_aryTranspiration_obs[i] * pow(10, 6) / calculate_latent_heat(data.m_aryTa[i]);
		}
		if(data.m_aryLE[i] != c_dError && data.m_aryE_soil[i] == c_dError && data.m_aryTa[i] != c_dError){
			data.m_aryTranspiration_obs[i] = data.m_aryLE[i];
			data.m_aryLE_mg[i] = data.m_aryTranspiration_obs[i] * pow(10, 6) / calculate_latent_heat(data.m_aryTa[i]);
		}
		if(data.m_aryLE[i] == c_dError){
			data.m_aryTranspiration_obs[i] = c_dError;
			data.m_aryLE_mg[i] = c_dError;
		}
	}
}

void calculate_effective_vpd(CData& data, int& iUseKB_inverse)
{
	// calculating effective vapor pressure deficit at leaf surface (Kelliher et al., 1976)
	// Kelliher et al., (1976), Evaporation and canopy characteristics of coniferous forests and grasslands, Oecologica 85, 153-163.
	// aryGb        : boundary layer conductance (m s-1)
	// aryTa        : air temperature (degree C)
	// aryVPD : vapor pressure deficit (hPa)
	// aryPressure  : atmospheric pressure (hPa)
	// aryLE_eq		: equilibrium evaporation rate (W m-2)
	// aryLE		: evaporation rate (W m-2)
	// aryD0        : effective VPD (hPa)
	double dSlope;			// rate of change of saturation vapor pressure with temperature (hPa K-1)
	double dRow;			// air density (kg m-3)
	double dLatentHeat;		// latent heat of water vaporization (J kg-1)
	double dGb;		// boundary layer conductance (m s-1)

	for(int i = 0; i < data.m_aryTa.size(); i++){
		if(g_iUseKB_inverse){
			dGb = data.m_aryGb_h[i];
		}
		else{
			dGb = data.m_aryGb[i];
		}

		if(data.m_aryTa[i]  == c_dError || data.m_aryPressure[i] == c_dError || dGb == c_dError || data.m_aryLE[i] == c_dError || data.m_aryLE_eq[i] == c_dError){
			data.m_aryD0[i] = c_dError;
			continue;
		}

		dLatentHeat = calculate_latent_heat(data.m_aryTa[i]);
		dSlope = calculate_rate_change_saturation_vapor_pressure(data.m_aryTa[i], data.m_aryPressure[i]);
		// dRow = 1.293 / (1.0 + 0.00367 * data.m_aryTa[i] );
		dRow = calculate_air_density(data.m_aryTa[i], data.m_aryPressure[i], data.m_aryRH[i], 0);

		data.m_aryD0[i] = (dSlope * c_dSpecificHeat / dLatentHeat  + 1.0) * data.m_aryPressure[i] / 10.0 / 0.622 / dGb / dRow;
		data.m_aryD0[i] *=(data.m_aryLE[i] - data.m_aryLE_eq[i] ) / dLatentHeat;
		data.m_aryD0[i] *= 10.0;		// (kPa) -> (hPa)
		data.m_aryD0[i] = data.m_aryVPD[i] - data.m_aryD0[i];

		if(data.m_aryD0[i] < 0.0){
			data.m_aryD0[i] = 0.0;
		}
	}
}

double calculate_rate_change_saturation_vapor_pressure(const double& dT, const double& dPressure)
{
	// dT :	air temperature (degree C)
	double dt = 0.2;     // set the temperature offset for slope calculation

    // calculate temperature offsets for slope estimate
    double dT1 = dT + dt;
    double dT2 = dT - dt;
    
    // calculate saturation vapor pressures at t1 and t2
    double dSVP1 = Goff_Gratch(dT1, dPressure);
    double dSVP2 = Goff_Gratch(dT2, dPressure);

	// calculate slope of pvs vs. T curve, at ta
    double dSlope = (dSVP1 - dSVP2) / (dT1 - dT2);

	return dSlope;
}

void calculate_vapor_pressure(std::vector<double>& aryTa, std::vector<double>& aryRH, std::vector<double>& aryVPD, std::vector<double>& aryTs, std::vector<double>& aryPressure, std::vector<double>& aryVP_air, std::vector<double>& aryVP_leaf, std::vector<double>& arySVP)
{
	// double dSVP;		// saturated vapor pressure (hPa)
	for(int i = 0; i < aryTa.size(); i++){
		arySVP[i] = Goff_Gratch(aryTa[i], aryPressure[i]);
		aryVP_air[i] = arySVP[i] * aryRH[i] / 100.0;
		aryVPD[i] = arySVP[i] - aryVP_air[i];
		if(aryVPD[i] < 0){
			aryVPD[i] = 0.0;
		}
		aryVP_leaf[i] =  Goff_Gratch(aryTs[i], aryPressure[i]);
	}
}

void apply_extended_big_leaf_model(CData& data, const double& dSaturationLightRatio, int& iUseKB_inverse)
{
	double dRd_eBL;		// leaf respiration that is determined by iterration.
	double dSaturatedLightLevel;
	double dLeafTemp;
	double dGb;			// boundary layer conductance (m s-1)

	for(int i = 0; i < data.m_aryTa.size(); i++){
		// calculating light saturation point using rectangular hyperbola
		if(i % g_iRunPerDay == 0){
			vector<double> aryGPP;
			vector<double> aryPPFD;
			int iStart = i - ((g_iWindowSize - 1) / 2 ) * g_iRunPerDay;
			int iEnd   = i + ((g_iWindowSize - 1) / 2 + 1) * g_iRunPerDay;
			if(iStart < 0) iStart = 0;
			if(iEnd > data.m_aryTa.size()) iEnd = data.m_aryTa.size();

			for(int j = iStart; j < iEnd; j++){
				aryGPP.push_back(data.m_aryGPP[j]);
				aryPPFD.push_back(data.m_aryAPPFD[j]);
			}

			dSaturatedLightLevel = get_light_saturation_point(aryGPP, aryPPFD, dSaturationLightRatio);
		}
		// printf("Extended Big leaf : %d\n", i);

		if(g_iUseKB_inverse){
			dGb = data.m_aryGb_h[i];
		}
		else{
			dGb = data.m_aryGb[i];
		}

		// filling leaf temp
		dLeafTemp = data.m_aryTs[i];
		if(dLeafTemp == c_dError){
			dLeafTemp = data.m_aryTa[i];
		}

		CLeafPhotosynthesis cPhoto_eBL(c_dError);
		dRd_eBL = 0.0;	// set initial value
		cPhoto_eBL.ExtendedBigLeaf_Vcmax(data.m_aryCO2[i], dLeafTemp, data.m_aryPressure[i], data.m_aryAPPFD[i], 
			data.m_aryGPP[i], data.m_aryLE_mg[i] / 1000.0 / 18.0, data.m_aryGc[i], dGb, dSaturatedLightLevel, dRd_eBL);

		data.m_aryVcmax_eBL[i] = cPhoto_eBL.m_dVCmax_eBL;
		data.m_aryVcmax25_eBL[i] = cPhoto_eBL.m_dVCmax25_eBL;
		data.m_aryCi_eBL[i] = cPhoto_eBL.m_dCi_eBL;
	}
}

double get_light_saturation_point(std::vector<double>& aryGPP, std::vector<double>& aryPPFD, double dSaturationLightRatio)
{
	double dRMSE = 0.0, dRMSE_min = -c_dError;
	double dPmax = 0.0, dB = 0.01, dRd = 0.0, dSimPhoto;
	double dPmax_final = 0.0, dB_final = 0.01;
	int iDiv = 100;

	// get maximum values and step for optimization
	double dGPP_max = c_dError;
	double dPPFD_max = c_dError;
	for(int i = 0; i < aryGPP.size(); i++){
		if(aryGPP[i] != c_dError && dGPP_max < aryGPP[i]){
			dGPP_max = aryGPP[i];
		}
		if(aryPPFD[i] != c_dError && dPPFD_max < aryPPFD[i]){
			dPPFD_max = aryPPFD[i];
		}
	}
	double dPmax_step = dGPP_max / iDiv;
	double dB_step = dGPP_max / (dPPFD_max / 20.0) / iDiv;

	// determin light-photosynthesis curve
	for(int iP = 0; iP < iDiv; iP++){
		dPmax = iP * dPmax_step;
		for(int iB = 0.000000001; iB < iDiv; iB++){
			dB = iB * dB_step;

			dRMSE = 0.0;
			for(i = 0; i < aryGPP.size(); i++){
				if(aryGPP[i] == c_dError || aryPPFD[i] == c_dError){
					continue;
				}

				dSimPhoto = (dPmax * aryPPFD[i]) / (aryPPFD[i] + dPmax / dB) - dRd;
				dRMSE += pow(aryGPP[i] - dSimPhoto, 2);
			}

			if(dRMSE_min > dRMSE){
				dRMSE_min = dRMSE;
				dPmax_final = dPmax;
				dB_final = dB;
			}
			
		}
	}

	// estimating light-saturation point
	for(i = 0; i < int(dPPFD_max); i++){
		dSimPhoto = (dPmax_final * i) / (i + dPmax_final / dB_final) - dRd;
		if(dSimPhoto > dPmax_final * dSaturationLightRatio){
			break;
		}
	}

	// printf("%lf, %lf, %lf\n", dPmax_final, dB_final, double(i));

	return double(i);
}

double Goff_Gratch(const double& dT_degreeC, const double& dPressure)
{
	// calculate saturation water vapor given temperature using Goff-Gratch
	// dT        : temperature (degree C)
	// dPressure : atmospheric pressure (hPa)
	double dT;				// temperature (K)
	double dQsat;			// saturation water vapor (hPa)
	double vL;
	double T1 = 273.16;		//　triple point temperature of water (K)

	dT = dT_degreeC + 273.15;

	// https://www.metsoc.jp/tenki/pdf/1988/1988_02_0115.pdf
	vL = 10.79574 * (1.0 - T1 / dT) - 5.028 * log10(dT / T1);
	vL = vL + 1.50475 * pow(10,-4) * (1.0 - pow(10, -8.2969 * (dT / T1 - 1.0)));
	vL = vL + 0.42873 * pow(10,-3) * (pow(10, 4.76955 * (1.0 - T1 / dT)) - 1.0) + 0.78614;

	if(dT_degreeC < 0.0){
		vL = -9.09685 * (T1 / dT - 1.0) - 3.56654 * log10(T1 / dT);
		vL = vL + 0.87682 * (1.0 - dT / T1) + 0.78614;
	}

	// dQsat = 622.0 / dPressure * pow(10, vL);
	dQsat = pow(10, vL);

	return dQsat;
}

double calculate_latent_heat(const double& dT)
{
	// dT :	air temperature (degree C)
	double dLatentHeat;	// latent heat of water vaporization (J kg-1)

	if(dT > 0){
		dLatentHeat = 2.50025 * pow(10, 6) - 2365.0 * dT;
	}
	else{
		dLatentHeat = 2.8341  * pow(10, 6) - 149.0 * dT;
	}
	return dLatentHeat;
}

double calculate_psychrometric_constant(const double& dT, const double& dPressure)
{
	// http://en.wikipedia.org/wiki/Psychrometric_constant
	// dT        :	air temperature (degree C)
	// dPressure :	atmospheric pressure (hPa)
	const double cdMolecularWeight = 0.622;				// ratio molecular weight of water vapor/dry air = 0.622.
	double dLatentHeat = calculate_latent_heat(dT);		// latent heat of water vaporization (J kg-1)
	double dPsychrometricConstant;						// psychrometric constant (hPa K-1)

	dPsychrometricConstant = c_dSpecificHeat * dPressure / dLatentHeat / cdMolecularWeight;

	return dPsychrometricConstant;
}

void calculate_photosynthetic_variables(CData& data, std::vector< std::vector<double> >& aryBestParameterSet, std::vector<double>& aryBestFunction, double& dRMSE_GPP, double& dRMSE_LE, int& iUseKB_inverse)
{
	double dVcmax25, dJmax25;
	double dLeafTemp, dUpscalingFactor;
	double dBBm;
	double dBBb;
	double dD0 = c_dError;
	double dGb;			// boundary layer conductance (m s-1)
	double dSumPhoto = 0.0, dSumLE = 0.0;
	int iNumPhoto = 0, iNumLE = 0;

	double dMinimumFunction = -c_dError;
	int iBestIndex = 0;
	int iSize = aryBestFunction.size();
	for(int i = 0; i < iSize; i++){
		if(dMinimumFunction > aryBestFunction[i] ){
			iBestIndex = i;
		}
	}

	dVcmax25 = aryBestParameterSet[iBestIndex][0];
	dJmax25 = aryBestParameterSet[iBestIndex][1];
	dBBm = aryBestParameterSet[iBestIndex][2];
	dBBb = aryBestParameterSet[iBestIndex][3];
	if(aryBestParameterSet[iBestIndex].size() == 5 && g_iLeuningModel == 1){
		dD0 = aryBestParameterSet[iBestIndex][4];
	}

	for(i = 0; i < data.m_aryCO2.size(); i++){
		
		if(iUseKB_inverse){
			dGb = data.m_aryGb_h[i];
		}
		else{
			dGb = data.m_aryGb[i];
		}

		// filling leaf temp
		dLeafTemp = data.m_aryTs[i];
		if(dLeafTemp == c_dError && g_iFilling == 1){
			dLeafTemp = data.m_aryTa[i];
		}

		// calculating upscaling factor
		// dUpscalingFactor = data.m_aryLAI[i] * (data.m_aryWeight_sun[i] + data.m_aryWeight_shade[i]);
		dUpscalingFactor = data.m_aryLAI[i] * (1.0 - exp(- g_dKn)) / g_dKn;  // Ryu et al., (2011: GBC)

		if(data.m_aryCO2[i] == c_dError || data.m_aryAPPFD[i] == c_dError || dLeafTemp == c_dError ||
			data.m_aryVP_air[i] == c_dError || data.m_aryVP_leaf[i] == c_dError || data.m_aryPressure[i] == c_dError ||
			data.m_aryGc[i] == c_dError || dGb == c_dError){
			
			data.m_aryCi[i] = c_dError;
			data.m_aryGs[i] = c_dError;
			data.m_aryVcmax[i] = c_dError;
			data.m_aryJmax[i] = c_dError;
			data.m_aryPhotosynthesis[i] = c_dError;
			data.m_aryTranspiration[i] = c_dError;
//			data.m_aryQstar[i] = c_dError;
		}
		else{
			CLeafPhotosynthesis cPhoto(c_dError);
			cPhoto.SetParameter(dVcmax25, dVcmax25 * dJmax25, dBBm, dBBb, dD0);
			if(g_iCanopyStructure == 0){
				cPhoto.Farquhar_BigLeaf(data.m_aryCO2[i], data.m_aryAPPFD[i], data.m_aryTa[i], dLeafTemp, data.m_aryD0[i], 
					data.m_aryVP_air[i], data.m_aryVP_leaf[i], data.m_aryPressure[i], data.m_aryGc[i], dGb, data.m_aryTg[i], dUpscalingFactor,
					data.m_aryLAI_sun[i] + data.m_aryLAI_shade[i], data.m_aryPPFD_direct[i], data.m_aryPPFD_diffuse[i], data.m_aryKb[i], data.m_aryKb2[i], data.m_aryRow_cb[i], data.m_aryRow_cd[i]);
			}
			else if(g_iCanopyStructure == 1){
				cPhoto.Farquhar_BigLeaf_two_leaf(data.m_aryCO2[i], data.m_aryAPPFD[i], data.m_aryTa[i], dLeafTemp, data.m_aryD0[i], 
					data.m_aryVP_air[i], data.m_aryVP_leaf[i], data.m_aryPressure[i], data.m_aryGc[i], dGb, data.m_aryTg[i], dUpscalingFactor,
					data.m_aryPPFD_sun[i], data.m_aryPPFD_shade[i], data.m_aryWeight_sun[i], data.m_aryWeight_shade[i], data.m_aryLAI_sun[i] + data.m_aryLAI_shade[i],
					data.m_aryPPFD_direct[i], data.m_aryPPFD_diffuse[i], data.m_aryKb2[i], data.m_aryRow_cb[i], data.m_aryRow_cd[i]);
			}
			else{
				cPhoto.Farquhar_BigLeaf_multi_layer(data.m_aryCO2[i], data.m_aryAPPFD[i], data.m_aryTa[i], dLeafTemp, data.m_aryD0[i], 
					data.m_aryVP_air[i], data.m_aryVP_leaf[i], data.m_aryPressure[i], data.m_aryGc[i], dGb, data.m_aryTg[i], dUpscalingFactor,
					data.m_aryLAI_sun[i], data.m_aryLAI_shade[i], data.m_aryPPFD_direct[i], data.m_aryPPFD_diffuse[i], 
					data.m_aryPPFD_sun[i], data.m_aryPPFD_shade[i], data.m_aryKb[i], data.m_aryKb2[i], data.m_aryRow_cb[i], data.m_aryRow_cd[i]);
			}

			data.m_aryCi[i] = cPhoto.m_dCi;
			data.m_aryGs[i] = cPhoto.m_dGsc;
			data.m_aryVcmax[i] = cPhoto.m_dVCmax;
			data.m_aryJmax[i] = cPhoto.m_dJmax;
//			data.m_aryQstar[i] = cPhoto.m_dQstar;
			if(cPhoto.m_dAn > -fabs(cPhoto.m_dRd)  && cPhoto.m_dCi < data.m_aryCO2[i] * 1.5 ){
				data.m_aryPhotosynthesis[i] = cPhoto.m_dAn;	
				if(data.m_aryGPP[i] != c_dError){
					dSumPhoto += (cPhoto.m_dAn - data.m_aryGPP[i]) * (cPhoto.m_dAn - data.m_aryGPP[i]);
					iNumPhoto++;
				}
			}
			else{
				data.m_aryPhotosynthesis[i] = c_dError;	
				data.m_aryCi[i] = c_dError;	
			}
			if(cPhoto.m_dTranspiration > c_dError / 10.0){
				data.m_aryTranspiration[i] = cPhoto.m_dTranspiration;
				if(data.m_aryLE[i] != c_dError){
					dSumLE += (data.m_aryTranspiration[i] - data.m_aryLE_mg[i]) * (data.m_aryTranspiration[i] - data.m_aryLE_mg[i]) * calculate_latent_heat(data.m_aryTa[i]) / pow(10, 6) * calculate_latent_heat(data.m_aryTa[i]) / pow(10, 6);
					iNumLE++;
				}
			}
			else{
				data.m_aryTranspiration[i] = c_dError;
			}

		}
	}

	// calculating RMSE
	if(iNumPhoto != 0){
		dRMSE_GPP = sqrt(dSumPhoto / iNumPhoto);
	}
	else{
		dRMSE_GPP = c_dError;
	}
	if(iNumLE != 0){
		dRMSE_LE  = sqrt(dSumLE / iNumLE);
	}
	else{
		dRMSE_LE = c_dError;
	}
}

void calculate_photosynthetic_variables_window(CData& data, std::vector< std::vector<double> >& aryBestParameterSet, std::vector< std::vector<double> >& aryRMSE, int& iUseKB_inverse)
{
	double dVcmax25, dJmax25, dOmega;
	double dLeafTemp, dUpscalingFactor;
	double dBBm;
	double dBBb;
	double dD0 = c_dError;
	int iDOY = -1;
	double dGb;			// boundary layer conductance (m s-1)

	for(int i = 0; i < data.m_aryCO2.size(); i++){
		if(i % g_iRunPerDay == 0){
			iDOY++;
			dVcmax25 = aryBestParameterSet[iDOY][0];
			dJmax25 = aryBestParameterSet[iDOY][1];
			dOmega = aryBestParameterSet[iDOY][2];
			dBBm = aryBestParameterSet[iDOY][3];
			dBBb = aryBestParameterSet[iDOY][4];
			if(aryBestParameterSet[iDOY].size() == 6 && g_iLeuningModel == 1){
				dD0 = aryBestParameterSet[iDOY][5];
			}
		}
		
		if(iUseKB_inverse){
			dGb = data.m_aryGb_h[i];
		}
		else{
			dGb = data.m_aryGb[i];
		}

		// filling leaf temp
		dLeafTemp = data.m_aryTs[i];
		if(dLeafTemp == c_dError && g_iFilling == 1){
			dLeafTemp = data.m_aryTa[i];
		}

		// calculating upscaling factor
		// dUpscalingFactor = data.m_aryLAI[i] * (data.m_aryWeight_sun[i] + data.m_aryWeight_shade[i]);
		dUpscalingFactor = data.m_aryLAI[i] * (1.0 - exp(- g_dKn)) / g_dKn;  // Ryu et al., (2011: GBC)

		if(data.m_aryCO2[i] == c_dError || data.m_aryAPPFD[i] == c_dError || dLeafTemp == c_dError ||
			data.m_aryVP_air[i] == c_dError || data.m_aryVP_leaf[i] == c_dError || data.m_aryPressure[i] == c_dError ||
			data.m_aryGc[i] == c_dError || dGb == c_dError || 
			dVcmax25 == c_dError || dJmax25 == c_dError ||  dBBm == c_dError || dBBb == c_dError ){
			
			data.m_aryCi_window[i] = c_dError;
			data.m_aryAsun_window[i] = c_dError;
			data.m_aryAshade_window[i] = c_dError;
			data.m_aryGs_window[i] = c_dError;
			data.m_aryVcmax_window[i] = c_dError;
			data.m_aryJmax_window[i] = c_dError;
			data.m_aryPhotosynthesis_window[i] = c_dError;
			data.m_aryTranspiration_window[i] = c_dError;
			data.m_aryQstar_window[i] = c_dError;
			data.m_aryA_gs_window[i] = c_dError;
			data.m_aryA_gs_ga_window[i] = c_dError;
			data.m_aryA_gs_ga_ts_window[i] = c_dError;
			data.m_aryAv_window[i] = c_dError;
			data.m_aryAj_window[i] = c_dError;
		}
		else{
			CLeafPhotosynthesis cPhoto(c_dError);
			cPhoto.SetParameter(dVcmax25, dVcmax25 * dJmax25, dOmega, dBBm, dBBb, dD0);

			if(g_iForwarmdMode <= 1){
				if(g_iCanopyStructure == 0){
					cPhoto.Farquhar_BigLeaf(data.m_aryCO2[i], data.m_aryAPPFD[i], data.m_aryTa[i], dLeafTemp, data.m_aryD0[i], 
						data.m_aryVP_air[i], data.m_aryVP_leaf[i], data.m_aryPressure[i], data.m_aryGc[i], dGb, data.m_aryTg[i], dUpscalingFactor,
						data.m_aryLAI_sun[i] + data.m_aryLAI_shade[i], data.m_aryPPFD_direct[i], data.m_aryPPFD_diffuse[i], data.m_aryKb[i], data.m_aryKb2[i], data.m_aryRow_cb[i], data.m_aryRow_cd[i]);
				}
				else if(g_iCanopyStructure == 1){
					cPhoto.Farquhar_BigLeaf_two_leaf(data.m_aryCO2[i], data.m_aryAPPFD[i], data.m_aryTa[i], dLeafTemp, data.m_aryD0[i], 
						data.m_aryVP_air[i], data.m_aryVP_leaf[i], data.m_aryPressure[i], data.m_aryGc[i], dGb, data.m_aryTg[i], dUpscalingFactor,
						// data.m_aryPPFD_sun[i], data.m_aryPPFD_shade[i], data.m_aryWeight_sun_day[i], data.m_aryWeight_shade_day[i]);
						data.m_aryPPFD_sun[i], data.m_aryPPFD_shade[i], data.m_aryWeight_sun[i], data.m_aryKb[i], data.m_aryLAI_sun[i] + data.m_aryLAI_shade[i],
						data.m_aryPPFD_direct[i], data.m_aryPPFD_diffuse[i], data.m_aryKb2[i], data.m_aryRow_cb[i], data.m_aryRow_cd[i]);
				}
				else{
					cPhoto.Farquhar_BigLeaf_multi_layer(data.m_aryCO2[i], data.m_aryAPPFD[i], data.m_aryTa[i], dLeafTemp, data.m_aryD0[i], 
						data.m_aryVP_air[i], data.m_aryVP_leaf[i], data.m_aryPressure[i], data.m_aryGc[i], dGb, data.m_aryTg[i], dUpscalingFactor,
						data.m_aryLAI_sun[i], data.m_aryLAI_shade[i], data.m_aryPPFD_direct[i], data.m_aryPPFD_diffuse[i], 
						data.m_aryPPFD_sun[i], data.m_aryPPFD_shade[i], data.m_aryKb[i], data.m_aryKb2[i], data.m_aryRow_cb[i], data.m_aryRow_cd[i]);
				}
			}
			else{
				double ddd = data.m_aryTs[i];
				double dRamda = calculate_latent_heat(data.m_aryTa[i]);
				cPhoto.Farquhar_BigLeaf_coupled_EB(data.m_aryCO2[i], data.m_aryAPPFD[i], data.m_aryTa[i], dLeafTemp, data.m_aryD0[i], 
					data.m_aryVP_air[i], data.m_aryVP_leaf[i], data.m_aryPressure[i], data.m_aryGc[i], dGb,
					data.m_aryH[i], data.m_aryLE[i], data.m_aryG[i], data.m_aryTa[i], data.m_aryTg[i], dRamda, dUpscalingFactor,
					data.m_aryLAI_sun[i] + data.m_aryLAI_shade[i], data.m_aryPPFD_direct[i], data.m_aryPPFD_diffuse[i], data.m_aryKb[i], data.m_aryKb2[i], data.m_aryRow_cb[i], data.m_aryRow_cd[i]);
				data.m_aryTs[i] = dLeafTemp;
			}

			data.m_aryCi_window[i] = cPhoto.m_dCi;
			data.m_aryAsun_window[i] = cPhoto.m_dAn_sun;
			data.m_aryAshade_window[i] = cPhoto.m_dAn_shade;
			data.m_aryGs_window[i] = cPhoto.m_dGsc;
			data.m_aryVcmax_window[i] = cPhoto.m_dVCmax;
			data.m_aryJmax_window[i] = cPhoto.m_dJmax;
			data.m_aryQstar_window[i] = cPhoto.m_dQstar;
			data.m_aryAv_window[i] = cPhoto.m_dAv;
			data.m_aryAj_window[i] = cPhoto.m_dAj;
			if(cPhoto.m_dAn > -fabs(cPhoto.m_dRd) && cPhoto.m_dCi < data.m_aryCO2[i] * 1.5){
				data.m_aryPhotosynthesis_window[i] = cPhoto.m_dAn;
				data.m_aryA_gs_window[i] = cPhoto.m_dA_gs;
				data.m_aryA_gs_ga_window[i] = cPhoto.m_dA_gs_ga;
				data.m_aryA_gs_ga_ts_window[i] = cPhoto.m_dA_gs_ga_ts;
			}
			else{
				data.m_aryPhotosynthesis_window[i] = c_dError;
				data.m_aryA_gs_window[i] = c_dError;
				data.m_aryA_gs_ga_window[i] = c_dError;
				data.m_aryA_gs_ga_ts_window[i] = c_dError;
				data.m_aryCi_window[i] = c_dError;
			}
			if(cPhoto.m_dTranspiration != c_dError){
				data.m_aryTranspiration_window[i] = cPhoto.m_dTranspiration * calculate_latent_heat(data.m_aryTa[i]) / pow(10, 6);	// W m-2
			}
			else{
				data.m_aryTranspiration_window[i] = c_dError;
			}
		}
	}
}

void get_annual_paramters(std::vector< std::vector<double> >& aryBestParameterSet, std::vector<double>& aryBestFunction, std::vector<double>& aryAnnualBestPrm, std::vector<double>& aryAnnualBestPrmStdev)
{
	int iBestIndex = 0;
	double dMinimumFunction = -c_dError;
	double dXX_vc = 0.0, dX_vc = 0.0, dXX_j = 0.0, dX_j = 0.0, dXX_m = 0.0, dX_m = 0.0, dXX_b = 0.0, dX_b = 0.0, dXX_d0 = 0.0, dX_d0 = 0.0;
	double dStdev_vc, dStdev_j, dStdev_m, dStdev_b, dStdev_d0 = c_dError;
	
	int iSize = aryBestFunction.size();
	for(int i = 0; i < iSize; i++){
		if(dMinimumFunction > aryBestFunction[i] ){
			iBestIndex = i;
		}
		dXX_vc += aryBestParameterSet[i][0] * aryBestParameterSet[i][0];
		dX_vc  += aryBestParameterSet[i][0];
		dXX_j += aryBestParameterSet[i][1] * aryBestParameterSet[i][1];
		dX_j  += aryBestParameterSet[i][1];
		dXX_m += aryBestParameterSet[i][2] * aryBestParameterSet[i][2];
		dX_m  += aryBestParameterSet[i][2];
		dXX_b += aryBestParameterSet[i][3] * aryBestParameterSet[i][3];
		dX_b  += aryBestParameterSet[i][3];
		if(g_iLeuningModel == 1 && aryBestParameterSet[i].size() >= 5){
			dXX_d0 += aryBestParameterSet[i][4] * aryBestParameterSet[i][4];
			dX_d0  += aryBestParameterSet[i][4];
		}
	}

	aryAnnualBestPrm.push_back(aryBestParameterSet[iBestIndex][0]);
	aryAnnualBestPrm.push_back(aryBestParameterSet[iBestIndex][1]);
	aryAnnualBestPrm.push_back(aryBestParameterSet[iBestIndex][2]);
	aryAnnualBestPrm.push_back(aryBestParameterSet[iBestIndex][3]);
	if(g_iLeuningModel == 1 && aryBestParameterSet[iBestIndex].size() >= 5){
		aryAnnualBestPrm.push_back(aryBestParameterSet[iBestIndex][4]);
	}
	
	if(iSize != 1){
		dStdev_vc = sqrt((dXX_vc - dX_vc * dX_vc / iSize) / iSize);
		dStdev_j = sqrt((dXX_j - dX_j * dX_j / iSize) / iSize);
		dStdev_m = sqrt((dXX_m - dX_m * dX_m / iSize) / iSize);
		dStdev_b = sqrt((dXX_b - dX_b * dX_b / iSize) / iSize);
		if(g_iLeuningModel == 1){
			dStdev_d0 = sqrt((dXX_d0 - dX_d0 * dX_d0 / iSize) / iSize);
		}
	}
	else{
		dStdev_vc = c_dError;
		dStdev_j = c_dError;
		dStdev_m = c_dError;
		dStdev_b = c_dError;
		dStdev_d0 = c_dError;
	}
	aryAnnualBestPrmStdev.push_back(dStdev_vc);
	aryAnnualBestPrmStdev.push_back(dStdev_j);
	aryAnnualBestPrmStdev.push_back(dStdev_m);
	aryAnnualBestPrmStdev.push_back(dStdev_b);
	aryAnnualBestPrmStdev.push_back(dStdev_d0);
}

// ****************************************************************
//  Optimization of phtosynthesis model by SCE-UA
// ****************************************************************
void optimize_photosynthesis_stomatal_conductance_model(CSCE_UA& cSCE_UA, model_input& cModel, CData& data, vector< vector<double> >& aryBestParameterSet, vector<double>& aryBestFunction, int nrun)
{
	int i, iseed;
	if(nrun <= 0) return;

	aryBestParameterSet.assign(2);
	aryBestFunction.assign(2);

	// create random number seeds
	bool iUseTime = true;
	cSCE_UA.create_random_seed_defualt(nrun, iUseTime);

	vector<double> aryGPP_qc;
	for(i = 0; i < data.m_aryGPP.size(); i++){
		if(data.m_aryPhotosynthesis_window[i] != c_dError){
			aryGPP_qc.push_back(data.m_aryGPP[i]);
		}
		else{
			aryGPP_qc.push_back(c_dError);
		}
	}

	cModel.m_aryInputData.clear();
	cModel.m_aryObsData.clear();
	cModel.m_aryDate.clear();

	// set input data to class
//	cModel.m_aryObsData.push_back(data.m_aryGPP);
	cModel.m_aryObsData.push_back(aryGPP_qc);
	cModel.m_aryObsData.push_back(data.m_aryLE_mg);

	cModel.m_aryInputData.push_back(data.m_aryCO2);
	cModel.m_aryInputData.push_back(data.m_aryAPPFD);
	cModel.m_aryInputData.push_back(data.m_aryTa);
	cModel.m_aryInputData.push_back(data.m_aryTs);
	cModel.m_aryInputData.push_back(data.m_aryD0);
	// cModel.m_aryInputData.push_back(data.m_aryVPD);
	cModel.m_aryInputData.push_back(data.m_aryVP_air);
	cModel.m_aryInputData.push_back(data.m_aryVP_leaf);
	cModel.m_aryInputData.push_back(data.m_aryPressure);
	cModel.m_aryInputData.push_back(data.m_aryGc);

	if(g_iUseKB_inverse){
		cModel.m_aryInputData.push_back(data.m_aryGb);
	}
	else{
		cModel.m_aryInputData.push_back(data.m_aryGb_h);
	}
	cModel.m_aryInputData.push_back(data.m_aryTg);

	vector<double> aryUpscalingFactor;
	for(i = 0; i < data.m_aryLAI.size(); i++){		
		// aryUpscalingFactor.push_back( data.m_aryLAI[i] * (data.m_aryWeight_sun[i] + data.m_aryWeight_shade[i]) );
		aryUpscalingFactor.push_back( data.m_aryLAI[i] *  (1.0 - exp(- g_dKn)) / g_dKn);  // Ryu et al., (2011: GBC)
	}
	cModel.m_aryInputData.push_back(aryUpscalingFactor);

	cModel.m_aryInputData.push_back(data.m_aryPPFD_sun);
	cModel.m_aryInputData.push_back(data.m_aryPPFD_shade);
	cModel.m_aryInputData.push_back(data.m_aryLAI_sun);
	cModel.m_aryInputData.push_back(data.m_aryLAI_shade);
	cModel.m_aryInputData.push_back(data.m_aryWeight_sun);
	cModel.m_aryInputData.push_back(data.m_aryWeight_shade);

	cModel.m_aryInputData.push_back(data.m_aryGPP);

	cModel.m_aryInputData.push_back(data.m_aryPPFD_direct);
	cModel.m_aryInputData.push_back(data.m_aryPPFD_diffuse);
	cModel.m_aryInputData.push_back(data.m_aryKb);
	cModel.m_aryInputData.push_back(data.m_aryKb2);
	cModel.m_aryInputData.push_back(data.m_aryRow_cb);
	cModel.m_aryInputData.push_back(data.m_aryRow_cd);

	cModel.m_aryDate = data.m_aryDate;
	cSCE_UA.m_iRecordNum = cModel.m_aryDate.size();

	// set input data for model simulation
	if(sce_setting_input(cSCE_UA, cModel) == false){
		printf("error in sce_setting_input.\n");
		return;
	}
			
	int iBestIndex = 0;
	double dStdev_vc = c_dError, dStdev_j = c_dError, dStdev_omega = c_dError, dStdev_m = c_dError, dStdev_b = c_dError, dStdev_d0 = c_dError;

	// sequential optimization transpiration after optimizing GPP
	if(g_iSequentialOpt == 1){
		cSCE_UA.m_iOptimizedPrm = 0;
		
		// ****************************************************************
		// optimize m, b and D0 
		// ****************************************************************
		cSCE_UA.m_iOptimizedPrm = 1;

		// clear old best parameters
		aryBestParameterSet.clear();
		aryBestFunction.clear();
		
		set_parameter_range(cSCE_UA, 3, cSCE_UA.m_aryIniPrm[3], cSCE_UA.m_aryLowPrmDefault[3], cSCE_UA.m_aryHighPrmDefault[3]); // m
		set_parameter_range(cSCE_UA, 4, cSCE_UA.m_aryIniPrm[4], cSCE_UA.m_aryLowPrmDefault[4], cSCE_UA.m_aryHighPrmDefault[4]); // b
		if(g_iLeuningModel == 1 && cSCE_UA.m_aryBestPrm.size() == 6){
			set_parameter_range(cSCE_UA, 5, cSCE_UA.m_aryIniPrm[5], cSCE_UA.m_aryLowPrmDefault[5], cSCE_UA.m_aryHighPrmDefault[5]); // b
		}

		for(i = 0; i < nrun; i++){
			iseed = cSCE_UA.m_jseed[i];
			cSCE_UA.sceua(cModel, g_strOutFile, i, stomatal_model);
			aryBestParameterSet.push_back(cSCE_UA.m_aryBestPrm);
			aryBestFunction.push_back(cSCE_UA.m_dBestFunc);
		}

		// search best parameters and calculating stdev of parmaters
		search_best_stdev(aryBestParameterSet, aryBestFunction, 3, iBestIndex, dStdev_m);
		search_best_stdev(aryBestParameterSet, aryBestFunction, 4, iBestIndex, dStdev_b);
		if(g_iLeuningModel == 1 && cSCE_UA.m_aryBestPrm.size() == 6){	
			search_best_stdev(aryBestParameterSet, aryBestFunction, 5, iBestIndex, dStdev_d0);
		}

		// ****************************************************************
		// re-optimize Vcmax and Jmax using optimized m and b
		// ****************************************************************
		cSCE_UA.m_iOptimizedPrm = 0;
		set_parameter_range(cSCE_UA, 0, cSCE_UA.m_aryIniPrm[0], cSCE_UA.m_aryLowPrmDefault[0], cSCE_UA.m_aryHighPrmDefault[0]); // vcmax
		set_parameter_range(cSCE_UA, 1, cSCE_UA.m_aryIniPrm[1], cSCE_UA.m_aryLowPrmDefault[1], cSCE_UA.m_aryHighPrmDefault[1]); // Jmax
		if(g_iOmegaOptimization){
			// set_parameter_range(cSCE_UA, 2, cSCE_UA.m_aryIniPrm[2], cSCE_UA.m_aryLowPrmDefault[2], cSCE_UA.m_aryHighPrmDefault[2]); // Omega
			double dStedev = 0.06;
			set_parameter_range(cSCE_UA, 2, g_dOmega, dStedev); // Omega
		}
		else{
			double dStedev = 0.001;
			set_parameter_range(cSCE_UA, 2, g_dOmega, dStedev); // Omega
		}
		set_parameter_range(cSCE_UA, 3, aryBestParameterSet[iBestIndex][3], dStdev_m); // m
		set_parameter_range(cSCE_UA, 4, aryBestParameterSet[iBestIndex][4], dStdev_b); // b
		if(g_iLeuningModel == 1 && cSCE_UA.m_aryBestPrm.size() == 6){
			set_parameter_range(cSCE_UA, 5, aryBestParameterSet[iBestIndex][5], dStdev_d0); // D0
		}

		aryBestParameterSet.clear();			// clear old best parameters
		aryBestFunction.clear();				// clear old best parameters

		for(i = 0; i < nrun; i++){				// SCE-UA optimization again
			iseed = cSCE_UA.m_jseed[i];
			cSCE_UA.sceua(cModel, g_strOutFile, i, photosynthesis_model);
			aryBestParameterSet.push_back(cSCE_UA.m_aryBestPrm);
			aryBestFunction.push_back(cSCE_UA.m_dBestFunc);
		}

		search_best_stdev(aryBestParameterSet, aryBestFunction, 0, iBestIndex, dStdev_vc);
		search_best_stdev(aryBestParameterSet, aryBestFunction, 1, iBestIndex, dStdev_j);
		search_best_stdev(aryBestParameterSet, aryBestFunction, 2, iBestIndex, dStdev_omega);

		// ****************************************************************

		cSCE_UA.m_iOptimizedPrm = 0;
	}	

	cModel.m_aryInputData.clear();
	cModel.m_aryObsData.clear();
	cModel.m_aryDate.clear();
}

void optimize_photosynthesis_stomatal_conductance_model_window(CSCE_UA& cSCE_UA, model_input& cModel, CData& data, vector< vector<double> >& aryBestParameterSet, vector< vector<double> >& aryStdevParameterSet, vector< vector<double> >& aryRMSE, int nrun)
{
	if(nrun <= 0) return;

	
	int iOptDay = 0;
	int iPeriod = 0;

	int iWindowSize = g_iWindowSize * g_iRunPerDay;

	// create random number seeds
	bool iUseTime = true;
	cSCE_UA.create_random_seed_defualt(nrun, iUseTime);
	
	// set input data for model simulation
	if(sce_setting_input(cSCE_UA, cModel) == false){
		printf("error in sce_setting_input.\n");
		return;
	}

	vector<double> aryCO2;
	vector<double> aryPPFD;
	vector<double> aryTa;
	vector<double> aryTs;
	vector<double> aryVPD;
	vector<double> aryVP_air;
	vector<double> aryVP_leaf;
	vector<double> aryPressure;
	vector<double> aryGc;
	vector<double> aryGb;
	vector<double> aryTg;
	vector<double> aryUpscalingFactor;

	vector<double> aryPPFD_sun;
	vector<double> aryPPFD_shade;
	vector<double> aryLAI_sun;
	vector<double> aryLAI_shade;
	vector<double> aryWeight_sun;
	vector<double> aryWeight_shade;

	vector<double> aryPPFD_direct;
	vector<double> aryPPFD_diffuse;
	vector<double> aryKb;			
	vector<double> aryKb2;		
	vector<double> aryRow_cb;		
	vector<double> aryRow_cd;

	vector<double> aryGPP;
	vector<double> aryLE_mg;
	vector<string> aryDate;

	// divide terms using block window
	for(int iCurrent = 0; iCurrent < data.m_aryCO2.size(); iCurrent++){
		if(g_iBlockWindow == 1){
			if( iCurrent % g_iRunPerDay == 0){
				iPeriod = data.m_aryPeriod[iCurrent];
			}
			if(g_bPeriod == true && iCurrent >= g_iRunPerDay && iCurrent % g_iRunPerDay == 0 && iPeriod != data.m_aryPeriod[(iCurrent / g_iRunPerDay) * g_iRunPerDay - 1] && aryCO2.size() != 0){
				iCurrent--;
				iOptDay = 1;
			}
			else{
				// apply block window
				aryCO2.push_back(data.m_aryCO2[iCurrent]);
				aryPPFD.push_back(data.m_aryAPPFD[iCurrent]);
				aryTa.push_back(data.m_aryTa[iCurrent]);
				aryTs.push_back(data.m_aryTs[iCurrent]);
				aryVPD.push_back(data.m_aryD0[iCurrent]);
				// aryVPD.push_back(data.m_aryVPD[iCurrent]);
				aryVP_air.push_back(data.m_aryVP_air[iCurrent]);
				aryVP_leaf.push_back(data.m_aryVP_leaf[iCurrent]);
				aryPressure.push_back(data.m_aryPressure[iCurrent]);
				aryGc.push_back(data.m_aryGc[iCurrent]);
				if(g_iUseKB_inverse){
					aryGb.push_back(data.m_aryGb_h[iCurrent]);
				}
				else{
					aryGb.push_back(data.m_aryGb[iCurrent]);
				}
				aryGb.push_back(data.m_aryGb[iCurrent]);
				aryTg.push_back(data.m_aryTg[iCurrent]);
				// aryUpscalingFactor.push_back(data.m_aryLAI[iCurrent] * (data.m_aryWeight_sun[iCurrent] + data.m_aryWeight_shade[iCurrent]));
				aryUpscalingFactor.push_back( data.m_aryLAI[iCurrent] *  (1.0 - exp(- g_dKn)) / g_dKn );  // Ryu et al., (2011: GBC)

				aryPPFD_sun.push_back(data.m_aryPPFD_sun[iCurrent]);
				aryPPFD_shade.push_back(data.m_aryPPFD_shade[iCurrent]);
				aryLAI_sun.push_back(data.m_aryLAI_sun[iCurrent]);
				aryLAI_shade.push_back(data.m_aryLAI_shade[iCurrent]);
				aryWeight_sun.push_back(data.m_aryWeight_sun[iCurrent]);
				aryWeight_shade.push_back(data.m_aryWeight_shade[iCurrent]);

				aryPPFD_direct.push_back(data.m_aryPPFD_direct[iCurrent]);
				aryPPFD_diffuse.push_back(data.m_aryPPFD_diffuse[iCurrent]);
				aryKb.push_back(data.m_aryKb[iCurrent]);
				aryKb2.push_back(data.m_aryKb2[iCurrent]);
				aryRow_cb.push_back(data.m_aryRow_cb[iCurrent]);
				aryRow_cd.push_back(data.m_aryRow_cd[iCurrent]);

				aryGPP.push_back(data.m_aryGPP[iCurrent]);
				aryLE_mg.push_back(data.m_aryLE_mg[iCurrent]);
				aryDate.push_back(data.m_aryDate[iCurrent]);			

				if( iCurrent % iWindowSize == iWindowSize - 1 || iCurrent == data.m_aryCO2.size() - 1){
					iOptDay = 1;
				}
			}
		}
		else{
			// apply moving window
			if( iCurrent % g_iRunPerDay == 0){
				iOptDay = 1;
				iPeriod = data.m_aryPeriod[iCurrent];

				int iWindowSize = (g_iWindowSize - 1) / 2;
				int iStart = iCurrent - iWindowSize * g_iRunPerDay;
				int iEnd   = iCurrent + (iWindowSize + 1) * g_iRunPerDay;
				if(iStart < 0){
					iStart = 0;
				}
				if(iEnd > data.m_aryCO2.size()){
					iEnd = data.m_aryCO2.size();
				}

				for(int iMoving = iStart; iMoving < iEnd; iMoving++){
					if(g_bPeriod == true && data.m_aryPeriod[iMoving / g_iRunPerDay] != iPeriod){
						continue;
					}
					aryCO2.push_back(data.m_aryCO2[iMoving]);
					aryPPFD.push_back(data.m_aryAPPFD[iMoving]);
					aryTa.push_back(data.m_aryTa[iMoving]);
					aryTs.push_back(data.m_aryTs[iMoving]);
					aryVPD.push_back(data.m_aryD0[iMoving]);
					// aryVPD.push_back(data.m_aryVPD[iMoving]);
					aryVP_air.push_back(data.m_aryVP_air[iMoving]);
					aryVP_leaf.push_back(data.m_aryVP_leaf[iMoving]);
					aryPressure.push_back(data.m_aryPressure[iMoving]);
					aryGc.push_back(data.m_aryGc[iMoving]);
					if(g_iUseKB_inverse){
						aryGb.push_back(data.m_aryGb_h[iMoving]);
					}
					else{
						aryGb.push_back(data.m_aryGb[iMoving]);
					}		
					aryTg.push_back(data.m_aryTg[iMoving]);	
					// aryUpscalingFactor.push_back(data.m_aryLAI[iMoving] * (data.m_aryWeight_sun[iMoving] + data.m_aryWeight_shade[iMoving]));
					aryUpscalingFactor.push_back( data.m_aryLAI[iMoving] *  (1.0 - exp(- g_dKn)) / g_dKn );  // Ryu et al., (2011: GBC)
					
					aryPPFD_sun.push_back(data.m_aryPPFD_sun[iMoving]);
					aryPPFD_shade.push_back(data.m_aryPPFD_shade[iMoving]);
					aryLAI_sun.push_back(data.m_aryLAI_sun[iMoving]);
					aryLAI_shade.push_back(data.m_aryLAI_shade[iMoving]);
					aryWeight_sun.push_back(data.m_aryWeight_sun[iMoving]);
					aryWeight_shade.push_back(data.m_aryWeight_shade[iMoving]);

					aryPPFD_direct.push_back(data.m_aryPPFD_direct[iMoving]);
					aryPPFD_diffuse.push_back(data.m_aryPPFD_diffuse[iMoving]);
					aryKb.push_back(data.m_aryKb[iMoving]);
					aryKb2.push_back(data.m_aryKb2[iMoving]);
					aryRow_cb.push_back(data.m_aryRow_cb[iMoving]);
					aryRow_cd.push_back(data.m_aryRow_cd[iMoving]);

					aryGPP.push_back(data.m_aryGPP[iMoving]);
					aryLE_mg.push_back(data.m_aryLE_mg[iMoving]);
					aryDate.push_back(data.m_aryDate[iMoving]);
				}
			}
		}

		if(iOptDay == 1){
			// set input data to class
			cModel.m_aryInputData.clear();
			cModel.m_aryObsData.clear();
			cModel.m_aryDate.clear();

			cModel.m_aryInputData.push_back(aryCO2);
			cModel.m_aryInputData.push_back(aryPPFD);
			cModel.m_aryInputData.push_back(aryTa);
			cModel.m_aryInputData.push_back(aryTs);
			cModel.m_aryInputData.push_back(aryVPD);
			cModel.m_aryInputData.push_back(aryVP_air);
			cModel.m_aryInputData.push_back(aryVP_leaf);
			cModel.m_aryInputData.push_back(aryPressure);
			cModel.m_aryInputData.push_back(aryGc);
			cModel.m_aryInputData.push_back(aryGb);
			cModel.m_aryInputData.push_back(aryTg);
			cModel.m_aryInputData.push_back(aryUpscalingFactor);

			cModel.m_aryInputData.push_back(aryPPFD_sun);
			cModel.m_aryInputData.push_back(aryPPFD_shade);
			cModel.m_aryInputData.push_back(aryLAI_sun);
			cModel.m_aryInputData.push_back(aryLAI_shade);
			cModel.m_aryInputData.push_back(aryWeight_sun);
			cModel.m_aryInputData.push_back(aryWeight_shade);

			cModel.m_aryInputData.push_back(aryGPP);

			cModel.m_aryInputData.push_back(aryPPFD_direct);
			cModel.m_aryInputData.push_back(aryPPFD_diffuse);
			cModel.m_aryInputData.push_back(aryKb);
			cModel.m_aryInputData.push_back(aryKb2);
			cModel.m_aryInputData.push_back(aryRow_cb);
			cModel.m_aryInputData.push_back(aryRow_cd);

			cModel.m_aryObsData.push_back(aryGPP);
			cModel.m_aryObsData.push_back(aryLE_mg);

			cModel.m_aryDate = aryDate;
			cSCE_UA.m_iRecordNum = cModel.m_aryDate.size();
	
			cSCE_UA.m_aryLowPrm = cSCE_UA.m_aryLowPrmDefault;
			cSCE_UA.m_aryHighPrm = cSCE_UA.m_aryHighPrmDefault;

			optimize_photosynthesis_stomatal_conductance_model_each(cSCE_UA, cModel, data, aryBestParameterSet, aryStdevParameterSet, aryRMSE, nrun);

			aryCO2.clear();
			aryPPFD.clear();
			aryTs.clear();
			aryTa.clear();
			aryVPD.clear();
			aryVP_air.clear();
			aryVP_leaf.clear();
			aryPressure.clear();
			aryGc.clear();
			aryGb.clear();
			aryTg.clear();
			aryPPFD_sun.clear();
			aryPPFD_shade.clear();
			aryLAI_sun.clear();
			aryLAI_shade.clear();
			aryWeight_sun.clear();
			aryWeight_shade.clear();
			aryGPP.clear();			
			aryPPFD_direct.clear();
			aryPPFD_diffuse.clear();
			aryKb.clear();
			aryKb2.clear();
			aryRow_cb.clear();
			aryRow_cd.clear();
			aryLE_mg.clear();
			aryDate.clear();
			iOptDay = 0;
		}
	}
}

void optimize_photosynthesis_stomatal_conductance_model_each(CSCE_UA& cSCE_UA, model_input& cModel, CData& data, vector< vector<double> >& aryBestParameterSet, vector< vector<double> >& aryStdevParameterSet, vector< vector<double> >& aryRMSE, int nrun)
{
	int iParameterNum = 6;
	vector< vector<double> > aryCuuretBestParameters;
	vector<double> aryBestFunction, aryBestParameters(iParameterNum), aryStdevParameters(iParameterNum);
	vector<double> aryRMSEs(iParameterNum);
	int iseed;

	// conducting SCE-UA optimization
//	for(int i = 0; i < nrun; i++){
//		iseed = cSCE_UA.m_jseed[i];
//		cSCE_UA.sceua(cModel, g_strOutFile, i, photosynthesis_model);
//		aryCuuretBestParameters.push_back(cSCE_UA.m_aryBestPrm);
//		aryBestFunction.push_back(cSCE_UA.m_dBestFunc);
//	}

	// search best parameters and calculating stdev of parmaters
	int iBestIndex = 0, iSize = aryBestFunction.size();
	double dStdev_vc = c_dError, dStdev_j = c_dError, dStdev_omega = c_dError, dStdev_m = c_dError, dStdev_b = c_dError, dStdev_d0 = c_dError;

	// sequential optimization transpiration after optimizing GPP
	if(g_iSequentialOpt == 1){
		cSCE_UA.m_iOptimizedPrm = 1;
		// ****************************************************************
		// optimize m, b and D0
		// ****************************************************************
		// clear old best parameters
		aryCuuretBestParameters.clear();
		aryBestFunction.clear();

		for(int i = 0; i < nrun; i++){
			iseed = cSCE_UA.m_jseed[i];
			cSCE_UA.sceua(cModel, g_strOutFile, i, stomatal_model);
			aryCuuretBestParameters.push_back(cSCE_UA.m_aryBestPrm);
			aryBestFunction.push_back(cSCE_UA.m_dBestFunc);
		}

		iSize = aryBestFunction.size();

		// search best parameters and calculating stdev of parmaters
		search_best_stdev(aryCuuretBestParameters, aryBestFunction, 3, iBestIndex, dStdev_m);
		search_best_stdev(aryCuuretBestParameters, aryBestFunction, 4, iBestIndex, dStdev_b);
		if(g_iLeuningModel == 1 && cSCE_UA.m_aryBestPrm.size() == 6){	
			search_best_stdev(aryCuuretBestParameters, aryBestFunction, 5, iBestIndex, dStdev_d0);
		}
		aryRMSEs[1] = aryBestFunction[iBestIndex];

		// set stdev
		aryStdevParameters[3] = dStdev_m;
		aryStdevParameters[4] = dStdev_b;
		aryStdevParameters[5] = dStdev_d0;

		// set best prm
		aryBestParameters[3] = aryCuuretBestParameters[iBestIndex][3];		// set best prm m
		aryBestParameters[4] = aryCuuretBestParameters[iBestIndex][4];		// set best prm b
		if(g_iLeuningModel && cSCE_UA.m_aryBestPrm.size() == 6){
			aryBestParameters[5] = aryCuuretBestParameters[iBestIndex][5];	// set best prm D0
		}
		else{
			aryBestParameters[5] = c_dError;		// set best prm Jmax
		}

		// ****************************************************************
		// re-optimize Vcmax and Jmax using optimized m and b
		// ****************************************************************
		cSCE_UA.m_iOptimizedPrm = 0;
		set_parameter_range(cSCE_UA, 0, aryCuuretBestParameters[iBestIndex][0], cSCE_UA.m_aryLowPrmDefault[0], cSCE_UA.m_aryHighPrmDefault[0]); // vcmax
		set_parameter_range(cSCE_UA, 1, aryCuuretBestParameters[iBestIndex][1], cSCE_UA.m_aryLowPrmDefault[1], cSCE_UA.m_aryHighPrmDefault[1]); // Jmax
		if(g_iOmegaOptimization){
			// set_parameter_range(cSCE_UA, 2, aryCuuretBestParameters[iBestIndex][2], cSCE_UA.m_aryLowPrmDefault[2], cSCE_UA.m_aryHighPrmDefault[2]); // Omega
			double dStedev = 0.06;
			set_parameter_range(cSCE_UA, 2, g_dOmega, dStedev); // Omega
		}
		else{
			double dStedev = 0.01;
			set_parameter_range(cSCE_UA, 2, g_dOmega, dStedev); // Omega
		}		
		set_parameter_range(cSCE_UA, 3, aryCuuretBestParameters[iBestIndex][3], dStdev_m); // m
		set_parameter_range(cSCE_UA, 4, aryCuuretBestParameters[iBestIndex][4], dStdev_b); // b
		if(g_iLeuningModel == 1 && cSCE_UA.m_aryBestPrm.size() == 6){
			set_parameter_range(cSCE_UA, 5, aryCuuretBestParameters[iBestIndex][5], dStdev_d0); // D0
		}

		aryCuuretBestParameters.clear();		// clear old best parameters
		aryBestFunction.clear();				// clear old best parameters

		for(i = 0; i < nrun; i++){				// SCE-UA optimization again
			iseed = cSCE_UA.m_jseed[i];
			cSCE_UA.sceua(cModel, g_strOutFile, i, photosynthesis_model);
			aryCuuretBestParameters.push_back(cSCE_UA.m_aryBestPrm);
			aryBestFunction.push_back(cSCE_UA.m_dBestFunc);
		}
		iSize = aryBestFunction.size();

		search_best_stdev(aryCuuretBestParameters, aryBestFunction, 0, iBestIndex, dStdev_vc);
		search_best_stdev(aryCuuretBestParameters, aryBestFunction, 1, iBestIndex, dStdev_j);
		search_best_stdev(aryCuuretBestParameters, aryBestFunction, 2, iBestIndex, dStdev_omega);
		aryRMSEs[0] = aryBestFunction[iBestIndex];

		aryStdevParameters[0] = dStdev_vc;
		aryStdevParameters[1] = dStdev_j;
		aryStdevParameters[2] = dStdev_omega;

		aryBestParameters[0] = aryCuuretBestParameters[iBestIndex][0];		// set best prm Vcmax
		aryBestParameters[1] = aryCuuretBestParameters[iBestIndex][1];		// set best prm Jmax
		aryBestParameters[2] = aryCuuretBestParameters[iBestIndex][2];		// set best prm Omega

		cSCE_UA.m_iOptimizedPrm = 0;
	}

	aryBestParameterSet.push_back(aryBestParameters);
	aryStdevParameterSet.push_back(aryStdevParameters);
	aryRMSE.push_back(aryRMSEs);
}

void set_parameter_range(CSCE_UA& cSCE_UA, int iIndex, double& dBestPrm, double& dStdev)
{
	cSCE_UA.m_aryIniPrm[iIndex] = dBestPrm;					// array for initial value of target paramameter
	cSCE_UA.m_aryLowPrm[iIndex] = dBestPrm - dStdev;		// array for lower boudary of parameter space
	cSCE_UA.m_aryHighPrm[iIndex]= dBestPrm + dStdev;		// array for upper boudary of parameter space
}

void set_parameter_range(CSCE_UA& cSCE_UA, int iIndex, double& dBestPrm, double& dLow, double& dHigh )
{
	cSCE_UA.m_aryIniPrm[iIndex] = dBestPrm;					// array for initial value of target paramameter
	cSCE_UA.m_aryLowPrm[iIndex] = dLow;						// array for lower boudary of parameter space
	cSCE_UA.m_aryHighPrm[iIndex]= dHigh;					// array for upper boudary of parameter space
}


void search_best_stdev(const std::vector< std::vector<double> >& aryBestParameters, const std::vector<double>& aryBestFunction, int iIndex, int& iBestIndex, double& dStdev)
{
	double dTxx = 0.0, dTx = 0.0;
	double dMinimumFunction = -c_dError;
	int iSize = aryBestFunction.size();

	dStdev = 0.01;

	// search best parameters and calculating stdev of parmaters
	for(int i = 0; i < iSize; i++){
		if(dMinimumFunction > aryBestFunction[i] ){
			iBestIndex = i;
			dMinimumFunction = aryBestFunction[i];
		}
		dTx   += aryBestParameters[i][iIndex];
		dTxx  += aryBestParameters[i][iIndex] * aryBestParameters[i][iIndex];
	}
	if(iSize != 1){
		dStdev = sqrt((dTxx - dTx * dTx / iSize) / iSize);
	}
}

void photosynthesis_model(std::vector<double>& parameters, const std::vector< std::vector<double> >& input,  std::vector< std::vector<double> >& output)
{
	double dVcmax25 = parameters[0];
	// double dJmax25  = parameters[1];
	double dJmax25  = dVcmax25 * parameters[1];
	double dOmega   = parameters[2];
	double dBBm     = parameters[3];
	double dBBb     = parameters[4];

	double dD0 = c_dError;
	if(parameters.size() == 6 && g_iLeuningModel == 1){
		dD0 = parameters[5];
	}

	for(int i = 0; i < output[0].size(); i++){
		if(input[c_iCO2_sce][i] == c_dError || input[c_iPPFD_sce][i] == c_dError || input[c_iLeafTemperature_sce][i] == c_dError ||
			input[c_iVPD_sce][i] == c_dError || input[c_iVP_air_sce][i] == c_dError || input[c_iVP_leaf_sce][i] == c_dError || input[c_iPressure_sce][i] == c_dError ||
			input[c_iGc_sce][i] == c_dError ||input[c_iGb_sce][i] == c_dError ||input[c_iTg_sce][i] == c_dError){
			output[0][i] = c_dError;
			output[1][i] = c_dError;
			continue;
		}

		
		// two leaf model
		if(g_iCanopyStructure >= 1 && input[c_iPPFD_sun_sce][i] < 0.0 ||input[c_iPPFD_shade_sce][i] < 0.0 ||
			input[c_iLAI_sun_sce][i] < 0.0 || input[c_iLAI_shade_sce][i] < 0.0 || 
			input[c_iWeight_sun_sce][i] <= 0.0 || input[c_iWeight_shade_sce][i] <= 0.0){
			output[0][i] = c_dError;
			output[1][i] = c_dError;
			continue;
		}

		CLeafPhotosynthesis cPhoto(c_dError);
		cPhoto.SetParameter(dVcmax25, dJmax25, dOmega, dBBm, dBBb, dD0);

		if(g_iCanopyStructure == 0){
			// sinple big leaf model
			cPhoto.Farquhar_BigLeaf(input[c_iCO2_sce][i], input[c_iPPFD_sce][i], input[c_iAirTemperature_sce][i], input[c_iLeafTemperature_sce][i], input[c_iVPD_sce][i], 
				input[c_iVP_air_sce][i], input[c_iVP_leaf_sce][i], input[c_iPressure_sce][i], input[c_iGc_sce][i], input[c_iGb_sce][i], input[c_iTg_sce][i], input[c_iUpscalingFactor_sce][i],
				input[c_iLAI_sun_sce][i] + input[c_iLAI_shade_sce][i], input[c_iPPFD_direct_sce][i], input[c_idPPFD_diffuse_sce][i], input[c_iKb_sce][i], input[c_iKb2_sce][i], input[c_iRow_cb_sce][i], input[c_iRow_cd_sce][i]);
		}
		else if(g_iCanopyStructure == 1){
			// two leaf model
			cPhoto.Farquhar_BigLeaf_two_leaf(input[c_iCO2_sce][i], input[c_iPPFD_sce][i], input[c_iAirTemperature_sce][i], input[c_iLeafTemperature_sce][i], input[c_iVPD_sce][i], 
				input[c_iVP_air_sce][i], input[c_iVP_leaf_sce][i], input[c_iPressure_sce][i], input[c_iGc_sce][i], input[c_iGb_sce][i], input[c_iTg_sce][i], input[c_iUpscalingFactor_sce][i],
				input[c_iPPFD_sun_sce][i], input[c_iPPFD_shade_sce][i], input[c_iWeight_sun_sce][i], input[c_iKb_sce][i], input[c_iLAI_sun_sce][i] + input[c_iLAI_shade_sce][i],
				input[c_iPPFD_direct_sce][i], input[c_idPPFD_diffuse_sce][i], input[c_iKb2_sce][i], input[c_iRow_cb_sce][i], input[c_iRow_cd_sce][i]);
		}
		else{
			// multi layer leaf model
			cPhoto.Farquhar_BigLeaf_multi_layer(input[c_iCO2_sce][i], input[c_iPPFD_sce][i], input[c_iAirTemperature_sce][i], input[c_iLeafTemperature_sce][i], input[c_iVPD_sce][i], 
				input[c_iVP_air_sce][i], input[c_iVP_leaf_sce][i], input[c_iPressure_sce][i], input[c_iGc_sce][i], input[c_iGb_sce][i], input[c_iTg_sce][i], input[c_iUpscalingFactor_sce][i],
				input[c_iLAI_sun_sce][i], input[c_iLAI_shade_sce][i], 
				input[c_iPPFD_direct_sce][i], input[c_idPPFD_diffuse_sce][i], input[c_iPPFD_sun_sce][i], input[c_iPPFD_shade_sce][i],
				input[c_iKb_sce][i], input[c_iKb2_sce][i], input[c_iRow_cb_sce][i], input[c_iRow_cd_sce][i]);
		}

		output[0][i] = cPhoto.m_dAn;
		output[1][i] = cPhoto.m_dTranspiration;	// mg m-2 s-1 ;
	}
}

void stomatal_model(std::vector<double>& parameters, const std::vector< std::vector<double> >& input,  std::vector< std::vector<double> >& output)
{
	double dVcmax25 = parameters[0];
	double dJmax25  = dVcmax25 * parameters[1];
	double dOmega   = parameters[2];
	double dBBm     = parameters[3];
	double dBBb     = parameters[4];

	double dD0 = c_dError;
	if(parameters.size() == 6 && g_iLeuningModel == 1){
		dD0 = parameters[5];
	}

	for(int i = 0; i < output[0].size(); i++){
		if(input[c_iCO2_sce][i] == c_dError || input[c_iPPFD_sce][i] == c_dError || input[c_iGPP_sce][i] == c_dError || input[c_iLeafTemperature_sce][i] == c_dError ||
			input[c_iVPD_sce][i] == c_dError || input[c_iVP_air_sce][i] == c_dError || input[c_iVP_leaf_sce][i] == c_dError || input[c_iPressure_sce][i] == c_dError ||
			input[c_iGc_sce][i] == c_dError ||input[c_iGb_sce][i] == c_dError ||input[c_iTg_sce][i] == c_dError){
			output[0][i] = c_dError;
			output[1][i] = c_dError;
			continue;
		}

		CLeafPhotosynthesis cPhoto(c_dError);
		cPhoto.SetParameter(dVcmax25, dJmax25, dOmega, dBBm, dBBb, dD0);
		cPhoto.Stomatal_conductance_Ball_Berry(input[c_iCO2_sce][i], input[c_iPPFD_sce][i], input[c_iGPP_sce][i], input[c_iLeafTemperature_sce][i], input[c_iVPD_sce][i], 
			input[c_iVP_air_sce][i], input[c_iVP_leaf_sce][i], input[c_iPressure_sce][i], input[c_iGc_sce][i], input[c_iGb_sce][i], input[c_iTg_sce][i], input[c_iUpscalingFactor_sce][i]);

		output[0][i] = c_dError;
		output[1][i] = cPhoto.m_dTranspiration;	// mg m-2 s-1 ;
	}
}

void interpolate_parameter_block_window(CData& data, std::vector< std::vector<double> >& aryBestParametersWindow, std::vector< std::vector<double> >& aryStdevParametersWindow, std::vector< std::vector<double> >& aryRMSE)
{
	std::vector< std::vector<double> > _aryBestParametersWindow = aryBestParametersWindow;
	std::vector< std::vector<double> > _aryStdevParametersWindow = aryStdevParametersWindow;
	std::vector< std::vector<double> > _aryRMSE = aryRMSE;

	aryBestParametersWindow.clear();
	aryStdevParametersWindow.clear();
	aryRMSE.clear();

	int iCurrent = 0, iPeriod = 0;

	for(int i = 0; i < data.m_aryDate.size(); i++){
		if(i % g_iRunPerDay == 0){
			if(i % g_iRunPerDay == 0){
				iPeriod = data.m_aryPeriod[i];
			}
			if(i % (g_iRunPerDay * g_iWindowSize) == 0 && i != 0){
				iCurrent++;
			}
			else{				
				if(g_bPeriod == true && i >= g_iRunPerDay && iPeriod != data.m_aryPeriod[(i / g_iRunPerDay) * g_iRunPerDay - 1] ){
					iCurrent++;
				}
			}

			aryBestParametersWindow.push_back(_aryBestParametersWindow[iCurrent]);
			aryStdevParametersWindow.push_back(_aryStdevParametersWindow[iCurrent]);
			aryRMSE.push_back(_aryRMSE[iCurrent]);
		}
	}
}

void quality_control_parameter(std::vector< std::vector<double> >& aryBestParametersWindow, std::vector< std::vector<double> >& aryStdevParametersWindow, std::vector< std::vector<double> >& aryRMSE)
{
	int i, j; 

	for(i = 0; i < aryRMSE.size(); i++){
		if(aryRMSE[i][0] == -c_dError){
			for(j = 0; j < aryBestParametersWindow[i].size(); j++){
				aryBestParametersWindow[i][j] = c_dError;
			}
			for(j = 0; j < aryStdevParametersWindow[i].size(); j++){
				aryStdevParametersWindow[i][j] = c_dError;
			}
		}
	}

	if(g_iBlockWindow == 1){
		return;
	}
	return;
	
	// quality control using Robust method by Papale et al. (2006)
	vector<int> aryFlag;
	vector<double> aryParameter;
	int iStart, iEnd;
	double dZvalue = 9.0;

	for(int iPrm = 0; iPrm < aryBestParametersWindow[0].size(); iPrm++){
		for(j = 0; j < aryBestParametersWindow.size(); j++){
			iStart = j - g_iWindowSize / 2;
			iEnd   = j + g_iWindowSize / 2;

			if(iStart < 0)  iStart = 0;
			if(iEnd > aryBestParametersWindow.size() - 1) iEnd = aryBestParametersWindow.size() - 1;

			// copy paramter from vector array
			for(int iDay = iStart; iDay < iEnd; iDay ++){
				if(aryBestParametersWindow[iDay][iPrm] != c_dError) aryParameter.push_back(aryBestParametersWindow[iDay][iPrm]);
			}
			if(aryParameter.size() == 0) continue;

			// appying MAD method for quality control
			MedianOfAbsoluteDeviation(aryParameter, aryFlag, dZvalue);

			// delete spike parameter by using flag
			for(i = 0; i < aryFlag.size(); i++){
				if(aryFlag[i] == 1){
					aryBestParametersWindow[iStart + i][iPrm] = c_dError;
				}
			}
			aryFlag.clear();
			aryParameter.clear();
		}
	}
}

bool input_csv_file(CSCE_UA& cSCE_UA, CData& data)
{
	// *******************************************************
	// open input data files
	// *******************************************************
	FILE* in;
	bool bIsOK = true;
	char strLine[MAX_NUM];
	string strLines, strTemp;

	if((in = fopen(strInCsvFile, "rt")) == NULL){
		printf("Input file could not opened.\n");
		bIsOK = false;
		return bIsOK;
	}	

	// skip header file
	fgets(strLine, sizeof(strLine), in);
	fgets(strLine, sizeof(strLine), in);

	// get input data number by using comma
	int iColumn = 0;
	strLines = strLine;
	for(int i = 0; i < strLines.size(); i++){
		if(strLines.c_str()[i] == ',')  iColumn++;
	}

	// dynamically reading csv file
	double dValue;
	int iPos, iLoop = 0;
	while(fgets(strLine, sizeof(strLine), in) != NULL){
		string strLines = strLine;
		iLoop = 0;

		// vector<double> aryInputData;

		DeleteHeadSpace(strLines);
		while(strLines.compare("\n") != 0 && strLines.size() != 0){
			iPos = strLines.find(",");
			strTemp = strLines.substr(0, iPos);
			dValue = atof(strTemp.c_str());

			if( strTemp.compare("#N/A") == 0){
				dValue = c_dError;
			}

			if(iLoop == 0){
				data.m_aryDate.push_back(strTemp);
				data.m_aryDate_double.push_back(dValue);
			}

			if(iLoop == c_iWindSpeed){
				data.m_aryU.push_back(dValue);
			}
			if(iLoop == c_iPPFD){
				data.m_aryPPFD.push_back(dValue);
			}
			if(iLoop == c_iPPFD_ref){
				data.m_aryPPFD_ref.push_back(dValue);
			}
			if(iLoop == c_iTemperature){
				data.m_aryTa.push_back(dValue);
			}
			if(iLoop == c_iRH){
				if(dValue > 100) dValue = 100.0;
				if(dValue < 0)   dValue = 0.0;
				data.m_aryRH.push_back(dValue);
				data.m_aryVPD.push_back(c_dError);
			}
			if(iLoop == c_iRain){
				data.m_aryRain.push_back(dValue);
			}
			if(iLoop == c_iPressure){
				data.m_aryPressure.push_back(dValue);
			}
			if(iLoop == c_iCO2){
				data.m_aryCO2.push_back(dValue);
			}
			if(iLoop == c_iRn){
				data.m_aryRn.push_back(dValue);
			}
			if(iLoop == c_iG){
				data.m_aryG.push_back(dValue);
			}
			if(iLoop == c_iUs){
				data.m_aryUs.push_back(dValue);
			}
			if(iLoop == c_iH){
				data.m_aryH.push_back(dValue);
			}
			if(iLoop == c_iLE){
				data.m_aryLE.push_back(dValue);
			}
			if(iLoop == c_iGPP){
				data.m_aryGPP.push_back(dValue);
			}
			if(iLoop == c_iTg){
				data.m_aryTg.push_back(dValue);
			}
			if(iLoop == c_iFPAR){
				data.m_aryFPAR.push_back(dValue);
			}
			if(iLoop == c_iLAI){
				data.m_aryLAI.push_back(dValue);
			}
			if(iLoop == iColumn){
				data.m_aryPeriod.push_back(dValue);
			}

			strLines.erase(0, strLines.find(',') + 1);
			DeleteHeadSpace(strLines);

			if(iLoop == iColumn) break;
			iLoop++;
		}
		// cModel.m_aryInputData.push_back(aryInputData);
	}
	// cModel.m_aryObsData.push_back(data.m_aryGPP);

	for(i = 0; i < data.m_aryLE.size(); i++){
		if(data.m_aryLE[i] != c_dError){
			data.m_aryLE_mg.push_back(data.m_aryLE[i] * pow(10, 6) / calculate_latent_heat(data.m_aryTa[i]));
		}
		else{
			data.m_aryLE_mg.push_back(c_dError);
		}
	}

	fclose(in);

	return bIsOK;
}

bool input_forward_parameter_file(vector< vector<double> >& aryBestParametersWindow)
{
	// column number for input/output parameter file
	// *******************************************************
	// open input data files
	// *******************************************************
	FILE* in;
	bool bIsOK = true;
	char strLine[MAX_NUM];
	string strLines, strTemp;

	aryBestParametersWindow.clear();

	if((in = fopen(strInForwardParameterFile, "rt")) == NULL){
		printf("Input parameter file could not opened.\n");
		bIsOK = false;
		return bIsOK;
	}

	// skip header file
	fgets(strLine, sizeof(strLine), in);
	fgets(strLine, sizeof(strLine), in);

	// get input data number by using comma
	int iColumn = 0;
	strLines = strLine;
	for(int i = 0; i < strLines.size(); i++){
		if(strLines.c_str()[i] == ',')  iColumn++;
	}

	// dynamically reading csv file
	double dValue, dVcmax25;
	int iPos, iLoop = 0;
	while(fgets(strLine, sizeof(strLine), in) != NULL){
		vector<double> aryParameters;
		string strLines = strLine;
		iLoop = 0;

		// vector<double> aryInputData;

		DeleteHeadSpace(strLines);
		while(strLines.compare("\n") != 0 && strLines.size() != 0){
			iPos = strLines.find(",");
			strTemp = strLines.substr(0, iPos);
			dValue = atof(strTemp.c_str());

			if( strTemp.compare("#N/A") == 0){
				dValue = c_dError;
			}

			if(iLoop == c_iVcmax25){
				dVcmax25 = dValue;
				aryParameters.push_back(dValue);
			}
			if(iLoop == c_iJmax25){
				aryParameters.push_back(dValue / dVcmax25);
			}			
			if(iLoop == c_iOmega){
				aryParameters.push_back(dValue);
			}
			if(iLoop == c_iM){
				aryParameters.push_back(dValue);
			}
			if(iLoop == c_iB){
				aryParameters.push_back(dValue);
			}
			if(iLoop == c_iD0){
				aryParameters.push_back(dValue);
			}
			if(iLoop > c_iD0){
				break;
			}

			strLines.erase(0, strLines.find(',') + 1);
			DeleteHeadSpace(strLines);

			if(iLoop == iColumn) break;
			iLoop++;
		}
		aryBestParametersWindow.push_back(aryParameters);
	}

	fclose(in);

	return bIsOK;
}

bool sce_setting_input(CSCE_UA& cSCE_UA, model_input& cModel)
{
	//  WRITTEN BY QINGYUN DUAN - UNIVERSITY OF ARIZONA, APRIL 1992
	//  TRANSRATED TO C++ BY M. UEYAMA

	FILE *in;
	char strLine[MAX_NUM];
	std::string strLines, strTemp;
	int iIndex, iPos;
	double dValue;

	const char deflt[MAX_NUM] = " DEFAULT  ";
	const char usrsp[MAX_NUM] = "USER SPEC.";
	const char ysflg[MAX_NUM] = "YES ";
	const char noflg[MAX_NUM] = "NO ";
	char pcntrl[MAX_NUM];
	bool bIsOK = true;

	printf("ENTER THE SCEIN SUBROUTINE --- \n");

	// *******************************************************
	// open parameter files
	// *******************************************************
	if((in = fopen(strInFile, "rt")) == NULL){
		printf("Input file could not opened.\n");
		bIsOK = false;
		return bIsOK;
	}

	int ierror = 0;
	int iwarn = 0;

	// *******************************************************
	// READ THE SCE CONTROL PARAMETERS
	// *******************************************************
	int ideflt = 0;	// SCE-UA パラメタ情報の入力選択 (0: 基本設定を利用, 1:手動入力で設定)

	fgets(strLine, sizeof(strLine), in);		// skip header file  "# npg,nps,nspl,mings,iniflg,iprint"
	fscanf(in, "%d  %d  %lf  %d  %d  %d\n", &cSCE_UA.m_maxn, &cSCE_UA.m_kstop, &cSCE_UA.m_dEpsPercent, &cSCE_UA.m_ngs, &cSCE_UA.m_nopt, &ideflt);
	cSCE_UA.m_iseed = cSCE_UA.m_jseed[0];
	
	// IF ideflt IS EQUAL TO 1, READ THE SCE CONTROL PARAMETERS
	if (ideflt == 1){
		fgets(strLine, sizeof(strLine), in);	// skip header file "# npg,nps,nspl,mings,iniflg,iprint"
		fscanf(in, "%d  %d  %d  %d  %d  %d\n", &cSCE_UA.m_npg, &cSCE_UA.m_nps, &cSCE_UA.m_nspl, &cSCE_UA.m_mings, &cSCE_UA.m_iniflg, &cSCE_UA.m_iprint);
		strcpy(pcntrl, usrsp);
	}
	else{
		fgets(strLine, sizeof(strLine), in);	// skip header file "# npg,nps,nspl,mings,iniflg,iprint"
		fgets(strLine, sizeof(strLine), in);	// skip values for using default value
		strcpy(pcntrl, deflt);
	}

	// READ THE INITIAL PARAMETER VALUES AND THE PARAMETER BOUNDS
	fgets(strLine, sizeof(strLine), in);		// skip header file "# initial     lower    upper boundary"
	double dIniPrm, dLowPrm, dHighPrm;
	cSCE_UA.m_aryIniPrm.clear();
	cSCE_UA.m_aryLowPrm.clear();
	cSCE_UA.m_aryHighPrm.clear();
	for(int iopt = 0; iopt < cSCE_UA.m_nopt; iopt++){
		fscanf(in, "%lf  %lf  %lf\n", &dIniPrm, &dLowPrm, &dHighPrm);
		cSCE_UA.m_aryIniPrm.push_back(dIniPrm);
		cSCE_UA.m_aryLowPrm.push_back(dLowPrm);
		cSCE_UA.m_aryHighPrm.push_back(dHighPrm);
		cSCE_UA.m_aryLowPrmDefault.push_back(dLowPrm);
		cSCE_UA.m_aryHighPrmDefault.push_back(dHighPrm);
	}

	// IF ideflt IS EQUAL TO 0, SET THE SCE CONTROL PARAMETERS TO THE DEFAULT VALUES
	if(ideflt == 0){
		cSCE_UA.set_default_sce_parameters(cSCE_UA.m_nopt, cSCE_UA.m_ngs);
	}

	// *******************************************************
	// add by M. Ueyama
	// read Hydromodel parameter and input data
	// *******************************************************
	int ns;
	fgets(strLine, sizeof(strLine), in);		// skip header file "# PAR, # DATA, # STATES, OBJ FUNC, DATA TYPE"
	fscanf(in, "%d  %d  %d  %d  %d\n", &cSCE_UA.m_npar, &cSCE_UA.m_ndata, &ns, &cSCE_UA.m_iobj, &cSCE_UA.m_idata);
	cSCE_UA.m_npar = cSCE_UA.m_aryIniPrm.size();

	// cSCE_UA.m_ndata = cModel.m_aryDate.size();

	fgets(strLine, sizeof(strLine), in);		// skip header file "# TRUE PARAMETER VALUES: k11 k12 k13 k21 k22 k41 h11 h12 h21"	

	fgets(strLine, sizeof(strLine), in);
	strLines = strLine;
	DeleteHeadSpace(strLines);
	while(strLines.compare("\n") != 0 && strLines.size() != 0){
		iPos = strLines.find(" ");
		strTemp = strLines.substr(0, iPos);
		dValue = atof(strTemp.c_str());
		cModel.m_aryTestParameters.push_back(dValue);
		strLines.erase(0, strLines.find(strTemp) + strTemp.length());
		DeleteHeadSpace(strLines);
	}

	fgets(strLine, sizeof(strLine), in);		// skip header file "# INDEX OF PARAMETERS TO BE OPTIMIZED:"
	fgets(strLine, sizeof(strLine), in);
	
	strLines = strLine;
	DeleteHeadSpace(strLines);
	cModel.m_aryLocationOfOptParameter.clear();
	while(strLines.compare("\n") != 0  && strLines.size() != 0){
		iPos = strLines.find(" ");
		strTemp = strLines.substr(0, iPos);
		iIndex = atoi(strTemp.c_str());
		cModel.m_aryLocationOfOptParameter.push_back(iIndex);
		strLines.erase(0, strLines.find(strTemp) +  strTemp.length());
		DeleteHeadSpace(strLines);
	}

	// テスト用の合成パラメタから流出量を算出
	if(cSCE_UA.m_idata){
		photosynthesis_model(cModel.m_aryTestParameters, cModel.m_aryInputData, cModel.m_aryObsData);
	}

	// *******************************************************
	// close input file
	// *******************************************************
	fclose(in);
	
	// *******************************************************
	// CHECK IF THE SCE CONTROL PARAMETERS ARE VALID
	// *******************************************************
	if (cSCE_UA.m_ngs < 1 || cSCE_UA.m_ngs >= 1320){
		// fprintf(ipr, "   **ERROR** NUMBER OF COMPLEXES IN INITIAL POPULATION (%d) IS NOT A VALID CHOICE.\n", cSCE_UA.m_ngs);
        ierror = ierror + 1;
	}

	if (cSCE_UA.m_kstop <= 0 || cSCE_UA.m_kstop >= 20){
		// fprintf(ipr, "   **WARNING** THE NUMBER OF SHUFFLING LOOPS IN WHICH THE CRITERION VALUE MUST CHANGE.\n\
		//	             SHOULD BE  GREATER THAN 0 AND LESS THAN 10.  ','kstop = %d WAS SPECIFIED.\n\
		//				 BUT kstop = 5 WILL BE USED INSTEAD.\n", cSCE_UA.m_kstop);
		iwarn = iwarn + 1;
		cSCE_UA.m_kstop = 5;
	}

	if (cSCE_UA.m_mings <= 1 || cSCE_UA.m_mings > cSCE_UA.m_ngs){
		// fprintf(ipr, "   **WARNING** THE MINIMUM NUMBER OF COMPLEXES %d IS NOT A VALID CHOICE. SET IT TO DEFAULT", cSCE_UA.m_mings);
		iwarn = iwarn + 1;
		cSCE_UA.m_mings = cSCE_UA.m_ngs;
	}
	
	if (cSCE_UA.m_npg < 2 || cSCE_UA.m_npg > 1320 / max(cSCE_UA.m_ngs, 1)){
		// fprintf(ipr, "   **WARNING** THE NUMBER OF POINTS IN A COMPLEX %d IS NOT A VALID CHOICE, SET IT TO DEFAULT\n", cSCE_UA.m_npg);
		iwarn = iwarn + 1;
		cSCE_UA.m_npg = 2 * cSCE_UA.m_nopt + 1;
	}

	if (cSCE_UA.m_nps < 2 || cSCE_UA.m_nps > cSCE_UA.m_npg || cSCE_UA.m_nps > 50){
		// fprintf(ipr, "   **WARNING** THE NUMBER OF POINTS IN A SUB-COMPLEX %d IS NOT A VALID CHOICE, SET IT TO DEFAULT\n", cSCE_UA.m_nps);
		iwarn = iwarn + 1;
        cSCE_UA.m_nps = cSCE_UA.m_nopt + 1;
	}
	
	if (cSCE_UA.m_nspl < 1){
		// fprintf(ipr, "   **WARNING** THE NUMBER OF EVOLUTION STEPS TAKEN IN EACH COMPLEX BEFORE SHUFFLING %d \n\
		// 	             IS NOT A VALID CHOICE, SET IT TO DEFAULT\n", cSCE_UA.m_nspl);
		iwarn = iwarn + 1;
		cSCE_UA.m_nspl = cSCE_UA.m_npg;
	}

	// *******************************************************
	// COMPUTE THE TOTAL NUMBER OF POINTS IN INITIAL POPULATION
	// *******************************************************
	int npt = cSCE_UA.m_ngs * cSCE_UA.m_npg;

	if (npt > 1320){
		iwarn = iwarn + 1;
		cSCE_UA.m_ngs = 2;
		cSCE_UA.m_npg = 2 * cSCE_UA.m_nopt + 1;
		cSCE_UA.m_nps = cSCE_UA.m_nopt + 1;
		cSCE_UA.m_nspl = cSCE_UA.m_npg;
	}

	return bIsOK;
}

void DeleteHeadSpace(string &buf)
{
	// 先頭の空白(スペース，タブ)を削除
    size_t pos;
    while((pos = buf.find_first_of(" 　\t")) == 0){
        buf.erase(buf.begin());
        if(buf.empty()) break;
    }
}

int max(int iA, int iB)
{
	if(iA >= iB){
		return iA;

	}
	else{
		return iB;
	}
}

// ****************************************************************
//  Create Output file name
// ****************************************************************
void create_output_filename(const char strOutDirectory[])
{
	char strModelName[MAX_NUM];
	char strPhotoFuncName[MAX_NUM];
	char strWindowType[MAX_NUM];
	char strWindowSize[MAX_NUM];
	char strWindowSize_Oren[MAX_NUM];
	char strSuffix[MAX_NUM];

	if(g_iLeuningModel){
		strcpy(strModelName, "Leuning");
	}
	else{
		strcpy(strModelName, "BallBerry");
	}

	if(g_iPhotosynthesisFunctions == 0){
		strcpy(strPhotoFuncName, "dPF1997");
	}
	if(g_iPhotosynthesisFunctions == 1){
		strcpy(strPhotoFuncName, "B2001");
	}
	if(g_iPhotosynthesisFunctions == 2){
		strcpy(strPhotoFuncName, "vC2009");
	}
	if(g_iPhotosynthesisFunctions == 3){
		strcpy(strPhotoFuncName, "C1991");
	}
	if(g_iPhotosynthesisFunctions == 4){
		strcpy(strPhotoFuncName, "K2003");
	}
	if(g_iPhotosynthesisFunctions == 5){
		strcpy(strPhotoFuncName, "KK2007");
	}
	if(g_iPhotosynthesisFunctions == 10){
		strcpy(strPhotoFuncName, "C4");
	}

	if(g_iCanopyStructure == 0){
		strcat(strPhotoFuncName, ".big");
	}
	if(g_iCanopyStructure == 1){
		strcat(strPhotoFuncName, ".two");
	}
	if(g_iCanopyStructure == 2){
		strcat(strPhotoFuncName, ".multi.b");
	}
	if(g_iCanopyStructure == 3){
		strcat(strPhotoFuncName, ".multi.t");
	}

	if(g_iBlockWindow){
		strcpy(strWindowType, "bw");
	}
	else{
		strcpy(strWindowType, "mw");
	}

	if(g_iForwarmdMode == 0){
		strcpy(strSuffix, "Inv");
	}
	else if(g_iForwarmdMode == 1){
		strcpy(strSuffix, "Fwd");
	}
	else{
		strcpy(strSuffix, "Fwd.cp");
	}

	sprintf(strWindowSize, "%03d", g_iWindowSize);
	sprintf(strWindowSize_Oren, "%03d", g_iWindowSize_Oren);

	// get input file name 
	char strTemp[MAX_NUM], strInFileName[MAX_NUM];
	char* iStart = strrchr(strInCsvFile, '\\');
	strcpy(strTemp, iStart + 1);
	iStart = strrchr(strTemp, '.');
	int iLength = strlen(strTemp) - strlen(iStart);
	strncpy(strInFileName, strTemp, iLength );
	strInFileName[iLength] = '\0';

	sprintf(g_strOutPhysiologicalFile30, "%s\\%s.%s.Physiological_30Hours_%s_%s_%s%s.csv", strOutDirectory, strInFileName, strSuffix, strModelName, strPhotoFuncName, strWindowType, strWindowSize);
	sprintf(g_strOutPhysicalFile30, "%s\\%s.%s.Physical_30Hours.csv", strOutDirectory, strInFileName, strSuffix);
	sprintf(g_strOutFile_AnnualPrm, "%s\\%s.%s_AnnualPRM_%s_%s_%s%s.csv", strOutDirectory, strInFileName, strSuffix, strModelName, strPhotoFuncName, strWindowType, strWindowSize);
	sprintf(g_strOutFile_WindowPrm, "%s\\%s.%s_DailyPRM_%s_%s_%s%s.csv", strOutDirectory, strInFileName, strSuffix, strModelName, strPhotoFuncName, strWindowType, strWindowSize);
	sprintf(g_strOutFile_LeafPrm,   "%s\\%s.%s_DailyLeafPRM_%s_%s_%s%s.csv", strOutDirectory, strInFileName, strSuffix, strModelName, strPhotoFuncName, strWindowType, strWindowSize);
	sprintf(g_strOutFile_OrenPrm,   "%s\\%s.%s_DailyPRM_%s%s.csv", strOutDirectory, strInFileName, strSuffix, strWindowType, strWindowSize_Oren);
	sprintf(g_strOutFile_Statistics,"%s\\%s.%s_statistics_%s_%s_%s%s.csv", strOutDirectory, strInFileName, strSuffix, strModelName, strPhotoFuncName, strWindowType, strWindowSize);
}

// ****************************************************************
//  Output data
// ****************************************************************
bool output_30hour_physiological_variable(std::vector<string>& aryDate, CData& data)
{
	bool bIsOK = true;
	FILE *fp;

	if((fp  = fopen(g_strOutPhysiologicalFile30, "wt")) == NULL){
		printf("Output file could not opened.\n");
		bIsOK = false;
		return bIsOK;
	}

	// write header
	if(g_iCanopyStructure == 0 || g_iCanopyStructure == 2){
		fprintf(fp, "Date,WUE ,LUE ,Ci_ebl ,Ci / Ca_ebl ,Vcmax_ebl ,Vcmax25_ebl ,Ci ,Ci / Ca ,gsc ,Vcmax ,Jmax ,Photosynthesis ,Traspiration ,Av ,Aj ,A_gs ,A_ga_gs ,A_ga_gs_ts\n");
		fprintf(fp, "--, umol mmol-1 ,umol umol-1 ,ppm ,-- ,mol m-2 s-1 ,umol m-2 s-1 ,ppm ,-- ,mol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,W m-2 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1\n");
	}
	else{
		fprintf(fp, "Date,WUE ,LUE ,Ci_ebl ,Ci / Ca_ebl ,Vcmax_ebl ,Vcmax25_ebl ,Ci ,Ci / Ca ,gsc ,Vcmax ,Jmax ,Photosynthesis ,Traspiration ,Av ,Aj ,A_gs ,A_ga_gs ,A_ga_gs_ts, A_sun, A_shade\n");
		fprintf(fp, "--, umol mmol-1 ,umol umol-1 ,ppm ,-- ,mol m-2 s-1 ,umol m-2 s-1 ,ppm ,-- ,mol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,W m-2 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1\n");
	}

	double dCi, dCi_Ca, dGs, dVcmax, dJmax, dPhotosynthesis, dTrasnspiration;
	double dCi_win, dCi_Ca_win, dGs_win, dVcmax_win, dJmax_win, dPhotosynthesis_win, dTrasnspiration_win, dQstar_win, dPhoto_gs_win, dPhoto_gs_ga_win, dPhoto_gs_ga_ts_win;
	double dCi_ebl, dCi_Ca_ebl, dVcmax_ebl, dVcmax25_ebl;
	double dA_sun, dA_shade, dAv_win, dAj_win;

	for(int i = 0; i < data.m_aryDate.size(); i++){
		if(data.m_aryCi[i] < 0){
			dCi = c_dError;
			dCi_Ca = c_dError;
			dGs = c_dError;
			dVcmax = c_dError;
			dJmax = c_dError;
			dPhotosynthesis = c_dError;
			dTrasnspiration = c_dError;
//			dQstar = c_dError;
		}
		else{
			dCi = data.m_aryCi[i];
			dCi_Ca = data.m_aryCi[i] / data.m_aryCO2[i];
			dGs = data.m_aryGs[i];
			dVcmax = data.m_aryVcmax[i];
			dJmax = data.m_aryJmax[i];
			dPhotosynthesis = data.m_aryPhotosynthesis[i];
			dTrasnspiration = data.m_aryTranspiration[i];
//			dQstar = data.m_aryQstar[i];
		}

		if(data.m_aryCi_window[i] < 0){
			dCi_win = c_dError;
			dCi_Ca_win = c_dError;
			dGs_win = c_dError;
			dVcmax_win = c_dError;
			dJmax_win = c_dError;
			dPhotosynthesis_win = c_dError;
			dTrasnspiration_win = c_dError;
			dQstar_win = c_dError;
			dPhoto_gs_win = c_dError;
			dPhoto_gs_ga_win = c_dError;
			dPhoto_gs_ga_ts_win = c_dError;
			dA_sun = c_dError;
			dA_shade = c_dError;
			dAv_win = c_dError;
			dAj_win = c_dError;
		}
		else{
			dCi_win = data.m_aryCi_window[i];
			dCi_Ca_win = data.m_aryCi_window[i] / data.m_aryCO2[i];
			dGs_win = data.m_aryGs_window[i];
			dVcmax_win = data.m_aryVcmax_window[i];
			dJmax_win = data.m_aryJmax_window[i];
			dPhotosynthesis_win = data.m_aryPhotosynthesis_window[i];
			dTrasnspiration_win = data.m_aryTranspiration_window[i];
			dQstar_win = data.m_aryQstar_window[i];
			dPhoto_gs_win = data.m_aryA_gs_window[i];
			dPhoto_gs_ga_win = data.m_aryA_gs_ga_window[i];
			dPhoto_gs_ga_ts_win = data.m_aryA_gs_ga_ts_window[i];
			dA_sun = data.m_aryAsun_window[i];
			dA_shade = data.m_aryAshade_window[i];
			dAv_win = data.m_aryAv_window[i];
			dAj_win = data.m_aryAj_window[i];
		}

		if(data.m_aryCi_eBL[i] < 0.0 || data.m_aryVcmax_eBL[i] < 0.0){
			dCi_ebl = c_dError;
			dCi_Ca_ebl = c_dError;
			dVcmax_ebl = c_dError;
			dVcmax25_ebl = c_dError;
		}
		else{
			dCi_ebl = data.m_aryCi_eBL[i];
			dCi_Ca_ebl = data.m_aryCi_eBL[i] / data.m_aryCO2[i];
			dVcmax_ebl = data.m_aryVcmax_eBL[i];
			dVcmax25_ebl = data.m_aryVcmax25_eBL[i];
		}

		if(g_iCanopyStructure == 0){
			fprintf(fp, "%s, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf\n", 
				data.m_aryDate[i].c_str(), 
				data.m_aryWUE[i], data.m_aryLUE[i], 
				dCi_ebl, dCi_Ca_ebl, dVcmax_ebl, dVcmax25_ebl, 
				// dCi, dCi_Ca, dGs, dVcmax, dJmax, dPhotosynthesis, dTrasnspiration, dQstar,
				dCi_win, dCi_Ca_win, dGs_win, dVcmax_win, dJmax_win, dPhotosynthesis_win, dTrasnspiration_win, dAv_win, dAj_win, dPhoto_gs_win, dPhoto_gs_ga_win, dPhoto_gs_ga_ts_win);
		}
		else{
			fprintf(fp, "%s, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf\n", 
				data.m_aryDate[i].c_str(), 
				data.m_aryWUE[i], data.m_aryLUE[i], 
				dCi_ebl, dCi_Ca_ebl, dVcmax_ebl, dVcmax25_ebl, 
				// dCi, dCi_Ca, dGs, dVcmax, dJmax, dPhotosynthesis, dTrasnspiration, dQstar,
				dCi_win, dCi_Ca_win, dGs_win, dVcmax_win, dJmax_win, dPhotosynthesis_win, dTrasnspiration_win, dAv_win, dAj_win, dPhoto_gs_win, dPhoto_gs_ga_win, dPhoto_gs_ga_ts_win,
				dA_sun, dA_shade);

		}
	}

	fclose(fp);

	return bIsOK;
}

bool output_30hour_physical_variable(CData& data)
{
	bool bIsOK = true;
	FILE *fp;

	if((fp  = fopen(g_strOutPhysicalFile30, "wt")) == NULL){
		printf("Output file could not opened.\n");
		bIsOK = false;
		return bIsOK;
	}

	// write header
	fprintf(fp, "Date,d ,z0 ,canopy_height ,ga ,ga_h ,gc ,LEeq ,LEimp ,omega ,beta ,E, Ts ,D0 ,SVP ,f ,ramda0 ,Rs_toa ,PPFD direct ,PPFD diffuse ,PPFD sun ,PPFD shade ,LAI sun ,LAI shade\n");
	fprintf(fp, "--,m ,m ,m ,m s-1 ,m s-1 ,m s-1 ,W m-2 ,W m-2 ,-- ,-- , W m-2, degree C ,hPa ,hPa ,-- ,K m2 W-1 ,W m-2 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,m2 m-2 ,m2 m-2\n");

	for(int i = 0; i < data.m_aryDate.size(); i++){
		fprintf(fp, "%s, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf\n", 
			data.m_aryDate[i].c_str(), 
			data.m_aryD[i],  data.m_aryZ0[i], data.m_aryCanopyHeight[i],
			data.m_aryGb[i], data.m_aryGb_h[i], data.m_aryGc[i], data.m_aryLE_eq[i], data.m_aryLE_imp[i], 
			data.m_aryOmega[i], data.m_aryBeta[i], data.m_aryE_soil[i], data.m_aryTs[i], data.m_aryD0[i], data.m_arySVP[i], data.m_aryF[i], data.m_aryRamda0[i], 
			data.m_aryRs_toa[i], data.m_aryPPFD_direct[i], data.m_aryPPFD_diffuse[i], data.m_aryPPFD_sun[i], data.m_aryPPFD_shade[i], 
			data.m_aryLAI_sun[i], data.m_aryLAI_shade[i]);
	}

	fclose(fp);

	return bIsOK;
}

bool output_estimated_paramters(std::vector< std::vector<double> >& aryBestParameterSet, std::vector<double>& aryBestFunction, double& dRmseGPP)
{
	bool bIsOK = true;
	FILE *fp;
	double dD0 = c_dError;

	if((fp  = fopen(g_strOutFile_AnnualPrm, "wt")) == NULL){
		printf("Output file could not opened.\n");
		bIsOK = false;
		return bIsOK;
	}

	// write header
	fprintf(fp, "Num ,Vcmax25 ,Jmax25 ,m ,b ,D0 ,RMSE_gpp ,RMSE_le \n");
	if(g_iCanopyStructure == 0){
		fprintf(fp, "Num,Vcmax25,Jmax25,Omega,m,B,D0,RMSE_gpp,RMSE_le\n");
	}
	else if(g_iCanopyStructure == 1){
		fprintf(fp, "Num,Vcmax25_sun,Jmax25_sun,Omega,m,B_sun,D0,RMSE_gpp,RMSE_le\n");
	}
	else{
		fprintf(fp, "Num,vcmax25_leaf,jmax25_leaf,Omega,m,b_leaf,D0,RMSE_gpp,RMSE_le\n");
	}
	fprintf(fp, "--,mol m-2 s-1 ,umol m-2 s-1,-- ,-- ,mol m-2 s-1 ,hPa ,umol m-2 s-1 ,W m-2\n");

	for(int i = 0; i < aryBestFunction.size(); i++){
		if(g_iLeuningModel == 1 && aryBestParameterSet[i].size() == 6){
			dD0 = aryBestParameterSet[i][5];
		}
		fprintf(fp, "%d, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf\n", 
			i, aryBestParameterSet[i][0], aryBestParameterSet[i][0] * aryBestParameterSet[i][1], aryBestParameterSet[i][2], aryBestParameterSet[i][3], aryBestParameterSet[i][4], dD0, dRmseGPP, aryBestFunction[i]);
	}

	fclose(fp);

	return bIsOK;
}

bool output_estimated_paramters_window(std::vector< std::vector<double> >& aryBestParametersWindow, std::vector< std::vector<double> >& aryStdevParametersWindow, std::vector< std::vector<double> >& aryRMSE, std::vector<double>& aryAnnualBestPrm, std::vector<double>& aryAnnualBestPrmStdev, double& dRmseGPP, double& dRmseLE)
{
	bool bIsOK = true;
	FILE *fp;

	double dVcmax_stdev, dJmax_stdev, dOmega_stdev, dBM_stdev, dBB_stdev, dD0_stdev, dD0_bset;
	double dJmax_best, dJmax_best_annual;
	double dRMSE_photosynthesis, dRMSE_et;

	if((fp  = fopen(g_strOutFile_WindowPrm, "wt")) == NULL){
		printf("Output file could not opened.\n");
		bIsOK = false;
		return bIsOK;
	}

	// write header
	if(g_iCanopyStructure == 0){
		fprintf(fp, "Date,Vcmax25,Jmax25,Omega,m,B,D0,Vcmax25_std,Jmax25_std,Omega_std,m_std,b_std,D0_std,RMSE_gpp,RMSE_le\n");
	}
	else if(g_iCanopyStructure == 1){
		fprintf(fp, "Date,Vcmax25,Jmax25,Omega,m,B,D0,Vcmax25_std,Jmax25_std,Omega_std,m_std,b_std,D0_std,RMSE_gpp,RMSE_le\n");
	}
	else{
		fprintf(fp, "Date,vcmax25_sun_leaf,jcmax25_sun_leaf,Omega,m,b_sun_leaf,D0,vcmax25_std,jmax25_std,Omega_std,m_std,b_std,D0_std,RMSE_gpp,RMSE_le\n");
	}
	fprintf(fp, "--,umol m-2 s-1 ,umol m-2 s-1 ,--, -- ,mol m-2 s-1 ,hPa ,mol m-2 s-1 ,umol m-2 s-1 ,-- ,-- ,mol m-2 s-1 ,hPa ,umol m-2 s-1 ,W m-2\n");

	for(int i = 0; i < aryBestParametersWindow.size(); i++){
		dVcmax_stdev = aryStdevParametersWindow[i][0];
		dOmega_stdev = aryStdevParametersWindow[i][2];
		dBM_stdev = aryStdevParametersWindow[i][3];
		dBB_stdev = aryStdevParametersWindow[i][4];
		dD0_stdev = aryStdevParametersWindow[i][5];
		dD0_bset = aryBestParametersWindow[i][5];

		if(aryBestParametersWindow[i][1] != c_dError){
			dJmax_best = aryBestParametersWindow[i][0] * aryBestParametersWindow[i][1];
			dJmax_stdev = aryStdevParametersWindow[i][0] * aryStdevParametersWindow[i][1];
		}
		else{
			dJmax_best = aryBestParametersWindow[i][1];
			dJmax_stdev = aryStdevParametersWindow[i][1];
		}

		if(g_iLeuningModel != 1){
			dD0_bset = c_dError;
			dD0_stdev = c_dError;
		}

		dRMSE_photosynthesis = aryRMSE[i][0];
		if(dRMSE_photosynthesis == -c_dError) dRMSE_photosynthesis = c_dError;
		dRMSE_et = aryRMSE[i][1];
		if(dRMSE_et == -c_dError) dRMSE_et = c_dError;

		if(dVcmax_stdev == 0.1 && dBM_stdev == 0.1 && dBB_stdev == 0.1){
			fprintf(fp, "%d, %lf, %lf, %lf, %lf, %lf, %lf, --, --, --, --, --, --, %lf, %lf\n", 
				i, aryBestParametersWindow[i][0], dJmax_best, aryBestParametersWindow[i][2], aryBestParametersWindow[i][3], aryBestParametersWindow[i][4], dD0_bset,
				dRMSE_photosynthesis, dRMSE_et);

		}
		else{
			fprintf(fp, "%d, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf\n", 
				i + 1, aryBestParametersWindow[i][0], dJmax_best, aryBestParametersWindow[i][2], aryBestParametersWindow[i][3], aryBestParametersWindow[i][4], aryBestParametersWindow[i][5], 
				dVcmax_stdev, dJmax_stdev, dOmega_stdev, dBM_stdev, dBB_stdev, dD0_stdev,
				dRMSE_photosynthesis, dRMSE_et);
		}
	}

	dRMSE_photosynthesis = dRmseGPP;
	if(dRMSE_photosynthesis == -c_dError) dRMSE_photosynthesis = c_dError;
	dRMSE_et = dRmseLE;
	if(dRMSE_et == -c_dError) dRMSE_et = c_dError;

	dJmax_best_annual = aryAnnualBestPrm[0] * aryAnnualBestPrm[1];
	if(g_iLeuningModel != 1){
		dD0_bset = c_dError;
		dD0_stdev = c_dError;
	}
	else{
		dD0_bset = aryAnnualBestPrm[5];
		dD0_stdev = aryAnnualBestPrmStdev[5];
	}

	if(aryAnnualBestPrmStdev[0] == c_dError){
		fprintf(fp, "Annual, %lf, %lf, %lf, %lf, %lf, %lf, --, --, --, --, --, --, %lf, %lf\n", 
				aryAnnualBestPrm[0], dJmax_best_annual, aryAnnualBestPrm[2], aryAnnualBestPrm[3], aryAnnualBestPrm[4],  dD0_bset,  dRMSE_photosynthesis, dRMSE_et);
	}
	else{
		fprintf(fp, "Annual, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf\n", 
				aryAnnualBestPrm[0], dJmax_best_annual, aryAnnualBestPrm[2], aryAnnualBestPrm[3], aryAnnualBestPrm[4], dD0_bset, 
				aryAnnualBestPrmStdev[0], aryAnnualBestPrmStdev[0] * aryAnnualBestPrmStdev[1], aryAnnualBestPrmStdev[2], aryAnnualBestPrmStdev[3], aryAnnualBestPrmStdev[4], dD0_stdev, dRMSE_photosynthesis, dRMSE_et);
	}

	fclose(fp);

	return bIsOK;
}

bool output_leaf_paramters_window(CDailyData& daily)
{
	bool bIsOK = true;
	FILE *fp;

	if((fp  = fopen(g_strOutFile_LeafPrm, "wt")) == NULL){
		printf("Output file could not opened.\n");
		bIsOK = false;
		return bIsOK;
	}

	// write header
	fprintf(fp, "Date ,FPAR ,LAI_sun ,LAI_shade ,Vcmax25 ,Vcmax25_sun ,Vcmax25_shade ,vcmax25_leaf ,vcmax25_sun_leaf ,vcmax25_shade_leaf ,Jmax25 ,Jmax25_sun ,Jmax25_shade ,jmax25_leaf ,jmax25_sun_leaf ,jmax25_shade_leaf ,m ,B ,B_sun ,B_shade ,b_leaf ,b_sun_leaf ,b_shade_leaf ,Weight_sun ,Weight_shade ,Kn\n");
	fprintf(fp, "--,-- ,m2 m-2 ,m2 m-2 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,umol m-2 s-1 ,-- ,mol m-2 s-1 ,mol m-2 s-1 ,mol m-2 s-1 ,mol m-2 s-1 ,mol m-2 s-1 ,mol m-2 s-1 ,-- ,-- ,--\n");

	for(int i = 0; i < daily.m_aryFPAR.size(); i ++){
		fprintf(fp, "%d, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf\n", 
			i + 1, daily.m_aryFPAR[i], daily.m_aryLAI_sun[i], daily.m_aryLAI_shade[i],
			daily.m_aryVcmax25[i], daily.m_aryVcmax25_sun[i], daily.m_aryVcmax25_shade[i], daily.m_aryVcmax25_leaf[i], daily.m_aryVcmax25_sun_leaf[i], daily.m_aryVcmax25_shade_leaf[i],
			daily.m_aryJmax25[i], daily.m_aryJmax25_sun[i], daily.m_aryJmax25_shade[i], daily.m_aryJmax25_leaf[i], daily.m_aryJmax25_sun_leaf[i], daily.m_aryJmax25_shade_leaf[i],
			daily.m_aryM_bb[i], daily.m_aryB_bb[i], daily.m_aryB_bb_sun[i], daily.m_aryB_bb_shade[i], daily.m_aryB_bb_leaf[i], daily.m_aryB_bb_sun_leaf[i], daily.m_aryB_bb_shade_leaf[i],
			daily.m_aryWeight_sun[i], daily.m_aryWeight_shade[i], daily.m_aryKn[i]/*, daily.m_aryOmega[i]*/);
	}

	fclose(fp);

	return bIsOK;
}

bool output_daily_paramters_window(CDailyData& daily)
{
	bool bIsOK = true;
	FILE *fp;

	if((fp  = fopen(g_strOutFile_OrenPrm, "wt")) == NULL){
		printf("Output file could not opened.\n");
		bIsOK = false;
		return bIsOK;
	}

	// write header
	fprintf(fp, "Date ,WUE ,LUE ,canopy_height ,d ,z0 ,stand_density ,gs_ref ,m ,R2 \n");
	fprintf(fp, "--, umol mmol-1,  umol umol-1, m, m, m, trees ha-1, mmol m-2 s-1, mmol m-2 s-1 ln(kPa)-1, --\n");

	for(int i = 0; i < daily.m_aryGs_ref.size() - 1; i ++){
		fprintf(fp, "%d, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf\n", 
			i + 1, daily.m_aryWUE[i], daily.m_aryLUE[i], daily.m_aryCanopyHeight[i], daily.m_aryD[i], daily.m_aryZ0[i], daily.m_aryStandDensity[i],
			daily.m_aryGs_ref[i], daily.m_aryM[i], daily.m_aryR2_Oren[i]);
	}

	fprintf(fp, "Annual, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf\n", 
			daily.m_aryWUE[daily.m_aryGs_ref.size() - 1], daily.m_aryLUE[daily.m_aryGs_ref.size() - 1], 
			daily.m_aryCanopyHeight[daily.m_aryGs_ref.size() - 1], daily.m_aryD[daily.m_aryGs_ref.size() - 1], daily.m_aryZ0[daily.m_aryGs_ref.size() - 1], daily.m_aryStandDensity[daily.m_aryGs_ref.size() - 1],
			daily.m_aryGs_ref[daily.m_aryGs_ref.size() - 1], daily.m_aryM[daily.m_aryGs_ref.size() - 1], daily.m_aryR2_Oren[daily.m_aryGs_ref.size() - 1]);

	fclose(fp);

	return bIsOK;
}

bool output_statistics(const CStatistics& cStatistics_GPP, const CStatistics& cStatistics_LE)
{
	bool bIsOK = true;
	FILE *fp;

	if((fp  = fopen(g_strOutFile_Statistics, "wt")) == NULL){
		printf("Output statistics file could not opened.\n");
		bIsOK = false;
		return bIsOK;
	}

	// for GPP
	fprintf(fp, "GPP statistics\n");
	fprintf(fp, "Slope m_vs_o ,Offset m_vs_o ,R ,Slope0 m_vs_o ,R2 0 m_vs_o ,Slope o_vs_m ,Offset o_vs_m ,R ,Slope0 o_vs_m ,R2 0 o_vs_m ,RMSE ,ME ,Num\n");
	fprintf(fp, "--,umol m-2 s-1 ,-- ,-- ,umol m-2 s-1 ,-- ,-- ,-- ,umol m-2 s-1 ,umol m-2 s-1 ,n\n");
	fprintf(fp, "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%d\n\n",
			cStatistics_GPP.dSlopeA, 
			cStatistics_GPP.dOffsetA,
			cStatistics_GPP.dR, 
			cStatistics_GPP.dSlope0A,
			cStatistics_GPP.dR20a, 
			cStatistics_GPP.dSlopeB, 
			cStatistics_GPP.dOffsetB, 
			cStatistics_GPP.dR, 
			cStatistics_GPP.dSlope0B, 
			cStatistics_GPP.dR20b, 
			cStatistics_GPP.dRMSE, 
			cStatistics_GPP.dME, 
			cStatistics_GPP.iNumber);

	// for LE
	fprintf(fp, "LE statistics\n");
	fprintf(fp, "Slope m_vs_o, Offset m_vs_o, R, Slope0 m_vs_o,  R2 0 m_vs_o, Slope o_vs_m, Offset o_vs_m, R, Slope0 o_vs_m,  R2 0 o_vs_m, RMSE, ME, Num\n");
	fprintf(fp, "--, W m-2, --, --, W m-2, --, --,  --, W m-2, W m-2, n\n");
	fprintf(fp, "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%d\n",
			cStatistics_LE.dSlopeA, 
			cStatistics_LE.dOffsetA,
			cStatistics_LE.dR, 
			cStatistics_LE.dSlope0A,
			cStatistics_LE.dR20a, 
			cStatistics_LE.dSlopeB, 
			cStatistics_LE.dOffsetB, 
			cStatistics_LE.dR, 
			cStatistics_LE.dSlope0B, 
			cStatistics_LE.dR20b, 
			cStatistics_LE.dRMSE, 
			cStatistics_LE.dME, 
			cStatistics_LE.iNumber);

	
	fclose(fp);

	return bIsOK;
}

void radiation_transfer(CData& data, CDailyData& daily)
{
	// radiative transfer model for sun / shade partitioning
	// de Pury and Farquhar (1997) Simple scaling of photosynthesis from leaves to canopies without the errors of big-leaf models
	//    Plant, Cell and Environment, 20, 537-557.
	// Wang and Leuning (1998) A two-leaf model for canopy conductance, photosynthesis and partitioning of available energy I: model description and comparison with a multi-layered model
	//    Agricultural and Forest Meteorology, 91, 89-111.
	// Weiss and Norman (1985) Partitioning solar radiation into direct and diffuse, visible and infrared components
	//    Agricultural and Forest Meteorology, 34, 205-213.
	double dDate, dHour;
	double dPPFD_obs;					// observed PPFD (umol m-2 s-1)
	double dSolarDeclinationAngle;		// solar declination angle (radian)
	double dDayAngle;					// day angle (radian)
	double dEquationTime;				// equation of time (radian)
	double dSolarNoon;					// solar noon (radian) 
	double dLongitudeFraction;			// difference of longitude between local and standard time (degree)
	double dLongitudeStandard;			// longitude of international standard time (degree)
	double dHourAngle;					// hour angle (hour)
	double dSolarElevationAngle;		// solar elevation anagle (radian)
	double dBeta;						// beta (radian)
	double dTheta;						// theta (radian)
	double dTheta_degree;				// theta (degree)
	double dP_P0;						// ratio of atmospheric pressure to sea level pressure
	double dPAR_direct;					// direct PAR (W m-2)	(Eq. 1 in Weiss and Norman, 1985)
	double dPAR_diffuse;				// diffuse PAR (W m-2)	(Eq. 3 in Weiss and Norman, 1985)
	double dPAR;						// PAR (W m-2)
	double dPPFD;						// PPFD (umol m-2 s-1)
	double dRatio;						// ratio of geometric to observed PPFD
	double dDirectFraction;				// Direct fraction (--)
	double dDiffuseFraction;			// Diffuse fraction (--)
	double dKb;							// extinction coefficient of a canopy of black leaves for direct beam radiation (Wang and Leuning, 1998AFM)
	double dKb2;						// extinction coefficient
	double dWeight_direct;				// W1 : weighting factor of direct beam		(Wang and Leuning, 1998AFM)
	double dWeight_diffuse;				// W2 : weighting factor of diffuse beam	(Wang and Leuning, 1998AFM)
	double dLAI_direct;					// L1 : leaf area index for direct beam		(Wang and Leuning, 1998AFM)
	double dLAI_diffuse;				// L2 : leaf area index for diffuse beam	(Wang and Leuning, 1998AFM)
	double dRow_cb;						// relfectance of beam irradiance, uniform leaf-angle distribution (A19; de Pury and Farquhar, 1997PCE)
	double dRow_cd;						// relfectance of diffuse irradiance, uniform leaf-angle distribution
	double dPAR_direct_sun;				// direct PAR absorbed by the sunlit leaf (umol m-2 s-1) (Eq. 20b; de Pury and Farquhar, 1997PCE)
	double dPAR_diffuse_sun;			// diffuse PAR absorbed by the sunlit leaf (umol m-2 s-1) (Eq. 20c; de Pury and Farquhar, 1997PCE)
	double dPAR_scatter_sun;			// scattered PAR absorbed by the sunlit leaf (umol m-2 s-1) (Eq. 20d; de Pury and Farquhar, 1997PCE)
	double dPAR_sun;					// PAR absorbed by the sunlit leaf (umol m-2 s-1) (Eq. 20a; de Pury and Farquhar, 1997PCE)
	double dPAR_diffuse_shade;			// diffuse PAR absorbed by the shaded leaf (umol m-2 s-1) (Eq. A26b; de Pury and Farquhar, 1997PCE)
	double dPAR_scatter_shade;			// scatter PAR absorbed by the shaded leaf (umol m-2 s-1) (Eq. A26c; de Pury and Farquhar, 1997PCE)
	double dPAR_shade;					// PAR absorbed by the shaded leaf (umol m-2 s-1) (Eq. A26a; de Pury and Farquhar, 1997PCE)
	double dAPAR;						// abosrbed PAR (umol m-2 s-1)
	double dPAR_ref;					// reflected PAR (umol m-2 s-1)
	double dTPAR;						// transmitted PAR (umol m-2 s-1)
	double dFPAR;						// fraction of absorbed PAR (FPAR) (no dimension)
	double dG;							// calculating G function defined as the projection coefficient of foliage area on the plane perpendicular to the view direciton (--)
	double dR_Rs;                       // geocentric solar distance
	double dRs_toa;						// solar radiation at the top of the atmosphere (W m-2)
	double dPAR_upward_sun;				// absrobed PAR by sun leaf from that reflected PAR by soil (umol m-2 s-1)
	double dPAR_upward_shade;			// absrobed PAR by shade leaf from that reflected PAR by soil (umol m-2 s-1)

	// for NIR radiative transfer
	double dNIR_direct;					// direct NIR (W m-2)
	double dNIR_diffuse;				// diffuse NIR (W m-2)
	double dNIR_direct_sun;				// direct NIR absorbed by the sunlit leaf (W m-2)
	double dNIR_diffuse_sun;			// diffuse NIR absorbed by the sunlit leaf (W m-2)
	double dNIR_scatter_sun;			// scattered NIR absorbed by the sunlit leaf (W m-2)
	double dNIR_sun;					// NIR absorbed by the sunlit leaf (W m-2)
	double dNIR_shade;					// NIR absorbed by the shaded leaf (W m-2)
	double dNIR_soil;					// NIR absorbed by bare soil (W m-2)
	double dPAR_soil;					// PAR absorbed by bare soil (W m-2)
	double dRow_nir_cb;					// relfectance of beam irradiance, uniform leaf-angle distribution (NIR) (--)
	double dRow_nir_cd;					// relfectance of diffuse irradiance, uniform leaf-angle distribution (NIR) (--)
	double dTransmittedSW;				// fraction of transmitted shortwave radiation into bare soil (--)
	double dDirectFraction_nir;			// Direct fraction for NIR (--)
	double dKb_nir;						// extinction coefficient for direct NIR (Eq. 12 in Ryu et al. 2011GBC)
	double dKd_nir;						// extinction coefficient for diffuse NIR (Eq. 13 in Ryu et al. 2011GBC)

	// for multi-layer model	
	double dWeight_direct_top;			// W1 : weighting factor of direct beam at the top layer
	double dLAI_top;					// LAI at the top layer

	vector<double> aryPAR_sun;
	vector<double> aryPAR_shade;
	vector<double> aryLAI_sun;
	vector<double> aryLAI_shade;
	vector<double> aryWeight_sun;
	vector<double> aryWeight_shade;

	const double c_dSolarConst = 1367.0;	// solar constant (W m-2)
	const double c_dRatio_PAR_to_SW = 0.45;	// contribution of PAR in shortwave radiation (--)
	const double c_dPAR_to_PPFD = 4.58;		// conversion factor from W m-2 to umol m-2 s-1

	// beam irradiance, horizontal leaves
	double g_Row_h_par = (1.0 - sqrt( 1.0 - g_dSigma_scattering) ) / ( 1.0 + sqrt( 1.0 - g_dSigma_scattering) );	
	double g_Row_h_nir = (1.0 - sqrt( 1.0 - g_dLeaf_scattering_nir) ) / ( 1.0 + sqrt( 1.0 - g_dLeaf_scattering_nir) );
	
	// nitrogen redistribution factor
	double dKn = 0.2;
	if(g_dKn > 0.0){
		dKn = g_dKn;
	}

	// ********************************************
	// calculating half-hourly variables
	// ********************************************
	// international standard meridians are multiples of 15 degree east or west of Greenwich, U<
	dLongitudeFraction = fmod ( g_dLongitude, 15.0);
	if( fabs(dLongitudeFraction) > 15.0 / 2.0){
		dLongitudeStandard = fabs(g_dLongitude) + (15.0 - fabs(dLongitudeFraction));
	}
	else{
		dLongitudeStandard = fabs(g_dLongitude) - fabs(dLongitudeFraction);
	}
	if(dLongitudeFraction < 0.0) dLongitudeStandard *= -1.0;

	// latitude of radian
	const double dLatitude_radian = g_dLatitude * c_dPI / 180.0;

	// zenith angle
	const double dZenithAngle = 90.0 / 180.0 * c_dPI;

	for(int i = 0; i < data.m_aryDate.size(); i++){
		dDate = data.m_aryDate_double[i];
		dPPFD_obs = data.m_aryPPFD[i];
		if(dPPFD_obs < 0.0) dPPFD_obs = 0.0;

		if(data.m_aryDate_double[i] > 15.49){
			double dd = 0.0;
		}

		// hour
		dHour = (dDate - int(dDate) ) * 24;

		// solar declination angle (radian)
		dSolarDeclinationAngle = -23.4 * c_dPI / 180.0 * cos(2.0 * c_dPI * (int(dDate) + 10.0) / 365.0 );

		// day angle (radian)
		dDayAngle = 2.0 * c_dPI * int(dDate - 1.0) / 365.0;

		// equation of time (radian)
		dEquationTime = 0.017 + 0.4281 * cos(dDayAngle) - 7.351 * sin(dDayAngle) - 3.349 * cos( 2.0 * dDayAngle ) - 9.731 * sin(dDayAngle);

		// solar noon (radian)
		dSolarNoon = 12.0 + ( 4.0 * ( dLongitudeStandard - g_dLongitude ) - dEquationTime ) / 60.0;

		// hour angle (hour)
		dHourAngle = c_dPI * ( dHour - dSolarNoon ) / 12.0;

		// solar elevation anagle
		dSolarElevationAngle = sin(dLatitude_radian) * sin(dSolarDeclinationAngle) + cos(dLatitude_radian) * cos(dSolarDeclinationAngle) * cos(dHourAngle);

		// β
		dBeta = asin(dSolarElevationAngle);

		// θ
		dTheta = dZenithAngle - dBeta;

		// calculating G function defined as the projection coefficient of foliage area on the plane perpendicular to the view direciton
		// de Wit, C. T. (1965) Photosynthesis of Leaf Canopies. Agricultural Research Report no. 663, Wageningen.
		dTheta_degree = dTheta * 180.0 / c_dPI;
		get_G_function(dG, dTheta_degree, g_iShape);

		// ratio of atmospheric pressure to sea level pressure
		dP_P0 = pow((1.0 - 0.0065 * g_dElevation / (data.m_aryTa[i] + 273.15 ) ), 5.258);

		// geocentric solar distance
		dR_Rs = 1.0 /pow(1.00011 + 0.034221 * cos(dDayAngle) + 0.00128 * sin(dDayAngle) + 0.000719 * cos(2.0 * dDayAngle) + 0.000077 * sin(2.0 * dDayAngle), 0.5);

		// solar radiation at the top of the atmosphere
		dRs_toa = c_dSolarConst * sin(dBeta) * dR_Rs * dR_Rs;
		if(c_dSolarConst * sin(dBeta) * dR_Rs * dR_Rs < 0.0){
			dRs_toa = 0.0;
		}
		data.m_aryRs_toa[i] = dRs_toa;

		// direct PAR (W m-2)	(Eq. 1 in Weiss and Norman, 1985)
		dPAR_direct = 600.0 * exp( -0.185 * dP_P0 * 1.0 / cos(dTheta) ) * cos(dTheta);
		if(dBeta < 0.0){
			dPAR_direct = 0.0;
		}

		// diffuse PAR (W m-2)	(Eq. 3 in Weiss and Norman, 1985)
		dPAR_diffuse = 0.4 * (600.0 - dPAR_direct) * cos(dTheta);
		if(dBeta < 0.0){
			dPAR_diffuse = 0.0;
		}

		// PAR (W m-2)
		dPAR = dPAR_direct + dPAR_diffuse;

		// PPFD (umol m-2 s-1)
		dPPFD = dPAR * c_dPAR_to_PPFD;

		// Ratio
		if(dPPFD == 0.0){
			dRatio = 0.0;
		}
		else{
			dRatio = dPPFD_obs / dPPFD;
		}
		if(dRatio > 0.99) dRatio = 0.99;
		if(dRatio < 0.00) dRatio = 0.0;

		// Direct fraction (--)
		if(dPAR == 0.0){
			dDirectFraction = 0.0;
			dDirectFraction_nir = 0.0;
		}
		else{
			if(dRatio > 0.9){
				dDirectFraction = dPAR_direct / dPAR;
			}
			else{
				if(pow((0.9 - dRatio) / 0.7, 2.0 / 3.0) > 1.0){
					dDirectFraction = 0.0;
				}
				else{
					dDirectFraction = dPAR_direct / dPAR * ( 1.0 - pow((0.9 - dRatio) / 0.7, 2.0 / 3.0) );
				}
			}
			if(dRatio > 0.88){
				dDirectFraction_nir = dDirectFraction;
			}
			else{
				if(pow((0.88 - dRatio) / 0.68, 2.0 / 3.0) > 1.0){
					dDirectFraction_nir = dDirectFraction;
				}
				else{
					dDirectFraction_nir = dPAR_direct / dPAR * ( 1.0 - pow((0.88 - dRatio) / 0.68, 2.0 / 3.0) );
				}
			}
		}
		data.m_aryPPFD_direct[i] = dPPFD_obs * dDirectFraction;

		// Diffuse fraction (--)
		dDiffuseFraction = 1.0 - dDirectFraction;
		data.m_aryPPFD_diffuse[i] = dPPFD_obs - data.m_aryPPFD_direct[i];

		// kb : extinction coefficient of a canopy of black leaves for direct beam radiation (Wang and Leuning, 1998AFM)
		dKb = ( 0.5 - ( 0.633 - 1.11 * cos(dTheta) ) * g_dKai - ( 0.33 - 0.579 * cos(dTheta) ) * g_dKai * g_dKai) / cos(dTheta);
		dKb = dG / cos(dTheta);

//		if(dKb > 10.0) dKb = 10.0;
		if(dKb <  0.0) dKb = 0.0;
		dKb2 = 0.46 / sin(dBeta);

		// NIR radiation
		dNIR_direct = dPPFD_obs / c_dRatio_PAR_to_SW * (1.0 - c_dRatio_PAR_to_SW) * dDirectFraction_nir;
		dNIR_diffuse = dPPFD_obs / c_dRatio_PAR_to_SW * (1.0 - c_dRatio_PAR_to_SW) - dNIR_direct;
		dNIR_direct /= c_dPAR_to_PPFD;
		dNIR_diffuse /= c_dPAR_to_PPFD;
		dKb_nir = dKb * sqrt(1.0 - g_dLeaf_scattering_nir);		// Eq. 12 in Ryu et al (2011 GBC)
		dKd_nir = 0.35 * sqrt(1.0 - g_dLeaf_scattering_nir);	// Eq. 13 in Ryu et al (2011 GBC)

		// W1 : weighting factor of direct beam  (Eq. C6 in Wang and Leuning, 1998AFM)
//		dWeight_direct = (1.0 - exp(-( dKb + data.m_aryKn[i] )            * data.m_aryLAI[i] ) ) / ( dKb + data.m_aryKn[i] );
//■		dWeight_direct = (1.0 - exp(-( dKb + data.m_aryKn[i] ) * g_dOmega * data.m_aryLAI[i] ) ) / ( dKb + data.m_aryKn[i] );

		// de Pury and Farquhar (1997) Eq. 22 devided by Eq. 15
		dWeight_direct = g_dOmega * ( 1.0 - exp(-dKn - dKb *  g_dOmega * data.m_aryLAI[i]) ) / (dKn + dKb *  g_dOmega * data.m_aryLAI[i]);
//		dWeight_direct = ( 1.0 - exp(-dKn - dKb *  g_dOmega * data.m_aryLAI[i]) ) / (dKn + dKb *  g_dOmega * data.m_aryLAI[i]);
		dWeight_direct /= (1.0 - exp(-dKn) ) / dKn;
		data.m_aryWeight_sun[i] = dWeight_direct;		

		if(data.m_aryLAI[i] > g_dMultiLayerSplit){
			dLAI_top = g_dMultiLayerSplit;
		}
		else{
			dLAI_top = data.m_aryLAI[i];
		}
		dWeight_direct_top = g_dOmega * ( 1.0 - exp(-dKn - dKb *  g_dOmega * dLAI_top) ) / (dKn + dKb *  g_dOmega * dLAI_top);
		dWeight_direct_top /= (1.0 - exp(-dKn) ) / dKn;
//		data.m_aryWeight_sun_top[i] = dWeight_direct_top;

		// W2 : weighting factor of diffuse beam  (Eq. C7 in Wang and Leuning, 1998AFM)
//		dWeight_diffuse = (1.0 - exp( -dKn            * data.m_aryLAI[i] ) ) / dKn - dWeight_direct;
//		dWeight_diffuse = (1.0 - exp( -dKn * g_dOmega * data.m_aryLAI[i] ) ) / dKn - dWeight_direct;
		dWeight_diffuse = 1.0 - dWeight_direct;
		data.m_aryWeight_shade[i] = dWeight_diffuse;

		// L1 : leaf area index for direct beam (Eq. C8 in Wang and Leuning, 1998AFM)
		if(dKb == 0.0){
			dLAI_direct = 0.0;
		}
		else{
			dLAI_direct = (1.0 - exp( -dKb * g_dOmega * data.m_aryLAI[i]) ) / dKb;
		}
		data.m_aryLAI_sun[i] = dLAI_direct;

		// L2 : leaf area index for diffuse beam (Eq. C9 in Wang and Leuning, 1998AFM)
		dLAI_diffuse = data.m_aryLAI[i] - dLAI_direct;
		data.m_aryLAI_shade[i] = dLAI_diffuse;

		// relfectance of beam irradiance, uniform leaf-angle distribution (A19; de Pury and Farquhar, 1997PCE)
		dRow_cb = 1.0 - exp( -2.0 * g_Row_h_par * dKb / (1.0 + dKb) ) ;

		// relfectance of diffuse irradiance, uniform leaf-angle distribution (A19; de Pury and Farquhar, 1997PCE)
		dRow_cd = 1.0 - exp( -2.0 * g_Row_h_par * g_dKdd / ( 1.0 + g_dKdd ) );

		// direct PAR absorbed by the sunlit leaf (umol m-2 s-1) (Eq. 20b; de Pury and Farquhar, 1997PCE)
		// dPAR_direct_sun = data.m_aryPPFD_direct[i] * ( 1.0 - g_dSigma_scattering ) * ( 1.0 - exp( -dKb * data.m_aryLAI[i] ) );
		dPAR_direct_sun = data.m_aryPPFD_direct[i] * ( 1.0 - g_dSigma_scattering ) * ( 1.0 - exp( -dKb * g_dOmega * data.m_aryLAI[i] ) );

		// diffuse PAR absorbed by the sunlit leaf (umol m-2 s-1) (Eq. 20c; de Pury and Farquhar, 1997PCE)
		// dPAR_diffuse_sun = data.m_aryPPFD_diffuse[i] * ( 1.0 - dRow_cd )            * ( 1.0 - exp( -( g_dKdd + dKb )            * data.m_aryLAI[i] ) ) * g_dKdd / ( g_dKdd + dKb ) ;
		dPAR_diffuse_sun = data.m_aryPPFD_diffuse[i] * ( 1.0 - dRow_cd ) * g_dOmega * ( 1.0 - exp( -( g_dKdd + dKb ) * g_dOmega * data.m_aryLAI[i] ) ) * g_dKdd / ( g_dKdd + dKb ) ;

		// scattered PAR absorbed by the sunlit leaf (umol m-2 s-1) (Eq. 20d; de Pury and Farquhar, 1997PCE)
		if(dKb == 0.0){
			dPAR_scatter_sun = 0.0;
		}
		else{
			// dPAR_scatter_sun = data.m_aryPPFD_direct[i]            * ( ( 1.0 - dRow_cb ) * ( 1.0 - exp( -( dKb2 + dKb )            * data.m_aryLAI[i] ) ) * dKb2 / ( dKb2 + dKb )-( 1.0 - g_dSigma_scattering ) * ( 1.0 - exp( -2.0 * dKb *            data.m_aryLAI[i] ) ) / 2.0);
			dPAR_scatter_sun = data.m_aryPPFD_direct[i] * g_dOmega * ( ( 1.0 - dRow_cb ) * ( 1.0 - exp( -( dKb2 + dKb ) * g_dOmega * data.m_aryLAI[i] ) ) * dKb2 / ( dKb2 + dKb )-( 1.0 - g_dSigma_scattering ) * ( 1.0 - exp( -2.0 * dKb * g_dOmega * data.m_aryLAI[i] ) ) / 2.0);
		}

		// PAR absorbed by the sunlit leaf (umol m-2 s-1) (Eq. 20a; de Pury and Farquhar, 1997PCE)
		dPAR_sun = dPAR_direct_sun + dPAR_diffuse_sun + dPAR_scatter_sun;

		
		// diffuse PAR absorbed by the shaded leaf (umol m-2 s-1) (Eq. A26b; de Pury and Farquhar, 1997PCE)
		// dPAR_diffuse_shade = data.m_aryPPFD_diffuse[i] * ( 1.0 - dRow_cd ) * (  1.0 - exp( -g_dKdd            * data.m_aryLAI[i] )   - ( 1.0 - exp( -( g_dKdd + dKb )            * data.m_aryLAI[i] ) ) * g_dKdd            / ( g_dKdd + dKb ) );
		dPAR_diffuse_shade = data.m_aryPPFD_diffuse[i] * ( 1.0 - dRow_cd ) * ( (1.0 - exp( -g_dKdd * g_dOmega * data.m_aryLAI[i] ) ) - ( 1.0 - exp( -( g_dKdd + dKb ) * g_dOmega * data.m_aryLAI[i] ) ) * g_dKdd * g_dOmega / ( g_dKdd + dKb ) );

		// scatter PAR absorbed by the shaded leaf (umol m-2 s-1) (Eq. A26c; de Pury and Farquhar, 1997PCE)
		if(dKb == 0.0){
			dPAR_scatter_shade = 0.0;
		}
		else{
			//dPAR_scatter_shade = data.m_aryPPFD_direct[i];
			//dPAR_scatter_shade *= ( ( 1.0 - dRow_cb ) * (   1.0 - exp( -dKb2            * data.m_aryLAI[i] )   - ( 1.0 - exp( -( dKb2 + dKb )            * data.m_aryLAI[i] ) ) * dKb2            / ( dKb2 + dKb ) ) - ( 1.0 - g_dSigma_scattering ) * (   1.0 - exp( -dKb            * data.m_aryLAI[i] )   - ( 1.0 - exp( -2.0 * dKb            * data.m_aryLAI[i] ) )            / 2.0 ) ) ;
			dPAR_scatter_shade = data.m_aryPPFD_direct[i];
			dPAR_scatter_shade *= ( ( 1.0 - dRow_cb ) * (  (1.0 - exp( -dKb2 * g_dOmega * data.m_aryLAI[i] ) ) - ( 1.0 - exp( -( dKb2 + dKb ) * g_dOmega * data.m_aryLAI[i] ) ) * dKb2 * g_dOmega / ( dKb2 + dKb ) ) - ( 1.0 - g_dSigma_scattering ) * (  (1.0 - exp( -dKb * g_dOmega * data.m_aryLAI[i] ) ) - ( 1.0 - exp( -2.0 * dKb * g_dOmega * data.m_aryLAI[i] ) ) * g_dOmega / 2.0 ) ) ;
		}
		if(dPAR_scatter_shade < 0.0) dPAR_scatter_shade = 0.0;

		// reflected PAR (umol m-2 s-1)
		dPAR_ref = dRow_cb * data.m_aryPPFD_direct[i] * ( 1.0 - exp( -dKb2            * data.m_aryLAI[i] ) ) + dRow_cd * data.m_aryPPFD_diffuse[i] * ( 1.0 - exp( -g_dKdd            * data.m_aryLAI[i] ) );

		// PAR absorbed by the shaded leaf (umol m-2 s-1) (Eq. A26a; de Pury and Farquhar, 1997PCE)
		dPAR_shade = dPAR_diffuse_shade + dPAR_scatter_shade;

		// absrobed PAR by sun leaf from that reflected PAR by soil (umol m-2 s-1) (Ryu et al., 2011GBC)
		dPAR_upward_sun = data.m_aryPPFD_direct[i] * ( 1.0 - g_dSigma_scattering ) + data.m_aryPPFD_diffuse[i] * ( 1.0 - dRow_cd ) - (dPAR_sun + dPAR_shade);
		dPAR_upward_sun *= g_dSoilReflectance_ppfd * exp( - dKb * g_dOmega * data.m_aryLAI[i]);

		dPAR_sun += dPAR_upward_sun;
		data.m_aryPPFD_sun[i] = dPAR_sun;
	
		// absrobed PAR by shade leaf from that reflected PAR by soil (umol m-2 s-1) (Ryu et al., 2011GBC)
		dPAR_upward_shade = data.m_aryPPFD_direct[i] * ( 1.0 - g_dSigma_scattering ) + data.m_aryPPFD_diffuse[i] * ( 1.0 - dRow_cd ) - (dPAR_sun + dPAR_shade);
		dPAR_upward_shade *= g_dSoilReflectance_ppfd * (1.0 - exp( - dKb * g_dOmega * data.m_aryLAI[i]) );
		dPAR_shade += dPAR_upward_shade;


		if(g_iUseAPAR == 0){
			dPAR_shade = data.m_aryPPFD[i] - data.m_aryPPFD_sun[i];
			if(dPAR_shade < 0) dPAR_shade = 0.0;
		}
		if(g_iUseAPAR == 1){
			dPAR_shade = data.m_aryPPFD[i] - data.m_aryPPFD_ref[i] - data.m_aryPPFD_sun[i];
			//if(dPAR_sun + dPAR_shade > 0){
			//	dPAR_sun *= (data.m_aryPPFD[i] - data.m_aryPPFD_ref[i]) / (dPAR_sun + dPAR_shade);
			//	dPAR_shade *= (data.m_aryPPFD[i] - data.m_aryPPFD_ref[i]) / (dPAR_sun + dPAR_shade);
			//}
			if(dPAR_shade < 0) dPAR_shade = 0.0;
			if(data.m_aryPPFD[i] == c_dError || data.m_aryPPFD_ref[i] == c_dError || data.m_aryPPFD_sun[i] == c_dError){
				if(data.m_aryPPFD[i] == c_dError || data.m_aryPPFD_sun[i] == c_dError){
					dPAR_shade = c_dError;
				}
			}
		}
		if(g_iUseAPAR == 2){
			dPAR_shade = data.m_aryPPFD[i] * data.m_aryFPAR[i] - data.m_aryPPFD_sun[i];
			if(dPAR_shade < 0) dPAR_shade = 0.0;
		}
		if(g_iUseAPAR == 4){	// neglecting trasmitted PAR
			dPAR_shade = data.m_aryPPFD[i] - data.m_aryPPFD_sun[i] - dPAR_ref;
			if(dPAR_shade < 0) dPAR_shade = 0.0;
		}
		data.m_aryPPFD_shade[i] = dPAR_shade;

		// abosrbed PAR (umol m-2 s-1)
		if(dPAR_sun != c_dError && dPAR_shade != c_dError){
			dAPAR = dPAR_sun + dPAR_shade;
		}
		else{
			dAPAR = c_dError;
		}
		if(g_iUseAPAR == 3){
			data.m_aryAPPFD[i] = dAPAR;
		}

		// transmitted PAR (umol m-2 s-1)
		if(dPPFD_obs != c_dError && dAPAR != c_dError && dPAR_ref != c_dError){
			dTPAR = dPPFD_obs - dAPAR - dPAR_ref;
		}
		else{
			dTPAR = c_dError;
		}

		// fraction of absorbed PAR (FPAR) (no dimension)
		if(dPPFD_obs <= 0.0){
			dFPAR = 0.0;
		}
		else{
			dFPAR = dAPAR / dPPFD_obs;
		}
		if(dFPAR > 1.0) dFPAR = 1.0;

		// NIR radiation absorbed by sunlit leaf  (W m-2)
		dRow_nir_cb = 1.0 - exp( -2.0 * g_Row_h_nir * dKb / (1.0 + dKb) ) ;				// relfectance of beam irradiance, uniform leaf-angle distribution (A19; de Pury and Farquhar, 1997PCE)
		dRow_nir_cd = 1.0 - exp( -2.0 * g_Row_h_nir * dKb_nir / ( 1.0 + dKb_nir ) );	// relfectance of diffuse irradiance, uniform leaf-angle distribution (A19; de Pury and Farquhar, 1997PCE)
		dNIR_direct_sun = dNIR_direct * ( 1.0 - g_dLeaf_scattering_nir ) * ( 1.0 - exp( -dKb * g_dOmega * data.m_aryLAI[i] ) );
		dNIR_diffuse_sun = dNIR_diffuse * ( 1.0 - dRow_nir_cd ) * g_dOmega * ( 1.0 - exp( -( dKd_nir + dKb ) * g_dOmega * data.m_aryLAI[i] ) ) * dKd_nir / ( dKd_nir + dKb ) ;
		if(dKb_nir == 0.0){
			dNIR_scatter_sun = 0.0;
		}
		else{
			dNIR_scatter_sun = dNIR_direct * g_dOmega * ( ( 1.0 - dRow_nir_cb ) * ( 1.0 - exp( -( dKb_nir + dKb ) * g_dOmega * data.m_aryLAI[i] ) ) * dKb_nir / ( dKb_nir + dKb )-( 1.0 - g_dSigma_scattering ) * ( 1.0 - exp( -2.0 * dKb * g_dOmega * data.m_aryLAI[i] ) ) / 2.0);
		}

		dNIR_sun = dNIR_direct_sun + dNIR_diffuse_sun + dNIR_scatter_sun;

		// NIR absorbed by the shaded leaf (W m-2)
		dNIR_shade = dNIR_direct_sun * ( 1.0 - dRow_nir_cb ) * ( 1.0 - exp( -dKb_nir * g_dOmega * data.m_aryLAI[i] ) );
		dNIR_shade += dNIR_diffuse * ( 1.0 - dRow_nir_cd )   * ( 1.0 - exp( -dKd_nir * g_dOmega * data.m_aryLAI[i] ) );
		dNIR_shade -= dNIR_sun;
		if(dNIR_shade < 0.0) dNIR_shade = 0.0;

		// shortwave radiation absorbed by soil (W m-2)
		dNIR_soil = dNIR_direct * ( 1.0 - g_dLeaf_scattering_nir ) + dNIR_diffuse * ( 1.0 - dRow_nir_cd ) - (dNIR_sun + dNIR_shade);
		dNIR_soil *= ( 1.0 - g_dSoilReflectance_nir );
		
		dPAR_soil = data.m_aryPPFD_direct[i] * ( 1.0 - g_dSigma_scattering ) + data.m_aryPPFD_diffuse[i] * ( 1.0 - dRow_cd ) - (dPAR_sun + dPAR_shade);
		dPAR_soil *= ( 1.0 - g_dSoilReflectance_ppfd ) / c_dPAR_to_PPFD;

		// calculated transmittance of shortwave radiation
		dTransmittedSW = (dPAR_soil + dNIR_soil) / (dPPFD_obs / c_dRatio_PAR_to_SW);
		if(dPPFD_obs < 1.0) dTransmittedSW = 0.01;

		// net radiation by soil, by assumed that attenuation of Rn is same as those for shortwave radiation
		data.m_aryRn_soil[i] = data.m_aryRn[i] * dTransmittedSW;

		// **************************************************************************************************
		// Multi-Layer radiative trasfer
		// **************************************************************************************************
		data.m_aryKb[i] = dKb;
		data.m_aryKb2[i] = dKb2;
		data.m_aryRow_cb[i] = dRow_cb;
		data.m_aryRow_cd[i] = dRow_cd;
	}

	// ********************************************
	// calculating daily variables
	// ********************************************
	dAPAR = 0.0;
	dPPFD = 0.0;
	dKb = 0.0;
	double dWeightSun = 0.0, dWeightShade = 0.0, dWeightSun_top = 0.0;
	double dLAI_Sun = 0.0, dLAI_Shade = 0.0;
	double dFPAR_daily;
	int iCount_lai = 0, iCount = 0;

	for(i = 0; i < data.m_aryDate.size(); i++){
		// calculating weight factor
		if(data.m_aryPPFD[i] > 0.0 && data.m_aryPPFD_sun[i] > 0.0 &&  data.m_aryPPFD_shade[i] > 0.0){
			// calculating daily FPAR
			dAPAR += data.m_aryPPFD_sun[i] + data.m_aryPPFD_shade[i];
			dPPFD += data.m_aryPPFD[i];
			iCount++;

			if(data.m_aryWeight_sun[i] != 0 && data.m_aryWeight_shade[i] != 0){
				dWeightSun += data.m_aryWeight_sun[i];
				dWeightShade += data.m_aryWeight_shade[i];
//				dWeightSun_top += data.m_aryWeight_sun_top[i];
				dKb += data.m_aryKb[i];

				// calculating sun / shade leaf area index
				dLAI_Sun += data.m_aryLAI_sun[i];
				dLAI_Shade += data.m_aryLAI_shade[i];
				iCount_lai++;
			}
		}
		
		if( i % g_iRunPerDay == g_iRunPerDay - 1 ){
			if(dPPFD != 0.0){
				dFPAR_daily = dAPAR / dPPFD;
			}
			else{
				dFPAR_daily = 0.0;
			}
			daily.m_aryFPAR.push_back(dFPAR_daily);

			dWeightSun = dWeightSun / iCount_lai;
			dWeightShade = dWeightShade / iCount_lai;
			dWeightSun_top = dWeightSun_top / iCount_lai;
			dLAI_Sun = dLAI_Sun / iCount_lai;
			dLAI_Shade = dLAI_Shade / iCount_lai;
			dKb = dKb / iCount_lai;

			if(iCount_lai == 0){
				dWeightSun = c_dError;
				dWeightShade = c_dError;
				dWeightSun_top = c_dError;
				dLAI_Sun = c_dError;
				dLAI_Shade = c_dError;
				dKb = c_dError;
			}

			daily.m_aryWeight_sun.push_back(dWeightSun);
			daily.m_aryWeight_shade.push_back(dWeightShade);
//			daily.m_aryWeight_sun_top.push_back(dWeightSun_top);

			daily.m_aryLAI_sun.push_back(dLAI_Sun);
			daily.m_aryLAI_shade.push_back(dLAI_Shade);

			for(int j = i - g_iRunPerDay + 1; j < i + 1; j++){
//				data.m_aryLAI_sun_day[j] = dLAI_Sun;
//				data.m_aryLAI_shade_day[j] = dLAI_Shade;
//				data.m_aryWeight_sun_day[j] = dWeightSun;
//				data.m_aryWeight_shade_day[j] = dWeightShade;
//				data.m_aryWeight_sun_top_day[j] = dWeightSun_top;
//				data.m_aryKb_day[j] = dKb;
			}

			// initilize
			dAPAR = 0.0;
			dPPFD = 0.0;
			dWeightSun = 0.0;
			dWeightShade = 0.0;
			dWeightSun_top = 0.0;
			dLAI_Sun = 0.0;
			dLAI_Shade = 0.0;
			dKb = 0.0;
			iCount_lai = 0;
		}
	}

	// apply moving window to weight factors
	// mean_parameters_window(data);
}

void mean_parameters_window(CData& data)
{
	double dWeightSun = 0.0, dWeightSun_top = 0.0, dKb = 0.0;
	double dWeightSun_daytime = 0.0, dWeightSun_top_daytime = 0.0, dKb_daytime = 0.0;
	int iCount = 0, iCount_daytime = 0;

	for(int iCurrent = 0; iCurrent < data.m_aryWeight_sun.size(); iCurrent++){
		if( iCurrent % g_iRunPerDay == 0){
			int iWindowSize = (g_iWindowSize - 1) / 2;
			int iStart = iCurrent - iWindowSize * g_iRunPerDay;
			int iEnd   = iCurrent + (iWindowSize + 1) * g_iRunPerDay;
			if(iStart < 0){
				iStart = 0;
			}
			if(iEnd > data.m_aryWeight_sun.size()){
				iEnd = data.m_aryWeight_sun.size();
			}

			for(int iMoving = iStart; iMoving < iEnd; iMoving++){
				if(data.m_aryWeight_sun[iMoving] != 0 && data.m_aryWeight_shade[iMoving] != 0){
					dWeightSun += data.m_aryWeight_sun[iMoving];
//					dWeightSun_top += data.m_aryWeight_sun_top[iMoving];
					dKb += data.m_aryKb[iMoving];
					iCount++;

					if(data.m_aryPPFD[iMoving] > 0.0){
						dWeightSun_daytime += data.m_aryWeight_sun[iMoving];
//						dWeightSun_top_daytime += data.m_aryWeight_sun_top[iMoving];
						dKb_daytime += data.m_aryKb[iMoving];
						iCount_daytime++;
					}
				}
			}

			if(iCount != 0){
				dWeightSun /= iCount;
				dWeightSun_top /= iCount;
				dKb /= iCount;
			}
			else{
				dWeightSun = c_dError;
				dWeightSun_top = c_dError;
				dKb = c_dError;
			}

			if(iCount_daytime != 0){
				dWeightSun_daytime /= iCount_daytime;
				dWeightSun_top_daytime /= iCount_daytime;
				dKb_daytime /= iCount_daytime;
			}
			else{
				dWeightSun_daytime = c_dError;
				dWeightSun_top_daytime = c_dError;
				dKb_daytime = c_dError;
			}

			// set mean value for the day
//			iEnd   = iCurrent + g_iRunPerDay;
//			if(iEnd > data.m_aryWeight_sun_day.size()) iEnd = data.m_aryWeight_sun_day.size();
//			for(int j = iCurrent; j < iEnd; j++){
//				if(iCount_daytime == 0){
//					data.m_aryWeight_sun_day[j] = dWeightSun;
//					data.m_aryWeight_shade_day[j] = 1.0 - dWeightSun;
//					data.m_aryWeight_sun_top_day[j] = dWeightSun_top;
//					data.m_aryKb_day[j] = dKb;
//				}
//				else{
//					data.m_aryWeight_sun_day[j] = dWeightSun_daytime;
//					data.m_aryWeight_shade_day[j] = 1.0 - dWeightSun_daytime;
//					data.m_aryWeight_sun_top_day[j] = dWeightSun_top_daytime;
//					data.m_aryKb_day[j] = dKb_daytime;
//				}
//			}

			// reset the value
			dWeightSun = 0.0;
			dWeightSun_top = 0.0;
			dKb = 0.0;
			dWeightSun_daytime = 0.0;
			dWeightSun_top_daytime = 0.0;
			dKb_daytime = 0.0;
			iCount = 0;
			iCount_daytime = 0;
		}
	}
}

void daily_parameters(CData& data, CDailyData& daily, std::vector< std::vector<double> >& aryBestParametersWindow)
{
	// Wang and Leuning (1998) A two-leaf model for canopy conductance, photosynthesis and partitioning of available energy I: model description and comparison with a multi-layered model
	//    Agricultural and Forest Meteorology, 91, 89-111.	
	double dWeightSun = 0.0, dWeightShade = 0.0, dWeightSun_each = 0.0, dLAI_Sun = 0.0, dLAI_Shade = 0.0;
	double dWeightSun_top = 0.0, dWeightShade_top = 0.0;
	double dVcmax25, dVcmax25_leaf, dVcmax25_sun, dVcmax25_shade, dVcmax25_sun_leaf, dVcmax25_shade_leaf;	// Vcmax25
	double dJmax25,  dJmax25_leaf,  dJmax25_sun,  dJmax25_shade,  dJmax25_sun_leaf,  dJmax25_shade_leaf;	// Jmax25
	double dMbb;
	double dBbb,  dBbb_leaf,  dBbb_sun,  dBbb_shade,  dBbb_sun_leaf,  dBbb_shade_leaf;						// b in Ball Berry model
	double dKn = 0.0, dKn_median = 0.0, dKn_median_winter = 0.0;
	vector<double> aryKn, aryKn_winter;
	int iDay, iCount = 0;

	// ***************************************************
	// updated sunlit leaf weight
	// ***************************************************
	int iCount_lai = 0;
	if(g_dKn < 0.0){
		for(int i = 0; i < data.m_aryDate.size(); i++){
			if( i % g_iRunPerDay == 0 ){
				iDay = i / g_iRunPerDay;				
			}
			dVcmax25 = aryBestParametersWindow[iDay][0];
		
			// calculating weight factor
			if(data.m_aryPPFD[i] > 0.0 && data.m_aryKb[i] != 0 &&  data.m_aryLAI[i] != 0){
				if(g_iCanopyStructure == 0){
					dKn = calculate_kn(dVcmax25, data.m_aryLAI[i], 0.0, g_iCanopyStructure);
				}
				if(g_iCanopyStructure == 1){
					dKn = calculate_kn(dVcmax25, data.m_aryLAI[i], data.m_aryKb[i], g_iCanopyStructure);
				}
				if(g_iCanopyStructure >= 2){
					dKn = calculate_kn(dVcmax25, data.m_aryLAI[i], data.m_aryKb[i], g_iCanopyStructure);
				}
				dWeightSun_each = (g_dOmega * ( 1.0 - exp(-dKn - data.m_aryKb[i] *  g_dOmega * data.m_aryLAI[i]) ) / (dKn + data.m_aryKb[i] *  g_dOmega * data.m_aryLAI[i]) ) / ( (1.0 - exp(-dKn) ) / dKn ) ;
				dWeightSun += dWeightSun_each;
				iCount_lai++;

				if(dWeightSun_each != c_dError){
					data.m_aryLAI_sun[i] = data.m_aryLAI[i] *  dWeightSun_each;
					data.m_aryLAI_shade[i] = data.m_aryLAI[i] *  (1.0 - dWeightSun_each);
					data.m_aryWeight_sun[i] = dWeightSun_each;
					data.m_aryWeight_shade[i] = (1.0 - dWeightSun_each);
				}
			}
				
			if( i % g_iRunPerDay == g_iRunPerDay - 1 ){
				dWeightSun = dWeightSun / iCount_lai;

				if(iCount_lai == 0)	dWeightSun = c_dError;
					
				if(dWeightSun != c_dError) daily.m_aryWeight_sun[ (i + 1) / g_iRunPerDay - 1] = dWeightSun;
				if(dWeightSun != c_dError) daily.m_aryWeight_shade[ (i + 1) / g_iRunPerDay - 1] = 1.0 - dWeightSun;
				if(dWeightSun != c_dError) daily.m_aryLAI_sun[ (i + 1) / g_iRunPerDay - 1] = data.m_aryLAI[i] *  dWeightSun;
				if(dWeightSun != c_dError) daily.m_aryLAI_shade[ (i + 1) / g_iRunPerDay - 1] = data.m_aryLAI[i] * (1.0 - dWeightSun);

				// initilize
				dWeightSun = 0.0;
				iCount_lai = 0;
			}
		}
	}	

	// ***************************************************
	// calculate kn for determining median value
	// ***************************************************
	if(g_dKn < 0.0){
		for(int i = 0; i < data.m_aryDate.size(); i++){	
			if( i % g_iRunPerDay == g_iRunPerDay - 1 ){
				iDay = (i + 1) / g_iRunPerDay - 1;
				dVcmax25 = aryBestParametersWindow[iDay][0];
				dWeightSun = daily.m_aryWeight_sun[ (i + 1) / g_iRunPerDay - 1];
				dWeightShade = daily.m_aryWeight_shade[ (i + 1) / g_iRunPerDay - 1];

				if(dVcmax25 == c_dError || dWeightSun == c_dError) continue;

				if(g_iCanopyStructure == 0) dKn = calculate_kn(dVcmax25, data.m_aryLAI[i], 0.0, 0);
				if(g_iCanopyStructure == 1) dKn = calculate_kn(dVcmax25 + dVcmax25 * dWeightShade / dWeightSun, data.m_aryLAI[i], 0.0, 0);
				if(g_iCanopyStructure == 2) dKn = calculate_kn(dVcmax25, data.m_aryLAI[i], 0.0, -1);
				if(g_iCanopyStructure == 3) dKn = calculate_kn(dVcmax25, data.m_aryLAI[i], 0.0, -1);
				if(data.m_aryTa[i] > 0.0 && dKn != 1.0 && dKn > 0.0){
					// only add growing season value
					aryKn.push_back(dKn);
				}
				if(data.m_aryTa[i] <= 0.0 && dKn != 1.0 && dKn > 0.0){
					aryKn_winter.push_back(dKn);
				}
			}
			dKn_median = Median(aryKn);
			if(aryKn_winter.size() != 0){
				dKn_median_winter = Median(aryKn_winter);
			}
			else{
				dKn_median_winter = dKn_median;
			}
		}
	}	

	// ***************************************************
	// calculate daily parameters
	// ***************************************************
	for(int i = 0; i < data.m_aryDate.size(); i++){	
		if( i % g_iRunPerDay == g_iRunPerDay - 1 ){

			dWeightSun = daily.m_aryWeight_sun[ (i + 1) / g_iRunPerDay - 1];
			dWeightShade = daily.m_aryWeight_shade[ (i + 1) / g_iRunPerDay - 1];
			dLAI_Sun = daily.m_aryLAI_sun[ (i + 1) / g_iRunPerDay - 1];
			dLAI_Shade = daily.m_aryLAI_shade[ (i + 1) / g_iRunPerDay - 1];

//			dWeightSun_top = daily.m_aryWeight_sun_top[ (i + 1) / g_iRunPerDay - 1];
			dWeightShade_top = 1.0 - dWeightSun_top;
			dKn = c_dError;

			iDay = (i + 1) / g_iRunPerDay - 1;

			// downscaling big-leaf parameters to leaf parameters
			dVcmax25 = aryBestParametersWindow[iDay][0];
			dMbb     = aryBestParametersWindow[iDay][3];
			dBbb     = aryBestParametersWindow[iDay][4];
			
			if(dVcmax25 != c_dError && dWeightSun != c_dError && dWeightShade != c_dError ){
				if(g_iCanopyStructure == 0){
					// Big Leaf Model
					if(g_dKn < 0.0){
						dKn = calculate_kn(dVcmax25, data.m_aryLAI[i], 0.0, 0);	// solving Kn using big-leaf Vcmax
						if((dKn < 0.0 || dKn == 1.0) && data.m_aryTa[i] > 0.0) dKn = dKn_median;
						if((dKn < 0.0 || dKn == 1.0) && data.m_aryTa[i] <= 0.0) dKn = dKn_median_winter;
					}
					else{
						dKn = g_dKn;
					}
					dVcmax25_leaf = dVcmax25 / data.m_aryLAI[i] * dKn / (1.0 - exp( -dKn ) );
					dVcmax25_sun = dVcmax25 * dWeightSun;
					dVcmax25_shade = dVcmax25 * dWeightShade;
					dVcmax25_sun_leaf = dVcmax25_sun / dLAI_Sun;
					dVcmax25_shade_leaf = dVcmax25_shade / dLAI_Shade;

					dJmax25 = aryBestParametersWindow[iDay][0] * aryBestParametersWindow[iDay][1];
					dJmax25_leaf = dJmax25 / data.m_aryLAI[i] * dKn / (1.0 - exp( -dKn ) );
					dJmax25_sun = dJmax25 * dWeightSun;
					dJmax25_shade = dJmax25 * dWeightShade;
					dJmax25_sun_leaf = dJmax25_sun / dLAI_Sun;
					dJmax25_shade_leaf = dJmax25_shade / dLAI_Shade;
					
					dBbb_leaf = dBbb / data.m_aryLAI[i] * dKn / (1.0 - exp( -dKn ) );
					dBbb_sun = dBbb * dWeightSun;
					dBbb_shade = dBbb * dWeightShade;
					dBbb_sun_leaf = dBbb_sun / dLAI_Sun;
					dBbb_shade_leaf = dBbb_shade / dLAI_Shade;
				}
				else if(g_iCanopyStructure == 1){
					// Sun / Shade Leaf Model
					dVcmax25_sun = dVcmax25 * dWeightSun;
					dVcmax25_shade = dVcmax25 * dWeightShade;		
					dVcmax25_sun_leaf = dVcmax25_sun / dLAI_Sun;
					dVcmax25_shade_leaf = dVcmax25_shade / dLAI_Shade;
					dVcmax25 = dVcmax25_sun + dVcmax25_shade;
					if(g_dKn < 0.0){
						dKn = calculate_kn(dVcmax25, data.m_aryLAI[i], 0.0, 0);	// solving Kn using big-leaf Vcmax
						if((dKn < 0.0 || dKn == 1.0) && data.m_aryTa[i] > 0.0) dKn = dKn_median;
						if((dKn < 0.0 || dKn == 1.0) && data.m_aryTa[i] <= 0.0) dKn = dKn_median_winter;
					}
					else{
						dKn = g_dKn;
					}
					dVcmax25_leaf = dVcmax25 / data.m_aryLAI[i] * dKn / (1.0 - exp( -dKn ) );

					dJmax25_sun = aryBestParametersWindow[iDay][0] * aryBestParametersWindow[iDay][1] * dWeightSun;
					dJmax25_shade = aryBestParametersWindow[iDay][0] * aryBestParametersWindow[iDay][1] * dWeightShade;
					dJmax25_sun_leaf = dJmax25_sun / dLAI_Sun;
					dJmax25_shade_leaf = dJmax25_shade / dLAI_Shade;
					dJmax25 = dJmax25_sun + dJmax25_shade;
					dJmax25_leaf = dJmax25 / data.m_aryLAI[i] * dKn / (1.0 - exp( -dKn ) );
					
					dBbb_sun = dBbb * dWeightSun;
					dBbb_shade = dBbb * dWeightShade;
					dBbb_sun_leaf = dBbb_sun / dLAI_Sun;
					dBbb_shade_leaf = dBbb_shade / dLAI_Shade;
					dBbb = dBbb_sun + dBbb_shade;
					dBbb_leaf = dBbb / data.m_aryLAI[i] * dKn / (1.0 - exp( -dKn ) );
				}
				else{
					// Multi Layer model
					double dMultiLayerSplit = g_dMultiLayerSplit;
					if(dLAI_Sun + dLAI_Shade < dMultiLayerSplit) dMultiLayerSplit = dLAI_Sun + dLAI_Shade;

					if(g_dKn < 0.0){
						dKn = calculate_kn(dVcmax25, data.m_aryLAI[i], 0.0, g_iCanopyStructure);
						if((dKn < 0.0 || dKn == 1.0) && data.m_aryTa[i] > 0.0) dKn = dKn_median;
						if((dKn < 0.0 || dKn == 1.0) && data.m_aryTa[i] <= 0.0) dKn = dKn_median_winter;
					}
					else{
						dKn = g_dKn;
					}

					dVcmax25_leaf = dVcmax25; //( dVcmax25 + dVcmax25 * dWeightShade_top / dWeightSun_top ) / dMultiLayerSplit;
					dVcmax25 = dVcmax25_leaf * data.m_aryLAI[i] / dKn * (1.0 - exp( -dKn ) );
					dVcmax25_sun = dVcmax25 * dWeightSun;
					dVcmax25_shade = dVcmax25 * dWeightShade;
					dVcmax25_sun_leaf = dVcmax25_sun / dLAI_Sun;
					dVcmax25_shade_leaf = dVcmax25_shade / dLAI_Shade;

					dJmax25_leaf = aryBestParametersWindow[iDay][0] * aryBestParametersWindow[iDay][1]; //( aryBestParametersWindow[iDay][0] * aryBestParametersWindow[iDay][1] + aryBestParametersWindow[iDay][0] * aryBestParametersWindow[iDay][1] * dWeightShade_top / dWeightSun_top ) / dMultiLayerSplit;
					dJmax25 = dJmax25_leaf * data.m_aryLAI[i] / dKn * (1.0 - exp( -dKn ) );
					dJmax25_sun = dJmax25 * dWeightSun;
					dJmax25_shade = dJmax25 * dWeightShade;
					dJmax25_sun_leaf = dJmax25_sun / dLAI_Sun;
					dJmax25_shade_leaf = dJmax25_sun_leaf / dLAI_Shade;

					dBbb_leaf = dBbb; //( dBbb + dBbb * dWeightShade_top / dWeightSun_top ) / dMultiLayerSplit;
					dBbb = dBbb_leaf * data.m_aryLAI[i] / dKn * (1.0 - exp( -dKn ) );
					dBbb_sun = dBbb * dWeightSun;
					dBbb_shade = dBbb * dWeightShade;
					dBbb_sun_leaf = dBbb_sun / dLAI_Sun;
					dBbb_shade_leaf = dBbb_shade_leaf / dLAI_Shade;
				}

				if(dLAI_Sun == 0 && dLAI_Shade != 0){
					dVcmax25_sun_leaf = dVcmax25_shade_leaf;
					dJmax25_sun_leaf = dJmax25_sun_leaf;
					dBbb_sun_leaf = dBbb_shade_leaf;
				}
			}
			else{
				dVcmax25_leaf = c_dError;
				dVcmax25_sun = c_dError;
				dVcmax25_shade = c_dError;
				dVcmax25_sun_leaf = c_dError;
				dVcmax25_shade_leaf = c_dError;
				dJmax25 = c_dError;
				dJmax25_leaf = c_dError;
				dJmax25_sun = c_dError;
				dJmax25_shade = c_dError;
				dJmax25_sun_leaf = c_dError;
				dJmax25_shade_leaf = c_dError;
				dBbb_leaf = c_dError;
				dBbb_sun = c_dError;
				dBbb_shade = c_dError;
				dBbb_sun_leaf = c_dError;
				dBbb_shade_leaf = c_dError;
			}
			// Vcmax25
			daily.m_aryVcmax25.push_back( dVcmax25 );
			daily.m_aryVcmax25_leaf.push_back( dVcmax25_leaf );
			daily.m_aryVcmax25_sun.push_back( dVcmax25_sun );
			daily.m_aryVcmax25_shade.push_back( dVcmax25_shade );
			daily.m_aryVcmax25_sun_leaf.push_back( dVcmax25_sun_leaf );
			daily.m_aryVcmax25_shade_leaf.push_back( dVcmax25_shade_leaf );
			// Jmax25
			daily.m_aryJmax25.push_back( dJmax25 );
			daily.m_aryJmax25_leaf.push_back( dJmax25_leaf);
			daily.m_aryJmax25_sun.push_back( dJmax25_sun );
			daily.m_aryJmax25_shade.push_back( dJmax25_shade );
			daily.m_aryJmax25_sun_leaf.push_back( dJmax25_sun_leaf );
			daily.m_aryJmax25_shade_leaf.push_back( dJmax25_shade_leaf );
			// m in Ball-Berry model
			daily.m_aryM_bb.push_back( dMbb );
			// b in Ball-Berry model
			daily.m_aryB_bb.push_back( dBbb );
			daily.m_aryB_bb_leaf.push_back( dBbb_leaf);
			daily.m_aryB_bb_sun.push_back( dBbb_sun );
			daily.m_aryB_bb_shade.push_back( dBbb_shade );
			daily.m_aryB_bb_sun_leaf.push_back( dBbb_sun_leaf );
			daily.m_aryB_bb_shade_leaf.push_back( dBbb_shade_leaf );

			daily.m_aryKn.push_back( dKn );

			// initilize
			iCount = 0;
		}
	}
}

double calculate_kn(const double& dVcmax, const double& dLAI, const double& dKb, int iCanopyStructure)
{
	// calculating nitrogen distribution coefficient
	// Lloyd et al., 2010: Optimisation of photosynthetic carbon gain and within-canopy gradients of associated foliar traits for Amazon forest trees.
	//   Biogeosciences, 7, 1833-1859.

	// dVcmax			: maximum carboxylation rate at 25 degree C
	// dLAI				: total leaf area index (m2 m-2) 
	// dKb				: beam radiation extinction coefficient
	// iCanopyStructure	: 0=Big-Leaf Vcmax, 1=Big SunLeaf Vcmax, 2=leaf-scale vcmax at canopy top

	double dKn = 0.2, dKn_old = 0.5;
	double dWeight_sun;
	int iCount = 0;

	if(dVcmax == c_dError){
		return c_dError;
	}

	if(iCanopyStructure < 0 || iCanopyStructure >= 2){
		dKn = exp( 0.00963 * dVcmax - 2.43 );
		if(dKn > 1.0) dKn = 1.0;
		return dKn;
	}

	while(iCount < 10 && fabs(dKn - dKn_old) > 0.01 ){
		dKn_old = dKn;
		if(iCanopyStructure == 0){
			// big leaf model
			dKn =exp( 0.00963 * dVcmax / dLAI * dKn_old / ( 1.0 - exp(-dKn_old) ) - 2.43 );
		}
		if(iCanopyStructure == 1){
			// sun / shade model
			// in sun / shade model, dVcmax represnet Vcmax for sunlit leaf
			dWeight_sun = g_dOmega * ( 1.0 - exp(-dKn - dKb *  g_dOmega * dLAI) ) / (dKn + dKb *  g_dOmega * dLAI);
			dWeight_sun /= (1.0 - exp(-dKn) ) / dKn;
			dKn =exp( 0.00963 * (dVcmax + dVcmax * (1.0 - dWeight_sun) / dWeight_sun) / dLAI * dKn_old / ( 1.0 - exp(-dKn_old) ) - 2.43 );
		}

		if(dKn > 5.0) break;
		iCount++;
	}
	if(dKn > 1.0) dKn = 1.0;

	return dKn;
}

void get_G_function(double& dG, const double& dRad, const int& iShape)
{
	switch ( static_cast<int>(dRad) ){
		case 0:
			if(iShape == 0) dG = 0.5;
			if(iShape == 1) dG = 0.848826408;
			if(iShape == 2) dG = 0.424413204;
			break;
		case 1:
			if(iShape == 0) dG = 0.499923885;
			if(iShape == 1) dG = 0.848697066;
			if(iShape == 2) dG = 0.424348533;
			break;
		case 2:
			if(iShape == 0) dG = 0.499992937;
			if(iShape == 1) dG = 0.848309398;
			if(iShape == 2) dG = 0.424533367;
			break;
		case 3:
			if(iShape == 0) dG = 0.500122428;
			if(iShape == 1) dG = 0.847663522;
			if(iShape == 2) dG = 0.424859732;
			break;
		case 4:
			if(iShape == 0) dG = 0.500136793;
			if(iShape == 1) dG = 0.846759379;
			if(iShape == 2) dG = 0.425103933;
			break;
		case 5:
			if(iShape == 0) dG = 0.500012875;
			if(iShape == 1) dG = 0.845597386;
			if(iShape == 2) dG = 0.425236553;
			break;
		case 6:
			if(iShape == 0) dG = 0.499743491;
			if(iShape == 1) dG = 0.844177723;
			if(iShape == 2) dG = 0.425248444;
			break;
		case 7:
			if(iShape == 0) dG = 0.499743372;
			if(iShape == 1) dG = 0.842506945;
			if(iShape == 2) dG = 0.425664425;
			break;
		case 8:
			if(iShape == 0) dG = 0.49993524;
			if(iShape == 1) dG = 0.840584397;
			if(iShape == 2) dG = 0.426386476;
			break;
		case 9:
			if(iShape == 0) dG = 0.500127017;
			if(iShape == 1) dG = 0.838408053;
			if(iShape == 2) dG = 0.427171528;
			break;
 		case 10:
			if(iShape == 0) dG = 0.500259459;
			if(iShape == 1) dG = 0.835977495;
			if(iShape == 2) dG = 0.427944094;
			break;
 		case 11:
			if(iShape == 0) dG = 0.500302255;
			if(iShape == 1) dG = 0.833293319;
			if(iShape == 2) dG = 0.428665817;
			break;
 		case 12:
			if(iShape == 0) dG = 0.500237644;
			if(iShape == 1) dG = 0.830355883;
			if(iShape == 2) dG = 0.429313898;
			break;
 		case 13:
			if(iShape == 0) dG = 0.500054181;
			if(iShape == 1) dG = 0.827166021;
			if(iShape == 2) dG = 0.429873556;
			break;
 		case 14:
			if(iShape == 0) dG = 0.499744058;
			if(iShape == 1) dG = 0.823724508;
			if(iShape == 2) dG = 0.430334955;
			break;
 		case 15:
			if(iShape == 0) dG = 0.49950242;
			if(iShape == 1) dG = 0.82004869;
			if(iShape == 2) dG = 0.430938095;
			break;
 		case 16:
			if(iShape == 0) dG = 0.499609768;
			if(iShape == 1) dG = 0.816162884;
			if(iShape == 2) dG = 0.432028234;
			break;
 		case 17:
			if(iShape == 0) dG = 0.499810904;
			if(iShape == 1) dG = 0.812047839;
			if(iShape == 2) dG = 0.43329069;
			break;
 		case 18:
			if(iShape == 0) dG = 0.500026762;
			if(iShape == 1) dG = 0.807698011;
			if(iShape == 2) dG = 0.434627414;
			break;
 		case 19:
			if(iShape == 0) dG = 0.50021559;
			if(iShape == 1) dG = 0.80311197;
			if(iShape == 2) dG = 0.435986549;
			break;
 		case 20:
			if(iShape == 0) dG = 0.500350893;
			if(iShape == 1) dG = 0.798288643;
			if(iShape == 2) dG = 0.437335044;
			break;
 		case 21:
			if(iShape == 0) dG = 0.500414133;
			if(iShape == 1) dG = 0.793228388;
			if(iShape == 2) dG = 0.438649505;
			break;
 		case 22:
			if(iShape == 0) dG = 0.500391722;
			if(iShape == 1) dG = 0.787931561;
			if(iShape == 2) dG = 0.439912915;
			break;
 		case 23:
			if(iShape == 0) dG = 0.500273228;
			if(iShape == 1) dG = 0.782398939;
			if(iShape == 2) dG = 0.441112041;
			break;
 		case 24:
			if(iShape == 0) dG = 0.500050604;
			if(iShape == 1) dG = 0.776631594;
			if(iShape == 2) dG = 0.442236394;
			break;
 		case 25:
			if(iShape == 0) dG = 0.499717385;
			if(iShape == 1) dG = 0.770630836;
			if(iShape == 2) dG = 0.443277717;
			break;
 		case 26:
			if(iShape == 0) dG = 0.499418437;
			if(iShape == 1) dG = 0.764437258;
			if(iShape == 2) dG = 0.444401413;
			break;
 		case 27:
			if(iShape == 0) dG = 0.499462306;
			if(iShape == 1) dG = 0.758134246;
			if(iShape == 2) dG = 0.445961356;
			break;
 		case 28:
			if(iShape == 0) dG = 0.499622017;
			if(iShape == 1) dG = 0.751664996;
			if(iShape == 2) dG = 0.447695911;
			break;
 		case 29:
			if(iShape == 0) dG = 0.499823362;
			if(iShape == 1) dG = 0.74501276;
			if(iShape == 2) dG = 0.449519128;
			break;
 		case 30:
			if(iShape == 0) dG = 0.50002718;
			if(iShape == 1) dG = 0.73816967;
			if(iShape == 2) dG = 0.45138514;
			break;
 		case 31:
			if(iShape == 0) dG = 0.500207722;
			if(iShape == 1) dG = 0.731131613;
			if(iShape == 2) dG = 0.453263819;
			break;
 		case 32:
			if(iShape == 0) dG = 0.500346363;
			if(iShape == 1) dG = 0.723896265;
			if(iShape == 2) dG = 0.455133021;
			break;
 		case 33:
			if(iShape == 0) dG = 0.500428915;
			if(iShape == 1) dG = 0.716462374;
			if(iShape == 2) dG = 0.456975698;
			break;
 		case 34:
			if(iShape == 0) dG = 0.500444114;
			if(iShape == 1) dG = 0.708829641;
			if(iShape == 2) dG = 0.458778381;
			break;
 		case 35:
			if(iShape == 0) dG = 0.500382781;
			if(iShape == 1) dG = 0.700998068;
			if(iShape == 2) dG = 0.460529774;
			break;
 		case 36:
			if(iShape == 0) dG = 0.500237226;
			if(iShape == 1) dG = 0.692968369;
			if(iShape == 2) dG = 0.46222046;
			break;
 		case 37:
			if(iShape == 0) dG = 0.500001311;
			if(iShape == 1) dG = 0.684741497;
			if(iShape == 2) dG = 0.463842601;
			break;
 		case 38:
			if(iShape == 0) dG = 0.499669343;
			if(iShape == 1) dG = 0.676318705;
			if(iShape == 2) dG = 0.465389222;
			break;
 		case 39:
			if(iShape == 0) dG = 0.499446929;
			if(iShape == 1) dG = 0.667832196;
			if(iShape == 2) dG = 0.467064261;
			break;
 		case 40:
			if(iShape == 0) dG = 0.499488473;
			if(iShape == 1) dG = 0.659382582;
			if(iShape == 2) dG = 0.469020665;
			break;
 		case 41:
			if(iShape == 0) dG = 0.499619722;
			if(iShape == 1) dG = 0.650865257;
			if(iShape == 2) dG = 0.471083373;
			break;
 		case 42:
			if(iShape == 0) dG = 0.499787658;
			if(iShape == 1) dG = 0.642251015;
			if(iShape == 2) dG = 0.473198116;
			break;
 		case 43:
			if(iShape == 0) dG = 0.499962211;
			if(iShape == 1) dG = 0.633524835;
			if(iShape == 2) dG = 0.475333989;
			break;
 		case 44:
			if(iShape == 0) dG = 0.500122905;
			if(iShape == 1) dG = 0.624677718;
			if(iShape == 2) dG = 0.477469325;
			break;
 		case 45:
			if(iShape == 0) dG = 0.500254452;
			if(iShape == 1) dG = 0.615703642;
			if(iShape == 2) dG = 0.479587823;
			break;
 		case 46:
			if(iShape == 0) dG = 0.500344694;
			if(iShape == 1) dG = 0.606598735;
			if(iShape == 2) dG = 0.481676668;
			break;
 		case 47:
			if(iShape == 0) dG = 0.500384033;
			if(iShape == 1) dG = 0.597360373;
			if(iShape == 2) dG = 0.483725131;
			break;
 		case 48:
			if(iShape == 0) dG = 0.500364125;
			if(iShape == 1) dG = 0.587987006;
			if(iShape == 2) dG = 0.485724062;
			break;
 		case 49:
			if(iShape == 0) dG = 0.500278115;
			if(iShape == 1) dG = 0.578477621;
			if(iShape == 2) dG = 0.487665802;
			break;
 		case 50:
			if(iShape == 0) dG = 0.500120044;
			if(iShape == 1) dG = 0.568832099;
			if(iShape == 2) dG = 0.489543438;
			break;
 		case 51:
			if(iShape == 0) dG = 0.499884874;
			if(iShape == 1) dG = 0.55905056;
			if(iShape == 2) dG = 0.491351128;
			break;
 		case 52:
			if(iShape == 0) dG = 0.499614954;
			if(iShape == 1) dG = 0.549192965;
			if(iShape == 2) dG = 0.493120641;
			break;
 		case 53:
			if(iShape == 0) dG = 0.499586076;
			if(iShape == 1) dG = 0.539614201;
			if(iShape == 2) dG = 0.495067775;
			break;
 		case 54:
			if(iShape == 0) dG = 0.499658436;
			if(iShape == 1) dG = 0.530142963;
			if(iShape == 2) dG = 0.497080892;
			break;
 		case 55:
			if(iShape == 0) dG = 0.499773592;
			if(iShape == 1) dG = 0.520710588;
			if(iShape == 2) dG = 0.499112278;
			break;
  		case 56:
			if(iShape == 0) dG = 0.499902964;
			if(iShape == 1) dG = 0.51128608;
			if(iShape == 2) dG = 0.501138151;
			break;
  		case 57:
			if(iShape == 0) dG = 0.500028074;
			if(iShape == 1) dG = 0.501851082;
			if(iShape == 2) dG = 0.503142774;
			break;
  		case 58:
			if(iShape == 0) dG = 0.500135422;
			if(iShape == 1) dG = 0.492393047;
			if(iShape == 2) dG = 0.505114019;
			break;
  		case 59:
			if(iShape == 0) dG = 0.500214398;
			if(iShape == 1) dG = 0.482903332;
			if(iShape == 2) dG = 0.507042527;
			break;
  		case 60:
			if(iShape == 0) dG = 0.500256419;
			if(iShape == 1) dG = 0.47337535;
			if(iShape == 2) dG = 0.50892055;
			break;
  		case 61:
			if(iShape == 0) dG = 0.500254452;
			if(iShape == 1) dG = 0.463804543;
			if(iShape == 2) dG = 0.510741234;
			break;
  		case 62:
			if(iShape == 0) dG = 0.500202358;
			if(iShape == 1) dG = 0.454187423;
			if(iShape == 2) dG = 0.512498915;
			break;
  		case 63:
			if(iShape == 0) dG = 0.50009495;
			if(iShape == 1) dG = 0.444521397;
			if(iShape == 2) dG = 0.514188588;
			break;
  		case 64:
			if(iShape == 0) dG = 0.499927521;
			if(iShape == 1) dG = 0.434804648;
			if(iShape == 2) dG = 0.515805602;
			break;
  		case 65:
			if(iShape == 0) dG = 0.499767095;
			if(iShape == 1) dG = 0.425206572;
			if(iShape == 2) dG = 0.517384768;
			break;
  		case 66:
			if(iShape == 0) dG = 0.499766827;
			if(iShape == 1) dG = 0.416104615;
			if(iShape == 2) dG = 0.519008398;
			break;
  		case 67:
			if(iShape == 0) dG = 0.49982214;
			if(iShape == 1) dG = 0.40725404;
			if(iShape == 2) dG = 0.520617664;
			break;
  		case 68:
			if(iShape == 0) dG = 0.499898881;
			if(iShape == 1) dG = 0.398579031;
			if(iShape == 2) dG = 0.522192419;
			break;
  		case 69:
			if(iShape == 0) dG = 0.499978751;
			if(iShape == 1) dG = 0.390042067;
			if(iShape == 2) dG = 0.523721218;
			break;
  		case 70:
			if(iShape == 0) dG = 0.500049353;
			if(iShape == 1) dG = 0.381619453;
			if(iShape == 2) dG = 0.525196016;
			break;
  		case 71:
			if(iShape == 0) dG = 0.500101626;
			if(iShape == 1) dG = 0.37329495;
			if(iShape == 2) dG = 0.526610672;
			break;
  		case 72:
			if(iShape == 0) dG = 0.500128388;
			if(iShape == 1) dG = 0.365056574;
			if(iShape == 2) dG = 0.527960241;
			break;
  		case 73:
			if(iShape == 0) dG = 0.500123739;
			if(iShape == 1) dG = 0.356895357;
			if(iShape == 2) dG = 0.529240429;
			break;
  		case 74:
			if(iShape == 0) dG = 0.500082791;
			if(iShape == 1) dG = 0.348804027;
			if(iShape == 2) dG = 0.530447483;
			break;
  		case 75:
			if(iShape == 0) dG = 0.500001431;
			if(iShape == 1) dG = 0.340777367;
			if(iShape == 2) dG = 0.531578541;
			break;
  		case 76:
			if(iShape == 0) dG = 0.499909699;
			if(iShape == 1) dG = 0.332972318;
			if(iShape == 2) dG = 0.532641292;
			break;
  		case 77:
			if(iShape == 0) dG = 0.499909699;
			if(iShape == 1) dG = 0.325889885;
			if(iShape == 2) dG = 0.533666611;
			break;
  		case 78:
			if(iShape == 0) dG = 0.499939263;
			if(iShape == 1) dG = 0.319242448;
			if(iShape == 2) dG = 0.534633636;
			break;
  		case 79:
			if(iShape == 0) dG = 0.499976695;
			if(iShape == 1) dG = 0.312934488;
			if(iShape == 2) dG = 0.535534143;
			break;
  		case 80:
			if(iShape == 0) dG = 0.50001055;
			if(iShape == 1) dG = 0.306919962;
			if(iShape == 2) dG = 0.536363542;
			break;
  		case 81:
			if(iShape == 0) dG = 0.500033379;
			if(iShape == 1) dG = 0.301170379;
			if(iShape == 2) dG = 0.537118435;
			break;
  		case 82:
			if(iShape == 0) dG = 0.500039756;
			if(iShape == 1) dG = 0.295666337;
			if(iShape == 2) dG = 0.537796378;
			break;
  		case 83:
			if(iShape == 0) dG = 0.50002563;
			if(iShape == 1) dG = 0.290393889;
			if(iShape == 2) dG = 0.538395226;
			break;
  		case 84:
			if(iShape == 0) dG = 0.499988586;
			if(iShape == 1) dG = 0.285354763;
			if(iShape == 2) dG = 0.538913429;
			break;
  		case 85:
			if(iShape == 0) dG = 0.499982446;
			if(iShape == 1) dG = 0.281210423;
			if(iShape == 2) dG = 0.539357305;
			break;
  		case 86:
			if(iShape == 0) dG = 0.49999097;
			if(iShape == 1) dG = 0.277785927;
			if(iShape == 2) dG = 0.539723694;
			break;
  		case 87:
			if(iShape == 0) dG = 0.499999851;
			if(iShape == 1) dG = 0.274927646;
			if(iShape == 2) dG = 0.540010095;
			break;
  		case 88:
			if(iShape == 0) dG = 0.500003815;
			if(iShape == 1) dG = 0.272580296;
			if(iShape == 2) dG = 0.540215313;
			break;
  		case 89:
			if(iShape == 0) dG = 0.500000477;
			if(iShape == 1) dG = 0.27076298;
			if(iShape == 2) dG = 0.540338457;
			break;
  		case 90:
			if(iShape == 0) dG = 0.5;
			if(iShape == 1) dG = 0.270189822;
			if(iShape == 2) dG = 0.540379643;
			break;
  		case 91:
			if(iShape == 0) dG = 0.500000477;
			if(iShape == 1) dG = 0.27076298;
			if(iShape == 2) dG = 0.540338457;
			break;
  		case 92:
			if(iShape == 0) dG = 0.500003815;
			if(iShape == 1) dG = 0.272580266;
			if(iShape == 2) dG = 0.540215313;
			break;
  		case 93:
			if(iShape == 0) dG = 0.499999821;
			if(iShape == 1) dG = 0.274927616;
			if(iShape == 2) dG = 0.540010095;
			break;
  		case 94:
			if(iShape == 0) dG = 0.49999091;
			if(iShape == 1) dG = 0.277785927;
			if(iShape == 2) dG =  0.539723694;
			break;
  		case 95:
			if(iShape == 0) dG = 0.499982446;
			if(iShape == 1) dG = 0.281210393;
			if(iShape == 2) dG = 0.539357305;
			break;
  		case 96:
			if(iShape == 0) dG = 0.499988586;
			if(iShape == 1) dG = 0.285354763;
			if(iShape == 2) dG = 0.538913369;
			break;
  		case 97:
			if(iShape == 0) dG = 0.50002563;
			if(iShape == 1) dG = 0.290393859;
			if(iShape == 2) dG = 0.538395226;
			break;
  		case 98:
			if(iShape == 0) dG = 0.500039756;
			if(iShape == 1) dG = 0.295666337;
			if(iShape == 2) dG = 0.537796378;
			break;
  		case 99:
			if(iShape == 0) dG = 0.500033379;
			if(iShape == 1) dG = 0.301170349;
			if(iShape == 2) dG = 0.537118435;
			break;
  		case 100:
			if(iShape == 0) dG = 0.50001055;
			if(iShape == 1) dG = 0.306919962;
			if(iShape == 2) dG = 0.536363542;
			break;
  		case 101:
			if(iShape == 0) dG = 0.499976724;
			if(iShape == 1) dG = 0.312934488;
			if(iShape == 2) dG = 0.535534203;
			break;
  		case 102:
			if(iShape == 0) dG = 0.499939263;
			if(iShape == 1) dG = 0.319242477;
			if(iShape == 2) dG = 0.534633636;
			break;
  		case 103:
			if(iShape == 0) dG = 0.499909699;
			if(iShape == 1) dG = 0.325889885;
			if(iShape == 2) dG = 0.533666611;
			break;
  		case 104:
			if(iShape == 0) dG = 0.499909699;
			if(iShape == 1) dG = 0.332972318;
			if(iShape == 2) dG = 0.532641292;
			break;
  		case 105:
			if(iShape == 0) dG = 0.500001431;
			if(iShape == 1) dG = 0.340777338;
			if(iShape == 2) dG = 0.531578541;
			break;
  		case 106:
			if(iShape == 0) dG = 0.500082791;
			if(iShape == 1) dG = 0.348804027;
			if(iShape == 2) dG = 0.530447483;
			break;
  		case 107:
			if(iShape == 0) dG = 0.500123739;
			if(iShape == 1) dG = 0.356895328;
			if(iShape == 2) dG = 0.529240429;
			break;
  		case 108:
			if(iShape == 0) dG = 0.500128388;
			if(iShape == 1) dG = 0.365056574;
			if(iShape == 2) dG = 0.527960241;
			break;
  		case 109:
			if(iShape == 0) dG = 0.500101626;
			if(iShape == 1) dG = 0.37329495;
			if(iShape == 2) dG = 0.526610672;
			break;
  		case 110:
			if(iShape == 0) dG = 0.500049353;
			if(iShape == 1) dG = 0.381619453;
			if(iShape == 2) dG = 0.525196016;
			break;
  		case 111:
			if(iShape == 0) dG = 0.499978751;
			if(iShape == 1) dG = 0.390042067;
			if(iShape == 2) dG = 0.523721218;
			break;
  		case 112:
			if(iShape == 0) dG = 0.499898911;
			if(iShape == 1) dG = 0.398579031;
			if(iShape == 2) dG = 0.522192419;
			break;
  		case 113:
			if(iShape == 0) dG = 0.49982214;
			if(iShape == 1) dG = 0.40725404;
			if(iShape == 2) dG = 0.520617783;
			break;
  		case 114:
			if(iShape == 0) dG = 0.499766827;
			if(iShape == 1) dG = 0.416104615;
			if(iShape == 2) dG = 0.519008398;
			break;
  		case 115:
			if(iShape == 0) dG = 0.499767154;
			if(iShape == 1) dG = 0.425206631;
			if(iShape == 2) dG = 0.517384768;
			break;
  		case 116:
			if(iShape == 0) dG = 0.499927521;
			if(iShape == 1) dG = 0.434804648;
			if(iShape == 2) dG = 0.515805602;
			break;
  		case 117:
			if(iShape == 0) dG = 0.500094891;
			if(iShape == 1) dG = 0.444521278;
			if(iShape == 2) dG = 0.514188588;
			break;
  		case 118:
			if(iShape == 0) dG = 0.500202358;
			if(iShape == 1) dG = 0.454187423;
			if(iShape == 2) dG = 0.512498915;
			break;
  		case 119:
			if(iShape == 0) dG = 0.500254452;
			if(iShape == 1) dG = 0.463804543;
			if(iShape == 2) dG = 0.510741234;
			break;
  		case 120:
			if(iShape == 0) dG = 0.500256419;
			if(iShape == 1) dG = 0.47337541;
			if(iShape == 2) dG = 0.50892055;
			break;
  		case 121:
			if(iShape == 0) dG = 0.500214398;
			if(iShape == 1) dG = 0.482903272;
			if(iShape == 2) dG = 0.507042527;
			break;
  		case 122:
			if(iShape == 0) dG = 0.500135422;
			if(iShape == 1) dG = 0.492393136;
			if(iShape == 2) dG = 0.505114019;
			break;
  		case 123:
			if(iShape == 0) dG = 0.500028074;
			if(iShape == 1) dG = 0.501851082;
			if(iShape == 2) dG = 0.503142774;
			break;
  		case 124:
			if(iShape == 0) dG = 0.499902993;
			if(iShape == 1) dG = 0.51128608;
			if(iShape == 2) dG = 0.50113821;
			break;
  		case 125:
			if(iShape == 0) dG = 0.499773562;
			if(iShape == 1) dG = 0.520710588;
			if(iShape == 2) dG = 0.499112219;
			break;
  		case 126:
			if(iShape == 0) dG = 0.499658436;
			if(iShape == 1) dG = 0.530142844;
			if(iShape == 2) dG = 0.497080863;
			break;
  		case 127:
			if(iShape == 0) dG = 0.499586105;
			if(iShape == 1) dG = 0.53961426;
			if(iShape == 2) dG = 0.495067775;
			break;
  		case 128:
			if(iShape == 0) dG = 0.499614954;
			if(iShape == 1) dG = 0.549192965;
			if(iShape == 2) dG = 0.493120641;
			break;
  		case 129:
			if(iShape == 0) dG = 0.499884844;
			if(iShape == 1) dG = 0.5590505;
			if(iShape == 2) dG = 0.491351187;
			break;
  		case 130:
			if(iShape == 0) dG = 0.500120044;
			if(iShape == 1) dG = 0.568832099;
			if(iShape == 2) dG = 0.489543438;
			break;
  		case 131:
			if(iShape == 0) dG = 0.500278115;
			if(iShape == 1) dG = 0.578477561;
			if(iShape == 2) dG = 0.487665802;
			break;
  		case 132:
			if(iShape == 0) dG = 0.500364125;
			if(iShape == 1) dG = 0.587987065;
			if(iShape == 2) dG = 0.485724121;
			break;
  		case 133:
			if(iShape == 0) dG = 0.500384033;
			if(iShape == 1) dG = 0.597360373;
			if(iShape == 2) dG = 0.483725131;
			break;
  		case 134:
			if(iShape == 0) dG = 0.500344753;
			if(iShape == 1) dG = 0.606598675;
			if(iShape == 2) dG = 0.481676757;
			break;
  		case 135:
			if(iShape == 0) dG = 0.500254452;
			if(iShape == 1) dG = 0.615703642;
			if(iShape == 2) dG = 0.479587853;
			break;
  		case 136:
			if(iShape == 0) dG = 0.500122905;
			if(iShape == 1) dG = 0.624677658;
			if(iShape == 2) dG = 0.477469325;
			break;
  		case 137:
			if(iShape == 0) dG = 0.49996227;
			if(iShape == 1) dG = 0.633524835;
			if(iShape == 2) dG = 0.475333989;
			break;
  		case 138:
			if(iShape == 0) dG = 0.499787658;
			if(iShape == 1) dG = 0.642251015;
			if(iShape == 2) dG = 0.473198175;
			break;
  		case 139:
			if(iShape == 0) dG = 0.499619693;
			if(iShape == 1) dG = 0.650865316;
			if(iShape == 2) dG = 0.471083313;
			break;
  		case 140:
			if(iShape == 0) dG = 0.499488503;
			if(iShape == 1) dG = 0.659382582;
			if(iShape == 2) dG = 0.469020724;
			break;
  		case 141:
			if(iShape == 0) dG = 0.499447078;
			if(iShape == 1) dG = 0.667832196;
			if(iShape == 2) dG = 0.467064291;
			break;
  		case 142:
			if(iShape == 0) dG = 0.499669343;
			if(iShape == 1) dG = 0.676318705;
			if(iShape == 2) dG = 0.465389222;
			break;
  		case 143:
			if(iShape == 0) dG = 0.500001371;
			if(iShape == 1) dG = 0.684741497;
			if(iShape == 2) dG = 0.46384266;
			break;
  		case 144:
			if(iShape == 0) dG = 0.500237286;
			if(iShape == 1) dG = 0.692968488;
			if(iShape == 2) dG = 0.46222046;
			break;
  		case 145:
			if(iShape == 0) dG = 0.500382781;
			if(iShape == 1) dG = 0.700998068;
			if(iShape == 2) dG = 0.460529804;
			break;
  		case 146:
			if(iShape == 0) dG = 0.500444114;
			if(iShape == 1) dG = 0.708829522;
			if(iShape == 2) dG = 0.458778411;
			break;
  		case 147:
			if(iShape == 0) dG = 0.500428915;
			if(iShape == 1) dG = 0.716462374;
			if(iShape == 2) dG = 0.456975698;
			break;
  		case 148:
			if(iShape == 0) dG = 0.500346363;
			if(iShape == 1) dG = 0.723896205;
			if(iShape == 2) dG = 0.455133021;
			break;
  		case 149:
			if(iShape == 0) dG = 0.500207722;
			if(iShape == 1) dG = 0.731131613;
			if(iShape == 2) dG = 0.453263819;
			break;
  		case 150:
			if(iShape == 0) dG = 0.50002718;
			if(iShape == 1) dG = 0.73816967;
			if(iShape == 2) dG = 0.45138523;
			break;
  		case 151:
			if(iShape == 0) dG = 0.499823421;
			if(iShape == 1) dG = 0.74501282;
			if(iShape == 2) dG = 0.449519157;
			break;
  		case 152:
			if(iShape == 0) dG = 0.499622017;
			if(iShape == 1) dG = 0.751664996;
			if(iShape == 2) dG = 0.447695971;
			break;
  		case 153:
			if(iShape == 0) dG = 0.499462336;
			if(iShape == 1) dG = 0.758134186;
			if(iShape == 2) dG = 0.445961446;
			break;
  		case 154:
			if(iShape == 0) dG = 0.499418437;
			if(iShape == 1) dG = 0.764437258;
			if(iShape == 2) dG = 0.444401413;
			break;
  		case 155:
			if(iShape == 0) dG = 0.499717474;
			if(iShape == 1) dG = 0.770630836;
			if(iShape == 2) dG = 0.443277717;
			break;
  		case 156:
			if(iShape == 0) dG = 0.500050604;
			if(iShape == 1) dG = 0.776631653;
			if(iShape == 2) dG = 0.442236453;
			break;
  		case 157:
			if(iShape == 0) dG = 0.500273287;
			if(iShape == 1) dG = 0.782398939;
			if(iShape == 2) dG = 0.441112041;
			break;
  		case 158:
			if(iShape == 0) dG = 0.500391722;
			if(iShape == 1) dG = 0.787931442;
			if(iShape == 2) dG = 0.439912915;
			break;
  		case 159:
			if(iShape == 0) dG = 0.500414193;
			if(iShape == 1) dG = 0.793228447;
			if(iShape == 2) dG = 0.438649505;
			break;
  		case 160:
			if(iShape == 0) dG = 0.500350893;
			if(iShape == 1) dG = 0.798288643;
			if(iShape == 2) dG = 0.437335044;
			break;
  		case 161:
			if(iShape == 0) dG = 0.50021559;
			if(iShape == 1) dG = 0.80311197;
			if(iShape == 2) dG = 0.435986549;
			break;
  		case 162:
			if(iShape == 0) dG = 0.500026762;
			if(iShape == 1) dG = 0.807698011;
			if(iShape == 2) dG = 0.434627414;
			break;
  		case 163:
			if(iShape == 0) dG = 0.499810904;
			if(iShape == 1) dG = 0.81204772;
			if(iShape == 2) dG = 0.43329069;
			break;
  		case 164:
			if(iShape == 0) dG = 0.499609768;
			if(iShape == 1) dG = 0.816162884;
			if(iShape == 2) dG = 0.432028234;
			break;
  		case 165:
			if(iShape == 0) dG = 0.49950251;
			if(iShape == 1) dG = 0.82004869;
			if(iShape == 2) dG = 0.430938095;
			break;
  		case 166:
			if(iShape == 0) dG = 0.499744058;
			if(iShape == 1) dG = 0.823724508;
			if(iShape == 2) dG = 0.430334896;
			break;
  		case 167:
			if(iShape == 0) dG = 0.500054181;
			if(iShape == 1) dG = 0.827166021;
			if(iShape == 2) dG = 0.429873556;
			break;
  		case 168:
			if(iShape == 0) dG = 0.500237644;
			if(iShape == 1) dG = 0.830355883;
			if(iShape == 2) dG = 0.429313898;
			break;
  		case 169:
			if(iShape == 0) dG = 0.500302255;
			if(iShape == 1) dG = 0.833293319;
			if(iShape == 2) dG = 0.428665817;
			break;
  		case 170:
			if(iShape == 0) dG = 0.500259459;
			if(iShape == 1) dG = 0.835977495;
			if(iShape == 2) dG = 0.427944094;
			break;
  		case 171:
			if(iShape == 0) dG = 0.500127017;
			if(iShape == 1) dG = 0.838408053;
			if(iShape == 2) dG = 0.427171528;
			break;
  		case 172:
			if(iShape == 0) dG = 0.49993524;
			if(iShape == 1) dG = 0.840584397;
			if(iShape == 2) dG = 0.426386476;
			break;
  		case 173:
			if(iShape == 0) dG = 0.499743372;
			if(iShape == 1) dG = 0.842506945;
			if(iShape == 2) dG = 0.425664425;
			break;
  		case 174:
			if(iShape == 0) dG = 0.499743491;
			if(iShape == 1) dG = 0.844177723;
			if(iShape == 2) dG = 0.425248444;
			break;
		case 175:
			if(iShape == 0) dG = 0.500012875;
			if(iShape == 1) dG = 0.845597386;
			if(iShape == 2) dG = 0.425236553;
			break;
		case 176:
			if(iShape == 0) dG = 0.500136793;
			if(iShape == 1) dG = 0.846759379;
			if(iShape == 2) dG = 0.425103933;
			break;
		case 177:
			if(iShape == 0) dG = 0.500122428;
			if(iShape == 1) dG = 0.847663522;
			if(iShape == 2) dG = 0.424859732;
			break;
		case 178:
			if(iShape == 0) dG = 0.499992937;
			if(iShape == 1) dG = 0.848309398;
			if(iShape == 2) dG = 0.424533367;
			break;
		case 179:
			if(iShape == 0) dG = 0.499923885;
			if(iShape == 1) dG = 0.848697066;
			if(iShape == 2) dG = 0.424348533;
			break;
		case 180:
			if(iShape == 0) dG = 0.5;
			if(iShape == 1) dG = 0.848826408;
			if(iShape == 2) dG = 0.424413204;
			break;
		default:
			break;
	 }
}

void quality_control(CData& data, std::vector<double>& aryData)
{
	double dZvalue = 3.0;
	int iCurrentStart, iPeriod;
	
	for(int iCurrent = 0; iCurrent < aryData.size(); iCurrent++){

		// apply moving window
		if( iCurrent % g_iRunPerDay == 0){
			iPeriod = data.m_aryPeriod[iCurrent];

			int iWindowSize = (g_iWindowSize - 1) / 2;
			int iStart = iCurrent - iWindowSize * g_iRunPerDay;
			int iEnd   = iCurrent + (iWindowSize + 1) * g_iRunPerDay;
			if(iStart < 0){
				iStart = 0;
			}
			if(iEnd > aryData.size()){
				iEnd = aryData.size();
			}
			iCurrentStart = iCurrent - iStart;

			vector<double> aryTargetData;
			vector<int> aryFlag;
			for(int iMoving = iStart; iMoving < iEnd; iMoving++){
				if(g_bPeriod == true && data.m_aryPeriod[iMoving / g_iRunPerDay] != iPeriod){
					continue;
				}
				aryTargetData.push_back(aryData[iMoving]);
			}
			QualityControl_MAD(aryTargetData, aryFlag, dZvalue);
			
			for(int iFlg = 0; iFlg < aryFlag.size(); iFlg++ ){
				if(aryFlag[iFlg] == 1 && iFlg >= iCurrentStart && iFlg < (iCurrentStart + g_iRunPerDay) ){
					aryData[iStart + iFlg] = c_dError;
				}
			}
		}
	}
}

void QualityControl_MAD(std::vector<double>& aryData, std::vector<int>& aryQC_flg, const double& dZvalue)
{
	// 欠測値を読み飛ばしたデータセットを作成
	vector<double> aryNoGapData;	
	for(int i = 0; i < aryData.size(); i++){
		if(aryData[i] != c_dError){
			aryNoGapData.push_back(aryData[i]);
		}
	}

	// MAD を適用して、フラグを作成
	vector<int> aryQC_flag;
	if(aryNoGapData.size() != 0) MedianOfAbsoluteDeviation(aryNoGapData, aryQC_flag, dZvalue);

	// 欠測値のあるデータにフラグを反映
	int iAll = 0, bLoopNum = 0;
	if(aryQC_flg.size() != 0) bLoopNum = 1;
	for(i = 0; i < aryData.size(); i++){
		if(aryData[i] != c_dError){
			if(bLoopNum == 0){
				aryQC_flg.push_back(aryQC_flag[iAll]);
				iAll++;
			}
			else{
				if(aryQC_flg[i] == 0) aryQC_flg[i] = aryQC_flag[iAll];
				iAll++;
			}
		}
		else{
			if(bLoopNum == 0){
				aryQC_flg.push_back(-1);			// もともと欠測の場合は、「-1」を挿入
			}
		}
	}
}

void MedianOfAbsoluteDeviation(const std::vector<double>& aryNoGapData, std::vector<int>& aryQC_flag, const double& dZvalue)
{
	vector<double> aryDvalue;
	for(int i = 0; i < aryNoGapData.size(); i++){
		if(i == 0 || i == (aryNoGapData.size() - 1) ){
			aryDvalue.push_back(0.0);
			continue;
		}

		// equation 1 for Papale et al., 2006
		aryDvalue.push_back( (aryNoGapData[i] - aryNoGapData[i - 1]) - (aryNoGapData[i + 1] - aryNoGapData[i]));
	}

	// equation 4 for Papale et al., 2006
	double Md = Median(aryDvalue);
	vector<double> aryAbsD_Md;

	for(i = 0; i < aryNoGapData.size(); i++){
		aryAbsD_Md.push_back(fabs(aryDvalue[i] - Md));
		double MAD = Median(aryAbsD_Md);

		if(aryDvalue[i] < Md - (dZvalue * MAD / 0.6745)  ||  aryDvalue[i] > Md + (dZvalue * MAD / 0.6745) ){
			aryQC_flag.push_back(1);
		}
		else{
			aryQC_flag.push_back(0);
		}
	}

	// for first and last data cannot be applied this method, and then simply set NO-Error flag.
	aryQC_flag[0] = 0;
	aryQC_flag[aryNoGapData.size() - 1] = 0;
}

double Median(std::vector<double> aryDouble)
{
	double median = c_dError;
	std::sort(aryDouble.begin(),aryDouble.end());		//昇順ソート

	 // メジアンを求める
    if(aryDouble.size() % 2 == 1)  // データ数が奇数個の場合
    {
        median = aryDouble[(aryDouble.size() - 1) / 2];  // メジアン
    }
    else  // データ数が偶数の場合
    {
        median = (aryDouble[(aryDouble.size() / 2) - 1] + aryDouble[aryDouble.size() / 2]) / 2.0;  // メジアン
	}

	return median;
}

void model_stomatal_conductance_Oren1999(CData& data, CDailyData& daily)
{
	// calculating coeffieicnt of the stomatal conductance model by Oren et al. (1999)
	// Oren et al. 1999    : Survey and synthesis of intra- and interspecific variation in stomatal sensitivity to vapor pressure deficit.
	//      Plant Cell Environment, 22, 1515-1526.
	int iPeriod;
	
	for(int iCurrent = 0; iCurrent < data.m_aryPeriod.size(); iCurrent++){

		// apply moving window
		if( iCurrent % g_iRunPerDay == 0){
			iPeriod = data.m_aryPeriod[iCurrent];

			int iWindowSize = (g_iWindowSize_Oren - 1) / 2;
			int iStart = iCurrent - iWindowSize * g_iRunPerDay;
			int iEnd   = iCurrent + (iWindowSize + 1) * g_iRunPerDay;
			if(iStart < 0){
				iStart = 0;
			}
			if(iEnd > data.m_aryPeriod.size()){
				iEnd = data.m_aryPeriod.size();
			}

			vector<double> aryGc, aryTa, aryVPD, aryPressure, aryRH;
			vector<int> aryFlag;
			for(int iMoving = iStart; iMoving < iEnd; iMoving++){
				if(g_bPeriod == true && data.m_aryPeriod[iMoving / g_iRunPerDay] != iPeriod){
					continue;
				}
				aryGc.push_back(data.m_aryGc[iMoving]);
				aryTa.push_back(data.m_aryTa[iMoving]);
				aryVPD.push_back(data.m_aryVPD[iMoving]);
				aryPressure.push_back(data.m_aryPressure[iMoving]);
				aryRH.push_back(data.m_aryRH[iMoving]);
			}

			double dGs_ref, dM, dR2;
			model_stomatal_conductance_Oren1999(aryGc, aryVPD, aryTa, aryPressure, aryRH, dGs_ref, dM, dR2);
			daily.m_aryGs_ref.push_back(dGs_ref);
			daily.m_aryM.push_back(dM);
			daily.m_aryR2_Oren.push_back(dR2);
		}
	}

	// using all data
	double dGs_ref, dM, dR2;
	model_stomatal_conductance_Oren1999(data.m_aryGc, data.m_aryVPD, data.m_aryTa, data.m_aryPressure, data.m_aryRH, dGs_ref, dM, dR2);
	daily.m_aryGs_ref.push_back(dGs_ref);
	daily.m_aryM.push_back(dM);
	daily.m_aryR2_Oren.push_back(dR2);
}

void model_stomatal_conductance_Oren1999(std::vector<double>& aryGc, std::vector<double>& aryVPD, std::vector<double>& aryTa, std::vector<double>&  aryPressure, std::vector<double>& aryRH, double& dGs_ref, double& dM, double& dR2)
{
	// calculating coeffieicnt of the stomatal conductance model by Oren et al. (1999) based on Igarashi et al. (2015)
	// Igarashi et al. 2015: Environmental control of stomatal conductance in a tropical deciduous forest in northern Thailand
	//      Agricultural and Forest Meteorology, 202, 1-10.
	// Oren et al. 1999    : Survey and synthesis of intra- and interspecific variation in stomatal sensitivity to vapor pressure deficit.
	//      Plant Cell Environment, 22, 1515-1526.
	const double c_dMinimumVPD = 6;		// hPa
	const int c_iMaximumVPD = 50;		// hPa
	const int c_iVPDStep    = 5;		// hPa

	vector<double> aryBoundaryVPD;
	vector<double> aryVPD_no_error, aryGc_no_error;
	vector<double> aryVPD_interval, aryGc_interval;

	// removing error data
	for(int i = 0; i < aryGc.size(); i++){
		if(aryGc[i] != c_dError && aryTa[i] != c_dError && aryVPD[i] > c_dMinimumVPD){
			// double dRow  = 1.293 / (1.0 + 0.00367 * aryTa[i] );					// kg m-3
			double dRow  = calculate_air_density(aryTa[i], aryPressure[i], aryRH[i], 0);
			aryVPD_no_error.push_back(aryVPD[i]);
			aryGc_no_error.push_back(aryGc[i] * dRow * 1000000.0 / 28.96 );		// (m s-1) -> (mmol m-2 s-1)
		}
	}

	for(int dCurrentInterval_VPD = 0; dCurrentInterval_VPD <= c_iMaximumVPD; dCurrentInterval_VPD += c_iVPDStep){
		vector<double> _aryGs, _aryVPD;
		for(int i = 0; i < aryVPD_no_error.size(); i++){
			if(aryVPD_no_error[i] >= dCurrentInterval_VPD && aryVPD_no_error[i] < (dCurrentInterval_VPD + c_iVPDStep) ){
				_aryGs.push_back(aryGc_no_error[i]);
				_aryVPD.push_back(aryVPD_no_error[i]);
			}
		}

		if(_aryGs.size() != 0){
			// average and standard deviation
			double dGs_ave = c_dError, dGs_std = c_dError, dVPD_ave = c_dError, dVPD_std = c_dError;
			average_stdev(_aryGs, dGs_ave, dGs_std);
			average_stdev(_aryVPD, dVPD_ave, dVPD_std);

			// removing outliner
			remove_out_linear_Dixon(_aryGs, _aryVPD);

			// selecting data above the mean plus 1 standard deviation
			vector<double> _aryGs_target, _aryVPD_target;
			for(i = 0; i < _aryGs.size(); i++){
				if(_aryGs[i] > dGs_ave + dGs_std){
					_aryGs_target.push_back(_aryGs[i]);
					_aryVPD_target.push_back(_aryVPD[i]);
				}
			}

			// averaging the selected data for each VPD interval
			if(_aryGs_target.size() != 0){
				average_stdev(_aryGs_target, dGs_ave, dGs_std);
				average_stdev(_aryVPD_target, dVPD_ave, dVPD_std);

				aryGc_interval.push_back(dGs_ave);					// (mmol m-2 s-1)
				aryVPD_interval.push_back( log(dVPD_ave / 10.0) );	// ln(hPa) -> ln(kPa)
			}
		}
	}

	// calculating coefficients of a linear regression 
	if(aryGc_interval.size() > 2 ){
		linear_regression(aryGc_interval, aryVPD_interval, dM, dGs_ref,dR2);
		dM *= -1.0;
	}
	else{
		dM = c_dError; 
		dGs_ref = c_dError;
		dR2 = c_dError;
	}
}

void calculate_water_light_use_efficiency(CData& data, CDailyData& daily)
{
	const double c_dMinLE = 10;			// minimum LE for calculating WUE (W m-2)
	const double c_dMinET = 1.0;		// minimum daily ET for calculating WUE (mmol m-2 s-1)
	const double c_dMinPPFD = 5.0;		// minimum PPFD for calculating LUE (umol m-2 s-1)
	const double c_dMinPPFD_day = 5.0;	// minimum daily PPFD for calculating LUE (umol m-2 s-1)

	double dET;						// evapotranspiration (mmol m-2 s-1)
	double dET_daily = 0.0;			// daily evapotranspiration (mmol m-2 s-1)
	double dGPP_daily = 0.0;		// daily GPP (umol m-2 s-1)
	double dGPP_ppfd_daily = 0.0;	// daily GPP (umol m-2 s-1)
	double dPPFD_daily = 0.0;		// dialy PPFD (umol m-2 s-1)
	double dET_annual = 0.0;		// annual evapotranspiration (mmol m-2 s-1)
	double dGPP_annual = 0.0;		// annual GPP (umol m-2 s-1)
	double dGPP_ppfd_annual = 0.0;	// annual GPP (umol m-2 s-1)
	double dPPFD_annual = 0.0;		// annual PPFD (umol m-2 s-1)

	for(int i = 0; i < data.m_aryDate.size(); i++){
		dET = data.m_aryLE[i] / ( calculate_latent_heat(data.m_aryTa[i]));	// (W m-2) -> (kg m-2 s-1)
		dET = dET * 1000.0 * 1000.0 / 18.0;		// mmol m-2 s-1

		if(fabs(data.m_aryLE[i]) < c_dMinLE || data.m_aryGPP[i] == 0.0 || data.m_aryGPP[i] == c_dError || data.m_aryLE[i] == c_dError){
			data.m_aryWUE[i] = c_dError;
		}
		else{
			data.m_aryWUE[i] = data.m_aryGPP[i] / dET;
		}

		if(data.m_aryPPFD[i] < c_dMinPPFD || data.m_aryGPP[i] == 0.0 || data.m_aryGPP[i] == c_dError){
			data.m_aryLUE[i] = c_dError;
		}
		else{
			data.m_aryLUE[i] = data.m_aryGPP[i] / data.m_aryPPFD[i];
		}

		// caluculating daily value
		if(data.m_aryGPP[i] != c_dError && data.m_aryLE[i] != c_dError){
			dGPP_daily += data.m_aryGPP[i];
			dET_daily += dET;
			dGPP_annual += data.m_aryGPP[i];
			dET_annual += dET;
		}
		if(data.m_aryGPP[i] != c_dError && data.m_aryPPFD[i] != c_dError){
			dGPP_ppfd_daily += data.m_aryGPP[i];
			dPPFD_daily += data.m_aryPPFD[i];
			dGPP_ppfd_annual += data.m_aryGPP[i];
			dPPFD_annual += data.m_aryPPFD[i];
		}

		if(i != 0 && i % g_iRunPerDay == 0 || i == data.m_aryDate.size() - 1){
			// water use efficiency
			daily.m_aryWUE.push_back( dGPP_daily / dET_daily );
			if(fabs(dET_daily) < c_dMinET){
				daily.m_aryWUE[ daily.m_aryWUE.size() - 1 ] = c_dError;
			}
			dGPP_daily = 0.0;
			dET_daily = 0.0;

			// light use efficiency
			daily.m_aryLUE.push_back( dGPP_ppfd_daily / dPPFD_daily );
			if(dGPP_ppfd_daily < c_dMinPPFD_day){
				daily.m_aryLUE[ daily.m_aryLUE.size() - 1 ] = c_dError;
			}
			dGPP_ppfd_daily = 0.0;
			dPPFD_daily = 0.0;
		}
	}
	daily.m_aryWUE.push_back( dGPP_annual / dET_annual );
	daily.m_aryLUE.push_back( dGPP_ppfd_annual / dPPFD_annual );
}

void average_stdev(const std::vector<double>& x, double& average, double& stdev)
{   
	// average and standard deviation
    double S = 0;
	double Tx = 0;
	double Txx = 0;

    for(int i = 0; i < x.size(); i++)
    {
    	Tx += x[i];
        Txx += x[i] * x[i];
    }
	average = Tx / x.size();
    stdev = sqrt( (Txx - Tx * Tx / x.size()) / x.size() );
}

void remove_out_linear_Dixon(std::vector<double>& aryTargetData, std::vector<double>& aryPairedData)
{
	// if data number is less than two, skip this sub-program
	if(aryTargetData.size() <= 2){
		return;
	}

	// calculating range of data
	vector<double> _aryTargetData, _aryPairedData;
	double dMax1 = c_dError, dMax2 = c_dError, dMin = -c_dError;
	int iMaximumColumn = -1;
	for(int i = 0; i < aryTargetData.size(); i++){
		_aryTargetData.push_back(aryTargetData[i]);
		_aryPairedData.push_back(aryPairedData[i]);
		if(aryTargetData[i] > dMax1){
			dMax2 = dMax1;
			dMax1 = aryTargetData[i];
			iMaximumColumn = i;
		}
		if(aryTargetData[i] < dMin){
			dMin = aryTargetData[i];
		}
	}
	if(dMax1 != c_dError && dMax2 == c_dError){
		for(i = 0; i < aryTargetData.size(); i++){
			if(aryTargetData[i] > dMax2 && aryTargetData[i] != dMax1){
				dMax2 = aryTargetData[i];
			}
		}
	}
	double dRange = dMax1 - dMin;
	double dGap   = dMax1 - dMax2;

	// test upper boudary using Dixon test
	double dQ95 = look_up_Dixon_table(aryTargetData.size());
	if(dQ95 > dGap / dRange){
		aryTargetData.clear();
		aryPairedData.clear();
		for(i = 0; i < _aryTargetData.size(); i++){
			if(i != iMaximumColumn){
				aryTargetData.push_back(_aryTargetData[i]);
				aryPairedData.push_back(_aryPairedData[i]);
			}
		}
	}
}

double look_up_Dixon_table(const int& n)
{
	// Bohrer (2008): One-sided and two-sided critical values for Dixon's outlier test for sample size up to n = 30.
	//    Economic Quality Control, 23, 5-13.
	double dQvalue = c_dError;

	// p = 0.05; one-side test
	if(n == 3)	dQvalue = 0.94125;
	if(n == 4)	dQvalue = 0.76548;
	if(n == 5)	dQvalue = 0.64231;
	if(n == 6)	dQvalue = 0.56246;
	if(n == 7)	dQvalue = 0.50734;
	if(n == 8)	dQvalue = 0.55401;
	if(n == 9)	dQvalue = 0.51116;
	if(n == 10)	dQvalue = 0.47793;
	if(n == 11)	dQvalue = 0.57493;
	if(n == 12)	dQvalue = 0.54563;
	if(n == 13)	dQvalue = 0.52123;
	if(n == 14)	dQvalue = 0.5455;
	if(n == 15)	dQvalue = 0.52403;
	if(n == 16)	dQvalue = 0.50533;
	if(n == 17)	dQvalue = 0.48903;
	if(n == 18)	dQvalue = 0.47458;
	if(n == 19)	dQvalue = 0.46167;
	if(n == 20)	dQvalue = 0.45006;
	if(n == 21)	dQvalue = 0.43957;
	if(n == 22)	dQvalue = 0.43;
	if(n == 23)	dQvalue = 0.42125;
	if(n == 24)	dQvalue = 0.41324;
	if(n == 25)	dQvalue = 0.40581;
	if(n == 26)	dQvalue = 0.39891;
	if(n == 27)	dQvalue = 0.39257;
	if(n == 28)	dQvalue = 0.38658;
	if(n == 29)	dQvalue = 0.38101;
	if(n >= 30)	dQvalue = 0.37575;

	return dQvalue;
}

void DeleteSpace(std::string &buf)
{
    size_t pos;
    while((pos = buf.find_first_of(" 　\t")) != string::npos){
        buf.erase(pos, 1);
    }
}

void DeleteComment(std::string &buf)
{
	if(buf.find("//", 0) != -1){
		int iPosition = buf.find("//", 0); 
		buf.erase(iPosition, buf.length() - iPosition);
	}
}

int read_setting_file(const char strInSettingFile[] )
{
	FILE* in;
	bool bIsOK = true;
	char strLine[MAX_NUM];
	char *pChar;
	string strLines, strTemp;

	if((in = fopen(strInSettingFile, "rt")) == NULL){
		printf("Input parameter file could not opened.\n");
		bIsOK = false;
		return bIsOK;
	}

	// read file
	while(fgets(strLine, sizeof(strLine), in) != NULL){
		string strLines = strLine;

		// skip blank and comment lines
		if(strLines.size() <= 1){
			continue;
		}
		if(strLines.find("//", 0) == 0){
			continue;
		}

		// delete comment
		if(strLines.find("//", 0) != -1){
			int iPosition = strLines.find("//", 0); 
			strLines.erase(iPosition, strLines.length() - iPosition);
		}

		// read parameters (site information)
		if(strLines.find("Latitude", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("Latitude"), " "); 
			DeleteSpace(strLines);
			g_dLatitude = atof( strLines.c_str() );
			continue;
		}

		if(strLines.find("Longitude", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("Longitude"), " "); 
			DeleteSpace(strLines);
			g_dLongitude = atof( strLines.c_str() );
			continue;
		}

		if(strLines.find("Elevation", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("Elevation"), " "); 
			DeleteSpace(strLines);
			g_dElevation = atof( strLines.c_str() );
			continue;
		}

		if(strLines.find("CanopyHeight", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("CanopyHeight"), " "); 
			DeleteSpace(strLines);
			g_dCanopyHeight = atof( strLines.c_str() );
			continue;
		}

		if(strLines.find("MeasurementHeight", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("MeasurementHeight"), " "); 
			DeleteSpace(strLines);
			g_dMeasurementHeight = atof( strLines.c_str() );
			continue;
		}

		// read parameters (general setting)
		if(strLines.find("RunPerDay", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("RunPerDay"), " "); 
			DeleteSpace(strLines);
			g_iRunPerDay = atoi( strLines.c_str() );
			continue;
		}
		
		if(strLines.find("WindowSize_optimization", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("WindowSize_optimization"), " "); 
			DeleteSpace(strLines);
			g_iWindowSize = atoi( strLines.c_str() );
			continue;
		}
		
		if(strLines.find("WindowSize_conductance", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("WindowSize_conductance"), " "); 
			DeleteSpace(strLines);
			g_iWindowSize_Oren = atoi( strLines.c_str() );
			continue;
		}
		
		if(strLines.find("ForwarmdMode", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("ForwarmdMode"), " "); 
			DeleteSpace(strLines);
			g_iForwarmdMode = atoi( strLines.c_str() );
			continue;
		}

		// read parameters (model setting)
		if(strLines.find("CanopyStructure", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("CanopyStructure"), " "); 
			DeleteSpace(strLines);
			g_iCanopyStructure = atoi( strLines.c_str() );
			continue;
		}

		if(strLines.find("StomatalModel", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("StomatalModel"), " "); 
			DeleteSpace(strLines);
			g_iLeuningModel = atoi( strLines.c_str() );
			continue;
		}

		if(strLines.find("PhotosynthesisFunctions", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("PhotosynthesisFunctions"), " "); 
			DeleteSpace(strLines);
			g_iPhotosynthesisFunctions = atoi( strLines.c_str() );
			continue;
		}

		if(strLines.find("Energy_Balance", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("Energy_Balance"), " "); 
			DeleteSpace(strLines);
			g_iImbalanceCorrection = atoi( strLines.c_str() );
			continue;
		}

		if(strLines.find("Soil_Evaporation", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("Soil_Evaporation"), " "); 
			DeleteSpace(strLines);
			g_iSoilEvaporation = atoi( strLines.c_str() );
			continue;
		}

		if(strLines.find("UseAPAR", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("UseAPAR"), " "); 
			DeleteSpace(strLines);
			g_iUseAPAR = atoi( strLines.c_str() );
			continue;
		}

		if(strLines.find("UseKB_inverse", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("UseKB_inverse"), " "); 
			DeleteSpace(strLines);
			g_iUseKB_inverse = atoi( strLines.c_str() );
			continue;
		}

		if(strLines.find("Filling", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("Filling"), " "); 
			DeleteSpace(strLines);
			g_iFilling = atoi( strLines.c_str() );
			continue;
		}

		if(strLines.find("PrecipitationFilter", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("PrecipitationFilter"), " "); 
			DeleteSpace(strLines);
			g_iPrecipitationFilter = atoi( strLines.c_str() );
			continue;
		}

		if(strLines.find("UstarThreshold", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("UstarThreshold"), " "); 
			DeleteSpace(strLines);
			g_dUstarThreshold = atof( strLines.c_str() );
			continue;
		}

		// read parameters (radiative transfer model)
		if(strLines.find("OmegaOptimization", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("OmegaOptimization"), " "); 
			DeleteSpace(strLines);
			g_iOmegaOptimization = atoi( strLines.c_str() );
			continue;
		}
		
		if(strLines.find("Omega", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("Omega"), " "); 
			DeleteSpace(strLines);
			g_dOmega = atof( strLines.c_str() );
			continue;
		}
		
		if(strLines.find("Shape", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("Shape"), " "); 
			DeleteSpace(strLines);
			g_iShape = atof( strLines.c_str() );
			continue;
		}
		
		if(strLines.find("leaf_scatter_PAR", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("leaf_scatter_PAR"), " "); 
			DeleteSpace(strLines);
			g_dSigma_scattering = atof( strLines.c_str() );
			continue;
		}
		
		if(strLines.find("leaf_scatter_NIR", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("leaf_scatter_NIR"), " "); 
			DeleteSpace(strLines);
			g_dLeaf_scattering_nir = atof( strLines.c_str() );
			continue;
		}
		
		if(strLines.find("soil_reflectance_PAR", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("soil_reflectance_PAR"), " "); 
			DeleteSpace(strLines);
			g_dSoilReflectance_ppfd = atof( strLines.c_str() );
			continue;
		}
		
		if(strLines.find("soil_reflectance_NIR", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("soil_reflectance_NIR"), " "); 
			DeleteSpace(strLines);
			g_dSoilReflectance_nir = atof( strLines.c_str() );
			continue;
		}

		// read parameters (foliage nitrogen decay coefficient)
		if(strLines.find("Kn", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("Kn"), " "); 
			DeleteSpace(strLines);
			g_dKn = atof( strLines.c_str() );
			continue;
		}

		// read parameters (sec-ua setting)
		if(strLines.find("SceUaItteration_all", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("SceUaItteration_all"), " "); 
			DeleteSpace(strLines);
			g_iSceUaItteration = atoi( strLines.c_str() );
			continue;
		}
		
		if(strLines.find("SceUaItteration_each", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("SceUaItteration_each"), " "); 
			DeleteSpace(strLines);
			g_iSceUaItteration_each = atoi( strLines.c_str() );
			continue;
		}

		// read parameters (files)		
		if(strLines.find("SCE-UA", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("SCE-UA"), " "); 
			DeleteSpace(strLines);
			strcpy(strInFile, strLines.c_str());
			if ( (pChar = strchr(strInFile,'\n')) != NULL ){
				*pChar = '\0';
			 }
			continue;
		}
		
		if(strLines.find("met", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("met"), " "); 
			DeleteSpace(strLines);
			strcpy(strInCsvFile, strLines.c_str());
			if ( (pChar = strchr(strInCsvFile,'\n')) != NULL ){
				*pChar = '\0';
			 }
			continue;
		}
		
		if(strLines.find("out_dir", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("out_dir"), " "); 
			DeleteSpace(strLines);
			strcpy(strOutDirectory, strLines.c_str());
			if ( (pChar = strchr(strOutDirectory,'\n')) != NULL ){
				*pChar = '\0';
			 }
			continue;
		}
		
		if(strLines.find("forward_prm", 0) == 0){
			strLines.replace(strLines.begin(), strLines.begin() + sizeof("forward_prm"), " "); 
			DeleteSpace(strLines);
			strcpy(strInForwardParameterFile, strLines.c_str());
			if ( (pChar = strchr(strInForwardParameterFile,'\n')) != NULL ){
				*pChar = '\0';
			 }
			continue;
		}

	}

	fclose(in);

	return bIsOK;
}

void calculate_statistics(CStatistics& cStatistics, std::vector<double> aryObservation, std::vector<double> aryModel, std::vector<double> aryCi, const double &dUpperLimit, const double &dLowerLimit)
{
	// calculate statistics including linear regression, correlation coefficient, mean error, and root mean square error
    double Sxx = 0, Syy = 0, Sxy = 0;
	double x = 0, y = 0, Tx = 0, Txx = 0, Ty = 0, Tyy = 0, Txy = 0;
	double dDiff = 0.0, dDiffSqr = 0.0;
	int iSize = 0;

    for(int i = 0; i < aryObservation.size(); i++)
    {
		if(aryObservation[i] <= dUpperLimit && aryObservation[i] >= dLowerLimit && aryModel[i] <= dUpperLimit && aryModel[i] >= dLowerLimit && aryCi[i] >= 0){
    		x = aryObservation[i];
			y = aryModel[i];
			Tx += x;
			Txx += x * x;
			Ty += y;
			Tyy += y * y;
			Txy += x * y;
			dDiff += (y - x);
			dDiffSqr += (y - x) * (y - x);
			iSize++;
		}
    }
	Sxx = Txx - Tx * Tx / iSize;
	Syy = Tyy - Ty * Ty / iSize;
	Sxy = Txy - Tx * Ty / iSize;

	cStatistics.iNumber = iSize;

	cStatistics.dSlopeA = Sxy / Syy;
	cStatistics.dOffsetA = Tx / iSize - Ty / iSize * cStatistics.dSlopeA;
	cStatistics.dSlope0A = Txy / Tyy;
	cStatistics.dSlopeB = Sxy / Sxx;
	cStatistics.dOffsetB = Ty / iSize - Tx / iSize * cStatistics.dSlopeB;
	cStatistics.dSlope0B = Txy / Txx;
	cStatistics.dR = sqrt(Sxy * Sxy / Sxx / Syy);
	// cStatistics.dR0 = sqrt( (cStatistics.dSlope0B * cStatistics.dSlope0B * iSize * Txx) / Tyy );

	cStatistics.dRMSE = sqrt(dDiffSqr / iSize);
	cStatistics.dME = dDiff / iSize;

	// calculate r assuming offset = 0
	// http://www.ab.auone-net.jp/~biology/regline/R-Squared.htm
	double dDiffY = 0.0, dDevY = 0.0;
	double v, w, dDiffW = 0.0, dDevW = 0.0;
	for(i = 0; i < aryObservation.size(); i++)
    {
		if(aryObservation[i] <= dUpperLimit && aryObservation[i] >= dLowerLimit && aryModel[i] <= dUpperLimit && aryModel[i] >= dLowerLimit && aryCi[i] >= 0){
			v = aryModel[i] * cStatistics.dSlope0A;
			w = aryObservation[i];
			dDiffW += (w - v) * (w - v);
			dDevW  += (w - Tx/iSize) * (w - Tx/iSize);

    		x = aryObservation[i] * cStatistics.dSlope0B;
			y = aryModel[i];
			dDiffY += (y - x) * (y - x);
			dDevY  += (y - Ty/iSize) * (y - Ty/iSize);
		}
    }

	cStatistics.dR20a = 1.0 - dDiffW / dDevW;

	cStatistics.dR20b = 1.0 - dDiffY / dDevY;
}
