@@ -472,8 +472,8 @@ def __init__(self,
472472
473473 # Add default element properties to config
474474 c = {}
475- for p in self .ElementType .variables :
476- v = self .ElementType .variables [p ]
475+ for p in self .elements .variables :
476+ v = self .elements .variables [p ]
477477 if 'seed' in v and v ['seed' ] is False :
478478 continue # Properties which may not be provided by user
479479 c ['seed:%s' % p ] = {
@@ -1717,11 +1717,22 @@ def run(self,
17171717 ###################################################################################
17181718 for vn , var in self .required_variables .copy ().items ():
17191719 if 'skip_if' in var :
1720- skip = self . evaluate_conditional (* var ['skip_if' ])
1720+ skip = evaluate_conditional (* var ['skip_if' ], self )
17211721 if skip is True :
17221722 logger .info (f'Skipping environment variable { vn } because of condition { var ["skip_if" ]} ' )
17231723 self .required_variables .pop (vn )
17241724
1725+ ####################################################################################
1726+ # Evaluate conditionals to determine if previous element properties shall be stored
1727+ ####################################################################################
1728+ for en , prop in self .elements .variables .copy ().items ():
1729+ if 'store_previous_if' in prop :
1730+ store = evaluate_conditional (* prop ['store_previous_if' ], self )
1731+ if store is True :
1732+ logger .info (f'Storing previous values of element property { en } because of condition { prop ["store_previous_if" ]} ' )
1733+ self .elements .variables [en ]['store_previous' ] = True
1734+ del self .elements .variables [en ]['store_previous_if' ] # To avoid writing this to netCDF metadata
1735+
17251736 ########################
17261737 # Simulation time step
17271738 ########################
@@ -1878,7 +1889,7 @@ def run(self,
18781889
18791890 element_vars = {}
18801891 default_dtype = np .float32 # Allows NaN (in contrast to np.int)
1881- for varname , attrs in self .ElementType .variables .items ():
1892+ for varname , attrs in self .elements .variables .items ():
18821893 if varname == 'ID' or (self .export_variables is not None and
18831894 varname not in self .export_variables ):
18841895 continue
@@ -1923,7 +1934,7 @@ def run(self,
19231934
19241935 if self .origin_marker is not None and 'origin_marker' in self .result .data_vars :
19251936 self .result ['origin_marker' ] = self .result .origin_marker .assign_attrs (
1926- {'flag_values' : np .arange (len (self .origin_marker )).astype (self .ElementType .variables ['origin_marker' ]['dtype' ]),
1937+ {'flag_values' : np .arange (len (self .origin_marker )).astype (self .elements .variables ['origin_marker' ]['dtype' ]),
19271938 'flag_meanings' : " " .join (self .origin_marker .values ())
19281939 })
19291940
@@ -1943,11 +1954,6 @@ def run(self,
19431954 self .elements_scheduled .lat )
19441955 self .timer_end ('preparing main loop:moving elements to ocean' )
19451956
1946- # TODO: adjust store_previous according to config, later with upcming conditional mechanism
1947- if self .get_config ('general:coastline_action' , None ) in ['stranding' , 'previous' ]:
1948- logger .info ('Storing previous position of elements for coastline interaction' )
1949- self .elements .variables ['lon' ]['store_previous' ] = True
1950- self .elements .variables ['lat' ]['store_previous' ] = True
19511957
19521958 # Make Xarray datasets to store environment variables and element properties from previous time step
19531959 environment_previous = [vn for vn , v in self .required_variables .items ()
@@ -2211,7 +2217,7 @@ def state_to_buffer(self, final=False):
22112217 logger .debug (f'Truncating buffer from { numtimes_before } to { numtimes_after } times' )
22122218
22132219 # Final update some variable attributes
2214- status_dtype = self .ElementType .variables ['status' ]['dtype' ]
2220+ status_dtype = self .elements .variables ['status' ]['dtype' ]
22152221 self .result ['status' ] = self .result .status .assign_attrs (
22162222 {'valid_range' : np .array ((0 , len (self .status_categories ) - 1 )).astype (status_dtype ),
22172223 'flag_values' : np .array (np .arange (len (self .status_categories ))).astype (status_dtype ),
@@ -4676,33 +4682,47 @@ def gui_postproc(self):
46764682 '''To be overloaded by subclasses'''
46774683 pass
46784684
4679- def evaluate_conditional (self , key , operator , value ):
4680- """Evaluate a condition as True or False
4685+ def _evaluate_key (self , key ):
4686+ # Presently assuming that key is a config key
4687+ return self .get_config (key , 'not_implemented' )
46814688
4682- This can be used to:
4683- - skip required_variables that are not required, based on config setting
4684- - store previous value of element property or environment variable, based on config setting
4685- - disable a config setting based on another setting (for dynamic menus)
4689+ def evaluate_conditional (key , operator , value , self = None ):
4690+ """Evaluate a condition as True or False
46864691
4687- key: config key string
4688- operator: one from operator_map below
4689- value: the provided value to be matched with operator against actual config setting
4692+ This can be used to:
4693+ - skip required_variables that are not required, based on config setting
4694+ - store previous value of element property or environment variable, based on config setting
4695+ - disable a config setting based on another setting (for dynamic menus)
46904696
4691- Returns: True or False
4692- """
4697+ key: e.g. config key/setting as string
4698+ operator: relation between key and value, one from operator_map below
4699+ value: the provided value to be matched with operator against actual key
46934700
4694- operator_map = {
4695- '==' : lambda x , y : x == y ,
4696- '!=' : lambda x , y : x != y ,
4697- '<' : lambda x , y : x < y ,
4698- '<=' : lambda x , y : x <= y ,
4699- '>' : lambda x , y : x > y ,
4700- '>=' : lambda x , y : x >= y ,
4701- 'is' : lambda x , y : x is y ,
4702- 'is not' : lambda x , y : x is not y ,
4703- }
4704-
4705- # Presently assuming that key is a config key
4706- key = self .get_config (key )
4701+ Returns: True or False
4702+ """
47074703
4708- return operator_map [operator ](key , value )
4704+ operator_map = {
4705+ '==' : lambda x , y : x == y ,
4706+ '!=' : lambda x , y : x != y ,
4707+ '<' : lambda x , y : x < y ,
4708+ '<=' : lambda x , y : x <= y ,
4709+ '>' : lambda x , y : x > y ,
4710+ '>=' : lambda x , y : x >= y ,
4711+ 'in' : lambda x , y : x in y ,
4712+ 'is' : lambda x , y : x is y ,
4713+ 'is not' : lambda x , y : x is not y ,
4714+ 'or' : lambda x , y : x or y ,
4715+ 'and' : lambda x , y : x and y ,
4716+ }
4717+
4718+ if isinstance (key , tuple ):
4719+ key = evaluate_conditional (key [0 ], key [1 ], key [2 ], self )
4720+
4721+ if self is not None and not isinstance (key , bool ):
4722+ # If a OpenDrift instance is provided, this will evaluate the key, e.g. with get_config
4723+ key = self ._evaluate_key (key )
4724+
4725+ if isinstance (value , tuple ):
4726+ value = evaluate_conditional (value [0 ], value [1 ], value [2 ], self )
4727+
4728+ return operator_map [operator ](key , value )
0 commit comments