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)
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)
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)
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)