primo-optimizer 0.1__tar.gz
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.
Potentially problematic release.
This version of primo-optimizer might be problematic. Click here for more details.
- primo_optimizer-0.1/LICENSE.md +39 -0
- primo_optimizer-0.1/PKG-INFO +68 -0
- primo_optimizer-0.1/README.md +58 -0
- primo_optimizer-0.1/primo/__init__.py +13 -0
- primo_optimizer-0.1/primo/data_parser/__init__.py +10 -0
- primo_optimizer-0.1/primo/data_parser/data_model.py +197 -0
- primo_optimizer-0.1/primo/data_parser/input_parser.py +161 -0
- primo_optimizer-0.1/primo/opt_model/__init__.py +13 -0
- primo_optimizer-0.1/primo/opt_model/base_model.py +188 -0
- primo_optimizer-0.1/primo/opt_model/opt_model.py +583 -0
- primo_optimizer-0.1/primo/opt_model/tests/__init__.py +13 -0
- primo_optimizer-0.1/primo/opt_model/tests/test_base_model.py +120 -0
- primo_optimizer-0.1/primo/opt_model/tests/test_opt_model.py +137 -0
- primo_optimizer-0.1/primo/utils/__init__.py +40 -0
- primo_optimizer-0.1/primo/utils/census_utils.py +475 -0
- primo_optimizer-0.1/primo/utils/clustering_utils.py +111 -0
- primo_optimizer-0.1/primo/utils/config_utils.py +518 -0
- primo_optimizer-0.1/primo/utils/demo_utils.py +614 -0
- primo_optimizer-0.1/primo/utils/download_utils.py +73 -0
- primo_optimizer-0.1/primo/utils/elevation_utils.py +269 -0
- primo_optimizer-0.1/primo/utils/estimation_utils.py +346 -0
- primo_optimizer-0.1/primo/utils/geo_utils.py +335 -0
- primo_optimizer-0.1/primo/utils/kpi_utils.py +269 -0
- primo_optimizer-0.1/primo/utils/map_utils.py +536 -0
- primo_optimizer-0.1/primo/utils/multiple_scenario_util.py +97 -0
- primo_optimizer-0.1/primo/utils/opt_utils.py +165 -0
- primo_optimizer-0.1/primo/utils/proximity_utils.py +180 -0
- primo_optimizer-0.1/primo/utils/raise_exception.py +42 -0
- primo_optimizer-0.1/primo/utils/setup_arg_parser.py +144 -0
- primo_optimizer-0.1/primo/utils/setup_logger.py +86 -0
- primo_optimizer-0.1/primo/utils/solvers.py +156 -0
- primo_optimizer-0.1/primo/utils/tests/__init__.py +10 -0
- primo_optimizer-0.1/primo/utils/tests/test_census_utils.py +92 -0
- primo_optimizer-0.1/primo/utils/tests/test_clustering_utils.py +142 -0
- primo_optimizer-0.1/primo/utils/tests/test_config_utils.py +111 -0
- primo_optimizer-0.1/primo/utils/tests/test_demo_utils.py +422 -0
- primo_optimizer-0.1/primo/utils/tests/test_elevation_utils.py +152 -0
- primo_optimizer-0.1/primo/utils/tests/test_estimation_utils.py +388 -0
- primo_optimizer-0.1/primo/utils/tests/test_geo_utils.py +47 -0
- primo_optimizer-0.1/primo/utils/tests/test_headers.py +71 -0
- primo_optimizer-0.1/primo/utils/tests/test_imports.py +12 -0
- primo_optimizer-0.1/primo/utils/tests/test_kpi_utils.py +213 -0
- primo_optimizer-0.1/primo/utils/tests/test_map_utils.py +574 -0
- primo_optimizer-0.1/primo/utils/tests/test_proximity_utils.py +71 -0
- primo_optimizer-0.1/primo/utils/tests/weights_toy_example.xlsx +0 -0
- primo_optimizer-0.1/primo_optimizer.egg-info/PKG-INFO +68 -0
- primo_optimizer-0.1/primo_optimizer.egg-info/SOURCES.txt +52 -0
- primo_optimizer-0.1/primo_optimizer.egg-info/dependency_links.txt +1 -0
- primo_optimizer-0.1/primo_optimizer.egg-info/entry_points.txt +2 -0
- primo_optimizer-0.1/primo_optimizer.egg-info/requires.txt +36 -0
- primo_optimizer-0.1/primo_optimizer.egg-info/top_level.txt +2 -0
- primo_optimizer-0.1/setup.cfg +4 -0
- primo_optimizer-0.1/setup.py +136 -0
- primo_optimizer-0.1/stagedfright.py +367 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
License
|
|
2
|
+
=======
|
|
3
|
+
|
|
4
|
+
PRIMO - The P&A Project Optimizer Toolkit Copyright (c) 2023---2026, by the software owners: KeyLogic Systems, LLC.
|
|
5
|
+
All rights reserved.
|
|
6
|
+
|
|
7
|
+
Redistribution and use in source and binary forms, with or without
|
|
8
|
+
modification, are permitted provided that the following conditions are met:
|
|
9
|
+
|
|
10
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
11
|
+
list of conditions and the following disclaimer.
|
|
12
|
+
|
|
13
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
14
|
+
this list of conditions and the following disclaimer in the documentation
|
|
15
|
+
and/or other materials provided with the distribution.
|
|
16
|
+
|
|
17
|
+
3. Neither the name of the U.S. Dept. of Energy, National Energy Technology Laboratory, KeyLogic Systems, LLC, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
29
|
+
|
|
30
|
+
You are under no obligation whatsoever to provide any bug fixes, patches, or
|
|
31
|
+
upgrades to the features, functionality or performance of the source code
|
|
32
|
+
("Enhancements") to anyone; however, if you choose to make your Enhancements
|
|
33
|
+
available either publicly, or directly to National Energy Technology Laboratory,
|
|
34
|
+
or directly to KeyLogic Systems, LLC, without imposing a separate written license
|
|
35
|
+
agreement for such Enhancements, then you hereby grant National Energy Technology Laboratory
|
|
36
|
+
and KeyLogic Systems, LLC the following license: a non-exclusive, royalty-free perpetual
|
|
37
|
+
license to install, use, modify, prepare derivative works, incorporate into other computer software,
|
|
38
|
+
distribute, and sublicense such enhancements or derivative works thereof, in
|
|
39
|
+
binary and source code form.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: primo-optimizer
|
|
3
|
+
Version: 0.1
|
|
4
|
+
Summary: PRIMO - The P&A Project Optimizer
|
|
5
|
+
Home-page: https://edx.netl.doe.gov/nemri/
|
|
6
|
+
Author: PRIMO team
|
|
7
|
+
Maintainer: Miguel Zamarripa
|
|
8
|
+
Maintainer-email: Miguel.Zamarripa-Perez@netl.doe.gov
|
|
9
|
+
License: BSD
|
|
10
|
+
Keywords: PRIMO,MERP,NEMRI,methane emissions,optimization,process modeling,operations research,well plugging
|
|
11
|
+
Platform: windows
|
|
12
|
+
Platform: linux
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
17
|
+
Classifier: Natural Language :: English
|
|
18
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
19
|
+
Classifier: Operating System :: Unix
|
|
20
|
+
Classifier: Programming Language :: Python
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
26
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
27
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
28
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
29
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
30
|
+
Requires-Python: >=3.8, <=4.0
|
|
31
|
+
Description-Content-Type: text/plain
|
|
32
|
+
License-File: LICENSE.md
|
|
33
|
+
Requires-Dist: appengine-python-standard
|
|
34
|
+
Requires-Dist: censusgeocode
|
|
35
|
+
Requires-Dist: folium
|
|
36
|
+
Requires-Dist: geopandas
|
|
37
|
+
Requires-Dist: gurobipy
|
|
38
|
+
Requires-Dist: highspy
|
|
39
|
+
Requires-Dist: haversine
|
|
40
|
+
Requires-Dist: ipyfilechooser
|
|
41
|
+
Requires-Dist: ipyleaflet
|
|
42
|
+
Requires-Dist: ipywidgets
|
|
43
|
+
Requires-Dist: kneed
|
|
44
|
+
Requires-Dist: matplotlib
|
|
45
|
+
Requires-Dist: notebook
|
|
46
|
+
Requires-Dist: numpy<=1.28
|
|
47
|
+
Requires-Dist: openpyxl
|
|
48
|
+
Requires-Dist: pandas
|
|
49
|
+
Requires-Dist: pyarrow
|
|
50
|
+
Requires-Dist: pyomo
|
|
51
|
+
Requires-Dist: pyscipopt
|
|
52
|
+
Requires-Dist: python-dotenv
|
|
53
|
+
Requires-Dist: scikit-learn
|
|
54
|
+
Requires-Dist: rasterio
|
|
55
|
+
Requires-Dist: xlsxwriter
|
|
56
|
+
Provides-Extra: dev
|
|
57
|
+
Requires-Dist: addheader; extra == "dev"
|
|
58
|
+
Requires-Dist: black; extra == "dev"
|
|
59
|
+
Requires-Dist: myst-parser; extra == "dev"
|
|
60
|
+
Requires-Dist: nbsphinx; extra == "dev"
|
|
61
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
62
|
+
Requires-Dist: sphinx; extra == "dev"
|
|
63
|
+
Requires-Dist: sphinx-rtd-theme; extra == "dev"
|
|
64
|
+
Provides-Extra: test
|
|
65
|
+
Requires-Dist: pytest; extra == "test"
|
|
66
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
67
|
+
|
|
68
|
+
PRIMO - The P&A Project Optimizer toolkit was produced under the Methane Emissions Reduction Program (MERP) and National Energy Technology Laboratory's (NETL) National Emissions Reduction Initiative (NEMRI). The major deliverable of this project will be an open-source, optimization-based, downloadable and executable decision-support application, PRIMO, that can be run by companies, technology providers, research organizations, and regulators.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# PRIMO - The P&A Project Optimizer Toolkit
|
|
2
|
+
|
|
3
|
+
PRIMO - The P&A Project Optimizer Toolkit aims to provide multi-scale, simulation-based, open source
|
|
4
|
+
computational tools and models to support the Methane Emissions Reduction Program (MERP) and the National
|
|
5
|
+
Emissions Reduction Initiative (NEMRI).
|
|
6
|
+
|
|
7
|
+
## Getting Started
|
|
8
|
+
|
|
9
|
+
Our complete documentation is currently being built, but here is a summarized set of steps to get started using the framework.
|
|
10
|
+
|
|
11
|
+
While not required, we encourage the installation of [Anaconda](https://www.anaconda.com/products/individual#Downloads) or [Miniconda](https://docs.conda.io/en/latest/miniconda.html) and using the `conda` command to create a separate python environment in which to install the PRIMO Toolkit.
|
|
12
|
+
|
|
13
|
+
Use conda to create a new "primo-env" (could be any name you like) environment then activate that environment:
|
|
14
|
+
```bash
|
|
15
|
+
conda create --name primo-env python
|
|
16
|
+
conda activate primo-env
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Install all dependencies with:
|
|
20
|
+
```
|
|
21
|
+
pip install -r requirements.txt
|
|
22
|
+
```
|
|
23
|
+
For developers, install dependencies with:
|
|
24
|
+
```
|
|
25
|
+
pip install -r requirements-dev.txt
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
For users interested in using the free solver SCIP to solve PRIMO's optimization problems, please run:
|
|
29
|
+
```
|
|
30
|
+
conda install -c conda-forge -y scip=9.1.0
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
To test the installation of the primo package, execute:
|
|
34
|
+
```
|
|
35
|
+
pytest primo\utils\tests\test_imports.py
|
|
36
|
+
```
|
|
37
|
+
The above test, if executed successfully, confirms that primo package is now installed and available in the "primo-env" package that was just created.
|
|
38
|
+
|
|
39
|
+
To use the utilities implemented in the PRIMO package that query the U.S. Census API and Bing Maps API, appropriate API keys must be obtained
|
|
40
|
+
by signing up with the respective services. These keys must be configured in a .env file in the parent directory. For more details, please see:
|
|
41
|
+
[API Keys](TBD)
|
|
42
|
+
|
|
43
|
+
Users can also employ other commercial solvers, for example Gurobi, to solve the optimization problem.
|
|
44
|
+
However, users are responsible for configuring and setting up these solvers themselves
|
|
45
|
+
|
|
46
|
+
General, background and overview information is available at the [NEMRI website](https://edx.netl.doe.gov/nemri/).
|
|
47
|
+
|
|
48
|
+
## Funding acknowledgements
|
|
49
|
+
|
|
50
|
+
This work was conducted as part of the [National Emissions Reduction Initiative](https://edx.netl.doe.gov/nemri/)
|
|
51
|
+
with support through the [Environmental Protection Agency - Methane Emissions Reduction Program](https://www.epa.gov/inflation-reduction-act/methane-emissions-reduction-program)
|
|
52
|
+
within the U.S. Department of Energy’s [Office of Fossil Energy and Carbon Management (FECM)](https://www.energy.gov/fecm/office-fossil-energy-and-carbon-management).
|
|
53
|
+
As of 2023, additional support was provided by FECM’s [Solid Oxide Fuel Cell Program](https://www.energy.gov/fecm/science-innovation/clean-coal-research/solid-oxide-fuel-cells),
|
|
54
|
+
and [Transformative Power Generation Program](https://www.energy.gov/fecm/science-innovation/office-clean-coal-and-carbon-management/advanced-energy-systems/transformative).
|
|
55
|
+
|
|
56
|
+
## Contributing
|
|
57
|
+
|
|
58
|
+
**By contributing to this repository, you are agreeing to all the terms set out in the LICENSE.md and COPYRIGHT.md files in this directory.**
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#################################################################################
|
|
2
|
+
# PRIMO - The P&A Project Optimizer was produced under the Methane Emissions Reduction Program (MERP)
|
|
3
|
+
# and National Energy Technology Laboratory's (NETL) National Emissions Reduction Initiative (NEMRI).
|
|
4
|
+
#
|
|
5
|
+
# NOTICE. This Software was developed under funding from the U.S. Government and the U.S.
|
|
6
|
+
# Government consequently retains certain rights. As such, the U.S. Government has been granted for
|
|
7
|
+
# itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license in
|
|
8
|
+
# the Software to reproduce, distribute copies to the public, prepare derivative works, and perform
|
|
9
|
+
# publicly and display publicly, and to permit others to do so.
|
|
10
|
+
#################################################################################
|
|
11
|
+
|
|
12
|
+
RELEASE = "0.1.dev0"
|
|
13
|
+
VERSION = "0.1"
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#################################################################################
|
|
2
|
+
# PRIMO - The P&A Project Optimizer was produced under the Methane Emissions Reduction Program (MERP)
|
|
3
|
+
# and National Energy Technology Laboratory's (NETL) National Emissions Reduction Initiative (NEMRI).
|
|
4
|
+
#
|
|
5
|
+
# NOTICE. This Software was developed under funding from the U.S. Government and the U.S.
|
|
6
|
+
# Government consequently retains certain rights. As such, the U.S. Government has been granted for
|
|
7
|
+
# itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license in
|
|
8
|
+
# the Software to reproduce, distribute copies to the public, prepare derivative works, and perform
|
|
9
|
+
# publicly and display publicly, and to permit others to do so.
|
|
10
|
+
#################################################################################
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#################################################################################
|
|
2
|
+
# PRIMO - The P&A Project Optimizer was produced under the Methane Emissions Reduction Program (MERP)
|
|
3
|
+
# and National Energy Technology Laboratory's (NETL) National Emissions Reduction Initiative (NEMRI).
|
|
4
|
+
#
|
|
5
|
+
# NOTICE. This Software was developed under funding from the U.S. Government and the U.S.
|
|
6
|
+
# Government consequently retains certain rights. As such, the U.S. Government has been granted for
|
|
7
|
+
# itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license in
|
|
8
|
+
# the Software to reproduce, distribute copies to the public, prepare derivative works, and perform
|
|
9
|
+
# publicly and display publicly, and to permit others to do so.
|
|
10
|
+
#################################################################################
|
|
11
|
+
|
|
12
|
+
# Standard lib
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
import logging
|
|
16
|
+
from typing import Dict, Union
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# User defined lib
|
|
20
|
+
from primo.utils.geo_utils import get_distance
|
|
21
|
+
from primo.utils.raise_exception import raise_exception
|
|
22
|
+
|
|
23
|
+
LOGGER = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
# TODO: Write tests for entire module
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
class Well:
|
|
30
|
+
"""
|
|
31
|
+
A Well dataclass
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
__slots__ = (
|
|
35
|
+
"well_id",
|
|
36
|
+
"lat",
|
|
37
|
+
"long",
|
|
38
|
+
"score",
|
|
39
|
+
"is_disadvantaged",
|
|
40
|
+
)
|
|
41
|
+
well_id: str
|
|
42
|
+
lat: Union[float, None]
|
|
43
|
+
long: Union[float, None]
|
|
44
|
+
score: float
|
|
45
|
+
is_disadvantaged: bool
|
|
46
|
+
|
|
47
|
+
def haversine_distance(self, other_well: Well) -> float:
|
|
48
|
+
"""
|
|
49
|
+
Returns the distance in miles between two wells calculated with Haversine formula.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
other_well : Well
|
|
54
|
+
The other well under consideration
|
|
55
|
+
|
|
56
|
+
Returns
|
|
57
|
+
-------
|
|
58
|
+
distance : float
|
|
59
|
+
The distance between self and other_well
|
|
60
|
+
"""
|
|
61
|
+
origin = (self.lat, self.long)
|
|
62
|
+
dest = (other_well.lat, other_well.long)
|
|
63
|
+
return get_distance(origin, dest)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass(frozen=True)
|
|
67
|
+
class CampaignCandidates:
|
|
68
|
+
"""
|
|
69
|
+
A dataclass that combines wells that are potential candidates to be included
|
|
70
|
+
in a plugging campaign
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
__slots__ = ("campaign_id", "well_dict", "n_wells")
|
|
74
|
+
campaign_id: str
|
|
75
|
+
well_dict: Dict[str, Well]
|
|
76
|
+
n_wells: int
|
|
77
|
+
|
|
78
|
+
def __post_init__(self):
|
|
79
|
+
"""
|
|
80
|
+
Run some validation checks
|
|
81
|
+
"""
|
|
82
|
+
for well_id, well in self.well_dict.items():
|
|
83
|
+
if well_id != well.well_id:
|
|
84
|
+
msg = (
|
|
85
|
+
f"Dictionary for {self.campaign_id} is corrupted. Expect key "
|
|
86
|
+
"to be the same as well_id"
|
|
87
|
+
)
|
|
88
|
+
raise_exception(msg, ValueError)
|
|
89
|
+
|
|
90
|
+
if self.n_wells != len(self.well_dict):
|
|
91
|
+
LOGGER.warning(
|
|
92
|
+
f"{self.n_wells} incorrectly initialized for {self.campaign_id}"
|
|
93
|
+
)
|
|
94
|
+
LOGGER.warning("Automatically correcting!")
|
|
95
|
+
self.n_wells = len(self.well_dict)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@dataclass(frozen=True)
|
|
99
|
+
class OptInputs:
|
|
100
|
+
"""
|
|
101
|
+
Succinctly captures all inputs relevant to the optimization model
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
__slots__ = (
|
|
105
|
+
"well_dict",
|
|
106
|
+
"campaign_candidates",
|
|
107
|
+
"budget",
|
|
108
|
+
"mobilization_cost",
|
|
109
|
+
"owner_well_count",
|
|
110
|
+
"max_wells_per_owner",
|
|
111
|
+
"dac_budget_fraction",
|
|
112
|
+
"distance_threshold",
|
|
113
|
+
)
|
|
114
|
+
well_dict: Dict[str, Well]
|
|
115
|
+
campaign_candidates: Dict[str, CampaignCandidates]
|
|
116
|
+
budget: float
|
|
117
|
+
mobilization_cost: Dict[int, float]
|
|
118
|
+
owner_well_count: Dict[str, Well]
|
|
119
|
+
max_wells_per_owner: float
|
|
120
|
+
dac_budget_fraction: float
|
|
121
|
+
distance_threshold: float
|
|
122
|
+
|
|
123
|
+
def __post_init__(self):
|
|
124
|
+
"""
|
|
125
|
+
Run some validation checks
|
|
126
|
+
"""
|
|
127
|
+
# Create a set to retrieve unique well_id (identifiers that do not repeat).
|
|
128
|
+
well_id_set = set(self.well_dict.keys())
|
|
129
|
+
|
|
130
|
+
if self.budget <= 0:
|
|
131
|
+
msg = f"Budget cannot be negative. Received " f"{self.budget} for budget."
|
|
132
|
+
raise_exception(msg, ValueError)
|
|
133
|
+
|
|
134
|
+
for well_id, well in self.well_dict.items():
|
|
135
|
+
if well_id != well.well_id:
|
|
136
|
+
msg = (
|
|
137
|
+
f"Dictionary for optimization inputs corrupted. "
|
|
138
|
+
f"Expect key: {well_id} to be the same as"
|
|
139
|
+
f" well_id: {well.well_id}"
|
|
140
|
+
)
|
|
141
|
+
raise_exception(msg, ValueError)
|
|
142
|
+
|
|
143
|
+
max_wells = 0
|
|
144
|
+
# Iterate through each campaign using its campaign_id.
|
|
145
|
+
for campaign_id, campaign in self.campaign_candidates.items():
|
|
146
|
+
# Lines 167-173 aim to verify the accuracy of the
|
|
147
|
+
# campaign_candidates construction.
|
|
148
|
+
if campaign_id != campaign.campaign_id:
|
|
149
|
+
msg = (
|
|
150
|
+
f"Dictionary of candidates corrupted. "
|
|
151
|
+
f"Expect key: {campaign_id} to be the same as "
|
|
152
|
+
f"campaign_id: {campaign.campaign_id}"
|
|
153
|
+
)
|
|
154
|
+
raise_exception(msg, ValueError)
|
|
155
|
+
|
|
156
|
+
for well_id in campaign.well_dict:
|
|
157
|
+
# Lines 178-183 aim to verify whether the wells in CampaignCandidates
|
|
158
|
+
# are all sourced from the input well data.
|
|
159
|
+
if well_id not in self.well_dict:
|
|
160
|
+
msg = (
|
|
161
|
+
f"Campaign candidate: {campaign_id} includes well: {well_id}"
|
|
162
|
+
f". This well is not provided in well_dict"
|
|
163
|
+
)
|
|
164
|
+
raise_exception(msg, ValueError)
|
|
165
|
+
|
|
166
|
+
# Lines 187-190 aim to check if a well appears more than once within
|
|
167
|
+
# the same campaign or across different campaigns.
|
|
168
|
+
if well_id not in well_id_set:
|
|
169
|
+
msg = f"Well: {well_id} is included in multiple clusters (campaign candidates)."
|
|
170
|
+
raise_exception(msg, ValueError)
|
|
171
|
+
well_id_set.remove(well_id)
|
|
172
|
+
# Remove a well_id from the well_id_set the first time it is checked. If the well_id
|
|
173
|
+
# appears a second time and has already been removed from the unique well_id_set,
|
|
174
|
+
# an error message on line 188 will be raised.
|
|
175
|
+
# Each cluster represents a campaign candidate.
|
|
176
|
+
|
|
177
|
+
max_wells = max(max_wells, len(campaign.well_dict))
|
|
178
|
+
|
|
179
|
+
# Upon iterating through all campaigns and well_ids within those campaigns, all
|
|
180
|
+
# well_ids in well_id_set should be dropped. If not, it indicates that not all wells
|
|
181
|
+
# are assigned to a cluster during the clustering step. An error message will be raised at
|
|
182
|
+
# Line 202.
|
|
183
|
+
if well_id_set:
|
|
184
|
+
msg = "The clustering is not exhaustive."
|
|
185
|
+
raise_exception(msg, ValueError)
|
|
186
|
+
for n_wells in range(1, max_wells + 1):
|
|
187
|
+
cost = self.mobilization_cost.get(n_wells)
|
|
188
|
+
if cost is None:
|
|
189
|
+
msg = f"Mobilization cost for n_wells: {n_wells} is missing"
|
|
190
|
+
raise_exception(msg, ValueError)
|
|
191
|
+
|
|
192
|
+
if cost < 0:
|
|
193
|
+
msg = (
|
|
194
|
+
f"Mobilization cost for campaign with n_wells: {n_wells}"
|
|
195
|
+
f" is negative: {cost}"
|
|
196
|
+
)
|
|
197
|
+
raise_exception(msg, ValueError)
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#################################################################################
|
|
2
|
+
# PRIMO - The P&A Project Optimizer was produced under the Methane Emissions Reduction Program (MERP)
|
|
3
|
+
# and National Energy Technology Laboratory's (NETL) National Emissions Reduction Initiative (NEMRI).
|
|
4
|
+
#
|
|
5
|
+
# NOTICE. This Software was developed under funding from the U.S. Government and the U.S.
|
|
6
|
+
# Government consequently retains certain rights. As such, the U.S. Government has been granted for
|
|
7
|
+
# itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license in
|
|
8
|
+
# the Software to reproduce, distribute copies to the public, prepare derivative works, and perform
|
|
9
|
+
# publicly and display publicly, and to permit others to do so.
|
|
10
|
+
#################################################################################
|
|
11
|
+
|
|
12
|
+
# Standard libs
|
|
13
|
+
import argparse
|
|
14
|
+
import logging
|
|
15
|
+
import os
|
|
16
|
+
from typing import Dict
|
|
17
|
+
|
|
18
|
+
# Installed libs
|
|
19
|
+
import pandas as pd
|
|
20
|
+
|
|
21
|
+
# User-defined libs
|
|
22
|
+
from primo.data_parser.data_model import CampaignCandidates, OptInputs, Well
|
|
23
|
+
from primo.utils.raise_exception import raise_exception
|
|
24
|
+
|
|
25
|
+
LOGGER = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class InputParser:
|
|
29
|
+
"""
|
|
30
|
+
InputParser class
|
|
31
|
+
Implements methods for parsing input data from csv
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(self, args: argparse.Namespace):
|
|
35
|
+
"""
|
|
36
|
+
Initialize the class and read in a CSV file.
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
args : argparse.Namespace
|
|
41
|
+
The arguments parsed from the command line.
|
|
42
|
+
|
|
43
|
+
Raises
|
|
44
|
+
------
|
|
45
|
+
ValueError
|
|
46
|
+
If the specified file does not exist or is not a CSV file.
|
|
47
|
+
"""
|
|
48
|
+
file_path = args.input_file
|
|
49
|
+
# Check 1: Check file exists
|
|
50
|
+
if not os.path.exists(file_path):
|
|
51
|
+
raise_exception(f"File: {file_path} does not exist.", ValueError)
|
|
52
|
+
|
|
53
|
+
# Check 2: Check file is a csv file
|
|
54
|
+
if file_path.suffix != ".csv":
|
|
55
|
+
raise_exception(
|
|
56
|
+
f"File: {file_path} is expected to be an csv file", ValueError
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
self.well_data = pd.read_csv(file_path)
|
|
60
|
+
self.args = args
|
|
61
|
+
LOGGER.info(f"Initialized class and read file: {file_path}")
|
|
62
|
+
|
|
63
|
+
def parse_data(
|
|
64
|
+
self,
|
|
65
|
+
mobilization_cost: Dict[int, float],
|
|
66
|
+
) -> OptInputs:
|
|
67
|
+
"""
|
|
68
|
+
Parse data to create an OptInputs object that models all input parameters
|
|
69
|
+
to set up the optimization model.
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
mobilization_cost : Dict[int, float]
|
|
74
|
+
The cost associated with mobilization for a campaign based on the number
|
|
75
|
+
of wells in a campaign.
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
opt_inputs : OptInputs
|
|
80
|
+
A fully instantiated object for inputs to the optimization model.
|
|
81
|
+
|
|
82
|
+
Raises
|
|
83
|
+
------
|
|
84
|
+
ValueError
|
|
85
|
+
If a well ID is repeated in the CSV file.
|
|
86
|
+
"""
|
|
87
|
+
budget = self.args.total_budget
|
|
88
|
+
max_wells_per_owner = self.args.max_wells_per_owner
|
|
89
|
+
well_dict = {}
|
|
90
|
+
candidates = {}
|
|
91
|
+
# dac_budget_fraction is the percentage of budget that needs
|
|
92
|
+
# to be spent on plugging wells in the disadvantaged community
|
|
93
|
+
dac_budget_fraction = self.args.dac_weight_percent
|
|
94
|
+
distance_threshold = self.args.maximum_well_distance
|
|
95
|
+
|
|
96
|
+
# new data
|
|
97
|
+
owner_well_count = (
|
|
98
|
+
self.well_data.groupby("Operator Name")["Well ID"].apply(list).to_dict()
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
dac_weight = self.args.dac_weight
|
|
102
|
+
|
|
103
|
+
if self.args.dac_weight_percent is not None:
|
|
104
|
+
if dac_weight is not None:
|
|
105
|
+
threshold = dac_weight / 100 * self.args.dac_weight_percent
|
|
106
|
+
else:
|
|
107
|
+
raise_exception(
|
|
108
|
+
"Disadvantaged Community Impact must be selected as a "
|
|
109
|
+
"priority factor if you wish to implement the DAC constraint.",
|
|
110
|
+
ValueError,
|
|
111
|
+
)
|
|
112
|
+
else:
|
|
113
|
+
# When the user does not provide a value for disadvantaged community,
|
|
114
|
+
# all wells are set as not disadvantaged.
|
|
115
|
+
# The maximum score possible for disadvantaged_community_score is 100.
|
|
116
|
+
threshold = 100
|
|
117
|
+
for _, row in self.well_data.iterrows():
|
|
118
|
+
well_id = row["Well ID"]
|
|
119
|
+
lat = row["Latitude"]
|
|
120
|
+
long = row["Longitude"]
|
|
121
|
+
score = row["Priority Score [0-100]"]
|
|
122
|
+
if dac_weight is not None:
|
|
123
|
+
disadvantaged_community_score = row[f"DAC Score [0-{int(dac_weight)}]"]
|
|
124
|
+
is_disadvantaged = float(disadvantaged_community_score > threshold)
|
|
125
|
+
else:
|
|
126
|
+
# When the user does not select DAC as a priority factor,
|
|
127
|
+
# all wells are assumed to not be located in a disadvantaged community.
|
|
128
|
+
is_disadvantaged = float(False)
|
|
129
|
+
|
|
130
|
+
if well_id in well_dict:
|
|
131
|
+
msg = f"Well id must be unique. Well id: {well_id} is repeated in csv file"
|
|
132
|
+
raise_exception(msg, ValueError)
|
|
133
|
+
|
|
134
|
+
well_dict[well_id] = Well(well_id, lat, long, score, is_disadvantaged)
|
|
135
|
+
|
|
136
|
+
LOGGER.info("Parsing for campaign candidates")
|
|
137
|
+
|
|
138
|
+
for _, row in self.well_data.iterrows():
|
|
139
|
+
well_id = row["Well ID"]
|
|
140
|
+
cluster = row["cluster"]
|
|
141
|
+
if cluster not in candidates:
|
|
142
|
+
candidates.setdefault(cluster, {})
|
|
143
|
+
candidates[cluster][well_id] = well_dict[well_id]
|
|
144
|
+
|
|
145
|
+
campaign_candidates = {}
|
|
146
|
+
for campaign_id, campaign_dict in candidates.items():
|
|
147
|
+
LOGGER.info(f"Preparing cluster: {campaign_id}")
|
|
148
|
+
campaign_candidates[campaign_id] = CampaignCandidates(
|
|
149
|
+
campaign_id, campaign_dict, len(campaign_dict)
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
return OptInputs(
|
|
153
|
+
well_dict,
|
|
154
|
+
campaign_candidates,
|
|
155
|
+
budget,
|
|
156
|
+
mobilization_cost,
|
|
157
|
+
owner_well_count,
|
|
158
|
+
max_wells_per_owner,
|
|
159
|
+
dac_budget_fraction,
|
|
160
|
+
distance_threshold,
|
|
161
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#################################################################################
|
|
2
|
+
# PRIMO - The P&A Project Optimizer was produced under the Methane Emissions Reduction Program (MERP)
|
|
3
|
+
# and National Energy Technology Laboratory's (NETL) National Emissions Reduction Initiative (NEMRI).
|
|
4
|
+
#
|
|
5
|
+
# NOTICE. This Software was developed under funding from the U.S. Government and the U.S.
|
|
6
|
+
# Government consequently retains certain rights. As such, the U.S. Government has been granted for
|
|
7
|
+
# itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license in
|
|
8
|
+
# the Software to reproduce, distribute copies to the public, prepare derivative works, and perform
|
|
9
|
+
# publicly and display publicly, and to permit others to do so.
|
|
10
|
+
#################################################################################
|
|
11
|
+
|
|
12
|
+
# Optimization Feasibility tolerance
|
|
13
|
+
FEASIBILITY_TOLERANCE = 1e-6
|