|
45 | 45 | </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> |
46 | 46 | <ul class="current"> |
47 | 47 | <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> |
49 | 52 | <li class="toctree-l1"><a class="reference internal" href="common.html">OPM Common Python Documentation</a></li> |
50 | 53 | <li class="toctree-l1"><a class="reference internal" href="simulators.html">OPM Simulators Python Documentation</a></li> |
51 | 54 | </ul> |
@@ -124,6 +127,115 @@ <h1>Run Python embedded in OPM Flow<a class="headerlink" href="#run-python-embed |
124 | 127 | </ul> |
125 | 128 | </li> |
126 | 129 | </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">'setup_done'</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">"""</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"> """</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">"""</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"> """</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">"""</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"> """</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"><</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">>=</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">></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">"Opened well </span><span class="si">{</span><span class="n">next_well</span><span class="si">}</span><span class="s2">"</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">"""</span> |
| 188 | +<span class="sd"> Insert the NEXTSTEP keyword to control the simulator'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"> """</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">>=</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">"""</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"> """</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">'PROD01'</span><span class="p">,</span> <span class="s1">'PROD02'</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">'P'</span><span class="p">,</span> <span class="s1">'GOPR'</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("PROD01: {}".format(schedule.get_well("PROD01", report_step).status()))</span> |
| 228 | +<span class="c1"># opm_embedded.OpmLog.info("PROD02: {}".format(schedule.get_well("PROD02", 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 | +'wellcontroller.py' / |
| 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> |
127 | 239 | </section> |
128 | 240 |
|
129 | 241 |
|
|
0 commit comments