def __init__(self, shared_mtg, delta_t, culm_density, model_organs_inputs_df, model_hiddenzones_inputs_df, model_elements_inputs_df, model_soils_inputs_df, 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_parameters=None): """ :param openalea.mtg.mtg.MTG shared_mtg: The MTG shared between all models. :param int delta_t: The delta between two runs, in seconds. :param dict culm_density: The density of culm. One key per plant. :param pandas.DataFrame model_organs_inputs_df: the inputs of the model at organs scale. :param pandas.DataFrame model_hiddenzones_inputs_df: the inputs of the model at hiddenzones scale. :param pandas.DataFrame model_elements_inputs_df: the inputs of the model at elements scale. :param pandas.DataFrame model_soils_inputs_df: the inputs of the model at soils scale. :param pandas.DataFrame shared_axes_inputs_outputs_df: the dataframe of inputs and outputs at axes scale shared between all models. :param pandas.DataFrame shared_organs_inputs_outputs_df: the dataframe of inputs and outputs at organs scale shared between all models. :param pandas.DataFrame shared_hiddenzones_inputs_outputs_df: the dataframe of inputs and outputs at hiddenzones scale shared between all models. :param pandas.DataFrame shared_elements_inputs_outputs_df: the dataframe of inputs and outputs at elements scale shared between all models. :param pandas.DataFrame shared_soils_inputs_outputs_df: the dataframe of inputs and outputs at soils scale shared between all models. :param dict or None update_parameters: A dictionary with the parameters to update, should have the form {'Organ_label1': {'param1': value1, 'param2': value2}, ...}. """ self._shared_mtg = shared_mtg #: the MTG shared between all models self._simulation = cnwheat_simulation.Simulation( respiration_model=respiwheat_model, delta_t=delta_t, culm_density=culm_density) self.population, self.soils = cnwheat_converter.from_dataframes( model_organs_inputs_df, model_hiddenzones_inputs_df, model_elements_inputs_df, model_soils_inputs_df) self._update_parameters = update_parameters self._simulation.initialize(self.population, self.soils) self._update_shared_MTG() self._shared_axes_inputs_outputs_df = shared_axes_inputs_outputs_df #: the dataframe at axes scale shared between all models self._shared_organs_inputs_outputs_df = shared_organs_inputs_outputs_df #: the dataframe at organs scale shared between all models self._shared_hiddenzones_inputs_outputs_df = shared_hiddenzones_inputs_outputs_df #: the dataframe at hiddenzones scale shared between all models self._shared_elements_inputs_outputs_df = shared_elements_inputs_outputs_df #: the dataframe at elements scale shared between all models self._shared_soils_inputs_outputs_df = shared_soils_inputs_outputs_df #: the dataframe at soils scale shared between all models self._update_shared_dataframes( cnwheat_organs_data_df=model_organs_inputs_df, cnwheat_hiddenzones_data_df=model_hiddenzones_inputs_df, cnwheat_elements_data_df=model_elements_inputs_df, cnwheat_soils_data_df=model_soils_inputs_df)
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)
inputs_dataframes[ELEMENTS_INITIAL_STATE_FILENAME], inputs_dataframes[SOILS_INITIAL_STATE_FILENAME]) # Set simulation parameters for interpolation if INTERPOLATE_FORCINGS: senescence_forcings_delta_t = time_step_seconds photosynthesis_forcings_delta_t = time_step_seconds else: senescence_forcings_delta_t = None photosynthesis_forcings_delta_t = None # Create the simulation simulation_ = cnwheat_simulation.Simulation( respiration_model=respiwheat_model, delta_t=time_step_seconds, culm_density=CULM_DENSITY, interpolate_forcings=INTERPOLATE_FORCINGS, senescence_forcings_delta_t=senescence_forcings_delta_t, photosynthesis_forcings_delta_t=photosynthesis_forcings_delta_t) # Initialize the simulation from the population of plants and the dictionary of soils created previously simulation_.initialize(population, soils) # get photosynthesis data 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)