Exemple #1
0
void carbon_allocation(control *c, fluxes *f, params *p, state *s,
                       double nitfac, int doy) {
    /* C distribution - allocate available C through system

    Parameters:
    -----------
    nitfac : float
        leaf N:C as a fraction of 'Ncmaxfyoung' (max 1.0)
    */
    double days_left;
    if (c->deciduous_model) {
        days_left = s->growing_days[doy];
        f->cpleaf = f->lrate * days_left;
        f->cpbranch = f->brate * days_left;
        f->cpstem = f->wrate * days_left;
        f->cproot = s->c_to_alloc_root * 1.0 / c->num_days;
        f->cpcroot = f->crate * days_left;
    } else {
        f->cpleaf = f->npp * f->alleaf;
        f->cproot = f->npp * f->alroot;
        f->cpcroot = f->npp * f->alcroot;
        f->cpbranch = f->npp * f->albranch;
        f->cpstem = f->npp * f->alstem;
    }

    /* evaluate SLA of new foliage accounting for variation in SLA
       with tree and leaf age (Sands and Landsberg, 2002). Assume
       SLA of new foliage is linearly related to leaf N:C ratio
       via nitfac. Based on date from two E.globulus stands in SW Aus, see
       Corbeels et al (2005) Ecological Modelling, 187, 449-474.
       (m2 onesided/kg DW) */
    p->sla = p->slazero + nitfac * (p->slamax - p->slazero);

    if (c->deciduous_model) {
        if (float_eq(s->shoot, 0.0)) {
            s->lai = 0.0;
        } else if (s->leaf_out_days[doy] > 0.0) {
            s->lai += (f->cpleaf *
                      (p->sla * M2_AS_HA / (KG_AS_TONNES * p->cfracts)) -
                      (f->deadleaves + f->ceaten) * s->lai / s->shoot);
        } else {
            s->lai = 0.0;
        }
    } else {
        /* update leaf area [m2 m-2] */
        if (float_eq(s->shoot, 0.0)) {
            s->lai = 0.0;
        } else {
            s->lai += (f->cpleaf *
                      (p->sla * M2_AS_HA / (KG_AS_TONNES * p->cfracts)) -
                      (f->deadleaves + f->ceaten) * s->lai / s->shoot);
        }
    }

    if (c->fixed_lai) {
        s->lai = p->fix_lai;
    }

    return;
}
Exemple #2
0
void calc_root_exudation_release(fluxes *f, state *s) {
    /* Root exudation modelled to occur: with (1) fine root growth or (2)
       as a result of excess C. A fraction of fine root growth is allocated
       to stimulate exudation. This fraction increases with N stress. */
    double leaf_CN, frac_to_rexc, presc_leaf_CN, fine_root_NC;

    if (float_eq(s->shoot, 0.0) || float_eq(s->shootn, 0.0)) {
        /* nothing happens during leaf off period */
        leaf_CN = 0.0;
        frac_to_rexc = 0.0;
    } else {
        leaf_CN = 1.0 / s->shootnc;
        presc_leaf_CN = 30.0; /* make a parameter */

        /* fraction varies between 0 and 50 % as a function of leaf CN */
        frac_to_rexc = MAX(0.0, MIN(0.5, (leaf_CN / presc_leaf_CN) - 1.0));
    }
    /*printf("%f %f\n", s->shootnc, 1./30.);*/
    f->root_exc = frac_to_rexc * f->cproot;
    if (float_eq(f->cproot, 0.0)) {
        f->root_exn = 0.0;
    } else {
        fine_root_NC = f->nproot / f->cproot;
        f->root_exn = f->root_exc * fine_root_NC;
    }

    /* Need to exudation C & N fluxes from fine root growth fluxes so that
       things balance. */
    f->cproot -= f->root_exc;
    f->nproot -= f->root_exn;

    return;
}
Exemple #3
0
END_TEST

START_TEST (test_resi)
{
    const char *commands[] = {"c1, resi 1+2-4",
                              "c2, resi 2-4",
                              "c3, resi 1",
                              "c4, resi 1 AND resi 2-4",
                              "c5, resi 1 OR  resi 2-4",
                              "c6, resi 1-2+2-4",
                              "c7, resi 1+2-4+3",
                              "c8, resi 1-2+7+9+3-5+100",
                              "c9, resi 1-4 AND NOT resi 2-4"};
    freesasa_set_verbosity(FREESASA_V_SILENT);
    test_select(commands,9);
    freesasa_set_verbosity(FREESASA_V_NORMAL);
    ck_assert(value[0] > 5);
    ck_assert(float_eq(value[0], addup(resi_1,result) + addup(resi_2r4,result), 1e-10));
    ck_assert(float_eq(value[1], addup(resi_2r4,result), 1e-10));
    ck_assert(float_eq(value[2], addup(resi_1,result), 1e-10));
    ck_assert(float_eq(value[3], 0, 1e-10));
    ck_assert(float_eq(value[4], value[0], 1e-10));
    ck_assert(float_eq(value[5], value[0], 1e-10));
    ck_assert(float_eq(value[6], value[0], 1e-10));
    ck_assert(float_eq(value[7], value[0], 1e-10));
    ck_assert(float_eq(value[8], value[2], 1e-10));
}
Exemple #4
0
static void
test_tree(freesasa_node *structure,
          const freesasa_result *result)
{
    freesasa_node *next, *chain, *residue, *atom;

    const freesasa_nodearea *area;
    ck_assert_ptr_ne((chain = freesasa_node_children(structure)), NULL);
    ck_assert_ptr_ne((residue = freesasa_node_children(chain)), NULL);
    ck_assert_ptr_ne((atom = freesasa_node_children(residue)), NULL);

    ck_assert_int_eq(freesasa_node_type(structure), FREESASA_NODE_STRUCTURE);
    ck_assert_int_eq(freesasa_node_type(chain), FREESASA_NODE_CHAIN);
    ck_assert_int_eq(freesasa_node_type(residue), FREESASA_NODE_RESIDUE);
    ck_assert_int_eq(freesasa_node_type(atom), FREESASA_NODE_ATOM);

    ck_assert_str_eq(freesasa_node_name(structure), "A");
    ck_assert_str_eq(freesasa_node_name(chain), "A");
    ck_assert_str_eq(freesasa_node_name(residue), "MET");
    ck_assert_str_eq(freesasa_node_name(atom), " N  ");

    ck_assert_int_eq(freesasa_node_structure_n_chains(structure), 1);
    ck_assert_int_eq(freesasa_node_structure_n_atoms(structure), 602);
    ck_assert_str_eq(freesasa_node_structure_chain_labels(structure), "A");

    ck_assert_int_eq(freesasa_node_chain_n_residues(chain), 76);

    // iterate
    next = freesasa_node_next(structure);
    ck_assert_ptr_eq(next, NULL);
    next = freesasa_node_next(chain);
    ck_assert_ptr_eq(next, NULL);
    next = freesasa_node_next(residue);
    ck_assert_ptr_ne(next, NULL);
    ck_assert_str_eq(freesasa_node_name(next), "GLN");
    next = freesasa_node_next(atom);
    ck_assert_str_eq(freesasa_node_name(next), " CA ");

    ck_assert_ptr_ne((area = freesasa_node_area(structure)), NULL);
    ck_assert(float_eq(result->total, area->total, 1e-10));
    ck_assert_ptr_ne((area = freesasa_node_area(chain)), NULL);
    ck_assert(float_eq(result->total, area->total, 1e-10));
    next = freesasa_node_next(residue);
    ck_assert_ptr_ne((area = freesasa_node_area(next)), NULL);
    ck_assert_ptr_ne((area = freesasa_node_area(atom)), NULL);
    ck_assert(float_eq(result->sasa[0], area->total, 1e-10));
    next = freesasa_node_next(atom);
    ck_assert_ptr_ne((area = freesasa_node_area(next)), NULL);
    ck_assert(float_eq(result->sasa[1], area->total, 1e-10));
}
Exemple #5
0
END_TEST

START_TEST (test_symbol)
{
    const char *commands[] = {"c1, symbol o+c",
                              "c2, symbol O",
                              "c3, symbol C",
                              "c4, symbol O AND symbol C",
                              "c5, symbol O OR symbol C",
                              "c6, symbol O+C+SE",
                              "c7, symbol SE",
                              "c8, symbol O+C+SE and not symbol se"};
    test_select(commands,8);
    ck_assert_str_eq(selection_name[0], "c1");
    ck_assert_str_eq(selection_name[1], "c2");
    ck_assert_str_eq(selection_name[2], "c3");
    ck_assert(value[0] > 5); //just to check that it's non-zero
    ck_assert(float_eq(value[0], addup(symb_O,result) + addup(symb_C,result), 1e-10));
    ck_assert(float_eq(value[1], addup(symb_O,result), 1e-10));
    ck_assert(float_eq(value[2], addup(symb_C,result), 1e-10));
    ck_assert(float_eq(value[3], 0, 1e-10));
    ck_assert(float_eq(value[4], value[0], 1e-10));
    ck_assert(float_eq(value[5], 
                       addup(symb_O,result) + addup(symb_C,result) + addup(symb_SE,result),
                       1e-10));
    ck_assert(float_eq(value[6], addup(symb_SE,result), 1e-10));
    ck_assert(float_eq(value[7], value[0], 1e-10));
}
Exemple #6
0
bool grid::node_point::operator<(const node_point& other) const {
	bool rc = false;
	for (integer d = 0; d != NDIM; ++d) {
		if (!float_eq(pt[d], other.pt[d])) {
			rc = (pt[d] < other.pt[d]);
			break;
		}
	}
	return rc;
}
Exemple #7
0
bool grid::xpoint_eq(const xpoint& a, const xpoint& b) {
	bool rc = true;
	for (integer d = 0; d != NDIM; ++d) {
		if (!float_eq(a[d], b[d])) {
			rc = false;
			break;
		}
	}
	return rc;
}
Exemple #8
0
  virtual double execute()
  {
	if (!m_con || !m_ef || !m_et)
	  return 0;
	
	double b = m_con->execute();
	if (float_eq(b, 0))
	  m_ef->execute();
	else
	  m_et->execute();
	return 0;
  }
Exemple #9
0
  virtual double execute()
  {
	if (!m_e1 || !m_e2)
	  return 0;
	  
    double num1 = m_e1->execute();
    double num2 = m_e2->execute();

    if (float_eq(num1, num2))
    {
      return 1;
    }
    return 0;
  }
Exemple #10
0
  virtual double execute()
  {
	if (!m_con || !m_e)
	  return 0;
	
    double ace = m_con->execute();

    while (!float_eq(ace, 0))
    {
      m_e->execute();
      ace = m_con->execute();
    }

    return 0;
  }
Exemple #11
0
void _eq(){
	struct atom *a, *b;

	b = u_pop_atom();
	a = u_pop_atom();

	if(a->type != b->type)
		error("Comparison: Numbers need to be of the same type.");
	
	if(a->type == FLOAT)
		float_eq(a,b);
	else
		int_eq(a,b);

}
Exemple #12
0
double calc_bdn_layer_free_conduct(double tair, double tleaf, double press,
                                   double leaf_width) {
    /*
        Boundary layer conductance for heat - single sided, free convection
        (mol m-2 s-1)
        See Leuning et al (1995) PC&E 18:1183-1200 Eqns E3 & E4
    */
    double cmolar, Tk, gbh, grashof, leaf_width_cubed;
    double tolerance = 1E-08;

    Tk = tair + DEG_TO_KELVIN;
    cmolar = press / (RGAS * Tk);
    leaf_width_cubed = leaf_width * leaf_width * leaf_width;

    if (float_eq((tleaf - tair), 0.0)) {
        gbh = 0.0;
    } else {
        grashof = 1.6E8 * fabs(tleaf - tair) * leaf_width_cubed;
        gbh = 0.5 * DHEAT * pow(grashof, 0.25) / leaf_width * cmolar;
    }

    return (gbh);
}
Exemple #13
0
END_TEST

START_TEST (test_chain)
{
    const char *commands[] = {"c1, chain A+B",
                              "c2, chain A",
                              "c3, chain B",
                              "c4, chain A AND chain B",
                              "c5, chain A OR chain B",
                              "c6, chain A-B",
                              "c7, chain A-B AND NOT chain A"};
    test_select(commands,7);
    ck_assert(value[0] > 5);
    ck_assert(float_eq(value[0], addup(chain_A,result) + addup(chain_B,result), 1e-10));
    ck_assert(float_eq(value[0], value[4], 1e-10));
    ck_assert(float_eq(value[0], value[5], 1e-10));
    ck_assert(float_eq(value[1], addup(chain_A,result), 1e-10));
    ck_assert(float_eq(value[2], addup(chain_B,result), 1e-10));
    ck_assert(float_eq(value[3], 0, 1e-10));
    ck_assert(float_eq(value[6], addup(chain_B,result), 1e-10));

}
Exemple #14
0
END_TEST

START_TEST (test_resn)
{
    const char *commands[] = {"c1, resn ala+arg",
                              "c2, resn ala",
                              "c3, resn arg",
                              "c4, resn ala AND resn arg",
                              "c5, resn ala OR  resn arg",
                              "c6, resn ala+arg AND NOT resn arg"};
    test_select(commands,6);
    ck_assert(value[0] > 5);
    ck_assert(float_eq(value[0], addup(resn_A,result) + addup(resn_R,result), 1e-10));
    ck_assert(float_eq(value[1], addup(resn_A,result), 1e-10));
    ck_assert(float_eq(value[2], addup(resn_R,result), 1e-10));
    ck_assert(float_eq(value[3], 0, 1e-10));
    ck_assert(float_eq(value[4], value[0], 1e-10));
    ck_assert(float_eq(value[5], value[1], 1e-10));
}
Exemple #15
0
void calc_carbon_allocation_fracs(control *c, fluxes *f, params *p, state *s,
                                  double nitfac) {
    /* Carbon allocation fractions to move photosynthate through the plant.

    Parameters:
    -----------
    nitfac : float
        leaf N:C as a fraction of 'Ncmaxfyoung' (max 1.0)

    Returns:
    --------
    alleaf : float
        allocation fraction for shoot
    alroot : float
        allocation fraction for fine roots
    albranch : float
        allocation fraction for branches
    alstem : float
        allocation fraction for stem

    References:
    -----------
    Corbeels, M. et al (2005) Ecological Modelling, 187, 449-474.
    McMurtrie, R. E. et al (2000) Plant and Soil, 224, 135-152.
    */
    double min_leaf_alloc, adj, arg1, arg2, arg3, arg4, leaf2sa_target,
           sap_cross_sec_area, lr_max, stress, mis_match, orig_af, orig_ar,
           reduction, target_branch, coarse_root_target, left_over,
           total_alloc, leaf2sap, spare;

    /* this is obviously arbitary */
    double min_stem_alloc = 0.01;

    if (c->alloc_model == FIXED){
        f->alleaf = (p->c_alloc_fmax + nitfac *
                     (p->c_alloc_fmax - p->c_alloc_fmin));

        f->alroot = (p->c_alloc_rmax + nitfac *
                     (p->c_alloc_rmax - p->c_alloc_rmin));

        f->albranch = (p->c_alloc_bmax + nitfac *
                       (p->c_alloc_bmax - p->c_alloc_bmin));

        /* allocate remainder to stem */
        f->alstem = 1.0 - f->alleaf - f->alroot - f->albranch;

        f->alcroot = p->c_alloc_cmax * f->alstem;
        f->alstem -= f->alcroot;

    } else if (c->alloc_model == GRASSES) {

        /* First figure out root allocation given available water & nutrients
           hyperbola shape to allocation */
        f->alroot = (p->c_alloc_rmax * p->c_alloc_rmin /
                     (p->c_alloc_rmin + (p->c_alloc_rmax - p->c_alloc_rmin) *
                      s->prev_sma));
        f->alleaf = 1.0 - f->alroot;

        /* Now adjust root & leaf allocation to maintain balance, accounting
           for stress e.g. -> Sitch et al. 2003, GCB. */

        /* leaf-to-root ratio under non-stressed conditons */
        lr_max = 0.8,

        /* Calculate adjustment on lr_max, based on current "stress"
           calculated from running mean of N and water stress */
        stress = lr_max * s->prev_sma;

        /* calculate new allocation fractions based on imbalance in *biomass* */
        mis_match = s->shoot / (s->root * stress);


        if (mis_match > 1.0) {
            /* reduce leaf allocation fraction */
            adj = f->alleaf / mis_match;
            f->alleaf = MAX(p->c_alloc_fmin, MIN(p->c_alloc_fmax, adj));
            f->alroot = 1.0 - f->alleaf;
        } else {
            /* reduce root allocation */
            adj = f->alroot * mis_match;
            f->alroot = MAX(p->c_alloc_rmin, MIN(p->c_alloc_rmax, adj));
            f->alleaf = 1.0 - f->alroot;
        }
        f->alstem = 0.0;
        f->albranch = 0.0;
        f->alcroot = 0.0;

    } else if (c->alloc_model == ALLOMETRIC) {

        /* Calculate tree height: allometric reln using the power function
           (Causton, 1985) */
        s->canht = p->heighto * pow(s->stem, p->htpower);

        /* LAI to stem sapwood cross-sectional area (As m-2 m-2)
           (dimensionless)
           Assume it varies between LS0 and LS1 as a linear function of tree
           height (m) */
        arg1 = s->sapwood * TONNES_AS_KG * M2_AS_HA;
        arg2 = s->canht * p->density * p->cfracts;
        sap_cross_sec_area = arg1 / arg2;
        leaf2sap = s->lai / sap_cross_sec_area;

        /* Allocation to leaves dependant on height. Modification of pipe
           theory, leaf-to-sapwood ratio is not constant above a certain
           height, due to hydraulic constraints (Magnani et al 2000; Deckmyn
           et al. 2006). */

        if (s->canht < p->height0) {
            leaf2sa_target = p->leafsap0;
        } else if (float_eq(s->canht, p->height1)) {
            leaf2sa_target = p->leafsap1;
        } else if (s->canht > p->height1) {
            leaf2sa_target = p->leafsap1;
        } else {
            arg1 = p->leafsap0;
            arg2 = p->leafsap1 - p->leafsap0;
            arg3 = s->canht - p->height0;
            arg4 = p->height1 - p->height0;
            leaf2sa_target = arg1 + (arg2 * arg3 / arg4);
        }
        f->alleaf = alloc_goal_seek(leaf2sap, leaf2sa_target, p->c_alloc_fmax,
                                    p->targ_sens);

        /* Allocation to branch dependent on relationship between the stem
           and branch */
        target_branch = p->branch0 * pow(s->stem, p->branch1);
        f->albranch = alloc_goal_seek(s->branch, target_branch, p->c_alloc_bmax,
                                      p->targ_sens);

        coarse_root_target = p->croot0 * pow(s->stem, p->croot1);
        f->alcroot = alloc_goal_seek(s->croot, coarse_root_target,
                                      p->c_alloc_cmax, p->targ_sens);



        /* figure out root allocation given available water & nutrients
           hyperbola shape to allocation, this is adjusted below as we aim
           to maintain a functional balance */

        f->alroot = (p->c_alloc_rmax * p->c_alloc_rmin /
                     (p->c_alloc_rmin + (p->c_alloc_rmax - p->c_alloc_rmin) *
                      s->prev_sma));

        /* Now adjust root & leaf allocation to maintain balance, accounting
           for stress e.g. -> Sitch et al. 2003, GCB. */

        /* leaf-to-root ratio under non-stressed conditons */
        lr_max = 1.0;

        /* Calculate adjustment on lr_max, based on current "stress"
           calculated from running mean of N and water stress */
        stress = lr_max * s->prev_sma;

        /* calculate imbalance, based on *biomass* */
        if (c->deciduous_model) {
            mis_match = s->shoot / (s->root * stress);
        } else {
            /* Catch for floating point reset of root C mass */
            if (float_eq(s->root, 0.0))
                mis_match = 1.9;
            else
                mis_match = s->shoot / (s->root * stress);
        }


        if (mis_match > 1.0) {
            /* Root=Leaf biomass in out of balance, borrow from the stem to try
               and alleviate this difference and move towards a functional
               balance. */
            spare = 1.0 - f->alleaf - f->albranch - f->alcroot - min_stem_alloc;
            adj = f->alroot * mis_match;
            f->alroot += MAX(p->c_alloc_rmin, MIN(spare, adj));
            f->alroot = MIN(p->c_alloc_rmax, f->alroot);

        } else if (mis_match < 1.0) {
            /* Root=Leaf biomass in out of balance, borrow from the root to try
               and alleviate this difference and move towards a functional
               balance */
            /* reduce root allocation */
            orig_ar = f->alroot;
            adj = f->alroot * mis_match;
            f->alroot = MAX(p->c_alloc_rmin, MIN(p->c_alloc_rmax, adj));
            reduction = MAX(0.0, orig_ar - f->alroot);
            f->alleaf += MAX(p->c_alloc_fmax, reduction);
        }


        /* Ensure we don't end up with alloc fractions that make no
           physical sense. */
        left_over = 1.0 - f->alroot - f->alleaf;
        if (f->albranch + f->alcroot > left_over) {
            if (float_eq(s->croot, 0.0)) {
                f->alcroot = 0.0;
                f->alstem = 0.5 * left_over;
                f->albranch = 0.5 * left_over;
            } else {
                f->alcroot = 0.3 * left_over;
                f->alstem = 0.4 * left_over;
                f->albranch = 0.3 * left_over;
            }
        }
        f->alstem = 1.0 - f->alroot - f->albranch - f->alleaf - f->alcroot;

        /* minimum allocation to leaves - without it tree would die, as this
           is done annually. */
        if (c->deciduous_model) {
            if (f->alleaf < 0.05) {
                min_leaf_alloc = 0.05;
                if (f->alstem > min_leaf_alloc)
                    f->alstem -= min_leaf_alloc;
                else
                    f->alroot -= min_leaf_alloc;
                f->alleaf = min_leaf_alloc;
            }
        }
    } else {
        fprintf(stderr, "Unknown C allocation model: %d\n", c->alloc_model);
        exit(EXIT_FAILURE);
    }

    /*printf("%f %f %f %f %f\n", f->alleaf, f->albranch + f->alstem, f->alroot,  f->alcroot, s->canht);*/

    /* Total allocation should be one, if not print warning */
    total_alloc = f->alroot + f->alleaf + f->albranch + f->alstem + f->alcroot;
    if (total_alloc > 1.0+EPSILON) {
        fprintf(stderr, "Allocation fracs > 1: %.13f\n", total_alloc);
        exit(EXIT_FAILURE);
    }

    return;
}
Exemple #16
0
int nitrogen_allocation(control *c, fluxes *f, params *p, state *s,
                        double ncbnew, double nccnew, double ncwimm,
                        double ncwnew, double fdecay, double rdecay, int doy) {
    /* Nitrogen distribution - allocate available N through system.
    N is first allocated to the woody component, surplus N is then allocated
    to the shoot and roots with flexible ratios.

    References:
    -----------
    McMurtrie, R. E. et al (2000) Plant and Soil, 224, 135-152.

    Parameters:
    -----------
    ncbnew : float
        N:C ratio of branch
    ncwimm : float
        N:C ratio of immobile stem
    ncwnew : float
        N:C ratio of mobile stem
    fdecay : float
        foliage decay rate
    rdecay : float
        fine root decay rate
    */

    int    recalc_wb;
    double nsupply, rtot, ntot, arg, lai_inc = 0.0, conv;
    double depth_guess = 1.0, total_req;

    /* default is we don't need to recalculate the water balance,
       however if we cut back on NPP due to available N below then we do
       need to do this */
    recalc_wb = FALSE;

    /* N retranslocated proportion from dying plant tissue and stored within
       the plant */
    f->retrans = nitrogen_retrans(c, f, p, s, fdecay, rdecay, doy);
    f->nuptake = calculate_nuptake(c, p, s);

    /*  Ross's Root Model. */
    if (c->model_optroot) {

        /* convert t ha-1 day-1 to gN m-2 year-1 */
        nsupply = (calculate_nuptake(c, p, s) *
                   TONNES_HA_2_G_M2 * DAYS_IN_YRS);

        /* covnert t ha-1 to kg DM m-2 */
        rtot = s->root * TONNES_HA_2_KG_M2 / p->cfracts;
        /*f->nuptake_old = f->nuptake; */

        calc_opt_root_depth(p->d0x, p->r0, p->topsoil_depth * MM_TO_M,
                            rtot, nsupply, depth_guess, &s->root_depth,
                            &f->nuptake, &f->rabove);

        /*umax = self.rm.calc_umax(f->nuptake) */

        /* covert nuptake from gN m-2 year-1  to t ha-1 day-1 */
        f->nuptake = f->nuptake * G_M2_2_TONNES_HA * YRS_IN_DAYS;

        /* covert from kg DM N m-2 to t ha-1 */
        f->deadroots = p->rdecay * f->rabove * p->cfracts * KG_M2_2_TONNES_HA;
        f->deadrootn = s->rootnc * (1.0 - p->rretrans) * f->deadroots;
    }

    /* Mineralised nitrogen lost from the system by volatilisation/leaching */
    f->nloss = p->rateloss * s->inorgn;

    /* total nitrogen to allocate */
    ntot = MAX(0.0, f->nuptake + f->retrans);

    if (c->deciduous_model) {
        /* allocate N to pools with fixed N:C ratios */

        /* N flux into new ring (immobile component -> structrual components) */
        f->npstemimm = f->wnimrate * s->growing_days[doy];

        /* N flux into new ring (mobile component -> can be retrans for new
           woody tissue) */
        f->npstemmob = f->wnmobrate * s->growing_days[doy];
        f->nproot = s->n_to_alloc_root / c->num_days;
        f->npcroot = f->cnrate * s->growing_days[doy];
        f->npleaf = f->lnrate * s->growing_days[doy];
        f->npbranch = f->bnrate * s->growing_days[doy];
    } else {
        /* allocate N to pools with fixed N:C ratios */

        /* N flux into new ring (immobile component -> structural components) */
        f->npstemimm = f->npp * f->alstem * ncwimm;

        /* N flux into new ring (mobile component -> can be retrans for new
           woody tissue) */
        f->npstemmob = f->npp * f->alstem * (ncwnew - ncwimm);
        f->npbranch = f->npp * f->albranch * ncbnew;
        f->npcroot = f->npp * f->alcroot * nccnew;

        /* If we have allocated more N than we have available
            - cut back C prodn */
        arg = f->npstemimm + f->npstemmob + f->npbranch + f->npcroot;


        if (arg > ntot && c->fixleafnc == FALSE && c->fixed_lai && c->ncycle) {


            /* Need to readjust the LAI for the reduced growth as this will
               have already been increased. First we need to figure out how
               much we have increased LAI by, important it is done here
               before cpleaf is reduced! */
            if (float_eq(s->shoot, 0.0)) {
                lai_inc = 0.0;
            } else {
                lai_inc = (f->cpleaf *
                           (p->sla * M2_AS_HA / (KG_AS_TONNES * p->cfracts)) -
                           (f->deadleaves + f->ceaten) * s->lai / s->shoot);
            }

            f->npp *= ntot / (f->npstemimm + f->npstemmob + \
                              f->npbranch + f->npcroot);

            /* need to adjust growth values accordingly as well */
            f->cpleaf = f->npp * f->alleaf;
            f->cproot = f->npp * f->alroot;
            f->cpcroot = f->npp * f->alcroot;
            f->cpbranch = f->npp * f->albranch;
            f->cpstem = f->npp * f->alstem;

            f->npbranch = f->npp * f->albranch * ncbnew;
            f->npstemimm = f->npp * f->alstem * ncwimm;
            f->npstemmob = f->npp * f->alstem * (ncwnew - ncwimm);
            f->npcroot = f->npp * f->alcroot * nccnew;

            /* Save WUE before cut back */
            f->wue = f->gpp_gCm2 / f->transpiration;

            /* Also need to recalculate GPP and thus Ra and return a flag
               so that we know to recalculate the water balance. */
            f->gpp = f->npp / p->cue;
            conv = G_AS_TONNES / M2_AS_HA;
            f->gpp_gCm2 = f->gpp / conv;
            f->gpp_am = f->gpp_gCm2 / 2.0;
            f->gpp_pm = f->gpp_gCm2 / 2.0;


            /* New respiration flux */
            f->auto_resp =  f->gpp - f->npp;
            recalc_wb = TRUE;

            /* Now reduce LAI for down-regulated growth. */
            if (c->deciduous_model) {
                if (float_eq(s->shoot, 0.0)) {
                    s->lai = 0.0;
                } else if (s->leaf_out_days[doy] > 0.0) {
                    s->lai -= lai_inc;
                    s->lai += (f->cpleaf *
                               (p->sla * M2_AS_HA / \
                               (KG_AS_TONNES * p->cfracts)) -
                               (f->deadleaves + f->ceaten) * s->lai / s->shoot);
                } else {
                    s->lai = 0.0;
                }
            } else {
                /* update leaf area [m2 m-2] */
                if (float_eq(s->shoot, 0.0)) {
                    s->lai = 0.0;
                } else {
                    s->lai -= lai_inc;
                    s->lai += (f->cpleaf *
                               (p->sla * M2_AS_HA / \
                               (KG_AS_TONNES * p->cfracts)) -
                               (f->deadleaves + f->ceaten) * s->lai / s->shoot);
                }
            }


        }

        ntot -= f->npbranch + f->npstemimm + f->npstemmob + f->npcroot;
        ntot = MAX(0.0, ntot);

        /* allocate remaining N to flexible-ratio pools */
        f->npleaf = ntot * f->alleaf / (f->alleaf + f->alroot * p->ncrfac);
        f->nproot = ntot - f->npleaf;
    }
    return (recalc_wb);
}
Exemple #17
0
void update_plant_state(control *c, fluxes *f, params *p, state *s,
                        double fdecay, double rdecay, int doy) {
    /*
    Daily change in C content

    Parameters:
    -----------
    fdecay : float
        foliage decay rate
    rdecay : float
        fine root decay rate

    */

    double age_effect, ncmaxf, ncmaxr, extras, extrar;

    /*
    ** Carbon pools
    */
    s->shoot += f->cpleaf - f->deadleaves - f->ceaten;
    s->root += f->cproot - f->deadroots;
    s->croot += f->cpcroot - f->deadcroots;
    s->branch += f->cpbranch - f->deadbranch;
    s->stem += f->cpstem - f->deadstems;

    /* annoying but can't see an easier way with the code as it is.
       If we are modelling grases, i.e. no stem them without this
       the sapwood will end up being reduced to a silly number as
       deadsapwood will keep being removed from the pool, even though there
       is no wood. */
    if (float_eq(s->stem, 0.01)) {
        s->sapwood = 0.01;
    } else if (s->stem < 0.01) {
        s->sapwood = 0.01;
    } else {
        s->sapwood += f->cpstem - f->deadsapwood;
    }


    /*
    ** Nitrogen pools
    */
    if (c->deciduous_model) {
        s->shootn += (f->npleaf - (f->lnrate * s->remaining_days[doy]) -
                      f->neaten);
    } else {
        s->shootn += f->npleaf - fdecay * s->shootn - f->neaten;
    }

    s->branchn += f->npbranch - p->bdecay * s->branchn;
    s->rootn += f->nproot - rdecay * s->rootn;
    s->crootn += f->npcroot - p->crdecay * s->crootn;
    s->stemnimm += f->npstemimm - p->wdecay * s->stemnimm;
    s->stemnmob += (f->npstemmob - p->wdecay * s->stemnmob - p->retransmob *
                    s->stemnmob);
    s->stemn = s->stemnimm + s->stemnmob;


    if (c->deciduous_model == FALSE) {
        /*
           =============================
            Enforce maximum N:C ratios.
           =============================
        */

        /* If foliage or root N/C exceeds its max, then N uptake is cut back*/

        /* maximum leaf n:c ratio is function of stand age
            - switch off age effect by setting ncmaxfyoung = ncmaxfold */
        age_effect = (s->age - p->ageyoung) / (p->ageold - p->ageyoung);
        ncmaxf = p->ncmaxfyoung - (p->ncmaxfyoung - p->ncmaxfold) * age_effect;

        if (ncmaxf < p->ncmaxfold)
            ncmaxf = p->ncmaxfold;

        if (ncmaxf > p->ncmaxfyoung)
            ncmaxf = p->ncmaxfyoung;

        extras = 0.0;
        if (s->lai > 0.0) {

            if (s->shootn > (s->shoot * ncmaxf)) {
                extras = s->shootn - s->shoot * ncmaxf;

                /* Ensure N uptake cannot be reduced below zero. */
                if (extras >  f->nuptake)
                    extras = f->nuptake;

                s->shootn -= extras;
                f->nuptake -= extras;
            }
        }

        /* if root N:C ratio exceeds its max, then nitrogen uptake is cut
           back. n.b. new ring n/c max is already set because it is related
           to leaf n:c */

        /* max root n:c */
        ncmaxr = ncmaxf * p->ncrfac;
        extrar = 0.0;
        if (s->rootn > (s->root * ncmaxr)) {
            extrar = s->rootn - s->root * ncmaxr;

            /* Ensure N uptake cannot be reduced below zero. */
            if ((extras + extrar) > f->nuptake)
                extrar = f->nuptake - extras;

            s->rootn -= extrar;
            f->nuptake -= extrar;
        }
    }
    /* Update deciduous storage pools */
    if (c->deciduous_model)
        calculate_cn_store(f, s);

    return;
}