Beispiel #1
0
int ndep_init(file ndepfile, ndepcontrol_struct* ndepctrl)
{
	int ok = 1,i = 0,reccount = 0;
	
	/* if using variable CO2 file, open it, otherwise
	discard the next line of the ini file */
	if (file_open(&ndepfile,'r')) 
	{
		bgc_printf(BV_ERROR, "Error opening annual NDEP file: %s\n",ndepfile);
		ok=0;
	}

	/* Find the number of lines in the file*/
	/* Then use that number to malloc the appropriate arrays */
	while(fscanf(ndepfile.ptr,"%*lf%*lf") != EOF) reccount++;
	rewind(ndepfile.ptr);

	/* Store the total number of ndep records found in the ndepvals variable */
	ndepctrl->ndepvals = reccount;

	bgc_printf(BV_DIAG,"Found: %i NDEP records in co2_init()\n",reccount);
	
	/* allocate space for the annual CO2 array */
	if (ok && !(ndepctrl->ndep_array = (double*) malloc(reccount * sizeof(double))))
	{
		bgc_printf(BV_ERROR, "Error allocating for annual ndep array, ndep_init()\n");
		ok=0;
	}
	if (ok && !(ndepctrl->ndepyear_array = (int*) malloc(reccount * sizeof(int))))
	{
		bgc_printf(BV_ERROR, "Error allocating for annual ndep year array, co2_init()\n");
		ok=0;
	}
	/* read year and co2 concentration for each simyear */
	for (i=0 ; ok && i<reccount ; i++)
	{
		if (fscanf(ndepfile.ptr,"%i%lf", &(ndepctrl->ndepyear_array[i]),&(ndepctrl->ndep_array[i]))==EOF)
		{
			bgc_printf(BV_ERROR, "Error reading annual NDEP array, ndep_init()\n");
			bgc_printf(BV_ERROR, "Note: file must contain a pair of values for each\n");
			bgc_printf(BV_ERROR, "simyear: year and ndep.\n");
			ok=0;
		}
		bgc_printf(BV_DIAG, "NDEP value read: %i %lf\n",ndepctrl->ndepyear_array[i],ndepctrl->ndep_array[i]);
		
	}
	fclose(ndepfile.ptr);
	
	return (!ok);
}
Beispiel #2
0
int bgc_logfile_setup (char *logfile)
{
    extern FILE    *bgc_logfile;

    bgc_logfile = fopen (logfile, "w");

    if (bgc_logfile == NULL)
    {
        bgc_printf (BV_ERROR, "Couldn't Open logfile for writing: '%s' (Error: %s)\n", logfile, strerror (errno));
        bgc_print_usage ();
        exit (EXIT_FAILURE);
    }
    return 1;
}
Beispiel #3
0
signed char bgc_verbosity_decode (char *keyword)
{
    signed char     verbosity = BV_ERROR;
    int             i;
    if (isdigit ((char)(keyword[0])))
    {
        verbosity = (signed char)atoi (keyword);
        if (verbosity <= BV_SILENT)
        {
            return BV_SILENT;
        }
        else if (verbosity >= BV_DIAG)
        {
            return BV_DIAG;
        }
        else
        {
            return verbosity;
        }
    }
    else
    {
        /*  Conversion to Upper case allows to use strncmp() instead of strncasecmp 
         * strncasecmp() is in strings.h from BSD and isn't available on win32 */
        for (i = 0; i < 4 && i < (int)strlen (keyword); i++)
        {
            keyword[i] = toupper (keyword[i]);
        }

        if (strncmp ("SILENT", keyword, 4) == 0)
        {
            return BV_SILENT;
        }
        else if (strncmp ("ERROR", keyword, 4) == 0)
        {
            return BV_ERROR;
        }
        else if (strncmp ("WARN", keyword, 4) == 0)
        {
            return BV_WARN;
        }
        else if (strncmp ("PROGRESS", keyword, 4) == 0)
        {
            return BV_PROGRESS;
        }
        else if (strncmp ("DETAIL", keyword, 4) == 0)
        {
            return BV_DETAIL;
        }
        else if (strncmp ("DIAG", keyword, 4) == 0)
        {
            return BV_DIAG;
        }
        else
        {
            bgc_printf (BV_ERROR, "Unknown Verbosity Keyword: %s\n", keyword);
            bgc_print_usage ();
            exit (EXIT_FAILURE);
        }
    }
}
Beispiel #4
0
void bgc_print_usage (void)
{
    extern char    *argv_zero;

    bgc_printf (BV_ERROR, "\nusage: %s {-l <logfile>} {-s | -v [0..4]} {-p} {-V} {-a} {-u | -g | -m} <ini file>\n\n", argv_zero);
    bgc_printf (BV_ERROR, "       -l <logfile> send output to logfile, overwrite old logfile\n");
    bgc_printf (BV_ERROR, "       -V print version number and build information and exit\n");
    bgc_printf (BV_ERROR, "       -p do alternate calculation for summary outputs (see USAGE.TXT)\n");
    bgc_printf (BV_ERROR, "       -a output ascii formated data\n");
    bgc_printf (BV_ERROR, "       -s run in silent mode, no standard out or error\n");
    bgc_printf (BV_ERROR, "       -v [0..4] set the verbosity level \n");
    bgc_printf (BV_ERROR, "           0 ERROR - only report errors \n");
    bgc_printf (BV_ERROR, "           1 WARN - also report warnings\n");
    bgc_printf (BV_ERROR, "           2 PROGRESS - also report basic progress information\n");
    bgc_printf (BV_ERROR, "           3 DETAIL - also report progress details (default level)\n");
    bgc_printf (BV_ERROR, "           4 DIAG - also print internal diagnostics\n");
    bgc_printf (BV_ERROR, "       -u Run in spin-up mode (over ride ini setting).\n");
    bgc_printf (BV_ERROR, "       -g Run in spin 'n go mode: do spinup and model in one run\n");
    bgc_printf (BV_ERROR, "       -m Run in model mode (over ride ini setting).\n");
    bgc_printf (BV_ERROR, "       -n <ndepfile> use an external nitrogen deposition file.\n");

}
Beispiel #5
0
int co2_init(file init, co2control_struct* co2, int simyears)
{
	int ok = 1;
	int i;
	char key1[] = "CO2_CONTROL";
	char keyword[80];
	char junk[80];
	file temp;
	int reccount = 0;
	/********************************************************************
	**                                                                 **
	** Begin reading initialization file block starting with keyword:  **
	** CO2_CONTROL                                                     ** 
	**                                                                 **
	********************************************************************/

	/* scan for the climate change block keyword, exit if not next */
	if (ok && scan_value(init, keyword, 's'))
	{
		bgc_printf(BV_ERROR, "Error reading keyword, co2_init()\n");
		ok=0;
	}
	if (ok && strcmp(keyword,key1))
	{
		bgc_printf(BV_ERROR, "Expecting keyword --> %s in %s\n",key1,init.name);
		ok=0;
	}

	/* begin reading co2 control information */
	if (ok && scan_value(init, &co2->varco2, 'i'))
	{
		bgc_printf(BV_ERROR, "Error reading variable CO2 flag: co2_init()\n");
		ok=0;
	}
	if (ok && scan_value(init, &co2->co2ppm, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading constant CO2 value: co2_init()\n");
		ok=0;
	}
	/* if using variable CO2 file, open it, otherwise
	discard the next line of the ini file */
	if (ok && co2->varco2)
	{
    	if (scan_open(init,&temp,'r')) 
		{
			bgc_printf(BV_ERROR, "Error opening annual CO2 file\n");
			ok=0;
		}

		/* Find the number of lines in the file*/
		/* Then use that number to malloc the appropriate arrays */
		while(fscanf(temp.ptr,"%*lf%*lf") != EOF)
		{
			reccount++;
		}
		rewind(temp.ptr);

		/* Store the total number of CO2 records found in the co2vals variable */
		co2->co2vals = reccount;
		bgc_printf(BV_DIAG,"Found: %i CO2 records in co2_init()\n",reccount);
		
		/* allocate space for the annual CO2 array */
		if (ok && !(co2->co2ppm_array = (double*) malloc(reccount *
			sizeof(double))))
		{
			bgc_printf(BV_ERROR, "Error allocating for annual CO2 array, co2_init()\n");
			ok=0;
		}
		if (ok && !(co2->co2year_array = (int*) malloc(reccount *
			sizeof(int))))
		{
			bgc_printf(BV_ERROR, "Error allocating for annual CO2 year array, co2_init()\n");
			ok=0;
		}
		/* read year and co2 concentration for each simyear */
		for (i=0 ; ok && i<reccount ; i++)
		{
			if (fscanf(temp.ptr,"%i%lf",
				&(co2->co2year_array[i]),&(co2->co2ppm_array[i]))==EOF)
			{
				bgc_printf(BV_ERROR, "Error reading annual CO2 array, ctrl_init()\n");
				bgc_printf(BV_ERROR, "Note: file must contain a pair of values for each\n");
				bgc_printf(BV_ERROR, "simyear: year and CO2.\n");
				ok=0;
			}
			/* printf("CO2 value read: %i %lf\n",co2->co2year_array[i],co2->co2ppm_array[i]); */
			if (co2->co2ppm_array[i] < 0.0)
			{
				bgc_printf(BV_ERROR, "Error in co2_init(): co2 (ppm) must be positive\n");
				ok=0;
			}
		}
		fclose(temp.ptr);
	}
	else
	{
		if (scan_value(init, junk, 's'))
		{
			bgc_printf(BV_ERROR, "Error scanning annual co2 filename\n");
			ok=0;
		}
	}
	
	if (co2->co2ppm < 0.0)
	{
		bgc_printf(BV_ERROR, "Error in co2_init(): co2 (ppm) must be positive\n");
		ok=0;
	}

	return (!ok);
}
Beispiel #6
0
int epc_init(file init, epconst_struct* epc)
{
	int ok = 1;
	double t1,t2,t3,t4,r1;
	file temp;
	char key1[] = "EPC_FILE";
	char key2[] = "ECOPHYS";
	char keyword[80];

	/********************************************************************
	**                                                                 **
	** Begin reading initialization file block starting with keyword:  **
	** EPC_FILES                                                       ** 
	**                                                                 **
	********************************************************************/
	
	/* scan for the EPC file keyword, exit if not next */
	if (ok && scan_value(init, keyword, 's'))
	{
		bgc_printf(BV_ERROR, "Error reading keyword for control data\n");
		ok=0;
	}
	if (ok && strcmp(keyword, key1))
	{
		bgc_printf(BV_ERROR, "Expecting keyword --> %s in file %s\n",key1,init.name);
		ok=0;
	}

	/* open file  */
	if (ok && scan_open(init,&temp,'r')) 
	{
		bgc_printf(BV_ERROR, "Error opening epconst file, epc_init()\n");
		ok=0;
	}
	
	/* first scan epc keyword to ensure proper *.init format */
	if (ok && scan_value(temp, keyword, 's'))
	{
		bgc_printf(BV_ERROR, "Error reading keyword, epc_init()\n");
		ok=0;
	}
	if (ok && strcmp(keyword,key2))
	{
		bgc_printf(BV_ERROR, "Expecting keyword --> %s in %s\n",key2,init.name);
		ok=0;
	}
	
	/* begin reading constants from *.init */
	if (ok && scan_value(temp, &epc->woody, 'i'))
	{
		bgc_printf(BV_ERROR, "Error reading woody/non-woody flag, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->evergreen, 'i'))
	{
		bgc_printf(BV_ERROR, "Error reading evergreen/deciduous flag, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->c3_flag, 'i'))
	{
		bgc_printf(BV_ERROR, "Error reading C3/C4 flag, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->phenology_flag, 'i'))
	{
		bgc_printf(BV_ERROR, "Error reading phenology flag, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->onday, 'i'))
	{
		bgc_printf(BV_ERROR, "Error reading onday, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->offday, 'i'))
	{
		bgc_printf(BV_ERROR, "Error reading offday, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->transfer_pdays, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading transfer_pdays, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->litfall_pdays, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading litfall_pdays, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->leaf_turnover, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading leaf turnover, epc_init()\n");
		ok=0;
	}
	/* force leaf turnover fraction to 1.0 if deciduous */
	if (!epc->evergreen)
	{
		epc->leaf_turnover = 1.0;
	}
	epc->froot_turnover = epc->leaf_turnover;
	if (ok && scan_value(temp, &epc->livewood_turnover, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading livewood turnover, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &t1, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading whole-plant mortality, epc_init()\n");
		ok=0;
	}
	epc->daily_mortality_turnover = t1/365;
	if (ok && scan_value(temp, &t1, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading fire mortality, epc_init()\n");
		ok=0;
	}
	epc->daily_fire_turnover = t1/365;
	if (ok && scan_value(temp, &epc->alloc_frootc_leafc, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading froot C:leaf C, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->alloc_newstemc_newleafc, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading new stemC:new leaf C, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->alloc_newlivewoodc_newwoodc, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading new livewood C:new wood C, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->alloc_crootc_stemc, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading croot C:stem C, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->alloc_prop_curgrowth, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading new growth:storage growth, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->leaf_cn, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading average leaf C:N, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->leaflitr_cn, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading leaf litter C:N, epc_init()\n");
		ok=0;
	}
	/* test for leaflitter C:N > leaf C:N */
	if (epc->leaflitr_cn < epc->leaf_cn)
	{
		bgc_printf(BV_ERROR, "Error: leaf litter C:N must be >= leaf C:N\n");
		bgc_printf(BV_ERROR, "change the values in ECOPHYS block of initialization file\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->froot_cn, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading initial fine root C:N, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->livewood_cn, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading initial livewood C:N, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->deadwood_cn, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading initial deadwood C:N, epc_init()\n");
		ok=0;
	}
	/* test for deadwood C:N > livewood C:N */
	if (epc->deadwood_cn < epc->livewood_cn)
	{
		bgc_printf(BV_ERROR, "Error: livewood C:N must be >= deadwood C:N\n");
		bgc_printf(BV_ERROR, "change the values in ECOPHYS block of initialization file\n");
		ok=0;
	}
	if (ok && scan_value(temp, &t1, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading leaf litter labile proportion, epc_init()\n");
		ok=0;
	}
	epc->leaflitr_flab = t1;
	if (ok && scan_value(temp, &t2, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading leaf litter cellulose proportion, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &t3, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading leaf litter lignin proportion, epc_init()\n");
		ok=0;
	}
	epc->leaflitr_flig = t3;

	/* test for litter fractions sum to 1.0 */
	if ( ok && (fabs(t1+t2+t3-1.0) > FLT_COND_TOL) )
	{
		bgc_printf(BV_ERROR, "Error:\n");
		bgc_printf(BV_ERROR, "leaf litter proportions of labile, cellulose, and lignin\n");
		bgc_printf(BV_ERROR, "must sum to 1.0. Check initialization file and try again.\n");
		ok=0;
	}
	/* calculate shielded and unshielded cellulose fraction */
	if (ok)
	{
		r1 = t3/t2;
		if (r1 <= 0.45)
		{
			epc->leaflitr_fscel = 0.0;
			epc->leaflitr_fucel = t2;
		}
		else if (r1 > 0.45 && r1 < 0.7)
		{
			t4 = (r1 - 0.45)*3.2;
			epc->leaflitr_fscel = t4*t2;
			epc->leaflitr_fucel = (1.0 - t4)*t2;
		}
		else
		{
			epc->leaflitr_fscel = 0.8*t2;
			epc->leaflitr_fucel = 0.2*t2;
		}
	}
	if (ok && scan_value(temp, &t1, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading froot litter labile proportion, epc_init()\n");
		ok=0;
	}
	epc->frootlitr_flab = t1;
	if (ok && scan_value(temp, &t2, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading froot litter cellulose proportion, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &t3, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading froot litter lignin proportion, epc_init()\n");
		ok=0;
	}
	
	epc->frootlitr_flig = t3;

	/* test for litter fractions sum to 1.0 */
	if ( ok && (fabs(t1+t2+t3-1.0) > FLT_COND_TOL) )
	{
		bgc_printf(BV_ERROR, "Error:\n");
		bgc_printf(BV_ERROR, "froot litter proportions of labile, cellulose, and lignin\n");
		bgc_printf(BV_ERROR, "must sum to 1.0. Check initialization file and try again.\n");
		ok=0;
	}
	/* calculate shielded and unshielded cellulose fraction */
	if (ok)
	{
		r1 = t3/t2;
		if (r1 <= 0.45)
		{
			epc->frootlitr_fscel = 0.0;
			epc->frootlitr_fucel = t2;
		}
		else if (r1 > 0.45 && r1 < 0.7)
		{
			t4 = (r1 - 0.45)*3.2;
			epc->frootlitr_fscel = t4*t2;
			epc->frootlitr_fucel = (1.0 - t4)*t2;
		}
		else
		{
			epc->frootlitr_fscel = 0.8*t2;
			epc->frootlitr_fucel = 0.2*t2;
		}
	}
	if (ok && scan_value(temp, &t1, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading dead wood %% cellulose, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &t2, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading dead wood %% lignin, epc_init()\n");
		ok=0;
	}
	epc->deadwood_flig = t2;

	/* test for litter fractions sum to 1.0 */
	if (ok && (fabs(t1+t2-1.0) > FLT_COND_TOL) )
	{
		bgc_printf(BV_ERROR, "Error:\n");
		bgc_printf(BV_ERROR, "deadwood proportions of cellulose and lignin must sum\n");
		bgc_printf(BV_ERROR, "to 1.0. Check initialization file and try again.\n");
		ok=0;
	}
	/* calculate shielded and unshielded cellulose fraction */
	if (ok)
	{
		r1 = t2/t1;
		if (r1 <= 0.45)
		{
			epc->deadwood_fscel = 0.0;
			epc->deadwood_fucel = t1;
		}
		else if (r1 > 0.45 && r1 < 0.7)
		{
			t4 = (r1 - 0.45)*3.2;
			epc->deadwood_fscel = t4*t1;
			epc->deadwood_fucel = (1.0 - t4)*t1;
		}
		else
		{
			epc->deadwood_fscel = 0.8*t1;
			epc->deadwood_fucel = 0.2*t1;
		}
	}
	if (ok && scan_value(temp, &epc->int_coef, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading canopy water int coef, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->ext_coef, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading canopy light ext coef, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->lai_ratio, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading all to projected LA ratio, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->avg_proj_sla, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading canopy average projected specific leaf area, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->sla_ratio, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading shaded to sunlit SLA ratio, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->flnr, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading Rubisco N fraction, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->gl_smax, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading gl_smax, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->gl_c, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading gl_c, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->gl_bl, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading gl_bl, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->psi_open, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading psi_close, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->psi_close, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading psi_sat, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->vpd_open, 'd')) 
	{
		bgc_printf(BV_ERROR, "Error reading vpd_max, epc_init()\n");
		ok=0;
	}
	if (ok && scan_value(temp, &epc->vpd_close, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading vpd_min, epc_init()\n");
		ok=0;
	}
	
	fclose(temp.ptr);
		
	return (!ok);
}
Beispiel #7
0
int scc_init(file init, climchange_struct* scc)
{
	int ok = 1;
	char key1[] = "CLIM_CHANGE";
	char keyword[80];

	/********************************************************************
	**                                                                 **
	** Begin reading initialization file block starting with keyword:  **
	** CLIM_CHANGE                                                     ** 
	**                                                                 **
	********************************************************************/

	/* scan for the climate change block keyword, exit if not next */
	if (ok && scan_value(init, keyword, 's'))
	{
		bgc_printf(BV_ERROR, "Error reading keyword, scc_init()\n");
		ok=0;
	}
	if (ok && strcmp(keyword,key1))
	{
		bgc_printf(BV_ERROR, "Expecting keyword --> %s in %s\n",key1,init.name);
		ok=0;
	}

	/* begin reading climate change data */
	if (ok && scan_value(init, &scc->s_tmax, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading scalar for tmax, scc_init()\n");
		ok=0;
	}
	if (ok && scan_value(init, &scc->s_tmin, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading scalar for tmin, scc_init()\n");
		ok=0;
	}
	if (ok && scan_value(init, &scc->s_prcp, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading scalar for prcp, scc_init()\n");
		ok=0;
	}
	if (ok && scan_value(init, &scc->s_vpd, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading scalar for vpd, scc_init()\n");
		ok=0;
	}
	if (ok && scan_value(init, &scc->s_swavgfd, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading scalar for swavgfd, scc_init()\n");
		ok=0;
	}
	
	/* some error checking on scalar climate change values */
	if (scc->s_prcp < 0.0)
	{
		bgc_printf(BV_ERROR, "Error in scc_init(): prcp scalar must be positive\n");
		ok=0;
	}
	if (scc->s_vpd < 0.0)
	{
		bgc_printf(BV_ERROR, "Error in scc_init(): vpd scalar must be positive\n");
		ok=0;
	}
	if (scc->s_swavgfd < 0.0)
	{
		bgc_printf(BV_ERROR, "Error in scc_init(): swavgfd scalar must be positive\n");
		ok=0;
	}

	return (!ok);
}
Beispiel #8
0
int boxcar_smooth (double *input, double *output, int n, int w, int w_flag)
{
    int             ok = 1;
    int             tail, i, j;
    int            *wt;
    double          total, sum;

    if (ok && (w > n / 2))
    {
        bgc_printf (BV_ERROR, "Boxcar window longer than 1/2 array length...\n");
        bgc_printf (BV_ERROR, "Resize window and try again\n");
        ok = 0;
    }

    /* establish the lengths of the boxcar tails */
    if (ok)
    {
        if (!(w % 2))
            w += 1;
        tail = w / 2;
    }

    if (ok && (!(wt = (int *)malloc (w * sizeof (int)))))
    {
        bgc_printf (BV_ERROR, "Allocation error in boxcar_smooth... Exiting\n");
        ok = 0;
    }

    /* when w_flag != 0, use linear ramp to weight tails, 
     * otherwise use constant weight */
    if (ok)
    {
        if (w_flag)
        {
            for (i = 0; i < tail; i++)
                wt[i] = i + 1;
            for (i = 0; i <= tail; i++)
                wt[i + tail] = tail + 1 - i;
        }
        else
            for (i = 0; i < w; i++)
                wt[i] = 1;


        for (i = 0; i < n; i++)
        {
            total = 0.0;
            sum = 0.0;
            if (i < tail)
            {
                for (j = tail - i; j < w; j++)
                {
                    total += input[i + j - tail] * wt[j];
                    sum += (double)wt[j];
                }
            }
            else if ((i >= tail) && (i < n - tail))
            {
                for (j = 0; j < w; j++)
                {
                    total += input[i + j - tail] * wt[j];
                    sum += (double)wt[j];
                }
            }
            else if (i >= n - tail)
            {
                for (j = 0; j < tail + n - i; j++)
                {
                    total += input[i + j - tail] * wt[j];
                    sum += (double)wt[j];
                }
            }
            output[i] = total / sum;

        }                       /* end for i=nelements */

        free (wt);

    }                           /* end if ok */

    return (!ok);
}
Beispiel #9
0
int run_avg (const double *input, double *output, int n, int w, int w_flag)
{
    /* calculates running averages
     * n = length of input and output arrays
     * w = width of averaging window
     * w_flag : 1=linearly weighted window, 0=constant weighted window
     */

    register int    i, j;
    int             ok = 1;
    int            *wt;
    double          total, sum;

    if (w > n)
    {
        bgc_printf (BV_ERROR, "Error: averaging window longer than input array\n");
        ok = 0;
    }

    if (ok && (!(wt = (int *)malloc (w * sizeof (int)))))
    {
        bgc_printf (BV_ERROR, "Allocation error in boxcar_smooth... Exiting\n");
        ok = 0;
    }

    if (ok)
    {
        if (w_flag)
            for (i = 0; i < w; i++)
                wt[i] = i + 1;
        else
            for (i = 0; i < w; i++)
                wt[i] = 1;

        for (i = 0; i < n; i++)
        {
            total = 0.0;
            sum = 0.0;
            if (i < (w - 1))
            {
                for (j = w - i - 1; j < w; j++)
                {
                    total += (double)wt[j] * input[i - w + j + 1];
                    sum += (double)wt[j];
                }
            }
            else
            {
                for (j = 0; j < w; j++)
                {
                    total += (double)wt[j] * input[i - w + j + 1];
                    sum += (double)wt[j];
                }
            }
            output[i] = total / sum;

        }                       /* end for i=nelements */

        free (wt);
    }
    return (!ok);
}
Beispiel #10
0
int sitec_init(file init, siteconst_struct* sitec)
{
	/* reads the site physical constants from *.init */ 

	int ok=1;
	char key[] = "SITE";
	char keyword[80];
	double sand,silt,clay; /* percent sand, silt, and clay */

	/* first scan keyword to ensure proper *.init format */ 
	if (ok && scan_value(init, keyword, 's'))
	{
		bgc_printf(BV_ERROR, "Error reading keyword, sitec_init()\n");
		ok=0;
	}
	if (ok && strcmp(keyword,key))
	{
		bgc_printf(BV_ERROR, "Expecting keyword --> %s in %s\n",key,init.name);
		ok=0;
	}

	/* begin reading constants from *.init */
	if (ok && scan_value(init, &sitec->soil_depth, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading soil depth, sitec_init()\n");
		ok=0;
	}
	if (ok && scan_value(init, &sand, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading percent sand, sitec_init()\n");
		ok=0;
	}
	if (ok && scan_value(init, &silt, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading percent clay, sitec_init()\n");
		ok=0;
	}
	if (ok && scan_value(init, &clay, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading percent clay, sitec_init()\n");
		ok=0;
	}
	
	if (ok && scan_value(init, &sitec->elev, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading elevation, sitec_init()\n");
		ok=0;
	}
	if (ok && scan_value(init, &sitec->lat, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading site latitude, sitec_init()\n");
		ok=0;
	}
	if (ok && scan_value(init, &sitec->sw_alb, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading shortwave albedo, sitec_init()\n");
		ok=0;
	}
	if (ok && scan_value(init, &sitec->ndep, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading N deposition, sitec_init()\n");
		ok=0;
	}
	if (ok && scan_value(init, &sitec->nfix, 'd'))
	{
		bgc_printf(BV_ERROR, "Error reading N fixation, sitec_init()\n");
		ok=0;
	}
	if (ok && scan_value(init, &sitec->obs_alpha, 'd'))
        {
                bgc_printf(BV_ERROR, "Error reading alpha, sitec_init()\n");
                ok=0;
        }
	if (ok && scan_value(init, &sitec->obs_beta, 'd'))
        {
                bgc_printf(BV_ERROR, "Error reading beta, sitec_init()\n");
                ok=0;
        }	
	if (ok && scan_value(init, &sitec->obs_theta_s, 'd'))
        {
                bgc_printf(BV_ERROR, "Error reading theta_s, sitec_init()\n");
                ok=0;
        }
	if (ok && scan_value(init, &sitec->obs_theta_r, 'd'))
        {
                bgc_printf(BV_ERROR, "Error reading theta_r, sitec_init()\n");
                ok=0;
        }
	if (ok && scan_value(init, &sitec->obs_fc, 'd'))
        {
                bgc_printf(BV_ERROR, "Error reading field capacity, sitec_init()\n");
                ok=0;
        }


	/* calculate the soil pressure-volume coefficients from texture data */
	/* Uses the multivariate regressions from Cosby et al., 1984 */
	/* first check that the percentages add to 100.0 */
	if (ok && fabs(sand+silt+clay-100) > FLT_COND_TOL)
	{
		bgc_printf(BV_ERROR, "Error: %%sand + %%silt + %%clay  MUST EQUAL 100%%\n");
		bgc_printf(BV_ERROR, "Check values in initialization file.\n");
		ok=0;
	}
	if (ok)
	{
		sitec->soil_b = -(3.10 + 0.157*clay - 0.003*sand);
		sitec->vwc_sat = (50.5 - 0.142*sand - 0.037*clay)/100.0;
		sitec->psi_sat = -(exp((1.54 - 0.0095*sand + 0.0063*silt)*log(10.0))*9.8e-5);
		sitec->vwc_fc = sitec->vwc_sat*pow((-0.015/sitec->psi_sat),1.0/sitec->soil_b);

		/* define maximum soilwater content, for outflow calculation
		converts volumetric water content (m3/m3) --> (kg/m2) */
		sitec->soilw_fc = sitec->soil_depth * sitec->vwc_fc * 1000.0;
		sitec->soilw_sat = sitec->soil_depth * sitec->vwc_sat * 1000.0;
	}
	
	return (!ok);
}
Beispiel #11
0
int photosynthesis(psn_struct* psn)
{
	/*
	The following variables are assumed to be defined in the psn struct
	at the time of the function call:
	c3         (flag) set to 1 for C3 model, 0 for C4 model
	pa         (Pa) atmospheric pressure 
	co2        (ppm) atmospheric [CO2] 
	t          (deg C) air temperature
	lnc        (kg Nleaf/m2) leaf N concentration, per unit projected LAI 
	flnr       (kg NRub/kg Nleaf) fraction of leaf N in Rubisco
	ppfd       (umol photons/m2/s) PAR flux density, per unit projected LAI
	g          (umol CO2/m2/s/Pa) leaf-scale conductance to CO2, proj area basis
	dlmr       (umol CO2/m2/s) day leaf maint resp, on projected leaf area basis
	
	The following variables in psn struct are defined upon function return:
	Ci         (Pa) intercellular [CO2]
	Ca         (Pa) atmospheric [CO2]
	O2         (Pa) atmospheric [O2]
	gamma      (Pa) CO2 compensation point, in the absence of maint resp.
	Kc         (Pa) MM constant for carboxylation
	Ko         (Pa) MM constant for oxygenation
	Vmax       (umol CO2/m2/s) max rate of carboxylation
	Jmax       (umol electrons/m2/s) max rate electron transport
	J          (umol RuBP/m2/s) rate of RuBP regeneration
	Av         (umol CO2/m2/s) carboxylation limited assimilation
	Aj         (umol CO2/m2/s) RuBP regen limited assimilation
	A          (umol CO2/m2/s) final assimilation rate
	*/
	
	/* the weight proportion of Rubisco to its nitrogen content, fnr, is 
	calculated from the relative proportions of the basic amino acids 
	that make up the enzyme, as listed in the Handbook of Biochemistry, 
	Proteins, Vol III, p. 510, which references:
	Kuehn and McFadden, Biochemistry, 8:2403, 1969 */
	static double fnr = 7.16;   /* kg Rub/kg NRub */
	
	/* the following enzyme kinetic constants are from: 
	Woodrow, I.E., and J.A. Berry, 1980. Enzymatic regulation of photosynthetic
	CO2 fixation in C3 plants. Ann. Rev. Plant Physiol. Plant Mol. Biol.,
	39:533-594.
	Note that these values are given in the units used in the paper, and that
	they are converted to units appropriate to the rest of this function before
	they are used. */
	/* I've changed the values for Kc and Ko from the Woodrow and Berry
	reference, and am now using the values from De Pury and Farquhar,
	1997. Simple scaling of photosynthesis from leaves to canopies
	without the errors of big-leaf models. Plant, Cell and Env. 20: 537-557. 
	All other parameters, including the q10's for Kc and Ko are the same
	as in Woodrow and Berry. */
	static double Kc25 = 404.0;   /* (ubar) MM const carboxylase, 25 deg C */ 
	static double q10Kc = 2.1;    /* (DIM) Q_10 for Kc */
	static double Ko25 = 248.0;   /* (mbar) MM const oxygenase, 25 deg C */
	static double q10Ko = 1.2;    /* (DIM) Q_10 for Ko */
	static double act25 = 3.6;    /* (umol/mgRubisco/min) Rubisco activity */
	static double q10act = 2.4;   /* (DIM) Q_10 for Rubisco activity */
	static double pabs = 0.85;    /* (DIM) fPAR effectively absorbed by PSII */
	
	/* local variables */
	int ok=1;	
	double t;      /* (deg C) temperature */
	double tk;     /* (K) absolute temperature */
	double Kc;     /* (Pa) MM constant for carboxylase reaction */
	double Ko;     /* (Pa) MM constant for oxygenase reaction */
	double act;    /* (umol CO2/kgRubisco/s) Rubisco activity */
	double Jmax;   /* (umol/m2/s) max rate electron transport */
	double ppe;    /* (mol/mol) photons absorbed by PSII per e- transported */
	double Vmax, J, gamma, Ca, Rd, O2, g;
	double a,b,c,det;
	double Av,Aj, A;

	
	/* begin by assigning local variables */
	g = psn->g;
	t = psn->t;
	tk = t + 273.15;
	Rd = psn->dlmr;
	
	/* convert atmospheric CO2 from ppm --> Pa */
	Ca = psn->co2 * psn->pa / 1e6;
	
	/* set parameters for C3 vs C4 model */
	if (psn->c3)
	{
		ppe = 2.6;
	}
	else /* C4 */
	{
		ppe = 3.5;
		Ca *= 10.0;
	}
	psn->Ca = Ca;		
	
	/* calculate atmospheric O2 in Pa, assumes 21% O2 by volume */
	psn->O2 = O2 = 0.21 * psn->pa;
	
	/* correct kinetic constants for temperature, and do unit conversions */
	Ko = Ko25 * pow(q10Ko, (t-25.0)/10.0);
	psn->Ko = Ko = Ko * 100.0;   /* mbar --> Pa */
	if (t > 15.0)
	{
		Kc = Kc25 * pow(q10Kc, (t-25.0)/10.0);
		act = act25 * pow(q10act, (t-25.0)/10.0);
	}
	else
	{
		Kc = Kc25 * pow(1.8*q10Kc, (t-15.0)/10.0) / q10Kc;
		act = act25 * pow(1.8*q10act, (t-15.0)/10.0) / q10act;
	}
	psn->Kc = Kc = Kc * 0.10;   /* ubar --> Pa */
	act = act * 1e6 / 60.0;     /* umol/mg/min --> umol/kg/s */
	
	/* calculate gamma (Pa), assumes Vomax/Vcmax = 0.21 */
	psn->gamma = gamma = 0.5 * 0.21 * Kc * psn->O2 / Ko;
	 
	/* calculate Vmax from leaf nitrogen data and Rubisco activity */
	
	/* kg Nleaf   kg NRub    kg Rub      umol            umol 
	   -------- X -------  X ------- X ---------   =   --------
	      m2      kg Nleaf   kg NRub   kg RUB * s       m2 * s       
	   
	     (lnc)  X  (flnr)  X  (fnr)  X   (act)     =    (Vmax)
	*/
	psn->Vmax = Vmax = psn->lnc * psn->flnr * fnr * act;
	
	/* calculate Jmax = f(Vmax), reference:
	Wullschleger, S.D., 1993.  Biochemical limitations to carbon assimilation
		in C3 plants - A retrospective analysis of the A/Ci curves from
		109 species. Journal of Experimental Botany, 44:907-920.
	*/
	psn->Jmax = Jmax = 2.1*Vmax;
	
	/* calculate J = f(Jmax, ppfd), reference:
	de Pury and Farquhar 1997
	Plant Cell and Env.
	*/
	a = 0.7;
	b = -Jmax - (psn->ppfd*pabs/ppe);
	c = Jmax * psn->ppfd*pabs/ppe;
	psn->J = J = (-b - sqrt(b*b - 4.0*a*c))/(2.0*a);
	
	/* solve for Av and Aj using the quadratic equation, substitution for Ci
	from A = g(Ca-Ci) into the equations from Farquhar and von Caemmerer:
	     
	       Vmax (Ci - gamma)
	Av =  -------------------   -   Rd
	      Ci + Kc (1 + O2/Ko)
	
	
	         J (Ci - gamma)
	Aj  =  -------------------  -   Rd
           4.5 Ci + 10.5 gamma  
    */

	/* quadratic solution for Av */    
    a = -1.0/g;
    b = Ca + (Vmax - Rd)/g + Kc*(1.0 + O2/Ko);
    c = Vmax*(gamma - Ca) + Rd*(Ca + Kc*(1.0 + O2/Ko));
    
    if ((det = b*b - 4.0*a*c) < 0.0)
    {
    	bgc_printf(BV_ERROR, "negative root error in psn routine\n");
    	ok=0;
    }
    
    psn->Av = Av = (-b + sqrt(det)) / (2.0*a);
    
    /* quadratic solution for Aj */
/*	a = -4.5/g;    
	b = 4.5*Ca + 10.5*gamma + J/g - 4.5*Rd/g;
	c = J*(gamma - Ca) + Rd*(4.5*Ca + 10.5*gamma);
*/		
	a = -4/g;    
	b = 4*Ca + 8*gamma + J/g - 4*Rd/g;
	c = J*(gamma - Ca) + Rd*(4*Ca + 8*gamma);
	if ((det = b*b - 4.0*a*c) < 0.0)
	{
		bgc_printf(BV_ERROR, "negative root error in psn routine\n");
		ok=0;
	}
	
	psn->Aj = Aj = (-b + sqrt(det)) / (2.0*a);
	
	/* estimate A as the minimum of (Av,Aj) */
	if (Av < Aj) A = Av; 
	else         A = Aj;
	psn->A = A;
	bgc_printf(BV_DIAG, "psn->A: %f, A: %f\n", psn->A, A);
	psn->Ci = Ca - (A/g);
	
	return (!ok);
}	
Beispiel #12
0
int total_photosynthesis(const metvar_struct* metv, const epconst_struct* epc, 
			epvar_struct* epv, cflux_struct* cf, psn_struct *psn_sun, psn_struct *psn_shade)
{
	/* This function is a wrapper and replacement for the photosynthesis code which used
		to be in the central bgc.c code.  At Mott Jolly's request, all of the science code
		is being moved into funtions. */
	int ok=1;
	/* psn_struct psn_sun, psn_shade; */

	/* SUNLIT canopy fraction photosynthesis */
  /* set the input variables */
	psn_sun->c3 = epc->c3_flag;
	psn_sun->co2 = metv->co2;
	psn_sun->pa = metv->pa;
	psn_sun->t = metv->tday;
	psn_sun->lnc = 1.0 / (epv->sun_proj_sla * epc->leaf_cn);
	psn_sun->flnr = epc->flnr;
	psn_sun->ppfd = metv->ppfd_per_plaisun;
	/* convert conductance from m/s --> umol/m2/s/Pa, and correct
	for CO2 vs. water vapor */
	psn_sun->g = epv->gl_t_wv_sun * 1e6/(1.6*R*(metv->tday+273.15));
	psn_sun->dlmr = epv->dlmr_area_sun;
	if (ok && photosynthesis(psn_sun))
	{
		bgc_printf(BV_ERROR, "Error in photosynthesis() from bgc()\n");
		ok=0;
	}

	bgc_printf(BV_DIAG, "\t\tdone sun psn\n");

	epv->assim_sun = psn_sun->A;

	/* for the final flux assignment, the assimilation output
		needs to have the maintenance respiration rate added, this
		sum multiplied by the projected leaf area in the relevant canopy
		fraction, and this total converted from umol/m2/s -> kgC/m2/d */
	cf->psnsun_to_cpool = (epv->assim_sun + epv->dlmr_area_sun) *
		epv->plaisun * metv->dayl * 12.011e-9;
	/* SHADED canopy fraction photosynthesis */
	psn_shade->c3 = epc->c3_flag;
	psn_shade->co2 = metv->co2;
	psn_shade->pa = metv->pa;
	psn_shade->t = metv->tday;
	psn_shade->lnc = 1.0 / (epv->shade_proj_sla * epc->leaf_cn);
	psn_shade->flnr = epc->flnr;
	psn_shade->ppfd = metv->ppfd_per_plaishade;
	/* convert conductance from m/s --> umol/m2/s/Pa, and correct
	for CO2 vs. water vapor */
	psn_shade->g = epv->gl_t_wv_shade * 1e6/(1.6*R*(metv->tday+273.15));
	psn_shade->dlmr = epv->dlmr_area_shade;
	if (ok && photosynthesis(psn_shade))
	{
		bgc_printf(BV_ERROR, "Error in photosynthesis() from bgc()\n");
		ok=0;
	}

	bgc_printf(BV_DIAG, "\t\tdone shade_psn\n");

	epv->assim_shade = psn_shade->A;

//	printf("assim_sun=%f\t assim_shade=%f\t total_assim=%f\n",psn_sun->A,psn_shade->A,psn_sun->A+psn_shade->A);

	/* for the final flux assignment, the assimilation output
		needs to have the maintenance respiration rate added, this
		sum multiplied by the projected leaf area in the relevant canopy
		fraction, and this total converted from umol/m2/s -> kgC/m2/d */
	cf->psnshade_to_cpool = (epv->assim_shade + epv->dlmr_area_shade) *
		epv->plaishade * metv->dayl * 12.011e-9;
	//added by Y.H 03/31/2015 not considering N limitation in allocation;
	cf->total_assimilation = cf->psnsun_to_cpool + cf->psnshade_to_cpool;
	return (!ok);
}
Beispiel #13
0
int prephenology(const control_struct* ctrl, const epconst_struct* epc, 
const siteconst_struct* sitec, const metarr_struct* metarr,
phenarray_struct* phen)
{
	int ok=1;
	int model,woody,evergreen,south;
	double t1;
	char round[80];
	int i,pday,ndays,py;
	int nyears,phenyears;
	int ngrowthdays,ntransferdays,nlitfalldays;
	int onday,offday;
	int counter;
	int remdays_curgrowth[365];
	int remdays_transfer[365];
	int predays_transfer[365];
	int remdays_litfall[365];
	int predays_litfall[365];
	/* phenology model variables */
	int *onday_arr, *offday_arr;
	int fall_tavg_count;
	int onset_day, offset_day;
	double mean_tavg,fall_tavg;
	double phensoilt,phendayl;
	double onset_critsum, sum_soilt;
	double critdayl = 39300.0; /* seconds */
	/* grass model parameters */
	double ann_prcp;
	double sum_prcp, phenprcp;
	double grass_stsumcrit;
	double grass_prcpcrit;
	double grass_stsummax = 1380.0;
	double grass_stsummid = 900.0;
	double grass_stsummin = 418.0;
	double grass_a = 32.9;
	double grass_k = 0.15;
	double grass_tmid = 9.0;
	double grass_prcpyear[365];
	double grass_prcpprevcrit = 1.14;
	double grass_prcpprev;
	double grass_prcpnextcrit = 0.97;
	double grass_prcpnext;
	double grass_tmaxyear[365];
	double grass_tminyear[365];
	double grass_3daytmin[365];
	int psum_startday, psum_stopday;
	double tmax_ann, tmax, new_tmax;
	double tmin_annavg;

	/* allocate space for phenology arrays */
	nyears = ctrl->metyears;
	ndays = 365 * nyears;
	if (ok && !(phen->remdays_curgrowth = (int*) malloc(ndays*sizeof(int))))
	{
		bgc_printf(BV_ERROR, "Error allocating for phen->curgrowth, prephenology()\n");
		ok=0;
	}
	if (ok && !(phen->remdays_transfer = (int*) malloc(ndays*sizeof(int))))
	{
		bgc_printf(BV_ERROR, "Error allocating for phen->remdays_transfer, prephenology()\n");
		ok=0;
	}
	if (ok && !(phen->remdays_litfall = (int*) malloc(ndays*sizeof(int))))
	{
		bgc_printf(BV_ERROR, "Error allocating for phen->remdays_litfall, prephenology()\n");
		ok=0;
	}
	if (ok && !(phen->predays_transfer = (int*) malloc(ndays*sizeof(int))))
	{
		bgc_printf(BV_ERROR, "Error allocating for phen->predays_transfer, prephenology()\n");
		ok=0;
	}
	if (ok && !(phen->predays_litfall = (int*) malloc(ndays*sizeof(int))))
	{
		bgc_printf(BV_ERROR, "Error allocating for phen->predays_litfall, prephenology()\n");
		ok=0;
	}
	if (ok && !(onday_arr = (int*) malloc((nyears+1) * sizeof(int))))
	{
		bgc_printf(BV_ERROR, "Error allocating for onday_arr, prephenology()\n");
		ok=0;
	}
	if (ok && !(offday_arr = (int*) malloc((nyears+1) * sizeof(int))))
	{
		bgc_printf(BV_ERROR, "Error allocating for offday_arr, prephenology()\n");
		ok=0;
	}
	
	/* set some local flags to control the phenology model behavior */
	/* model=1 --> use phenology model   model=0 --> user specified phenology */
	/* woody=1 --> woody veg type        woody=0 --> non-woody veg type */
	/* evergreen=1 --> evergreen type    evergreen=0 --> deciduous type */
	/* south=1 --> southern hemisphere   south=0 --> northern hemisphere */
	model = epc->phenology_flag;
	woody = epc->woody;
	evergreen = epc->evergreen;
	south = (sitec->lat < 0.0);
		
	/* for southern hemisphere sites, use an extra phenology year */
	if (south) phenyears = nyears+1;
	else phenyears = nyears;
	
	/* define the phenology signals for cases in which the phenology signals
	are constant between years */
	if (evergreen || !model)
	{
		/* zero the 365-day phen arrays */
		for (pday=0 ; pday<365 ; pday++)
		{
			remdays_curgrowth[pday] = 0;
			remdays_transfer[pday] = 0;
			predays_transfer[pday] = 0;
			remdays_litfall[pday] = 0;
			predays_litfall[pday] = 0;
		}
		
		/* user defined on and off days (base zero) */
		onday = epc->onday;
		offday = epc->offday;
		if (!model && onday == -1 && offday == -1)
		{
			/* this is the special signal to repress all vegetation
			growth, for simulations of bare ground */
			for (pday=0 ; pday<365 ; pday++)
			{
				remdays_curgrowth[pday] = 0;
				remdays_transfer[pday] = 0;
				predays_transfer[pday] = 0;
				remdays_litfall[pday] = 0;
				predays_litfall[pday] = 0;
			}
		} /* end if special no-growth signal */
		else
		{
			/* normal growth */

			if (!model && !evergreen)
			{
				/* user-specified dates for onset and offset, but this
				gets overridden for evergreen types, so this case is only
				for USER-SPECIFIED DECIDUOUS (either woody or non-woody) */
				/* IMPORTANT NOTE:  the user specified yeardays for onset
				and offset are in relation to a phenological definition for
				a year, instead of the calendar year. In the Northern hemisphere,
				this is the same as the calendar year, but in the southern
				hemisphere, the phenological yeardays are defined to start on
				July 2 (N. Hem yearday 182, using base-zero).  This lets a
				user shift from N. Hem site to S. Hem site without having to
				change phenological yeardays in the ini file */
				/* force onset and offset to be at least one day apart */
				if (onday == offday)
				{
					if (onday > 0) onday--;
					else offday++;
				}
				ngrowthdays = offday - onday;
				/* define the length of the transfer and litfall periods */
				/* calculate number of transfer days and number of litfall days
				as proportions of number of growth days, as specified by user.
				Round and truncate to force these values between 1 and 
				ngrowthdays */
				t1 = epc->transfer_pdays * (double)ngrowthdays;
				sprintf(round,"%.0f",t1);
				ntransferdays = atoi(round);
				if (ntransferdays < 1) ntransferdays = 1;
				if (ntransferdays > ngrowthdays) ntransferdays = ngrowthdays;
				t1 = epc->litfall_pdays * (double)ngrowthdays;
				sprintf(round,"%.0f",t1);
				nlitfalldays = atoi(round);
				if (nlitfalldays < 1) nlitfalldays = 1;
				if (nlitfalldays > ngrowthdays) nlitfalldays = ngrowthdays;
				for (pday=0 ; pday<onday ; pday++)
				{
					remdays_curgrowth[pday] = 0;
					remdays_transfer[pday] = 0;
					remdays_litfall[pday] = 0;
					predays_transfer[pday] = 0;
					predays_litfall[pday] = 0;
				}
				counter = ngrowthdays;
				for (pday=onday ; pday<offday ; pday++)
				{
					remdays_curgrowth[pday] = counter;
					counter--;
				}
				for (pday=offday ; pday<365 ; pday++)
				{
					remdays_curgrowth[pday] = 0;
				}
				counter = ntransferdays;
				for (pday=onday ; pday<onday+ntransferdays ; pday++)
				{
					remdays_transfer[pday] = counter;
					predays_transfer[pday] = ntransferdays - counter;
					counter--;
				}
				for (pday=onday+ntransferdays ; pday<=offday ; pday++)
				{
					remdays_transfer[pday] = 0;
					predays_transfer[pday] = ntransferdays;
				}
				for (pday=offday+1 ; pday<365 ; pday++)
				{
					remdays_transfer[pday] = 0;
					predays_transfer[pday] = 0;
				}
				for (pday=onday ; pday<offday-nlitfalldays+1 ; pday++)
				{
					remdays_litfall[pday] = 0;
					predays_litfall[pday] = 0;
				}
				counter = nlitfalldays;
				for (pday=offday-nlitfalldays+1 ; pday<=offday ; pday++)
				{
					remdays_litfall[pday] = counter;
					predays_litfall[pday] = nlitfalldays - counter;
					counter--;
				}
				for (pday=offday+1 ; pday<365 ; pday++)
				{
					remdays_litfall[pday] = 0;
					predays_litfall[pday] = 0;
				}
			} /* end if user-specified and deciduous */

			if (evergreen)
			{	
				/* specifying evergreen overrides any user input phenology data,
				and triggers a very simple treatment of the transfer, litterfall,
				and current growth signals.  Treatment is the same for woody and
				non-woody types, and the same for model or user-input phenology */
				/* fill the local phenyear control arrays */
				for (pday=0 ; pday<365 ; pday++)
				{
					remdays_curgrowth[pday] = 365-pday;
					remdays_transfer[pday] = 365-pday;
					remdays_litfall[pday] = 365-pday;
					predays_transfer[pday] = pday;
					predays_litfall[pday] = pday;
				} 
			} /* end if evergreen */
		} /* end else normal growth */

		/* now copy this year multiple times to the permanent phenology struct
		arrays, with tests for southern hemisphere. */
		for (py=0 ; py<phenyears ; py++)
		{
			if (south)
			{
				if (py==0)
				{
					/* only copy the second half of this phenological
					year to the permanent phenology array */
					for (pday=182 ; pday<365 ; pday++)
					{
						phen->remdays_curgrowth[pday-182] = remdays_curgrowth[pday];
						phen->remdays_transfer[pday-182] = remdays_transfer[pday];
						phen->remdays_litfall[pday-182] = remdays_litfall[pday];
						phen->predays_transfer[pday-182] = predays_transfer[pday];
						phen->predays_litfall[pday-182] = predays_litfall[pday];
					}
				}
				else if (py==phenyears-1)
				{
					/* only copy the first half of this phenological
					year to the permanent phenology array */
					for (pday=0 ; pday<182 ; pday++)
					{
						phen->remdays_curgrowth[py*365-182+pday] = remdays_curgrowth[pday];
						phen->remdays_transfer[py*365-182+pday] = remdays_transfer[pday];
						phen->remdays_litfall[py*365-182+pday] = remdays_litfall[pday];
						phen->predays_transfer[py*365-182+pday] = predays_transfer[pday];
						phen->predays_litfall[py*365-182+pday] = predays_litfall[pday];
					}
				}
				else
				{
					for (pday=0 ; pday<365 ; pday++)
					{
						phen->remdays_curgrowth[py*365-182+pday] = remdays_curgrowth[pday];
						phen->remdays_transfer[py*365-182+pday] = remdays_transfer[pday];
						phen->remdays_litfall[py*365-182+pday] = remdays_litfall[pday];
						phen->predays_transfer[py*365-182+pday] = predays_transfer[pday];
						phen->predays_litfall[py*365-182+pday] = predays_litfall[pday];
					}
				}
			} /* end if south */
			else
			{
				/* north */
				for (pday=0 ; pday<365 ; pday++)
				{
					phen->remdays_curgrowth[py*365+pday] = remdays_curgrowth[pday];
					phen->remdays_transfer[py*365+pday] = remdays_transfer[pday];
					phen->remdays_litfall[py*365+pday] = remdays_litfall[pday];
					phen->predays_transfer[py*365+pday] = predays_transfer[pday];
					phen->predays_litfall[py*365+pday] = predays_litfall[pday];
				}
			} /* end if north */
		} /* end py loop */
	} /* end if constant phenological signals */
	else
	{
		/* Cases that have variable phenological signals between years */
		/* Use the phenology model described in White et al., 1997 */
		/* the two cases that make it to this block are:
		model, deciduous, woody   and
		model, deciduous, non-woody (grass), which are the two cases
		handled by the White et al. paper */
		if (woody)
		{
			/* use DECIDUOUS TREE PHENOLOGY MODEL */
			/* loop through the entire tavg timeseries to calculate long-term
			average tavg */
			mean_tavg = 0.0;
			for (i=0 ; i<ndays ; i++)
			{
				mean_tavg += metarr->tavg[i];
			}
			mean_tavg /= (double)ndays;
			/* tree onset equation from Mike White, Aug. 1997 */
			onset_critsum = exp(4.795 + 0.129*mean_tavg);
			
			/* now go through the phenological years and generate expansion
			and litterfall arrays. Some complications for Southern
			hemisphere sites... */
			/* calculate fall_tavg, the mean tavg from phenyday 244-304 */
			fall_tavg = 0.0;
			fall_tavg_count = 0;
			for (py=0 ; py<phenyears ; py++)
			{
				for (pday=244 ; pday<305 ; pday++)
				{
					if (south)
					{
						if (py==phenyears-1 && pday>181)
						{
							/* use the beginning of the last year to fill the
							end of the last phenological year */
							phensoilt = metarr->tavg_ra[ndays-547+pday];
						}
						else
						{
							phensoilt = metarr->tavg_ra[py*365-182+pday];
						}
					}
					else /* north */
					{
						phensoilt = metarr->tavg_ra[py*365+pday];
					}
					
					fall_tavg += phensoilt;
					fall_tavg_count++;
					
				} /* end pday loop */
			} /* end py loop */
			fall_tavg /= (double)fall_tavg_count;
			
			/* loop through phenyears again, fill onset and offset arrays */
			for (py=0 ; py<phenyears ; py++)
			{
				sum_soilt = 0.0;
				onset_day = offset_day = -1;
				for (pday=0 ; pday<365 ; pday++)
				{
					if (south)
					{
						if (py==0 && pday<182)
						{
							/* use the end of the first year to fill the 
							beginning of a southern hemisphere phenological
							year */
							phensoilt = metarr->tavg_ra[183+pday];
							phendayl = metarr->dayl[183+pday];
						}
						else if (py==phenyears-1 && pday>181)
						{
							/* use the beginning of the last year to fill the
							end of the last phenological year */
							phensoilt = metarr->tavg_ra[ndays-547+pday];
							phendayl = metarr->dayl[ndays-547+pday];
						}
						else
						{
							phensoilt = metarr->tavg_ra[py*365-182+pday];
							phendayl = metarr->dayl[py*365-182+pday];
						}
					}
					else /* north */
					{
						phensoilt = metarr->tavg_ra[py*365+pday];
						phendayl = metarr->dayl[py*365+pday];
					}
					
					/* tree onset test */
					if (onset_day == -1)
					{
						if (phensoilt > 0.0) sum_soilt += phensoilt;
						if (sum_soilt >= onset_critsum) onset_day = pday;
					}
					
					/* tree offset test */
					if (onset_day != -1 && offset_day == -1)
					{
						if ((pday>182) && 
						(((phendayl<=critdayl) && (phensoilt<=fall_tavg)) ||
						(phensoilt<=2.0))) offset_day = pday;
					}
					
				} /* end pday loop */
				
				/* now do some exception handling for this year's phenology */
				if (onset_day != -1)
				{
					/* leaves are turned on sometime this year */
					/* subtract 15 days from onset day to approximate the
					start of the new growth period, instead of the middle of
					the new growth period, as is used in the White et al. ms. */
					if (onset_day >= 15)
					{
						onset_day -= 15;
					}
					else onset_day = 0;

					/* if leaves never got turned off, force off on last day */
					if (offset_day == -1) offset_day = 364;
					/* add 15 days to offset day to approximate the
					end of the litterfall period, instead of the middle
					as in the White et al. ms. */
					if (offset_day <= 349)
					{
						offset_day += 15;
					}
					else offset_day = 364;
					
					/* force onset and offset to be at least one day apart */
					if (onset_day == offset_day)
					{
						if (onset_day > 0) onset_day--;
						else offset_day++;
					}
				}
				else
				{
					/* leaves never got turned on, this is a non-growth
					year.  This probably indicates a problem with the
					phenology model */
					onset_day = -1;
					offset_day = -1;
				}

				/* save these onset and offset days and go to the next
				phenological year */
				onday_arr[py] = onset_day;
				offday_arr[py] = offset_day;
				
			} /* end phenyears loop for filling onset and offset arrays */
		} /* end if woody (tree phenology model) */
		else
		{
			/* non-woody, use the GRASS PHENOLOGY MODEL to calculate the
			array of onset and offset days */
			/* loop through the entire tavg timeseries to calculate long-term
			average tavg and long-term average annual total precip */
			mean_tavg = 0.0;
			ann_prcp = 0.0;
			for (i=0 ; i<ndays ; i++)
			{
				mean_tavg += metarr->tavg[i];
				ann_prcp += metarr->prcp[i];
			}
			mean_tavg /= (double)ndays;
			ann_prcp /= (double)ndays / 365.0;
			
			/* grass onset equation from White et al., 1997, with parameter
			values specified by Mike White, Aug. 1997 */
			t1 = exp(grass_a * (mean_tavg - grass_tmid));
			grass_stsumcrit = ((grass_stsummax - grass_stsummin)* 0.5 *
				((t1-1)/(t1+1))) + grass_stsummid;
			grass_prcpcrit = ann_prcp * grass_k;
			
			/* now go through the phenological years and generate onset
			and offset days */
			
			/* calculate the long-term average annual high temperature
			for use in grass offset prediction */
			tmax_ann = 0.0;
			tmin_annavg = 0.0;
			for (py=0 ; py<phenyears ; py++)
			{
				new_tmax = -1000.0;
				for (pday=0 ; pday<365 ; pday++)
				{
					if (south)
					{
						if (py==0 && pday<182)
						{
							/* use the end of the first year to fill the 
							beginning of a southern hemisphere phenological
							year */
							tmax = metarr->tmax[183+pday];
							tmin_annavg += metarr->tmin[183+pday];
						}
						else if (py==phenyears-1 && pday>181)
						{
							/* use the beginning of the last year to fill the
							end of the last phenological year */
							tmax = metarr->tmax[ndays-547+pday];
							tmin_annavg += metarr->tmin[ndays-547+pday];
						}
						else
						{
							tmax = metarr->tmax[py*365-182+pday];
							tmin_annavg += metarr->tmin[py*365-182+pday];
						}
					}
					else /* north */
					{
						tmax = metarr->tmax[py*365+pday];
						tmin_annavg += metarr->tmin[py*365+pday];
					}
					
					if (tmax > new_tmax) new_tmax = tmax;
					
				} /* end pday loop */
				
				tmax_ann += new_tmax;
			} /* end py loop */
			tmax_ann /= (double) phenyears;
			/* 92% of tmax_ann is the threshold used in grass offset below */
			tmax_ann *= 0.92;
			tmin_annavg /= (double) phenyears * 365.0;
			
			/* loop through phenyears again, fill onset and offset arrays */
			for (py=0 ; py<phenyears ; py++)
			{
				sum_soilt = 0.0;
				sum_prcp = 0.0;
				onset_day = offset_day = -1;
				for (pday=0 ; pday<365 ; pday++)
				{
					if (south)
					{
						if (py==0 && pday<182)
						{
							/* use the end of the first year to fill the 
							beginning of a southern hemisphere phenological
							year */
							phensoilt = metarr->tavg_ra[183+pday];
							phenprcp = metarr->prcp[183+pday];
							grass_prcpyear[pday] = phenprcp;
							grass_tminyear[pday] = metarr->tmin[183+pday];
							grass_tmaxyear[pday] = metarr->tmax[183+pday];
						}
						else if (py==phenyears-1 && pday>181)
						{
							/* use the beginning of the last year to fill the
							end of the last phenological year */
							phensoilt = metarr->tavg_ra[ndays-547+pday];
							phenprcp = metarr->prcp[ndays-547+pday];
							grass_prcpyear[pday] = phenprcp;
							grass_tminyear[pday] = metarr->tmin[ndays-547+pday];
							grass_tmaxyear[pday] = metarr->tmax[ndays-547+pday];
						}
						else
						{
							phensoilt = metarr->tavg_ra[py*365-182+pday];
							phenprcp = metarr->prcp[py*365-182+pday];
							grass_prcpyear[pday] = phenprcp;
							grass_tminyear[pday] = metarr->tmin[py*365-182+pday];
							grass_tmaxyear[pday] = metarr->tmax[py*365-182+pday];
						}
					}
					else /* north */
					{
						phensoilt = metarr->tavg_ra[py*365+pday];
						phenprcp = metarr->prcp[py*365+pday];
						grass_prcpyear[pday] = phenprcp;
						grass_tminyear[pday] = metarr->tmin[py*365+pday];
						grass_tmaxyear[pday] = metarr->tmax[py*365+pday];
					}
					
					/* grass onset test */
					if (onset_day == -1)
					{
						if (phensoilt > 0.0) sum_soilt += phensoilt;
						sum_prcp += phenprcp;
						if (sum_soilt >= grass_stsumcrit &&
							sum_prcp >= grass_prcpcrit) onset_day = pday;
					}
					
				} /* end pday loop */
				
				/* do averaging operations on grass_prcpyear and grass_tminyear,
				and do tests for offset day. Offset due to hot & dry can't
				happen within one month after the onset day, and offset due
				to cold can't happen before midyear (yearday 182) */
				if (onset_day != -1)
				{
					/* calculate three-day boxcar average of tmin */
					if (boxcar_smooth(grass_tminyear, grass_3daytmin, 365,3,0))
					{
						bgc_printf(BV_ERROR, "Error in prephenology() call to boxcar()\n");
						ok=0;
					}
					
					for (pday=onset_day+30 ; pday<365 ; pday++)
					{
						/* calculate the previous 31-day prcp total */
						psum_startday = pday - 30;
						grass_prcpprev = 0.0;
						for (i=psum_startday ; i<=pday ; i++)
						{
							grass_prcpprev += grass_prcpyear[i];
						}

						/* calculate the next 7-day prcp total */
						if (pday > 358) psum_stopday = 364;
						else psum_stopday = pday + 6;
						grass_prcpnext = 0.0;
						for (i=pday ; i<=psum_stopday ; i++)
						{
							grass_prcpnext += grass_prcpyear[i];
						}
						
						/* test for hot and dry conditions */
						if (offset_day == -1)
						{
							if (grass_prcpprev < grass_prcpprevcrit && 
								grass_prcpnext < grass_prcpnextcrit &&
								grass_tmaxyear[pday] > tmax_ann)
								offset_day = pday;
						}
						
						/* test for cold offset condition */
						if (offset_day == -1)
						{
							if (pday > 182 &&
								grass_3daytmin[pday] <= tmin_annavg)
								offset_day = pday;
						}
						
					} /* end of pdays loop for grass offset testing */
				} /* end of if onset_day != -1 block */
					
				/* now do some exception handling for this year's phenology */
				if (onset_day != -1)
				{
					/* leaves are turned on sometime this year */
					/* subtract 15 days from onset day to approximate the
					start of the new growth period, instead of the middle of
					the new growth period, as is used in the White et al. ms. */
					if (onset_day >= 15)
					{
						onset_day -= 15;
					}
					else onset_day = 0;

					/* if leaves never got turned off, force off on last day */
					if (offset_day == -1) offset_day = 364;

					/* force onset and offset to be at least one day apart */
					if (onset_day == offset_day)
					{
						if (onset_day > 0) onset_day--;
						else offset_day++;
					}
				}
				else
				{
					/* leaves never got turned on, this is a non-growth
					year.  This probably indicates a problem with the
					phenology model */
					onset_day = -1;
					offset_day = -1;
				}
				
				/* save these onset and offset days and go to the next
				phenological year */
				onday_arr[py] = onset_day;
				offday_arr[py] = offset_day;
				
			} /* end phenyears loop for filling onset and offset arrays */
		} /* end else !woody (grass phenology model) */
		
		/* now the onset and offset days are established for each phenyear,
		either by the deciduous tree or the grass model.  Next loop through
		phenyears filling the phenology signal arrays and copying them to 
		the permanent phen struct arrays */
		for (py=0 ; py<phenyears ; py++)
		{
			/* zero the 365-day phen arrays */
			for (pday=0 ; pday<365 ; pday++)
			{
				remdays_curgrowth[pday] = 0;
				remdays_transfer[pday] = 0;
				predays_transfer[pday] = 0;
				remdays_litfall[pday] = 0;
				predays_litfall[pday] = 0;
			}
			
			onday = onday_arr[py];
			offday = offday_arr[py];
			
			if (onday == -1 && offday == -1)
			{
				/* this is the special signal to repress all vegetation
				growth */
				for (pday=0 ; pday<365 ; pday++)
				{
					remdays_curgrowth[pday] = 0;
					remdays_transfer[pday] = 0;
					predays_transfer[pday] = 0;
					remdays_litfall[pday] = 0;
					predays_litfall[pday] = 0;
				}
			} /* end if special no-growth signal */
			else
			{
				/* normal growth year */
				ngrowthdays = offday - onday;
				if (ngrowthdays < 1)
				{
					bgc_printf(BV_ERROR, "FATAL ERROR: ngrowthdays < 1\n");
					bgc_printf(BV_ERROR, "ngrowthdays = %d\n",ngrowthdays);
					bgc_printf(BV_ERROR, "onday = %d\toffday = %d\tphenyear = %d\n",
					onday,offday,py);
					ok=0;
				}
				/* define the length of the transfer and litfall periods */
				/* calculate number of transfer days and number of litfall days
				as proportions of number of growth days, as specified by user.
				Round and truncate to force these values between 1 and 
				ngrowthdays */
				t1 = epc->transfer_pdays * (double)ngrowthdays;
				sprintf(round,"%.0f",t1);
				ntransferdays = atoi(round);
				if (ntransferdays < 1) ntransferdays = 1;
				if (ntransferdays > ngrowthdays) ntransferdays = ngrowthdays;
				t1 = epc->litfall_pdays * (double)ngrowthdays;
				sprintf(round,"%.0f",t1);
				nlitfalldays = atoi(round);
				if (nlitfalldays < 1) nlitfalldays = 1;
				if (nlitfalldays > ngrowthdays) nlitfalldays = ngrowthdays;
				
				for (pday=0 ; pday<onday ; pday++)
				{
					remdays_curgrowth[pday] = 0;
					remdays_transfer[pday] = 0;
					remdays_litfall[pday] = 0;
					predays_transfer[pday] = 0;
					predays_litfall[pday] = 0;
				}
				counter = ngrowthdays;
				for (pday=onday ; pday<offday ; pday++)
				{
					remdays_curgrowth[pday] = counter;
					counter--;
				}
				for (pday=offday ; pday<365 ; pday++)
				{
					remdays_curgrowth[pday] = 0;
				}
				counter = ntransferdays;
				for (pday=onday ; pday<onday+ntransferdays ; pday++)
				{
					remdays_transfer[pday] = counter;
					predays_transfer[pday] = ntransferdays - counter;
					counter--;
				}
				for (pday=onday+ntransferdays ; pday<=offday ; pday++)
				{
					remdays_transfer[pday] = 0;
					predays_transfer[pday] = ntransferdays;
				}
				for (pday=offday+1 ; pday<365 ; pday++)
				{
					remdays_transfer[pday] = 0;
					predays_transfer[pday] = 0;
				}
				for (pday=onday ; pday<offday-nlitfalldays+1 ; pday++)
				{
					remdays_litfall[pday] = 0;
					predays_litfall[pday] = 0;
				}
				counter = nlitfalldays;
				for (pday=offday-nlitfalldays+1 ; pday<=offday ; pday++)
				{
					remdays_litfall[pday] = counter;
					predays_litfall[pday] = nlitfalldays - counter;
					counter--;
				}
				for (pday=offday+1 ; pday<365 ; pday++)
				{
					remdays_litfall[pday] = 0;
					predays_litfall[pday] = 0;
				}
			} /* end else normal growth year */
			
			/* now put the signals for this phenological year into the
			right place in the permanent phen struct arrays */ 
			if (south)
			{
				if (py==0)
				{
					/* only copy the second half of this phenological
					year to the permanent phenology array */
					for (pday=182 ; pday<365 ; pday++)
					{
						phen->remdays_curgrowth[pday-182] = remdays_curgrowth[pday];
						phen->remdays_transfer[pday-182] = remdays_transfer[pday];
						phen->remdays_litfall[pday-182] = remdays_litfall[pday];
						phen->predays_transfer[pday-182] = predays_transfer[pday];
						phen->predays_litfall[pday-182] = predays_litfall[pday];
					}
				}
				else if (py==phenyears-1)
				{
					/* only copy the first half of this phenological
					year to the permanent phenology array */
					for (pday=0 ; pday<182 ; pday++)
					{
						phen->remdays_curgrowth[py*365-182+pday] = remdays_curgrowth[pday];
						phen->remdays_transfer[py*365-182+pday] = remdays_transfer[pday];
						phen->remdays_litfall[py*365-182+pday] = remdays_litfall[pday];
						phen->predays_transfer[py*365-182+pday] = predays_transfer[pday];
						phen->predays_litfall[py*365-182+pday] = predays_litfall[pday];
					}
				}
				else
				{
					for (pday=0 ; pday<365 ; pday++)
					{
						phen->remdays_curgrowth[py*365-182+pday] = remdays_curgrowth[pday];
						phen->remdays_transfer[py*365-182+pday] = remdays_transfer[pday];
						phen->remdays_litfall[py*365-182+pday] = remdays_litfall[pday];
						phen->predays_transfer[py*365-182+pday] = predays_transfer[pday];
						phen->predays_litfall[py*365-182+pday] = predays_litfall[pday];
					}
				}
			} /* end if south */
			else
			{
				/* north */
				for (pday=0 ; pday<365 ; pday++)
				{
					phen->remdays_curgrowth[py*365+pday] = remdays_curgrowth[pday];
					phen->remdays_transfer[py*365+pday] = remdays_transfer[pday];
					phen->remdays_litfall[py*365+pday] = remdays_litfall[pday];
					phen->predays_transfer[py*365+pday] = predays_transfer[pday];
					phen->predays_litfall[py*365+pday] = predays_litfall[pday];
				}
			} /* end if north */
		} /* end phenyears loop for filling permanent arrays */
	} /* end else phenology model block */
				
	/* free the local array memory */
	free(onday_arr);
	free(offday_arr);
	
	return (!ok);
}
Beispiel #14
0
int main(int argc, char *argv[])
{
	/* bgc input and output structures */
	bgcin_struct bgcin;
	bgcout_struct bgcout;

	/* local control information */
	point_struct point;
	restart_ctrl_struct restart;
	climchange_struct scc;
	output_struct output;
	
	/* initialization file */
	file init;
	file ndep_file;

	/* system time variables */
	struct tm *tm_ptr;
	time_t lt;

	extern signed char summary_sanity;

	int c; /* for getopt cli argument processing */
	extern signed char bgc_verbosity;
	extern int optind, opterr;
	unsigned char bgc_ascii = 0;
	extern char *optarg;
	extern signed char cli_mode; /* What cli requested mode to run in.*/
	int readndepfile = 0;		/* Flag to tell the program to read an external NDEP file passed using getpopt -n */
	
	bgcin.ndepctrl.varndep = 0;
	/* Store command name for use by bgc_print_usage() */
	argv_zero = (char *)malloc(strlen(argv[0])+1);
	strncpy(argv_zero, argv[0], strlen(argv[0])+1);

	/* Process command line arguments */
	opterr = 0;
	while((c = getopt(argc, argv, "pVsl:v:ugmn:a")) != -1)
	{
		switch(c)
		{
			case 'V':
				bgc_printf(BV_ERROR, "BiomeBGC version %s (built %s %s by %s on %s)\n", VERS, __DATE__, __TIME__, USER, HOST);
				exit(EXIT_SUCCESS);
				break;
			case 's':
				bgc_verbosity = BV_SILENT;
				break;
			case 'v':
				bgc_verbosity = bgc_verbosity_decode(optarg);
				break;
			case 'l':
				bgc_logfile_setup(optarg);
				bgc_printf(BV_DIAG, "Using logfile for output.\n");
				break;
			case 'p':
				summary_sanity = SANE;
				break;
			case 'u':
				cli_mode = MODE_SPINUP;
				break;
			case 'm':
				cli_mode = MODE_MODEL;
				break;
			case 'g':
				cli_mode = MODE_SPINNGO;
				break;
			case 'a':
				bgc_ascii = 1;
				break;
			case 'n':  /* Nitrogen deposition file */
				strcpy(ndep_file.name,optarg);
				bgc_printf(BV_DIAG,"Using annual NDEP file: %s\n",ndep_file.name);
				readndepfile = 1;
				bgcin.ndepctrl.varndep = 1;
				break;
				
			case '?':
				break;
			default:
				break;
			}
	}

	bgc_printf(BV_DIAG, "Verbosity Level Set To: %d\n", bgc_verbosity);
	
	if (summary_sanity == SANE)
		bgc_printf(BV_WARN, "Summary outputs will be calculated more sanely. See USAGE.TXT for details\n");

	if (cli_mode != MODE_INI)
	{
		bgc_printf(BV_WARN, "Overridding ini mode. ");
		if (cli_mode == MODE_SPINUP)
			bgc_printf(BV_WARN, "Running in Spinup Mode.\n");
		if (cli_mode == MODE_MODEL)
			bgc_printf(BV_WARN, "Running in Model mode.\n");
		if (cli_mode == MODE_SPINNGO)
			bgc_printf(BV_WARN, "Running in Spin-and-Go mode.\nThe spinup and model will both be run.\n");
	}
		
	bgc_printf(BV_DIAG, "Done processing CLI arguments.\n");

	/* get the system time at start of simulation */
	lt = time(NULL);
	tm_ptr = localtime(&lt);
	strcpy(point.systime,asctime(tm_ptr));
	/* Andrew tried this, you shouldn't. localtime returns a global extern. */
	/* free(tm_ptr); */
	output.anncodes = NULL;
	output.daycodes = NULL;
	output.bgc_ascii = bgc_ascii;
	
	/* initialize the bgcin state variable structures before filling with
	values from ini file */
	if (presim_state_init(&bgcin.ws, &bgcin.cs, &bgcin.ns, &bgcin.cinit))
	{
		bgc_printf(BV_ERROR, "Error in call to presim_state_init() from pointbgc()\n");
		exit(EXIT_FAILURE);
	}

	/******************************
	**                           **
	**  BEGIN READING INIT FILE  **
	**                           **
	******************************/

	/* read the name of the main init file from the command line
	and store as init.name */
	if (optind >= argc )
	{
		bgc_print_usage();
		exit(EXIT_FAILURE);
	}
	strcpy(init.name, argv[optind]);
	
	/* open the main init file for ascii read and check for errors */
	if (file_open(&init,'i'))
	{
		bgc_printf(BV_ERROR, "Error opening init file, pointbgc.c\n");
		exit(EXIT_FAILURE);
	}

	/* read the header string from the init file */
	if (fgets(point.header, 100, init.ptr)==NULL)
	{
		bgc_printf(BV_ERROR, "Error reading header string: pointbgc.c\n");
		exit(EXIT_FAILURE);
	}

	/* open met file, discard header lines */
	if (met_init(init, &point))
	{
		bgc_printf(BV_ERROR, "Error in call to met_init() from pointbgc.c... Exiting\n");
		exit(EXIT_FAILURE);
	}

	/* read restart control parameters */
	if (restart_init(init, &restart))
	{
		bgc_printf(BV_ERROR, "Error in call to restart_init() from pointbgc.c... Exiting\n");
		exit(EXIT_FAILURE);
	}

	/* read simulation timing control parameters */
	if (time_init(init, &(bgcin.ctrl)))
	{
		bgc_printf(BV_ERROR, "Error in call to epclist_init() from pointbgc.c... Exiting\n");
		exit(EXIT_FAILURE);
	}
	
	/* read scalar climate change parameters */
	if (scc_init(init, &scc))
	{
		bgc_printf(BV_ERROR, "Error in call to scc_init() from pointbgc.c... Exiting\n");
		exit(EXIT_FAILURE);
	}
	
	/* read CO2 control parameters */
	if (co2_init(init, &(bgcin.co2), bgcin.ctrl.simyears))
	{
		bgc_printf(BV_ERROR, "Error in call to co2_init() from pointbgc.c... Exiting\n");
		exit(EXIT_FAILURE);
	}
	if(readndepfile)
	{
		if (ndep_init(ndep_file, &(bgcin.ndepctrl)))
		{
			bgc_printf(BV_ERROR, "Error in call to ndep_init() from pointbgc.c... Exiting\n");
			exit(EXIT_FAILURE);
		}
	}
	/* read site constants */
	if (sitec_init(init, &bgcin.sitec))
	{
		bgc_printf(BV_ERROR, "Error in call to sitec_init() from pointbgc.c... Exiting\n");
		exit(EXIT_FAILURE);
	}
	
	/* read ramped nitrogen deposition block */
	if (ramp_ndep_init(init, &bgcin.ramp_ndep))
	{
		bgc_printf(BV_ERROR, "Error in call to ramp_ndep_init() from pointbgc.c... Exiting\n");
		exit(EXIT_FAILURE);
	}
	
	/* read ecophysiological constants */
	if (epc_init(init, &bgcin.epc))
	{
		bgc_printf(BV_ERROR, "Error in call to epc_init() from pointbgc.c... Exiting\n");
		exit(EXIT_FAILURE);
	}

	/* initialize water state structure */
	if (wstate_init(init, &bgcin.sitec, &bgcin.ws))
	{
		bgc_printf(BV_ERROR, "Error in call to wstate_init() from pointbgc.c... Exiting\n");
		exit(EXIT_FAILURE);
	}

	/* initialize carbon and nitrogen state structures */
	if (cnstate_init(init, &bgcin.epc, &bgcin.cs, &bgcin.cinit,
		&bgcin.ns))
	{
		bgc_printf(BV_ERROR, "Error in call to cstate_init() from pointbgc.c... Exiting\n");
		exit(EXIT_FAILURE);
	}

	/* read the output control information */
	if (output_ctrl(init, &output))
	{
		bgc_printf(BV_ERROR, "Error in call to output_ctrl() from pointbgc.c... Exiting\n");
		exit(EXIT_FAILURE);
	}
	
	/* initialize output files. Does nothing in spinup mode*/
	if (output_init(&output))
	{
		bgc_printf(BV_ERROR, "Error in call to output_init() from pointbgc.c... Exiting\n");
		exit(EXIT_FAILURE);
	}
	
	/* read final line out of init file to test for proper file structure */
	if (end_init(init))
	{
		bgc_printf(BV_ERROR, "Error in call to end_init() from pointbgc.c... exiting\n");
		exit(EXIT_FAILURE);
	}
	fclose(init.ptr);

	/* read meteorology file, build metarr arrays, compute running avgs */
	if (metarr_init(point.metf, &bgcin.metarr, &scc, bgcin.ctrl.metyears))
	{
		bgc_printf(BV_ERROR, "Error in call to metarr_init() from pointbgc.c... Exiting\n");
		exit(EXIT_FAILURE);
	}
	fclose(point.metf.ptr);

	/* copy some of the info from input structure to bgc simulation control
	structure */
	bgcin.ctrl.onscreen = output.onscreen;
	bgcin.ctrl.dodaily = output.dodaily;
	bgcin.ctrl.domonavg = output.domonavg;
	bgcin.ctrl.doannavg = output.doannavg;
	bgcin.ctrl.doannual = output.doannual;
	bgcin.ctrl.ndayout = output.ndayout;
	bgcin.ctrl.nannout = output.nannout;
	bgcin.ctrl.daycodes = output.daycodes;
	bgcin.ctrl.anncodes = output.anncodes;
	bgcin.ctrl.read_restart = restart.read_restart;
	bgcin.ctrl.write_restart = restart.write_restart;
	bgcin.ctrl.keep_metyr = restart.keep_metyr;
	
	/* copy the output file structures into bgcout */
	if (output.dodaily) bgcout.dayout = output.dayout;
	if (output.domonavg) bgcout.monavgout = output.monavgout;
	if (output.doannavg) bgcout.annavgout = output.annavgout;
	if (output.doannual) bgcout.annout = output.annout;
	if (output.bgc_ascii && output.dodaily) bgcout.dayoutascii = output.dayoutascii;
	if (output.bgc_ascii && output.domonavg) bgcout.monoutascii = output.monoutascii;
	if (output.bgc_ascii && output.doannual) bgcout.annoutascii = output.annoutascii;
	bgcout.anntext = output.anntext;
	bgcout.bgc_ascii = bgc_ascii;
	
	/* if using ramped Ndep, copy preindustrial Ndep into ramp_ndep struct */
	if (bgcin.ramp_ndep.doramp)
	{
		bgcin.ramp_ndep.preind_ndep = bgcin.sitec.ndep;
	}
	
	/* if using an input restart file, read a record */
	if (restart.read_restart)
	{
		/* 02/06/04
		 * The if statement gaurds against core dump on bad restart file.
		 * If spinup exits with error then the norm trys to use the restart,
		 * that has nothing in it, a seg fault occurs. Amac */
		if( fread(&(bgcin.restart_input),sizeof(restart_data_struct),1,restart.in_restart.ptr) == 0)
		{
			bgc_printf(BV_ERROR, "Error reading restart file! 0 bytes read. Aborting..\n");
			exit(EXIT_FAILURE);
		}
	}

	/*********************
	**                  **
	**  CALL BIOME-BGC  **
	**                  **
	*********************/

	/* all initialization complete, call model */
	/* either call the spinup code or the normal simulation code */
	if (bgcin.ctrl.spinup)
	{
		if (bgc(&bgcin, &bgcout,MODE_SPINUP))
		{
			bgc_printf(BV_ERROR, "Error in call to bgc()\n");
			exit(EXIT_FAILURE);
		}
		bgc_printf(BV_PROGRESS, "SPINUP: residual trend  = %.6lf\n",bgcout.spinup_resid_trend);
		bgc_printf(BV_PROGRESS, "SPINUP: number of years = %d\n",bgcout.spinup_years);
	}
	else
	{
		if (bgc(&bgcin, &bgcout, MODE_MODEL))
		{
			bgc_printf(BV_ERROR, "Error in call to bgc()\n");
			exit(EXIT_FAILURE);
		}
	}
		

	/* if using an output restart file, write a record */
	if (restart.write_restart)
	{
		fwrite(&(bgcout.restart_output),sizeof(restart_data_struct),1,
			restart.out_restart.ptr);
	}
	
	/* Now do the Model part of Spin & Go. */
	if (cli_mode == MODE_SPINNGO)
	{
		bgc_printf(BV_PROGRESS, "Finished Spinup for Spin 'n Go. Now starting Model run ('Go' part of Spin'n Go)\n");
			
		bgc_printf(BV_PROGRESS, "Assigned bgcout struct to bgcin for spinngo model run\n");
		
		bgcin.ctrl.spinup = 0;
		output.doannavg = 1;
		output.doannual = 1;
		output.dodaily = 1;
		output.domonavg = 1;
		
		if (output_init(&output))
		{
			bgc_printf(BV_ERROR, "Error in call to output_init() from pointbgc.c... Exiting\n");
			exit(EXIT_FAILURE);
		}
		
		/* copy some of the info from input structure to bgc simulation control structure */
		bgcin.ctrl.dodaily = output.dodaily;
		bgcin.ctrl.domonavg = output.domonavg;
		bgcin.ctrl.doannavg = output.doannavg;
		bgcin.ctrl.doannual = output.doannual;
	
		/* copy the output file structures into bgcout */
		if (output.dodaily) bgcout.dayout = output.dayout;
		if (output.domonavg) bgcout.monavgout = output.monavgout;
		if (output.doannavg) bgcout.annavgout = output.annavgout;
		if (output.doannual) bgcout.annout = output.annout;
		if (output.bgc_ascii && output.dodaily) bgcout.dayoutascii = output.dayoutascii;
		if (output.bgc_ascii && output.domonavg) bgcout.monoutascii = output.monoutascii;
		if (output.bgc_ascii && output.doannual) bgcout.annoutascii = output.annoutascii;
		if (output.bgc_ascii && output.doannual) bgcout.anntext = output.anntext;
		
		/* initialize output files. Does nothing in spinup mode*/
		
		
		bgcin.ctrl.read_restart = 1;
		bgcin.restart_input = bgcout.restart_output;
		
		if (bgc(&bgcin, &bgcout, MODE_MODEL))
		{
			bgc_printf(BV_ERROR, "Error in call to bgc()\n");
			exit(EXIT_FAILURE);
		}
		restart.read_restart = 0;
		bgcin.ctrl.read_restart = 0;

		bgc_printf(BV_WARN, "Finished the bgc() Model call in spinngo\n");
		
	}

	/* post-processing output handling, if any, goes here */
	
	/* free memory */
	free(bgcin.metarr.tmax);
	free(bgcin.metarr.tmin);
	free(bgcin.metarr.prcp);
	free(bgcin.metarr.vpd);
	free(bgcin.metarr.tavg);
	free(bgcin.metarr.tavg_ra);
	free(bgcin.metarr.swavgfd);
	free(bgcin.metarr.par);
	free(bgcin.metarr.dayl);
	if (bgcin.co2.varco2) free(bgcin.co2.co2ppm_array);
	if (bgcin.ndepctrl.varndep) free(bgcin.ndepctrl.ndepyear_array);
	if (bgcin.ndepctrl.varndep) free(bgcin.ndepctrl.ndep_array);
	if (output.anncodes != NULL) free(output.anncodes);
	if (output.daycodes != NULL) free(output.daycodes);
	
	/* close files */
	if (restart.read_restart) fclose(restart.in_restart.ptr);
	if (restart.write_restart) {
		if (fclose(restart.out_restart.ptr) != 0)
		{
			bgc_printf(BV_WARN, "Warning, error closing restart file after write: %s\n", strerror(errno));
		}
	}
	if (output.dodaily) fclose(output.dayout.ptr);
	if (output.domonavg) fclose(output.monavgout.ptr);
	if (output.doannavg) fclose(output.annavgout.ptr);
	if (output.doannual) fclose(output.annout.ptr);
	/* Close the ASCII output files */
	if (output.bgc_ascii && output.dodaily) fclose(output.dayoutascii.ptr);
	if (output.bgc_ascii && output.domonavg) fclose(output.monoutascii.ptr);
	if (output.bgc_ascii && output.doannual) fclose(output.annoutascii.ptr);
	
	if ( output.bgc_ascii && output.doannual && (fclose(output.anntext.ptr) != 0))
	{
		bgc_printf(BV_WARN, "Warning, error closing ascii annual output file: %s\n", strerror(errno));
	}

	bgc_logfile_finish();
	free(argv_zero);
	return EXIT_SUCCESS;
} /* end of main */