def test_diet_intermediates(herb_class):
    """Scraps of the function calc_diet_intermediates."""
    diet = forage.Diet()
    diet.If = 10.
    diet.DMDf = 0.64
    diet.CPIf = 1.

    # copied from calc_diet_intermediates()
    supp = forage.Supplement(FreerParam.FreerParamCattle('indicus'), 0, 0, 0,
                             0, 0, 0)
    site = forage.SiteInfo(1, 0)
    diet_interm = forage.DietIntermediates()
    MEIf = (17.0 * diet.DMDf - 2) * diet.If  # eq 31: herbage
    MEIs = (13.3 * supp.DMD + 23.4 * supp.EE + 1.32) * diet.Is  # eq 32
    FMEIs = (13.3 * supp.DMD + 1.32) * diet.Is  # eq 32, supp.EE = 0
    MEItotal = MEIf + MEIs  # assuming no intake of milk
    M_per_Dforage = MEIf / diet.If
    kl = herb_class.FParam.CK5 + herb_class.FParam.CK6 * M_per_Dforage  # eq 34
    km = (herb_class.FParam.CK1 + herb_class.FParam.CK2 * M_per_Dforage
          )  # eq 33 efficiency of energy use for maintenance
    Emove = herb_class.FParam.CM16 * herb_class.D * herb_class.W
    Egraze = herb_class.FParam.CM6 * herb_class.W * diet.If * \
             (herb_class.FParam.CM7 - diet.DMDf) + Emove
    Emetab = herb_class.FParam.CM2 * herb_class.W**0.75 * max(
        math.exp(-herb_class.FParam.CM3 * herb_class.A), herb_class.FParam.CM4)
    # eq 41, energy req for maintenance:
    MEm = (Emetab + Egraze) / km + herb_class.FParam.CM1 * MEItotal
    if herb_class.sex == 'castrate' or herb_class.sex == 'entire_m':
        MEm = MEm * 1.15
    if herb_class.sex == 'herd_average':
        MEm = MEm * 1.055
    if herb_class.sex == 'NA':
        MEm = (MEm + MEm * 1.15) / 2
    diet_interm.L = (MEItotal / MEm) - 1.

    # new calculations to test --- copy any corrections from here
    A_foet = 30.  # assumed days since conception
    RA = A_foet / herb_class.FParam.CP1
    BW = (1 - herb_class.FParam.CP4 + herb_class.FParam.CP4 *
          herb_class.Z) * herb_class.FParam.CP15 * herb_class.SRW
    BC_foet = 1  # assume condition of foetus is 1, ignoring weight
    # assume she is pregnant with one foetus
    MEc_num1 = (herb_class.FParam.CP8 * (herb_class.FParam.CP5 * BW) * BC_foet)
    MEc_num2 = ((herb_class.FParam.CP9 * herb_class.FParam.CP10) /
                herb_class.FParam.CP1)
    MEc_num3 = math.exp(herb_class.FParam.CP10 * (1 - RA) +
                        herb_class.FParam.CP9 *
                        (1 - math.exp(herb_class.FParam.CP10 * (1 - RA))))
    MEc = (MEc_num1 * MEc_num2 * MEc_num3) / herb_class.FParam.CK8

    Pc_1 = herb_class.FParam.CP11 * (herb_class.FParam.CP5 * BW) * BC_foet
    Pc_2 = ((herb_class.FParam.CP12 * herb_class.FParam.CP13) /
            herb_class.FParam.CP1)
    Pc_3 = herb_class.FParam.CP13 * (1 - RA)
    Pc_4 = (herb_class.FParam.CP12 * (1 - math.exp(herb_class.FParam.CP13 *
                                                   (1 - RA))))
    Pc_5 = math.exp(Pc_3 + Pc_4)
    Pc = Pc_1 * Pc_2 * Pc_5
예제 #2
0
breed = 'Brahman'  # see documentation for allowable breeds; assumed to apply to all animal classes
sex = 'castrate'  # right now, we only deal with steers
A = 225.  # initial age (days)
W = 161.  # initial weight (Rubanza et al 2005)
herd_size = 1
DOY_start = 213
outdir = 'C:\Users\Ginger\Dropbox\NatCap_backup\Forage_model\Forage_model\Verification_calculations\Sensitivity\SRW'
time_step = 'day'
force_supp = False
forage.set_time_step(time_step)
steps = 10

FParam = FreerParam.FreerParam(forage.get_general_breed(breed))

available_forage = forage.calc_feed_types(grass_list)
supp = forage.Supplement(FParam, 0.643, 0, 8.87, 0.031, 0.181, 0.75)
supp_available = 0

SRW_list = np.linspace(400, 700, steps)
Wbirth_list = np.linspace(27, 48, steps)
test_list = [SRW_list, Wbirth_list]


def one_step(FParam,
             DOY,
             herd,
             available_forage,
             prop_legume,
             supp_available,
             supp,
             intake=None):
예제 #3
0
def different_diets(available_forage, herbivore_csv, weight_1):
    """Create different diets for two hypothetical animal types.  The weight
    ratio describes the ratio of """

    time_step = 'month'
    forage_u.set_time_step(time_step)
    total_SD = 2
    prop_legume = 0
    DOY = 100
    supp_available = 0
    site = forage_u.SiteInfo(1., -3.25)

    supp_csv = "C:/Users/Ginger/Dropbox/NatCap_backup/Forage_model/Forage_model/model_inputs/Shem_et_al_1995_supp.csv"
    supp_list = (pandas.read_csv(supp_csv)).to_dict(orient='records')
    supp_info = supp_list[0]
    supp = forage_u.Supplement(FreerParam.FreerParamCattle('indicus'),
                               supp_info['digestibility'],
                               supp_info['kg_per_day'], supp_info['M_per_d'],
                               supp_info['ether_extract'],
                               supp_info['crude_protein'],
                               supp_info['rumen_degradability'])
    herbivore_input = (pandas.read_csv(herbivore_csv)).to_dict(
        orient='records')
    herbivore_list = []
    for h_class in herbivore_input:
        herd = forage_u.HerbivoreClass(h_class)
        herd.update()
        herbivore_list.append(herd)

    avail_weights = [weight_1, 0]
    qual_weights = [0, weight_1]

    diet_dict = {}
    for idx in xrange(len(herbivore_list)):
        herb_class = herbivore_list[idx]
        f_w = avail_weights[idx]
        rq_w = qual_weights[idx]
        herb_class.calc_distance_walked(total_SD, site.S, available_forage)
        max_intake = herb_class.calc_max_intake()

        ZF = herb_class.calc_ZF()
        HR = forage_u.calc_relative_height(available_forage)
        diet = diet_selection_t2(ZF, HR, prop_legume, supp_available, supp,
                                 max_intake, herb_class.FParam,
                                 available_forage, idx, f_w, rq_w)
        diet_interm = forage_u.calc_diet_intermediates(diet, supp, herb_class,
                                                       site, prop_legume, DOY)
        # if herb_class.type != 'hindgut_fermenter':
        # reduced_max_intake = forage_u.check_max_intake(diet,
        # diet_interm,
        # herb_class,
        # max_intake)
        # if reduced_max_intake < max_intake:
        # diet = forage_u.diet_selection_t2(ZF, HR,
        # args[u'prop_legume'],
        # supp_available, supp,
        # reduced_max_intake,
        # herb_class.FParam,
        # available_forage)
        diet_dict[herb_class.label] = diet
    return diet_dict
    # forage_u.reduce_demand(diet_dict, stocking_density_dict,
    # available_forage)
    diet_interm = forage_u.calc_diet_intermediates(diet, supp, herb_class,
                                                   site, prop_legume, DOY)
    delta_W = forage_u.calc_delta_weight(diet_interm, herb_class)
    delta_W_step = forage_u.convert_daily_to_step(delta_W)
    herb_class.update(delta_weight=delta_W_step,
                      delta_time=forage_u.find_days_per_step())
예제 #4
0
def run_test():
    SRW_list = np.linspace(160, 600, 9).tolist()
    total_SD = 1.
    site = forage.SiteInfo(1., -3.25)
    prop_legume = 0.0
    supp_available = 0
    breed = 'Ayrshire'
    sex = 'entire_m'
    herd_size = 1
    DOY_start = 1
    outdir = r'C:/Users/Ginger/Dropbox/NatCap_backup/Forage_model/Forage_model/Verification_calculations/Shem_et_al_1995/revisions_10_12/summary_unsupplemented'
    if not os.path.exists(outdir):
        os.makedirs(outdir)
    time_step = 'day'
    forage.set_time_step(time_step)
    supp_csv = "C:/Users/Ginger/Dropbox/NatCap_backup/Forage_model/Forage_model/model_inputs/Shem_et_al_1995_supp.csv"
    herbivore_csv = "C:/Users/Ginger/Dropbox/NatCap_backup/Forage_model/Forage_model/model_inputs/herbivore_Shem_et_al.csv"
    grass_csv = "C:/Users/Ginger/Dropbox/NatCap_backup/Forage_model/Forage_model/model_inputs/grasses_Shem_et_al_1995.csv"
    grass_list = (pandas.read_csv(grass_csv)).to_dict(orient='records')
    out_name = os.path.join(outdir, "summary.csv")

    supp_list = (pandas.read_csv(supp_csv)).to_dict(orient='records')
    supp_info = supp_list[0]
    supp = forage.Supplement(FreerParam.FreerParamCattle('indicus_x_taurus'),
                             supp_info['digestibility'],
                             supp_info['kg_per_day'], supp_info['M_per_d'],
                             supp_info['ether_extract'],
                             supp_info['crude_protein'],
                             supp_info['rumen_degradability'])
    if supp.DMO > 0.:
        supp_available = 1
    supp_available = 0  # change to allow supplementation
    with open(out_name, 'wb') as out:
        writer = csv.writer(out, delimiter=',')
        header = ['red_max_intake', 'max_intake', 'intake_forage',
                  'intake_supp', 'daily_gain', 'grass_label',
                  'step', 'study', 'SRW']
        writer.writerow(header)
        for SRW in SRW_list:
            modify_SRW(herbivore_csv, SRW)
            herbivore_input = (pandas.read_csv(herbivore_csv)).to_dict(orient='records')
            for grass in grass_list:
                one_grass = [grass]
                available_forage = forage.calc_feed_types(one_grass)
                herbivore_list = []
                for h_class in herbivore_input:
                    herd = forage.HerbivoreClass(h_class)
                    herd.update()
                    herbivore_list.append(herd)
                    print "beginning weight: " + str(herd.W)
                    print "beginning BC: " + str(herd.BC)
                    print "SRW: " + str(herd.SRW)
                for step in xrange(60):
                    DOY = DOY_start + step
                    row = forage.one_step(site, DOY, herd,
                                          available_forage, prop_legume,
                                          supp_available, supp)
                    row.append(grass['label'])
                    row.append(step)
                    row.append('Schem_et_al')
                    row.append(SRW)
                    writer.writerow(row)
def launch_model(herb_csv, grass_list, outdir):
    f_args = {
        'latitude': 0.02759,
        'prop_legume': 0.0,
        'steepness': 1.,
        'DOY': 1,
        'start_year': 2015,
        'start_month': 1,
        'num_months': 1,
        'mgmt_threshold': 0.,
        'century_dir':
        'C:/Users/Ginger/Dropbox/NatCap_backup/Forage_model/CENTURY4.6/Century46_PC_Jan-2014',
        'outdir': outdir,
        'template_level': 'GH',
        'fix_file': 'drytrpfi.100',
        'user_define_protein': 1,
        'user_define_digestibility': 0,
        'herbivore_csv': herb_csv,
        'supp_csv':
        "C:/Users/Ginger/Dropbox/NatCap_backup/Forage_model/Forage_model/model_inputs/Rubanza_et_al_2005_supp.csv",
        'restart_yearly': 0,
        'diet_verbose': 1,
    }
    now_str = datetime.now().strftime("%Y-%m-%d--%H_%M_%S")
    if not os.path.exists(f_args['outdir']):
        os.makedirs(f_args['outdir'])
    forage.write_inputs_log(f_args, now_str)
    forage.set_time_step('month')  # current default, enforced by CENTURY
    add_event = 1  # TODO should this ever be 0?
    steps_per_year = forage.find_steps_per_year()
    if f_args['diet_verbose']:
        master_diet_dict = {}
        diet_segregation_dict = {'step': [], 'segregation': []}
    herbivore_list = []
    if f_args[u'herbivore_csv'] is not None:
        herbivore_input = (pandas.read_csv(
            f_args[u'herbivore_csv'])).to_dict(orient='records')
        for h_class in herbivore_input:
            herd = forage.HerbivoreClass(h_class)
            herd.update()
            BC = 1  # TODO get optional BC from user
            # if BC:
            # herd.check_BC(BC)

            herbivore_list.append(herd)
    results_dict = {'step': [], 'year': [], 'month': []}
    for h_class in herbivore_list:
        results_dict[h_class.label + '_kg'] = []
        results_dict[h_class.label + '_gain_kg'] = []
        results_dict[h_class.label + '_intake_forage_per_indiv_kg'] = []
        if h_class.sex == 'lac_female':
            results_dict['milk_prod_kg'] = []
    results_dict['total_offtake'] = []
    supp_available = 0
    if 'supp_csv' in f_args.keys():
        supp_list = (pandas.read_csv(
            f_args[u'supp_csv'])).to_dict(orient='records')
        assert len(supp_list) == 1, "Only one supplement type is allowed"
        supp_info = supp_list[0]
        supp = forage.Supplement(FreerParam.FreerParamCattle('indicus'),
                                 supp_info['digestibility'],
                                 supp_info['kg_per_day'], supp_info['M_per_d'],
                                 supp_info['ether_extract'],
                                 supp_info['crude_protein'],
                                 supp_info['rumen_degradability'])
        if supp.DMO > 0.:
            supp_available = 1

    stocking_density_dict = forage.populate_sd_dict(herbivore_list)
    total_SD = forage.calc_total_stocking_density(herbivore_list)
    site = forage.SiteInfo(f_args[u'steepness'], f_args[u'latitude'])
    threshold_exceeded = 0
    try:
        for step in xrange(f_args[u'num_months']):
            step_month = f_args[u'start_month'] + step
            if step_month > 12:
                mod = step_month % 12
                if mod == 0:
                    month = 12
                else:
                    month = mod
            else:
                month = step_month
            year = (step / 12) + f_args[u'start_year']
            if month == 1 and f_args['restart_yearly'] and \
                                            f_args[u'herbivore_csv'] is not None:
                threshold_exceeded = 0
                herbivore_list = []
                for h_class in herbivore_input:
                    herd = forage.HerbivoreClass(h_class)
                    herd.update()
                    herbivore_list.append(herd)
            # get biomass and crude protein for each grass type
            available_forage = forage.calc_feed_types(grass_list)
            results_dict['step'].append(step)
            results_dict['year'].append(year)
            results_dict['month'].append(month)
            if not f_args[u'user_define_digestibility']:
                for feed_type in available_forage:
                    feed_type.calc_digestibility_from_protein()
            total_biomass = forage.calc_total_biomass(available_forage)
            if step == 0:
                # threshold biomass, amount of biomass required to be left
                # standing (kg per ha)
                threshold_biomass = total_biomass * float(
                    f_args[u'mgmt_threshold'])
            diet_dict = {}
            for herb_class in herbivore_list:
                herb_class.calc_distance_walked(total_SD, site.S,
                                                available_forage)
                max_intake = herb_class.calc_max_intake()

                ZF = herb_class.calc_ZF()
                HR = forage.calc_relative_height(available_forage)
                diet = forage.diet_selection_t2(ZF, HR, f_args[u'prop_legume'],
                                                supp_available, supp,
                                                max_intake, herb_class.FParam,
                                                available_forage,
                                                herb_class.f_w, herb_class.q_w)
                diet_interm = forage.calc_diet_intermediates(
                    diet, supp, herb_class, site, f_args[u'prop_legume'],
                    f_args[u'DOY'])
                if herb_class.type != 'hindgut_fermenter':
                    reduced_max_intake = forage.check_max_intake(
                        diet, diet_interm, herb_class, max_intake)
                    if reduced_max_intake < max_intake:
                        diet = forage.diet_selection_t2(
                            ZF, HR, f_args[u'prop_legume'], supp_available,
                            supp, reduced_max_intake, herb_class.FParam,
                            available_forage)
                diet_dict[herb_class.label] = diet
            forage.reduce_demand(diet_dict, stocking_density_dict,
                                 available_forage)
            if f_args['diet_verbose']:
                # save diet_dict across steps to be written out later
                master_diet_dict[step] = diet_dict
                # diet_segregation = forage.calc_diet_segregation(diet_dict)
                # diet_segregation_dict['step'].append(step)
                # diet_segregation_dict['segregation'].append(diet_segregation)
            total_intake_step = forage.calc_total_intake(
                diet_dict, stocking_density_dict)
            if (total_biomass - total_intake_step) < threshold_biomass:
                print "Forage consumed violates management threshold"
                threshold_exceeded = 1
                total_intake_step = 0
            for herb_class in herbivore_list:
                if threshold_exceeded:
                    diet_dict[herb_class.label] = forage.Diet()
                diet = diet_dict[herb_class.label]
                # if herb_class.type != 'hindgut_fermenter':
                diet_interm = forage.calc_diet_intermediates(
                    diet, supp, herb_class, site, f_args[u'prop_legume'],
                    f_args[u'DOY'])
                if herb_class.sex == 'lac_female':
                    milk_production = forage.check_milk_production(
                        herb_class.FParam, diet_interm)
                    milk_kg_day = herb_class.calc_milk_yield(milk_production)
                if threshold_exceeded:
                    delta_W = -(forage.convert_step_to_daily(herb_class.W))
                else:
                    delta_W = forage.calc_delta_weight(diet_interm, herb_class)
                delta_W_step = forage.convert_daily_to_step(delta_W)
                herb_class.update(delta_weight=delta_W_step,
                                  delta_time=forage.find_days_per_step())

                results_dict[herb_class.label + '_kg'].append(herb_class.W)
                results_dict[herb_class.label +
                             '_gain_kg'].append(delta_W_step)
                results_dict[herb_class.label +
                             '_intake_forage_per_indiv_kg'].append(
                                 forage.convert_daily_to_step(diet.If))
                if herb_class.sex == 'lac_female':
                    results_dict['milk_prod_kg'].append(
                        forage.convert_daily_to_step(milk_kg_day))
            results_dict['total_offtake'].append(total_intake_step)
    finally:
        if f_args['diet_verbose']:
            # df = pandas.DataFrame(diet_segregation_dict)
            # save_as = os.path.join(f_args['outdir'], 'diet_segregation.csv')
            # df.to_csv(save_as, index=False)
            for h_label in master_diet_dict[0].keys():
                new_dict = {}
                new_dict['step'] = master_diet_dict.keys()
                new_dict['DMDf'] = [
                    master_diet_dict[step][h_label].DMDf
                    for step in master_diet_dict.keys()
                ]
                new_dict['CPIf'] = [
                    master_diet_dict[step][h_label].CPIf
                    for step in master_diet_dict.keys()
                ]
                grass_labels = master_diet_dict[0][h_label].intake.keys()
                for g_label in grass_labels:
                    new_dict['intake_' + g_label] = \
                          [master_diet_dict[step][h_label].intake[g_label] for
                           step in master_diet_dict.keys()]
                df = pandas.DataFrame(new_dict)
                save_as = os.path.join(f_args['outdir'], h_label + '_diet.csv')
                df.to_csv(save_as, index=False)
        filled_dict = forage.fill_dict(results_dict, 'NA')
        df = pandas.DataFrame(filled_dict)
        df.to_csv(os.path.join(f_args['outdir'], 'summary_results.csv'))
예제 #6
0
def run_simulations():
    century_dir = 'C:/Users/Ginger/Dropbox/NatCap_backup/Forage_model/CENTURY4.6/Century46_PC_Jan-2014'
    fix_file = 'drytrpfi.100'
    graz_file = os.path.join(century_dir, "graz.100")
    site_list = ['Research', 'Loidien']  #, 'Rongai', 'Kamok']
    input_dir = "C:/Users/Ginger/Dropbox/NatCap_backup/Forage_model/CENTURY4.6/Kenya/input"
    outer_dir = "C:/Users/Ginger/Dropbox/NatCap_backup/Forage_model/CENTURY4.6/Output/Stocking_density_test"
    prop_legume = 0
    template_level = 'GL'
    herb_class_weights = "C:/Users/Ginger/Dropbox/NatCap_backup/Forage_model/CENTURY4.6/Kenya/Boran_weights.csv"
    sd_dir = 'C:/Users/Ginger/Dropbox/NatCap_backup/Forage_model/CENTURY4.6/Kenya/OPC_stocking_density'
    breed = 'Boran'
    steepness = 1.
    latitude = 0
    supp_available = 0
    FParam = FreerParam.FreerParam(forage.get_general_breed(breed))
    supp = forage.Supplement(FParam, 0, 0, 0, 0, 0, 0)
    forage.set_time_step('month')
    add_event = 1

    grass_file = "C:/Users/ginge/Dropbox/NatCap_backup/Forage_model/Forage_model/model_inputs/grass.csv"
    grass = (pandas.read_csv(grass_file)).to_dict(orient='records')[0]
    grass['DMD_green'] = 0.64
    grass['DMD_dead'] = 0.64
    grass['cprotein_green'] = 0.1
    grass['cprotein_dead'] = 0.1

    for site in site_list:
        spin_up_outputs = [site + '_hist_log.txt', site + '_hist.lis']
        century_outputs = [site + '_log.txt', site + '.lis', site + '.bin']
        filename = 'average_animals_%s_2km_per_ha.csv' % site
        stocking_density_file = os.path.join(sd_dir, filename)
        sd_df = pandas.read_table(stocking_density_file, sep=',')

        outdir = os.path.join(outer_dir, site)
        if not os.path.exists(outdir):
            os.makedirs(outdir)
        # write CENTURY bat for spin-up simulation
        hist_bat = os.path.join(input_dir, (site + '_hist.bat'))
        hist_schedule = site + '_hist.sch'
        hist_output = site + '_hist'
        cent.write_century_bat(input_dir, hist_bat, hist_schedule, hist_output,
                               fix_file, 'outvars.txt')
        # write CENTURY bat for extend simulation
        extend_bat = os.path.join(input_dir, site + '.bat')
        schedule = site + '.sch'
        output = site
        extend = site + '_hist'
        cent.write_century_bat(century_dir, extend_bat, schedule, output,
                               fix_file, 'outvars.txt', extend)
        # move CENTURY run files to CENTURY dir
        site_file = os.path.join(input_dir, site + '.100')
        weather_file = os.path.join(input_dir, site + '.wth')
        e_schedule = os.path.join(input_dir, site + '.sch')
        h_schedule = os.path.join(input_dir, site + '_hist.sch')
        file_list = [
            hist_bat, extend_bat, e_schedule, h_schedule, site_file,
            weather_file
        ]
        for file in file_list:
            shutil.copyfile(file,
                            os.path.join(century_dir, os.path.basename(file)))

        # make a copy of the original graz params and schedule file
        shutil.copyfile(graz_file, os.path.join(century_dir, 'graz_orig.100'))
        label = os.path.basename(e_schedule)[:-4]
        copy_name = label + '_orig.sch'
        shutil.copyfile(e_schedule, os.path.join(input_dir, copy_name))

        # run CENTURY for spin-up up to start_year and start_month
        hist_bat = os.path.join(century_dir, site + '_hist.bat')
        century_bat = os.path.join(century_dir, site + '.bat')
        p = Popen(["cmd.exe", "/c " + hist_bat], cwd=century_dir)
        stdout, stderr = p.communicate()
        p = Popen(["cmd.exe", "/c " + century_bat], cwd=century_dir)
        stdout, stderr = p.communicate()

        # save copies of CENTURY outputs, but remove from CENTURY dir
        intermediate_dir = os.path.join(outdir, 'CENTURY_outputs_spin_up')
        if not os.path.exists(intermediate_dir):
            os.makedirs(intermediate_dir)
        to_move = century_outputs + spin_up_outputs
        for file in to_move:
            shutil.copyfile(os.path.join(century_dir, file),
                            os.path.join(intermediate_dir, file))
            os.remove(os.path.join(century_dir, file))

        grass_list = [grass]
        results_dict = {'year': [], 'month': []}
        herbivore_input = (pandas.read_csv(herb_class_weights).to_dict(
            orient='records'))
        herbivore_list = []
        for h_class in herbivore_input:
            results_dict[h_class['label'] + '_gain_kg'] = []
            results_dict[h_class['label'] + '_offtake'] = []
        results_dict['milk_prod_kg'] = []
        for grass in grass_list:
            results_dict[grass['label'] + '_green_kgha'] = []
            results_dict[grass['label'] + '_dead_kgha'] = []
        results_dict['total_offtake'] = []
        results_dict['stocking_density'] = []
        try:
            for row in xrange(len(sd_df)):
                herbivore_list = []
                for h_class in herbivore_input:
                    herd = forage.HerbivoreClass(FParam,
                                                 breed,
                                                 h_class['weight'],
                                                 h_class['sex'],
                                                 h_class['age'],
                                                 h_class['stocking_density'],
                                                 h_class['label'],
                                                 Wbirth=24)
                    herd.update(FParam, 0, 0)
                    herbivore_list.append(herd)
                for h_class in herbivore_list:
                    h_class.stocking_density = sd_df.iloc[row][h_class.label]
                total_SD = forage.calc_total_stocking_density(herbivore_list)
                results_dict['stocking_density'].append(total_SD)
                siteinfo = forage.SiteInfo(total_SD, steepness, latitude)
                month = sd_df.iloc[row].month
                year = sd_df.iloc[row].year
                suf = '%d-%d' % (month, year)
                DOY = month * 30
                # get biomass and crude protein for each grass type from CENTURY
                output_file = os.path.join(intermediate_dir, site + '.lis')
                outputs = cent.read_CENTURY_outputs(output_file, year,
                                                    year + 2)
                target_month = cent.find_prev_month(year, month)
                grass['prev_g_gm2'] = grass['green_gm2']
                grass['prev_d_gm2'] = grass['dead_gm2']
                grass['green_gm2'] = outputs.loc[target_month, 'aglivc']
                grass['dead_gm2'] = outputs.loc[target_month, 'stdedc']
                grass['cprotein_green'] = (
                    outputs.loc[target_month, 'aglive1'] /
                    outputs.loc[target_month, 'aglivc'])
                grass['cprotein_dead'] = (
                    outputs.loc[target_month, 'stdede1'] /
                    outputs.loc[target_month, 'stdedc'])
                if row == 0:
                    available_forage = forage.calc_feed_types(grass_list)
                else:
                    available_forage = forage.update_feed_types(
                        grass_list, available_forage)
                results_dict['year'].append(year)
                results_dict['month'].append(month)
                for feed_type in available_forage:
                    results_dict[feed_type.label + '_' +
                                 feed_type.green_or_dead + '_kgha'].append(
                                     feed_type.biomass)

                siteinfo.calc_distance_walked(FParam, available_forage)
                for feed_type in available_forage:
                    feed_type.calc_digestibility_from_protein()
                total_biomass = forage.calc_total_biomass(available_forage)
                # Initialize containers to track forage consumed across herbivore
                # classes
                total_intake_step = 0.
                total_consumed = {}
                for feed_type in available_forage:
                    label_string = ';'.join(
                        [feed_type.label, feed_type.green_or_dead])
                    total_consumed[label_string] = 0.

                for herb_class in herbivore_list:
                    max_intake = herb_class.calc_max_intake(FParam)
                    if herb_class.Z < FParam.CR7:
                        ZF = 1. + (FParam.CR7 - herb_class.Z)
                    else:
                        ZF = 1.
                    if herb_class.stocking_density > 0:
                        adj_forage = forage.calc_adj_availability(
                            available_forage, herb_class.stocking_density)
                    else:
                        adj_forage = list(available_forage)
                    diet = forage.diet_selection_t2(ZF, prop_legume,
                                                    supp_available, supp,
                                                    max_intake, FParam,
                                                    adj_forage)
                    diet_interm = forage.calc_diet_intermediates(
                        FParam, diet, supp, herb_class, siteinfo, prop_legume,
                        DOY)
                    reduced_max_intake = forage.check_max_intake(
                        FParam, diet, diet_interm, herb_class, max_intake)
                    if reduced_max_intake < max_intake:
                        diet = forage.diet_selection_t2(
                            ZF, prop_legume, supp_available, supp,
                            reduced_max_intake, FParam, adj_forage)
                        diet_interm = forage.calc_diet_intermediates(
                            FParam, diet, supp, herb_class, siteinfo,
                            prop_legume, DOY)
                    total_intake_step += (
                        forage.convert_daily_to_step(diet.If) *
                        herb_class.stocking_density)
                    if herb_class.sex == 'lac_female':
                        milk_production = forage.check_milk_production(
                            FParam, diet_interm)
                        milk_kg_day = forage.calc_milk_yield(
                            FParam, milk_production)
                    delta_W = forage.calc_delta_weight(FParam, diet,
                                                       diet_interm, supp,
                                                       herb_class)
                    delta_W_step = forage.convert_daily_to_step(delta_W)
                    herb_class.update(FParam, delta_W_step,
                                      forage.find_days_per_step())
                    if herb_class.stocking_density > 0:
                        results_dict[herb_class.label +
                                     '_gain_kg'].append(delta_W_step)
                        results_dict[herb_class.label + '_offtake'].append(
                            diet.If)
                    else:
                        results_dict[herb_class.label +
                                     '_gain_kg'].append('NA')
                        results_dict[herb_class.label +
                                     '_offtake'].append('NA')
                    if herb_class.sex == 'lac_female':
                        results_dict['milk_prod_kg'].append(milk_kg_day * 30.)

                    # after have performed max intake check, we have the final diet
                    # selected
                    # calculate percent live and dead removed for each grass type
                    consumed_by_class = forage.calc_percent_consumed(
                        available_forage, diet, herb_class.stocking_density)
                    forage.sum_percent_consumed(total_consumed,
                                                consumed_by_class)

                results_dict['total_offtake'].append(total_intake_step)
                # send to CENTURY for this month's scheduled grazing event
                date = year + float('%.2f' % (month / 12.))
                schedule = os.path.join(century_dir, site + '.sch')
                target_dict = cent.find_target_month(add_event, schedule, date,
                                                     1)
                if target_dict == 0:
                    er = "Error: no opportunities exist to add grazing event"
                    raise Exception(er)
                new_code = cent.add_new_graz_level(grass, total_consumed,
                                                   graz_file, template_level,
                                                   outdir, suf)
                cent.modify_schedule(schedule, add_event, target_dict,
                                     new_code, outdir, suf)

                # call CENTURY from the batch file
                century_bat = os.path.join(century_dir, site + '.bat')
                p = Popen(["cmd.exe", "/c " + century_bat], cwd=century_dir)
                stdout, stderr = p.communicate()
                # save copies of CENTURY outputs, but remove from CENTURY dir
                intermediate_dir = os.path.join(
                    outdir, 'CENTURY_outputs_m%d_y%d' % (month, year))
                if not os.path.exists(intermediate_dir):
                    os.makedirs(intermediate_dir)
                for file in century_outputs:
                    shutil.copyfile(os.path.join(century_dir, file),
                                    os.path.join(intermediate_dir, file))
                    os.remove(os.path.join(century_dir, file))

        # remove files from CENTURY directory
        finally:
            # replace graz params used by CENTURY with original file
            os.remove(graz_file)
            shutil.copyfile(os.path.join(century_dir, 'graz_orig.100'),
                            graz_file)
            os.remove(os.path.join(century_dir, 'graz_orig.100'))
            files_to_remove = [
                os.path.join(century_dir, os.path.basename(f))
                for f in file_list
            ]
            for file in files_to_remove:
                os.remove(file)
            os.remove(os.path.join(century_dir, site + '_hist.bin'))
            filled_dict = forage.fill_dict(results_dict, 'NA')
            df = pandas.DataFrame(filled_dict)
            df.to_csv(os.path.join(outdir, 'summary_results.csv'))
force_supp = False
forage.set_time_step(time_step)

available_forage = forage.calc_feed_types(grass_list)

# different levels of supplement (kg per day) offered to experimental groups
supp_kg_list = [0, 0.4, 0.6, 0.8]
initial_weight_list = [162., 151., 164., 164.]

# forage intake published by Rubanza
intake_list = [3.1, 3.45, 3.72, 3.82]
supp_list = []
herd_list = []
for supp_index in xrange(4):
    supp = forage.Supplement(FreerParam.FreerParamCattle('indicus'), 0.643,
                             supp_kg_list[supp_index], 8.87, 0.031, 0.181,
                             0.75)
    supp_list.append(supp)
    herd = forage.HerbivoreClass('B_indicus',
                                 initial_weight_list[supp_index],
                                 sex,
                                 A,
                                 1,
                                 SRW,
                                 Wbirth=Wbirth)
    herd.update()
    herd_list.append(herd)


def one_step(site,
             DOY,