Exemplo n.º 1
0
def test_simulation_run(overwrite_desired_data=False):
    """Test the run of a simulation, without interpolation of the forcings."""

    TEST_DIR_PATH = 'simulation_run'

    # Inputs of the test
    INPUTS_DIRPATH = os.path.join(TEST_DIR_PATH, 'inputs')
    ORGANS_INITIAL_STATE_FILENAME = 'organs_initial_state.csv'
    HIDDENZONES_INITIAL_STATE_FILENAME = 'hiddenzones_initial_state.csv'
    ELEMENTS_INITIAL_STATE_FILENAME = 'elements_initial_state.csv'
    SOILS_INITIAL_STATE_FILENAME = 'soils_initial_state.csv'
    ELEMENTS_PHOTOSYNTHESIS_FORCINGS_FILENAME = 'elements_photosynthesis_forcings.csv'
    ROOTS_SENESCENCE_FORCINGS_FILENAME = 'roots_senescence_forcings.csv'
    ELEMENTS_SENESCENCE_FORCINGS_FILENAME = 'elements_senescence_forcings.csv'

    # Outputs of the test
    OUTPUTS_DIRPATH = os.path.join(TEST_DIR_PATH, 'outputs')
    DESIRED_AXES_OUTPUTS_FILENAME = 'desired_axes_outputs.csv'
    DESIRED_ORGANS_OUTPUTS_FILENAME = 'desired_organs_outputs.csv'
    DESIRED_HIDDENZONES_OUTPUTS_FILENAME = 'desired_hiddenzones_outputs.csv'
    DESIRED_ELEMENTS_OUTPUTS_FILENAME = 'desired_elements_outputs.csv'
    DESIRED_SOILS_OUTPUTS_FILENAME = 'desired_soils_outputs.csv'
    ACTUAL_AXES_OUTPUTS_FILENAME = 'actual_axes_outputs.csv'
    ACTUAL_ORGANS_OUTPUTS_FILENAME = 'actual_organs_outputs.csv'
    ACTUAL_HIDDENZONES_OUTPUTS_FILENAME = 'actual_hiddenzones_outputs.csv'
    ACTUAL_ELEMENTS_OUTPUTS_FILENAME = 'actual_elements_outputs.csv'
    ACTUAL_SOILS_OUTPUTS_FILENAME = 'actual_soils_outputs.csv'

    # Simulation parameters
    START_TIME = 0
    SIMULATION_LENGTH = 48
    TIME_STEP = 1
    CULM_DENSITY = {1: 410}

    time_step_seconds = TIME_STEP * HOUR_TO_SECOND_CONVERSION_FACTOR

    # Read the inputs from CSV files and create inputs dataframes
    inputs_dataframes = {}
    for inputs_filename in (ORGANS_INITIAL_STATE_FILENAME,
                            HIDDENZONES_INITIAL_STATE_FILENAME,
                            ELEMENTS_INITIAL_STATE_FILENAME,
                            SOILS_INITIAL_STATE_FILENAME):
        inputs_dataframes[inputs_filename] = pd.read_csv(
            os.path.join(INPUTS_DIRPATH, inputs_filename))

    # Convert the inputs dataframes to a population of plants and a dictionary of soils
    population, soils = cnwheat_converter.from_dataframes(
        inputs_dataframes[ORGANS_INITIAL_STATE_FILENAME],
        inputs_dataframes[HIDDENZONES_INITIAL_STATE_FILENAME],
        inputs_dataframes[ELEMENTS_INITIAL_STATE_FILENAME],
        inputs_dataframes[SOILS_INITIAL_STATE_FILENAME])

    # Create the simulation
    simulation_ = cnwheat_simulation.Simulation(
        respiration_model=respiwheat_model,
        delta_t=time_step_seconds,
        culm_density=CULM_DENSITY)

    # Initialize the simulation from the population of plants and the dictionary of soils created previously
    simulation_.initialize(population, soils)

    # Read photosynthesis and senescence forcings from CSV files, create dataframes, and group the dataframes by object index
    photosynthesis_elements_data_filepath = os.path.join(
        INPUTS_DIRPATH, ELEMENTS_PHOTOSYNTHESIS_FORCINGS_FILENAME)
    photosynthesis_elements_data_df = pd.read_csv(
        photosynthesis_elements_data_filepath)
    photosynthesis_elements_data_grouped = photosynthesis_elements_data_df.groupby(
        cnwheat_simulation.Simulation.ELEMENTS_T_INDEXES)
    senescence_roots_data_filepath = os.path.join(
        INPUTS_DIRPATH, ROOTS_SENESCENCE_FORCINGS_FILENAME)
    senescence_roots_data_df = pd.read_csv(senescence_roots_data_filepath)
    senescence_roots_data_grouped = senescence_roots_data_df.groupby(
        cnwheat_simulation.Simulation.AXES_T_INDEXES)
    senescence_elements_data_filepath = os.path.join(
        INPUTS_DIRPATH, ELEMENTS_SENESCENCE_FORCINGS_FILENAME)
    senescence_elements_data_df = pd.read_csv(
        senescence_elements_data_filepath)
    senescence_elements_data_grouped = senescence_elements_data_df.groupby(
        cnwheat_simulation.Simulation.ELEMENTS_T_INDEXES)

    # Force the senescence and photosynthesis of the population
    force_senescence_and_photosynthesis(0, population,
                                        senescence_roots_data_grouped,
                                        senescence_elements_data_grouped,
                                        photosynthesis_elements_data_grouped)

    # Reinitialize the simulation from forced population and soils
    simulation_.initialize(population, soils)

    # Define the time grid of the simulation
    time_grid = range(START_TIME, SIMULATION_LENGTH + TIME_STEP, TIME_STEP)

    # Create empty lists of dataframes to store the outputs at each step of the simulation
    axes_outputs_df_list = []
    organs_outputs_df_list = []
    hiddenzones_outputs_df_list = []
    elements_outputs_df_list = []
    soils_outputs_df_list = []

    for t in time_grid:

        if t > 0:
            # Run the model of CN exchanges ; the population is internally updated by the model
            simulation_.run()

        # Convert the model outputs to dataframes
        _, axes_outputs_df, _, organs_outputs_df, hiddenzones_outputs_df, elements_outputs_df, soils_outputs_df = cnwheat_converter.to_dataframes(
            simulation_.population, simulation_.soils)

        # Append the outputs dataframes at current t to the global lists of dataframes
        for df, list_ in ((axes_outputs_df, axes_outputs_df_list),
                          (organs_outputs_df, organs_outputs_df_list),
                          (hiddenzones_outputs_df,
                           hiddenzones_outputs_df_list),
                          (elements_outputs_df, elements_outputs_df_list),
                          (soils_outputs_df, soils_outputs_df_list)):
            df.insert(0, 't', t)
            list_.append(df)

        if 0 < t < SIMULATION_LENGTH:
            # Force the senescence and photosynthesis of the population
            force_senescence_and_photosynthesis(
                t, population, senescence_roots_data_grouped,
                senescence_elements_data_grouped,
                photosynthesis_elements_data_grouped)
            # Reinitialize the simulation from forced population and soils
            simulation_.initialize(population, soils)

    # compare actual to desired outputs at each scale level (an exception is raised if the test failed)
    for (outputs_df_list,
         desired_outputs_filename,
         actual_outputs_filename,
         state_variables_names) \
            in ((axes_outputs_df_list, DESIRED_AXES_OUTPUTS_FILENAME, ACTUAL_AXES_OUTPUTS_FILENAME,
                 cnwheat_simulation.Simulation.AXES_T_INDEXES + cnwheat_simulation.Simulation.AXES_STATE),
                (organs_outputs_df_list, DESIRED_ORGANS_OUTPUTS_FILENAME, ACTUAL_ORGANS_OUTPUTS_FILENAME,
                 cnwheat_simulation.Simulation.ORGANS_T_INDEXES + cnwheat_simulation.Simulation.ORGANS_STATE),
                (hiddenzones_outputs_df_list, DESIRED_HIDDENZONES_OUTPUTS_FILENAME,
                 ACTUAL_HIDDENZONES_OUTPUTS_FILENAME,
                 cnwheat_simulation.Simulation.HIDDENZONE_T_INDEXES + cnwheat_simulation.Simulation.HIDDENZONE_STATE),
                (elements_outputs_df_list, DESIRED_ELEMENTS_OUTPUTS_FILENAME, ACTUAL_ELEMENTS_OUTPUTS_FILENAME,
                 cnwheat_simulation.Simulation.ELEMENTS_T_INDEXES + cnwheat_simulation.Simulation.ELEMENTS_STATE),
                (soils_outputs_df_list, DESIRED_SOILS_OUTPUTS_FILENAME, ACTUAL_SOILS_OUTPUTS_FILENAME,
                 cnwheat_simulation.Simulation.SOILS_T_INDEXES + cnwheat_simulation.Simulation.SOILS_STATE)):
        outputs_df = pd.concat(outputs_df_list, ignore_index=True)
        outputs_df = outputs_df.loc[:,
                                    state_variables_names]  # compare only the values of the compartments
        cnwheat_tools.compare_actual_to_desired(
            OUTPUTS_DIRPATH,
            outputs_df,
            desired_outputs_filename,
            actual_outputs_filename,
            precision=PRECISION,
            overwrite_desired_data=overwrite_desired_data)
Exemplo n.º 2
0
def test_simulation_logging(overwrite_desired_data=False):
    """Test the logging of a simulation."""

    TEST_DIR_PATH = 'simulation_logging'

    # Inputs of the test
    INPUTS_DIRPATH = os.path.join(TEST_DIR_PATH, 'inputs')
    ORGANS_INITIAL_STATE_FILENAME = 'organs_initial_state.csv'
    HIDDENZONES_INITIAL_STATE_FILENAME = 'hiddenzones_initial_state.csv'
    ELEMENTS_INITIAL_STATE_FILENAME = 'elements_initial_state.csv'
    SOILS_INITIAL_STATE_FILENAME = 'soils_initial_state.csv'
    ELEMENTS_PHOTOSYNTHESIS_FORCINGS_FILENAME = 'elements_photosynthesis_forcings.csv'
    ROOTS_SENESCENCE_FORCINGS_FILENAME = 'roots_senescence_forcings.csv'
    ELEMENTS_SENESCENCE_FORCINGS_FILENAME = 'elements_senescence_forcings.csv'

    # Outputs of the test
    LOGS_DIRPATH = os.path.join(TEST_DIR_PATH, 'logs')
    DESIRED_AXES_COMPARTMENTS_FILENAME = 'desired_axes_compartments.csv'
    DESIRED_ORGANS_COMPARTMENTS_FILENAME = 'desired_organs_compartments.csv'
    DESIRED_HIDDENZONES_COMPARTMENTS_FILENAME = 'desired_hiddenzones_compartments.csv'
    DESIRED_ELEMENTS_COMPARTMENTS_FILENAME = 'desired_elements_compartments.csv'
    DESIRED_SOILS_COMPARTMENTS_FILENAME = 'desired_soils_compartments.csv'
    DESIRED_AXES_DERIVATIVES_FILENAME = 'desired_axes_derivatives.csv'
    DESIRED_ORGANS_DERIVATIVES_FILENAME = 'desired_organs_derivatives.csv'
    DESIRED_HIDDENZONES_DERIVATIVES_FILENAME = 'desired_hiddenzones_derivatives.csv'
    DESIRED_ELEMENTS_DERIVATIVES_FILENAME = 'desired_elements_derivatives.csv'
    DESIRED_SOILS_DERIVATIVES_FILENAME = 'desired_soils_derivatives.csv'
    ACTUAL_AXES_COMPARTMENTS_FILENAME = 'actual_axes_compartments.csv'
    ACTUAL_ORGANS_COMPARTMENTS_FILENAME = 'actual_organs_compartments.csv'
    ACTUAL_HIDDENZONES_COMPARTMENTS_FILENAME = 'actual_hiddenzones_compartments.csv'
    ACTUAL_ELEMENTS_COMPARTMENTS_FILENAME = 'actual_elements_compartments.csv'
    ACTUAL_SOILS_COMPARTMENTS_FILENAME = 'actual_soils_compartments.csv'
    ACTUAL_AXES_DERIVATIVES_FILENAME = 'actual_axes_derivatives.csv'
    ACTUAL_ORGANS_DERIVATIVES_FILENAME = 'actual_organs_derivatives.csv'
    ACTUAL_HIDDENZONES_DERIVATIVES_FILENAME = 'actual_hiddenzones_derivatives.csv'
    ACTUAL_ELEMENTS_DERIVATIVES_FILENAME = 'actual_elements_derivatives.csv'
    ACTUAL_SOILS_DERIVATIVES_FILENAME = 'actual_soils_derivatives.csv'

    # Config file path for logging
    LOGGING_CONFIG_FILEPATH = os.path.join(TEST_DIR_PATH, 'logging.json')

    # Simulation parameters
    START_TIME = 0
    SIMULATION_LENGTH = 5
    TIME_STEP = 1
    CULM_DENSITY = {1: 410}

    time_step_seconds = TIME_STEP * HOUR_TO_SECOND_CONVERSION_FACTOR

    # Remove actual logs files
    for logs_file in glob.glob(os.path.join(LOGS_DIRPATH, "actual*.csv")):
        os.remove(logs_file)

    # Setup the logging (without removing the desired logs since we need them for the comparison test)
    cnwheat_tools.setup_logging(config_filepath=LOGGING_CONFIG_FILEPATH,
                                level=logging.DEBUG,
                                log_model=True,
                                log_compartments=True,
                                log_derivatives=True,
                                remove_old_logs=False)

    # Read the inputs from CSV files and create inputs dataframes
    inputs_dataframes = {}
    for inputs_filename in (ORGANS_INITIAL_STATE_FILENAME,
                            HIDDENZONES_INITIAL_STATE_FILENAME,
                            ELEMENTS_INITIAL_STATE_FILENAME,
                            SOILS_INITIAL_STATE_FILENAME):
        inputs_dataframes[inputs_filename] = pd.read_csv(
            os.path.join(INPUTS_DIRPATH, inputs_filename))

    # Convert the inputs dataframes to a population of plants and a dictionary of soils
    population, soils = cnwheat_converter.from_dataframes(
        inputs_dataframes[ORGANS_INITIAL_STATE_FILENAME],
        inputs_dataframes[HIDDENZONES_INITIAL_STATE_FILENAME],
        inputs_dataframes[ELEMENTS_INITIAL_STATE_FILENAME],
        inputs_dataframes[SOILS_INITIAL_STATE_FILENAME])

    # Create the simulation
    simulation_ = cnwheat_simulation.Simulation(
        respiration_model=respiwheat_model,
        delta_t=time_step_seconds,
        culm_density=CULM_DENSITY)

    # Initialize the simulation from the population of plants and the dictionary of soils created previously
    simulation_.initialize(population, soils)

    # Read photosynthesis and senescence forcings from CSV files, create dataframes, and group the dataframes by object index
    photosynthesis_elements_data_filepath = os.path.join(
        INPUTS_DIRPATH, ELEMENTS_PHOTOSYNTHESIS_FORCINGS_FILENAME)
    photosynthesis_elements_data_df = pd.read_csv(
        photosynthesis_elements_data_filepath)
    photosynthesis_elements_data_grouped = photosynthesis_elements_data_df.groupby(
        cnwheat_simulation.Simulation.ELEMENTS_T_INDEXES)
    senescence_roots_data_filepath = os.path.join(
        INPUTS_DIRPATH, ROOTS_SENESCENCE_FORCINGS_FILENAME)
    senescence_roots_data_df = pd.read_csv(senescence_roots_data_filepath)
    senescence_roots_data_grouped = senescence_roots_data_df.groupby(
        cnwheat_simulation.Simulation.AXES_T_INDEXES)
    senescence_elements_data_filepath = os.path.join(
        INPUTS_DIRPATH, ELEMENTS_SENESCENCE_FORCINGS_FILENAME)
    senescence_elements_data_df = pd.read_csv(
        senescence_elements_data_filepath)
    senescence_elements_data_grouped = senescence_elements_data_df.groupby(
        cnwheat_simulation.Simulation.ELEMENTS_T_INDEXES)

    # Force the senescence and photosynthesis of the population
    force_senescence_and_photosynthesis(0, population,
                                        senescence_roots_data_grouped,
                                        senescence_elements_data_grouped,
                                        photosynthesis_elements_data_grouped)

    # Reinitialize the simulation from forced population and soils
    simulation_.initialize(population, soils)

    # Define the time grid of the simulation
    time_grid = range(START_TIME, SIMULATION_LENGTH + TIME_STEP, TIME_STEP)

    # Create empty lists of dataframes to store the outputs at each step of the simulation
    axes_outputs_df_list = []
    organs_outputs_df_list = []
    hiddenzones_outputs_df_list = []
    elements_outputs_df_list = []
    soils_outputs_df_list = []

    for t in time_grid:

        if t > 0:
            # Run the model of CN exchanges ; the population is internally updated by the model
            simulation_.run()

        # Convert the model outputs to dataframes
        _, axes_outputs_df, _, organs_outputs_df, hiddenzones_outputs_df, elements_outputs_df, soils_outputs_df = cnwheat_converter.to_dataframes(
            simulation_.population, simulation_.soils)

        # Append the outputs dataframes at current t to the global lists of dataframes
        for df, list_ in ((axes_outputs_df, axes_outputs_df_list),
                          (organs_outputs_df, organs_outputs_df_list),
                          (hiddenzones_outputs_df,
                           hiddenzones_outputs_df_list),
                          (elements_outputs_df, elements_outputs_df_list),
                          (soils_outputs_df, soils_outputs_df_list)):
            df.insert(0, 't', t)
            list_.append(df)

        if 0 < t < SIMULATION_LENGTH:
            # Force the senescence and photosynthesis of the population
            force_senescence_and_photosynthesis(
                t, population, senescence_roots_data_grouped,
                senescence_elements_data_grouped,
                photosynthesis_elements_data_grouped)
            # Reinitialize the simulation from forced population and soils
            simulation_.initialize(population, soils)

    # compare actual to desired logs at each scale level (an exception is raised if the test failed)
    # Compartments logs
    for (desired_compartments_filename,
         actual_compartments_filename) \
            in ((DESIRED_AXES_COMPARTMENTS_FILENAME, ACTUAL_AXES_COMPARTMENTS_FILENAME),
                (DESIRED_ORGANS_COMPARTMENTS_FILENAME, ACTUAL_ORGANS_COMPARTMENTS_FILENAME),
                (DESIRED_HIDDENZONES_COMPARTMENTS_FILENAME, ACTUAL_HIDDENZONES_COMPARTMENTS_FILENAME),
                (DESIRED_ELEMENTS_COMPARTMENTS_FILENAME, ACTUAL_ELEMENTS_COMPARTMENTS_FILENAME),
                (DESIRED_SOILS_COMPARTMENTS_FILENAME, ACTUAL_SOILS_COMPARTMENTS_FILENAME)):
        try:
            actual_compartments_df = pd.read_csv(
                os.path.join(LOGS_DIRPATH, actual_compartments_filename))
        except pd.errors.EmptyDataError:
            continue  # This file is empty: ignore it.
        cnwheat_tools.compare_actual_to_desired(
            LOGS_DIRPATH,
            actual_compartments_df,
            desired_compartments_filename,
            precision=PRECISION,
            overwrite_desired_data=overwrite_desired_data)
    # Derivatives logs
    for (desired_derivatives_filename,
         actual_derivatives_filename) \
            in ((DESIRED_AXES_DERIVATIVES_FILENAME, ACTUAL_AXES_DERIVATIVES_FILENAME),
                (DESIRED_ORGANS_DERIVATIVES_FILENAME, ACTUAL_ORGANS_DERIVATIVES_FILENAME),
                (DESIRED_HIDDENZONES_DERIVATIVES_FILENAME, ACTUAL_HIDDENZONES_DERIVATIVES_FILENAME),
                (DESIRED_ELEMENTS_DERIVATIVES_FILENAME, ACTUAL_ELEMENTS_DERIVATIVES_FILENAME),
                (DESIRED_SOILS_DERIVATIVES_FILENAME, ACTUAL_SOILS_DERIVATIVES_FILENAME)):
        try:
            actual_derivatives_df = pd.read_csv(
                os.path.join(LOGS_DIRPATH, actual_derivatives_filename))
        except pd.errors.EmptyDataError:
            continue  # This file is empty: ignore it.
        cnwheat_tools.compare_actual_to_desired(
            LOGS_DIRPATH,
            actual_derivatives_df,
            desired_derivatives_filename,
            precision=PRECISION,
            overwrite_desired_data=overwrite_desired_data)
Exemplo n.º 3
0
def test_postprocessing(overwrite_desired_data=False):
    """Test the postprocessing."""

    TEST_DIR_PATH = 'postprocessing'

    # Inputs of the test
    OUTPUTS_DIRPATH = os.path.join(TEST_DIR_PATH, 'outputs')
    AXES_OUTPUTS_FILENAME = 'axes_outputs.csv'
    ORGANS_OUTPUTS_FILENAME = 'organs_outputs.csv'
    HIDDENZONES_OUTPUTS_FILENAME = 'hiddenzones_outputs.csv'
    ELEMENTS_OUTPUTS_FILENAME = 'elements_outputs.csv'
    SOILS_OUTPUTS_FILENAME = 'soils_outputs.csv'

    # Outputs of the test
    POSTPROCESSING_DIRPATH = os.path.join(TEST_DIR_PATH, 'postprocessing')
    DESIRED_AXES_POSTPROCESSING_FILENAME = 'desired_axes_postprocessing.csv'
    DESIRED_ORGANS_POSTPROCESSING_FILENAME = 'desired_organs_postprocessing.csv'
    DESIRED_HIDDENZONES_POSTPROCESSING_FILENAME = 'desired_hiddenzones_postprocessing.csv'
    DESIRED_ELEMENTS_POSTPROCESSING_FILENAME = 'desired_elements_postprocessing.csv'
    DESIRED_SOILS_POSTPROCESSING_FILENAME = 'desired_soils_postprocessing.csv'
    ACTUAL_AXES_POSTPROCESSING_FILENAME = 'actual_axes_postprocessing.csv'
    ACTUAL_ORGANS_POSTPROCESSING_FILENAME = 'actual_organs_postprocessing.csv'
    ACTUAL_HIDDENZONES_POSTPROCESSING_FILENAME = 'actual_hiddenzones_postprocessing.csv'
    ACTUAL_ELEMENTS_POSTPROCESSING_FILENAME = 'actual_elements_postprocessing.csv'
    ACTUAL_SOILS_POSTPROCESSING_FILENAME = 'actual_soils_postprocessing.csv'

    # Retrieve outputs dataframes
    outputs_df_dict = {}

    for outputs_filename in (AXES_OUTPUTS_FILENAME, ORGANS_OUTPUTS_FILENAME,
                             HIDDENZONES_OUTPUTS_FILENAME,
                             ELEMENTS_OUTPUTS_FILENAME,
                             SOILS_OUTPUTS_FILENAME):
        outputs_filepath = os.path.join(OUTPUTS_DIRPATH, outputs_filename)
        outputs_df = pd.read_csv(outputs_filepath)
        outputs_file_basename = outputs_filename.split('.')[0]
        outputs_df_dict[outputs_file_basename] = outputs_df

    time_grid = outputs_df_dict.values()[0].t
    delta_t = (time_grid.loc[1] -
               time_grid.loc[0]) * HOUR_TO_SECOND_CONVERSION_FACTOR

    # Compute the post-processing
    axes_postprocessing_file_basename = DESIRED_AXES_POSTPROCESSING_FILENAME.split(
        '.')[0]
    hiddenzones_postprocessing_file_basename = DESIRED_HIDDENZONES_POSTPROCESSING_FILENAME.split(
        '.')[0]
    organs_postprocessing_file_basename = DESIRED_ORGANS_POSTPROCESSING_FILENAME.split(
        '.')[0]
    elements_postprocessing_file_basename = DESIRED_ELEMENTS_POSTPROCESSING_FILENAME.split(
        '.')[0]
    soils_postprocessing_file_basename = DESIRED_SOILS_POSTPROCESSING_FILENAME.split(
        '.')[0]

    postprocessing_df_dict = {}

    try:
        (postprocessing_df_dict[axes_postprocessing_file_basename],
         postprocessing_df_dict[hiddenzones_postprocessing_file_basename],
         postprocessing_df_dict[organs_postprocessing_file_basename],
         postprocessing_df_dict[elements_postprocessing_file_basename],
         postprocessing_df_dict[soils_postprocessing_file_basename]) \
            = cnwheat_postprocessing.postprocessing(axes_df=outputs_df_dict[AXES_OUTPUTS_FILENAME.split('.')[0]],
                                                    hiddenzones_df=outputs_df_dict[HIDDENZONES_OUTPUTS_FILENAME.split('.')[0]],
                                                    organs_df=outputs_df_dict[ORGANS_OUTPUTS_FILENAME.split('.')[0]],
                                                    elements_df=outputs_df_dict[ELEMENTS_OUTPUTS_FILENAME.split('.')[0]],
                                                    soils_df=outputs_df_dict[SOILS_OUTPUTS_FILENAME.split('.')[0]],
                                                    delta_t=delta_t)
    except KeyError as ke:
        warnings.warn(str(ke))
        return

    # Write the postprocessing to CSV files
    for postprocessing_file_basename, postprocessing_filename in (
        (axes_postprocessing_file_basename,
         ACTUAL_AXES_POSTPROCESSING_FILENAME),
        (hiddenzones_postprocessing_file_basename,
         ACTUAL_HIDDENZONES_POSTPROCESSING_FILENAME),
        (organs_postprocessing_file_basename,
         ACTUAL_ORGANS_POSTPROCESSING_FILENAME),
        (elements_postprocessing_file_basename,
         ACTUAL_ELEMENTS_POSTPROCESSING_FILENAME),
        (soils_postprocessing_file_basename,
         ACTUAL_SOILS_POSTPROCESSING_FILENAME)):
        postprocessing_filepath = os.path.join(POSTPROCESSING_DIRPATH,
                                               postprocessing_filename)
        postprocessing_df_dict[postprocessing_file_basename].to_csv(
            postprocessing_filepath,
            na_rep='NA',
            index=False,
            float_format='%.{}f'.format(OUTPUTS_PRECISION))

    # compare actual to desired postprocessing at each scale level (an exception is raised if the test failed)
    for (postprocessing_file_basename,
         desired_postprocessing_filename,
         actual_postprocessing_filename,
         postprocessing_variables_names) \
            in ((axes_postprocessing_file_basename, DESIRED_AXES_POSTPROCESSING_FILENAME, ACTUAL_AXES_POSTPROCESSING_FILENAME,
                 cnwheat_postprocessing.AXES_T_INDEXES + cnwheat_postprocessing.AXES_POSTPROCESSING_VARIABLES),
                (organs_postprocessing_file_basename, DESIRED_ORGANS_POSTPROCESSING_FILENAME, ACTUAL_ORGANS_POSTPROCESSING_FILENAME,
                 cnwheat_postprocessing.ORGANS_T_INDEXES + cnwheat_postprocessing.ORGANS_POSTPROCESSING_VARIABLES),
                (hiddenzones_postprocessing_file_basename, DESIRED_HIDDENZONES_POSTPROCESSING_FILENAME, ACTUAL_HIDDENZONES_POSTPROCESSING_FILENAME,
                 cnwheat_postprocessing.HIDDENZONE_T_INDEXES + cnwheat_postprocessing.HIDDENZONE_POSTPROCESSING_VARIABLES),
                (elements_postprocessing_file_basename, DESIRED_ELEMENTS_POSTPROCESSING_FILENAME, ACTUAL_ELEMENTS_POSTPROCESSING_FILENAME,
                 cnwheat_postprocessing.ELEMENTS_T_INDEXES + cnwheat_postprocessing.ELEMENTS_POSTPROCESSING_VARIABLES),
                (soils_postprocessing_file_basename, DESIRED_SOILS_POSTPROCESSING_FILENAME, ACTUAL_SOILS_POSTPROCESSING_FILENAME,
                 cnwheat_postprocessing.SOILS_T_INDEXES + cnwheat_postprocessing.SOILS_POSTPROCESSING_VARIABLES)):
        actual_postprocessing_df = postprocessing_df_dict[
            postprocessing_file_basename]
        actual_postprocessing_df = actual_postprocessing_df.loc[:,
                                                                actual_postprocessing_df
                                                                .columns.
                                                                intersection(
                                                                    postprocessing_variables_names
                                                                )]  # compare only the postprocessing values
        cnwheat_tools.compare_actual_to_desired(
            POSTPROCESSING_DIRPATH,
            actual_postprocessing_df,
            desired_postprocessing_filename,
            actual_postprocessing_filename,
            precision=PRECISION,
            overwrite_desired_data=overwrite_desired_data)
Exemplo n.º 4
0
def test_run(overwrite_desired_data=False):
    # ---------------------------------------------
    # ----- CONFIGURATION OF THE SIMULATION -------
    # ---------------------------------------------

    # -- INPUTS CONFIGURATION --

    # Path of the directory which contains the inputs of the model
    INPUTS_DIRPATH = 'inputs'

    # Name of the CSV files which describes the initial state of the system
    AXES_INITIAL_STATE_FILENAME = 'axes_initial_state.csv'
    ORGANS_INITIAL_STATE_FILENAME = 'organs_initial_state.csv'
    HIDDENZONES_INITIAL_STATE_FILENAME = 'hiddenzones_initial_state.csv'
    ELEMENTS_INITIAL_STATE_FILENAME = 'elements_initial_state.csv'
    SOILS_INITIAL_STATE_FILENAME = 'soils_initial_state.csv'
    METEO_FILENAME = 'meteo_Ljutovac2002.csv'

    # Read the inputs from CSV files and create inputs dataframes
    inputs_dataframes = {}
    for inputs_filename in (AXES_INITIAL_STATE_FILENAME,
                            ORGANS_INITIAL_STATE_FILENAME,
                            HIDDENZONES_INITIAL_STATE_FILENAME,
                            ELEMENTS_INITIAL_STATE_FILENAME,
                            SOILS_INITIAL_STATE_FILENAME):
        inputs_dataframe = pd.read_csv(
            os.path.join(INPUTS_DIRPATH, inputs_filename))
        inputs_dataframes[inputs_filename] = inputs_dataframe.where(
            inputs_dataframe.notnull(), None)

    # -- SIMULATION PARAMETERS --
    START_TIME = 0
    SIMULATION_LENGTH = 24
    PLANT_DENSITY = {1: 410}

    # define the time step in hours for each simulator
    CARIBU_TIMESTEP = 4
    SENESCWHEAT_TIMESTEP = 2
    FARQUHARWHEAT_TIMESTEP = 2
    ELONGWHEAT_TIMESTEP = 1
    GROWTHWHEAT_TIMESTEP = 1
    CNWHEAT_TIMESTEP = 1

    # Name of the CSV files which contains the meteo data
    meteo = pd.read_csv(os.path.join(INPUTS_DIRPATH, METEO_FILENAME),
                        index_col='t')

    # -- OUTPUTS CONFIGURATION --
    # Path of the directory which contains the inputs of the model
    OUTPUTS_DIRPATH = 'outputs'

    # Name of the CSV files which will contain the outputs of the model
    DESIRED_AXES_OUTPUTS_FILENAME = 'desired_axes_outputs.csv'
    DESIRED_ORGANS_OUTPUTS_FILENAME = 'desired_organs_outputs.csv'
    DESIRED_HIDDENZONES_OUTPUTS_FILENAME = 'desired_hiddenzones_outputs.csv'
    DESIRED_ELEMENTS_OUTPUTS_FILENAME = 'desired_elements_outputs.csv'
    DESIRED_SOILS_OUTPUTS_FILENAME = 'desired_soils_outputs.csv'
    ACTUAL_AXES_OUTPUTS_FILENAME = 'actual_axes_outputs.csv'
    ACTUAL_ORGANS_OUTPUTS_FILENAME = 'actual_organs_outputs.csv'
    ACTUAL_HIDDENZONES_OUTPUTS_FILENAME = 'actual_hiddenzones_outputs.csv'
    ACTUAL_ELEMENTS_OUTPUTS_FILENAME = 'actual_elements_outputs.csv'
    ACTUAL_SOILS_OUTPUTS_FILENAME = 'actual_soils_outputs.csv'

    # create empty dataframes to shared data between the models
    shared_axes_inputs_outputs_df = pd.DataFrame()
    shared_organs_inputs_outputs_df = pd.DataFrame()
    shared_hiddenzones_inputs_outputs_df = pd.DataFrame()
    shared_elements_inputs_outputs_df = pd.DataFrame()
    shared_soils_inputs_outputs_df = pd.DataFrame()

    # define lists of dataframes to store the inputs and the outputs of the models at each step.
    axes_all_data_list = []
    organs_all_data_list = [
    ]  # organs which belong to axes: roots, phloem, grains
    hiddenzones_all_data_list = []
    elements_all_data_list = []
    soils_all_data_list = []

    all_simulation_steps = []  # to store the steps of the simulation

    # -- ADEL and MTG CONFIGURATION --

    # read adelwheat inputs at t0
    adel_wheat = AdelDyn(seed=1,
                         scene_unit='m',
                         leaves=echap_leaves(xy_model='Soissons_byleafclass'))
    g = adel_wheat.load(dir=INPUTS_DIRPATH)

    # ---------------------------------------------
    # ----- CONFIGURATION OF THE FACADES -------
    # ---------------------------------------------

    # -- ELONGWHEAT (created first because it is the only facade to add new metamers) --
    # Initial states
    elongwheat_hiddenzones_initial_state = inputs_dataframes[
        HIDDENZONES_INITIAL_STATE_FILENAME][
            elongwheat_facade.converter.HIDDENZONE_TOPOLOGY_COLUMNS + [
                i
                for i in elongwheat_facade.simulation.HIDDENZONE_INPUTS if i in
                inputs_dataframes[HIDDENZONES_INITIAL_STATE_FILENAME].columns
            ]].copy()
    elongwheat_elements_initial_state = inputs_dataframes[
        ELEMENTS_INITIAL_STATE_FILENAME][
            elongwheat_facade.converter.ELEMENT_TOPOLOGY_COLUMNS + [
                i for i in elongwheat_facade.simulation.ELEMENT_INPUTS if i in
                inputs_dataframes[ELEMENTS_INITIAL_STATE_FILENAME].columns
            ]].copy()
    elongwheat_axes_initial_state = inputs_dataframes[
        AXES_INITIAL_STATE_FILENAME][
            elongwheat_facade.converter.AXIS_TOPOLOGY_COLUMNS + [
                i for i in elongwheat_facade.simulation.AXIS_INPUTS
                if i in inputs_dataframes[AXES_INITIAL_STATE_FILENAME].columns
            ]].copy()

    phytoT = os.path.join(INPUTS_DIRPATH, 'phytoT.csv')

    # Update some parameters
    update_cnwheat_parameters = {'SL_ratio_d': 0.25}

    # Facade initialisation
    elongwheat_facade_ = elongwheat_facade.ElongWheatFacade(
        g, ELONGWHEAT_TIMESTEP * HOUR_TO_SECOND_CONVERSION_FACTOR,
        elongwheat_axes_initial_state, elongwheat_hiddenzones_initial_state,
        elongwheat_elements_initial_state, shared_axes_inputs_outputs_df,
        shared_hiddenzones_inputs_outputs_df,
        shared_elements_inputs_outputs_df, adel_wheat, phytoT,
        update_cnwheat_parameters)

    # -- CARIBU --
    caribu_facade_ = caribu_facade.CaribuFacade(
        g, shared_elements_inputs_outputs_df, adel_wheat)

    # -- SENESCWHEAT --
    # Initial states
    senescwheat_roots_initial_state = inputs_dataframes[
        ORGANS_INITIAL_STATE_FILENAME].loc[
            inputs_dataframes[ORGANS_INITIAL_STATE_FILENAME]['organ'] ==
            'roots'][senescwheat_facade.converter.ROOTS_TOPOLOGY_COLUMNS + [
                i
                for i in senescwheat_facade.converter.SENESCWHEAT_ROOTS_INPUTS
                if i in
                inputs_dataframes[ORGANS_INITIAL_STATE_FILENAME].columns
            ]].copy()

    senescwheat_elements_initial_state = inputs_dataframes[
        ELEMENTS_INITIAL_STATE_FILENAME][
            senescwheat_facade.converter.ELEMENTS_TOPOLOGY_COLUMNS + [
                i for i in
                senescwheat_facade.converter.SENESCWHEAT_ELEMENTS_INPUTS if i
                in inputs_dataframes[ELEMENTS_INITIAL_STATE_FILENAME].columns
            ]].copy()

    senescwheat_axes_initial_state = inputs_dataframes[
        AXES_INITIAL_STATE_FILENAME][
            senescwheat_facade.converter.AXES_TOPOLOGY_COLUMNS + [
                i for i in senescwheat_facade.converter.SENESCWHEAT_AXES_INPUTS
                if i in inputs_dataframes[AXES_INITIAL_STATE_FILENAME].columns
            ]].copy()

    # Update some parameters
    update_cnwheat_parameters = {'AGE_EFFECT_SENESCENCE': 10000}

    # Facade initialisation
    senescwheat_facade_ = senescwheat_facade.SenescWheatFacade(
        g, SENESCWHEAT_TIMESTEP * HOUR_TO_SECOND_CONVERSION_FACTOR,
        senescwheat_roots_initial_state, senescwheat_axes_initial_state,
        senescwheat_elements_initial_state, shared_organs_inputs_outputs_df,
        shared_axes_inputs_outputs_df, shared_elements_inputs_outputs_df,
        update_cnwheat_parameters)

    # -- FARQUHARWHEAT --
    # Initial states
    farquharwheat_elements_initial_state = inputs_dataframes[
        ELEMENTS_INITIAL_STATE_FILENAME][
            farquharwheat_facade.converter.ELEMENT_TOPOLOGY_COLUMNS + [
                i for i in
                farquharwheat_facade.converter.FARQUHARWHEAT_ELEMENTS_INPUTS if
                i in inputs_dataframes[ELEMENTS_INITIAL_STATE_FILENAME].columns
            ]].copy()

    farquharwheat_axes_initial_state = inputs_dataframes[
        AXES_INITIAL_STATE_FILENAME][
            farquharwheat_facade.converter.AXIS_TOPOLOGY_COLUMNS + [
                i for i in
                farquharwheat_facade.converter.FARQUHARWHEAT_AXES_INPUTS
                if i in inputs_dataframes[AXES_INITIAL_STATE_FILENAME].columns
            ]].copy()

    # Facade initialisation
    farquharwheat_facade_ = farquharwheat_facade.FarquharWheatFacade(
        g, farquharwheat_elements_initial_state,
        farquharwheat_axes_initial_state, shared_elements_inputs_outputs_df)

    # -- GROWTHWHEAT --
    # Initial states
    growthwheat_hiddenzones_initial_state = inputs_dataframes[
        HIDDENZONES_INITIAL_STATE_FILENAME][
            growthwheat_facade.converter.HIDDENZONE_TOPOLOGY_COLUMNS + [
                i for i in growthwheat_facade.simulation.HIDDENZONE_INPUTS
                if i in
                inputs_dataframes[HIDDENZONES_INITIAL_STATE_FILENAME].columns
            ]].copy()

    growthwheat_elements_initial_state = inputs_dataframes[
        ELEMENTS_INITIAL_STATE_FILENAME][
            growthwheat_facade.converter.ELEMENT_TOPOLOGY_COLUMNS + [
                i for i in growthwheat_facade.simulation.ELEMENT_INPUTS if i in
                inputs_dataframes[ELEMENTS_INITIAL_STATE_FILENAME].columns
            ]].copy()

    growthwheat_root_initial_state = inputs_dataframes[
        ORGANS_INITIAL_STATE_FILENAME].loc[
            inputs_dataframes[ORGANS_INITIAL_STATE_FILENAME]['organ'] ==
            'roots'][growthwheat_facade.converter.ROOT_TOPOLOGY_COLUMNS + [
                i for i in growthwheat_facade.simulation.ROOT_INPUTS if i in
                inputs_dataframes[ORGANS_INITIAL_STATE_FILENAME].columns
            ]].copy()

    growthwheat_axes_initial_state = inputs_dataframes[
        AXES_INITIAL_STATE_FILENAME][
            growthwheat_facade.converter.AXIS_TOPOLOGY_COLUMNS + [
                i for i in growthwheat_facade.simulation.AXIS_INPUTS
                if i in inputs_dataframes[AXES_INITIAL_STATE_FILENAME].columns
            ]].copy()

    # Update some parameters
    update_cnwheat_parameters = {'VMAX_ROOTS_GROWTH_PREFLO': 0.02885625}

    # Facade initialisation
    growthwheat_facade_ = growthwheat_facade.GrowthWheatFacade(
        g, GROWTHWHEAT_TIMESTEP * HOUR_TO_SECOND_CONVERSION_FACTOR,
        growthwheat_hiddenzones_initial_state,
        growthwheat_elements_initial_state, growthwheat_root_initial_state,
        growthwheat_axes_initial_state, shared_organs_inputs_outputs_df,
        shared_hiddenzones_inputs_outputs_df,
        shared_elements_inputs_outputs_df, shared_axes_inputs_outputs_df,
        update_cnwheat_parameters)

    # -- CNWHEAT --
    # Initial states
    cnwheat_organs_initial_state = inputs_dataframes[
        ORGANS_INITIAL_STATE_FILENAME][[
            i for i in cnwheat_facade.cnwheat_converter.ORGANS_VARIABLES
            if i in inputs_dataframes[ORGANS_INITIAL_STATE_FILENAME].columns
        ]].copy()

    cnwheat_hiddenzones_initial_state = inputs_dataframes[
        HIDDENZONES_INITIAL_STATE_FILENAME][[
            i for i in cnwheat_facade.cnwheat_converter.HIDDENZONE_VARIABLES if
            i in inputs_dataframes[HIDDENZONES_INITIAL_STATE_FILENAME].columns
        ]].copy()

    cnwheat_elements_initial_state = inputs_dataframes[
        ELEMENTS_INITIAL_STATE_FILENAME][[
            i for i in cnwheat_facade.cnwheat_converter.ELEMENTS_VARIABLES
            if i in inputs_dataframes[ELEMENTS_INITIAL_STATE_FILENAME].columns
        ]].copy()

    cnwheat_soils_initial_state = inputs_dataframes[
        SOILS_INITIAL_STATE_FILENAME][[
            i for i in cnwheat_facade.cnwheat_converter.SOILS_VARIABLES
            if i in inputs_dataframes[SOILS_INITIAL_STATE_FILENAME].columns
        ]].copy()

    # Update some parameters
    update_cnwheat_parameters = {
        'roots': {
            'K_AMINO_ACIDS_EXPORT': 3E-5,
            'K_NITRATE_EXPORT': 1E-6
        }
    }

    # Facade initialisation
    cnwheat_facade_ = cnwheat_facade.CNWheatFacade(
        g, CNWHEAT_TIMESTEP * HOUR_TO_SECOND_CONVERSION_FACTOR, PLANT_DENSITY,
        cnwheat_organs_initial_state, cnwheat_hiddenzones_initial_state,
        cnwheat_elements_initial_state, cnwheat_soils_initial_state,
        shared_axes_inputs_outputs_df, shared_organs_inputs_outputs_df,
        shared_hiddenzones_inputs_outputs_df,
        shared_elements_inputs_outputs_df, shared_soils_inputs_outputs_df,
        update_cnwheat_parameters)

    # ---------------------------------------------
    # -----      RUN OF THE SIMULATION      -------
    # ---------------------------------------------

    for t_caribu in range(START_TIME, SIMULATION_LENGTH, CARIBU_TIMESTEP):
        # run Caribu
        PARi = meteo.loc[t_caribu, ['PARi_MA4']].iloc[0]
        DOY = meteo.loc[t_caribu, ['DOY']].iloc[0]
        hour = meteo.loc[t_caribu, ['hour']].iloc[0]
        caribu_facade_.run(energy=PARi,
                           DOY=DOY,
                           hourTU=hour,
                           latitude=48.85,
                           sun_sky_option='sky',
                           heterogeneous_canopy=True,
                           plant_density=PLANT_DENSITY[1])

        for t_senescwheat in range(t_caribu, t_caribu + CARIBU_TIMESTEP,
                                   SENESCWHEAT_TIMESTEP):
            # run SenescWheat
            senescwheat_facade_.run()

            # Run the rest of the model if the plant is alive
            for t_farquharwheat in range(t_senescwheat,
                                         t_senescwheat + SENESCWHEAT_TIMESTEP,
                                         FARQUHARWHEAT_TIMESTEP):
                # get the meteo of the current step
                Ta, ambient_CO2, RH, Ur = meteo.loc[t_farquharwheat, [
                    'air_temperature_MA2', 'ambient_CO2_MA2', 'humidity_MA2',
                    'Wind_MA2'
                ]]

                # run FarquharWheat
                farquharwheat_facade_.run(Ta, ambient_CO2, RH, Ur)

                for t_elongwheat in range(
                        t_farquharwheat,
                        t_farquharwheat + FARQUHARWHEAT_TIMESTEP,
                        ELONGWHEAT_TIMESTEP):
                    # run ElongWheat
                    Tair, Tsoil = meteo.loc[
                        t_elongwheat, ['air_temperature', 'soil_temperature']]
                    elongwheat_facade_.run(Tair, Tsoil, option_static=False)

                    # Update geometry
                    adel_wheat.update_geometry(g)

                    for t_growthwheat in range(
                            t_elongwheat, t_elongwheat + ELONGWHEAT_TIMESTEP,
                            GROWTHWHEAT_TIMESTEP):
                        # run GrowthWheat
                        growthwheat_facade_.run()

                        for t_cnwheat in range(
                                t_growthwheat,
                                t_growthwheat + GROWTHWHEAT_TIMESTEP,
                                CNWHEAT_TIMESTEP):
                            if t_cnwheat > 0:

                                # run CNWheat
                                Tair = meteo.loc[t_elongwheat,
                                                 'air_temperature']
                                Tsoil = meteo.loc[t_elongwheat,
                                                  'soil_temperature']
                                cnwheat_facade_.run(Tair, Tsoil)

                            # append outputs at current step to global lists
                            all_simulation_steps.append(t_cnwheat)
                            axes_all_data_list.append(
                                shared_axes_inputs_outputs_df.copy())
                            organs_all_data_list.append(
                                shared_organs_inputs_outputs_df.copy())
                            hiddenzones_all_data_list.append(
                                shared_hiddenzones_inputs_outputs_df.copy())
                            elements_all_data_list.append(
                                shared_elements_inputs_outputs_df.copy())
                            soils_all_data_list.append(
                                shared_soils_inputs_outputs_df.copy())

    # compare actual to desired outputs at each scale level (an exception is raised if the test failed)
    for (outputs_df_list,
         desired_outputs_filename,
         actual_outputs_filename,
         state_variables_names) \
            in ((axes_all_data_list, DESIRED_AXES_OUTPUTS_FILENAME, ACTUAL_AXES_OUTPUTS_FILENAME, AXES_INDEX_COLUMNS),
                (organs_all_data_list, DESIRED_ORGANS_OUTPUTS_FILENAME, ACTUAL_ORGANS_OUTPUTS_FILENAME, ORGANS_INDEX_COLUMNS),
                (hiddenzones_all_data_list, DESIRED_HIDDENZONES_OUTPUTS_FILENAME, ACTUAL_HIDDENZONES_OUTPUTS_FILENAME, HIDDENZONES_INDEX_COLUMNS),
                (elements_all_data_list, DESIRED_ELEMENTS_OUTPUTS_FILENAME, ACTUAL_ELEMENTS_OUTPUTS_FILENAME, ELEMENTS_INDEX_COLUMNS),
                (soils_all_data_list, DESIRED_SOILS_OUTPUTS_FILENAME, ACTUAL_SOILS_OUTPUTS_FILENAME, SOILS_INDEX_COLUMNS)):
        outputs_df = pd.concat(outputs_df_list, ignore_index=True)
        outputs_df = outputs_df.loc[:,
                                    state_variables_names]  # compare only the values of the compartments
        cnwheat_tools.compare_actual_to_desired(
            OUTPUTS_DIRPATH,
            outputs_df,
            desired_outputs_filename,
            actual_outputs_filename,
            precision=PRECISION,
            overwrite_desired_data=overwrite_desired_data)