diff --git a/aiida_flexpart/calculations/post_processing.py b/aiida_flexpart/calculations/post_processing.py index 0b78970..b5cd72d 100644 --- a/aiida_flexpart/calculations/post_processing.py +++ b/aiida_flexpart/calculations/post_processing.py @@ -24,7 +24,6 @@ def define(cls, spec): 'num_machines': 1, 'num_mpiprocs_per_machine': 1, } - spec.input('metadata.options.max_wallclock_seconds', valid_type = int, default=1800) #INPUTS spec.input("input_dir", valid_type = orm.RemoteData, required=True, diff --git a/aiida_flexpart/utils.py b/aiida_flexpart/utils.py index 8f1bce0..113efa2 100644 --- a/aiida_flexpart/utils.py +++ b/aiida_flexpart/utils.py @@ -2,6 +2,7 @@ """Utilties to convert between python and fortran data types and formats.""" import numbers +import datetime import importlib import numpy import jinja2 @@ -203,7 +204,29 @@ def reformat_locations(dict_, model): dict_[key]['lower_z_level'] = dict_[key]['level']['default'] dict_[key]['upper_z_level'] = dict_[key]['level']['default'] + dict_[key]['level_type'] = dict_[key]['level_type'][model] + dict_[key].pop('longitude') dict_[key].pop('latitude') dict_[key].pop('level') return dict_ + +def get_simulation_period(date, + age_class_time, + release_duration, + simulation_direction + ): + """Dealing with simulation times.""" + #initial values + simulation_beginning_date = datetime.datetime.strptime(date,'%Y-%m-%d %H:%M:%S') + age_class_time = datetime.timedelta(seconds=age_class_time) + release_duration = datetime.timedelta(seconds=release_duration+3600) + + if simulation_direction>0: #forward + simulation_ending_date=simulation_beginning_date+release_duration+age_class_time + else: #backward + simulation_ending_date=release_duration+simulation_beginning_date + simulation_beginning_date-=age_class_time + + return datetime.datetime.strftime(simulation_ending_date,'%Y%m%d%H'), datetime.datetime.strftime(simulation_beginning_date,'%Y%m%d%H') + diff --git a/aiida_flexpart/workflows/multi_dates_workflow.py b/aiida_flexpart/workflows/multi_dates_workflow.py index b54bff2..439e103 100644 --- a/aiida_flexpart/workflows/multi_dates_workflow.py +++ b/aiida_flexpart/workflows/multi_dates_workflow.py @@ -3,9 +3,10 @@ from aiida import engine, plugins, orm from aiida_shell import launch_shell_job from aiida.engine import calcfunction, while_, if_ -import datetime +from aiida_flexpart.utils import get_simulation_period -FlexpartCalculation = plugins.CalculationFactory('flexpart.cosmo') +#plugins +FlexpartCosmoCalculation = plugins.CalculationFactory('flexpart.cosmo') FlexpartIfsCalculation = plugins.CalculationFactory('flexpart.ifs') FlexpartPostCalculation = plugins.CalculationFactory('flexpart.post') @@ -13,25 +14,6 @@ cosmo_models = ['cosmo7', 'cosmo1', 'kenda1'] ECMWF_models = ['IFS_GL_05', 'IFS_GL_1', 'IFS_EU_02', 'IFS_EU_01'] -def get_simulation_period(date, - age_class_time, - release_duration, - simulation_direction - ): - """Dealing with simulation times.""" - #initial values - simulation_beginning_date = datetime.datetime.strptime(date,'%Y-%m-%d %H:%M:%S') - age_class_time = datetime.timedelta(seconds=age_class_time) - release_duration = datetime.timedelta(seconds=release_duration+3600) - - if simulation_direction>0: #forward - simulation_ending_date=simulation_beginning_date+release_duration+age_class_time - else: #backward - simulation_ending_date=release_duration+simulation_beginning_date - simulation_beginning_date-=age_class_time - - return datetime.datetime.strftime(simulation_ending_date,'%Y%m%d%H'), datetime.datetime.strftime(simulation_beginning_date,'%Y%m%d%H') - class FlexpartMultipleDatesWorkflow(engine.WorkChain): """Flexpart multi-dates workflow""" @@ -89,9 +71,9 @@ def define(cls, spec): help='#TODO') spec.input_namespace('land_use_ifs', valid_type=orm.RemoteData, required=False, dynamic=True) - spec.expose_inputs(FlexpartCalculation, + spec.expose_inputs(FlexpartCosmoCalculation, include=['metadata.options'], - namespace='flexpart') + namespace='flexpartcosmo') spec.expose_inputs(FlexpartIfsCalculation, include=['metadata.options'], namespace='flexpartifs') @@ -116,11 +98,6 @@ def define(cls, spec): cls.run_ifs_simulation ) ), - if_(cls.run_offline)( - if_(cls.prepare_meteo_folder_ifs)( - cls.run_ifs_simulation - ) - ), cls.post_processing, ), cls.results, @@ -136,18 +113,14 @@ def run_cosmo(self): return False def run_ifs(self): - if all(mod in ECMWF_models for mod in self.inputs.model) and self.inputs.model: + if (all(mod in ECMWF_models for mod in self.inputs.model) or + all(mod in ECMWF_models for mod in self.inputs.model_offline) and + self.inputs.model and + self.inputs.model_offline + ): return True else: return False - - def run_offline(self): - if all(mod in ECMWF_models for mod in self.inputs.model_offline) and self.inputs.model and self.inputs.model_offline: - self.ctx.index-=1 - return True - elif all(mod in ECMWF_models for mod in self.inputs.model_offline) and not self.inputs.model: - return True - return False def setup(self): """Prepare a simulation.""" @@ -262,7 +235,7 @@ def run_cosmo_simulation(self): self.report(f'starting flexpart cosmo {self.ctx.simulation_dates[self.ctx.index]}') - builder = FlexpartCalculation.get_builder() + builder = FlexpartCosmoCalculation.get_builder() builder.code = self.inputs.fcosmo_code #update command file @@ -287,14 +260,14 @@ def run_cosmo_simulation(self): # Walltime, memory, and resources. builder.metadata.description = 'Test workflow to submit a flexpart calculation' - builder.metadata.options = self.inputs.flexpart.metadata.options + builder.metadata.options = self.inputs.flexpartcosmo.metadata.options # Ask the workflow to continue when the results are ready and store them in the context running = self.submit(builder) self.to_context(calculations=engine.append_(running)) - - self.ctx.index += 1 + if self.ctx.offline_integration_time == 0: + self.ctx.index += 1 def run_ifs_simulation(self): """Run calculations for equation of state.""" @@ -307,19 +280,17 @@ def run_ifs_simulation(self): new_dict = self.ctx.command.get_dict() new_dict['simulation_date'] = self.ctx.simulation_dates[self.ctx.index] - if self.inputs.model_offline[0] in ECMWF_models: + if self.ctx.offline_integration_time > 0: new_dict['age_class'] = self.ctx.offline_integration_time * 3600 new_dict['dumped_particle_data'] = True - if self.inputs.model: - self.ctx.parent_calc_folder = self.ctx.calculations[-1].outputs.remote_folder - self.report(f'starting from: {self.ctx.parent_calc_folder}') - else: - self.ctx.parent_calc_folder = self.inputs.parent_calc_folder + self.ctx.parent_calc_folder = self.ctx.calculations[-1].outputs.remote_folder + builder.parent_calc_folder = self.ctx.parent_calc_folder + self.report(f'starting from: {self.ctx.parent_calc_folder}') builder.meteo_path = self.inputs.meteo_path_offline - builder.parent_calc_folder = self.ctx.parent_calc_folder new_dict.update(self.inputs.meteo_inputs_offline) + else: new_dict['age_class'] = self.inputs.integration_time * 3600 builder.meteo_path = self.inputs.meteo_path diff --git a/examples/example_workflow_combi.py b/examples/example_workflow_combi.py index c1e7619..2720334 100644 --- a/examples/example_workflow_combi.py +++ b/examples/example_workflow_combi.py @@ -63,8 +63,8 @@ def simulation_dates_parser(date_list: list) -> list: def test_run(flexpart_code): """Run workflow.""" - simulation_dates = simulation_dates_parser(['2020-10-01']) - model = ['cosmo7'] + simulation_dates = simulation_dates_parser(['2020-10-01,2020-10-02']) + model = ['cosmo7', 'cosmo1'] model_offline = [] username='lfernand' outgrid_main = 'Europe' @@ -118,10 +118,10 @@ def test_run(flexpart_code): builder.model = orm.List(model) builder.model_offline = orm.List(model_offline) - if model: - meteo_path = orm.List([scratch_address+mod for mod in model]) - builder.meteo_path = meteo_path - builder.meteo_inputs = orm.Dict( + + meteo_path = orm.List([scratch_address+mod for mod in model]) + builder.meteo_path = meteo_path + builder.meteo_inputs = orm.Dict( dict=read_yaml_data('inputs/meteo_inputs.yaml', names=[ model[-1], ])[model[-1]]) @@ -172,7 +172,7 @@ def test_run(flexpart_code): } builder.parent_calc_folder = parent_folder - builder.flexpart.metadata.options.stash = { + builder.flexpartcosmo.metadata.options.stash = { 'source_list': ['aiida.out','header*','partposit_inst', 'grid_time_*.nc'], 'target_base': f'/store/empa/em05/{username}/aiida_stash', 'stash_mode': StashMode.COPY.value, @@ -189,7 +189,7 @@ def test_run(flexpart_code): } #change wall time for cosmo and ifs in seconds - builder.flexpart.metadata.options.max_wallclock_seconds = 1800 + builder.flexpartcosmo.metadata.options.max_wallclock_seconds = 1800 #builder.flexpartifs.metadata.options.max_wallclock_seconds = 2700 engine.run(builder) diff --git a/examples/inputs/locations.yaml b/examples/inputs/locations.yaml index 56c2a4b..3a46dee 100644 --- a/examples/inputs/locations.yaml +++ b/examples/inputs/locations.yaml @@ -1,27 +1,45 @@ -TEST_32: - longitude_of_lower_left_corner: 0007.2480 - latitude_of_lower_left_corner: 0047.0536 - longitude_of_upper_right_corner: 0007.2480 - latitude_of_upper_right_corner: 0047.0536 - lower_z_level: 00032.000 - upper_z_level: 00032.000 - level_type: 1 # 1 for m above ground, 2 for m above sea level - -TEST_200: - longitude_of_lower_left_corner: 0007.2480 - latitude_of_lower_left_corner: 0047.0536 - longitude_of_upper_right_corner: 0007.2480 - latitude_of_upper_right_corner: 0047.0536 - lower_z_level: 00200.000 - upper_z_level: 00200.000 - level_type: 1 # 1 for m above ground, 2 for m above sea level - -TEST_210: - longitude: 7.2480 - latitude: 47.0536 - level: - cosmo7: 200.000 - cosmo1: 100.000 - default: 150.000 - level_type: 1 - +JFJ_5magl: + longitude: 7.9851 + latitude: 46.5475 + level: + IFS_EU_01: 3062.0 + IFS_EU_02: 2929.0 + cosmo7: 3121.0 + IFS_GL_05: 3085.0 + IFS_GL_1: 2600.0 + level_type: + IFS_EU_01: 2 + IFS_EU_02: 2 + cosmo7: 2 + IFS_GL_05: 2 + IFS_GL_1: 2 +MHD_10magl: + longitude: -9.9046 + latitude: 53.3267 + level: + IFS_EU_01: 10.0 + IFS_EU_02: 10.0 + cosmo7: 10.0 + IFS_GL_05: 10.0 + IFS_GL_1: 10.0 + level_type: + IFS_EU_01: 1 + IFS_EU_02: 1 + cosmo7: 1 + IFS_GL_05: 1 + IFS_GL_1: 1 +KIT_200magl: + longitude: 8.4249 + latitude: 49.0915 + level: + IFS_EU_02: 200.0 + cosmo7: 200.0 + IFS_EU_01: 200.0 + IFS_GL_05: 200.0 + IFS_GL_1: 200.0 + level_type: + IFS_EU_02: 1 + cosmo7: 1 + IFS_EU_01: 1 + IFS_GL_05: 1 + IFS_GL_1: 1