@@ -84,6 +84,9 @@ class OpenDriftModel(ParticleTrackingManager):
84
84
coastline_action : str, optional
85
85
Action to perform if a drifter hits the coastline, by default "previous". Options
86
86
are 'stranding', 'previous'.
87
+ seafloor_action : str, optional
88
+ Action to perform if a drifter hits the seafloor, by default "deactivate". Options
89
+ are 'deactivate', 'previous', 'lift_to_seafloor'.
87
90
max_speed : int
88
91
Typical maximum speed of elements, used to estimate reader buffer size.
89
92
wind_drift_factor : float
@@ -173,6 +176,7 @@ def __init__(
173
176
stokes_drift : bool = config_model ["stokes_drift" ]["default" ],
174
177
mixed_layer_depth : float = config_model ["mixed_layer_depth" ]["default" ],
175
178
coastline_action : str = config_model ["coastline_action" ]["default" ],
179
+ seafloor_action : str = config_model ["seafloor_action" ]["default" ],
176
180
max_speed : int = config_model ["max_speed" ]["default" ],
177
181
wind_drift_factor : float = config_model ["wind_drift_factor" ]["default" ],
178
182
wind_drift_depth : float = config_model ["wind_drift_depth" ]["default" ],
@@ -319,6 +323,15 @@ def __setattr_model__(self, name: str, value) -> None:
319
323
self .config_model [name ]["value" ] = value
320
324
self ._update_config ()
321
325
326
+ if name == "ocean_model" :
327
+ if value == "NWGOA" :
328
+ self .Dcrit = 0.5
329
+ elif "CIOFS" in value :
330
+ self .Dcrit = 0.3
331
+ else :
332
+ self .Dcrit = 0.1
333
+ self .logger .info (f"For ocean_model { value } , setting Dcrit to { self .Dcrit } ." )
334
+
322
335
if name in ["ocean_model" , "horizontal_diffusivity" ]:
323
336
324
337
# just set the value and move on if purposely setting a non-None value
@@ -332,12 +345,11 @@ def __setattr_model__(self, name: str, value) -> None:
332
345
# in all other cases that ocean_model is a known model, want to use the
333
346
# grid-dependent value
334
347
elif self .ocean_model in _KNOWN_MODELS :
335
- print (name , value )
336
- self .logger .info (
337
- "Setting horizontal_diffusivity parameter to one tuned to reader model"
338
- )
339
348
340
349
hdiff = self .calc_known_horizontal_diffusivity ()
350
+ self .logger .info (
351
+ f"Setting horizontal_diffusivity parameter to one tuned to reader model of value { hdiff } ."
352
+ )
341
353
# when editing the __dict__ directly have to also update config_model
342
354
self .__dict__ ["horizontal_diffusivity" ] = hdiff
343
355
self .config_model ["horizontal_diffusivity" ]["value" ] = hdiff
@@ -381,9 +393,21 @@ def __setattr_model__(self, name: str, value) -> None:
381
393
382
394
# Leeway doesn't have this option available
383
395
if name == "do3D" and not value and self .drift_model != "Leeway" :
396
+ self .logger .info ("do3D is False so disabling vertical motion." )
384
397
self .o .disable_vertical_motion ()
385
- elif name == "do3D" and value :
398
+ elif name == "do3D" and not value and self .drift_model == "Leeway" :
399
+ self .logger .info (
400
+ "do3D is False but drift_model is Leeway so doing nothing."
401
+ )
402
+
403
+ if name == "do3D" and value and self .drift_model != "Leeway" :
404
+ self .logger .info ("do3D is True so turning on vertical advection." )
386
405
self .o .set_config ("drift:vertical_advection" , True )
406
+ elif name == "do3D" and value and self .drift_model == "Leeway" :
407
+ self .logger .info (
408
+ "do3D is True but drift_model is Leeway so " "changing do3D to False."
409
+ )
410
+ self .do3D = False
387
411
388
412
# Make sure vertical_mixing_timestep equals default value if vertical_mixing False
389
413
if name in ["vertical_mixing" , "vertical_mixing_timestep" ]:
@@ -464,6 +488,25 @@ def __setattr_model__(self, name: str, value) -> None:
464
488
self .__dict__ ["stokes_drift" ] = False
465
489
self .config_model ["stokes_drift" ]["value" ] = False
466
490
491
+ # Add export variables for certain drift_model values
492
+ # drift_model is always set initially only
493
+ if name == "export_variables" and self .drift_model == "OpenOil" :
494
+ oil_vars = [
495
+ "mass_oil" ,
496
+ "density" ,
497
+ "mass_evaporated" ,
498
+ "mass_dispersed" ,
499
+ "mass_biodegraded" ,
500
+ "viscosity" ,
501
+ "water_fraction" ,
502
+ ]
503
+ self .__dict__ ["export_variables" ] += oil_vars
504
+ self .config_model ["export_variables" ]["value" ] += oil_vars
505
+ elif name == "export_variables" and self .drift_model == "Leeway" :
506
+ vars = ["object_type" ]
507
+ self .__dict__ ["export_variables" ] += vars
508
+ self .config_model ["export_variables" ]["value" ] += vars
509
+
467
510
self ._update_config ()
468
511
469
512
def run_add_reader (
@@ -617,14 +660,13 @@ def run_add_reader(
617
660
618
661
drop_vars += [
619
662
"wetdry_mask_psi" ,
620
- "zeta" ,
621
663
]
622
664
if self .ocean_model == "CIOFS" :
623
665
624
666
loc_local = "/mnt/vault/ciofs/HINDCAST/ciofs_kerchunk.parq"
625
667
loc_remote = "http://xpublish-ciofs.srv.axds.co/datasets/ciofs_hindcast/zarr/"
626
668
627
- elif self .ocean_model . upper () == "CIOFSOP" :
669
+ elif self .ocean_model == "CIOFSOP" :
628
670
629
671
standard_name_mapping .update (
630
672
{
@@ -674,7 +716,6 @@ def run_add_reader(
674
716
# For NWGOA, need to calculate wetdry mask from a variable
675
717
if self .ocean_model == "NWGOA" and not self .use_static_masks :
676
718
ds ["wetdry_mask_rho" ] = (~ ds .zeta .isnull ()).astype (int )
677
- ds .drop_vars ("zeta" , inplace = True )
678
719
679
720
# For CIOFSOP need to rename u/v to have "East" and "North" in the variable names
680
721
# so they aren't rotated in the ROMS reader (the standard names have to be x/y not east/north)
@@ -683,7 +724,14 @@ def run_add_reader(
683
724
# grid = xr.open_dataset("/mnt/vault/ciofs/HINDCAST/nos.ciofs.romsgrid.nc")
684
725
# ds["angle"] = grid["angle"]
685
726
686
- units_date = pd .Timestamp (ds .ocean_time .attrs ["units" ].split ("since " )[1 ])
727
+ try :
728
+ units_date = pd .Timestamp (
729
+ ds .ocean_time .attrs ["units" ].split ("since " )[1 ]
730
+ )
731
+ except KeyError : # for remote
732
+ units_date = pd .Timestamp (
733
+ ds .ocean_time .encoding ["units" ].split ("since " )[0 ]
734
+ )
687
735
# use reader start time if not otherwise input
688
736
if self .start_time is None :
689
737
self .logger .info ("setting reader start_time as simulation start_time" )
@@ -787,11 +835,18 @@ def run_drifters(self):
787
835
}
788
836
789
837
self .o ._config = config_input_to_opendrift # only OpenDrift config
838
+
839
+ output_file = (
840
+ self .output_file
841
+ or f"output-results_{ datetime .datetime .utcnow ():%Y-%m-%dT%H%M:%SZ} .nc"
842
+ )
843
+
790
844
self .o .run (
791
845
time_step = timedir * self .time_step ,
846
+ time_step_output = self .time_step_output ,
792
847
steps = self .steps ,
793
848
export_variables = self .export_variables ,
794
- outfile = f"output-results_ { datetime . datetime . utcnow ():%Y-%m-%dT%H%M:%SZ } .nc" ,
849
+ outfile = output_file ,
795
850
)
796
851
797
852
self .o ._config = full_config # reinstate config
@@ -902,6 +957,30 @@ def export_variables(self):
902
957
903
958
return self .o .export_variables
904
959
960
+ def drift_model_config (self , ptm_level = [1 , 2 , 3 ], prefix = "" ):
961
+ """Show config for this drift model selection.
962
+
963
+ This shows all PTM-controlled parameters for the OpenDrift
964
+ drift model selected and their current values, at the selected ptm_level
965
+ of importance.
966
+
967
+ Parameters
968
+ ----------
969
+ ptm_level : int, list, optional
970
+ Options are 1, 2, 3, or lists of combinations. Use [1,2,3] for all.
971
+ Default is 1.
972
+ prefix : str, optional
973
+ prefix to search config for, only for OpenDrift parameters (not PTM).
974
+ """
975
+
976
+ return [
977
+ (key , value_dict ["value" ])
978
+ for key , value_dict in self .show_config (
979
+ substring = ":" , ptm_level = ptm_level , level = [1 , 2 , 3 ], prefix = prefix
980
+ ).items ()
981
+ if "value" in value_dict
982
+ ]
983
+
905
984
def get_configspec (self , prefix , substring , excludestring , level , ptm_level ):
906
985
"""Copied from OpenDrift, then modified."""
907
986
0 commit comments