diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 61e6a25..e9e0671 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.13'] + python-version: ['3.8'] os: [ubuntu-latest] runs-on: ${{ matrix.os }} @@ -37,14 +37,13 @@ jobs: - name: Install GNU Octave run: | - sudo apt install snapd + sudo apt-get update + sudo apt-get install snapd sudo snap install octave - name: Download MRST run: | - wget https://www.sintef.no/globalassets/project/mrst/mrst-2022a.zip - unzip mrst-2022a.zip - pwd + git clone https://github.com/SINTEF-AppliedCompSci/MRST.git - name: Install Flow Simulator run: | @@ -59,3 +58,13 @@ jobs: run: | pushd ./tests python3 quarter_single_leak.py + + - name: Check if the test succeded + run: | + file="/home/runner/work/py-micp/py-micp/tests/results/co2mass_comparison.png" + if [[ -f "$file" ]]; then + echo "py-micp succeeded" + else + echo "py-micp failed" + exit 1 + fi diff --git a/.gitignore b/.gitignore index bd61595..029360d 100644 --- a/.gitignore +++ b/.gitignore @@ -132,4 +132,4 @@ dmypy.json # py-micp MRST playground -debugging \ No newline at end of file +debugging diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..56384b5 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,12 @@ +cff-version: "1.2.0" +message: "If you use this software, please cite it as below." +authors: +- family-names: Landa-Marbán + given-names: David + orcid: "https://orcid.org/0000-0002-3343-1005" +title: "py-micp: An Open-Source Simulation Workflow for Field-Scale Application of + Microbially Induced Calcite Precipitation Technology for Leakage Remediation" +version: 2024.10 +identifiers: + - type: doi + value: 10.5281/zenodo.16880621 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..49783c1 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,90 @@ + +# Contributor Covenant 3.0 Code of Conduct + +## Our Pledge + +We pledge to make our community welcoming, safe, and equitable for all. + +We are committed to fostering an environment that respects and promotes the dignity, rights, and contributions of all individuals, regardless of characteristics including race, ethnicity, caste, color, age, physical characteristics, neurodiversity, disability, sex or gender, gender identity or expression, sexual orientation, language, philosophy or religion, national or social origin, socio-economic position, level of education, or other status. The same privileges of participation are extended to everyone who participates in good faith and in accordance with this Covenant. + + +## Encouraged Behaviors + +While acknowledging differences in social norms, we all strive to meet our community's expectations for positive behavior. We also understand that our words and actions may be interpreted differently than we intend based on culture, background, or native language. + +With these considerations in mind, we agree to behave mindfully toward each other and act in ways that center our shared values, including: + +1. Respecting the **purpose of our community**, our activities, and our ways of gathering. +2. Engaging **kindly and honestly** with others. +3. Respecting **different viewpoints** and experiences. +4. **Taking responsibility** for our actions and contributions. +5. Gracefully giving and accepting **constructive feedback**. +6. Committing to **repairing harm** when it occurs. +7. Behaving in other ways that promote and sustain the **well-being of our community**. + + +## Restricted Behaviors + +We agree to restrict the following behaviors in our community. Instances, threats, and promotion of these behaviors are violations of this Code of Conduct. + +1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal attention after any clear request to stop. +2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a community member or group of people. +3. **Stereotyping or discrimination.** Characterizing anyone’s personality or behavior on the basis of immutable identities or traits. +4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate in the context or purpose of the community. +5. **Violating confidentiality**. Sharing or acting on someone's personal or private information without their permission. +6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person or group. +7. Behaving in other ways that **threaten the well-being** of our community. + +### Other Restrictions + +1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone else to evade enforcement actions. +2. **Failing to credit sources.** Not properly crediting the sources of content you contribute. +3. **Promotional materials**. Sharing marketing or other commercial content in a way that is outside the norms of the community. +4. **Irresponsible communication.** Failing to responsibly present content which includes, links or describes any other restricted behaviors. + + +## Reporting an Issue + +Tensions can occur between community members even when they are trying their best to collaborate. Not every conflict represents a code of conduct violation, and this Code of Conduct reinforces encouraged behaviors and norms that can help avoid conflicts and minimize harm. + +When an incident does occur, it is important to report it promptly. To report a possible violation, send an email to dmar@norceresearch.no. + +Community Moderators take reports of violations seriously and will make every effort to respond in a timely manner. They will investigate all reports of code of conduct violations, reviewing messages, logs, and recordings, or interviewing witnesses and other participants. Community Moderators will keep investigation and enforcement actions as transparent as possible while prioritizing safety and confidentiality. In order to honor these values, enforcement actions are carried out in private with the involved parties, but communicating to the whole community may be part of a mutually agreed upon resolution. + + +## Addressing and Repairing Harm + +If an investigation by the Community Moderators finds that this Code of Conduct has been violated, the following enforcement ladder may be used to determine how best to repair harm, based on the incident's impact on the individuals involved and the community as a whole. Depending on the severity of a violation, lower rungs on the ladder may be skipped. + +1) Warning + 1) Event: A violation involving a single incident or series of incidents. + 2) Consequence: A private, written warning from the Community Moderators. + 3) Repair: Examples of repair include a private written apology, acknowledgement of responsibility, and seeking clarification on expectations. +2) Temporarily Limited Activities + 1) Event: A repeated incidence of a violation that previously resulted in a warning, or the first incidence of a more serious violation. + 2) Consequence: A private, written warning with a time-limited cooldown period designed to underscore the seriousness of the situation and give the community members involved time to process the incident. The cooldown period may be limited to particular communication channels or interactions with particular community members. + 3) Repair: Examples of repair may include making an apology, using the cooldown period to reflect on actions and impact, and being thoughtful about re-entering community spaces after the period is over. +3) Temporary Suspension + 1) Event: A pattern of repeated violation which the Community Moderators have tried to address with warnings, or a single serious violation. + 2) Consequence: A private written warning with conditions for return from suspension. In general, temporary suspensions give the person being suspended time to reflect upon their behavior and possible corrective actions. + 3) Repair: Examples of repair include respecting the spirit of the suspension, meeting the specified conditions for return, and being thoughtful about how to reintegrate with the community when the suspension is lifted. +4) Permanent Ban + 1) Event: A pattern of repeated code of conduct violations that other steps on the ladder have failed to resolve, or a violation so serious that the Community Moderators determine there is no way to keep the community safe with this person as a member. + 2) Consequence: Access to all community spaces, tools, and communication channels is removed. In general, permanent bans should be rarely used, should have strong reasoning behind them, and should only be resorted to if working through other remedies has failed to change the behavior. + 3) Repair: There is no possible repair in cases of this severity. + +This enforcement ladder is intended as a guideline. It does not limit the ability of Community Managers to use their discretion and judgment, in keeping with the best interests of our community. + + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public or other spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + + +## Attribution + +This Code of Conduct is adapted from the Contributor Covenant, version 3.0, permanently available at [https://www.contributor-covenant.org/version/3/0/](https://www.contributor-covenant.org/version/3/0/). + +Contributor Covenant is stewarded by the Organization for Ethical Source and licensed under CC BY-SA 4.0. To view a copy of this license, visit [https://creativecommons.org/licenses/by-sa/4.0/](https://creativecommons.org/licenses/by-sa/4.0/) + +For answers to common questions about Contributor Covenant, see the FAQ at [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are provided at [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations). Additional enforcement and community guideline resources can be found at [https://www.contributor-covenant.org/resources](https://www.contributor-covenant.org/resources). The enforcement ladder was inspired by the work of [Mozilla’s code of conduct team](https://github.com/mozilla/inclusion). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..8212437 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,27 @@ +# Contributing + +Contributions are more than welcome using the fork and pull request approach 🙂 (if you are not familiar with this approach, please visit [_GitHub Docs PRs_](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests) for an extended documentation about collaborating with pull request; also, looking at previous merged pull requests helps to get familiar with this). + +## Ground Rules + +- We document our code +- We keep compatibility with Octave + +## Contribute to the software + +1. Work on your own fork of the main repo +1. Make sure the examples run with Octave (see the [_CI.yml_](https://github.com/daavid00/py-micp/blob/main/.github/workflows/CI.yml) for the steps to run the example in the [_tests_](https://github.com/daavid00/py-micp/tests) folder) +1. Squash your commits into a single commit (see this [_nice tutorial_](https://gist.github.com/lpranam/4ae996b0a4bc37448dc80356efbca7fa) if you are not familiar with this) +1. Push your commit and make a pull request +1. The maintainers will review the pull request, and if the contribution is accepted, then it will be merge to the main repo + +## Reporting issues or problems + +1. Issues or problems can be raised by creating a [_new issue_](https://github.com/daavid00/py-micp/issues) in the repository GitHub page (if you are not familiar with this approach, please visit [_GitHub Docs Issues_](https://docs.github.com/en/issues/tracking-your-work-with-issues)). +1. We will try to answer as soon as possible, but also any user is more than welcome to answer. + +## Seek support + +1. The preferred approach to seek support is to raise an issue as described in the previous lines. +1. We will try to answer as soon as possible, but also any user is more than welcome to answer. +- An alternative approach is to send an email to dmar@norceresearch.no. diff --git a/README.md b/README.md index 5cc8eb7..4e0a7ad 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![Build Status](https://github.com/daavid00/py-micp/actions/workflows/py-micp.yml/badge.svg)](https://github.com/daavid00/py-micp/actions/workflows/py-micp.yml) - +[![Build Status](https://github.com/daavid00/py-micp/actions/workflows/CI.yml/badge.svg)](https://github.com/daavid00/py-micp/actions/workflows/CI.yml) + [![Code style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![DOI](https://zenodo.org/badge/444088296.svg)](https://doi.org/10.5281/zenodo.16880620) @@ -28,12 +28,12 @@ models in OPM Flow. ## Installation You will first need to install/download -* [Flow](https://opm-project.org) (tested with Flow==release/2025.04) -* [Python](https://www.python.org/downloads/) (tested with Python==3.13) -* [GNU Octave](https://www.gnu.org/software/octave/download) (tested with GNU Octave==9.4.0) +* [Flow](https://opm-project.org) (tested with Flow==2025.10) +* [Python](https://www.python.org/downloads/) (tested with Python==3.14) +* [GNU Octave](https://www.gnu.org/software/octave/download) (tested with GNU Octave==10.3.0) * [MRST](https://www.sintef.no/projectweb/mrst/download/) (tested with MRST==2025a) -You will also need to install some python packages see ```requirements.txt``` +You will also need to install some python packages, see ```requirements.txt``` for a complete list. You can install all the required python packages in a virtual environment with the following commands: @@ -52,10 +52,8 @@ pip install --upgrade pip setuptools wheel pip install -r requirements.txt ``` -You can install OPM Flow from binary packages on Ubuntu Linux 22.04 or 24.04 and Red -Hat Enterprise Linux 7. Installing instruction is found [here](https://opm-project.org/?page_id=245). -The OPM webpage also has instruction for installation on other systems. For building it from source (including macOS), -you could also [look here](https://opm.github.io/pyopmspe11/installation.html#opm-flow). +See this [_installation_](https://opm.github.io/pyopmspe11/installation.html#opm-flow) for further details on building OPM Flow from the master branches in Linux, Windows (via [_WSL_](https://learn.microsoft.com/en-us/windows/wsl/)), and macOS. + Once you have installed OPM Flow, GNU Octave, and downloaded MRST: * Edit line 11 of the python scripts (e.g., 'quarter_single_leak.py') with the @@ -65,7 +63,7 @@ full path to your 'flow' executable (e.g., '/Users/dmar/opm/build/opm-simulators full path to your MRST 'startup.m' file (e.g., '/Users/dmar/mrst-2025a/startup.m'). Tip: See the [CI.yml](https://github.com/daavid00/py-micp/blob/main/.github/workflows/CI.yml) for installation of -all dependencies and running the test in _py-micp_. +all dependencies in Ubuntu 24.04 and running the test in _py-micp_. ## Running the scripts * From the terminal, e.g., for the quarter_single_leak system: @@ -83,8 +81,8 @@ strategies for leakage mitigation using microbially induced calcite precipitation. https://arxiv.org/abs/2201.00669 Refer to the [_v2024.10 release_](https://github.com/daavid00/py-micp/releases/tag/v2024.10) for the code that was used in that paper. This is relevant -since in the OPM Flow version 2025.04, the MICP implementation was refactored, resulting in changes in the deck keywords (e.g., now we use BIOFPARA instead -of MICPPARA): see the corresponding OPM Flow version of the [_OPM Flow manual_](https://opm-project.org/?page_id=955) for details. +since in the OPM Flow version 2025.04, the MICP implementation was refactored, resulting in changes in the deck keywords (e.g., now we use `BIOFPARA` instead +of `MICPPARA`); see the corresponding OPM Flow version of the [_OPM Flow manual_](https://opm-project.org/?page_id=955) for details. ## About py-micp The _py-micp_ package was funded by the [_Efficient models for microbially induced calcite precipitation as a seal for CO2 storage (MICAP) project_](https://gassnova.no/app/uploads/sites/4/2022/02/Sluttrapport-MICAP.pdf) [project number 268390]. @@ -98,6 +96,7 @@ Below are some tools that might be of interest; check ‘em out 🙂. * pyopmspe11: A Python framework using OPM Flow for the CSP SPE11 benchmark project (https://github.com/OPM/pyopmspe11). * pycopm: An open-source tool to tailor OPM Flow geological models (https://github.com/cssr-tools/pycopm). * plopm: Quick generation of PNGs, GIFs, and VTKs from a OPM Flow type model (https://github.com/cssr-tools/plopm). +* pofff: An open-source image-based history-matching framework for the FluidFlower benchmark study using OPM Flow (https://github.com/cssr-tools/pofff). * pyopmnearwell: A Python framework to simulate near well dynamics using OPM Flow (https://github.com/cssr-tools/pyopmnearwell). * expreccs: A Python framework using OPM Flow to simulate regional and site reservoirs for CO2 storage (https://github.com/cssr-tools/expreccs). * pymm: An open-source image-based framework for CFD in microsystems (https://github.com/cssr-tools/pymm). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..9c58e8c --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,40 @@ +# Security Policy + +## Supported Versions + +We only provide security updates for the following versions: + +* **Version 2024.10** (Current Stable) + +## Reporting a Vulnerability + +We take security vulnerabilities seriously and appreciate your efforts to responsibly disclose them. To report a vulnerability, please follow these steps: + +1. **Do not open a public GitHub issue.** This could expose the vulnerability to malicious actors before a fix is available. +2. **Email us directly at `dmar@norceresearch.no`**. +3. **Provide detailed information:** + * A clear description of the vulnerability. + * Steps to reproduce the vulnerability. + * The affected versions of the project. + * Any potential impact or exploit scenarios. + * Your contact information for follow-up. + +## Our Disclosure Policy + +Upon receiving a security bug report, we will: + +1. **Acknowledge receipt** within 24-72 hours. +2. **Confirm the problem** and determine affected versions. +3. **Work on a fix** for all supported releases. +4. **Coordinate a release** with the fix. +5. **Publicly acknowledge your contribution** (with your permission) after the fix is released. + +## Responsible Disclosure + +We kindly request that you: + +* **Do not publicly disclose the vulnerability** until we have released a fix. +* **Allow us a reasonable amount of time** to address the issue before public disclosure. +* **Do not engage in any actions** that could harm our users or systems during your research. + +Thank you for helping to keep our project secure. diff --git a/full_diagonal_leak/full_diagonal_leak.py b/full_diagonal_leak/full_diagonal_leak.py index f52b96d..215d7e0 100644 --- a/full_diagonal_leak/full_diagonal_leak.py +++ b/full_diagonal_leak/full_diagonal_leak.py @@ -146,8 +146,8 @@ def compact_format(values): yy = len(Y0) + len(Y1) + len(Y2) - 1 zz = len(Z0) + len(Z1) + len(Z2) - 1 xyz = xx * yy * zz -ix = abs(np.transpose(XX)).argmin() + 1 -iy = abs(np.transpose(YY)).argmin() + 1 +ix = np.abs(np.transpose(XX)).argmin() + 1 +iy = np.abs(np.transpose(YY)).argmin() + 1 it = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) < ht])]) il = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) > H - hl])]) os.system( @@ -291,10 +291,18 @@ def compact_format(values): list_of_lines = f.readlines() ss = list_of_lines[-3] mesh = meshio.read(f"results/MICP-{int(ss[-13:-8]):05d}.vtu") -for row in mesh.cell_data["calcite fraction"]: +for row in mesh.cell_data["calcite volume fraction"]: c = row -for row in mesh.cell_data["biofilm fraction"]: - b = row +for ( + key +) in ( + mesh.cell_data.keys() +): # Flow 2025.10 prints biofilm voulme, this has been fixed in Flow master + if "biofilm" in key: + biokey = key + break +for row in mesh.cell_data[biokey]: + b = row.flatten() biof[: xx * yy * it] = b[: xx * yy * it] calc[: xx * yy * it] = c[: xx * yy * it] perm[: xx * yy * it] = Ka * permred(phi - b[: xx * yy * it] - c[: xx * yy * it]) @@ -409,9 +417,9 @@ def compact_format(values): p = row CO2M = QCO2 * t0[j] * day if t0[j] > 0: - a.append(100.0 * sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) + a.append(100.0 * np.sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) else: - a.append(sum(CO2[:II] * p[:II] * VOLUM[:II])) + a.append(np.sum(CO2[:II] * p[:II] * VOLUM[:II])) Lg.append(a) a = [] for j in range(len(t1)): @@ -422,12 +430,12 @@ def compact_format(values): p = row CO2M = QCO2 * t1[j] * day if t1[j] > 0: - a.append(100.0 * sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) + a.append(100.0 * np.sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) else: - a.append(sum(CO2[:II] * p[:II] * VOLUM[:II])) + a.append(np.sum(CO2[:II] * p[:II] * VOLUM[:II])) Lg.append(a) -print(f"Percentage of leake CO2:{Lg[0][-1][0]}") -print(f"Percentage of leake CO2 after MICP treatment:{Lg[1][-1][0]}") +print(f"Percentage of leake CO2:{Lg[0][-1]}") +print(f"Percentage of leake CO2 after MICP treatment:{Lg[1][-1]}") # Plot the results over time and save them as co2mass_comparison.png lw = 5 diff --git a/full_double_leak/full_double_leak.py b/full_double_leak/full_double_leak.py index 0136366..a3d89f8 100644 --- a/full_double_leak/full_double_leak.py +++ b/full_double_leak/full_double_leak.py @@ -149,8 +149,8 @@ def compact_format(values): yy = len(Y0) + len(Y1) + len(Y2) - 1 zz = len(Z0) + len(Z1) + len(Z2) - 1 xyz = xx * yy * zz -ix = abs(np.transpose(XX)).argmin() + 1 -iy = abs(np.transpose(YY)).argmin() + 1 +ix = np.abs(np.transpose(XX)).argmin() + 1 +iy = np.abs(np.transpose(YY)).argmin() + 1 it = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) < ht])]) il = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) > H - hl])]) os.system( @@ -302,10 +302,18 @@ def compact_format(values): list_of_lines = f.readlines() ss = list_of_lines[-3] mesh = meshio.read(f"results/MICP-{int(ss[-13:-8]):05d}.vtu") -for row in mesh.cell_data["calcite fraction"]: +for row in mesh.cell_data["calcite volume fraction"]: c = row -for row in mesh.cell_data["biofilm fraction"]: - b = row +for ( + key +) in ( + mesh.cell_data.keys() +): # Flow 2025.10 prints biofilm voulme, this has been fixed in Flow master + if "biofilm" in key: + biokey = key + break +for row in mesh.cell_data[biokey]: + b = row.flatten() biof[: xx * yy * it] = b[: xx * yy * it] calc[: xx * yy * it] = c[: xx * yy * it] perm[: xx * yy * it] = Ka * permred(phi - b[: xx * yy * it] - c[: xx * yy * it]) @@ -420,9 +428,9 @@ def compact_format(values): p = row CO2M = QCO2 * t0[j] * day if t0[j] > 0: - a.append(100.0 * sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) + a.append(100.0 * np.sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) else: - a.append(sum(CO2[:II] * p[:II] * VOLUM[:II])) + a.append(np.sum(CO2[:II] * p[:II] * VOLUM[:II])) Lg.append(a) a = [] for j in range(len(t1)): @@ -433,12 +441,12 @@ def compact_format(values): p = row CO2M = QCO2 * t1[j] * day if t1[j] > 0: - a.append(100.0 * sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) + a.append(100.0 * np.sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) else: - a.append(sum(CO2[:II] * p[:II] * VOLUM[:II])) + a.append(np.sum(CO2[:II] * p[:II] * VOLUM[:II])) Lg.append(a) -print(f"Percentage of leake CO2:{Lg[0][-1][0]}") -print(f"Percentage of leake CO2 after MICP treatment:{Lg[1][-1][0]}") +print(f"Percentage of leake CO2:{Lg[0][-1]}") +print(f"Percentage of leake CO2 after MICP treatment:{Lg[1][-1]}") # Plot the results over time and save them as co2mass_comparison.png lw = 5 diff --git a/full_single_leak/full_single_leak.py b/full_single_leak/full_single_leak.py index 7c873a2..3d38ba9 100644 --- a/full_single_leak/full_single_leak.py +++ b/full_single_leak/full_single_leak.py @@ -146,8 +146,8 @@ def compact_format(values): yy = len(Y0) + len(Y1) + len(Y2) - 1 zz = len(Z0) + len(Z1) + len(Z2) - 1 xyz = xx * yy * zz -ix = abs(np.transpose(XX)).argmin() + 1 -iy = abs(np.transpose(YY)).argmin() + 1 +ix = np.abs(np.transpose(XX)).argmin() + 1 +iy = np.abs(np.transpose(YY)).argmin() + 1 it = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) < ht])]) il = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) > H - hl])]) os.system( @@ -280,10 +280,18 @@ def compact_format(values): list_of_lines = f.readlines() ss = list_of_lines[-3] mesh = meshio.read(f"results/MICP-{int(ss[-13:-8]):05d}.vtu") -for row in mesh.cell_data["calcite fraction"]: +for row in mesh.cell_data["calcite volume fraction"]: c = row -for row in mesh.cell_data["biofilm fraction"]: - b = row +for ( + key +) in ( + mesh.cell_data.keys() +): # Flow 2025.10 prints biofilm voulme, this has been fixed in Flow master + if "biofilm" in key: + biokey = key + break +for row in mesh.cell_data[biokey]: + b = row.flatten() biof[: xx * yy * it] = b[: xx * yy * it] calc[: xx * yy * it] = c[: xx * yy * it] perm[: xx * yy * it] = Ka * permred(phi - b[: xx * yy * it] - c[: xx * yy * it]) @@ -398,9 +406,9 @@ def compact_format(values): p = row CO2M = QCO2 * t0[j] * day if t0[j] > 0: - a.append(100.0 * sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) + a.append(100.0 * np.sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) else: - a.append(sum(CO2[:II] * p[:II] * VOLUM[:II])) + a.append(np.sum(CO2[:II] * p[:II] * VOLUM[:II])) Lg.append(a) a = [] for j in range(len(t1)): @@ -411,12 +419,12 @@ def compact_format(values): p = row CO2M = QCO2 * t1[j] * day if t1[j] > 0: - a.append(100.0 * sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) + a.append(100.0 * np.sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) else: - a.append(sum(CO2[:II] * p[:II] * VOLUM[:II])) + a.append(np.sum(CO2[:II] * p[:II] * VOLUM[:II])) Lg.append(a) -print(f"Percentage of leake CO2:{Lg[0][-1][0]}") -print(f"Percentage of leake CO2 after MICP treatment:{Lg[1][-1][0]}") +print(f"Percentage of leake CO2:{Lg[0][-1]}") +print(f"Percentage of leake CO2 after MICP treatment:{Lg[1][-1]}") # Plot the results over time and save them as co2mass_comparison.png lw = 5 diff --git a/quarter_diagonal_leak/quarter_diagonal_leak.py b/quarter_diagonal_leak/quarter_diagonal_leak.py index 0f1b87a..7636c3d 100644 --- a/quarter_diagonal_leak/quarter_diagonal_leak.py +++ b/quarter_diagonal_leak/quarter_diagonal_leak.py @@ -141,8 +141,8 @@ def compact_format(values): yy = len(Y0) + len(Y1) - 1 zz = len(Z0) + len(Z1) + len(Z2) - 1 xyz = xx * yy * zz -ix = abs(np.transpose(XX)).argmin() + 1 -iy = abs(np.transpose(YY)).argmin() + 1 +ix = np.abs(np.transpose(XX)).argmin() + 1 +iy = np.abs(np.transpose(YY)).argmin() + 1 it = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) < ht])]) il = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) > H - hl])]) os.system( @@ -264,10 +264,18 @@ def compact_format(values): list_of_lines = f.readlines() ss = list_of_lines[-3] mesh = meshio.read(f"results/MICP-{int(ss[-13:-8]):05d}.vtu") -for row in mesh.cell_data["calcite fraction"]: +for row in mesh.cell_data["calcite volume fraction"]: c = row -for row in mesh.cell_data["biofilm fraction"]: - b = row +for ( + key +) in ( + mesh.cell_data.keys() +): # Flow 2025.10 prints biofilm voulme, this has been fixed in Flow master + if "biofilm" in key: + biokey = key + break +for row in mesh.cell_data[biokey]: + b = row.flatten() biof[: xx * yy * it] = b[: xx * yy * it] calc[: xx * yy * it] = c[: xx * yy * it] perm[: xx * yy * it] = Ka * permred(phi - b[: xx * yy * it] - c[: xx * yy * it]) @@ -380,9 +388,9 @@ def compact_format(values): p = row CO2M = QCO2 * t0[j] * day if t0[j] > 0: - a.append(100.0 * sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) + a.append(100.0 * np.sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) else: - a.append(sum(CO2[:II] * p[:II] * VOLUM[:II])) + a.append(np.sum(CO2[:II] * p[:II] * VOLUM[:II])) Lg.append(a) a = [] for j in range(len(t1)): @@ -393,12 +401,12 @@ def compact_format(values): p = row CO2M = QCO2 * t1[j] * day if t1[j] > 0: - a.append(100.0 * sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) + a.append(100.0 * np.sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) else: - a.append(sum(CO2[:II] * p[:II] * VOLUM[:II])) + a.append(np.sum(CO2[:II] * p[:II] * VOLUM[:II])) Lg.append(a) -print(f"Percentage of leake CO2:{Lg[0][-1][0]}") -print(f"Percentage of leake CO2 after MICP treatment:{Lg[1][-1][0]}") +print(f"Percentage of leake CO2:{Lg[0][-1]}") +print(f"Percentage of leake CO2 after MICP treatment:{Lg[1][-1]}") # Plot the results over time and save them as co2mass_comparison.png lw = 5 diff --git a/quarter_double_leak/quarter_double_leak.py b/quarter_double_leak/quarter_double_leak.py index f101fad..24aa0a1 100644 --- a/quarter_double_leak/quarter_double_leak.py +++ b/quarter_double_leak/quarter_double_leak.py @@ -142,8 +142,8 @@ def compact_format(values): yy = len(Y0) + len(Y1) - 1 zz = len(Z0) + len(Z1) + len(Z2) - 1 xyz = xx * yy * zz -ix = abs(np.transpose(XX)).argmin() + 1 -iy = abs(np.transpose(YY)).argmin() + 1 +ix = np.abs(np.transpose(XX)).argmin() + 1 +iy = np.abs(np.transpose(YY)).argmin() + 1 it = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) < ht])]) il = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) > H - hl])]) os.system( @@ -266,10 +266,18 @@ def compact_format(values): list_of_lines = f.readlines() ss = list_of_lines[-3] mesh = meshio.read(f"results/MICP-{int(ss[-13:-8]):05d}.vtu") -for row in mesh.cell_data["calcite fraction"]: +for row in mesh.cell_data["calcite volume fraction"]: c = row -for row in mesh.cell_data["biofilm fraction"]: - b = row +for ( + key +) in ( + mesh.cell_data.keys() +): # Flow 2025.10 prints biofilm voulme, this has been fixed in Flow master + if "biofilm" in key: + biokey = key + break +for row in mesh.cell_data[biokey]: + b = row.flatten() biof[: xx * yy * it] = b[: xx * yy * it] calc[: xx * yy * it] = c[: xx * yy * it] perm[: xx * yy * it] = Ka * permred(phi - b[: xx * yy * it] - c[: xx * yy * it]) @@ -382,9 +390,9 @@ def compact_format(values): p = row CO2M = QCO2 * t0[j] * day if t0[j] > 0: - a.append(100.0 * sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) + a.append(100.0 * np.sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) else: - a.append(sum(CO2[:II] * p[:II] * VOLUM[:II])) + a.append(np.sum(CO2[:II] * p[:II] * VOLUM[:II])) Lg.append(a) a = [] for j in range(len(t1)): @@ -395,12 +403,12 @@ def compact_format(values): p = row CO2M = QCO2 * t1[j] * day if t1[j] > 0: - a.append(100.0 * sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) + a.append(100.0 * np.sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) else: - a.append(sum(CO2[:II] * p[:II] * VOLUM[:II])) + a.append(np.sum(CO2[:II] * p[:II] * VOLUM[:II])) Lg.append(a) -print(f"Percentage of leake CO2:{Lg[0][-1][0]}") -print(f"Percentage of leake CO2 after MICP treatment:{Lg[1][-1][0]}") +print(f"Percentage of leake CO2:{Lg[0][-1]}") +print(f"Percentage of leake CO2 after MICP treatment:{Lg[1][-1]}") # Plot the results over time and save them as co2mass_comparison.png lw = 5 diff --git a/quarter_single_leak/quarter_single_leak.py b/quarter_single_leak/quarter_single_leak.py index d3d3b69..48da694 100644 --- a/quarter_single_leak/quarter_single_leak.py +++ b/quarter_single_leak/quarter_single_leak.py @@ -138,8 +138,8 @@ def compact_format(values): yy = len(Y0) + len(Y1) - 1 zz = len(Z0) + len(Z1) + len(Z2) - 1 xyz = xx * yy * zz -ix = abs(np.transpose(XX)).argmin() + 1 -iy = abs(np.transpose(YY)).argmin() + 1 +ix = np.abs(np.transpose(XX)).argmin() + 1 +iy = np.abs(np.transpose(YY)).argmin() + 1 it = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) < ht])]) il = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) > H - hl])]) os.system( @@ -255,9 +255,17 @@ def compact_format(values): list_of_lines = f.readlines() ss = list_of_lines[-3] mesh = meshio.read(f"results/MICP-{int(ss[-13:-8]):05d}.vtu") -for row in mesh.cell_data["calcite fraction"]: +for row in mesh.cell_data["calcite volume fraction"]: c = row.flatten() -for row in mesh.cell_data["biofilm fraction"]: +for ( + key +) in ( + mesh.cell_data.keys() +): # Flow 2025.10 prints biofilm voulme, this has been fixed in Flow master + if "biofilm" in key: + biokey = key + break +for row in mesh.cell_data[biokey]: b = row.flatten() biof[: xx * yy * it] = b[: xx * yy * it] calc[: xx * yy * it] = c[: xx * yy * it] @@ -367,9 +375,9 @@ def compact_format(values): p = row CO2M = QCO2 * t0[j] * day if t0[j] > 0: - a.append(100.0 * sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) + a.append(100.0 * np.sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) else: - a.append(sum(CO2[:II] * p[:II] * VOLUM[:II])) + a.append(np.sum(CO2[:II] * p[:II] * VOLUM[:II])) Lg.append(a) a = [] for j in range(len(t1)): @@ -380,12 +388,12 @@ def compact_format(values): p = row CO2M = QCO2 * t1[j] * day if t1[j] > 0: - a.append(100.0 * sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) + a.append(100.0 * np.sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) else: - a.append(sum(CO2[:II] * p[:II] * VOLUM[:II])) + a.append(np.sum(CO2[:II] * p[:II] * VOLUM[:II])) Lg.append(a) -print(f"Percentage of leake CO2:{Lg[0][-1][0]}") -print(f"Percentage of leake CO2 after MICP treatment:{Lg[1][-1][0]}") +print(f"Percentage of leake CO2:{Lg[0][-1]}") +print(f"Percentage of leake CO2 after MICP treatment:{Lg[1][-1]}") # Plot the results over time and save them as co2mass_comparison.png lw = 5 diff --git a/requirements.txt b/requirements.txt index 67318c2..5dc33db 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,4 @@ black mako matplotlib meshio -scipy \ No newline at end of file +scipy diff --git a/tests/quarter_single_leak.m b/tests/quarter_single_leak.m index f2b1cd9..bdedc1d 100644 --- a/tests/quarter_single_leak.m +++ b/tests/quarter_single_leak.m @@ -1,5 +1,5 @@ function quarter_single_leak(H, ht, hl, L, ux, uy, Wi, X, Y, Z) -run '/home/runner/work/py-micp/py-micp/mrst-2022a/startup.m' +run '/home/runner/work/py-micp/py-micp/MRST/startup.m' % Write a grid structure with a straight leakage path in the file % 'GRID.INC' in the 'decks' folder for simulation in % OPM Flow diff --git a/tests/quarter_single_leak.py b/tests/quarter_single_leak.py index 6899e1f..2c83c88 100644 --- a/tests/quarter_single_leak.py +++ b/tests/quarter_single_leak.py @@ -138,8 +138,8 @@ def compact_format(values): yy = len(Y0) + len(Y1) - 1 zz = len(Z0) + len(Z1) + len(Z2) - 1 xyz = xx * yy * zz -ix = abs(np.transpose(XX)).argmin() + 1 -iy = abs(np.transpose(YY)).argmin() + 1 +ix = np.abs(np.transpose(XX)).argmin() + 1 +iy = np.abs(np.transpose(YY)).argmin() + 1 it = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) < ht])]) il = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) > H - hl])]) os.system( @@ -235,9 +235,17 @@ def compact_format(values): list_of_lines = f.readlines() ss = list_of_lines[-3] mesh = meshio.read(f"results/MICP-{int(ss[-13:-8]):05d}.vtu") -for row in mesh.cell_data["calcite fraction"]: +for row in mesh.cell_data["calcite volume fraction"]: c = row.flatten() -for row in mesh.cell_data["biofilm fraction"]: +for ( + key +) in ( + mesh.cell_data.keys() +): # Flow 2025.10 prints biofilm voulme, this has been fixed in Flow master + if "biofilm" in key: + biokey = key + break +for row in mesh.cell_data[biokey]: b = row.flatten() biof[: xx * yy * it] = b[: xx * yy * it] calc[: xx * yy * it] = c[: xx * yy * it] @@ -346,9 +354,9 @@ def compact_format(values): p = row CO2M = QCO2 * t0[j] * day if t0[j] > 0: - a.append(100.0 * sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) + a.append(100.0 * np.sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) else: - a.append(sum(CO2[:II] * p[:II] * VOLUM[:II])) + a.append(np.sum(CO2[:II] * p[:II] * VOLUM[:II])) Lg.append(a) a = [] for j in range(len(t1)): @@ -359,12 +367,12 @@ def compact_format(values): p = row CO2M = QCO2 * t1[j] * day if t1[j] > 0: - a.append(100.0 * sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) + a.append(100.0 * np.sum(CO2[:II] * p[:II] * VOLUM[:II]) / CO2M) else: - a.append(sum(CO2[:II] * p[:II] * VOLUM[:II])) + a.append(np.sum(CO2[:II] * p[:II] * VOLUM[:II])) Lg.append(a) -print(f"Percentage of leake CO2:{Lg[0][-1][0]}") -print(f"Percentage of leake CO2 after MICP treatment:{Lg[1][-1][0]}") +print(f"Percentage of leake CO2:{Lg[0][-1]}") +print(f"Percentage of leake CO2 after MICP treatment:{Lg[1][-1]}") # Plot the results over time and save them as co2mass_comparison.png lw = 5 diff --git a/top_vs_vertical_variable_injection/top_vs_vertical_variable_injection.py b/top_vs_vertical_variable_injection/top_vs_vertical_variable_injection.py index 8bbda17..895449f 100644 --- a/top_vs_vertical_variable_injection/top_vs_vertical_variable_injection.py +++ b/top_vs_vertical_variable_injection/top_vs_vertical_variable_injection.py @@ -87,8 +87,8 @@ yyf = len(Yf0) + len(Yf1) + len(Yf2) - 1 zz = len(Z0) + len(Z1) + len(Z2) - 1 xyzf = xxf * yyf * zz -ix = abs(np.transpose(XXf)).argmin() + 1 -iy = abs(np.transpose(YYf)).argmin() + 1 +ix = np.abs(np.transpose(XXf)).argmin() + 1 +iy = np.abs(np.transpose(YYf)).argmin() + 1 it = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) < ht])]) il = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) > H - hl])]) os.system( diff --git a/towards_more_optimal_injection_strategies/towards_more_optimal_injection_strategies.py b/towards_more_optimal_injection_strategies/towards_more_optimal_injection_strategies.py index 8db4f3d..fb326e8 100644 --- a/towards_more_optimal_injection_strategies/towards_more_optimal_injection_strategies.py +++ b/towards_more_optimal_injection_strategies/towards_more_optimal_injection_strategies.py @@ -87,8 +87,8 @@ yyf = len(Yf0) + len(Yf1) + len(Yf2) - 1 zz = len(Z0) + len(Z1) + len(Z2) - 1 xyzf = xxf * yyf * zz -ix = abs(np.transpose(XXf)).argmin() + 1 -iy = abs(np.transpose(YYf)).argmin() + 1 +ix = np.abs(np.transpose(XXf)).argmin() + 1 +iy = np.abs(np.transpose(YYf)).argmin() + 1 it = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) < ht])]) il = len(np.transpose(ZZ)[tuple([np.transpose(ZZ) > H - hl])]) os.system(