From 0242215d0014f1651722e3bdec571f774b9f61c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Wed, 16 Apr 2025 17:12:34 +0200 Subject: [PATCH 001/102] FIX: bug with IGRF as np array --- pygimli/physics/gravimetry/kernel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygimli/physics/gravimetry/kernel.py b/pygimli/physics/gravimetry/kernel.py index 32ddb1c94..7403b873c 100644 --- a/pygimli/physics/gravimetry/kernel.py +++ b/pygimli/physics/gravimetry/kernel.py @@ -38,7 +38,7 @@ def SolveGravMagHolstein(mesh, pnts, cmp, igrf=None): # , foot=np.inf): B_tens = None kernel = np.zeros((mesh.cellCount(), len(pnts), len(cmp))) - if igrf: + if np.any(igrf): if len(igrf) == 3: # an X, Y, Z vector F = np.linalg.norm(igrf) fakt = F / (4*np.pi) From 7090003f53213b7b8f12c2c4ab31e43551f92e68 Mon Sep 17 00:00:00 2001 From: carsten-forty2 Date: Wed, 16 Apr 2025 17:07:31 +0200 Subject: [PATCH 002/102] FIX: better cache for lists --- pygimli/frameworks/modelling.py | 2 ++ pygimli/meshtools/mesh.py | 12 +++++------ pygimli/testing/test_misc.py | 36 +++++++++++++++++++-------------- pygimli/utils/__init__.py | 2 +- pygimli/utils/cache.py | 23 ++++++++++++++------- 5 files changed, 45 insertions(+), 30 deletions(-) diff --git a/pygimli/frameworks/modelling.py b/pygimli/frameworks/modelling.py index 1ce47348d..fbe0eb39f 100644 --- a/pygimli/frameworks/modelling.py +++ b/pygimli/frameworks/modelling.py @@ -752,6 +752,7 @@ def setMesh(self, mesh, ignoreRegionManager=False): self.regionManager().setMesh(mesh) self.setDefaultBackground() + def setDefaultBackground(self): """Set the lowest region to background if several exist.""" regionIds = self.regionManager().regionIdxs() @@ -762,6 +763,7 @@ def setDefaultBackground(self): "(marker={0})".format(bk)) self.setRegionProperties(bk, background=True) + def drawModel(self, ax, model, **kwargs): """Draw the model as mesh-based distribution.""" mod = None diff --git a/pygimli/meshtools/mesh.py b/pygimli/meshtools/mesh.py index 6aa533232..406ac1dd3 100644 --- a/pygimli/meshtools/mesh.py +++ b/pygimli/meshtools/mesh.py @@ -2,15 +2,13 @@ """General mesh generation and maintenance.""" import os - import numpy as np - import pygimli as pg def createMesh(poly, quality=32, area=0.0, smooth=None, switches=None, verbose=False, **kwargs): - """Create a mesh for a given PLC or point list. + r"""Create a mesh for a given PLC or point list. The mesh is created by :term:`triangle` or :term:`tetgen` if the pgGIMLi support for these mesh generators is installed. @@ -24,7 +22,7 @@ def createMesh(poly, quality=32, area=0.0, smooth=None, switches=None, Parameters ---------- poly: :gimliapi:`GIMLI::Mesh` or list or ndarray - * 2D or 3D gimli mesh that contains the PLC. + * 2D or 3D GIMli mesh that contains the PLC. * 2D mesh needs edges * 3D mesh needs a plc and tetgen as system component * List of x y pairs [[x0, y0], ... ,[xN, yN]] @@ -46,7 +44,7 @@ def createMesh(poly, quality=32, area=0.0, smooth=None, switches=None, 1: node center 2: weighted node center - If smooth is just set to True then [1, 4] is choosen. + If smooth is just set to True then [1, 4] is chosen. switches: str Set additional triangle command switches. @@ -96,8 +94,8 @@ def createMesh(poly, quality=32, area=0.0, smooth=None, switches=None, pg.critical("No nodes in poly to create a valid mesh") if switches is None: - # -D Conforming delaunay - # -F Uses Steven Fortune's sweepline algorithm + # -D Conforming Delaunay + # -F Uses Steven Fortune's sweep line algorithm switches = 'pzeA' if area > 0: diff --git a/pygimli/testing/test_misc.py b/pygimli/testing/test_misc.py index fa665bf34..e2fa87b5c 100644 --- a/pygimli/testing/test_misc.py +++ b/pygimli/testing/test_misc.py @@ -41,9 +41,9 @@ def test_Trans(self): f.add(pg.trans.TransLog(), 5) f.add(pg.trans.TransLog(), 5) - np.testing.assert_array_equal(f.at(0).fwd(np.ones(10)*10), + np.testing.assert_array_equal(f.at(0).fwd(np.ones(10)*10), np.log(np.ones(10)*10)) - np.testing.assert_array_equal(f.fwd(np.ones(10)*10), + np.testing.assert_array_equal(f.fwd(np.ones(10)*10), np.log(np.ones(10)*10)) # tm2 = pg.trans.TransLog() # tc.add(tm2, 5, 10) @@ -64,10 +64,10 @@ def test_DataContainerFilter(self): data.markInvalid(pg.core.IndexArray(np.arange(5, dtype="long"))) self.assertEqual(data('valid'), [0.0, 0.0, 0.0, 0.0, 0.0]) - + data.markValid(np.arange(5, dtype="long")) self.assertEqual(data('valid'), [1.0, 1.0, 1.0, 1.0, 1.0]) - + data.markInvalid(range(5)) self.assertEqual(data('valid'), [0.0, 0.0, 0.0, 0.0, 0.0]) @@ -75,23 +75,23 @@ def test_DataContainerFilter(self): data.markValid(pg.Vector(x) > 2.0) self.assertEqual(data('valid'), [0.0, 0.0, 0.0, 1.0, 1.0]) - + data.markValid(pg.BVector(x < 2.0)) self.assertEqual(data('valid'), [1.0, 1.0, 0.0, 1.0, 1.0]) data.markInvalid(pg.find(x > 3.0)) self.assertEqual(data('valid'), [1.0, 1.0, 0.0, 1.0, 0.0]) - + data.markInvalid(x < 1.0) self.assertEqual(data('valid'), [0.0, 1.0, 0.0, 1.0, 0.0]) def test_DataContainerSensors(self): data = pg.DataContainer() - + sensors = [[x, 0.0] for x in range(5)] data.setSensorPositions(sensors) data.setSensorPositions(data.sensors()[::-1]) - + self.assertEqual(data.sensor(0), [4., 0.0, 0.0]) self.assertEqual(data.sensor(4), [0., 0.0, 0.0]) @@ -100,7 +100,7 @@ def test_DataContainerIndex(self): data['b'] = np.ones(2) * 3.14 np.testing.assert_array_equal(data['b'], np.ones(2)*3.14) self.assertEqual(type(data['b']), type(pg.Vector())) - + data['b'][0] = 1.0 self.assertEqual(data['b'][0], 1.0) @@ -110,7 +110,7 @@ def test_DataContainerIndex(self): self.assertEqual(type(data['a']), type(np.array(1))) self.assertEqual(data['a'].dtype, 'int') data['a'][0] = 1.0 # will not work for sensorIndex until its changed in the datacontainer as IndexArray - + data['a'] = np.ones(2)*1.2 np.testing.assert_array_equal(data['a'], np.ones(2)) self.assertEqual(type(data['a']), type(np.array(1))) @@ -146,6 +146,7 @@ def test_Int64Problem(self): self.assertEqual(sum(data('m')), 9*2) self.assertEqual(sum(data('n')), 9*3) + def test_PosConstMember(self): p1 = pg.Pos(1.0, 0.0, 0.0) p2 = pg.Pos(0.0, 1.0, 0.0) @@ -153,12 +154,13 @@ def test_PosConstMember(self): p3 = p1.cross(p2) self.assertEqual(p3, pg.Pos(0.0, 0.0, 1.0)) + def test_Hash(self): v1 = pg.Vector(10, 2.) v2 = pg.Vector(10, 2.) self.assertFalse(pg.Vector(1, 0.).hash() == pg.Vector(2, 0.).hash()) - + self.assertEqual(v1.hash(), v2.hash()) self.assertEqual(hash(v1), hash(v2)) v2[2] = 3. @@ -167,10 +169,14 @@ def test_Hash(self): self.assertTrue(v1.hash() == v2.hash()) self.assertEqual(v1.hash(), pg.Vector(10, 2.).hash()) + self.assertEqual(pg.utils.valHash([1, 0, 0])== + pg.utils.valHash([0, 1, 0]), False) + + def test_HashData(self): d1 = pg.DataContainerERT() d2 = pg.DataContainerERT() - + self.assertEqual(d1.hash(), d2.hash()) d1.createSensor([1.0, 0.0]) d2.createSensor([2.0, 0.0]) @@ -203,15 +209,15 @@ def test_HashMesh(self): m2.node(0).setPos([1.0, 0.0]) self.assertTrue(m1.hash() == m2.hash()) - - # does not work .. need time to implement + + # does not work .. need time to implement # def test_DataContainerWrite(self): # data = pg.DataContainer() # data.save('test.dat') # fi = open('test2.dat', 'w') # data.write(fi) # fi.close() - + def test_DataTypes(self): pg.core.showSizes() diff --git a/pygimli/utils/__init__.py b/pygimli/utils/__init__.py index 0797e2f2a..6ce4b9592 100644 --- a/pygimli/utils/__init__.py +++ b/pygimli/utils/__init__.py @@ -18,7 +18,7 @@ from .complex import (isComplex, toComplex, toPolar, squeezeComplex, toRealMatrix, KramersKronig) -from .cache import (cache, strHash, noCache) +from .cache import (cache, strHash, noCache, valHash) from .geostatistics import (computeInverseRootMatrix, covarianceMatrix, generateGeostatisticalModel) from .gps import GKtoUTM, findUTMZone, getProjection, getUTMProjection, readGPX diff --git a/pygimli/utils/cache.py b/pygimli/utils/cache.py index e59fea45f..0bf0a761b 100644 --- a/pygimli/utils/cache.py +++ b/pygimli/utils/cache.py @@ -25,29 +25,32 @@ def myLongRunningStuff(*args, **kwargs): import time import numpy as np - import pygimli as pg __NO_CACHE__ = False def noCache(c): + """Set the cache to noCache mode.""" global __NO_CACHE__ __NO_CACHE__ = c + def strHash(string): + """Create a hash value for the given string.""" return int(hashlib.sha224(string.encode()).hexdigest()[:16], 16) + def valHash(a): - + """Create a hash value for the given value.""" if isinstance(a, str): return strHash(a) elif isinstance(a, int): return a elif isinstance(a, list): hsh = 0 - for item in a: - hsh = hsh ^ valHash(item) + for i, item in enumerate(a): + hsh = hsh ^ valHash(str(i)+str(item)) return hsh elif isinstance(a, np.ndarray): if a.ndim == 1: @@ -61,7 +64,13 @@ def valHash(a): return hash(a) + class Cache(object): + """Cache class to store and restore data. + + This class is used to store and restore data in a cache. + It is used to store and restore data in a cache. + """ def __init__(self, hashValue): self._value = None self._hash = hashValue @@ -144,7 +153,7 @@ def restore(self): # pg.error('only single return caches supported for now.') #pg._y(pg.pf(self.info)) - + if self.info['type'] == 'DataContainerERT': self._value = pg.DataContainerERT(self.info['file'], removeInvalid=False) @@ -240,7 +249,7 @@ def hash(self, funct, *args, **kwargs): argHash = argHash ^ (valHash(k + str(v))) else: argHash = argHash ^ valHash(k) ^ valHash(v) - + pg.debug("Hashing took:", pg.dur(), "s") return funcHash ^ versionHash ^ codeHash ^ argHash @@ -262,7 +271,7 @@ def cache(funct): def wrapper(*args, **kwargs): nc = kwargs.pop('skipCache', False) - + if any(('--noCache' in sys.argv, '-N' in sys.argv, nc is True, __NO_CACHE__)): From a1e637426aef19515695cbe97c9b76efa877b9ac Mon Sep 17 00:00:00 2001 From: Florian Wagner Date: Thu, 7 Mar 2024 17:12:57 +0100 Subject: [PATCH 003/102] DOC: Add prove of concept for myst-based user guide --- doc/_templates/navbar-nav.html | 3 ++ doc/conf.py | 19 ++++++- doc/user_guide/index.md | 95 ++++++++++++++++++++++++++++++++++ environment.yml | 5 +- 4 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 doc/user_guide/index.md diff --git a/doc/_templates/navbar-nav.html b/doc/_templates/navbar-nav.html index 9bdadc62e..8b4a4ee13 100644 --- a/doc/_templates/navbar-nav.html +++ b/doc/_templates/navbar-nav.html @@ -6,6 +6,9 @@ + diff --git a/doc/conf.py b/doc/conf.py index 787eefd79..ebfd48f0d 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -108,6 +108,7 @@ "srclinks", "sphinxcontrib.doxylink", "sphinx_design", + "myst_nb", # "sphinxcontrib.spelling" #'sphinx.ext.pngmath', # for breath #'sphinx.ext.todo', # for breath @@ -674,4 +675,20 @@ def monkeypatch(self, section: str, use_admonition: bool): # os.path.abspath(join(DOC_BUILD_DIR, "../../doxygen/xml")), # } # -# breathe_default_project = "gimli" \ No newline at end of file +# breathe_default_project = "gimli" +# Settings for myst +myst_enable_extensions = [ + "amsmath", + "attrs_inline", + "colon_fence", + "deflist", + "dollarmath", + "html_admonition", + "html_image", + "linkify", + "replacements", + "smartquotes", + "substitution", +] +myst_dmath_allow_labels=True +nb_execution_excludepatterns = ["*Untitled*", "_examples_auto/**/*", "_tutorials_auto/**/*"] diff --git a/doc/user_guide/index.md b/doc/user_guide/index.md new file mode 100644 index 000000000..8a3314fa6 --- /dev/null +++ b/doc/user_guide/index.md @@ -0,0 +1,95 @@ +--- +jupytext: + formats: ipynb,md:myst + text_representation: + extension: .md + format_name: myst +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +# User guide +```{contents} Table of Contents +:depth: 3 +``` + +## Evaluate code + +```{code-cell} ipython3 + +import pygimli as pg +mesh = pg.createGrid(20,5) +data = pg.x(mesh) +pg.show(mesh, data) +``` + +## Some Markdown features + +### Math +Since Pythagoras, we know that {math}`a^2 + b^2 = c^2`. + +$$ +(a + b)^2 &= (a + b)(a + b) \\ + &= a^2 + 2ab + b^2 +$$ (mymath2) + +The equation {eq}`mymath2` is also a quadratic equation. + +Some **text**! + +:::{admonition} Here's my title +:class: tip + +Here's my admonition content. +::: + +### Tables +:::{table} Table caption +:widths: auto +:align: center + +| foo | bar | +| --- | --- | +| baz | bim | +::: + +### Typography +**strong**, _emphasis_, `literal text`, \*escaped symbols\* + +### Footnotes +A longer footnote definition.[^mylongdef] + +[^mylongdef]: This is the _**footnote definition**_. + + That continues for all indented lines + + - even other block elements + + Plus any preceding unindented lines, +that are not separated by a blank line + +This is not part of the footnote. + +### Cards +:::{card} Card Title +Header +^^^ +Card content ++++ +Footer +::: + +### Tabs +::::{tab-set} + +:::{tab-item} Label1 +Content 1 +::: + +:::{tab-item} Label2 +Content 2 +::: + +:::: \ No newline at end of file diff --git a/environment.yml b/environment.yml index 7b8f124a4..3848c6793 100644 --- a/environment.yml +++ b/environment.yml @@ -21,8 +21,9 @@ dependencies: - bibtexparser - pyvista[all,trame]>=0.42 - meshio - - tetgen - scooby - sphinx-design - pydata-sphinx-theme - + - myst-parser + - myst-nb + - jupytext From 72bffd88ad273b21512d779f3bb2a1e454cb1e25 Mon Sep 17 00:00:00 2001 From: "hagen.soeding" Date: Fri, 8 Mar 2024 08:21:58 +0100 Subject: [PATCH 004/102] adding build, trame and linkify to environment --- environment.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/environment.yml b/environment.yml index 3848c6793..6a54b3b8c 100644 --- a/environment.yml +++ b/environment.yml @@ -27,3 +27,6 @@ dependencies: - myst-parser - myst-nb - jupytext + - trame-vtk + - conda-build + - linkify-it-py From a3259214266c0ae311537bedd7f7d32a7e686501 Mon Sep 17 00:00:00 2001 From: Florian Wagner Date: Fri, 8 Mar 2024 09:51:56 +0100 Subject: [PATCH 005/102] DOC: Avoid .html suffixes in URLs and prefer hyphens --- doc/CMakeLists.txt | 4 ++-- doc/Makefile | 11 +++-------- doc/_templates/navbar-nav.html | 16 ++++++++-------- doc/_templates/sidebar.html | 2 +- doc/{user_guide => user-guide}/index.md | 0 5 files changed, 14 insertions(+), 19 deletions(-) rename doc/{user_guide => user-guide}/index.md (100%) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 088a7bf10..1a1107ef3 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -95,7 +95,7 @@ add_custom_target(sphinxhtml ALL ${SPHINX_EXECUTABLE} -v -D abort_on_example_error=1 -T - -b html + -b dirhtml -c "${SPHINX_BUILD_DIR}/doc" -d "${SPHINX_CACHE_DIR}/html" "${SPHINX_BUILD_DIR}/doc" @@ -116,7 +116,7 @@ add_custom_target(sphinxhtml-nogallery ALL -D abort_on_example_error=1 -D plot_gallery=0 -T - -b html + -b dirhtml -c "${SPHINX_BUILD_DIR}/doc" -d "${SPHINX_CACHE_DIR}/html" "${SPHINX_BUILD_DIR}/doc" diff --git a/doc/Makefile b/doc/Makefile index a5a297a29..fa5d42c63 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -68,12 +68,12 @@ gallery: python ./sidebar_gallery.py html-nogallery: api - $(SPHINXBUILD) -D plot_gallery=0 -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + $(SPHINXBUILD) -D plot_gallery=0 -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished without gallery. The HTML pages are in $(BUILDDIR)/html." html: api - $(SPHINXBUILD) -v -D abort_on_example_error=True -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + $(SPHINXBUILD) -v -D abort_on_example_error=True -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." @@ -82,11 +82,6 @@ spelling: api @echo @echo "Spellcheck finished." -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @@ -103,7 +98,7 @@ json: @echo "Build finished; now you can process the JSON files." htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + $(SPHINXBUILD) -b dirhtmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." diff --git a/doc/_templates/navbar-nav.html b/doc/_templates/navbar-nav.html index 8b4a4ee13..fa8c74c72 100644 --- a/doc/_templates/navbar-nav.html +++ b/doc/_templates/navbar-nav.html @@ -4,25 +4,25 @@

- \ No newline at end of file + diff --git a/doc/_templates/sidebar.html b/doc/_templates/sidebar.html index 2e74cd136..56ba76b8f 100644 --- a/doc/_templates/sidebar.html +++ b/doc/_templates/sidebar.html @@ -22,7 +22,7 @@
diff --git a/doc/about/index.md b/doc/about/index.md index 5598c070d..5057cf25a 100644 --- a/doc/about/index.md +++ b/doc/about/index.md @@ -1,12 +1,10 @@ -About pyGIMLi -============= +# About pyGIMLi -Introduction ------------- +## Introduction pyGIMLi is an open-source library for -:ref:`modelling` and -:ref:`inversion` and in geophysics. The +{ref}`modelling` and +{ref}`inversion` and in geophysics. The object-oriented library provides management for structured and unstructured meshes in 2D and 3D, finite-element and finite-volume solvers, various geophysical forward operators, as well as Gauss-Newton based frameworks for @@ -14,40 +12,40 @@ constrained, joint and fully-coupled inversions with flexible regularization. What is pyGIMLi suited for? -* analyze, visualize and invert geophysical data in a reproducible manner -* forward modelling of (geo)physical problems on complex 2D and 3D geometries -* inversion with flexible controls on a-priori information and regularization -* combination of different methods in constrained, joint and fully-coupled inversions -* teaching applied geophysics (e.g. in combination with `Jupyter notebooks `_) +- analyze, visualize and invert geophysical data in a reproducible manner +- forward modelling of (geo)physical problems on complex 2D and 3D geometries +- inversion with flexible controls on a-priori information and regularization +- combination of different methods in constrained, joint and fully-coupled inversions +- teaching applied geophysics (e.g. in combination with [Jupyter notebooks](http://jupyter-notebook.readthedocs.io/en/latest/notebook.html#notebook-documents)) What is pyGIMLi **NOT** suited for? -* for people that expect a ready-made GUI for interpreting their data +- for people that expect a ready-made GUI for interpreting their data -.. _sec:authors: +(sec-authors)= -Authors -------- +## Authors -.. raw:: html +```{raw} html +

+ + + +

+``` -

- - - -

+% .. image:: https://img.shields.io/github/contributors/gimli-org/gimli.svg?style=flat-square +% :target: https://github.com/gimli-org/gimli/graphs/contributors -.. .. image:: https://img.shields.io/github/contributors/gimli-org/gimli.svg?style=flat-square - :target: https://github.com/gimli-org/gimli/graphs/contributors - -We gratefully acknowledge all contributors to the pyGIMLi open-source project and look forward to `your contribution `_! +We gratefully acknowledge all contributors to the pyGIMLi open-source project and look forward to [your contribution](https://pygimli.org/contrib.html)! +```{eval-rst} .. include:: ../AUTHORS.rst +``` -.. _sec:about_gimli_inversion: +(sec-about-gimli-inversion)= -Inversion ---------- +## Inversion One main task of pyGIMli is to carry out inversion, i.e. error-weighted minimization, for given forward routines and data. Various types of @@ -55,53 +53,41 @@ regularization on meshes (1D, 2D, 3D) with regular or irregular arrangement are available. There is flexible control of all inversion parameters. The default inversion framework is based on the generalized Gauss-Newton method. -Please see :ref:`tut:inversion` for examples and more +Please see {ref}`tut:inversion` for examples and more details. -.. _sec:about_gimli_modelling: +(sec-about-gimli-modelling)= -Modelling ---------- +## Modelling pyGIMLi comes with various geophysical forward operators, which can directly be used for a given problem. In addition, abstract finite-element and finite-volume interfaces are available to solve custom PDEs on a given mesh. See -:mod:`pygimli.physics` for a collection of forward operators and -:mod:`pygimli.solver` for the solver interface. +{mod}`pygimli.physics` for a collection of forward operators and +{mod}`pygimli.solver` for the solver interface. The modelling capabilities of pyGIMLi include: -* 1D, 2D, 3D discretizations -* linear and quadratic shape functions (automatic shape function generator for possible higher order) -* Triangle, Quads, Tetrahedron, Prism and Hexahedron, mixed meshes -* solver for elliptic problems (Helmholtz-type PDE) +- 1D, 2D, 3D discretizations +- linear and quadratic shape functions (automatic shape function generator for possible higher order) +- Triangle, Quads, Tetrahedron, Prism and Hexahedron, mixed meshes +- solver for elliptic problems (Helmholtz-type PDE) -Please see :ref:`tut:modelling` for examples and more details. +Please see {ref}`tut:modelling` for examples and more details. -License -------- -pyGIMLi is distributed under the terms of the **Apache 2.0** license. Details on -the license agreement can be found `here -`_. +## License +pyGIMLi is distributed under the terms of the **Apache 2.0** license. Details on +the license agreement can be found [here](https://www.pygimli.org/license.html). -Credits -------- +## Credits We use or link some third-party software (beside the usual tool stack: cmake, gcc, boost, python, numpy, scipy, matplotlib) and are grateful for all the work made by the authors of these awesome open-source tools: -* libkdtree++: Maybe abandoned, mirror: https://github.com/nvmd/libkdtree - -* meshio: https://github.com/nschloe/meshio - -* pyplusplus: https://pypi.org/project/pyplusplus/ - -* pyvista: https://docs.pyvista.org/ - -* suitesparse, umfpack: https://people.engr.tamu.edu/davis/suitesparse.html - -* Tetgen: http://wias-berlin.de/software/index.jsp?id=TetGen&lang=1 - -* Triangle: https://www.cs.cmu.edu/~quake/triangle.html - - +- libkdtree++: Maybe abandoned, mirror: +- meshio: +- pyplusplus: +- pyvista: +- suitesparse, umfpack: +- Tetgen: +- Triangle: diff --git a/doc/development/dependencies.md b/doc/development/dependencies.md index 669357fe7..824798d1f 100644 --- a/doc/development/dependencies.md +++ b/doc/development/dependencies.md @@ -1,53 +1,60 @@ -.. _sec:install_pre: +(sec-install-pre)= -Prerequisites -------------- +# Prerequisites To build pyGIMLi from source, the following tools are required: -* subversion, git, mercurial, wget, tar -* cmake >= 2.8.10 -* gcc >= 4.4 -* >=Python-3.5 | >=Python-2.7 -* numpy-dev -* >=matplotlib-3.0 -* >=clang++-3.6.0 (3.7.0, 3.8.0) -* libclang-3.7-dev -* >=llvm-3.6.0 (3.7.0, 3.8.0) -* libz-dev -* python-setuptools - - tested on: - - * gentoo x86_64: gcc-4.4.5, gcc-4.5.3, gcc-4.5.4, gcc-4.9.2 gcc-5.3.0 - * Debian 3.2.46-1 x86_64: gcc-4.7.2 - * Ubuntu 16.04 LTS with gcc-5.4.0 - * Arch Linux gcc-5.2.0 - * CentOS - * MinGW32: gcc-4.6.2/4, gcc-4.7.2, gcc-5.2.0 - * MinGW64: gcc-4.5.4, gcc-5.2.0, gcc-6.3.0, gcc-7.1.0 - -Optional Prerequisites -...................... +- subversion, git, mercurial, wget, tar + +- cmake >= 2.8.10 + +- gcc >= 4.4 + +- \>=Python-3.5 | >=Python-2.7 + +- numpy-dev + +- \>=matplotlib-3.0 + +- \>=clang++-3.6.0 (3.7.0, 3.8.0) + +- libclang-3.7-dev + +- \>=llvm-3.6.0 (3.7.0, 3.8.0) + +- libz-dev + +- python-setuptools + + > tested on: + > + > - gentoo x86_64: gcc-4.4.5, gcc-4.5.3, gcc-4.5.4, gcc-4.9.2 gcc-5.3.0 + > - Debian 3.2.46-1 x86_64: gcc-4.7.2 + > - Ubuntu 16.04 LTS with gcc-5.4.0 + > - Arch Linux gcc-5.2.0 + > - CentOS + > - MinGW32: gcc-4.6.2/4, gcc-4.7.2, gcc-5.2.0 + > - MinGW64: gcc-4.5.4, gcc-5.2.0, gcc-6.3.0, gcc-7.1.0 + +## Optional Prerequisites These tools can be installed system-wide with your native package manager (i.e. apt-get). If not found, the provided build scripts will automatically download and compile the necessary components. -* libboost >=1.46 (python) (1.46, 1.48, 1.49, 1.51, 1.52, 1.53, 1.57) -* blas and lapack for suitesparse (system or auto via cmake) -* SuiteSparse (http://faculty.cse.tamu.edu/davis/suitesparse.html) -* cppunit -* procps -* triangle (http://www.cs.cmu.edu/~quake/triangle.html) +- libboost >=1.46 (python) (1.46, 1.48, 1.49, 1.51, 1.52, 1.53, 1.57) +- blas and lapack for suitesparse (system or auto via cmake) +- SuiteSparse () +- cppunit +- procps +- triangle () -Prerequisites automatically installed by the installer -...................................................... +## Prerequisites automatically installed by the installer These tools are required to create the Python bindings and are likely to be outdated in your distribution and should therefore not be installed system-wide. The build scripts will install them automatically. -* castxml -* pygccxml -* pyplusplus +- castxml +- pygccxml +- pyplusplus From 0df3a821d6071705043300116372ab9da4ade2f5 Mon Sep 17 00:00:00 2001 From: Nino Menzel Date: Wed, 20 Mar 2024 13:11:31 +0100 Subject: [PATCH 014/102] DOC Solved merge conflict in index.md --- doc/user-guide/index.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/doc/user-guide/index.md b/doc/user-guide/index.md index 089dffce1..8f9b5de83 100644 --- a/doc/user-guide/index.md +++ b/doc/user-guide/index.md @@ -33,14 +33,11 @@ kernelspec: ## Evaluate code ```{code-cell} ipython3 -<<<<<<< Updated upstream --- editable: true slideshow: slide_type: '' --- -======= ->>>>>>> Stashed changes import pygimli as pg mesh = pg.createGrid(20,5) data = pg.x(mesh) @@ -122,12 +119,3 @@ Content 1 :::{tab-item} Label2 Content 2 ::: - -:::: -<<<<<<< Updated upstream -======= - -```{code-cell} ipython3 - -``` ->>>>>>> Stashed changes From 7062c5927249c7cae95c124310dcc47bdf0fa609 Mon Sep 17 00:00:00 2001 From: "andreabalzam@gmail.com" Date: Wed, 20 Mar 2024 16:16:23 +0100 Subject: [PATCH 015/102] DOC:Add table of import --- doc/user-guide/data.md | 36 ++++++++++++++++++++++++++---------- doc/user-guide/index.md | 10 ++++++++++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/doc/user-guide/data.md b/doc/user-guide/data.md index ed0025e31..dc6703fa4 100644 --- a/doc/user-guide/data.md +++ b/doc/user-guide/data.md @@ -16,7 +16,7 @@ kernelspec: +++ -## What is a `DataContainer` +## What is a `DataContainer`? +++ {"editable": true, "slideshow": {"slide_type": ""}} @@ -27,6 +27,7 @@ A data container holds vectors like in a dictionary, however, all of them need t ```{code-cell} ipython3 --- +editable: true slideshow: slide_type: '' tags: [hide-cell] @@ -64,7 +65,7 @@ print(ves_data) One can also use `showInfos()` to see the content of the data container with more wording. ```{code-cell} ipython3 -data.showInfos() +ves_data.showInfos() ``` As you can see from the print out there is no sensor information. In the next subsection we will explain how to add sensor information to a data container. @@ -142,11 +143,6 @@ At any point we can add sensors in the data container. data.showInfos() ``` -:::{admonition} Note -:class: tip - -+++ - ## File export +++ @@ -162,11 +158,31 @@ print(open("data.dat").read()) +++ -Now we will go over the case if you have your own data and want to first import it using pyGIMLi and assign it to a data container. +Now we will go over the case if you have your own data and want to first import it using pyGIMLi and assign it to a data container. You can manually do this by importing data via Python (data must be assigned as Numpy arrays) and assign the values to the different keys in the data container. -```{code-cell} ipython3 +However, pyGIMLi makes it easier for you using the different physics managers. For example, the `pygimli.physics.ert` has the `load()` function which supports most data formats. `pygimli.physics.em` has a `readusffile` function that reads data from single universal sounding file. Below is a table of the current loading utilities for every method -``` ++++ {"editable": true, "slideshow": {"slide_type": ""}, "tags": ["hide-cell"]} + +:::{admonition} Table of available import functions +:class: tip + +:::{table} Commands to import data types depending on the physics manager +:widths: auto +:align: center + +| physics manager | available loading functions | +| --- | --- | +| em | {py:func}`importMaxminData `, {py:func}`readusffile `, {py:func}`readHEMData `, {py:func}`importEmsysAsciiData ` | +| ert |{py:func}`load ` | +| SIP | {py:func}`load ` | +| traveltime | {py:func}`load `| +| ves | {py:func}`loadData ` | +::: + +::: + ++++ ## Visualization diff --git a/doc/user-guide/index.md b/doc/user-guide/index.md index 8f9b5de83..96e2d56a8 100644 --- a/doc/user-guide/index.md +++ b/doc/user-guide/index.md @@ -44,7 +44,17 @@ data = pg.x(mesh) pg.show(mesh, data) ``` ++++ {"editable": true, "slideshow": {"slide_type": ""}} + ++++ {"editable": true, "slideshow": {"slide_type": ""}} + +<<<<<<< Updated upstream ++++ {"editable": true, "slideshow": {"slide_type": ""}} + ## Some Markdown features +======= +## Some Markdown features +>>>>>>> Stashed changes ### Math From 79cdc482ec5f13536715ae1adf6cb2dea0eadd64 Mon Sep 17 00:00:00 2001 From: Nino Menzel Date: Wed, 20 Mar 2024 16:27:15 +0100 Subject: [PATCH 016/102] DOC: Added next chapters to meshes.md --- doc/user-guide/meshes.md | 155 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 148 insertions(+), 7 deletions(-) diff --git a/doc/user-guide/meshes.md b/doc/user-guide/meshes.md index 5dfd1b8c5..2bcebf296 100644 --- a/doc/user-guide/meshes.md +++ b/doc/user-guide/meshes.md @@ -29,13 +29,12 @@ We start off by looking at the general anatomy of a pyGIMLi mesh. It is represen ```{code-cell} ipython3 --- editable: true -jupyter: - source_hidden: true slideshow: slide_type: '' --- import matplotlib.pyplot as plt import pygimli as pg +import numpy as np from matplotlib.patches import Circle from matplotlib.patheffects import withStroke @@ -215,20 +214,85 @@ pg.show(m_reg) :widths: 200px :align: center -| Command | Useage | -| :---------------- | :------: | -| mesh.cells() | Allows to access mesh cells | -| mesh.cell() | Allows to access a single cell (using the cell ID) | +| Command | Useage | Source code | +| :---------------- | :------: | :------: | +| pg.meshtools.createGrid() | Creates a grid-style mesh | [source code](https://www.pygimli.org/_modules/pygimli/meshtools/grid.html#createGrid)| ::: +++ ### Creating an irregular mesh with pyGIMLi -After covering the basics of regular meshes +After covering the basics of regular grids, we want to dive into the world of irregular meshes. + +However, we first of all have to create a **geometry** that is used as underlying susurface model for the mesh creation. + +```{code-cell} ipython3 +import pygimli as pg # import pygimli with short name +from pygimli import meshtools as mt # import a module + +# dimensions of the world +left = -30 +right = 30 +depth = 25 + +world = mt.createWorld(start=[left, 0], + end=[right, -depth], + layers=[-5]) +print(world) +pg.show(world) +``` + +We are using the mt.createWorld() function to create a world based on the gíven x- & z-coordinates. The following table lists all handy functions that can be utilized when creating a geometry in pyGIMLi: + +:::{admonition} PLC creation in pyGIMLi +:class: tip +:::{table} **General commands for geometry creations** +:widths: 200px +:align: center + +| Command | Useage | +| :---------------- | :------: | +| {py:class}`createWorld ` | Creates a PLC out of a given geometry | +| {py:class}`createCircle ` | Creates a circular PLC | +| {py:class}`createCube ` | Creates a cubic PLC | +| {py:class}`createCylinder ` | Creates a cylindric PLC | +| {py:class}`createLine ` | Creates a line polygon | +| {py:class}`createPolygon ` | Creates a polygon from a list of vertices | +| {py:class}`createRectangle ` | Creates a rectangular PLC | +::: +++ +To not over-simplify the example, we will add a dipping interface into our subsurface model by adding a simple line. To combine two PLC's, we can simply add them to each other: + +```{code-cell} ipython3 +line = mt.createLine(start=[left, -20], end=[right, -15]) +geometry = world + line +pg.show(geometry) +``` + +Note that the line cuts region 2 dividing it into two. The upper part does not contain a region marker and thus becomes region 0. + + +pyGIMLi has different ways to create meshes. mt.createMesh creates a mesh using Triangle, a two-dimensional constrained Delaunay mesh generator. + +The additional input parameters control the maximum triangle area and the mesh smoothness. The quality factor prescribes the minimum angles allowed in the final mesh. This can improve numerical accuracy, however, fine meshes lead to increased computational costs. Notice that we are now using showMesh which is convenient for 2D mesh visualization. + +```{code-cell} ipython3 +from pygimli.viewer import showMesh +mesh = mt.createMesh(geometry, + area=2.0, + quality=33, + smooth=[2, 4] # [0:no smoothing or 1:node center or 2:weighted node center, # of iter] + ) +showMesh(mesh, markers=True, showMesh=True); +``` + +As there are different ways to generate a mesh in pyGIMLi, we + ++++ {"jp-MarkdownHeadingCollapsed": true} + ## Mesh import +++ @@ -241,6 +305,83 @@ After covering the basics of regular meshes +++ +pyGIMLi provides a variety of operators to modify your mesh. The following table gives an overview of the most important functions: + +:::{admonition} Mesh modifications +:class: tip +:::{table} +:widths: 200px +:align: center + +| Command | Useage | +| :---------------- | :------: | +| {py:class}`merge2Meshes ` | Merges two meshes | +| {py:class}`mergeMeshes ` | Merges two or more meshes | +| mesh.translate() | Allows to translate a mesh | +| mesh.scale()` | Scale a mesh with provided factors | +| mesh.rotate()` | Rotate a provided mesh | +::: + ++++ + +### Merging meshes + +In some cases, the modelling domain may require different degrees of flexibility in separate mesh regions. In the following, we demonstrate this for a two-dimensional mesh consisting of a region with regularly spaced quadrilaterals and a region with unstructured triangles. + +pyGIMLi offers the possibility to merge two meshes by calling {py:class}`merge2Meshes `. + +```{code-cell} ipython3 +xmin, xmax = -30, 30. +zmin, zmax = -50, -25. + +xreg = np.linspace(xmin, xmax, 30) +zreg = np.linspace(zmin, zmax, 25) + +mesh2merge = mt.createGrid(xreg, zreg, marker=3) +mergedMesh = mt.merge2Meshes(mesh,mesh2merge) +pg.show(mergedMesh, markers=True, showMesh=True) +``` + +The merged meshes appear as a singular hybrid mesh now, so we can append a triangle boundary as for non-hybrid meshes: + +```{code-cell} ipython3 +mesh_append = mt.appendTriangleBoundary(mergedMesh, xbound=50., ybound=50., quality=31, smooth=True, + marker=4, isSubSurface=True, addNodes=10) + +ax, cb = pg.show(mesh_append) +``` + +When merging more than two meshes, the function {py:class}`mergeMeshes() ` can be utilized instead of {py:class}`merge2Meshes `. + ++++ + +### Translating meshes + +To perform simple changes of the meshs x- and z-coordinates, we can make use of the {py:class}`translate ` function. The following lines of code move the mesh 500 m in x and 25 m in z direction: + +```{code-cell} ipython3 +translated_mesh = pg.Mesh(mesh) +translated_mesh.translate([500, 25]) +pg.show(translated_mesh) +``` + +### Scaling meshes + +Apart from moving the mesh along its axes, pyGIMLi also provides a tool to scale the mesh + +```{code-cell} ipython3 +scaled_mesh = pg.Mesh(mesh) +scaled_mesh.scale([1, 2]) +pg.show(scaled_mesh) +``` + +```{code-cell} ipython3 +import numpy as np +rotated_mesh = pg.Mesh(mesh) +rotated_mesh.rotate([0, 0, np.deg2rad(-20)]) +pg.show(rotated_mesh) +``` + ## Mesh export ```{code-cell} ipython3 From 696ec4eb4a8ff919f609355e908e3a94e552cf60 Mon Sep 17 00:00:00 2001 From: "Marc S. Boxberg" Date: Wed, 20 Mar 2024 16:48:51 +0100 Subject: [PATCH 017/102] DOC: Added more references. --- doc/references.bib | 87 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/doc/references.bib b/doc/references.bib index 327e2638d..9bb624cfc 100644 --- a/doc/references.bib +++ b/doc/references.bib @@ -627,5 +627,90 @@ @Article{GuentherRueSpi2006 doi = {10.1111/j.1365-246X.2006.03011.x}, } -@Comment{jabref-meta: databaseType:bibtex;} +@Article{WagnerGueSchMau2015GEO, + author = {Wagner, F.M. and G{\"u}nther, T. and Schmidt-Hattenberger, C. and Maurer, H.}, + year = {2015}, + title = {{C}onstructive optimization of electrode locations for target-focused resistivity monitoring}, + journal = {Geophysics}, + volume = {80}, + pages = {E29--E40}, + doi = {10.1190/geo2014-0214.1}, +} + +@Inproceedings{IgelStaGue2016SAGEEP, + author = {Igel, J. and Stadler, S. and Günther, T.}, + year = {2016}, + title = {{H}igh-resolution investigation of the capillary transition zone and its influence on {GPR} signatures}, + booktitle = {Ext. Abstr., SAGEEP, Denver, USA}, + doi = {10.4133/SAGEEP.29-046}, +} + +@Article{CostabelGue2014VZJ, + author = {Costabel, S. and G\"unther, T.}, + year = {2014}, + title = {{N}oninvasive {E}stimation of {W}ater {R}etention {P}arameters by {O}bserving the {C}apillary {F}ringe with {M}agnetic {R}esonance {S}ounding}, + journal = {Vadose Zone Journal}, + volume = {13}, + pages = {14}, + doi = {10.2136/vzj2013.09.0163}, +} + +@Article{GuentherMue2012HESS, + author = {G\"unther, T. and M\"uller-Petke, M.} + year = {2012}, + title = {{H}ydraulic properties at the {N}orth {S}ea island of {B}orkum derived from joint inversion of magnetic resonance and electrical resistivity soundings}, + journal = {Hydrology and Earth System Sciences}, + volume = {16}, + pages = {3279--3291}, + doi = {10.5194/hess-16-3279-2012}, +} + +@Article{BechtoldVanWei2012, + author = {Bechtold, M. and Vanderborght, J. and Weihermüller, L. and Herbst, M. and G\"unther, T. and Ippisch, O. and Kasteel, R. and Vereecken, H.}, + year = {2012}, + title = {{U}pward {T}ransport in a {T}hree-{D}imensional {H}eterogeneous {L}aboratory {S}oil under {E}vaporation {C}onditions}, + journal = {Vadose Zone Journal}, + volume = {11}, + doi = {10.2136/vzj2011.0066}, +} + +@Article{CostabelGueDluMue2016, + author = {Costabel, S. and G\"unther, T. and Dlugosch, R. and M\"uller-Petke, M.}, + year = {2016}, + title = {{T}orus-nuclear magnetic resonance: {Q}uasicontinuous airborne magnetic resonance profiling by using a helium-filled balloon}, + journal = {Geophysics}, + volume = {81}, + pages = {WB119--WB129}, + doi = {10.1190/geo2015-0467.1}, +} + +@Article{guenther2016JoAG, + author = {G{\"u}nther, T. and Martin, T.}, + year = {2016}, + title = {{S}pectral two-dimensional inversion of frequency-domain induced polarisation data from a mining slag heap}, + journal = {Journal of Applied Geophysics}, + volume = {135}, + pages = {436--448}, + doi = {10.1016/j.jappgeo.2016.01.008}, +} + +@Article{Ronczka_2016, + author = {Ronczka, M. and Hellman, K. and G{\"u}nther, T. and Wisen, R. and Dahlin, T.}, + year = {2016}, + title = {Electric resistivity and seismic refraction tomography, a challenging joint underwater survey at \"Asp\"o hard rock laboratory}, + journal = {Solid Earth Discussions}, + pages = {1--22}, + doi = {10.5194/se-2016-157}, +} +@Article{AttwaAkcBas2014, + author = {Attwa, M. and Akca, I. and Basokur, A.T. and G\"unther, T.}, + year = {2014}, + title = {{S}tructure-based geoelectrical models derived from genetic algorithms: {A} case study for hydrogeological investigations along {E}lbe {R}iver coastal area, {G}ermany}, + journal = {Journal of Applied Geophysics}, + volume = {103}, + pages = {57--70}, + doi = {10.1016/j.jappgeo.2014.01.006}, +} + +@Comment{jabref-meta: databaseType:bibtex;} From b3427e460ebca03d1f42109917f74cb4d9a1cda2 Mon Sep 17 00:00:00 2001 From: "andreabalzam@gmail.com" Date: Wed, 20 Mar 2024 17:19:51 +0100 Subject: [PATCH 018/102] DOC: Add other files to complete user guide structure --- doc/user-guide/advanced-users.md | 25 +++++++++++++++++++++++++ doc/user-guide/data.md | 12 ++++++------ doc/user-guide/fundamentals.md | 23 +++++++++++++++++++++++ doc/user-guide/modelling.md | 26 ++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 doc/user-guide/advanced-users.md create mode 100644 doc/user-guide/fundamentals.md create mode 100644 doc/user-guide/modelling.md diff --git a/doc/user-guide/advanced-users.md b/doc/user-guide/advanced-users.md new file mode 100644 index 000000000..2ba9cf94a --- /dev/null +++ b/doc/user-guide/advanced-users.md @@ -0,0 +1,25 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# Advanced users + ++++ + +## Setting up your own inversion with custom forward operator +## HPC & Parallelization ! +## Caching ! + +```{code-cell} ipython3 + +``` diff --git a/doc/user-guide/data.md b/doc/user-guide/data.md index dc6703fa4..35d02b15a 100644 --- a/doc/user-guide/data.md +++ b/doc/user-guide/data.md @@ -16,7 +16,7 @@ kernelspec: +++ -## What is a `DataContainer`? +## What is a pyGIMLi DataContainer? +++ {"editable": true, "slideshow": {"slide_type": ""}} @@ -75,7 +75,7 @@ As you can see from the print out there is no sensor information. In the next su :::{admonition} Note :class: tip -Data containers can also be initialized from different method managers. These have the custom names for sensors and data types of each method. For example `pygimli.physics.ert.DataContainer` already has ['a', 'b', 'm', 'n'] entries. One can also add alias translators like C1, C2, P1, P2, so that dataERT[“P1”] will return dataERT[“m”] +Data containers can also be initialized from different method managers. These have the custom names for sensors and data types of each method. For example {py:class}`pygimli.physics.ert.DataContainer` already has ['a', 'b', 'm', 'n'] entries. One can also add alias translators like C1, C2, P1, P2, so that dataERT[“P1”] will return dataERT[“m”] ::: +++ @@ -160,7 +160,9 @@ print(open("data.dat").read()) Now we will go over the case if you have your own data and want to first import it using pyGIMLi and assign it to a data container. You can manually do this by importing data via Python (data must be assigned as Numpy arrays) and assign the values to the different keys in the data container. -However, pyGIMLi makes it easier for you using the different physics managers. For example, the `pygimli.physics.ert` has the `load()` function which supports most data formats. `pygimli.physics.em` has a `readusffile` function that reads data from single universal sounding file. Below is a table of the current loading utilities for every method +pyGIMLi also uses {py:func}`pygimli.load` that loads meshes and data files. It should handle most data types since it detects the headings and file extensions to get a good guess on how to load the data. + +Most methods also have the `load` function to load common data types used for the method. Such as, {py:func}`pygimli.physics.ert.load`. However, some methods have moe specific functions. Below is a table of the current loading utilities for every method. +++ {"editable": true, "slideshow": {"slide_type": ""}, "tags": ["hide-cell"]} @@ -174,10 +176,8 @@ However, pyGIMLi makes it easier for you using the different physics managers. F | physics manager | available loading functions | | --- | --- | | em | {py:func}`importMaxminData `, {py:func}`readusffile `, {py:func}`readHEMData `, {py:func}`importEmsysAsciiData ` | -| ert |{py:func}`load ` | -| SIP | {py:func}`load ` | -| traveltime | {py:func}`load `| | ves | {py:func}`loadData ` | + ::: ::: diff --git a/doc/user-guide/fundamentals.md b/doc/user-guide/fundamentals.md new file mode 100644 index 000000000..32a05ed7f --- /dev/null +++ b/doc/user-guide/fundamentals.md @@ -0,0 +1,23 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# Fundamentals + ++++ {"editable": true, "slideshow": {"slide_type": ""}, "tags": ["hide-cell"]} + +## Software design + +## Module/method overview ! +## Basic pyGIMLi classes ! +## Viewer interface ! diff --git a/doc/user-guide/modelling.md b/doc/user-guide/modelling.md new file mode 100644 index 000000000..8c54e521d --- /dev/null +++ b/doc/user-guide/modelling.md @@ -0,0 +1,26 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# Modelling + ++++ + +## Theory (Basics of Finite Element Analysis) +## Parameterizing a mesh with physical properties +## Boundary conditions +## Quantification of modeling errors + +```{code-cell} ipython3 + +``` From 5be602f81c39edc8be5cc0529ef8ef953b97ee0d Mon Sep 17 00:00:00 2001 From: "andreabalzam@gmail.com" Date: Wed, 20 Mar 2024 17:34:34 +0100 Subject: [PATCH 019/102] Fix index file --- doc/user-guide/index.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/doc/user-guide/index.md b/doc/user-guide/index.md index 96e2d56a8..ee2bad1eb 100644 --- a/doc/user-guide/index.md +++ b/doc/user-guide/index.md @@ -44,17 +44,9 @@ data = pg.x(mesh) pg.show(mesh, data) ``` -+++ {"editable": true, "slideshow": {"slide_type": ""}} - -+++ {"editable": true, "slideshow": {"slide_type": ""}} - -<<<<<<< Updated upstream -+++ {"editable": true, "slideshow": {"slide_type": ""}} ## Some Markdown features -======= -## Some Markdown features ->>>>>>> Stashed changes + ### Math From 47627a436b2b56424aa38eb0fc4b1fad0277b9d1 Mon Sep 17 00:00:00 2001 From: Nino Menzel Date: Wed, 20 Mar 2024 18:02:25 +0100 Subject: [PATCH 020/102] DOC: Added more chapters for user-guide/meshes. --- doc/user-guide/meshes.md | 97 ++++++++++++++++++++++++++++------------ 1 file changed, 69 insertions(+), 28 deletions(-) diff --git a/doc/user-guide/meshes.md b/doc/user-guide/meshes.md index 2bcebf296..80099da3b 100644 --- a/doc/user-guide/meshes.md +++ b/doc/user-guide/meshes.md @@ -16,8 +16,6 @@ kernelspec: # User guide - mesh section - - This part of the user guide covers mesh-related topics, starting with a [general introduction](#basics-of-the-mesh-class) to the mesh class. Moreover, this section introduces general operations to [create](#mesh-creation) or [import](#mesh-import) meshes. Moreover, the general aspects of [visualization](#mesh-visualization) are covered within this section. @@ -42,7 +40,7 @@ from matplotlib.patheffects import withStroke def circle(x, y, text=None, radius=0.15, c="blue"): circle = Circle((x, y), radius, clip_on=False, zorder=10, linewidth=1, - edgecolor='black', facecolor=(0, 0, 0, .0125), + edgecolor='black', facecolor=(0, 0, 0, .0125), path_effects=[withStroke(linewidth=5, foreground='w')]) ax.add_artist(circle) ax.plot(x, y, color=c, marker=".") @@ -117,7 +115,7 @@ The mesh class holds either geometric definitions (piece-wise linear complex - * :widths: auto :align: center -| Command | Useage | +| Function | Usage | | :---------------- | :------: | | mesh.cells() | Allows to access mesh cells | | mesh.cell() | Allows to access a single cell (using the cell ID) | @@ -210,13 +208,13 @@ pg.show(m_reg) :::{admonition} Regular grids in 2D :class: tip -:::{table} **General commands for 2D regular grids** +:::{table} :widths: 200px :align: center -| Command | Useage | Source code | -| :---------------- | :------: | :------: | -| pg.meshtools.createGrid() | Creates a grid-style mesh | [source code](https://www.pygimli.org/_modules/pygimli/meshtools/grid.html#createGrid)| +| Function | Usage | +| :---------------- | :------: | +| {py:class}`createWorld ` | Creates a world based on provided x- and z-coordinates | ::: +++ @@ -251,15 +249,15 @@ We are using the mt.createWorld() function to create a world based on the gíven :widths: 200px :align: center -| Command | Useage | +| Function | Usage | | :---------------- | :------: | -| {py:class}`createWorld ` | Creates a PLC out of a given geometry | -| {py:class}`createCircle ` | Creates a circular PLC | -| {py:class}`createCube ` | Creates a cubic PLC | -| {py:class}`createCylinder ` | Creates a cylindric PLC | -| {py:class}`createLine ` | Creates a line polygon | -| {py:class}`createPolygon ` | Creates a polygon from a list of vertices | -| {py:class}`createRectangle ` | Creates a rectangular PLC | +| {py:class}`createWorld ` | Creates a PLC out of a given geometry | +| {py:class}`createCircle ` | Creates a circular PLC | +| {py:class}`createCube ` | Creates a cubic PLC | +| {py:class}`createCylinder ` | Creates a cylindric PLC | +| {py:class}`createLine ` | Creates a line polygon | +| {py:class}`createPolygon ` | Creates a polygon from a list of vertices | +| {py:class}`createRectangle ` | Creates a rectangular PLC | ::: +++ @@ -281,6 +279,7 @@ The additional input parameters control the maximum triangle area and the mesh s ```{code-cell} ipython3 from pygimli.viewer import showMesh + mesh = mt.createMesh(geometry, area=2.0, quality=33, @@ -289,11 +288,38 @@ mesh = mt.createMesh(geometry, showMesh(mesh, markers=True, showMesh=True); ``` -As there are different ways to generate a mesh in pyGIMLi, we +## Mesh import -+++ {"jp-MarkdownHeadingCollapsed": true} ++++ -## Mesh import +### Import options for meshes in pyGIMLi + +A broad variety of functions to import and convert different mesh types into a GIMLI mesh object exists within pyGIMLi. The following functions are the most commonly used ones: + +:::{admonition} PLC creation in pyGIMLi +:class: tip +:::{table} +:widths: 200px +:align: center + +| Function | Usage | +| :---------------- | :------: | +| {py:class}`FenicsHDF5Mesh ` | Read FEniCS mesh from .h5 format and return a GIMLI mesh object | +| {py:class}`Gmsh ` | Read GMSH ASCII file and return a GIMLI mesh object | +| {py:class}`HDF5Mesh ` | Load a mesh from HDF5 file format | +| {py:class}`Hydrus2dMesh ` | Import mesh from Hydrus 2D | +| {py:class}`Hydrus3dMesh ` | Import mesh from Hydrus 3D | +| {py:class}`MeshIO ` | Read generic meshIO mesh | +| {py:class}`STL ` | Read STL surface mesh and converts to GIMLI mesh object | +| {py:class}`Tetgen ` | Read and convert a mesh from the basic Tetgen output | +| {py:class}`Triangle ` | Read Triangle mesh | +::: + ++++ + +### Example: mesh generation using Gmsh + +When the scientific task requires a complex finite-element discretization (i.e. incorporation of structural information, usage of a complete electrode model (CEM), etc.), external meshing tools with visualization capabilities may be the option of choice for some users. In general, the bindings provided by pygimli allow to interface any external mesh generation software. +++ @@ -313,10 +339,10 @@ pyGIMLi provides a variety of operators to modify your mesh. The following table :widths: 200px :align: center -| Command | Useage | +| Function | Usage | | :---------------- | :------: | -| {py:class}`merge2Meshes ` | Merges two meshes | -| {py:class}`mergeMeshes ` | Merges two or more meshes | +| {py:class}`merge2Meshes ` | Merges two meshes | +| {py:class}`mergeMeshes ` | Merges two or more meshes | | mesh.translate() | Allows to translate a mesh | | mesh.scale()` | Scale a mesh with provided factors | | mesh.rotate()` | Rotate a provided mesh | @@ -367,7 +393,7 @@ pg.show(translated_mesh) ### Scaling meshes -Apart from moving the mesh along its axes, pyGIMLi also provides a tool to scale the mesh +Apart from moving the mesh along its axes, pyGIMLi also provides a tool to scale the mesh along specified axes - in this example, we scale along the z-axis with a factor of 2: ```{code-cell} ipython3 scaled_mesh = pg.Mesh(mesh) @@ -375,6 +401,8 @@ scaled_mesh.scale([1, 2]) pg.show(scaled_mesh) ``` +Another valuable mesh modification tool is the mesh.rotate function. By providing a rotation angle and the rotation plane, we can adjust the orientation angle of our mesh: + ```{code-cell} ipython3 import numpy as np rotated_mesh = pg.Mesh(mesh) @@ -384,11 +412,24 @@ pg.show(rotated_mesh) ## Mesh export ++++ {"editable": true, "slideshow": {"slide_type": ""}} + +Suppose we want to continue working on our GIMLi mesh object in a different meshing tool - pyGIMLi provides a variety of export functions to transfer your GIMLi mesh into a different format: + +:::{admonition} Mesh export functions +:class: tip +:::{table} +:widths: 200px +:align: center + +| Function | Usage | +| :---------------- | :------: | +| {py:class}` FenicsHDF5Mesh ` | Exports GIMLi mesh in HDF5 format suitable for Fenics | +| {py:class}`HDF5Mesh ` | Writes given GIMLI::Mesh in a hdf5 format file | +| {py:class}` FenicsHDF5Mesh ` | Export a piece-wise linear complex (PLC) to a .poly file (2D or 3D). | +| {py:class}`HDF5Mesh ` | Write STL surface mesh. | +::: + ```{code-cell} ipython3 ---- -editable: true -slideshow: - slide_type: '' ---- ``` From fd3f6bfad3de1f57b025e906ca2194162fbdca65 Mon Sep 17 00:00:00 2001 From: "andreabalzam@gmail.com" Date: Wed, 20 Mar 2024 18:07:42 +0100 Subject: [PATCH 021/102] DOC: add more to the data user guide --- doc/user-guide/advanced-users.md | 1 + doc/user-guide/data.md | 48 +++++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/doc/user-guide/advanced-users.md b/doc/user-guide/advanced-users.md index 2ba9cf94a..6df8daedb 100644 --- a/doc/user-guide/advanced-users.md +++ b/doc/user-guide/advanced-users.md @@ -17,6 +17,7 @@ kernelspec: +++ ## Setting up your own inversion with custom forward operator +## Matrices ## HPC & Parallelization ! ## Caching ! diff --git a/doc/user-guide/data.md b/doc/user-guide/data.md index 35d02b15a..5f2ecce32 100644 --- a/doc/user-guide/data.md +++ b/doc/user-guide/data.md @@ -40,7 +40,7 @@ from pygimli.physics import VESManager +++ {"editable": true, "slideshow": {"slide_type": ""}} -We define logarithmically equidistant AB/2 spacings. Which is the midpoint of current electrode spacing for each measurement. +We define logarithmically equidistant AB/2 spacings. Which is the midpoint of current electrode spacing for each measurement. ```{code-cell} ipython3 ab2 = np.logspace(0, 3, 11) @@ -62,7 +62,7 @@ ves_data["mn2"] = ab2 / 3 print(ves_data) ``` -One can also use `showInfos()` to see the content of the data container with more wording. +One can also use `showInfos()` to see the content of the data container with more wording. ```{code-cell} ipython3 ves_data.showInfos() @@ -84,7 +84,7 @@ Data containers can also be initialized from different method managers. These ha +++ {"editable": true, "slideshow": {"slide_type": ""}} -Assume we have data associate with a transmitter, receivers and a property U. The transmitter (Tx) and receiver (Rx) positions are stored separately and we refer them with an Index (integer). Therefore we define these fields index. +Assume we have data associate with a transmitter, receivers and a property U. The transmitter (Tx) and receiver (Rx) positions are stored separately and we refer them with an Index (integer). Therefore we define these fields index. ```{code-cell} ipython3 --- @@ -112,7 +112,7 @@ We want to use all of them (and two more!) as receivers and a constant transmitt data["Rx"] = np.arange(12) # data["Tx"] = np.arange(9) # does not work as size matters! data["Tx"] = pg.Vector(data.size(), 2) -print(data.sensors()) +print(data) ``` :::{admonition} Note @@ -123,7 +123,7 @@ The positions under the sensor indexes must be of the same size. +++ -You can check the validity of the measurements using a given condition. We can mask or unmask the data with a boolean vector. For example, below we would like to mark valid all receivers that are larger or equal to 0. +You can check the validity of the measurements using a given condition. We can mask or unmask the data with a boolean vector. For example, below we would like to mark valid all receivers that are larger or equal to 0. ```{code-cell} ipython3 data.markValid(data["Rx"] >= 0) @@ -131,13 +131,28 @@ print(data["valid"]) print(len(data["Rx"])) ``` -That adds a 'valid' entry to the data container that contains 1 and 0 values. You can also check the data validity by using `checkDataValidity`. It automatically removes values that are out of the sensor index bounds and reports a validity check. In this case it will remove the two additional values that were added. +That adds a 'valid' entry to the data container that contains 1 and 0 values. You can also check the data validity by using `checkDataValidity`. It automatically removes values that are 0 in the valid field and writes an `invalid.data` file to your local directory. In this case it will remove the two additional values that were marked invalid. ```{code-cell} ipython3 data.checkDataValidity() ``` -At any point we can add sensors in the data container. +You can pass more information about the data set into the data container. For example, here we calculate the distance between transmitter and receiver. + +```{code-cell} ipython3 +sx = pg.x(data) +data["dist"] = np.abs(sx[data["Rx"]] - sx[data["Tx"]]) +print(data["dist"]) +``` + ++++ {"editable": true, "slideshow": {"slide_type": ""}, "tags": ["hide-cell"]} + +You can also do some pre-processing using the validity option again. For example, here we would like to mark as **invalid** where the receiver is the same as the transmitter. + +```{code-cell} ipython3 +data.markInvalid(data["Rx"] == data["Tx"]) +data.checkDataValidity() +``` ```{code-cell} ipython3 data.showInfos() @@ -147,7 +162,7 @@ data.showInfos() +++ -This data container can also be saved on local disk using the method `.save()` usually in a .dat format. It can then be read using `open('filename').read()`. This is also a useful way to see the data file in Python. +This data container can also be saved on local disk using the method `.save()` usually in a .dat format. It can then be read using `open('filename').read()`. This is also a useful way to see the data file in Python. ```{code-cell} ipython3 data.save("data.dat") @@ -162,7 +177,7 @@ Now we will go over the case if you have your own data and want to first import pyGIMLi also uses {py:func}`pygimli.load` that loads meshes and data files. It should handle most data types since it detects the headings and file extensions to get a good guess on how to load the data. -Most methods also have the `load` function to load common data types used for the method. Such as, {py:func}`pygimli.physics.ert.load`. However, some methods have moe specific functions. Below is a table of the current loading utilities for every method. +Most methods also have the `load` function to load common data types used for the method. Such as, {py:func}`pygimli.physics.ert.load`. However, some methods have moe specific functions. Below is a table of the current loading utilities for every method. For a more extensive list of data imports please refer to [pybert importer package](http://resistivity.net/bert/_api/pybert.importer.html#module-pybert.importer). This also has compatability with pyGIMLi +++ {"editable": true, "slideshow": {"slide_type": ""}, "tags": ["hide-cell"]} @@ -179,7 +194,6 @@ Most methods also have the `load` function to load common data types used for th | ves | {py:func}`loadData ` | ::: - ::: +++ @@ -188,6 +202,20 @@ Most methods also have the `load` function to load common data types used for th +++ +You can visualize the data in many ways depending on the physics manager. To simply view the data as a matrix you can use + +```{code-cell} ipython3 +pg.viewer.mpl.showDataContainerAsMatrix(data, "Rx", "Tx", 'dist'); +``` + ++++ {"editable": true, "slideshow": {"slide_type": ""}, "tags": ["hide-cell"]} + +### Main difference between `show` functions and `draw` functions + +```{code-cell} ipython3 + +``` + ## Processing ```{code-cell} ipython3 From 1c4a841c29fa8055e5824efa77468c3b78f245ba Mon Sep 17 00:00:00 2001 From: "andreabalzam@gmail.com" Date: Wed, 20 Mar 2024 18:24:48 +0100 Subject: [PATCH 022/102] DOC: Last changes to data user guide --- doc/user-guide/data.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/doc/user-guide/data.md b/doc/user-guide/data.md index 5f2ecce32..f1f23547f 100644 --- a/doc/user-guide/data.md +++ b/doc/user-guide/data.md @@ -177,7 +177,7 @@ Now we will go over the case if you have your own data and want to first import pyGIMLi also uses {py:func}`pygimli.load` that loads meshes and data files. It should handle most data types since it detects the headings and file extensions to get a good guess on how to load the data. -Most methods also have the `load` function to load common data types used for the method. Such as, {py:func}`pygimli.physics.ert.load`. However, some methods have moe specific functions. Below is a table of the current loading utilities for every method. For a more extensive list of data imports please refer to [pybert importer package](http://resistivity.net/bert/_api/pybert.importer.html#module-pybert.importer). This also has compatability with pyGIMLi +Most methods also have the `load` function to load common data types used for the method. Such as, {py:func}`pygimli.physics.ert.load`. However, some methods have moe specific functions. Below is a table of the current loading utilities for every method. For a more extensive list of data imports please refer to [pybert importer package](http://resistivity.net/bert/_api/pybert.importer.html#module-pybert.importer). +++ {"editable": true, "slideshow": {"slide_type": ""}, "tags": ["hide-cell"]} @@ -202,19 +202,15 @@ Most methods also have the `load` function to load common data types used for th +++ -You can visualize the data in many ways depending on the physics manager. To simply view the data as a matrix you can use +You can visualize the data in many ways depending on the physics manager. To simply view the data as a matrix you can use `pg.viewer.mpl.showDataContainerAsMatrix`. This visualizes a matrix of receivers and transmitters pairs with the associated data to plot : 'dist'. ```{code-cell} ipython3 pg.viewer.mpl.showDataContainerAsMatrix(data, "Rx", "Tx", 'dist'); ``` -+++ {"editable": true, "slideshow": {"slide_type": ""}, "tags": ["hide-cell"]} - -### Main difference between `show` functions and `draw` functions - -```{code-cell} ipython3 +There are more formal ways of plotting different data containers depending on the method. As seen in (link to fundamentals show vs draw) here we can focus on showing the data container. Most of the methods use `show()` however, there are some method-dependent show function in the table below. -``` ++++ ## Processing From 536066403df91091fec388b14328f1c739de3a23 Mon Sep 17 00:00:00 2001 From: Nino Menzel Date: Wed, 20 Mar 2024 18:11:24 +0100 Subject: [PATCH 023/102] DOC: Typos and minor adjustments to links --- doc/user-guide/meshes.md | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/doc/user-guide/meshes.md b/doc/user-guide/meshes.md index 80099da3b..d86a24838 100644 --- a/doc/user-guide/meshes.md +++ b/doc/user-guide/meshes.md @@ -251,13 +251,13 @@ We are using the mt.createWorld() function to create a world based on the gíven | Function | Usage | | :---------------- | :------: | -| {py:class}`createWorld ` | Creates a PLC out of a given geometry | -| {py:class}`createCircle ` | Creates a circular PLC | -| {py:class}`createCube ` | Creates a cubic PLC | -| {py:class}`createCylinder ` | Creates a cylindric PLC | -| {py:class}`createLine ` | Creates a line polygon | -| {py:class}`createPolygon ` | Creates a polygon from a list of vertices | -| {py:class}`createRectangle ` | Creates a rectangular PLC | +| {py:class}`createWorld ` | Creates a PLC out of a given geometry | +| {py:class}`createCircle ` | Creates a circular PLC | +| {py:class}`createCube ` | Creates a cubic PLC | +| {py:class}`createCylinder ` | Creates a cylindric PLC | +| {py:class}`createLine ` | Creates a line polygon | +| {py:class}`createPolygon ` | Creates a polygon from a list of vertices | +| {py:class}`createRectangle ` | Creates a rectangular PLC | ::: +++ @@ -304,15 +304,15 @@ A broad variety of functions to import and convert different mesh types into a G | Function | Usage | | :---------------- | :------: | -| {py:class}`FenicsHDF5Mesh ` | Read FEniCS mesh from .h5 format and return a GIMLI mesh object | -| {py:class}`Gmsh ` | Read GMSH ASCII file and return a GIMLI mesh object | -| {py:class}`HDF5Mesh ` | Load a mesh from HDF5 file format | -| {py:class}`Hydrus2dMesh ` | Import mesh from Hydrus 2D | -| {py:class}`Hydrus3dMesh ` | Import mesh from Hydrus 3D | -| {py:class}`MeshIO ` | Read generic meshIO mesh | -| {py:class}`STL ` | Read STL surface mesh and converts to GIMLI mesh object | -| {py:class}`Tetgen ` | Read and convert a mesh from the basic Tetgen output | -| {py:class}`Triangle ` | Read Triangle mesh | +| {py:class}`FenicsHDF5Mesh ` | Read FEniCS mesh from .h5 format and return a GIMLI mesh object | +| {py:class}`Gmsh ` | Read GMSH ASCII file and return a GIMLI mesh object | +| {py:class}`HDF5Mesh ` | Load a mesh from HDF5 file format | +| {py:class}`Hydrus2dMesh ` | Import mesh from Hydrus 2D | +| {py:class}`Hydrus3dMesh ` | Import mesh from Hydrus 3D | +| {py:class}`MeshIO ` | Read generic meshIO mesh | +| {py:class}`STL ` | Read STL surface mesh and converts to GIMLI mesh object | +| {py:class}`Tetgen ` | Read and convert a mesh from the basic Tetgen output | +| {py:class}`Triangle ` | Read Triangle mesh | ::: +++ @@ -341,8 +341,8 @@ pyGIMLi provides a variety of operators to modify your mesh. The following table | Function | Usage | | :---------------- | :------: | -| {py:class}`merge2Meshes ` | Merges two meshes | -| {py:class}`mergeMeshes ` | Merges two or more meshes | +| {py:class}`merge2Meshes ` | Merges two meshes | +| {py:class}`mergeMeshes ` | Merges two or more meshes | | mesh.translate() | Allows to translate a mesh | | mesh.scale()` | Scale a mesh with provided factors | | mesh.rotate()` | Rotate a provided mesh | @@ -424,10 +424,10 @@ Suppose we want to continue working on our GIMLi mesh object in a different mesh | Function | Usage | | :---------------- | :------: | -| {py:class}` FenicsHDF5Mesh ` | Exports GIMLi mesh in HDF5 format suitable for Fenics | -| {py:class}`HDF5Mesh ` | Writes given GIMLI::Mesh in a hdf5 format file | -| {py:class}` FenicsHDF5Mesh ` | Export a piece-wise linear complex (PLC) to a .poly file (2D or 3D). | -| {py:class}`HDF5Mesh ` | Write STL surface mesh. | +| {py:class}` FenicsHDF5Mesh ` | Exports GIMLi mesh in HDF5 format suitable for Fenics | +| {py:class}`HDF5Mesh ` | Writes given GIMLI::Mesh in a hdf5 format file | +| {py:class}` FenicsHDF5Mesh ` | Export a piece-wise linear complex (PLC) to a .poly file (2D or 3D). | +| {py:class}`HDF5Mesh ` | Write STL surface mesh. | ::: ```{code-cell} ipython3 From 2daa5992e2c09a339e71fe54332b13152458dc3d Mon Sep 17 00:00:00 2001 From: Nino Menzel Date: Wed, 20 Mar 2024 18:27:59 +0100 Subject: [PATCH 024/102] DOC: Added export mesh chapter to user guide --- doc/user-guide/meshes.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/user-guide/meshes.md b/doc/user-guide/meshes.md index d86a24838..f5b1fa53b 100644 --- a/doc/user-guide/meshes.md +++ b/doc/user-guide/meshes.md @@ -401,6 +401,7 @@ scaled_mesh.scale([1, 2]) pg.show(scaled_mesh) ``` +### Rotating meshes Another valuable mesh modification tool is the mesh.rotate function. By providing a rotation angle and the rotation plane, we can adjust the orientation angle of our mesh: ```{code-cell} ipython3 @@ -426,10 +427,17 @@ Suppose we want to continue working on our GIMLi mesh object in a different mesh | :---------------- | :------: | | {py:class}` FenicsHDF5Mesh ` | Exports GIMLi mesh in HDF5 format suitable for Fenics | | {py:class}`HDF5Mesh ` | Writes given GIMLI::Mesh in a hdf5 format file | -| {py:class}` FenicsHDF5Mesh ` | Export a piece-wise linear complex (PLC) to a .poly file (2D or 3D). | -| {py:class}`HDF5Mesh ` | Write STL surface mesh. | +| {py:class}` PLC ` | Export a piece-wise linear complex (PLC) to a .poly file (2D or 3D) | +| {py:class}`STL ` | Write STL surface mesh | +| {py:class}`STL ` | Save mesh alongside properties as vtk | ::: +```{code-cell} ipython3 +# Save rotated mesh from above as vtk file + +rotated_mesh.exportVTK('rotated_mesh.vtk') +``` + ```{code-cell} ipython3 ``` From 81deb726381e8ddb2219caaca5e0d007e0cd90e9 Mon Sep 17 00:00:00 2001 From: Florian Wagner Date: Wed, 20 Mar 2024 18:04:57 +0100 Subject: [PATCH 025/102] DOC: Add cheatsheet --- doc/documentation.rst | 24 +++---- doc/user-guide/cheatsheet.md | 119 +++++++++++++++++++++++++++++++++++ doc/user-guide/index.md | 113 +++------------------------------ environment.yml | 4 +- 4 files changed, 138 insertions(+), 122 deletions(-) create mode 100644 doc/user-guide/cheatsheet.md diff --git a/doc/documentation.rst b/doc/documentation.rst index 2307d9bee..c6858a92d 100644 --- a/doc/documentation.rst +++ b/doc/documentation.rst @@ -80,18 +80,12 @@ Documentation Publications cited in the documentation -.. only:: latex - - .. toctree:: - :maxdepth: 4 - - about.rst - citation.rst - design.rst - installation.rst - faq.rst - _examples_auto/index.rst - _tutorials_auto/index.rst - pygimliapi/index.rst - contrib.rst - glossary.rst +.. toctree:: + :hidden: + + user-guide/index + _examples_auto/index.rst + _tutorials_auto/index.rst + pygimliapi/index.rst + contrib.rst + glossary.rst diff --git a/doc/user-guide/cheatsheet.md b/doc/user-guide/cheatsheet.md new file mode 100644 index 000000000..9ef6b5a15 --- /dev/null +++ b/doc/user-guide/cheatsheet.md @@ -0,0 +1,119 @@ +--- +jupytext: + formats: ipynb,md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + ++++ {"editable": true, "slideshow": {"slide_type": ""}} + +```{contents} Table of Content +:depth: 3 +``` + ++++ {"editable": true, "slideshow": {"slide_type": ""}} + +## Citations + ++++ {"editable": true, "slideshow": {"slide_type": ""}} + +{cite}`Seigel1959` did something great + ++++ {"editable": true, "slideshow": {"slide_type": ""}} + +## Evaluate code + +```{code-cell} ipython3 +--- +editable: true +slideshow: + slide_type: '' +--- +import pygimli as pg +mesh = pg.createGrid(20,5) +data = pg.x(mesh) +pg.show(mesh, data) +``` + +## Some Markdown features + +### Math + +Since Pythagoras, we know that $a^2 + b^2 = c^2$ + +$$ +(a + b)^2 = (a + b)(a + b) \\ + = a^2 + 2ab + b^2 +$$ (mymath2) + +The equation {eq}"mymath2" is also a quadratic equation. + +Some **text-like stuff**! + +:::{admonition} Here's my title +:class: tip + +Here's my admonition content. + +::: + +### Tables + +:::{table} Table caption +:widths: auto +:align: center + +| foo | bar | +| --- | --- | +| baz | bim | +::: + +### Typography + +**strong**, _emphasis_, `literal text`, \*escaped symbols\* + +### Footnotes + +A longer footnote definition.[^mylongdef] + +[^mylongdef]: This is the _**footnote definition**_. + + That continues for all indented lines + + - even other block elements + + Plus any preceding unindented lines, +that are not separated by a blank line + +This is not part of the footnote. + +### Cards + +:::{card} Card Title +Header +^^^ +Card content + ++++ + +Footer +::: + +### Tabs + +::::{tab-set} + +:::{tab-item} Label1 +Content 1 +::: + +:::{tab-item} Label2 +Content 2 +::: diff --git a/doc/user-guide/index.md b/doc/user-guide/index.md index ee2bad1eb..54c8225ad 100644 --- a/doc/user-guide/index.md +++ b/doc/user-guide/index.md @@ -12,112 +12,13 @@ kernelspec: name: python3 --- -+++ {"editable": true, "slideshow": {"slide_type": ""}} - # User guide -```{contents}Table of Content -:depth: 3 -``` - -+++ {"editable": true, "slideshow": {"slide_type": ""}} - -## Citations - -+++ {"editable": true, "slideshow": {"slide_type": ""}} - -{cite}`Seigel1959` did something great - -+++ {"editable": true, "slideshow": {"slide_type": ""}} - -## Evaluate code - -```{code-cell} ipython3 ---- -editable: true -slideshow: - slide_type: '' ---- -import pygimli as pg -mesh = pg.createGrid(20,5) -data = pg.x(mesh) -pg.show(mesh, data) -``` - - -## Some Markdown features - - -### Math - -Since Pythagoras, we know that $a^2 + b^2 = c^2$ - -$$ -(a + b)^2 = (a + b)(a + b) \\ - = a^2 + 2ab + b^2 -$$ (mymath2) - -The equation {eq}"mymath2" is also a quadratic equation. - -Some **text-like stuff**! - -:::{admonition} Here's my title -:class: tip - -Here's my admonition content. - -::: - -### Tables - -:::{table} Table caption -:widths: auto -:align: center - -| foo | bar | -| --- | --- | -| baz | bim | -::: - -### Typography - -**strong**, _emphasis_, `literal text`, \*escaped symbols\* - -### Footnotes - -A longer footnote definition.[^mylongdef] - -[^mylongdef]: This is the _**footnote definition**_. - - That continues for all indented lines - - - even other block elements - - Plus any preceding unindented lines, -that are not separated by a blank line - -This is not part of the footnote. - -### Cards - -:::{card} Card Title -Header -^^^ -Card content - -+++ - -Footer -::: - -### Tabs - -::::{tab-set} - -:::{tab-item} Label1 -Content 1 -::: +:::{toctree} +:numbered: -:::{tab-item} Label2 -Content 2 -::: +test +data +meshes +inversion +::: \ No newline at end of file diff --git a/environment.yml b/environment.yml index 09880fe2d..164cdabda 100644 --- a/environment.yml +++ b/environment.yml @@ -18,7 +18,6 @@ dependencies: - sphinxcontrib-programoutput - sphinxcontrib-spelling - sphinxcontrib-doxylink - - sphinx-tippy - bibtexparser - pyvista[all,trame]>=0.42 - meshio @@ -32,3 +31,6 @@ dependencies: - conda-build - linkify-it-py - jupytext + - pip +pip: + - sphinx-tippy From d9ae1c13d9e4825c693f2e3cfe29ddbbf9885749 Mon Sep 17 00:00:00 2001 From: Florian Wagner Date: Wed, 20 Mar 2024 19:41:33 +0100 Subject: [PATCH 026/102] DOC: Add working version with jupytext config --- CMakeLists.txt | 32 ----------------- .../{advanced-users.md => advanced.md} | 2 -- doc/user-guide/cheatsheet.md | 17 ++++----- doc/user-guide/data.md | 35 ++++++------------- doc/user-guide/fundamentals.md | 5 --- doc/user-guide/index.md | 10 +++++- doc/user-guide/inversion.md | 2 -- doc/user-guide/jupytext.toml | 2 ++ doc/user-guide/meshes.md | 13 ++----- doc/user-guide/modelling.md | 8 ----- 10 files changed, 31 insertions(+), 95 deletions(-) rename doc/user-guide/{advanced-users.md => advanced.md} (83%) create mode 100644 doc/user-guide/jupytext.toml diff --git a/CMakeLists.txt b/CMakeLists.txt index 158687aa5..91b027a0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -668,17 +668,6 @@ if (SPHINX_FOUND AND NOT SKIP_SPHINX) add_subdirectory(doc EXCLUDE_FROM_ALL) message(STATUS "Search recursive for related doc files from here: " ${CMAKE_SOURCE_DIR}) - file(GLOB DOCFILES LIST_DIRECTORIES false - RELATIVE "${CMAKE_SOURCE_DIR}" - "*.rst") - message(STATUS "DOCFILES: " ${DOCFILES}) - - file(GLOB DFILES LIST_DIRECTORIES false - RELATIVE "${CMAKE_SOURCE_DIR}" - "*.md") - message(STATUS "MDFILES: " ${DFILES}) - list(APPEND DOCFILES ${DFILES}) - set (RECDOCTYPES "*.rst" "*.md" "*.png" "*.svg" "*.bib" "paper/*.py") foreach (DTYPE ${RECDOCTYPES}) @@ -689,27 +678,6 @@ if (SPHINX_FOUND AND NOT SKIP_SPHINX) message(STATUS "Append DOC files: (${DTYPE}) " ${DFILES}) list(APPEND DOCFILES ${DFILES}) endforeach() - # message(STATUS "RSTFILES: " ${DFILES}) - - # file(GLOB_RECURSE DFILES LIST_DIRECTORIES false - # RELATIVE "${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}" "./doc/*.md") - # message(STATUS "MDFILES: " ${DFILES}) - # list(APPEND DOCFILES ${DFILES}) - - # file(GLOB_RECURSE DFILES LIST_DIRECTORIES false - # RELATIVE "${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}" "./doc/*.png") - # message(STATUS "PNGFILES: " ${DFILES}) - # list(APPEND DOCFILES ${DFILES}) - - # file(GLOB_RECURSE DFILES LIST_DIRECTORIES false - # RELATIVE "${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}" "./doc/*.bib") - # message(STATUS "BIBFILES: " ${DFILES}) - # list(APPEND DOCFILES ${DFILES}) - - # file(GLOB_RECURSE PYFILES LIST_DIRECTORIES false - # RELATIVE "${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}" "doc/paper/*.py") - # message(STATUS "PYFILES: " ${PYFILES}) - # list(APPEND DOCFILES ${PYFILES}) set(RSTFILES ${DOCFILES} CACHE INTERNAL "RST source file that we need to copy") diff --git a/doc/user-guide/advanced-users.md b/doc/user-guide/advanced.md similarity index 83% rename from doc/user-guide/advanced-users.md rename to doc/user-guide/advanced.md index 6df8daedb..f9d2b52fb 100644 --- a/doc/user-guide/advanced-users.md +++ b/doc/user-guide/advanced.md @@ -5,9 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.1 kernelspec: - display_name: Python 3 (ipykernel) language: python name: python3 --- diff --git a/doc/user-guide/cheatsheet.md b/doc/user-guide/cheatsheet.md index 9ef6b5a15..ef9276df2 100644 --- a/doc/user-guide/cheatsheet.md +++ b/doc/user-guide/cheatsheet.md @@ -5,37 +5,32 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.1 kernelspec: - display_name: Python 3 (ipykernel) language: python name: python3 --- -+++ {"editable": true, "slideshow": {"slide_type": ""}} +# Cheatsheet + ++++ ```{contents} Table of Content :depth: 3 ``` -+++ {"editable": true, "slideshow": {"slide_type": ""}} ++++ ## Citations -+++ {"editable": true, "slideshow": {"slide_type": ""}} ++++ {cite}`Seigel1959` did something great -+++ {"editable": true, "slideshow": {"slide_type": ""}} ++++ ## Evaluate code ```{code-cell} ipython3 ---- -editable: true -slideshow: - slide_type: '' ---- import pygimli as pg mesh = pg.createGrid(20,5) data = pg.x(mesh) diff --git a/doc/user-guide/data.md b/doc/user-guide/data.md index f1f23547f..994239a10 100644 --- a/doc/user-guide/data.md +++ b/doc/user-guide/data.md @@ -5,20 +5,18 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.1 kernelspec: - display_name: Python 3 (ipykernel) language: python name: python3 --- -# User guide - Data in pyGIMLi +# Data +++ ## What is a pyGIMLi DataContainer? -+++ {"editable": true, "slideshow": {"slide_type": ""}} ++++ Data are often organized in a data container storing the individual data values as well as any description how they were obtained, e.g. the geometry of source and receivers. DataContainer is essentially a class that stores all of this information. It is different for every method and can be then filtered accordingly. It stores two primary things: sensor information and data measurements. @@ -26,20 +24,14 @@ Data are often organized in a data container storing the individual data values A data container holds vectors like in a dictionary, however, all of them need to have the same length defined by the .size() method. Let's first go over how you can create a DataContainer from scratch. Assume we want to create and store Vertical Electrical Sounding (VES) data. ```{code-cell} ipython3 ---- -editable: true -slideshow: - slide_type: '' -tags: [hide-cell] ---- +:tags: [hide-cell] + import numpy as np import matplotlib.pyplot as plt import pygimli as pg from pygimli.physics import VESManager ``` -+++ {"editable": true, "slideshow": {"slide_type": ""}} - We define logarithmically equidistant AB/2 spacings. Which is the midpoint of current electrode spacing for each measurement. ```{code-cell} ipython3 @@ -70,7 +62,7 @@ ves_data.showInfos() As you can see from the print out there is no sensor information. In the next subsection we will explain how to add sensor information to a data container. -+++ {"editable": true, "slideshow": {"slide_type": ""}} ++++ :::{admonition} Note :class: tip @@ -82,16 +74,11 @@ Data containers can also be initialized from different method managers. These ha ## Creating Sensors in DataContainer -+++ {"editable": true, "slideshow": {"slide_type": ""}} ++++ Assume we have data associate with a transmitter, receivers and a property U. The transmitter (Tx) and receiver (Rx) positions are stored separately and we refer them with an Index (integer). Therefore we define these fields index. ```{code-cell} ipython3 ---- -editable: true -slideshow: - slide_type: '' ---- data = pg.DataContainer() data.registerSensorIndex("Tx") data.registerSensorIndex("Rx") @@ -131,13 +118,13 @@ print(data["valid"]) print(len(data["Rx"])) ``` -That adds a 'valid' entry to the data container that contains 1 and 0 values. You can also check the data validity by using `checkDataValidity`. It automatically removes values that are 0 in the valid field and writes an `invalid.data` file to your local directory. In this case it will remove the two additional values that were marked invalid. +That adds a 'valid' entry to the data container that contains 1 and 0 values. You can also check the data validity by using `checkDataValidity`. It automatically removes values that are 0 in the valid field and writes an `invalid.data` file to your local directory. In this case it will remove the two additional values that were marked invalid. ```{code-cell} ipython3 data.checkDataValidity() ``` -You can pass more information about the data set into the data container. For example, here we calculate the distance between transmitter and receiver. +You can pass more information about the data set into the data container. For example, here we calculate the distance between transmitter and receiver. ```{code-cell} ipython3 sx = pg.x(data) @@ -145,9 +132,9 @@ data["dist"] = np.abs(sx[data["Rx"]] - sx[data["Tx"]]) print(data["dist"]) ``` -+++ {"editable": true, "slideshow": {"slide_type": ""}, "tags": ["hide-cell"]} ++++ {"tags": ["hide-cell"]} -You can also do some pre-processing using the validity option again. For example, here we would like to mark as **invalid** where the receiver is the same as the transmitter. +You can also do some pre-processing using the validity option again. For example, here we would like to mark as **invalid** where the receiver is the same as the transmitter. ```{code-cell} ipython3 data.markInvalid(data["Rx"] == data["Tx"]) @@ -179,7 +166,7 @@ pyGIMLi also uses {py:func}`pygimli.load` that loads meshes and data files. It s Most methods also have the `load` function to load common data types used for the method. Such as, {py:func}`pygimli.physics.ert.load`. However, some methods have moe specific functions. Below is a table of the current loading utilities for every method. For a more extensive list of data imports please refer to [pybert importer package](http://resistivity.net/bert/_api/pybert.importer.html#module-pybert.importer). -+++ {"editable": true, "slideshow": {"slide_type": ""}, "tags": ["hide-cell"]} ++++ {"tags": ["hide-cell"]} :::{admonition} Table of available import functions :class: tip diff --git a/doc/user-guide/fundamentals.md b/doc/user-guide/fundamentals.md index 32a05ed7f..f54f258a2 100644 --- a/doc/user-guide/fundamentals.md +++ b/doc/user-guide/fundamentals.md @@ -5,19 +5,14 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.1 kernelspec: - display_name: Python 3 (ipykernel) language: python name: python3 --- # Fundamentals -+++ {"editable": true, "slideshow": {"slide_type": ""}, "tags": ["hide-cell"]} - ## Software design - ## Module/method overview ! ## Basic pyGIMLi classes ! ## Viewer interface ! diff --git a/doc/user-guide/index.md b/doc/user-guide/index.md index 54c8225ad..9c16dce5d 100644 --- a/doc/user-guide/index.md +++ b/doc/user-guide/index.md @@ -17,8 +17,16 @@ kernelspec: :::{toctree} :numbered: -test +fundamentals data meshes inversion +modelling +advanced +::: + +:::{toctree} +:caption: Temp + +cheatsheet ::: \ No newline at end of file diff --git a/doc/user-guide/inversion.md b/doc/user-guide/inversion.md index ea531edbc..fbaa9551b 100644 --- a/doc/user-guide/inversion.md +++ b/doc/user-guide/inversion.md @@ -5,9 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.1 kernelspec: - display_name: Python 3 (ipykernel) language: python name: python3 --- diff --git a/doc/user-guide/jupytext.toml b/doc/user-guide/jupytext.toml new file mode 100644 index 000000000..486ef7717 --- /dev/null +++ b/doc/user-guide/jupytext.toml @@ -0,0 +1,2 @@ +notebook_metadata_filter="kernelspec,jupytext,-kernelspec.display_name,-jupytext.text_representation.jupytext_version" +cell_metadata_filter="all,-autoscroll,-collapsed,-scrolled,-trusted,-ExecuteTime,-editable,-slideshow" diff --git a/doc/user-guide/meshes.md b/doc/user-guide/meshes.md index f5b1fa53b..98c931d85 100644 --- a/doc/user-guide/meshes.md +++ b/doc/user-guide/meshes.md @@ -5,16 +5,14 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.1 kernelspec: - display_name: Python 3 (ipykernel) language: python name: python3 --- -+++ {"editable": true, "slideshow": {"slide_type": ""}, "raw_mimetype": ""} ++++ {"raw_mimetype": ""} -# User guide - mesh section +# Meshes This part of the user guide covers mesh-related topics, starting with a [general introduction](#basics-of-the-mesh-class) to the mesh class. Moreover, this section introduces general operations to [create](#mesh-creation) or [import](#mesh-import) meshes. Moreover, the general aspects of [visualization](#mesh-visualization) are covered within this section. @@ -25,11 +23,6 @@ This part of the user guide covers mesh-related topics, starting with a [general We start off by looking at the general anatomy of a pyGIMLi mesh. It is represented by a collection of nodes, cells and boundaries, i.e., geometrical entities: ```{code-cell} ipython3 ---- -editable: true -slideshow: - slide_type: '' ---- import matplotlib.pyplot as plt import pygimli as pg import numpy as np @@ -413,7 +406,7 @@ pg.show(rotated_mesh) ## Mesh export -+++ {"editable": true, "slideshow": {"slide_type": ""}} ++++ Suppose we want to continue working on our GIMLi mesh object in a different meshing tool - pyGIMLi provides a variety of export functions to transfer your GIMLi mesh into a different format: diff --git a/doc/user-guide/modelling.md b/doc/user-guide/modelling.md index 8c54e521d..f66ac09b3 100644 --- a/doc/user-guide/modelling.md +++ b/doc/user-guide/modelling.md @@ -5,22 +5,14 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.1 kernelspec: - display_name: Python 3 (ipykernel) language: python name: python3 --- # Modelling -+++ - ## Theory (Basics of Finite Element Analysis) ## Parameterizing a mesh with physical properties ## Boundary conditions ## Quantification of modeling errors - -```{code-cell} ipython3 - -``` From e4fb5d59ec8fd747a199d349dd75e64b0d1da4eb Mon Sep 17 00:00:00 2001 From: Florian Wagner Date: Tue, 4 Mar 2025 16:28:32 +0100 Subject: [PATCH 027/102] DOC: Test doc structure for advanced section --- doc/Makefile | 2 +- doc/conf.py | 4 ++-- doc/user-guide/advanced.md | 24 ------------------------ doc/user-guide/advanced/caching.md | 1 + doc/user-guide/advanced/custom-fop.md | 1 + doc/user-guide/advanced/hpc-parallel.md | 1 + doc/user-guide/advanced/index.md | 10 ++++++++++ doc/user-guide/advanced/matrices.md | 2 ++ doc/user-guide/index.md | 5 ++--- environment.yml | 5 +++-- 10 files changed, 23 insertions(+), 32 deletions(-) delete mode 100644 doc/user-guide/advanced.md create mode 100644 doc/user-guide/advanced/caching.md create mode 100644 doc/user-guide/advanced/custom-fop.md create mode 100644 doc/user-guide/advanced/hpc-parallel.md create mode 100644 doc/user-guide/advanced/index.md create mode 100644 doc/user-guide/advanced/matrices.md diff --git a/doc/Makefile b/doc/Makefile index fa5d42c63..37bcc432b 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -44,7 +44,7 @@ help: @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" -auto: api +auto: # Used to auto-update website in local build. Requires sphinx-autobuild. sphinx-autobuild --delay 2 --ignore "pygimliapi/*" --ignore "pygimliapi/_generated/*" --ignore "*gallery.html" --ignore "*.examples" --ignore "*.ipynb" --ignore "*.zip" --ignore "*.pickle" . _build/html -D plot_gallery=0 diff --git a/doc/conf.py b/doc/conf.py index 5a8baa4bf..af506a44e 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -153,7 +153,7 @@ def reset_mpl(gallery_conf, fname): "within_subsection_order": FileNameSortKey, "remove_config_comments": True, # Only parse filenames starting with plot_ - "filename_pattern": "plot_", + "filename_pattern": "/plot_", "first_notebook_cell": ("# Checkout www.pygimli.org for more examples"), "reset_modules": (reset_mpl), # Avoid representation of mpl axis, LineCollections, etc. @@ -239,7 +239,7 @@ def reset_mpl(gallery_conf, fname): source_encoding = "utf-8-sig" # The master toctree document. -master_doc = "documentation" +master_doc = "user-guide/index" # General information about the project. project = "pyGIMLi" diff --git a/doc/user-guide/advanced.md b/doc/user-guide/advanced.md deleted file mode 100644 index f9d2b52fb..000000000 --- a/doc/user-guide/advanced.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -jupytext: - formats: md:myst - text_representation: - extension: .md - format_name: myst - format_version: 0.13 -kernelspec: - language: python - name: python3 ---- - -# Advanced users - -+++ - -## Setting up your own inversion with custom forward operator -## Matrices -## HPC & Parallelization ! -## Caching ! - -```{code-cell} ipython3 - -``` diff --git a/doc/user-guide/advanced/caching.md b/doc/user-guide/advanced/caching.md new file mode 100644 index 000000000..07f88797a --- /dev/null +++ b/doc/user-guide/advanced/caching.md @@ -0,0 +1 @@ +# Caching \ No newline at end of file diff --git a/doc/user-guide/advanced/custom-fop.md b/doc/user-guide/advanced/custom-fop.md new file mode 100644 index 000000000..1bfc9f5e5 --- /dev/null +++ b/doc/user-guide/advanced/custom-fop.md @@ -0,0 +1 @@ +# Setting up your own inversion with custom forward operator \ No newline at end of file diff --git a/doc/user-guide/advanced/hpc-parallel.md b/doc/user-guide/advanced/hpc-parallel.md new file mode 100644 index 000000000..f592867d5 --- /dev/null +++ b/doc/user-guide/advanced/hpc-parallel.md @@ -0,0 +1 @@ +# HPC & Parallel computing \ No newline at end of file diff --git a/doc/user-guide/advanced/index.md b/doc/user-guide/advanced/index.md new file mode 100644 index 000000000..474420309 --- /dev/null +++ b/doc/user-guide/advanced/index.md @@ -0,0 +1,10 @@ + +# Advanced users + +:::{toctree} +:hidden: +custom-fop +matrices +hpc-parallel +caching +::: \ No newline at end of file diff --git a/doc/user-guide/advanced/matrices.md b/doc/user-guide/advanced/matrices.md new file mode 100644 index 000000000..9a51f3902 --- /dev/null +++ b/doc/user-guide/advanced/matrices.md @@ -0,0 +1,2 @@ + +# Matrices \ No newline at end of file diff --git a/doc/user-guide/index.md b/doc/user-guide/index.md index 9c16dce5d..79a517766 100644 --- a/doc/user-guide/index.md +++ b/doc/user-guide/index.md @@ -12,17 +12,16 @@ kernelspec: name: python3 --- -# User guide - :::{toctree} :numbered: +:glob: fundamentals data meshes inversion modelling -advanced +advanced/index ::: :::{toctree} diff --git a/environment.yml b/environment.yml index 164cdabda..798e79782 100644 --- a/environment.yml +++ b/environment.yml @@ -10,7 +10,7 @@ dependencies: - sphinx >= 3.1 - pytest - numpy - - scipy + - scipy >= 1.14 - pytest-cov - pytest-html - sphinx-gallery @@ -19,9 +19,10 @@ dependencies: - sphinxcontrib-spelling - sphinxcontrib-doxylink - bibtexparser - - pyvista[all,trame]>=0.42 + - pyvista[all,trame]>=0.44 - meshio - scooby + - tdqm - sphinx-design - pydata-sphinx-theme - myst-parser From 165d05d7f88d757007a28d6b388ecbfd40411d09 Mon Sep 17 00:00:00 2001 From: Nino Menzel Date: Tue, 4 Mar 2025 17:25:02 +0100 Subject: [PATCH 028/102] Adjusted meshes.md --- doc/conf.py | 4 +- doc/user-guide/meshes.md | 175 ++++++++++++++++++++++++++------------- 2 files changed, 118 insertions(+), 61 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index af506a44e..bf7b303c5 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -590,7 +590,7 @@ def reset_mpl(gallery_conf, fname): # Create HTML table from bib2html import write_html -publications = write_html() +#publications = write_html() ################################################################################################ # Extra call to create small gallery of all already made tutorials and examples in the sidebar. @@ -603,7 +603,7 @@ def reset_mpl(gallery_conf, fname): random.shuffle(showcase) # mix it up html_context = { "showcase": showcase, - "publications": publications, + #"publications": publications, "default_mode": "light", } diff --git a/doc/user-guide/meshes.md b/doc/user-guide/meshes.md index 98c931d85..22c39ad3e 100644 --- a/doc/user-guide/meshes.md +++ b/doc/user-guide/meshes.md @@ -23,8 +23,10 @@ This part of the user guide covers mesh-related topics, starting with a [general We start off by looking at the general anatomy of a pyGIMLi mesh. It is represented by a collection of nodes, cells and boundaries, i.e., geometrical entities: ```{code-cell} ipython3 + import matplotlib.pyplot as plt import pygimli as pg +import pygimli.meshtools as mt import numpy as np from matplotlib.patches import Circle @@ -110,20 +112,20 @@ The mesh class holds either geometric definitions (piece-wise linear complex - * | Function | Usage | | :---------------- | :------: | -| mesh.cells() | Allows to access mesh cells | -| mesh.cell() | Allows to access a single cell (using the cell ID) | -| mesh.cell().center() | Allows to point to the center of a specific mesh cell | -| mesh.cell().center().x()/.y() | Allows to extract the x / y coordinate of a cell center | -| mesh.boundaries() | Accesses mesh boundaries | -| mesh.boundary() | Points to a specific boundary of the mesh (using boundary IDs) -| mesh.boundary().center() | Allows to point to the center of a specific mesh boundary | -| mesh.boundary().center().x/.y | Allows to extract x / y coordinate of a boundary -| mesh.nodes() | Accesses mesh nodes | -| mesh.node() | Refers to one specific node within the mesh | -| mesh.node().x()/.y() | Allows to extract x / y coordinate of a node +| `mesh.cells()` | Allows to access mesh cells | +| `mesh.cell()` | Allows to access a single cell (using the cell ID) | +| `mesh.cell().center()` | Allows to point to the center of a specific mesh cell | +| `mesh.cell().center().x()/.y()` | Allows to extract the x / y coordinate of a cell center | +| `mesh.boundaries()` | Accesses mesh boundaries | +| `mesh.boundary()` | Points to a specific boundary of the mesh (using boundary IDs) +| `mesh.boundary().center()` | Allows to point to the center of a specific mesh boundary | +| `mesh.boundary().center().x/.y` | Allows to extract x / y coordinate of a boundary +| `mesh.nodes()` | Accesses mesh nodes | +| `mesh.node()` | Refers to one specific node within the mesh | +| `mesh.node().x()/.y()` | Allows to extract x / y coordinate of a node ::: -+++ + It is common practice to classify meshes into two main types - structured and unstructured. @@ -143,7 +145,6 @@ jupyter: source_hidden: true --- from pygimli.meshtools import polytools as plc -import numpy as np fig, (ax1,ax2) = plt.subplots(1,2,figsize=(16,8), dpi=90) ax1.set_title("Structured mesh", fontweight="bold") @@ -169,16 +170,9 @@ pg.show(m, ax=ax2) fig.tight_layout() ``` -A mesh can have different regions, which are defined by **region markers** for each cell. Region markers can be used to assign properties for forward modelling as well as to control the inversion behavior. - -### Add chapter on markers ### - -+++ ## Mesh creation -+++ - ### Creating a regular mesh / grid in 2D To create a regular 2D grid, pyGIMLi offers a variety of tools that help with the task. To create a regular grid, we first of all have to create the extent of the mesh in x and z direction. For this example, we create a mesh of _20 x 10 m_ with a regular cell size of _1 x 1 m_. After defining the extent, we can simply call the pg.meshtools.createGrid() and get an overview of the number of nodes, cells and boundaries: @@ -207,10 +201,9 @@ pg.show(m_reg) | Function | Usage | | :---------------- | :------: | -| {py:class}`createWorld ` | Creates a world based on provided x- and z-coordinates | +| {py:class}`createGrid ` | Creates a regular grid mesh from the provided x- and z-coordinates | ::: -+++ ### Creating an irregular mesh with pyGIMLi @@ -219,9 +212,6 @@ After covering the basics of regular grids, we want to dive into the world of ir However, we first of all have to create a **geometry** that is used as underlying susurface model for the mesh creation. ```{code-cell} ipython3 -import pygimli as pg # import pygimli with short name -from pygimli import meshtools as mt # import a module - # dimensions of the world left = -30 right = 30 @@ -229,11 +219,20 @@ depth = 25 world = mt.createWorld(start=[left, 0], end=[right, -depth], - layers=[-5]) + layers=[-5], worldMarker=False) print(world) pg.show(world) ``` +:::{admonition} Region markers +:class: info + +A mesh can have different regions, which are defined by **region markers** for each cell. Region markers can be used to assign properties for forward modelling as well as to control the inversion behavior. + +For more information, see the later section on **Markers** +::: + + We are using the mt.createWorld() function to create a world based on the gíven x- & z-coordinates. The following table lists all handy functions that can be utilized when creating a geometry in pyGIMLi: :::{admonition} PLC creation in pyGIMLi @@ -253,18 +252,6 @@ We are using the mt.createWorld() function to create a world based on the gíven | {py:class}`createRectangle ` | Creates a rectangular PLC | ::: -+++ - -To not over-simplify the example, we will add a dipping interface into our subsurface model by adding a simple line. To combine two PLC's, we can simply add them to each other: - -```{code-cell} ipython3 -line = mt.createLine(start=[left, -20], end=[right, -15]) -geometry = world + line -pg.show(geometry) -``` - -Note that the line cuts region 2 dividing it into two. The upper part does not contain a region marker and thus becomes region 0. - pyGIMLi has different ways to create meshes. mt.createMesh creates a mesh using Triangle, a two-dimensional constrained Delaunay mesh generator. @@ -273,7 +260,7 @@ The additional input parameters control the maximum triangle area and the mesh s ```{code-cell} ipython3 from pygimli.viewer import showMesh -mesh = mt.createMesh(geometry, +mesh = mt.createMesh(world, area=2.0, quality=33, smooth=[2, 4] # [0:no smoothing or 1:node center or 2:weighted node center, # of iter] @@ -281,9 +268,93 @@ mesh = mt.createMesh(geometry, showMesh(mesh, markers=True, showMesh=True); ``` -## Mesh import -+++ +## Utilizing markers + +A mesh can have different regions, which are defined by **region markers** for each cell. Region markers can be used to assign properties for forward modelling as well as to control the inversion behavior. Moreover, a pyGIMLi mesh holds specific markers for all boundaries (outer mesh boundaries as well as interfaces between layers and boundaries around structures, see figure above). Those boundary markers are used to define specific properties or conditions on the boundaries of a mesh. They are essential for setting up boundary conditions in simulations, such as specifying fixed values or fluxes. Properly assigning boundary markers ensures accurate representation of physical boundaries and interactions in the model. + +When constructing complex geometries out of basic geometric shapes (e.g., circle, rectangle, …) we need to be careful with both the region and boundary markers. In this user guide, we explain the differences as well as the usage of both types of markers. + +### Region markers + +Let's take a closer look at the region markers of the two-layer case presented above. Every region marker of a specific mesh region has a position, which it is assigned to. By using ``, we can visualize the position in the PLC: + +```{code-cell} ipython3 + +fig, ax = plt.subplots(1,1) +pg.show(world, ax=ax) +for nr, marker in enumerate(world.regionMarkers()): + print('Position marker number {}:'.format(nr + 1), marker.x(), marker.y(), + marker.z()) + ax.text(marker.x()+2,marker.y()+2, f"Region marker position {nr+1}", + fontweight="bold",fontsize=11, ha="left", va="top", color="black") + ax.scatter(marker.x(), marker.y(), s=(4 - nr) * 20, color='k') + +``` + +By default, pyGIMLi assigns unique markers to every region of the PLC, starting from 1. A marker value of 0 is assigned to a region if no region marker is found - but even if this happens, we could still manually add a marker to the specific region. For now, we want to add a polygon to the already existing 2-layer PLC. This is done using the `createPolygon()` function. Within this function, we have two adjusting variables for the region markers - *marker* and *markerPosition*. The first variable specifies the marker number and the second the position of the marker. Note, that the **position** of a region marker has to lie **within its region** to work! In this case, we specify the newly defined region to have the marker 3. The marker position is set to *[-10, -10]*. + +```{code-cell} ipython3 +poly = mt.createPolygon([[left, -20], [right,-15],[right,-5],[left,-5]], isClosed=True, marker=3, markerPosition=[-10, -10]) +geometry = world + poly +fig, ax = plt.subplots(1,1) +pg.show(geometry, ax=ax) +for nr, marker in enumerate(geometry.regionMarkers()): + print('Position marker number {}:'.format(nr + 1), marker.x(), marker.y(), + marker.z()) + ax.text(marker.x()+2,marker.y()+2, f"Region marker position {nr+1}", + fontweight="bold",fontsize=11, ha="left", va="top", color="black") + ax.scatter(marker.x(), marker.y(), s=(4 - nr) * 20, color='k') +``` + +Of course it is also possible to assign the same region marker to multiple parts of your PLC. This gets especially handy as soon as you start assigning physical parameters to your meshed geometry for modelling and/or inversion purposes. For more detailed information on this matter, please take a look at the [modelling section](modelling.md) of the user guide. + +### Boundary markers +If we talk about markers in a PLC, one often forgets about the boundary markers. If you create a geometry in pyGIMLi, no matter whether it is a circle, rectangle or layered world, you need to deal with boundaries of different kinds. pyGIMLi automatically assigns numbers to the boundaries and, doing so, follows a specific pattern. + +If we assume a simple rectangular world without additional layers, we have two different options on how to enumerate the boundaries: + +1) Set `createWorld(worldMarker=False)`, which leads to enumerated boundaries (*1 = left, 2=right, 3=bottom, 4=top, 5=front and 6=back*). + +2) Set `createWorld(worldMarker=True)`, which leads to the top holding the boundary marker -1 and other outer boundaries -2. + + +```{code-cell} ipython3 +start = [left,0] +end = [right, -depth] +world1 = mt.createWorld(start=start, + end=end, worldMarker=False) + +world2 = mt.createWorld(start=start, + end=end, worldMarker=True) + +fig, (ax1,ax2) = plt.subplots(1,2,figsize=(16,12), dpi=90) +ax1.set_title("worldMarker = False", fontweight="bold") +ax2.set_title("worldMarker = True", fontweight="bold") + +pg.show(world1, markers=True, ax=ax1) +pg.show(world2, markers=True, ax=ax2) +``` + +Let's assume that we want to add an additional feature to our PLC, such as a rectangle. Doing so, the circle is automatically assigned a boundary marker - in this case 1. However, assuming the case where we set `worldMarker=False`, this marker is already assigned to the left boundary of the PLC (which could cause problems in any modelling application later on). So we need to adapt the boundary marker of the circle, which is simply done as follows: + +```{code-cell} ipython3 + +c1 = plc.createRectangle(start=[-10,-5], end=[10,-10], marker=2) +geom1 = world1+c1 +# %% +for i in range(geom1.boundaryCount()): + if i >= 4: + geom1.boundary(i).setMarker(5) + +pg.show(geom1, markers=True) +``` + +As you can see, the boundaries around the rectangle were all changed to 5, as defined in the for-loop above. `PLC.boundaryCount()` gives us the total count of boundaries in the PLC, while `PLC.boundary().setMarker()` allows us to change a specific boundary marker. + +To see applications where the indices of the PLC / mesh boundary are utilized, please refer to the [modelling section](modelling.md) of the user guide. + +## Mesh import ### Import options for meshes in pyGIMLi @@ -308,21 +379,14 @@ A broad variety of functions to import and convert different mesh types into a G | {py:class}`Triangle ` | Read Triangle mesh | ::: -+++ ### Example: mesh generation using Gmsh -When the scientific task requires a complex finite-element discretization (i.e. incorporation of structural information, usage of a complete electrode model (CEM), etc.), external meshing tools with visualization capabilities may be the option of choice for some users. In general, the bindings provided by pygimli allow to interface any external mesh generation software. - -+++ +When the scientific task requires a complex finite-element discretization (i.e. incorporation of structural information, usage of a complete electrode model (CEM), etc.), external meshing tools with visualization capabilities may be the option of choice for some users. In general, the bindings provided by pygimli allow to interface any external mesh generation software. For examples on how to use external meshing software, refer to the [examples section](../examples/1_meshing/) on the pyGIMLi website. -## Mesh visualization - -+++ ## Mesh modification -+++ pyGIMLi provides a variety of operators to modify your mesh. The following table gives an overview of the most important functions: @@ -336,12 +400,11 @@ pyGIMLi provides a variety of operators to modify your mesh. The following table | :---------------- | :------: | | {py:class}`merge2Meshes ` | Merges two meshes | | {py:class}`mergeMeshes ` | Merges two or more meshes | -| mesh.translate() | Allows to translate a mesh | -| mesh.scale()` | Scale a mesh with provided factors | -| mesh.rotate()` | Rotate a provided mesh | +| `mesh.translate()` | Allows to translate a mesh | +| `mesh.scale()` | Scale a mesh with provided factors | +| `mesh.rotate()` | Rotate a provided mesh | ::: -+++ ### Merging meshes @@ -372,7 +435,6 @@ ax, cb = pg.show(mesh_append) When merging more than two meshes, the function {py:class}`mergeMeshes() ` can be utilized instead of {py:class}`merge2Meshes `. -+++ ### Translating meshes @@ -406,7 +468,6 @@ pg.show(rotated_mesh) ## Mesh export -+++ Suppose we want to continue working on our GIMLi mesh object in a different meshing tool - pyGIMLi provides a variety of export functions to transfer your GIMLi mesh into a different format: @@ -430,7 +491,3 @@ Suppose we want to continue working on our GIMLi mesh object in a different mesh rotated_mesh.exportVTK('rotated_mesh.vtk') ``` - -```{code-cell} ipython3 - -``` From 93da778ade2530ac1fd6c2adbe36adf5841781fe Mon Sep 17 00:00:00 2001 From: Andrea Balza Morales Date: Tue, 4 Mar 2025 17:26:07 +0100 Subject: [PATCH 029/102] Completing data.md --- doc/user-guide/data.md | 114 ++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/doc/user-guide/data.md b/doc/user-guide/data.md index 994239a10..0b01c2c63 100644 --- a/doc/user-guide/data.md +++ b/doc/user-guide/data.md @@ -12,11 +12,9 @@ kernelspec: # Data -+++ ## What is a pyGIMLi DataContainer? -+++ Data are often organized in a data container storing the individual data values as well as any description how they were obtained, e.g. the geometry of source and receivers. DataContainer is essentially a class that stores all of this information. It is different for every method and can be then filtered accordingly. It stores two primary things: sensor information and data measurements. @@ -54,7 +52,7 @@ ves_data["mn2"] = ab2 / 3 print(ves_data) ``` -One can also use `showInfos()` to see the content of the data container with more wording. +One can also use `.showInfos()` to see the content of the data container with more wording. ```{code-cell} ipython3 ves_data.showInfos() @@ -70,11 +68,9 @@ As you can see from the print out there is no sensor information. In the next su Data containers can also be initialized from different method managers. These have the custom names for sensors and data types of each method. For example {py:class}`pygimli.physics.ert.DataContainer` already has ['a', 'b', 'm', 'n'] entries. One can also add alias translators like C1, C2, P1, P2, so that dataERT[“P1”] will return dataERT[“m”] ::: -+++ ## Creating Sensors in DataContainer -+++ Assume we have data associate with a transmitter, receivers and a property U. The transmitter (Tx) and receiver (Rx) positions are stored separately and we refer them with an Index (integer). Therefore we define these fields index. @@ -108,7 +104,46 @@ print(data) The positions under the sensor indexes must be of the same size. ::: -+++ +If the sensor positions are given by another file (for example a GPS file), you can transform this to a NumPy array and set the sensor positions using [`.setSensorPositions()`](https://www.pygimli.org/gimliapi/classGIMLI_1_1DataContainer.html#a3c58caec5486d5390a2b6c2d8056724f) method of the DataContainer. + + + +## File export + + +This data container can also be saved on local disk using the method `.save()` usually in a .dat format. It can then be read using `open('filename').read()`. This is also a useful way to see the data file in Python. + +```{code-cell} ipython3 +data.save("data.dat") +print(open("data.dat").read()) +``` + +## File format import + + + +Now we will go over the case if you have your own data and want to first import it using pyGIMLi and assign it to a data container. You can manually do this by importing data via Python (data must be assigned as Numpy arrays) and assign the values to the different keys in the data container. + +pyGIMLi also uses {py:func}`pygimli.load` that loads meshes and data files. It should handle most data types since it detects the headings and file extensions to get a good guess on how to load the data. + +Most methods also have the `load` function to load common data types used for the method. Such as, {py:func}`pygimli.physics.ert.load`. Method specific load functions assign the sensors if specified in the file. For a more extensive list of data imports please refer to [pybert importer package](http://resistivity.net/bert/_api/pybert.importer.html#module-pybert.importer). + + + +## Visualization + + +You can visualize the data in many ways depending on the physics manager. To simply view the data as a matrix you can use `pg.viewer.mpl.showDataContainerAsMatrix`. This visualizes a matrix of receivers and transmitters pairs with the associated data to plot : 'dist'. + +```{code-cell} ipython3 +pg.viewer.mpl.showDataContainerAsMatrix(data, "Rx", "Tx", 'dist'); +``` + +There are more formal ways of plotting different data containers depending on the method. As seen in [Fundamentals](fundamentals.md) here we can focus on showing the data container. Most of the method managers use `.show()` that is specific to their method, however, you can always use the main function {py:func}`pg.show`, and it will detect the data type and plot it accordingly. + +## Processing + +To start processing the data for inversion, you can filter out and analyze the data container by applying different methods available to all types of data containers. This is done to the data container and in my cases the changes happen in place, so it is recommended to view the data in between the steps to observe what changed. You can check the validity of the measurements using a given condition. We can mask or unmask the data with a boolean vector. For example, below we would like to mark valid all receivers that are larger or equal to 0. @@ -118,7 +153,7 @@ print(data["valid"]) print(len(data["Rx"])) ``` -That adds a 'valid' entry to the data container that contains 1 and 0 values. You can also check the data validity by using `checkDataValidity`. It automatically removes values that are 0 in the valid field and writes an `invalid.data` file to your local directory. In this case it will remove the two additional values that were marked invalid. +That adds a 'valid' entry to the data container that contains 1 and 0 values. You can also check the data validity by using `.checkDataValidity()`. It automatically removes values that are 0 in the valid field and writes the `invalid.data` file to your local directory. In this case it will remove the two additional values that were marked invalid. ```{code-cell} ipython3 data.checkDataValidity() @@ -145,62 +180,27 @@ data.checkDataValidity() data.showInfos() ``` -## File export +Below there is a table with the most useful methods, for a full list of methods of data container, please refer to [DataContainer class reference](https://www.pygimli.org/gimliapi/classGIMLI_1_1DataContainer.html) -+++ - -This data container can also be saved on local disk using the method `.save()` usually in a .dat format. It can then be read using `open('filename').read()`. This is also a useful way to see the data file in Python. - -```{code-cell} ipython3 -data.save("data.dat") -print(open("data.dat").read()) -``` - -## File format import - -+++ - -Now we will go over the case if you have your own data and want to first import it using pyGIMLi and assign it to a data container. You can manually do this by importing data via Python (data must be assigned as Numpy arrays) and assign the values to the different keys in the data container. - -pyGIMLi also uses {py:func}`pygimli.load` that loads meshes and data files. It should handle most data types since it detects the headings and file extensions to get a good guess on how to load the data. - -Most methods also have the `load` function to load common data types used for the method. Such as, {py:func}`pygimli.physics.ert.load`. However, some methods have moe specific functions. Below is a table of the current loading utilities for every method. For a more extensive list of data imports please refer to [pybert importer package](http://resistivity.net/bert/_api/pybert.importer.html#module-pybert.importer). - -+++ {"tags": ["hide-cell"]} - -:::{admonition} Table of available import functions +:::{admonition} Table of useful methods for DataContainer :class: tip -:::{table} Commands to import data types depending on the physics manager +:::{table} Methods to add, remove and sort information for a data container. +data represents a DataContainer :widths: auto :align: center -| physics manager | available loading functions | -| --- | --- | -| em | {py:func}`importMaxminData `, {py:func}`readusffile `, {py:func}`readHEMData `, {py:func}`importEmsysAsciiData ` | -| ves | {py:func}`loadData ` | - -::: -::: - -+++ - -## Visualization -+++ - -You can visualize the data in many ways depending on the physics manager. To simply view the data as a matrix you can use `pg.viewer.mpl.showDataContainerAsMatrix`. This visualizes a matrix of receivers and transmitters pairs with the associated data to plot : 'dist'. - -```{code-cell} ipython3 -pg.viewer.mpl.showDataContainerAsMatrix(data, "Rx", "Tx", 'dist'); -``` - -There are more formal ways of plotting different data containers depending on the method. As seen in (link to fundamentals show vs draw) here we can focus on showing the data container. Most of the methods use `show()` however, there are some method-dependent show function in the table below. - -+++ +| Method | Description | +| --- | --- | +| [data.remove()](https://www.pygimli.org/gimliapi/classGIMLI_1_1DataContainer.html#a3d07be3931623a5ebef2bf14d06d4f50) | Remove data from index vector. Remove all data that are covered by idx. Sensors are preserved. (Inplace - DataContainer is overwritten inplace) +| [data.add()](https://www.pygimli.org/gimliapi/classGIMLI_1_1DataContainer.html#af550aeba4f21ba26fd04c9bd3a3800ac) | Add data to this DataContainer and snap new sensor positions by tolerance snap. Data fields from this data are preserved. +| [data.clear()](https://www.pygimli.org/gimliapi/classGIMLI_1_1DataContainer.html#ad5aa50883c00a3989aed97401592f41b) | Clear the container, remove all sensor locations and data.| +| [data.findSensorIndex()](https://www.pygimli.org/gimliapi/classGIMLI_1_1DataContainer.html#adeff1f8755b09ce80bb92b890fb0d837) | Translate a RVector into a valid IndexArray for the corresponding sensors. +| [data.sortSensorsIndex()](https://www.pygimli.org/gimliapi/classGIMLI_1_1DataContainer.html#a3d07be3931623a5ebef2bf14d06d4f50) | Sort all data regarding there sensor indices and sensorIdxNames. Return the resulting permuation index array. +| [data.sortSensorsX()](https://www.pygimli.org/gimliapi/classGIMLI_1_1DataContainer.html#a8d917f4e6049799bda190dfd42efef6b) | Sort all sensors regarding their increasing coordinates. Set inc flag to False to sort respective coordinate in decreasing direction. +| [data.registerSensorIndex()](https://www.pygimli.org/gimliapi/classGIMLI_1_1DataContainer.html#a955c7c33ff8118ff9c3f5a7a78b75283) | Mark the data field entry as sensor index. +| [data.removeUnusedSensor()](https://www.pygimli.org/gimliapi/classGIMLI_1_1DataContainer.html#a017137847f635e56a0eb5f84cbc58f5d) | Remove all unused sensors from this DataContainer and recount data sensor index entries. +| [data.removeSensorIdx()](https://www.pygimli.org/gimliapi/classGIMLI_1_1DataContainer.html#ab0207d2be4491338818a6c67d1ed78e3) | Remove all data that contains the sensor and the sensor itself. -## Processing -```{code-cell} ipython3 - -``` From 0c530d85ed09c1d7b714c8a59ddc8ceffb9b5b44 Mon Sep 17 00:00:00 2001 From: Nino Menzel Date: Tue, 4 Mar 2025 19:22:05 +0100 Subject: [PATCH 030/102] Adjusted fundamentals.md --- doc/user-guide/fundamentals.md | 49 ++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/doc/user-guide/fundamentals.md b/doc/user-guide/fundamentals.md index f54f258a2..a3bb980dc 100644 --- a/doc/user-guide/fundamentals.md +++ b/doc/user-guide/fundamentals.md @@ -13,6 +13,51 @@ kernelspec: # Fundamentals ## Software design -## Module/method overview ! -## Basic pyGIMLi classes ! +In applied geophysics, a lot of research efforts are directed towards the integration of different physical models and combined inversion approaches to estimate multi-physical subsurface parameters. Such approaches often require coupling of different software packages and file-based data exchange. The idea of pyGIMLi is to present a very flexible framework for geophysical modelling and inversion, which allows standard and customized modelling and inversion workflows to be realized in a reproducible manner. + +The software is written in **Python** on top of a **C++ core library**, which allows a combination of flexible scripting and numerical efficiency. pyGIMLi uses selected **external dependencies** for quality constrained **mesh generation** in 2D (Triangle) and 3D (Tetgen) and **visualization** in 2D (Matplotlib) and 3D (Paraview) for example. For solving linear systems we use the open-source collection **SuiteSparse** [Chen et al., 2009], which contains multi-frontal direct and iterative solvers as well as reordering algorithms. + +pyGIMLi is organized in three different abstraction levels: + +**Application level** + +In the application level, ready-to-use method managers and frameworks are provided. Method managers (`pygimli.manager`) hold all relevant functionality related to a geophysical method. A method manager can be initialized with a data set and used to analyze and visualize this data set, create a corresponding mesh, and carry out an inversion. Various method managers are available in `pygimli.physics`. Frameworks (`pygimli.frameworks`) are generalized abstractions of standard and advanced inversions tasks such as time-lapse or joint inversion for example. Since frameworks communicate through a unified interface, they are method independent. + +**Modelling level** + +In the modelling level, users can set up customized forward operators that map discretized parameter distributions to a data vector. Once defined, it is straightforward to set up a corresponding inversion workflow or combine the forward operator with existing ones. + +**Equation level** + +The underlying equation level allows to directly access the finite element (`pygimli.solver.solveFiniteElements()`) and finite volume (`pygimli.solver.solveFiniteVolume()`) solvers to solve various partial differential equations on unstructured meshes, i.e. to approach various physical problems with possibly complex 2D and 3D geometries. + + +## Module/method overview + +| method | Forward | Inverse | Dimension | +| :---------------- | :------: |:--------:|:--------:| +| {py:class}`em ` | **✓** | **✓** | *1D* | +| {py:class}`ert ` | **✓** | **✓** | *2D, 3D, 4D* | +| {py:class}`gravimetry ` | **✓** | **✓** | *2D, 3D* | +| {py:class}`magnetics ` | **✓** | **✓** | *2D, 3D* | +| {py:class}`petro ` | **✓** | **✓** | *dimensionless* | +| {py:class}`seismics ` | **✓** | **-** | "1D" | +| {py:class}`SIP ` | **✓** | **✓** | *1D, 2D* | +| {py:class}`sNMR ` | **✓** | **✓** | *1D* | +| {py:class}`traveltime ` | **✓** | **✓** | *2D, (3D)* | +| {py:class}`ves ` | **✓** | **✓** | *1D* | +::: + + +## Basic pyGIMLi classes + +| pyGIMLi class | Description | +| :---------------- | :------: | +| {py:class}` Matrix ` | All elements are stored column-wise, i.e. all rows *A[i]* are of type `pg.Vector`. This matrix is used for storing dense data (like ERT Jacobians) and doing simple algebra. | +| {py:class}` RVector ` | One dimensional array aka Vector of limited size to store data, like ERT sensitivities. | +| {py:class}`SparseMatrix ` | Used for numerical approximation of partial differential equations like finite-element or finite volume. Not typically used unless efficiency is of importance. It exists also complex-valued as pg.matrix.CSparseMatrix | +| {py:class}` BlockMatrix ` | Arbitrary matrices are combined into a logical matrix. This is of importance for inversion frameworks, e.g., concatenated Jacobian matrices during joint inversions. | +| {py:class}`DataContainer ` | Data container storing the individual data values as well as any description how they were obtained, e.g. the geometry of source and receivers. | +::: + ## Viewer interface ! From efbbdc188cdee1c4cf5deb2659df46424d0941cd Mon Sep 17 00:00:00 2001 From: Florian Wagner Date: Mon, 31 Mar 2025 18:05:32 +0200 Subject: [PATCH 031/102] Resolve merge conflict --- INSTALLATION.md | 15 +++++---- doc/_templates/navbar-nav.html | 6 ++-- doc/conf.py | 19 ++++++++--- doc/documentation.rst | 1 + doc/getting-started/basics.md | 3 ++ doc/getting-started/first-inversion.md | 2 ++ doc/getting-started/first-modelling.md | 2 ++ doc/getting-started/how-to-continue.md | 2 ++ doc/getting-started/index.md | 46 ++++++++++++++++++++++++++ doc/user-guide/advanced/index.md | 2 +- doc/user-guide/index.md | 15 +-------- 11 files changed, 83 insertions(+), 30 deletions(-) create mode 100644 doc/getting-started/basics.md create mode 100644 doc/getting-started/first-inversion.md create mode 100644 doc/getting-started/first-modelling.md create mode 100644 doc/getting-started/how-to-continue.md create mode 100644 doc/getting-started/index.md diff --git a/INSTALLATION.md b/INSTALLATION.md index 0827f6b8a..695495aa7 100644 --- a/INSTALLATION.md +++ b/INSTALLATION.md @@ -1,3 +1,4 @@ +(installation)= # Installation ```{raw} html @@ -112,8 +113,8 @@ functionality. conda update -c gimli -c conda-forge pygimli ``` -If there something went wrong and you are running an old, not further -supported python version, consider a fresh install in a new clean environment. +If something went wrong and you are running an old, not further +supported Python version, consider a fresh install in a new clean environment. The only drawback of using conda is that you are bound to the rhythm in which we update the conda packages. In order to work with the latest Python codes you should create an environment with the latest pyGIMLi C++ core only, @@ -137,14 +138,14 @@ conda develop . or using pip -.. code-block:: bash - - pip install --no-build-isolation --no-deps -e . +```bash +pip install --no-build-isolation --no-deps -e . +``` -Alternatively you could set the PYTHONPATH variable but you would have to care +Alternatively you could set the `PYTHONPATH` variable, but you would have to care for dependencies by yourself. -Later you can just update the pygimli code by +Later you can just update the pyGIMLi code by ```bash git pull diff --git a/doc/_templates/navbar-nav.html b/doc/_templates/navbar-nav.html index dd47fe7d6..979f58140 100644 --- a/doc/_templates/navbar-nav.html +++ b/doc/_templates/navbar-nav.html @@ -4,7 +4,7 @@