Skip to content

Commit 3083de1

Browse files
author
lisajulia
committed
Deploying to gh-pages from @ 54e0904 🚀
1 parent dc3fdc3 commit 3083de1

6 files changed

Lines changed: 229 additions & 2 deletions

File tree

11.2 KB
Binary file not shown.
12.6 KB
Binary file not shown.

master/_sources/embedded-python.rst.txt

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,118 @@ In order to enable the PYACTION keyword:
5454
- ``current_report_step``: This is an integer for the report step we are currently working on. Observe that the PYACTION is called for every simulator timestep, i.e. it will typically be called multiple times with the same value for the report step argument.
5555

5656
- ``current_summary_state``: An instance of the `SummaryState <common.html#opm.io.sim.SummaryState>`_ class — this is where the current summary results of the simulator are stored. The `SummaryState <common.html#opm.io.sim.SummaryState>`_ class has methods to get hold of well, group, and general variables.
57+
58+
59+
Stateful behavior using Python classes
60+
--------------------------------------
61+
62+
In the below code snippet, we use a ``WellController`` class to manage production wells by tracking their status and simulation timing.
63+
We create one instance of the WellController and use its internal state across multiple timesteps and PYACTION calls.
64+
65+
.. code-block:: python
66+
67+
import opm_embedded
68+
from datetime import datetime, timedelta
69+
70+
# Check if the setup has already been done to avoid reinitialization
71+
if 'setup_done' not in locals():
72+
# Target oil production rate in standard units (e.g., stb/day)
73+
OIL_RATE_TARGET = 8000
74+
# Minimum time in days between opening new wells
75+
MIN_DAYS_BETWEEN_OPENINGS = 50
76+
77+
class WellController:
78+
"""
79+
A controller to manage the opening of production wells based on
80+
oil rate targets and elapsed simulation time.
81+
82+
Attributes:
83+
closed_wells (list[str]): List of wells yet to be opened.
84+
last_opening_time (datetime): Simulation time of the last well opening.
85+
Initially, this is set to the simulation start time.
86+
"""
87+
def __init__(self, well_names, start_time):
88+
"""
89+
Initialize the WellController.
90+
91+
Args:
92+
well_names (list[str]): Names of wells to be controlled.
93+
start_time (datetime): Simulation start time.
94+
"""
95+
self.closed_wells = list(well_names)
96+
self.last_opening_time = start_time
97+
98+
def update(self, current_oil_rate, current_time):
99+
"""
100+
Evaluate the current oil production and determine whether to open
101+
a new well based on the target rate and time since the last opening.
102+
103+
Args:
104+
current_oil_rate (float): The current oil rate.
105+
current_time (datetime): Current simulation time.
106+
"""
107+
days_since_last_opening = (current_time - self.last_opening_time).days
108+
109+
if (current_oil_rate < OIL_RATE_TARGET and
110+
days_since_last_opening >= MIN_DAYS_BETWEEN_OPENINGS and
111+
len(self.closed_wells) > 0):
112+
113+
next_well = self.closed_wells.pop(0)
114+
self.last_opening_time = current_time
115+
116+
schedule.open_well(next_well)
117+
opm_embedded.OpmLog.info(f"Opened well {next_well}")
118+
119+
def set_next_dt(self, current_time):
120+
"""
121+
Insert the NEXTSTEP keyword to control the simulator's timestep,
122+
adjusting based on whether a well was just opened.
123+
124+
Args:
125+
current_time (datetime): Current simulation time.
126+
"""
127+
if self.closed_wells:
128+
days_since_last_opening = (current_time - self.last_opening_time).days
129+
if days_since_last_opening >= MIN_DAYS_BETWEEN_OPENINGS:
130+
next_dt = 10.0
131+
else:
132+
next_dt = 50.0
133+
kw = f"""
134+
NEXTSTEP
135+
{next_dt} /
136+
"""
137+
schedule.insert_keywords(kw)
138+
139+
# Instantiate the controller with a list of wells and simulation start time
140+
# This controller will be instatiated once and be used in all following PYACTION calls.
141+
controller = WellController(well_names=['PROD01', 'PROD02'],
142+
start_time=opm_embedded.current_schedule.start)
143+
setup_done = True
144+
145+
# Retrieve current simulation components from the OPM embedded module
146+
schedule = opm_embedded.current_schedule
147+
report_step = opm_embedded.current_report_step
148+
summary_state = opm_embedded.current_summary_state
149+
150+
# Compute the current simulation time
151+
current_time = schedule.start + timedelta(seconds=summary_state.elapsed())
152+
current_oil_rate = summary_state.group_var('P', 'GOPR')
153+
154+
# Update well control logic based on current state
155+
controller.update(current_oil_rate, current_time)
156+
# Set the next simulation step duration
157+
controller.set_next_dt(current_time)
158+
159+
# Optional logs to track the status of the two wells:
160+
# opm_embedded.OpmLog.info("PROD01: {}".format(schedule.get_well("PROD01", report_step).status()))
161+
# opm_embedded.OpmLog.info("PROD02: {}".format(schedule.get_well("PROD02", report_step).status()))
162+
163+
Use this code snippet with the example `MSW-3D-TWO-PRODUCERS <https://github.com/OPM/opm-tests/blob/master/msw/MSW-3D-TWO-PRODUCERS.DATA>`_ by saving the file as ``wellcontroller.py`` at the same location as ``MSW-3D-TWO-PRODUCERS.DATA`` and adding
164+
165+
.. code-block:: none
166+
167+
PYACTION
168+
WELLCONTROLLER UNLIMITED /
169+
'wellcontroller.py' /
170+
171+
to the ``SCHEDULE`` section of ``MSW-3D-TWO-PRODUCERS.DATA``.

master/embedded-python.html

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@
4545
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
4646
<ul class="current">
4747
<li class="toctree-l1"><a class="reference internal" href="flow-in-python.html">Run OPM Flow from Python</a></li>
48-
<li class="toctree-l1 current"><a class="current reference internal" href="#">Run Python embedded in OPM Flow</a></li>
48+
<li class="toctree-l1 current"><a class="current reference internal" href="#">Run Python embedded in OPM Flow</a><ul>
49+
<li class="toctree-l2"><a class="reference internal" href="#stateful-behavior-using-python-classes">Stateful behavior using Python classes</a></li>
50+
</ul>
51+
</li>
4952
<li class="toctree-l1"><a class="reference internal" href="common.html">OPM Common Python Documentation</a></li>
5053
<li class="toctree-l1"><a class="reference internal" href="simulators.html">OPM Simulators Python Documentation</a></li>
5154
</ul>
@@ -124,6 +127,115 @@ <h1>Run Python embedded in OPM Flow<a class="headerlink" href="#run-python-embed
124127
</ul>
125128
</li>
126129
</ol>
130+
<section id="stateful-behavior-using-python-classes">
131+
<h2>Stateful behavior using Python classes<a class="headerlink" href="#stateful-behavior-using-python-classes" title="Link to this heading"></a></h2>
132+
<p>In the below code snippet, we use a <code class="docutils literal notranslate"><span class="pre">WellController</span></code> class to manage production wells by tracking their status and simulation timing.
133+
We create one instance of the WellController and use its internal state across multiple timesteps and PYACTION calls.</p>
134+
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">opm_embedded</span>
135+
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timedelta</span>
136+
137+
<span class="c1"># Check if the setup has already been done to avoid reinitialization</span>
138+
<span class="k">if</span> <span class="s1">&#39;setup_done&#39;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="nb">locals</span><span class="p">():</span>
139+
<span class="c1"># Target oil production rate in standard units (e.g., stb/day)</span>
140+
<span class="n">OIL_RATE_TARGET</span> <span class="o">=</span> <span class="mi">8000</span>
141+
<span class="c1"># Minimum time in days between opening new wells</span>
142+
<span class="n">MIN_DAYS_BETWEEN_OPENINGS</span> <span class="o">=</span> <span class="mi">50</span>
143+
144+
<span class="k">class</span> <span class="nc">WellController</span><span class="p">:</span>
145+
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
146+
<span class="sd"> A controller to manage the opening of production wells based on</span>
147+
<span class="sd"> oil rate targets and elapsed simulation time.</span>
148+
149+
<span class="sd"> Attributes:</span>
150+
<span class="sd"> closed_wells (list[str]): List of wells yet to be opened.</span>
151+
<span class="sd"> last_opening_time (datetime): Simulation time of the last well opening.</span>
152+
<span class="sd"> Initially, this is set to the simulation start time.</span>
153+
<span class="sd"> &quot;&quot;&quot;</span>
154+
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">well_names</span><span class="p">,</span> <span class="n">start_time</span><span class="p">):</span>
155+
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
156+
<span class="sd"> Initialize the WellController.</span>
157+
158+
<span class="sd"> Args:</span>
159+
<span class="sd"> well_names (list[str]): Names of wells to be controlled.</span>
160+
<span class="sd"> start_time (datetime): Simulation start time.</span>
161+
<span class="sd"> &quot;&quot;&quot;</span>
162+
<span class="bp">self</span><span class="o">.</span><span class="n">closed_wells</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">well_names</span><span class="p">)</span>
163+
<span class="bp">self</span><span class="o">.</span><span class="n">last_opening_time</span> <span class="o">=</span> <span class="n">start_time</span>
164+
165+
<span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">current_oil_rate</span><span class="p">,</span> <span class="n">current_time</span><span class="p">):</span>
166+
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
167+
<span class="sd"> Evaluate the current oil production and determine whether to open</span>
168+
<span class="sd"> a new well based on the target rate and time since the last opening.</span>
169+
170+
<span class="sd"> Args:</span>
171+
<span class="sd"> current_oil_rate (float): The current oil rate.</span>
172+
<span class="sd"> current_time (datetime): Current simulation time.</span>
173+
<span class="sd"> &quot;&quot;&quot;</span>
174+
<span class="n">days_since_last_opening</span> <span class="o">=</span> <span class="p">(</span><span class="n">current_time</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">last_opening_time</span><span class="p">)</span><span class="o">.</span><span class="n">days</span>
175+
176+
<span class="k">if</span> <span class="p">(</span><span class="n">current_oil_rate</span> <span class="o">&lt;</span> <span class="n">OIL_RATE_TARGET</span> <span class="ow">and</span>
177+
<span class="n">days_since_last_opening</span> <span class="o">&gt;=</span> <span class="n">MIN_DAYS_BETWEEN_OPENINGS</span> <span class="ow">and</span>
178+
<span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">closed_wells</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">):</span>
179+
180+
<span class="n">next_well</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">closed_wells</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
181+
<span class="bp">self</span><span class="o">.</span><span class="n">last_opening_time</span> <span class="o">=</span> <span class="n">current_time</span>
182+
183+
<span class="n">schedule</span><span class="o">.</span><span class="n">open_well</span><span class="p">(</span><span class="n">next_well</span><span class="p">)</span>
184+
<span class="n">opm_embedded</span><span class="o">.</span><span class="n">OpmLog</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Opened well </span><span class="si">{</span><span class="n">next_well</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
185+
186+
<span class="k">def</span> <span class="nf">set_next_dt</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">current_time</span><span class="p">):</span>
187+
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
188+
<span class="sd"> Insert the NEXTSTEP keyword to control the simulator&#39;s timestep,</span>
189+
<span class="sd"> adjusting based on whether a well was just opened.</span>
190+
191+
<span class="sd"> Args:</span>
192+
<span class="sd"> current_time (datetime): Current simulation time.</span>
193+
<span class="sd"> &quot;&quot;&quot;</span>
194+
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">closed_wells</span><span class="p">:</span>
195+
<span class="n">days_since_last_opening</span> <span class="o">=</span> <span class="p">(</span><span class="n">current_time</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">last_opening_time</span><span class="p">)</span><span class="o">.</span><span class="n">days</span>
196+
<span class="k">if</span> <span class="n">days_since_last_opening</span> <span class="o">&gt;=</span> <span class="n">MIN_DAYS_BETWEEN_OPENINGS</span><span class="p">:</span>
197+
<span class="n">next_dt</span> <span class="o">=</span> <span class="mf">10.0</span>
198+
<span class="k">else</span><span class="p">:</span>
199+
<span class="n">next_dt</span> <span class="o">=</span> <span class="mf">50.0</span>
200+
<span class="n">kw</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;&quot;&quot;</span>
201+
<span class="s2"> NEXTSTEP</span>
202+
<span class="s2"> </span><span class="si">{</span><span class="n">next_dt</span><span class="si">}</span><span class="s2"> /</span>
203+
<span class="s2"> &quot;&quot;&quot;</span>
204+
<span class="n">schedule</span><span class="o">.</span><span class="n">insert_keywords</span><span class="p">(</span><span class="n">kw</span><span class="p">)</span>
205+
206+
<span class="c1"># Instantiate the controller with a list of wells and simulation start time</span>
207+
<span class="c1"># This controller will be instatiated once and be used in all following PYACTION calls.</span>
208+
<span class="n">controller</span> <span class="o">=</span> <span class="n">WellController</span><span class="p">(</span><span class="n">well_names</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;PROD01&#39;</span><span class="p">,</span> <span class="s1">&#39;PROD02&#39;</span><span class="p">],</span>
209+
<span class="n">start_time</span><span class="o">=</span><span class="n">opm_embedded</span><span class="o">.</span><span class="n">current_schedule</span><span class="o">.</span><span class="n">start</span><span class="p">)</span>
210+
<span class="n">setup_done</span> <span class="o">=</span> <span class="kc">True</span>
211+
212+
<span class="c1"># Retrieve current simulation components from the OPM embedded module</span>
213+
<span class="n">schedule</span> <span class="o">=</span> <span class="n">opm_embedded</span><span class="o">.</span><span class="n">current_schedule</span>
214+
<span class="n">report_step</span> <span class="o">=</span> <span class="n">opm_embedded</span><span class="o">.</span><span class="n">current_report_step</span>
215+
<span class="n">summary_state</span> <span class="o">=</span> <span class="n">opm_embedded</span><span class="o">.</span><span class="n">current_summary_state</span>
216+
217+
<span class="c1"># Compute the current simulation time</span>
218+
<span class="n">current_time</span> <span class="o">=</span> <span class="n">schedule</span><span class="o">.</span><span class="n">start</span> <span class="o">+</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">seconds</span><span class="o">=</span><span class="n">summary_state</span><span class="o">.</span><span class="n">elapsed</span><span class="p">())</span>
219+
<span class="n">current_oil_rate</span> <span class="o">=</span> <span class="n">summary_state</span><span class="o">.</span><span class="n">group_var</span><span class="p">(</span><span class="s1">&#39;P&#39;</span><span class="p">,</span> <span class="s1">&#39;GOPR&#39;</span><span class="p">)</span>
220+
221+
<span class="c1"># Update well control logic based on current state</span>
222+
<span class="n">controller</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">current_oil_rate</span><span class="p">,</span> <span class="n">current_time</span><span class="p">)</span>
223+
<span class="c1"># Set the next simulation step duration</span>
224+
<span class="n">controller</span><span class="o">.</span><span class="n">set_next_dt</span><span class="p">(</span><span class="n">current_time</span><span class="p">)</span>
225+
226+
<span class="c1"># Optional logs to track the status of the two wells:</span>
227+
<span class="c1"># opm_embedded.OpmLog.info(&quot;PROD01: {}&quot;.format(schedule.get_well(&quot;PROD01&quot;, report_step).status()))</span>
228+
<span class="c1"># opm_embedded.OpmLog.info(&quot;PROD02: {}&quot;.format(schedule.get_well(&quot;PROD02&quot;, report_step).status()))</span>
229+
</pre></div>
230+
</div>
231+
<p>Use this code snippet with the example <a class="reference external" href="https://github.com/OPM/opm-tests/blob/master/msw/MSW-3D-TWO-PRODUCERS.DATA">MSW-3D-TWO-PRODUCERS</a> by saving the file as <code class="docutils literal notranslate"><span class="pre">wellcontroller.py</span></code> at the same location as <code class="docutils literal notranslate"><span class="pre">MSW-3D-TWO-PRODUCERS.DATA</span></code> and adding</p>
232+
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>PYACTION
233+
WELLCONTROLLER UNLIMITED /
234+
&#39;wellcontroller.py&#39; /
235+
</pre></div>
236+
</div>
237+
<p>to the <code class="docutils literal notranslate"><span class="pre">SCHEDULE</span></code> section of <code class="docutils literal notranslate"><span class="pre">MSW-3D-TWO-PRODUCERS.DATA</span></code>.</p>
238+
</section>
127239
</section>
128240

129241

master/searchindex.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)