Skip to content

Commit

Permalink
Merge pull request #799 from cgre-aachen/gempy_v2023.1.0-pandas2.0
Browse files Browse the repository at this point in the history
[WIP] remove inplace for pandas cat
  • Loading branch information
Japhiolite authored Jun 2, 2023
2 parents 3314aed + 2e0b2cd commit 28dcdc1
Show file tree
Hide file tree
Showing 28 changed files with 145 additions and 98 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
- name: Run tests with pytest
run: |
pytest
pytest --ignore-glob=/home/runner/work/gempy/gempy/gempy_3/api/test*_gempy3.py
testing_pip:
name: Pip install ${{ matrix.case.os }} py${{ matrix.case.python-version }} ${{ matrix.case.name }}
Expand Down Expand Up @@ -108,4 +108,4 @@ jobs:
- name: Run tests with pytest
run: |
pytest
pytest --ignore-glob=/home/runner/work/gempy/gempy/gempy_3/api/test*_gempy3.py
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@
[![DOI](https://zenodo.org/badge/96211155.svg)](https://zenodo.org/badge/latestdoi/96211155)
[![DOCKER](https://img.shields.io/docker/cloud/automated/leguark/gempy.svg)](https://cloud.docker.com/repository/docker/leguark/gempy)

:warning: **Warning: GemPy requires pandas version < 1.4.0. The new pandas release is not compatible with GemPy.
We're actively working on this issue for a future release.
Please make sure to use Pandas version 1.3.x when working with GemPy for the time being.**

**Using theano, GemPy requires numpy version < 1.22.0 as `blas_opt_info` was deprecated in newer numpy versions.**:warning:
## Overview

[GemPy](https://www.gempy.org/) is a Python-based, **open-source geomodeling library**. It is
Expand All @@ -40,9 +35,17 @@ the aesara conda installation. Therefore the process would be the following:

For more information, refer to the [installation documentation](https://docs.gempy.org/installation.html).

## Requirements

The following versions are required/strongly recommended for the main dependencies of GemPy (as of June 2023):
- python>=3.10
- pandas>=2.0
- matplotlib>=3.7
- pyvista>=0.39

## Resources

After installation you can either check the [notebook tutorials](https://docs.gempy.org/getting_started/get_started.html#sphx-glr-getting-started-get-started-py)
After installation, you can either check the [notebook tutorials](https://docs.gempy.org/getting_started/get_started.html#sphx-glr-getting-started-get-started-py)
or the [video introduction](https://www.youtube.com/watch?v=n0btC5Zilyc) to get started.

Go to the [documentation site](http://docs.gempy.org/) for further information and enjoy the [tutorials and examples](https://www.gempy.org/tutorials).
Expand All @@ -58,8 +61,8 @@ Follow these [guidelines](https://github.com/cgre-aachen/gempy/blob/WIP_readme-u

* de la Varga, M., Schaaf, A., and Wellmann, F. (2019). [GemPy 1.0: open-source stochastic geological modeling and inversion](https://gmd.copernicus.org/articles/12/1/2019/gmd-12-1-2019.pdf), Geosci. Model Dev., 12, 1-32.
* Wellmann, F., & Caumon, G. (2018). [3-D Structural geological models: Concepts, methods, and uncertainties.](https://hal.univ-lorraine.fr/hal-01921494/file/structural_models_for_geophysicsHAL.pdf) In Advances in Geophysics (Vol. 59, pp. 1-121). Elsevier.
* Calcagno, P., Chilès, J. P., Courrioux, G., & Guillen, A. (2008). Geological modelling from field data and geological knowledge: Part I. Modelling method coupling 3D potential-field interpolation and geological rules. Physics of the Earth and Planetary Interiors, 171(1-4), 147-157.
* Lajaunie, C., Courrioux, G., & Manuel, L. (1997). Foliation fields and 3D cartography in geology: principles of a method based on potential interpolation. Mathematical Geology, 29(4), 571-584.
* Calcagno, P., Chilès, J. P., Courrioux, G., & Guillen, A. (2008). [Geological modelling from field data and geological knowledge: Part I. Modelling method coupling 3D potential-field interpolation and geological rules](https://www.sciencedirect.com/science/article/abs/pii/S0031920108001258). Physics of the Earth and Planetary Interiors, 171(1-4), 147-157.
* Lajaunie, C., Courrioux, G., & Manuel, L. (1997). [Foliation fields and 3D cartography in geology: principles of a method based on potential interpolation](https://link.springer.com/article/10.1007/BF02775087). Mathematical Geology, 29(4), 571-584.

## Publications using GemPy

Expand Down
34 changes: 15 additions & 19 deletions gempy/api_modules/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,8 @@ def _load_surface_points(cat_series, cat_surfaces, geo_model, name, path):
'series': 'category',
'id': 'int64',
'order_series': 'int64'})
geo_model._surface_points.df['surface'].cat.set_categories(cat_surfaces,
inplace=True)
geo_model._surface_points.df['series'].cat.set_categories(cat_series,
inplace=True)
geo_model._surface_points.df['surface'] = geo_model._surface_points.df['surface'].cat.set_categories(cat_surfaces)
geo_model._surface_points.df['series'] = geo_model._surface_points.df['series'].cat.set_categories(cat_series)
# Code to add smooth columns for models saved before gempy 2.0bdev4
try:
geo_model._surface_points.df['smooth']
Expand All @@ -183,9 +181,8 @@ def _load_orientations(cat_series, cat_surfaces, geo_model, name, path):
'series': 'category',
'id': 'int64',
'order_series': 'int64'})
geo_model._orientations.df['surface'].cat.set_categories(cat_surfaces,
inplace=True)
geo_model._orientations.df['series'].cat.set_categories(cat_series, inplace=True)
geo_model._orientations.df['surface'] = geo_model._orientations.df['surface'].cat.set_categories(cat_surfaces)
geo_model._orientations.df['series'] = geo_model._orientations.df['series'].cat.set_categories(cat_series)

try:
geo_model._orientations.df['smooth']
Expand All @@ -207,7 +204,7 @@ def _load_surfaces(cat_series, geo_model, name, path):
ordered=False)
geo_model._surfaces.sort_surfaces()
geo_model._surfaces.colors.generate_colordict()
geo_model._surfaces.df['series'].cat.set_categories(cat_series, inplace=True)
geo_model._surfaces.df['series'] = geo_model._surfaces.df['series'].cat.set_categories(cat_series)
try:
geo_model._surfaces.df['isActive']
except KeyError:
Expand All @@ -228,8 +225,8 @@ def _load_stack(geo_model, name, path):
series_index = pn.CategoricalIndex(geo_model._stack.df.index.values)
# geo_model.series.df.index = pn.CategoricalIndex(series_index)
geo_model._stack.df.index = series_index
geo_model._stack.df['BottomRelation'].cat.set_categories(
['Erosion', 'Onlap', 'Fault'], inplace=True)
geo_model._stack.df['BottomRelation'] = geo_model._stack.df['BottomRelation'].cat.set_categories(
['Erosion', 'Onlap', 'Fault'])
try:
geo_model._stack.df['isActive']
except KeyError:
Expand Down Expand Up @@ -259,15 +256,14 @@ def _load_additional_data(geo_model, name, path):
'aesara_optimizer': 'category',
'device': 'category',
'verbosity': object})
geo_model._additional_data.options.df['dtype'].cat.set_categories(
['float32', 'float64'], inplace=True)
geo_model._additional_data.options.df['aesara_optimizer'].cat.set_categories(
['fast_run', 'fast_compile'],
inplace=True)
geo_model._additional_data.options.df['device'].cat.set_categories(
['cpu', 'cuda'], inplace=True)
geo_model._additional_data.options.df['output'].cat.set_categories(
['geology', 'gradients'], inplace=True)
geo_model._additional_data.options.df['dtype'] = geo_model._additional_data.options.df['dtype'].cat.set_categories(
['float32', 'float64'])
geo_model._additional_data.options.df['aesara_optimizer'] = geo_model._additional_data.options.df['aesara_optimizer'].cat.set_categories(
['fast_run', 'fast_compile'])
geo_model._additional_data.options.df['device'] = geo_model._additional_data.options.df['device'].cat.set_categories(
['cpu', 'cuda'])
geo_model._additional_data.options.df['output'] = geo_model._additional_data.options.df['output'].cat.set_categories(
['geology', 'gradients'])
geo_model._additional_data.options.df.loc['values', 'verbosity'] = None


Expand Down
6 changes: 3 additions & 3 deletions gempy/core/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ def __init__(self):
'aesara_optimizer': 'category', 'device': 'category',
'verbosity': object})

self.df['dtype'].cat.set_categories(['float32', 'float64'], inplace=True)
self.df['aesara_optimizer'].cat.set_categories(['fast_run', 'fast_compile'], inplace=True)
self.df['device'].cat.set_categories(['cpu', 'cuda'], inplace=True)
self.df['dtype'] = self.df['dtype'].cat.set_categories(['float32', 'float64'])
self.df['aesara_optimizer'] = self.df['aesara_optimizer'].cat.set_categories(['fast_run', 'fast_compile'])
self.df['device'] = self.df['device'].cat.set_categories(['cpu', 'cuda'])

self.default_options()

Expand Down
12 changes: 6 additions & 6 deletions gempy/core/data_modules/geometric_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def init_dependent_properties(self):
self.df['series'] = 'Default series'
self.df['series'] = self.df['series'].astype('category', copy=True)

self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories, inplace=True)
self.df['series'] = self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories)

# id
self.df['id'] = np.nan
Expand Down Expand Up @@ -80,12 +80,12 @@ def set_series_categories_from_series(self, series):
Args:
series (:class:`Series`): [s0]
"""
self.df['series'].cat.set_categories(series.df.index, inplace=True)
self.df['series'] = self.df['series'].cat.set_categories(series.df.index)
return True

def update_series_category(self):
"""Update the series categorical columns with the series categories of the :class:`Surfaces` attribute."""
self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories, inplace=True)
self.df['series'] = self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories)

return True

Expand All @@ -98,7 +98,7 @@ def set_surface_categories_from_surfaces(self, surfaces: Surfaces):
"""

self.df['surface'].cat.set_categories(surfaces.df['surface'], inplace=True)
self.df['surface'] = self.df['surface'].cat.set_categories(surfaces.df['surface'])
return True

# @_setdoc_pro(Series.__doc__)
Expand Down Expand Up @@ -126,7 +126,7 @@ def map_data_from_series(self, series, attribute: str, idx=None):

if type(self.df['order_series'].dtype) is pn.CategoricalDtype:

self.df['order_series'].cat.remove_unused_categories(inplace=True)
self.df['order_series'] = self.df['order_series'].cat.remove_unused_categories()
return self

@_setdoc_pro(Surfaces.__doc__)
Expand Down Expand Up @@ -165,7 +165,7 @@ def _add_surface_to_list_from_new_surface_points_or_orientations(self, idx, surf
# Check is self.df['surface'] is a category
if not isinstance(self.df['surface'].dtype, pd.CategoricalDtype):
self.df['surface'] = self.df['surface'].astype('category', copy=True)
self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values, inplace=True)
self.df['surface'] = self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values)

# Check if elements in surface are categories in self.df['surface'] and if not add them
# for s in surface:
Expand Down
8 changes: 4 additions & 4 deletions gempy/core/data_modules/orientations.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def set_orientations(self, coord: np.ndarray = None, pole_vector: np.ndarray = N
'azimuth', 'polarity', 'surface'], dtype=float)

self.df['surface'] = self.df['surface'].astype('category', copy=True)
self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values, inplace=True)
self.df['surface'] = self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values)

pole_vector = check_for_nans(pole_vector)
orientation = check_for_nans(orientation)
Expand Down Expand Up @@ -94,7 +94,7 @@ def set_orientations(self, coord: np.ndarray = None, pole_vector: np.ndarray = N
'this point. Check previous condition')

self.df['surface'] = self.df['surface'].astype('category', copy=True)
self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values, inplace=True)
self.df['surface'] = self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values)

self.init_dependent_properties()

Expand Down Expand Up @@ -161,10 +161,10 @@ def add_orientation(self, x, y, z, surface: list[str] | str, pole_vector: Union[

# create new pandas categories from slef.df.['surface']
self.df['surface'] = self.df['surface'].astype('category', copy=True)
self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values, inplace=True)
self.df['surface'] = self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values)

self.df['series'] = self.df['series'].astype('category', copy=True)
self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories, inplace=True)
self.df['series'] = self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories)

self.map_data_from_surfaces(self.surfaces, 'series', idx=idx)
self.map_data_from_surfaces(self.surfaces, 'id', idx=idx)
Expand Down
6 changes: 3 additions & 3 deletions gempy/core/data_modules/surface_points.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def set_surface_points(self, coord: np.ndarray = None, surface: list = None):
self.df['surface'] = surface

self.df['surface'] = self.df['surface'].astype('category', copy=True)
self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values, inplace=True)
self.df['surface'] = self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values)

# Choose types
self.init_dependent_properties()
Expand Down Expand Up @@ -128,10 +128,10 @@ def add_surface_points(self, x: Union[float, np.ndarray], y: Union[float, np.nda
self.df.loc[idx, ['smooth']] = 1e-6

self.df['surface'] = self.df['surface'].astype('category', copy=True)
self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values, inplace=True)
self.df['surface'] = self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values)

self.df['series'] = self.df['series'].astype('category', copy=True)
self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories, inplace=True)
self.df['series'] = self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories)

self.map_data_from_surfaces(self.surfaces, 'series', idx=idx)
self.map_data_from_surfaces(self.surfaces, 'id', idx=idx)
Expand Down
5 changes: 2 additions & 3 deletions gempy/core/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,9 +621,8 @@ def modify_order_features(self, new_value: int, idx: str):
"""
self._stack.modify_order_series(new_value, idx)

self._surfaces.df['series'].cat.reorder_categories(
np.asarray(self._stack.df.index),
ordered=False, inplace=True)
self._surfaces.df['series'] = self._surfaces.df['series'].cat.reorder_categories(
np.asarray(self._stack.df.index), ordered=False)

self._surfaces.sort_surfaces()
self._surfaces.set_basement()
Expand Down
11 changes: 6 additions & 5 deletions gempy/core/surfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def __init__(self, series, surface_names=None, values_array=None, properties_nam
if (np.array(sys.version_info[:2]) <= np.array([3, 6])).all():
self.df: pn.DataFrame

self.df['series'].cat.add_categories(['Default series'], inplace=True)
self.df['series'] = self.df['series'].cat.add_categories(['Default series'])
if surface_names is not None:
self.set_surfaces_names(surface_names)

Expand All @@ -64,7 +64,7 @@ def __repr__(self):
def _repr_html_(self):
c_ = self.df.columns[~(self.df.columns.isin(self._columns_vis_drop))]

return self.df[c_].style.applymap(self.background_color, subset=['color']).render()
return self.df[c_].style.applymap(self.background_color, subset=['color']).to_html()

@property
def properties_val(self):
Expand Down Expand Up @@ -312,7 +312,7 @@ def map_series(self, mapping_object: Union[dict, pn.DataFrame] = None):
"""

# Updating surfaces['series'] categories
self.df['series'].cat.set_categories(self.series.df.index, inplace=True)
self.df['series'] = self.df['series'].cat.set_categories(self.series.df.index)
# TODO Fixing this. It is overriding the formations already mapped
if mapping_object is not None:
# If none is passed and series exists we will take the name of the first series as a default
Expand All @@ -326,8 +326,8 @@ def map_series(self, mapping_object: Union[dict, pn.DataFrame] = None):
s.append(k)
f.append(form)

new_series_mapping = pn.DataFrame([pn.Categorical(s, self.series.df.index)],
f, columns=['series'])
new_series_mapping = pn.DataFrame(list(zip(pn.Categorical(s, self.series.df.index))),
index=f, columns=['series'])

elif isinstance(mapping_object, pn.Categorical):
# This condition is for the case we have surface on the index and in 'series' the category
Expand All @@ -351,6 +351,7 @@ def map_series(self, mapping_object: Union[dict, pn.DataFrame] = None):
self.reset_order_surfaces()
self.sort_surfaces()
self.set_basement()

return self

# endregion
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
import os
import pytest

#IN_GITHUB_ACTIONS = os.getenv("GITHUB_ACTIONS") == "true"
IN_GITHUB_ACTIONS = True

import gempy as gp
import gempy_engine
from gempy import Project
from gempy.plot.vista import GemPyToVista
from gempy_3.api.gp2_to_gp3_input import gempy_project_to_interpolation_input, gempy_project_to_input_data_descriptor, gempy_project_to_interpolation_options
from gempy_3.api.gp3_to_gp2_output import set_gp3_solutions_to_gp2_solution
from gempy_3.api.test_api._gp2togp3_test_utils import create_interpolator, load_model, map_sequential_pile
from gempy_engine.config import AvailableBackends
from gempy_engine.core.backend_tensor import BackendTensor
from gempy_engine.core.data import InterpolationOptions
from gempy_engine.core.data.input_data_descriptor import InputDataDescriptor
from gempy_engine.core.data.interpolation_input import InterpolationInput
from gempy_engine.core.data.solutions import Solutions

if not IN_GITHUB_ACTIONS:
import gempy_engine
from gempy_engine.config import AvailableBackends
from gempy_engine.core.backend_tensor import BackendTensor
from gempy_engine.core.data import InterpolationOptions
from gempy_engine.core.data.input_data_descriptor import InputDataDescriptor
from gempy_engine.core.data.interpolation_input import InterpolationInput
from gempy_engine.core.data.solutions import Solutions

input_path = os.path.dirname(__file__) + '/../../../test/input_data'
import sys # These two lines are necessary only if GemPy is not installed

sys.path.append("../..")


@pytest.mark.skipif(IN_GITHUB_ACTIONS, reason="Only runs once gempy 3 is published.")
def test_set_gempy3_gempy2_bridge():
"""
This test is based on gempy/test/test_core/test_model.py:test_compute_model
Expand Down
Loading

0 comments on commit 28dcdc1

Please sign in to comment.