-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwriting_a_new_model.html
201 lines (179 loc) · 16.8 KB
/
writing_a_new_model.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="./">
<head>
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>How to write a new module — OpenDrift documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
<link rel="stylesheet" type="text/css" href="_static/graphviz.css?v=4ae1632d" />
<link rel="stylesheet" type="text/css" href="_static/plot_directive.css" />
<link rel="stylesheet" type="text/css" href="_static/sg_gallery.css?v=d2d258e8" />
<link rel="stylesheet" type="text/css" href="_static/sg_gallery-binder.css?v=f4aeca0c" />
<link rel="stylesheet" type="text/css" href="_static/sg_gallery-dataframe.css?v=2082cf3c" />
<link rel="stylesheet" type="text/css" href="_static/sg_gallery-rendered-html.css?v=1277b6f3" />
<link rel="stylesheet" type="text/css" href="_static/theme_overrides.css" />
<script src="_static/jquery.js?v=5d32c60e"></script>
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="_static/documentation_options.js?v=5929fcd5"></script>
<script src="_static/doctools.js?v=9bcbadda"></script>
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="_static/js/theme.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Gallery" href="gallery/index.html" />
<link rel="prev" title="How to choose which model to use" href="choosing_a_model.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="index.html" class="icon icon-home">
OpenDrift
<img src="_static/opendrift_logo.png" class="logo" alt="Logo"/>
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<ul>
<li class="toctree-l1"><a class="reference internal" href="index.html">Introduction to OpenDrift</a></li>
</ul>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="history_link.html">History</a></li>
<li class="toctree-l1"><a class="reference internal" href="install.html">Installing OpenDrift</a></li>
<li class="toctree-l1"><a class="reference internal" href="performance.html">Performance in OpenDrift</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial.html">Tutorial</a></li>
<li class="toctree-l1"><a class="reference internal" href="theory/index.html">Theory</a></li>
<li class="toctree-l1"><a class="reference internal" href="theory/index.html#drift-in-the-ocean">Drift in the Ocean</a></li>
<li class="toctree-l1"><a class="reference internal" href="choosing_a_model.html">How to choose which model to use</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">How to write a new module</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#moving-elements">1. Moving elements</a></li>
<li class="toctree-l2"><a class="reference internal" href="#modifying-element-properties">2. Modifying element properties</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="gallery/index.html">Gallery</a></li>
<li class="toctree-l1"><a class="reference internal" href="oil_types.html">Oil types</a></li>
<li class="toctree-l1"><a class="reference internal" href="interaction_with_coastline.html">Interaction with coastline</a></li>
<li class="toctree-l1"><a class="reference internal" href="docker.html">Using OpenDrift in a container</a></li>
<li class="toctree-l1"><a class="reference internal" href="gui.html">Graphical User Interface</a></li>
<li class="toctree-l1"><a class="reference internal" href="references.html">Publications</a></li>
<li class="toctree-l1"><a class="reference internal" href="services.html">Services using OpenDrift</a></li>
<li class="toctree-l1"><a class="reference internal" href="autoapi/index.html">API Reference</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="index.html">OpenDrift</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item active">How to write a new module</li>
<li class="wy-breadcrumbs-aside">
<a href="_sources/writing_a_new_model.rst.txt" rel="nofollow"> View page source</a>
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<section id="how-to-write-a-new-module">
<h1>How to write a new module<a class="headerlink" href="#how-to-write-a-new-module" title="Link to this heading"></a></h1>
<p>The best way to get started in developing a new model, is to copy and modify an existing working model/module (e.g. <a class="reference external" href="https://opendrift.github.io/_modules/opendrift/models/oceandrift.html">oceandrift</a>) or look at the <a class="reference external" href="https://opendrift.github.io/_modules/opendrift/models/model_template.html">model_template</a> which contains instructions/comments. A general explanation is given below.</p>
<p>The main class of the OpenDrift framework is the <strong>OpenDriftSimulation</strong> class in the module <a class="reference external" href="https://opendrift.github.io/_modules/opendrift/models/basemodel.html">basemodel.py</a>, stored in the folder <a class="reference external" href="https://github.com/opendrift/opendrift/blob/master/opendrift/models/">models</a>.</p>
<p>A purpose specific trajectory model is made by subclassing <strong>OpenDriftSimulation</strong> (or any of its subclasses/models), mainly by:</p>
<blockquote>
<div><ul class="simple">
<li><p>defining (or importing/reusing) a particle/element type (e.g. oil particle, larvae particle…), by specifying names and default values of the (additional) properties the elements shall have.</p></li>
<li><p>defining which environment variables (wind, waves, current…) shall be needed by the model to update positions and properties of elements (below).</p>
<ul>
<li><p>these environment variables are obtained by <a class="reference internal" href="theory/data_model.html"><span class="doc">Readers</span></a>, however, when writing a model/module one do not need to worry about how environment variables are obtained.</p></li>
</ul>
</li>
<li><p>defining a class method <strong>update()</strong> to be called at each model time step.</p></li>
</ul>
</div></blockquote>
<p>The method <strong>update()</strong> will in principle do two different things, regardless of the specific application:</p>
<section id="moving-elements">
<h2>1. Moving elements<a class="headerlink" href="#moving-elements" title="Link to this heading"></a></h2>
<p>The positions of elements are stored as the element properties <code class="docutils literal notranslate"><span class="pre">longitude</span></code> and <code class="docutils literal notranslate"><span class="pre">latitude</span></code> with units of degrees, as well as the vertical coordinate <code class="docutils literal notranslate"><span class="pre">z</span></code> with units of meters, negative in the ocean. These properties might in principle be modified directly within the update() method, however, it is both safer and simpler to rather use the built in convenience methods, such as:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="bp">self</span><span class="o">.</span><span class="n">update_positions</span><span class="p">(</span><span class="n">x_velocity</span><span class="p">,</span> <span class="n">y_velocity</span><span class="p">)</span>
</pre></div>
</div>
<p>This method takes care of e.g. rotation of vectors from the specific x-y coordinate system of the simulation (Pyproj projection) to determine the correct update of the position (longitude and latitude), also taking the simulation time_step into account, including reversing advection direction if time step is negative (backtracking).
The <code class="docutils literal notranslate"><span class="pre">x_velocity</span></code> and <code class="docutils literal notranslate"><span class="pre">y_velocity</span></code> might be any velocity provided by the readers (currents, wind, stokes drift…) possibly scaled by the model application (e.g. 0.02 times the wind, which is often used for wind drift at ocean surface).</p>
<p>By inheritance, models may also reuse higher level advection methods inherited from their superclasses. E.g. the model <a class="reference external" href="https://opendrift.github.io/_modules/opendrift/models/oceandrift.html">OceanDrift</a>) uses very simple methods which takes care of everything needed for a correct and efficient advection:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Simply move particles with ambient current</span>
<span class="bp">self</span><span class="o">.</span><span class="n">advect_ocean_current</span><span class="p">()</span>
<span class="c1"># Advect particles due to wind drag (according to specified wind_drift_factor)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">advect_wind</span><span class="p">()</span>
</pre></div>
</div>
<p>Notice that these (convenience) methods are inherited in the specific model <a class="reference external" href="https://opendrift.github.io/_modules/opendrift/models/oceandrift.html">OceanDrift</a> from the generic model <a class="reference external" href="https://opendrift.github.io/_modules/opendrift/models/basemodel.html">OpenDriftSimulation</a>, which again inherits them from the helper class <a class="reference external" href="https://opendrift.github.io/_modules/opendrift/models/physics_methods.html">PhysicsMethods</a>).
Reusing functionality by inheritance makes it simpler and faster to develop and maintain new models and functionality.
The vertical coordinate (z) is modified e.g. by <a class="reference external" href="https://opendrift.github.io/gallery/example_vertical_mixing.html">vertical turbulence and buoyancy</a>, or by swimming in biological modules.</p>
</section>
<section id="modifying-element-properties">
<h2>2. Modifying element properties<a class="headerlink" href="#modifying-element-properties" title="Link to this heading"></a></h2>
<p>Element properties may be modified freely and directly within the method <strong>update()</strong>. The main “resources” available are the Python recarrays:</p>
<blockquote>
<div><ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">self.elements</span></code> which has any element properties (mass, length, orientation, age…) as attributes, and</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">self.environment</span></code> which has any environment variables (x_wind, y_wind, sea_water_temperature) as attributes.</p></li>
</ul>
</div></blockquote>
<p>E.g. if one (for some reason) would like to set the length of the elements equal to half of the seawater temperature:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="bp">self</span><span class="o">.</span><span class="n">elements</span><span class="o">.</span><span class="n">length</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">environment</span><span class="o">.</span><span class="n">sea_water_temperature</span> <span class="o">/</span> <span class="mi">2</span>
</pre></div>
</div>
<hr class="docutils" />
<p>Deactivation of elements must always be done with the special class method <code class="docutils literal notranslate"><span class="pre">deactivate_elements(indices,</span> <span class="pre">reason)</span></code>
Elements may be deactivated for any reason as determined by the model developer, and an arbitrary text string is provided as explanation. E.g. if one want to deactivate all elements whose mass is below, say 0.5 kg:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="bp">self</span><span class="o">.</span><span class="n">deactivate_elements</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">elements</span><span class="o">.</span><span class="n">mass</span> <span class="o"><</span> <span class="mf">0.5</span><span class="p">,</span> <span class="n">reason</span><span class="o">=</span><span class="s1">'vanished'</span><span class="p">)</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">self.elements.mass</span></code> is a numpy array with one value per element/particle, and thus <code class="docutils literal notranslate"><span class="pre">self.elements.mass</span> <span class="pre"><</span> <span class="pre">0.5</span></code> returns the indices of the elements for which the mass is below 0.5 kg (units are specified in element type declaration above).
The text string <code class="docutils literal notranslate"><span class="pre">reason</span></code> serves as an explanation of why the element was deactivated, and is used e.g. for labeling figures and when analysing results. The element property <code class="docutils literal notranslate"><span class="pre">status</span></code> will be updated accordingly, as the element is deactivated. All elements have status 0 (integer) as default, meaning <code class="docutils literal notranslate"><span class="pre">active</span></code>. Each time (in method <strong>update()</strong>) a new deactivation reason is used, the string (reason) is added to the list <code class="docutils literal notranslate"><span class="pre">status_categories</span></code>. The list of deactivation reason is also added to the metadata in exported netCDF files, e.g:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">int</span> <span class="n">status</span><span class="p">(</span><span class="n">trajectory</span><span class="p">,</span> <span class="n">time</span><span class="p">)</span> <span class="p">;</span>
<span class="n">status</span><span class="p">:</span><span class="n">flag_values</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span> <span class="p">;</span>
<span class="n">status</span><span class="p">:</span><span class="n">flag_meanings</span> <span class="o">=</span> <span class="s2">"active evaporated stranded"</span> <span class="p">;</span>
</pre></div>
</div>
<p>where one can see that elements have been deactivated for two different reasons (‘evaporated’ <strong>1</strong>, and ‘stranded’ <strong>2</strong>).</p>
</section>
</section>
</div>
</div>
<footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
<a href="choosing_a_model.html" class="btn btn-neutral float-left" title="How to choose which model to use" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
<a href="gallery/index.html" class="btn btn-neutral float-right" title="Gallery" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
</div>
<hr/>
<div role="contentinfo">
<p>© Copyright 2020, Knut-Frode Dagestad ([email protected]) and Gaute Hope ([email protected])..</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>