completor 1.3.0__py3-none-any.whl → 1.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
completor/utils.py CHANGED
@@ -5,13 +5,14 @@ from __future__ import annotations
5
5
  import re
6
6
  import sys
7
7
  from collections.abc import Mapping
8
+ from pathlib import Path
8
9
  from typing import Any
9
10
 
10
11
  import numpy as np
11
12
  import numpy.typing as npt
12
13
  import pandas as pd
13
14
 
14
- from completor.constants import Content, Headers, Keywords
15
+ from completor.constants import Content, Headers, ICVMethod, Keywords
15
16
  from completor.exceptions.clean_exceptions import CompletorError
16
17
  from completor.logger import logger
17
18
 
@@ -234,7 +235,7 @@ def check_width_lines(result: str, limit: int) -> list[tuple[int, str]]:
234
235
  cleaned_line = cleaned_line.rsplit("--")[0]
235
236
 
236
237
  if len(cleaned_line) > limit:
237
- too_long_lines.append((line_index, lines[line_index]))
238
+ too_long_lines.append((int(line_index), lines[line_index]))
238
239
  return too_long_lines
239
240
 
240
241
 
@@ -386,3 +387,133 @@ def replace_preprocessing_names(text: str, mapper: Mapping[str, str] | None) ->
386
387
  my_value = start + str(value) + end
387
388
  text = text.replace(my_key, my_value)
388
389
  return text
390
+
391
+
392
+ def sort_string_with_assign_first(input_string: str) -> str:
393
+ """Sort string such that lines starting with "ASSIGN" come before other lines preserving remaining lines.
394
+
395
+ Args:
396
+ input_string: The input string to be sorted.
397
+
398
+ Returns:
399
+ String starting with "ASSIGN" appearing before other lines.
400
+ """
401
+
402
+ assign_lines = []
403
+ other_lines = []
404
+ for line in input_string.splitlines():
405
+ if line.lstrip().startswith("ASSIGN"):
406
+ assign_lines.append(line)
407
+ elif line.strip() != "":
408
+ other_lines.append(line)
409
+
410
+ sorted_lines = assign_lines + other_lines
411
+ return "\n".join(sorted_lines) + "\n"
412
+
413
+
414
+ def reduce_newlines(data: str) -> str:
415
+ """Reduces consecutive occurrences of three or more newline characters to just two newline characters.
416
+
417
+ Args:
418
+ data: String to process.
419
+
420
+ Returns:
421
+ The processed string with reduced newline characters.
422
+ """
423
+
424
+ return re.sub(r"\n{3}", r"\n\n", data)
425
+
426
+
427
+ def remove_duplicates(data: list[str]) -> list[str]:
428
+ """Remove duplicates from a list while preserving the original order.
429
+
430
+ Exclude empty strings from the resulting list.
431
+
432
+ Args:
433
+ data: The input list.
434
+
435
+ Returns:
436
+ The data with duplicates removed inline.
437
+ """
438
+
439
+ return [x for x in dict.fromkeys(data) if x]
440
+
441
+
442
+ def insert_comment_custom_content() -> str:
443
+ """Writes a comment to schedule when loglevel is <= 10.
444
+
445
+ Returns:
446
+ A string to be inserted before the output in format:
447
+ "METHOD_NAME with step 'STEP' and criteria 'CRITERIA'."
448
+ """
449
+
450
+ if logger.level > 10:
451
+ return ""
452
+ return "\n -- This is custom content from CONTROL_CRITERIA keyword:\n"
453
+
454
+
455
+ def insert_comment(method: str | ICVMethod, step: str | int | None = None, criteria: str | int | None = None) -> str:
456
+ """Writes a comment to schedule when loglevel is <= 10.
457
+
458
+ Args:
459
+ method: The method that is producing the current output.
460
+ step: The current step (if applicable).
461
+ criteria: The current criteria (if applicable).
462
+
463
+ Returns:
464
+ A string to be inserted before the output in format:
465
+ "METHOD_NAME with step 'STEP' and criteria 'CRITERIA'."
466
+ """
467
+
468
+ if logger.level > 10:
469
+ return ""
470
+ msg = f"-- {ICVMethod(method).name}"
471
+ if step is not None:
472
+ msg += f" with step '{step}'"
473
+ if criteria is not None:
474
+ if step is None:
475
+ msg += " with"
476
+ else:
477
+ msg += " and"
478
+ msg += f" criteria '{criteria}'"
479
+ return msg + ".\n"
480
+
481
+
482
+ def icvc_keyword_in_file(path: Path | str) -> bool:
483
+ """If file contains ICV keyword.
484
+
485
+ Args:
486
+ path: Path to file to check.
487
+
488
+ Returns:
489
+ True if file contains ICV keyword.
490
+ """
491
+
492
+ path = Path(path)
493
+ with open(path, encoding="utf-8") as file:
494
+ case_file_content = file.read()
495
+
496
+ if Keywords.ICVC_KEYWORD in case_file_content:
497
+ return True
498
+ else:
499
+ return False
500
+
501
+
502
+ def completion_keyword_in_file(path: Path | str) -> bool:
503
+ """If file contains COMPLETION keyword.
504
+
505
+ Args:
506
+ path: Path to file to check.
507
+
508
+ Returns:
509
+ True if file contains COMPLETION keyword.
510
+ """
511
+
512
+ path = Path(path)
513
+ with open(path, encoding="utf-8") as file:
514
+ case_file_content = file.read()
515
+
516
+ if Keywords.COMPLETION in case_file_content:
517
+ return True
518
+ else:
519
+ return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: completor
3
- Version: 1.3.0
3
+ Version: 1.5.0
4
4
  Summary: Advanced multi-segmented well completion tool.
5
5
  Home-page: https://github.com/equinor/completor
6
6
  License: LGPL-3.0-only
@@ -16,14 +16,14 @@ Classifier: Programming Language :: Python :: 3.12
16
16
  Classifier: Programming Language :: Python :: 3.13
17
17
  Provides-Extra: ert
18
18
  Provides-Extra: test
19
- Requires-Dist: ert (>=14,<15) ; extra == "ert"
19
+ Requires-Dist: ert (>14) ; extra == "ert"
20
20
  Requires-Dist: matplotlib (>=3.9,<4.0)
21
21
  Requires-Dist: numpy (>=2.0,<3.0)
22
22
  Requires-Dist: pandas (>=2.2,<3.0)
23
23
  Requires-Dist: pytest (>=8.3,<9.0) ; extra == "test"
24
24
  Requires-Dist: pytest-env (>=1,<2) ; extra == "test"
25
25
  Requires-Dist: pytest-xdist (>=3.6,<4.0) ; extra == "test"
26
- Requires-Dist: rstcheck-core (>=1.2,<2.0) ; extra == "test"
26
+ Requires-Dist: scipy (>=1.14,<2.0)
27
27
  Requires-Dist: tqdm (>=4.66,<5.0)
28
28
  Project-URL: Bug Tracker, https://github.com/equinor/completor/issues
29
29
  Project-URL: Documentation, https://equinor.github.io/completor
@@ -76,6 +76,14 @@ This should run for some time and display a help message.
76
76
  ### Create and run your first model
77
77
  Some examples of Completor case file are available in [Examples](documentation/docs/about/examples.mdx) and detailed explanation is available in [Configuration](documentation/docs/about/configuration.mdx).
78
78
 
79
+ ### References
80
+ Some technical paper related to Completor and ICV Control applications are available to read and cite:
81
+ - Handita Sutoyo, Filippo Panini, Cuthbert Shang Wui Ng, Martin Halvorsen, Geir Elseth, Ingvild Berg Martiniussen, Corentin Cochard, Erik Johan Helland, Sean Robert Smith, and Lene Amundsen.
82
+ "Maximize Value from Inflow Control Technology Implementations Through Novel Standardized Workflow and Open-Source Modelling Tool."
83
+ Paper presented at the OTC Brasil, Rio de Janeiro, Brazil, October 2025. doi: [10.4043/36167-MS](https://doi.org/10.4043/36167-MS)
84
+ - Handita Sutoyo, Mathias Bellout, Margrete Hånes, and Rodolfo Oliveira. "Ensemble-Based Proactive Optimization using a Reactive Strategy
85
+ for ICV Control." Paper presented at the SPE Norway Subsurface Conference, Bergen, Norway, April 2024. doi: [10.2118/218472-MS](https://doi.org/10.2118/218472-MS)
86
+
79
87
  ## Getting started as a contributor
80
88
  ### Contribution guide
81
89
  We welcome all kinds of contributions, including code, bug reports, issues, feature requests, and documentation.
@@ -0,0 +1,32 @@
1
+ completor/__init__.py,sha256=k6amf7jhp7KkBIlaw93-NZITxyZjPSzA5McFAZh8yv8,76
2
+ completor/completion.py,sha256=quhQOdQREv8MsHW5amT0sG-84Y12KVdT0eylbKCul3g,31177
3
+ completor/config_jobs/run_completor,sha256=XePKj2xocfGF0XFRqr7sqfpZGrjgWcfaZLHIhVvGFCQ,600
4
+ completor/constants.py,sha256=y6nEtv-u8W-OFz84przKXVhS4as8SL8fwMMlJ38_WRA,13963
5
+ completor/create_output.py,sha256=7B3mx9xFc2Pq8Qo0GYWO3GNgylEa8pvfiHVV_3fs5Hs,26226
6
+ completor/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ completor/exceptions/clean_exceptions.py,sha256=uQ2jgGfvUDAoS56JBWh-8ZCPIMB4hvYxLF-snA-_-pg,373
8
+ completor/exceptions/exceptions.py,sha256=eS00mVzmC4gQ7MUyGSknvKotmo2XzNGyp007mhjLMy0,5081
9
+ completor/get_version.py,sha256=LMzybu7m-O203lUSZvyu86J4bMobbjE9A23fWLDlxaM,168
10
+ completor/hook_implementations/__init__.py,sha256=4tdNpVj3MNfzTMIGkp2MjP1_z3grIlwJikiA-f1a24g,104
11
+ completor/hook_implementations/forward_model_steps.py,sha256=48tKeQUE8Kx1jhxs1MCGFR_ndgciuOxe27T74qE4GQM,776
12
+ completor/hook_implementations/run_completor.py,sha256=WZhry4KmzxIaufXduYa6EO8BQHY3wNJ_gDXRRnPma6Y,2164
13
+ completor/icv_file_handling.py,sha256=PeZ6eACM38iy7smhViaV5gA8BhddPux-5psnkJeOTnY,15722
14
+ completor/icv_functions.py,sha256=yde_-FsFLG0_TXy3qk4wjDhAOSdaOzQ6elAOgXXcf3I,35156
15
+ completor/initialization.py,sha256=MyKDvvL_ZNJp_KxXivdvxndpMlrF66XU8H6vOAoaSfI,24627
16
+ completor/input_validation.py,sha256=vieorj4Onx4EZPA_nvIkpLkY3LRKS9LaIo5I0NRBC9A,16692
17
+ completor/launch_args_parser.py,sha256=gb3FcyufZlRnKS3BZkFmgVH1VoSxMD0MbCLsHZKmz4c,1413
18
+ completor/logger.py,sha256=-sIxcYfnk6CFbBP1BqZtEpnS3NVO0uxXxWx0Fw4HpSw,4791
19
+ completor/main.py,sha256=JDGnVa5CFBh-ytUUlqgMjcTbFXALEpxEyAyUnKKv-NM,12456
20
+ completor/parse.py,sha256=XUCWbhKQeBIBfj8s3p7TNsggQ3Z1euxgQ5Vet9dJIxQ,20118
21
+ completor/prepare_outputs.py,sha256=o-7SLD0F5jiw5_lnq5kewB1tYOiLa0u2TxGz6kRIO-8,87613
22
+ completor/read_casefile.py,sha256=Pxub_EzfR_5pB00pKqH9jK9EkXln7r2pLQkOE_jyASA,56248
23
+ completor/read_schedule.py,sha256=IYyCubOggFGg664h1flTl7MUJhJWyibr6JsptnURjUA,18101
24
+ completor/utils.py,sha256=1goaoJ_vZuCq_QC_BrVcI6agQp-zlzKEeGvRTfrfwQQ,17027
25
+ completor/visualization.py,sha256=ObxThqIyW3fsvVIupxVsgySFI_54n_Di-HTzFtDMSgo,4580
26
+ completor/visualize_well.py,sha256=HLglSN2ce-u9nklJelqwhSxwwaj7n-aU6o8lUScbiI0,8790
27
+ completor/wells.py,sha256=Q2detK0FxIBgusYkCRmomRIfcScBNvNTYX43GFyAHGw,12246
28
+ completor-1.5.0.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
29
+ completor-1.5.0.dist-info/METADATA,sha256=mYt9RURkbLLOSfZJKhUYSwpGfnmW3nB3flF3oZH6uF8,8863
30
+ completor-1.5.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
31
+ completor-1.5.0.dist-info/entry_points.txt,sha256=rhRKVhqh_ItG-tD5YrCfMvsGnfv-h0TXP0jX_fB6Kbc,121
32
+ completor-1.5.0.dist-info/RECORD,,
@@ -0,0 +1,6 @@
1
+ [console_scripts]
2
+ completor=completor.main:main
3
+
4
+ [ert]
5
+ run_completor=completor.hook_implementations.forward_model_steps
6
+
@@ -1,71 +0,0 @@
1
- import sys
2
- from pathlib import Path
3
-
4
- from completor.logger import logger
5
-
6
- try:
7
- from ert import plugin as ert_plugin # type: ignore
8
- except ModuleNotFoundError:
9
-
10
- def ert_plugin(name: str = ""):
11
- """Dummy decorator"""
12
-
13
- def decorator(func):
14
- return func
15
-
16
- return decorator
17
-
18
- logger.warning("Cannot import ERT, did you install Completor with ert option enabled?")
19
-
20
-
21
- def _get_jobs_from_directory(directory):
22
- resources = Path(sys.modules["completor"].__file__).parent / directory
23
-
24
- all_files = [resources / filename for filename in resources.glob("*") if (resources / filename).exists()]
25
- return {path.name: str(path) for path in all_files}
26
-
27
-
28
- @ert_plugin(name="completor")
29
- def installable_jobs():
30
- return _get_jobs_from_directory("config_jobs")
31
-
32
-
33
- @ert_plugin(name="completor")
34
- def job_documentation(job_name):
35
- if job_name != "run_completor":
36
- return None
37
-
38
- description = """Completor is a script for modelling
39
- wells with advanced completion.
40
- It generates a well schedule to be included in reservoir simulator,
41
- by combining the multi-segment tubing definition (from pre-processor reservoir modelling tools)
42
- with a user defined file specifying the completion design.
43
- The resulting well schedule comprises all keywords and parameters required by
44
- reservoir simulator. See the Completor documentation for details.
45
-
46
- Required:
47
- ---------
48
- -i : followed by name of file specifying completion design (e.g. completion.case).
49
- -s : followed by name of schedule file with multi-segment tubing definition,
50
- including COMPDAT, COMPSEGS and WELSEGS (required if not specified in case file).
51
-
52
- Optional:
53
- ---------
54
- --help : how to run completor.
55
- --about : about completor.
56
- -o : followed by name of completor output file.
57
- --figure : generates a pdf file with a schematics of the well segment structure.
58
-
59
- """
60
-
61
- examples = """.. code-block:: console
62
- FORWARD_MODEL run_completor(
63
- <CASE>=path/to/completion.case,
64
- <INPUT_SCH>=path/to/input.sch,
65
- <OUTPUT_SCH>path/to/output.sch
66
- )
67
- """
68
-
69
- category = "modelling.reservoir"
70
-
71
- return {"description": description, "examples": examples, "category": category}
@@ -1,27 +0,0 @@
1
- completor/__init__.py,sha256=k6amf7jhp7KkBIlaw93-NZITxyZjPSzA5McFAZh8yv8,76
2
- completor/completion.py,sha256=quhQOdQREv8MsHW5amT0sG-84Y12KVdT0eylbKCul3g,31177
3
- completor/config_jobs/run_completor,sha256=XePKj2xocfGF0XFRqr7sqfpZGrjgWcfaZLHIhVvGFCQ,600
4
- completor/constants.py,sha256=2e1o5Env5lHyhopkrs_C__9DksS5xml1-Ea_X3cLl0E,13521
5
- completor/create_output.py,sha256=6ygglcCUYYII5sWr_ey4cvUCCsXb0UGqXY5GQAzX8fQ,25969
6
- completor/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- completor/exceptions/clean_exceptions.py,sha256=uQ2jgGfvUDAoS56JBWh-8ZCPIMB4hvYxLF-snA-_-pg,373
8
- completor/exceptions/exceptions.py,sha256=eS00mVzmC4gQ7MUyGSknvKotmo2XzNGyp007mhjLMy0,5081
9
- completor/get_version.py,sha256=LMzybu7m-O203lUSZvyu86J4bMobbjE9A23fWLDlxaM,168
10
- completor/hook_implementations/jobs.py,sha256=8Ao8UadfJzEY7jWzj6C_OXm18fHmfXrbCB2_jS7KHiU,2180
11
- completor/input_validation.py,sha256=F17AWi-qR6cX5_1lEFgtYOMOO0Xo3gTtL2ETM5P_uGE,15022
12
- completor/launch_args_parser.py,sha256=gb3FcyufZlRnKS3BZkFmgVH1VoSxMD0MbCLsHZKmz4c,1413
13
- completor/logger.py,sha256=gYDbPL8ca5qT_MqYlDKEMKcSfIXW_59QklX8Gss5b2U,4784
14
- completor/main.py,sha256=HlQzv5gpBYdDbYTBLSkAnK7o6d2QfTQnjrNizq3Ym6s,9343
15
- completor/parse.py,sha256=EGlt9CgkrXPqa7woyWQ5t_nh6OWsFrc2SJr8aFr_KsQ,20133
16
- completor/prepare_outputs.py,sha256=o-7SLD0F5jiw5_lnq5kewB1tYOiLa0u2TxGz6kRIO-8,87613
17
- completor/read_casefile.py,sha256=NebZRrO35aqrZIJ7eHcS6buBbAaDWw8wUtc4kBHsV2U,38184
18
- completor/read_schedule.py,sha256=IYyCubOggFGg664h1flTl7MUJhJWyibr6JsptnURjUA,18101
19
- completor/utils.py,sha256=9Qayt7xMsimpoVDo5sL86gVaQBbIOezMBRyMXd3haXw,13598
20
- completor/visualization.py,sha256=ObxThqIyW3fsvVIupxVsgySFI_54n_Di-HTzFtDMSgo,4580
21
- completor/visualize_well.py,sha256=HLglSN2ce-u9nklJelqwhSxwwaj7n-aU6o8lUScbiI0,8790
22
- completor/wells.py,sha256=Q2detK0FxIBgusYkCRmomRIfcScBNvNTYX43GFyAHGw,12246
23
- completor-1.3.0.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
24
- completor-1.3.0.dist-info/METADATA,sha256=IL5-ncKANt09P_kbEZeJu0DV3YpjAS4RiFtCThhHBKM,8018
25
- completor-1.3.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
26
- completor-1.3.0.dist-info/entry_points.txt,sha256=co5L2_CC2QQWVdEALeMp-NIC4mx4nRpcLcvpVXMYdeI,106
27
- completor-1.3.0.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- [console_scripts]
2
- completor=completor.main:main
3
-
4
- [ert]
5
- run_completor=completor.hook_implementations.jobs
6
-