Running with helper class¶
[This note-book is in oceantracker/tutorials_how_to/]
Oceantracker is designed so that both coders and non-coders can get almost the same level of adaptability to their specific needs. Also to streamline running many cases across distributed computers, along with enabling online particle tracking as a service.
To achieve these capabilities, it uses parameters to both change the settings to meet the users needs, but also to build the computational pipeline for the users specific needs. This flexibility in the computational pipeline is achieved using “class” parameters.
Classes perform specific roles in the pipeline. Parameters tell Oceantracker which version of core classes the user wants to use for each role, or add optional classes. Eg. add multiple “release_groups” classes, which may release particles at points, or within a polygon, at different times, rates and locations, all within the same computational run.
Simply by changing the parameters, users can load their own version of a class, including the “solver” class which orchestrates the time stepping and operations by other classes. There are base classes for all the major roles within the computational pipeline. Classes can be adapted by inheriting the bases class, or one of its children, and overwriting some of the methods to alter how the class performs its role.
To make the ideas of settings and classes easier to adopt, the below uses methods of a helper class to add settings and classes to the pipeline. The notebook E_run_using_parameter_dictionaries.ipynb, shows how run directly from parameter dictionaries, which are built in code or read from a json or yaml file.
Parameters using helper¶
There are two types of parameters:
Settings parameters
These are set with one or more calls to helper method, ot.setting(…), where … are keyword arguments. eg “time_step”, the model time step in seconds is set using, time_step= 1800.
There are default values for most settings. A full set of settings and their defaults is at all settings
Class role parameters
Classes add specific tasks to the computational pipeline, eg. how to release particles, write output, particle suspension etc. These are added using helper method ot.add_class(class_role, ….). The first argument is a “class_role”. Each class has its own specific settings, which are set using keyword arguments of helper method. Eg. ot.add_class(‘reader’, input_dir= ‘my_hindcast_dir’, ….) adds a reader class and tells is it which folder contains the hindcast files.
A full set of classes and their default settings is at parameter_ref
Normally there must be a keyword argument “class_name” setting. This is used to import the required class into the computational pipeline, with its specific settings. This “class_name” is a string, used to import the class at setup (so is the same as that used to import any python class within a module).
The “class_name” setting is normally required. A few class_roles have a default class_name, eg. in minimal_example “release_groups” assumes a point_release, and the reader’s “class_name” is chosen by looking at variable names within the hindcast’s netcdf file.
There are two types of “class_role”.
When
Only a single class is required, these have singular “class_role”, eg.“reader” and “solver”.
One or more classes can be added. These have plural “class_role” (eg. can add multiple “release_groups”). Users must give a unique name to each one.
Documentation for all parameters/settings and their default values.
Add link here
Extend the minimal example¶
The below extends the minimal_example, it adds:
release at random locations within a polygon, at random water depths (the default)
a particle fall velocity
particles on the bottom are re-suspended if friction velocity exceeds a critical value.
# build parameters using helper class
from oceantracker.main import OceanTracker
ot = OceanTracker() # make an instance of the helper class
# one or more settings can be set by calls to os.settings
ot.settings(output_file_base='param_test1',# name used as base for output files
root_output_dir='output' # output is put in dir 'root_output_dir'/'output_file_base'
)
# ot.settings can be used more than once to add more settings
ot.settings(time_step =120) # 2 min model time step as seconds
# add a compulsory reader class
# no class_name setting is required
# as will detect that it needs a a schism reader class
ot.add_class('reader',input_dir= './demo_hindcast/schsim3D', # folder to search for hindcast files, sub-dirs will, by default, also be searched
file_mask= 'demo_hindcast_schisim3D*.nc') # hindcast file mask
# add some release groups
# release_groups are one or more release groups
# (ie locations where particles are released at the same times and locations)
# there must be at least one release group
# add release locations from two points,
ot.add_class('release_groups', # class_role is release_groups
name ='my_release_points1',
# the required name setting, is used to refer to this release group internally anf in postprocsing
points= [[1595000, 5482600],
[1599000, 5486200]], # must be an N by 2 or 3 or list, convertible to a numpy array
release_interval= 3600, # seconds between releasing particles
pulse_size = 10, # number of particles released each release_interval
# no class_name setting, so default is a point release
)
# add a second release group, from random locations within a polygon
ot.add_class('release_groups', # class_role is release_group
name ='my_polygon_release1',
class_name= 'PolygonRelease', # use a polygon release
# this time is a polygon , so below points are polygon cords
points = [ [1597682.1237, 5489972.7479],
[1598604.1667, 5490275.5488],
[1598886.4247, 5489464.0424],
[1597917.3387, 5489000],
[1597300, 5489000],
[1597682.1237, 5489972.7479]
],
release_interval= 7200, # seconds between releasing particles
pulse_size = 20, # number of particles released each release_interval
)
# alter default re-suspension class's default settings
ot.add_class('resuspension', critical_friction_velocity = .005) # only re-suspend particles if friction vel. exceeds this value
# add a class to modify the particle velocity
# velocity_modifiers are a set of velocities added to water velocity given in the hydrodynamic model's
# here a fall velocity with a given value is added to the computation
ot.add_class('velocity_modifiers', # class_role is velocity_modifiers
name ='my_fall_velocity',
class_name = 'TerminalVelocity',
value= -0.001, # mean terminal vel < 0 for falling
# optionally variance can also be use to give each particle its own fall velocity
)
# now run oceantracker
# as helper "ot" has set params above, simply run it
case_info_file_name = ot.run()
# output now in folder "root_output_dir"/"output_file_base"
# in this example output is in directory output/param_test1'
# case_info_file_name is the name of a json file with useful for post processing,
# eg it holds output file names to assist in reading and plotting data
print('case file name=',case_info_file_name)
prelim: Starting package set up helper: ---------------------------------------------------------------------- helper: Starting OceanTrackerhelper class, version 0.50.0041-2025-03-10 helper: Python version: 3.11.9 | packaged by conda-forge | (main, Apr 19 2024, 18:27:10) [MSC v.1938 64 bit (AMD64)] helper: >>> Warning: Oceantracker is compatible with Python 3.11, however not all external imported packages have been updated to be compatible with 3.11 helper: hint: Down grade to python 3.10 if unexplained issues in external packages helper: ---------------------------------------------------------------------- helper: OceanTracker version 0.50.0041-2025-03-10 starting setup helper "main.py": helper: >>> Warning: Deleted contents of existing output dir helper: Output is in dir "f:H_Local_driveParticleTrackingoceantrackertutorials_how_tooutputparam_test1" helper: hint: see for copies of screen output and user supplied parameters, plus all other output helper: >>> Note: to help with debugging, parameters as given by user are in "param_test1_raw_user_params.json" helper: ---------------------------------------------------------------------- helper: Numba setup: applied settings, max threads = 32, physical cores = 32 helper: hint: cache code = False, fastmath= False helper: ---------------------------------------------------------------------- helper: - Built OceanTracker package tree, 0.823 sec helper: - Built OceanTracker sort name map, 0.000 sec helper: - Done package set up to setup ClassImporter, 0.823 sec setup: ---------------------------------------------------------------------- setup: OceanTracker version 0.50.0041-2025-03-10 setup: Starting user param. runner: "param_test1" at 2025-03-10T13:08:41.071268 setup: ---------------------------------------------------------------------- setup: - Start field group manager and readers setup setup: - Found input dir "./demo_hindcast/schsim3D" setup: - Detected reader class_name = "oceantracker.reader.SCHISM_reader.SCHISMreader" setup: Hydro-model is "3D", type "SCHISMreader" setup: hint: Files found in dir and sub-dirs of "./demo_hindcast/schsim3D" setup: Geographic coords = "False" setup: Hindcast start: 2017-01-01T00:30:00 end: 2017-01-01T23:30:00 setup: time step = 0 days 1 hrs 0 min 0 sec, number of time steps= 24 setup: grid bounding box = [1589789.000 5479437.000] to [1603398.000 5501640.000] setup: - Starting grid setup setup: - built node to triangles map, 0.997 sec setup: - built triangle adjacency matrix, 0.160 sec setup: - found boundary triangles, 0.000 sec setup: - built domain and island outlines, 0.970 sec setup: - calculated triangle areas, 0.000 sec setup: - Finished grid setup setup: - built barycentric-transform matrix, 0.332 sec setup: - Finished field group manager and readers setup, 3.609 sec setup: - Added release groups and found run start and end times, 0.446 sec setup: - Done initial setup of all classes, 1.017 sec setup: ---------------------------------------------------------------------- setup: - Starting" param_test1, duration: 0 days 23 hrs 0 min 0 sec setup: From 2017-01-01T00:30:00 to 2017-01-01T23:30:00 setup: - Reading 24 time steps, for hindcast time steps 00:23 into ring buffer offsets 000:023 setup: - read 24 time steps in 1.6 sec, from ./demo_hindcast/schsim3D setup: ---------------------------------------------------------------------- setup: - Starting time stepping: 2017-01-01T00:30:00 to 2017-01-01T23:30:00 , duration 0 days 23 hrs 0 min 0 sec S: - Opened tracks output and done written first time step in: "param_test1_tracks_compact_000.nc", 0.016 sec S: 0000: 00%:H0000b00-01 Day +00 00:00 2017-01-01 00:30:00: Rel:40 : Active:40 Move:40 Bottom: 0 Strand:0 Dead: 0 Out: 0 Buffer: 5% step time = 12830.8 ms S: 0030: 04%:H0001b01-02 Day +00 01:00 2017-01-01 01:30:00: Rel:60 : Active:60 Move:55 Bottom: 5 Strand:0 Dead: 0 Out: 0 Buffer: 8% step time = 7.4 ms S: 0060: 09%:H0002b02-03 Day +00 02:00 2017-01-01 02:30:00: Rel:100 : Active:100 Move:94 Bottom: 6 Strand:0 Dead: 0 Out: 0 Buffer:13% step time = 7.5 ms S: 0090: 13%:H0003b03-04 Day +00 03:00 2017-01-01 03:30:00: Rel:120 : Active:120 Move:105 Bottom: 5 Strand:10 Dead: 0 Out: 0 Buffer:16% step time = 7.4 ms S: 0120: 17%:H0004b04-05 Day +00 04:00 2017-01-01 04:30:00: Rel:160 : Active:160 Move:143 Bottom: 7 Strand:10 Dead: 0 Out: 0 Buffer:22% step time = 9.2 ms S: 0150: 22%:H0005b05-06 Day +00 05:00 2017-01-01 05:30:00: Rel:180 : Active:180 Move:153 Bottom: 17 Strand:10 Dead: 0 Out: 0 Buffer:25% step time = 7.1 ms S: 0180: 26%:H0006b06-07 Day +00 06:00 2017-01-01 06:30:00: Rel:220 : Active:220 Move:201 Bottom: 9 Strand:10 Dead: 0 Out: 0 Buffer:30% step time = 12.0 ms S: 0210: 30%:H0007b07-08 Day +00 07:00 2017-01-01 07:30:00: Rel:240 : Active:240 Move:218 Bottom: 12 Strand:10 Dead: 0 Out: 0 Buffer:33% step time = 10.8 ms S: 0240: 35%:H0008b08-09 Day +00 08:00 2017-01-01 08:30:00: Rel:280 : Active:280 Move:257 Bottom: 13 Strand:10 Dead: 0 Out: 0 Buffer:38% step time = 9.2 ms S: 0270: 39%:H0009b09-10 Day +00 09:00 2017-01-01 09:30:00: Rel:300 : Active:300 Move:277 Bottom: 23 Strand:0 Dead: 0 Out: 0 Buffer:41% step time = 7.1 ms S: 0300: 43%:H0010b10-11 Day +00 10:00 2017-01-01 10:30:00: Rel:340 : Active:340 Move:298 Bottom: 42 Strand:0 Dead: 0 Out: 0 Buffer:47% step time = 8.7 ms S: 0330: 48%:H0011b11-12 Day +00 11:00 2017-01-01 11:30:00: Rel:360 : Active:360 Move:315 Bottom: 45 Strand:0 Dead: 0 Out: 0 Buffer:50% step time = 18.5 ms S: 0360: 52%:H0012b12-13 Day +00 12:00 2017-01-01 12:30:00: Rel:400 : Active:400 Move:348 Bottom: 52 Strand:0 Dead: 0 Out: 0 Buffer:55% step time = 11.4 ms S: 0390: 57%:H0012b12-13 Day +00 13:00 2017-01-01 13:30:00: Rel:420 : Active:420 Move:375 Bottom: 34 Strand:11 Dead: 0 Out: 0 Buffer:58% step time = 8.2 ms S: 0420: 61%:H0014b14-15 Day +00 14:00 2017-01-01 14:30:00: Rel:460 : Active:460 Move:395 Bottom: 53 Strand:12 Dead: 0 Out: 0 Buffer:63% step time = 20.3 ms S: 0450: 65%:H0015b15-16 Day +00 15:00 2017-01-01 15:30:00: Rel:480 : Active:480 Move:397 Bottom: 44 Strand:39 Dead: 0 Out: 0 Buffer:66% step time = 7.5 ms S: 0480: 70%:H0016b16-17 Day +00 16:00 2017-01-01 16:30:00: Rel:520 : Active:520 Move:386 Bottom: 88 Strand:46 Dead: 0 Out: 0 Buffer:72% step time = 8.0 ms S: 0510: 74%:H0017b17-18 Day +00 17:00 2017-01-01 17:30:00: Rel:540 : Active:540 Move:322 Bottom: 156 Strand:62 Dead: 0 Out: 0 Buffer:75% step time = 7.9 ms S: 0540: 78%:H0018b18-19 Day +00 18:00 2017-01-01 18:30:00: Rel:580 : Active:580 Move:394 Bottom: 124 Strand:62 Dead: 0 Out: 0 Buffer:80% step time = 11.7 ms S: 0570: 83%:H0019b19-20 Day +00 19:00 2017-01-01 19:30:00: Rel:600 : Active:600 Move:418 Bottom: 127 Strand:55 Dead: 0 Out: 0 Buffer:83% step time = 8.0 ms S: 0600: 87%:H0020b20-21 Day +00 20:00 2017-01-01 20:30:00: Rel:640 : Active:640 Move:483 Bottom: 109 Strand:48 Dead: 0 Out: 0 Buffer:88% step time = 9.3 ms S: 0630: 91%:H0021b21-22 Day +00 21:00 2017-01-01 21:30:00: Rel:660 : Active:660 Move:530 Bottom: 118 Strand:12 Dead: 0 Out: 0 Buffer:91% step time = 7.4 ms S: 0660: 96%:H0022b22-23 Day +00 22:00 2017-01-01 22:30:00: Rel:700 : Active:700 Move:533 Bottom: 156 Strand:11 Dead: 0 Out: 0 Buffer:97% step time = 8.3 ms S: 0690: 100%:H0023b23-00 Day +00 23:00 2017-01-01 23:30:00: Rel:700 : Active:700 Move:531 Bottom: 169 Strand:0 Dead: 0 Out: 0 Buffer:97% step time = 11.8 ms end: ---------------------------------------------------------------------- end: >>> Warning: Oceantracker is compatible with Python 3.11, however not all external imported packages have been updated to be compatible with 3.11 end: hint: Down grade to python 3.10 if unexplained issues in external packages end: end: >>> Warning: Deleted contents of existing output dir end: end: ---------------------------------------------------------------------- end: Error counts - 0 errors, 2 warnings, 1 notes, check above end: end: - Finished "param_test1" started: 21651.101759, ended: 2025-03-10 13:09:13.869712 end: Computational time =0:00:33.852219 end: Output in f:H_Local_driveParticleTrackingoceantrackertutorials_how_tooutputparam_test1 end: end: --- Finished Oceantracker run ---------------------------------------- end: case file name= f:H_Local_driveParticleTrackingoceantrackertutorials_how_tooutputparam_test1param_test1_caseInfo.json
# can see the parameters used to build
# using the helper class instance in ot.params
import json
print(json.dumps(ot.params, indent=4))
{
"output_file_base": "param_test1",
"root_output_dir": "output",
"time_step": 120,
"reader": {
"input_dir": "../demos/demo_hindcast/schsim3D",
"file_mask": "demo_hindcast_schisim3D*.nc"
},
"release_groups": [
{
"points": [
[
1595000,
5482600
],
[
1599000,
5486200
]
],
"release_interval": 3600,
"pulse_size": 10,
"name": "my_release_points1"
},
{
"points": [
[
1597682.1237,
5489972.7479
],
[
1598604.1667,
5490275.5488
],
[
1598886.4247,
5489464.0424
],
[
1597917.3387,
5489000
],
[
1597300,
5489000
],
[
1597682.1237,
5489972.7479
]
],
"release_interval": 7200,
"pulse_size": 20,
"class_name": "PolygonRelease",
"name": "my_polygon_release1"
}
],
"resuspension": {
"critical_friction_velocity": 0.005
},
"velocity_modifiers": [
{
"value": -0.001,
"class_name": "TerminalVelocity",
"name": "my_fall_velocity"
}
]
}
Basic plots of tracks¶
# plot animation of results
from matplotlib import pyplot as plt
from oceantracker.plot_output import plot_tracks
from oceantracker.read_output.python import load_output_files
from IPython.display import HTML # show animation in note book
# read particle track data into a dictionary using case_info_file_name
tracks = load_output_files.load_track_data(case_info_file_name)
ax= [1591000, 1601500, 5479500, 5491000] # area to plot
# animate particles
anim = plot_tracks.animate_particles(tracks, axis_lims=ax,title='Fall vel.+ re-sus., grey part. are on bottom when flows too weak to resuspend',
show_dry_cells=True, show_grid=True, show=False) # use ipython to show video, rather than matplotlib plt.show()
# this line only used in note books, in python scripts use show = True above
# this is slow to build!
HTML(anim.to_html5_video())
