Skip to main content

Install

pip install -U cmflow

Install Dependency

On most platforms, you should be able to install these packages by:

pip install shapely
pip install rtree
pip install pytough

On Linux (Ubuntu shown here) these can be installed via apt-get:

sudo apt-get install -y python-shapely
sudo apt-get install -y python-rtree

Using Leapfrog Geological Models

In Leapfrog Energy, it ispossible to generate rocktype in a Flow Model using a Geological Model. This allows user to Export Block Rock Types, which generates a .csv file, containing block by block lithology and faults. This csv file can be imported into a LeapfrogGM object. These objects provide useful ways to access model block's lithology and faults as generated by Leapfrog Energy:

from cmflow.conceptual_models import LeapfrogGM

gm = LeapfrogGM()
gm.import_leapfrog_csv('gAB12345_rocktypes.csv', report=True)

litho = gm.lf_block['xyz12'] # Leapfrog assignment for block, as LeapfrogLitho
print(litho.litho_name) # name used in Leapfrog .csv
print(litho.faults) # faults that crosses the block
print(litho.rock) # pure lithology/formation name

Faults from Leapfrog

It is also possible to automatically generate rocktype naming to be used in AUT2/Waiwera based on certain rules. Here is an example that generate TWO letter codes that represents either no fault, single fault or multiple faults crossed a block. By calling .gmf_fault_rocktype_2L(), a rocktype naming of faults are generated.

This also adds extra LeapfrogLitho object properties such as .rocktype_fault and .faults_sorted. They contain the TWO letter code and list of crossing faults respectively.

gmf_fault = gm.gmf_fault_rocktype_2L(gm_def["faults"], report=True)

code = gm.lf_block['xyz12'].rocktype_fault
# TWO character code that can be used as part of the rocktype naming

The method .gmf_fault_rocktype_2L() also generates a FaultRocktypes object. FaultRocktypes serves as a central registry for the fault related rocktype naming convention. This can be saved and loaded for alter use. Ideally each fault should have a preset direction. This can be done by .set_directions () which expects a mapping between the original Leapfrog Fault name (from .csv) and their directions.

Now the object can workout any rocktype's fault direction by working through the faults exists ina particular rocktype. If all faults going through a rocktype are with the same direction, that direction is used. Otherwise it returns None. The FaultRocktypes object can keep user specified directions.

# sets single fault directions
gmf_fault.set_directions({
    "F1": 1,
    "F2": 1,
    "F3": 1,
    "F4": 2,
})

print(gmf_fault.rocktype_faults)

# {
#     "A0": ("F1"),
#     "AB": ("F1", "F2"),
#     "AX": ("F1", "F2", "F3"),
#     "AY": ("F1", "F2", "F4"),
#     "D0": ("F4"),
#     ...
# }

print(gmf_fault['AB'].faults)    # ('F1', 'F2')

print(gmf_fault['A0'].direction) # 1
print(gmf_fault['AX'].direction) # 1, because all faults uses 1
print(gmf_fault['D0'].direction) # 2
print(gmf_fault['AY'].direction) # None

gmf_fault.set_rock_fault_dir('AY', 1) # user decides that this fault combo should be 1 anyways

print(gmf_fault['AY'].direction) # 1

Example

Creates BMStats that can be used later, from Leapfrog Geology:

# (ONLY ONCE) geo used to get geology from Leapfrog geological model
cmgeo = mulgrid('g_very_fine.dat')

# CSV file created by Leapfrog using cmgeo above
leapfrog = LeapfrogGM()
leapfrog.import_leapfrog_csv('grid_gtmp_ay2017_03_6_fit.csv')

cm_geology = CM_Blocky(cmgeo, leapfrog)

# whatever active model we are working on
bmgeo = mulgrid('gwaixx_yy.dat')

bms_geology = cm_geology.calc_bmstats(bm_geo)
bms_geology.save('a.json')

A BMStats object can be reused (very fast) to eg.

bms_geology = BMStats('a.json')

# get a cell's stats
cs = bms_geology.cellstats['abc12']

# rock that occupies most in cell 'abc12'
rock_name = bms_geology.zones[np.argmax(cs)]

# how many rock in cell 'abc12'
n_rock = len(np.nonzero(cs))

# list all rocks in cell 'abc12'
rocks = [bm_geology.zones[i] for i in np.nonzero(cs)]

# find all blocks intersect with the zone
blocks, ratios = bm_geology.blocks_in_zone('BASE1')
block_idx, ratios = bm_geology.blocks_in_zone('BASE1', indices=True)

BMStats

This is the object that we keep for later use. It is associated to a certain "geometry" file. So each cell has information on zones. Usually this is generated by cm.populate_model(), which can be expensive.

  • ? should I call it CMStats?
  • ? TODO, .cellstats access by cell index
  • ? TODO, .

Base Model Stats, mainly numpy arrays with rows corresponding to mulgrid blocks, and columns corresponding to zones. Each is a value, usually between 0.0 and 1.0. Often 1.0 is indicating that particular block is fully within the zone.

.stats numpy array (n,m), n = num of model blocks, m = num of zones .zones list of zone names (str) .zonestats dict of stats column by zone names .cellstats dict of stats row by block name

6 elements, 3 zones
 A    B    C
0.0, 0.7, 0.3,  -> row sum to 1.0, element 0, 0.7 rock B, 0.3 rock C 
1.0, 0.0, 0.0, 
1.0, 0.0, 0.0, 
0.0, 0.5, 0.5, 
0.1, 0.2, 0.7, 
0.0, 1.0, 0.0, 
(this is only one way of using it, such as a rocktype)

.stats, numpy array (n * m), n number of geometry cells, m number of zones .zones, a list of zone name, eg. geology rock names, fault names etc .zonestats, a dict keyed by zone name, an array of size number of cells, each cell is between .cellstats, a dict of stats by cell name

.save() .load() .add_stats() add another bmstat, merge stats .add_cm() calls cm.populate_model, and merge stats

CM

CM_Blocky

CM_Prism

CM_Faults

These are the objects that can be created in order to create the final BMStats objects. The common method .populate_model(bm_geo) is called to create BMStats objects. It means the conceptual model is "applied" onto the bm_geo.

  • TODO, .populate_model() should return BMStats instead
  • ? TODO, .populate_model() should be called something else?

.populate_model(bm_geo) takes a target geometry, and return/creates BMStats

LeapfrogGM

Build and Publish

To bump version, create a tag, eg. v0.1.0.

If upload for the first time, create a PyPI account token, then use it for the publish step. The PyPI project will be created on first upload. Then revoke the account token and create a project token for later publishes.

Publish to PyPI:

hatch build
hatch publish -u __token__ -a pypi-<token>

hatch publish will prompt for user and password. Use __token__ as user, and then paste the whole token including the first part pypi- as password. This will be cached by hatch automatically.

Release files for cmflow 0.4.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cmflow 0.4.3
File Size Uploaded
cmflow-0.4.3.tar.gz 429.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cmflow 0.4.3
File Interpreter ABI Platform
cmflow-0.4.3-py3-none-any.whl Python 3 none any Details

Total release size: 860.7 kB

Release files / cmflow-0.4.3.tar.gz

Download URL cmflow-0.4.3.tar.gz
Size 429.5 kB
Tags Source
SHA-256 checksum
How to use checksums
10bc755c2b569024b780b9a8c7d6da44aea963ca9c742d76fffaf3e9360ac3a5
BLAKE2b-256 checksum
How to use checksums
03493922a5187d6610f900b805c541e07805f30c807f42c280e343bd42002f22
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via Hatch/1.18.1 {"ci":true,"cpu":"x86_64","distro":{"id":"noble","libc":{"lib":"glibc","version":"2.39"},"name":"Ubuntu","version":"24.04"},"implementation":{"name":"CPython","version":"3.13.15"},"installer":{"name":"hatch","version":"1.18.1"},"openssl_version":"OpenSSL 3.0.13 30 Jan 2024","python":"3.13.15","system":{"name":"Linux","release":"6.17.0-1022-azure"}} HTTPX2/2.13.1

Release files / cmflow-0.4.3-py3-none-any.whl

Download URL cmflow-0.4.3-py3-none-any.whl
Size 431.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aaeafad27c3e3c31606991baa3a3620f35e2bd4f3e83a9fdfff7713b87aba280
BLAKE2b-256 checksum
How to use checksums
c3e3375178e527b48dcd4ab23dd20fc8f2555440949553cfcc471620c258d653
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via Hatch/1.18.1 {"ci":true,"cpu":"x86_64","distro":{"id":"noble","libc":{"lib":"glibc","version":"2.39"},"name":"Ubuntu","version":"24.04"},"implementation":{"name":"CPython","version":"3.13.15"},"installer":{"name":"hatch","version":"1.18.1"},"openssl_version":"OpenSSL 3.0.13 30 Jan 2024","python":"3.13.15","system":{"name":"Linux","release":"6.17.0-1022-azure"}} HTTPX2/2.13.1
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page