{"id":22438567,"url":"https://github.com/larsgeb/psvWave","last_synced_at":"2025-08-01T16:34:24.375Z","repository":{"id":51680975,"uuid":"124120207","full_name":"larsgeb/psvWave","owner":"larsgeb","description":"Forward code for the P-SV wave equation on a staggered grid, with full waveform inversion interfaces. Finite difference approach according to stress-velocity formulation.","archived":false,"fork":false,"pushed_at":"2022-06-03T19:09:45.000Z","size":78277,"stargazers_count":67,"open_issues_count":3,"forks_count":9,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-12-01T14:51:34.132Z","etag":null,"topics":["armadillo","cpp11","eigen","finite-difference","full-waveform-inversion","psv-wave","pybind11","python","shearwave","staggeredgrid","velocity-stress-formulation","wave-propagation"],"latest_commit_sha":null,"homepage":"","language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/larsgeb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null}},"created_at":"2018-03-06T18:20:57.000Z","updated_at":"2024-11-29T02:42:46.000Z","dependencies_parsed_at":"2022-08-03T08:31:00.691Z","dependency_job_id":null,"html_url":"https://github.com/larsgeb/psvWave","commit_stats":null,"previous_names":["larsgeb/forward-virieux"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/larsgeb%2FpsvWave","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/larsgeb%2FpsvWave/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/larsgeb%2FpsvWave/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/larsgeb%2FpsvWave/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/larsgeb","download_url":"https://codeload.github.com/larsgeb/psvWave/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228393618,"owners_count":17912865,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["armadillo","cpp11","eigen","finite-difference","full-waveform-inversion","psv-wave","pybind11","python","shearwave","staggeredgrid","velocity-stress-formulation","wave-propagation"],"created_at":"2024-12-06T01:10:44.593Z","updated_at":"2024-12-06T01:10:45.679Z","avatar_url":"https://github.com/larsgeb.png","language":"Jupyter Notebook","funding_links":[],"categories":[],"sub_categories":[],"readme":"# psvWave\n\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/psvWave)\n[![Main GitHub Language](https://img.shields.io/github/languages/top/larsgeb/forward-virieux)](https://github.com/larsgeb/psvWave)\n[![GitHub](https://img.shields.io/github/license/larsgeb/psvWave?color=4dc71f)](https://github.com/larsgeb/psvWave/blob/master/LICENSE)\n[![PyPI version](https://badge.fury.io/py/psvWave.svg)](https://pypi.org/project/psvWave/)\n[![](https://img.shields.io/badge/docs-latest-brightgreen)](https://larsgeb.github.io/psvWave/)\n[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6216312.svg)](https://doi.org/10.5281/zenodo.6216312)\n\nhttps://user-images.githubusercontent.com/21038893/155033663-5e22b5ee-1b2b-43eb-9aab-74bfd85f2a73.mp4\n\n\n[Check out the notebooks here!](https://github.com/larsgeb/psvWave/blob/master/notebooks)\n\nA Python/C++ package for 2D P-SV wave propagation using finite differences and OpenMP.\nThis package was written to facilitate high-throughput numerical wave simulations for\nMonte Carlo simulation in Seismology.\nIt uses the velocity-stress formulation on a staggered grid from [Virieux's\nclassical 1986 paper](https://doi.org/10.1190/1.1442147).\nFor compilation we require only OpenMP and the git subrepos (header-only):\n[Eigen](http://eigen.tuxfamily.org) and [inih](https://github.com/jtilly/inih),\nhowever installation can be easily done through pip.\nUsed as a PDE-simulation code for\n[this publication](https://doi.org/10.1029/2019JB018428).\n\n\n## Extremely quick start using Docker\n\nThe best way to run the code if you are not on Linux. Pull the docker image and start\nthe notebook server on port 7999. Feel free to change the port 7999 to something of your\npreference.\n\n```bash\ndocker run -it -p 7999:8888 larsgebraad/psvwave\n```\n\nYou can then navigate in your browser to `localhost:7999`. This starts you right off \nwith some fun notebooks! \n\nNote that the notebooks assume you have 6 cores available for your docker. You can\nspecify how many cores are available by starting the Docker the following way:\n\n```bash\ndocker run -it --cpus=2 -p 7999:8888 larsgebraad/psvwave\n```\n\n## Installing the package using PyPi (pip)\n\nThere are many ways to install this package.\nInstalling directly from the PyPi archives is arguably the easiest:\n\n```bash\npip install psvWave\n```\n\nTo check if everything worked correctly, you can run the following in an interactive python shell or notebook:\n\n```python\n\u003e\u003e\u003e import psvWave\n\u003e\u003e\u003e print(psvWave.__version__)\n```\n\nIf this raises an `ImportError`, the C++ packages have not correctly compiled and you\nare either on an unsupported system (Windows/MacOS) or I have made a terrible mistake.\nPlease contact me in any case!\n\n## Getting started\n\n## Working with the configuration files\n\n**This section is a must read for anyone wishing to use this package.**\n\nAn example configuration file is given below.\nThe simulations performed make a few basic assumptions about the medium, wavefield and\nsources:\n\n### 1: Physics\n\nAll sources propagate waves through the same medium / domain, and are recorded by\nthe same network.\nThe physics is defined in a **right-handed** coordinate system.\nHowever, you are allowed to interpret the simulations in any unit and orientation\nyou like.\nJust make sure you keep track of the units, and don't use numbers outside the range\nof either `float` or `double` (the package is by default compiled with doubles).\nAnd, the physics is for **in-plane** shear waves.\n\n### 2: Sources\n\nAll sources are normal/reverse faults (with strike parallel to the y-axis) with a\nRicker wavelet of all the same frequency as source time function.\nEvery source can have a different dip angle.\nThis source time function can be altered in both the Python and C++ API, the focal\nmechanism /source type not (yet).\n\n### 3: Simulations\n\nSimulations are divided in 'shots', i.e. a single time length in which data is\nrecorded and some 'sources' fire.\nIt is thus allowed to have 2 sources in a single shot.\nThis allows for source stacking.\nThe delay_cycles_per_shot variable allows for time staggering, delaying the source\ntime function per source by that many cycles.\nAn example relevant to the given configuration file:\n\n```\npeak_frequency = 50.0\n```\n\nMeans all source time functions (STF) are a Ricker wavelet with peak (central)\nfrequency of 50Hz.\n\n```\ndelay_cycles_per_shot = 24\n```\n\nMeans that if 2 sources are present in a shot, the STF of the second shot is delayed\nby 24 cycles. For a peak frequency of 50 Hz, this turns out to be\n`24cycl / 50cycl/s = 0.48s`. Every subsequent shot is delayed after the previous by\nthe same amount.\n\n```\nwhich_source_to_fire_in_which_shot = {{0, 1}}\n```\n\nMeans that both source 0 and source 1 (zero-based indexing) are fired in shot 1.\n\nIn the below given configuration, total simulation time is 1 second.\nThis means that the second shot is 'fired' at almost half the simulation time.\nThe idea behind source stacking is that without strong reflections, we can take\nadvantage of the position of the wavefields to simulate multiple shots at the same\ntime, with minimal 'cross-talk'.\n\n### 4: Domain and boundary\n\nThe domain is truncated on all 4 sides by absorbing boundary conditions.\nIt's width is variable, but as of yet, the same on all sides.\nThis does not directly allow for free boundary conditions, but this is planned to\nchange.\nWhen measuring distance or counting gridpoints, the zero-point is the first points\nnot inside the boundary layer but in the actual simulation medium.\nWhen updating medium properties within the domain, the boundary copies the medium\nproperties closest to it, to avoid creating reflectors.\n\n### 5: Indexing\n\nThe location of the sources and receivers is not expressed in distance, but in\ngridpoint numbering.\nBecause the actual indexing starts within the medium, and not the absorbing\nboundary, sources and receivers can only be placed inside the medium.\nHowever, the nx_inner_boundary and nz_inner_boundary variables determine how many\ngridpoints are not considered free parameters.\nThe idea behind this is that this allows us to place sources/receivers in regions\nof the domain that are not inverted for, and are also not inside the boundary.\nThis to avoid near-source and near-receiver effects.\n\n### Example file\n\n```\n[domain]\nnt = 4000\nnx_inner = 200\nnz_inner = 100\nnx_inner_boundary = 10\nnz_inner_boundary = 20\ndx = 1.249\ndz = 1.249\ndt = 0.00025\n\n[boundary]\nnp_boundary = 25\nnp_factor = 0.015\n\n[medium]\nscalar_rho = 1500.0\nscalar_vp = 2000.0\nscalar_vs = 800.0\n\n[sources]\npeak_frequency = 50.0\nn_sources = 2\nn_shots = 1\nsource_timeshift = 0.005\ndelay_cycles_per_shot = 24\nmoment_angles = {90, 180}\nix_sources = {25, 175}\niz_sources = {10, 10}\nwhich_source_to_fire_in_which_shot = {{0, 1}}\n\n[receivers]\nnr = 19\nix_receivers = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190}\niz_receivers = {90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90}\n\n[inversion]\nsnapshot_interval = 10\n```\n\n## Installing from GitHub\n\nYou might also be tempted to install it from tags or another GitHub hash.\nThis has the problem however that submodules are not automatically downloaded.\nIf you still wish to install from the repo, you have to clone it to your machine first,\nand then also pull all the submodules:\n\n```bash\ngit clone --recursive https://github.com/larsgeb/psvWave.git\ncd psvWave\n```\n\nAfterwards you can ...\n\n1. directly install from this directory:\n\n   ```bash\n   pip install -e .\n   ```\n\n2. create a source distribution (uncompiled) and install it on _any_ machine:\n\n   ```bash\n   python setup.py sdist\n   cd dist\n   pip install psvWave-*.tar.gz # this will compile the C++ modules\n   ```\n\n3. create a binary wheel in which the compiled code is present and install it on\n   _similar_ machines:\n\n   ```bash\n   python setup.py bdist_wheel # this will compile the C++ modules\n   cd dist\n   pip install psvWave-*.whl\n   ```\n\nThe main difference between 2 and 3 is that 2 doesn't compile the C++ code yet at the\ndistribution stage.\nOption 3 does compile in this stage, and therefore might not work on machines with\nwildly different architectures.\n\nIf you are really at the end of your rope, we can also send a precompiled wheel for the\nplatform you're using.\n\n## Compiling the C++ interface\n\nCompiling the C++ API into your C++ application is fairly straightforward. One needs\nan OpenMP enabled compiler, `cmake` installed and C++11 support. The different\ntargets are defined in the CMakeLists.txt. Assuming your in a local clone of this repo:\n\n```bash\nmkdir build\ncd build\ncmake -DCMAKE_BUILD_TYPE=Release ..\nmake forward_test # or other targets\n```\n\n## Compiling the Python interface yourself\n\nCompiling the CMake target `psvWave` creates a Python module for the current\nenvironments' Python version. However, to find the right requirements, we first need to\ndo two things:\n\n1. Install PyBind, to interface Python to C++, using your favourite package manager;\n1. Set the relevant environment variables.\n\nBefore you continue, make sure you are in your desired Python environment, e.g. Conda or\nPyEnv. **Python 3.6** or higher is recommended. Also, the `python3-dev` or equivalent\npackage is needed for compilation.\n\n### Installing development dependencies.\n\nUsing your relevant package manager, you need to install all required development\ndependencies. To at minimum compile the interface, `cmake` and `pybind11` are required:\n\n```bash\npip install pybind11\npip install cmake\n```\n\nHowever, you might want to perform code-formatting and run tests. To install all the\ndependencies for this, it might be easier to install them using the `setup.py` file.\nMake sure you are in the cloned repo folder and run the following:\n\n```bash\n# On Bash / SH\npip install -e .[dev]\n# On ZSH\npip install -e .\\[dev\\]\n```\n\n### Setting needed environment variables\n\nThe compiler needs three things to work correctly:\n\n1. the relevant PyBind files (headers);\n2. the relevant Python files (headers);\n3. the appropriate extension for the compiled file.\n\nThe CMakeLists.txt file loads these variables from the environment. If you know what you are doing, you can set these yourself. If not, run the following commands in the terminal in which you have activated your relevant Python environment:\n\n```bash\nexport PYBIND_INCLUDES=`python3 -c'import pybind11;print(pybind11.get_include())'`\nexport PYTHON_INCLUDES=`python3 -c\"from sysconfig import get_paths as gp; print(gp()[\\\"include\\\"])\"`\nexport SUFFIX=`python3-config --extension-suffix`\n```\n\n### Compiling the Python linked C++ code\n\nCompiling the Python interface is done by running CMake in the cloned repo:\n\n```bash\ncmake -DCMAKE_BUILD_TYPE=Release .\nmake psvWave_cpp\n```\n\nIf you are on MacOS, I advise against trying to get CLang to work. Instead, use GCC\ncompilers from homebrew:\n\n```bash\ncmake -DCMAKE_C_COMPILER=/opt/homebrew/Cellar/gcc/11.2.0_3/bin/gcc-11 \\\n      -DCMAKE_CXX_COMPILER=/opt/homebrew/Cellar/gcc/11.2.0_3/bin/g++-11  \\\n      -DCMAKE_BUILD_TYPE=Release \\\n      .\nmake psvWave_cpp\n```\n\n### Using the Python interface\n\nThis interface can be used by having the resulting `__psvWave_cpp.*.so` file in your\nworking directory or PATH variable, and importing it, e.g.:\n\n```python\nimport __psvWave_cpp\n\nmodel = __psvWave_cpp.fdModel(\n    \"../tests/test_configurations/forward_configuration.ini\")\n\nmodel.forward_shot(0, verbose=True, store_fields=True)\n\n```\n\nHowever, the files in the `./psvWave/` Python module provides an interface that is a\nlittle neater with additional functions. Place the .so file in this folder and have this\nfolder in your path.\n\n## Compiling the documentation\n\nThe documentation for the Python and C++ API requires one extra thing after running\n`pip install -e .[dev]`; A locally installed **doxygen**, to parse the C++ API into a\nSphinx readable structure (a bunch of XML files, really.\nInstalling this is a little platform dependent, with a quick\n`install doxygen \u003cplatform\u003e` typically being enough.\nOn e.g. Ubuntu the command to run would be:\n\n```bash\n$ sudo apt-get install doxygen\n```\n\nFor compiling the total documentation the following needs to be run out of the local git clone:\n\n```bash\n$ cd docs-source\n$ rm build/ -rf\n$ make html\n$ touch build/html/.nojekyll\n```\n\nThe entire content of the `docs-source/build/html` directory, together with an empty file `.nojekyll`, is used as the gh-pages branch.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flarsgeb%2FpsvWave","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flarsgeb%2FpsvWave","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flarsgeb%2FpsvWave/lists"}