├── .gitignore ├── README.md ├── bug ├── bug.py └── matrix_tests.py ├── freeze.sh ├── restart.sh ├── setup.py ├── srfpython ├── HerrMet │ ├── HerrMet.py │ ├── __init__.py │ ├── datacoders.py │ ├── files.py │ ├── optimizetools.py │ ├── overdisp.py │ ├── parameterizers.py │ ├── paramfile.py │ ├── plugins │ │ ├── __init__.py │ │ ├── default.py │ │ ├── display.py │ │ ├── extract.py │ │ ├── manage.py │ │ ├── neldermead.py │ │ ├── optimize.py │ │ ├── param.py │ │ ├── run.py │ │ ├── send.py │ │ └── target.py │ ├── priorpdf.py │ ├── relation.py │ ├── runfile.py │ └── theory.py ├── Herrmann │ ├── Herrmann.py │ ├── __init__.py │ ├── quickdisp.py │ └── src │ │ ├── Makefile │ │ ├── clean.sh │ │ ├── compile.sh │ │ ├── expected1.txt │ │ ├── expected2.txt │ │ ├── max_getdsp.f90 │ │ ├── max_igetmod.f90 │ │ ├── max_iputmod.f90 │ │ ├── max_lgstr.f90 │ │ ├── max_setdsp.f90 │ │ ├── max_setmod.f90 │ │ ├── max_srfdis96.f90 │ │ ├── max_srfpre96.f90 │ │ ├── readme.txt │ │ └── test.sh ├── __init__.py ├── bin │ ├── HerrMet │ ├── m96 │ ├── quickdisp.py │ ├── s96 │ ├── sker17 │ └── srfpython_tester.py ├── coordinates.py ├── depthdisp │ ├── __init__.py │ ├── depthdispdisplay.py │ ├── depthmodels.py │ ├── depthpdfs.py │ ├── dispcurves.py │ ├── disppdfs.py │ ├── m96.py │ ├── mod96.py │ ├── parametricdispcurves.py │ ├── parametricdispcurves1.py │ ├── s96.py │ └── surf96.py ├── inversion │ ├── __init__.py │ ├── concurenteigsearch.py │ ├── covmat.py │ ├── inviter.py │ ├── invsmooth.py │ ├── matinvissue.py │ ├── metropolis2.py │ ├── neldermead2.py │ ├── quasi_newton.py │ ├── tester1.py │ ├── tester2.py │ ├── tester30.py │ ├── tester31.py │ ├── tester32.py │ ├── tester33.py │ ├── tester40.py │ ├── tester41.py │ └── tester50.py ├── sensitivitykernels │ ├── __init__.py │ └── sker17.py ├── standalone │ ├── __init__.py │ ├── asciifile.py │ ├── cmaps.py │ ├── database.py │ ├── display.py │ ├── memtest.py │ ├── multipro8.py │ ├── printcolors.py │ ├── readme.txt │ └── stdout.py ├── synthetics │ ├── __init__.py │ ├── signalfuncs.py │ ├── synthetics.py │ ├── synthetics2.py │ └── testlaws.py ├── testbox │ ├── default_params.sh │ ├── performance.prof │ ├── performance.py │ └── tester.py ├── utils.py └── version.py ├── test ├── test_pyfiles.py └── test_tutorials.py └── tutorials ├── 00_simple_dispersion_example ├── 00_using_scripts │ ├── 000_create_model.py │ ├── 001_show.sh │ ├── 010_dispers.sh │ ├── 011_show.sh │ └── main_script.sh ├── 01_using_python_programs │ ├── 000_create_dephmodel.py │ └── 001_forward_dispersion.py └── 02_1d_sensitivity_kernel.py ├── 01_simple_inversion_example ├── 000_create_model.py ├── 001_show.sh ├── 002_sensitivity.sh ├── 010_dispers.sh ├── 011_show.sh ├── 100_set_target.sh ├── 101_show.sh ├── 110_template_param.sh ├── 111_param.sh ├── 112_show.sh ├── 115_send.sh ├── 117_show.sh ├── 120_run.sh ├── 130_manage.sh ├── 140_display.sh ├── 150_extract.sh ├── clear.sh └── main_script.sh ├── 02_acoustic_scale_inversion_example ├── clear.sh └── main_script.sh ├── 03_cube_inversion_example ├── 000_create_model.py ├── 001_model_to_mod96.py ├── 002_disperse.py ├── 100_set_target.sh ├── 111_param.sh ├── 112_show.sh ├── 115_send.sh ├── 117_show.sh ├── 120_run.sh ├── 130_manage.sh ├── 140_display.sh ├── 150_extract.sh ├── 151_compare.py ├── 200_optimize.sh ├── 201_get_mprior_and_dobs.sh ├── 202_run_optimize.sh ├── clear.sh └── main_script.sh └── 10_notebooks ├── 00_how_to_use_srfpython.html ├── 00_how_to_use_srfpython.ipynb └── readme.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .idea/* 3 | *._* 4 | .ipynb_checkpoints 5 | *.pyc 6 | *.mod96 7 | *.surf96 8 | *.target 9 | *.param 10 | *.run 11 | *.png 12 | *.surf96.copy 13 | *.npy 14 | *.npz 15 | *.log 16 | *.bdd 17 | 18 | .DS_Store 19 | srfpython/Herrmann/bin/max_srfdis96 20 | srfpython/Herrmann/bin/max_srfpre96 21 | /tutorials/02_cube_inversion_example/inversion/ 22 | /tutorials/02_cube_inversion_example/data/ 23 | /tutorials/02_cube_inversion_example/models/ 24 | /tutorials/02_cube_inversion_example/optimize/ 25 | !/maupasacq/*npy 26 | !/maupasacq/*npz 27 | /srfpython.egg-info/ 28 | srfpython/Herrmann/src/in1.txt 29 | srfpython/Herrmann/src/in2.txt 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SrfPython 2 | 3 | - programs for surface wave dispersion curves in python 4 | - compute, display, invert 1D depth models 5 | - based on Herrmann codes Computer Program in seismology 6 | 7 | 8 | ## Install 9 | 10 | ### Pre-requisties 11 | * git 12 | * Anaconda3 13 | * gfortran 14 | 15 | ### Install instructions 16 | - Go to the installation path (e.g. "~/git") and get srfpython 17 | ```bash 18 | cd ~/git 19 | git clone http://github.com/obsmax/srfpython.git 20 | ``` 21 | 22 | - Create the virtual environment and activate it 23 | 24 | ```bash 25 | conda create -n py3-srfpython 26 | conda activate py3-srfpython 27 | python --version # must be 3.X, or conda failed, retry in new tty 28 | ``` 29 | 30 | - Go to the cloned repository and install the package 31 | 32 | ```bash 33 | # install in editable mode 34 | # i.e. changes in python programs do not require re-installing the package 35 | cd ~/git/srfpython 36 | python -m pip install -e . 37 | 38 | # test the compilation using 39 | # (must work anywhere, no need to custom path or anything) 40 | srfpython_tester.py 41 | ``` 42 | 43 | - If you wish to use the jupyter notebooks with python3 (optional): 44 | 45 | 46 | ```bash 47 | # make sure the environment is activated 48 | conda activate py3-srfpython 49 | 50 | # install with 51 | conda install decorator=4.4.1 jupyter --yes 52 | ``` 53 | 54 | ## Tutorials 55 | for a simple dispersion curve example 56 | ```bash 57 | cd ~/git/srfpython/tutorials/00_simple_dispersion_example 58 | # follow instructions in readme.txt 59 | ``` 60 | 61 | for an depth inversion example 62 | ```bash 63 | cd ~/git/srfpython/tutorials/01_simple_inversion_example 64 | # follow instructions in readme.txt 65 | ``` 66 | 67 | more in the jupyter notebooks 68 | ```bash 69 | cd ~/git/srfpython/tutorials/10_notebooks 70 | jupyter notebook 71 | ``` 72 | 73 | ## Contributing authors 74 | * 2024 : The program has been converted from python 2.7 to >3.7 by Pierric Mora. 75 | 76 | 77 | ## Related references 78 | * Lehujeur, M., Chevrot, S., Villaseñor, A., Masini, E., Saspiturry, N., Lescoutre, R., Sylvander, M., 2021. Three-dimensional shear velocity structure of the Mauléon and Arzacq Basins (Western Pyrenees). BSGF - Earth Sci. Bull. 192, 47. https://doi.org/10.1051/bsgf/2021039 79 | * Lehujeur, M., Vergne, J., Schmittbuhl, J., Zigone, D., Le Chenadec, A., & EstOF Team (2018). Reservoir imaging using ambient noise correlation from a dense seismic network. Journal of Geophysical Research: Solid Earth, 123. https://doi.org/10.1029/2018JB015440 80 | 81 | -------------------------------------------------------------------------------- /bug/bug.py: -------------------------------------------------------------------------------- 1 | from srfpython import * 2 | 3 | for i in range(1): 4 | if i == 0: 5 | f = freqspace(0.2, 2.0, 20, "plog") 6 | elif i == 1: 7 | f = freqspace(0.2, 2.0, 200, "plog") 8 | curves = [ 9 | Curve(wave="R", type="U", mode=0, freqs=f), 10 | Curve(wave="R", type="U", mode=1, freqs=f)] 11 | 12 | hc = HerrmannCaller(curves=curves, h=0.005, ddc=0.005) 13 | dm = depthmodel_from_mod96('node014.mod96') 14 | curves_out = hc(dm.vs.z, dm.vp.values, dm.vs.values, dm.rh.values, keepnans=False) 15 | 16 | for curve in curves_out: 17 | curve.plot(plt.gca(), 'o-') 18 | 19 | plt.ion() 20 | plt.show() 21 | input('') 22 | -------------------------------------------------------------------------------- /bug/matrix_tests.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy import sparse 3 | 4 | """ 5 | test for matrix products 6 | """ 7 | 8 | 9 | A = np.array([[1, 2, 3], [0, 4, 5], [0, 0, 6]]) 10 | 11 | j, i = [_.flat[:] 12 | for _ in np.meshgrid(np.arange(A.shape[0]), 13 | np.arange(A.shape[1]))] 14 | 15 | I = A.flat[:] != 0 16 | A = sparse.csc_matrix((A.flat[I], (i[I], j[I])), shape=(3, 3)) 17 | print(sparse.issparse(A)) 18 | x = np.array([1, 2, 3]) 19 | 20 | # xTA = np.dot(x, A) # NO !!!! 21 | # xTA = np.matmul(x, A) # no 22 | # xTA = np.dot(x, A.toarray()) # yes 23 | # xTA = x * A # yes 24 | # xTA = A.__rmul__(x) # yes 25 | # xTA = x.__mul__(A) # no 26 | xTA = A.__rmatmul__(x) # yes 27 | 28 | print(type(xTA), xTA.__class__.__name__, xTA) 29 | -------------------------------------------------------------------------------- /freeze.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # a script to rapidely pause all running threads of HerrMet (using SIGSTOP) 4 | 5 | `ps -ef | grep HerrMet | grep -v grep | awk 'BEGIN {printf("kill -SIGSTOP ")} {printf($2" ")} END {print " "}'` 6 | -------------------------------------------------------------------------------- /restart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # a script to restart all paused threads after freeze.sh 4 | 5 | `ps -ef | grep HerrMet | grep -v grep | awk 'BEGIN {printf("kill -SIGCONT ")} {printf($2" ")} END {print " "}'` 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os, subprocess 2 | import setuptools 3 | from setuptools.command.build_py import build_py 4 | from setuptools.command.develop import develop 5 | 6 | 7 | # ================ paths and files 8 | version_file = os.path.join('srfpython', 'version.py') 9 | fortran_src_path = os.path.join('srfpython', 'Herrmann', 'src') 10 | fortran_bin_path = os.path.join('srfpython', 'Herrmann', 'bin') 11 | packages = setuptools.find_packages() 12 | 13 | # checks 14 | assert os.path.isfile(version_file), "{} not found".format(version_file) 15 | assert os.path.isdir(fortran_src_path), "{} not found".format(fortran_src_path) 16 | 17 | 18 | # ================ get version number from version file 19 | if not os.path.isfile(version_file): 20 | raise IOError(version_file) 21 | 22 | with open(version_file, "r") as fid: 23 | for line in fid: 24 | if line.strip('\n').strip().startswith('__version__'): 25 | __version__ = line.strip('\n').split('=')[-1].split()[0].strip().strip('"').strip("'") 26 | break 27 | else: 28 | raise Exception('could not detect __version__ affectation in {version_file}'.format(version_file=version_file)) 29 | 30 | # ================ load description 31 | with open("README.md", "r") as fh: 32 | long_description = fh.read() 33 | 34 | 35 | # ============= Custom build_py 36 | def make(): 37 | # run command "make all" in ./srfpython/Herrmann/src 38 | if not os.path.isdir(fortran_bin_path): 39 | os.makedirs(fortran_bin_path) 40 | 41 | proc = subprocess.Popen( 42 | ['/usr/bin/make', 'all'], 43 | shell=True, cwd=fortran_src_path) 44 | proc.wait() 45 | 46 | 47 | class CustomBuilder(build_py): 48 | # needed if the package is built, i.e. files will be copied to a site-packages directory 49 | def run(self): 50 | # it is important to run the make file before building the python packages 51 | # so that the shared library files (.so) will be copied to the site-packages directory 52 | # they must appear in the MANIFEST.in file ! 53 | make() 54 | build_py.run(self) 55 | 56 | 57 | class CustomDevelop(develop): 58 | # needed if the package is installed in editable mode 59 | 60 | def run(self): 61 | make() 62 | develop.run(self) 63 | 64 | 65 | setuptools.setup( 66 | name='srfpython', 67 | version=__version__, 68 | packages=packages, 69 | url='https://github.com/obsmax/srfpython', 70 | license='', 71 | author='Maximilien Lehujeur', 72 | author_email='maximilien.lehujeur@gmail.com', 73 | description='compute/inverse surface waves dispersion curves, based on Hermmann codes CPS', 74 | long_description=long_description, 75 | install_requires=['numpy', 'scipy', 'matplotlib', 'future'], 76 | python_requires=">=3.7,<3.12", 77 | classifiers=[ 78 | "Programming Language :: Python :: 3", 79 | "Operating System :: Linux"], 80 | cmdclass={"build_py": CustomBuilder, 81 | "develop": CustomDevelop}, 82 | scripts=['srfpython/bin/srfpython_tester.py', 83 | 'srfpython/bin/m96', 84 | 'srfpython/bin/s96', 85 | 'srfpython/bin/HerrMet', 86 | 'srfpython/bin/sker17', 87 | 'srfpython/bin/quickdisp.py', 88 | ]) 89 | -------------------------------------------------------------------------------- /srfpython/HerrMet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obsmax/srfpython/4e3c4e0effca909174b824d0608cee1371404f0e/srfpython/HerrMet/__init__.py -------------------------------------------------------------------------------- /srfpython/HerrMet/datacoders.py: -------------------------------------------------------------------------------- 1 | from srfpython.depthdisp.dispcurves import surf96reader, surf96reader_from_surf96string, mklaws 2 | import numpy as np 3 | import os 4 | from srfpython.depthdisp.dispcurves import surf96reader_from_arrays 5 | 6 | 7 | """ 8 | see theory.py 9 | """ 10 | 11 | 12 | def log_nofail(x): 13 | if np.isnan(x): 14 | return x 15 | elif x < 0.: 16 | return np.nan 17 | elif x == 0.: 18 | return -np.inf 19 | else: 20 | return np.log(x) 21 | 22 | 23 | class Datacoder(object): 24 | def __init__(self, waves, types, modes, freqs, values, dvalues): 25 | """init with the target data and uncertainty""" 26 | 27 | assert np.all(~np.isnan(values)) 28 | 29 | self.npoints = len(waves) 30 | assert len(types) == len(modes) == \ 31 | len(freqs) == len(values) == \ 32 | len(dvalues) == self.npoints 33 | 34 | self.waves = waves # parameters for forward problem 35 | self.types = types # parameters for forward problem 36 | self.modes = modes # parameters for forward problem 37 | self.freqs = freqs # parameters for forward problem 38 | self.values = values # target dispersion 39 | self.dvalues = dvalues # target dispersion 40 | 41 | def target(self): 42 | dobs = self.values # target data array 43 | CDinv = self.dvalues ** -2. # target data covariance (inverted, diagonal terms) 44 | return dobs, CDinv 45 | 46 | def __call__(self, values): 47 | """converts dispersion values into a data array d""" 48 | # the default behavior is identity, see subclasses for advanced conversions 49 | d = values 50 | return d 51 | 52 | def inv(self, d): 53 | """converts a data array d into dispersion values""" 54 | # the default behavior is identity, see subclasses for advanced conversions 55 | values = d 56 | return values 57 | 58 | def inv_to_surf96reader(self, d): 59 | values = self.inv(d) 60 | return surf96reader_from_arrays( 61 | waves=self.waves, types=self.types, modes=self.modes, 62 | freqs=self.freqs, values=values, dvalues=self.dvalues) 63 | 64 | def inv_to_surf96string(self, d): 65 | return str(self.inv_to_surf96reader(d)) 66 | 67 | def inv_to_laws(self, d): 68 | values = self.inv(d) 69 | laws = mklaws( 70 | waves=self.waves, types=self.types, 71 | modes=self.modes, freqs=self.freqs, 72 | values=values, dvalues=self.dvalues) 73 | return laws 74 | 75 | 76 | class Datacoder_log(Datacoder): 77 | def __init__(self, waves, types, modes, freqs, values, dvalues): 78 | Datacoder.__init__(self, waves, types, modes, freqs, values, dvalues) 79 | 80 | def target(self): 81 | dobs = np.log(self.values) 82 | CDinv = (self.dvalues / self.values) ** -2. 83 | return dobs, CDinv 84 | 85 | def __call__(self, values): 86 | assert len(values) == len(self.values) 87 | d = np.asarray(list(map(log_nofail, values)), float) 88 | return d 89 | 90 | def inv(self, d): 91 | values = np.exp(d) 92 | return values 93 | 94 | 95 | def makedatacoder(surf96filename, which=Datacoder_log): 96 | """ 97 | :param surf96filename: 98 | :type surf96filename: str 99 | :param which: which datacoder to use 100 | :type which: type 101 | :return datacoder: a datacoder object initialized from the data found in surf96filename 102 | :rtype datacoder: DataCoder 103 | """ 104 | if not isinstance(which, type): 105 | raise TypeError("which must be the class of the datacoder to use") 106 | 107 | if os.path.exists(surf96filename): 108 | s = surf96reader(surf96filename) 109 | else: 110 | s = surf96reader_from_surf96string(surf96filename) 111 | 112 | waves, types, modes, freqs, values, dvalues = s.wtmfvd() 113 | return which(waves, types, modes, freqs, values, dvalues) 114 | -------------------------------------------------------------------------------- /srfpython/HerrMet/files.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # rootname designates the directory for temporary files of each node 4 | ROOTKEY = "_HerrMet_" 5 | ROOTNAME = os.path.join(".", ROOTKEY + "{node}") 6 | 7 | # the parameter file is first custom localy and then sent to the temporary directories 8 | HERRMETPARAMFILELOCAL = "_HerrMet.param" 9 | 10 | # the name of the target file in each temporary directory 11 | HERRMETTARGETFILE = os.path.join("{rootname}", "_HerrMet.target") 12 | 13 | # the name of the parameter file in each temporary directory 14 | HERRMETPARAMFILE = os.path.join("{rootname}", HERRMETPARAMFILELOCAL) 15 | 16 | # the name of the run file in each temporary directory 17 | HERRMETRUNFILE = os.path.join("{rootname}", "_HerrMet.run") 18 | 19 | # the name of the display file in each temporary directory 20 | HERRMETDISPLAYFILE = os.path.join("{rootname}", "_HerrMet{options}.png") 21 | 22 | # the name of the display file in each temporary directory 23 | HERRMETSTATSFILE = os.path.join("{rootname}", "_HerrMet.stats.png") 24 | 25 | # the name of the extraction files in each temporary directory 26 | HERRMETEXTRACTPDFMODELFILE = os.path.join( 27 | '{rootname}', 28 | '_HerrMet.{extract_mode:s}_{extract_limit:d}_{extract_llkmin:.2f}_{extract_step:d}.p{percentile:.2f}.mod96') 29 | 30 | HERRMETEXTRACTPDFDISPFILE = os.path.join( 31 | '{rootname}', 32 | '_HerrMet.{extract_mode:s}_{extract_limit:d}_{extract_llkmin:.2f}_{extract_step:d}.p{percentile:.2f}.surf96') 33 | 34 | HERRMETEXTRACTBESTMODELFILE = os.path.join( 35 | '{rootname}', 36 | '_HerrMet.rank{rank:d}.modelid{modelid:d}.chainid{chainid:d}.llk{llk:f}.mod96') 37 | 38 | HERRMETOPTIMIZEPARAMFILE = '_HerrMet.optimize.param' 39 | HERRMETOPTIMIZEPRIORFILE = '_HerrMet.mprior.npz' 40 | HERRMETOPTIMIZEDOBSFILE = '_HerrMet.dobs.npz' 41 | HERRMETOPTIMIZEINVFILE = '_HerrMet.inv.npz' 42 | 43 | # the rootnames to use as default in several plugins 44 | DEFAULTROOTNAMES = os.path.dirname(HERRMETTARGETFILE.format(rootname=ROOTNAME.format(node="*"))) 45 | 46 | 47 | def rootname_to_nodename(rootname): 48 | return os.path.basename(rootname).split(ROOTKEY)[-1] 49 | 50 | 51 | def surf96filename_to_nodename(surf96filename): 52 | return os.path.basename(surf96filename).split('.s96')[0].split('.surf96')[0] 53 | 54 | 55 | def surf96filename_to_rootname(surf96filename): 56 | return ROOTNAME.format(node=surf96filename_to_nodename(surf96filename)) 57 | 58 | 59 | def surf96filename_to_herrmettargetfile(surf96filename, rootdir="."): 60 | return HERRMETTARGETFILE.format( 61 | rootdir=rootdir, 62 | rootname=surf96filename_to_rootname(surf96filename)) 63 | 64 | 65 | if __name__ == '__main__': 66 | print(ROOTNAME) 67 | print(DEFAULTROOTNAMES) 68 | print(HERRMETPARAMFILE) 69 | print(HERRMETTARGETFILE) 70 | print(HERRMETRUNFILE) 71 | print(HERRMETDISPLAYFILE) 72 | -------------------------------------------------------------------------------- /srfpython/HerrMet/overdisp.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from srfpython.Herrmann.Herrmann import HerrmannCallerBasis 3 | from srfpython.standalone.multipro8 import Job, MapSync 4 | from srfpython.standalone.stdout import waitbar 5 | 6 | 7 | class _OverdispCore(object): 8 | def __init__(self, herrmanncaller): 9 | self.herrmanncaller = herrmanncaller 10 | 11 | def __call__(self, mms): 12 | ztop, vp, vs, rh = mms 13 | try: 14 | overvalues = self.herrmanncaller.disperse(ztop, vp, vs, rh) 15 | 16 | except KeyboardInterrupt: 17 | raise 18 | 19 | except Exception as e: 20 | # assume failure was caused by rounding issues 21 | 22 | h = ztop[1:] - ztop[:-1] 23 | h[h <= 0.001] = 0.001001 24 | ztop = np.concatenate(([0.], h.cumsum())) 25 | try: # again 26 | overvalues = self.herrmanncaller.disperse(ztop, vp, vs, rh) 27 | 28 | except: 29 | raise e # raise the initial error 30 | 31 | return mms, overvalues 32 | 33 | 34 | def overdisp(ms, overwaves, overtypes, overmodes, overfreqs, verbose=True, **mapkwargs): 35 | """extrapolate dispersion curves""" 36 | 37 | herrmanncaller = HerrmannCallerBasis( 38 | waves=overwaves, types=overtypes, 39 | modes=overmodes, freqs=overfreqs, 40 | h=0.005, ddc=0.005) 41 | 42 | fun = _OverdispCore(herrmanncaller) 43 | gen = (Job(mms) for mms in ms) 44 | 45 | with MapSync(fun, gen, **mapkwargs) as ma: 46 | if verbose: wb = waitbar('overdisp') 47 | Njobs = len(ms) - 1. 48 | for jobid, (mms, overvalues), _, _ in ma: 49 | if verbose: wb.refresh(jobid / Njobs) 50 | dds = (overwaves, overtypes, overmodes, overfreqs, overvalues) 51 | yield mms, dds 52 | if verbose: 53 | wb.close() 54 | print() 55 | print() -------------------------------------------------------------------------------- /srfpython/HerrMet/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obsmax/srfpython/4e3c4e0effca909174b824d0608cee1371404f0e/srfpython/HerrMet/plugins/__init__.py -------------------------------------------------------------------------------- /srfpython/HerrMet/plugins/default.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | # ------------------------------ defaults 4 | default_option = None 5 | 6 | # ------------------------------ autorized_keys 7 | authorized_keys = ["-option", "-h", "-help"] 8 | 9 | # ------------------------------ help messages 10 | short_help = "--default default plugin structure" 11 | 12 | long_help = """\ 13 | --default s [s..] blablabla 14 | -option f f i s blablabla, default {default_option} 15 | -h, -help display the help message for this plugin 16 | """.format(default_option=default_option) 17 | 18 | # ------------------------------ example usage 19 | example = """\ 20 | ## DEFAULT 21 | # explain what is done 22 | 23 | HerrMet --default 24 | """ 25 | 26 | 27 | def check_keys(argv): 28 | for k in argv.keys(): 29 | if k in ['main', "_keyorder"]: 30 | continue # private keys 31 | 32 | if k not in authorized_keys: 33 | print('option {} is not recognized'.format(k)) # only for the default plugin 34 | 35 | raise Exception('option {} is not recognized'.format(k)) # please use this line in other plugins 36 | 37 | 38 | def default(argv, verbose, mapkwargs): 39 | 40 | if '-h' in argv.keys() or "-help" in argv.keys(): 41 | print(long_help) 42 | return 43 | 44 | check_keys(argv) 45 | 46 | for key, val in argv.items(): 47 | print(key) 48 | print(val) 49 | print('') 50 | 51 | 52 | -------------------------------------------------------------------------------- /srfpython/HerrMet/plugins/manage.py: -------------------------------------------------------------------------------- 1 | import os, glob 2 | import warnings 3 | import numpy as np 4 | from srfpython.depthdisp.depthdispdisplay import plt, showme 5 | from srfpython.HerrMet.runfile import RunFile 6 | from srfpython.HerrMet.files import ROOTNAME, DEFAULTROOTNAMES, HERRMETRUNFILE, HERRMETSTATSFILE, rootname_to_nodename 7 | 8 | # ------------------------------ defaults 9 | default_rootnames = DEFAULTROOTNAMES 10 | 11 | # ------------------------------ autorized_keys 12 | authorized_keys = ["-stats", "-plot", "-delbad", "-delchains", "-inline", "-h", "-help"] 13 | 14 | # ------------------------------ help messages 15 | short_help = "--manage summarize run file content, manage run results" 16 | 17 | long_help = """\ 18 | --manage s [s..] manage run results for given rootnames, default {default_rootnames} 19 | -stats prints detailed stats for each chain of each runfile 20 | -plot [f] display the convergence for every chain and every rootname, specify the lower bound 21 | -inline do not pause (jupyter) 22 | -delbad f delete bad models, log likelihood below a given threshold, no default 23 | -delchains i [i...] delete one or more chains using their chainid 24 | -h, -help display the help message for this plugin 25 | 26 | """.format(default_rootnames=default_rootnames) 27 | 28 | # ------------------------------ example usage 29 | example = """\ 30 | ## MANAGE 31 | # summarize the content of all runfiles, 32 | HerrMet --manage 33 | 34 | # print detailed stats and display the convergence 35 | # of all chains in rootname {rootname} 36 | HerrMet --manage {rootname} -stats 37 | 38 | # remove all models whose log likelihood is below -25 39 | # remove chains 8 11 and 14 40 | HerrMet --manage -delbad -25 -delchains 8 11 14 41 | 42 | """.format(rootname=ROOTNAME.format(node="001")) 43 | 44 | 45 | # ------------------------------ 46 | def manage(argv, verbose, mapkwargs): 47 | 48 | if '-h' in argv.keys() or "-help" in argv.keys(): 49 | print(long_help) 50 | return 51 | 52 | for k in argv.keys(): 53 | if k in ['main', "_keyorder"]: 54 | continue # private keys 55 | 56 | if k not in authorized_keys: 57 | raise Exception('option {} is not recognized'.format(k)) 58 | 59 | rootnames0 = argv['main'] 60 | if rootnames0 == []: 61 | rootnames0 = glob.glob(default_rootnames) 62 | assert len(rootnames0) 63 | 64 | # exclude rootnames with no run file 65 | rootnames = [] 66 | runfiles = [] 67 | for rootname in rootnames0: 68 | runfile = HERRMETRUNFILE.format(rootname=rootname) 69 | if os.path.exists(runfile): 70 | rootnames.append(rootname) 71 | runfiles.append(runfile) 72 | else: 73 | pass # print "%s : %s does not exist" % (rootname, runfile) 74 | del rootnames0 75 | assert len(rootnames) and len(rootnames) == len(runfiles) 76 | 77 | # summarize all files 78 | for rootname, runfile in zip(rootnames, runfiles): 79 | with RunFile(runfile, verbose=False) as rundb: 80 | rundb.summary(head=rootname + " : ") 81 | 82 | showfun = showme 83 | if "-inline" in argv.keys(): 84 | showfun = plt.show 85 | 86 | # more options 87 | if np.any([opt in argv.keys() for opt in ["-stats", "-delbad", "-delchains", "-plot"]]): 88 | fig = None 89 | if "-plot" in argv.keys(): 90 | fig = plt.figure(figsize=(8, 4)) 91 | 92 | for rootname, runfile in zip(rootnames, runfiles): 93 | 94 | with RunFile(runfile, verbose=verbose) as rundb: 95 | # ------------ print chains stats 96 | if "-stats" in argv.keys(): 97 | rundb.stats(head=rootname + " : ") 98 | 99 | # ------------ rm 100 | if "-delbad" in argv.keys(): 101 | rundb.del_bad(llkmin=argv['-delbad'][0]) 102 | 103 | if "-delchains" in argv.keys(): 104 | rundb.del_chain(chainid=argv['-delchains']) 105 | 106 | # ------------ plot 107 | if "-plot" in argv.keys(): 108 | vmin = argv['-plot'][0] if len(argv['-plot']) else None 109 | s = rundb.select(''' 110 | select CHAINID, group_concat(NITER), group_concat(LLK) from MODELS 111 | group by CHAINID 112 | ''') 113 | if s is None: 114 | warnings.warn('no chains found, if the inversion is running, ' 115 | 'please wait for the next commit') 116 | continue 117 | 118 | fig.clf() 119 | ax0 = fig.add_subplot(121) 120 | ax1 = fig.add_subplot(122, sharey=ax0) 121 | LLKs = [] 122 | for CHAINID, NITER, LLK in s: 123 | NITER = np.asarray(NITER.split(','), int) 124 | LLK = np.asarray(LLK.split(','), float) 125 | ax0.plot(NITER, LLK) 126 | ax0.text(NITER[-1], LLK[-1], CHAINID).set_clip_on(True) 127 | LLKs = np.concatenate((LLKs, LLK)) 128 | 129 | ax1.plot(np.sort(LLKs)[::-1]) 130 | if vmin is not None: 131 | ax0.set_ylim(vmin, 0) 132 | ax0.set_xlabel('# iteration') 133 | ax0.set_ylabel('log likelihood') 134 | ax1.set_xlabel('# rank') 135 | ax0.grid(True, linestyle=":") 136 | ax1.grid(True, linestyle=":") 137 | fig.suptitle(rootname_to_nodename(rootname)) 138 | showfun() 139 | statsfile = HERRMETSTATSFILE.format(rootname=rootname) 140 | if verbose: 141 | print('saving ' + statsfile) 142 | fig.savefig(statsfile) 143 | 144 | if "-plot" in argv.keys(): 145 | plt.close(fig) 146 | -------------------------------------------------------------------------------- /srfpython/HerrMet/plugins/neldermead.py: -------------------------------------------------------------------------------- 1 | # import os, glob 2 | # import numpy as np 3 | # from srfpython.standalone.multipro8 import Job, MapAsync 4 | # from srfpython.inversion.metropolis2 import LogGaussND 5 | # from srfpython.inversion.neldermead2 import neldermead as neldermead_function 6 | # from srfpython.HerrMet.runfile import RunFile 7 | # from srfpython.HerrMet.paramfile import load_paramfile 8 | # from srfpython.HerrMet.datacoders import makedatacoder, Datacoder_log 9 | # from srfpython.HerrMet.theory import Theory 10 | # from srfpython.depthdisp.depthdispdisplay import * #DepthDispDisplay, * 11 | # 12 | # # ------------------------------ defaults 13 | # default_rootnames = "_HerrMet_*" 14 | # default_top_llkmin = -1000. 15 | # default_top_limit = 1 16 | # default_top_step = 1 17 | # default_niter = 1000 18 | # default_ic = 1.e-3 19 | # # ------------------------------ autorized_keys 20 | # authorized_keys = ["-top", "-niter", "-ic"] 21 | # 22 | # # ------------------------------ help messages 23 | # short_help = "--neldermead NOT READY, optimize best solutions from run using the nelder mead algorithm" 24 | # 25 | # long_help = """\ 26 | # --neldermead s [s..] start inversion for the required rootnames, default {default_rootnames} 27 | # -top [f i i] show the best models on the figure, see --extract for arguments 28 | # default {default_top_llkmin}, {default_top_limit}, {default_top_step} 29 | # -niter [i] max number of iteration, default {default_niter} 30 | # -ic [f] interruption condition , default {default_ic} 31 | # """.format(default_rootnames=default_rootnames, 32 | # default_top_llkmin=default_top_llkmin, 33 | # default_top_limit=default_top_limit, 34 | # default_top_step=default_top_step, 35 | # default_niter=default_niter, 36 | # default_ic=default_ic) 37 | # 38 | # # ------------------------------ example usage 39 | # example = """\ 40 | # ## NELDERMEAD 41 | # # comments 42 | # 43 | # HerrMet -w 4 \\ 44 | # --neldermead 45 | # 46 | # """ 47 | # 48 | # def argunique(X): 49 | # return np.unique(X, return_index = True)[1] 50 | # 51 | # # ------------------------------ 52 | # def neldermead(argv, verbose, mapkwargs): 53 | # raise Exception('not ready') 54 | # for k in argv.keys(): 55 | # if k in ['main', "_keyorder"]: 56 | # continue # private keys 57 | # 58 | # if k not in authorized_keys: 59 | # raise Exception('option %s is not recognized' % k) 60 | # 61 | # rootnames = argv['main'] 62 | # if rootnames == []: 63 | # rootnames = glob.glob(default_rootnames) 64 | # assert len(rootnames) 65 | # for rootname in rootnames: 66 | # runfile = "%s/_HerrMet.run" % rootname 67 | # assert os.path.exists(runfile) 68 | # 69 | # assert argv["-top"] == [] or len(argv["-top"]) == 3 # unexpected argument number 70 | # if argv["-top"] == []: 71 | # top_llkmin, top_limit, top_step = default_top_llkmin, default_top_limit, default_top_step 72 | # elif len(argv['-top']) == 3: 73 | # top_llkmin, top_limit, top_step = argv['-top'] 74 | # print "top : llkmin %f, limit %d, step %d" % (top_llkmin, top_limit, top_step) 75 | # 76 | # # ------------------------ 77 | # def gen(rootnames): 78 | # 79 | # for rootname in rootnames: 80 | # targetfile = "%s/_HerrMet.target" % rootname 81 | # paramfile = "%s/_HerrMet.param" % rootname 82 | # runfile = "%s/_HerrMet.run" % rootname 83 | # 84 | # # ------ 85 | # p, logRHOM = load_paramfile(paramfile) 86 | # # ------ 87 | # d = makedatacoder(targetfile, which=Datacoder_log) # datacoder based on observations 88 | # dobs, CDinv = d.target() 89 | # duncs = CDinv ** -.5 90 | # ND = len(dobs) 91 | # dinfs = d(0.1 * np.ones_like(d.values)) 92 | # dsups = d(3.5 * np.ones_like(d.values)) 93 | # logRHOD = LogGaussND(dobs, duncs, dinfs, dsups, k=1000., nanbehavior=1) 94 | # # ------ 95 | # G = Theory(parameterizer=p, datacoder=d) 96 | # # --------------------------------- 97 | # with RunFile(runfile, verbose=verbose) as rundb: 98 | # best = list(rundb.get(llkmin=top_llkmin, limit=top_limit, step=top_step, algo=None)) 99 | # 100 | # # --------------------------------- 101 | # for modelid, chainid, weight, llk, nlayer, model, dat in best: 102 | # M0 = p(*model) 103 | # DM = 1.0 #p.MSTD 104 | # 105 | # yield Job(runfile=runfile, 106 | # rootname=rootname, 107 | # chainid=chainid, 108 | # M0=M0, 109 | # DM=DM, 110 | # G=G, 111 | # ND=ND, 112 | # logRHOD=logRHOD, 113 | # logRHOM=logRHOM, 114 | # p=p, d=d, 115 | # verbose=verbose) 116 | # 117 | # def fun(runfile, rootname, chainid, M0, DM, G, ND, logRHOD, logRHOM, p, d, verbose): 118 | # models, datas, llks = neldermead_function(M0, DM, G, ND, logRHOD, logRHOM, 119 | # alpha=1.0, 120 | # beta=0.9, 121 | # gamma=1.2, 122 | # maxiter=1000, 123 | # interrupt=1e-12, 124 | # debug=1) 125 | # 126 | # weights = np.ones_like(llks) 127 | # I = np.any(~np.isnan(datas), axis=1) 128 | # models, datas, weights, llks = models[I, :], datas[I, :], weights[I], llks[I] 129 | # 130 | # I = argunique(llks) 131 | # models, datas, weights, llks = models[I, :], datas[I, :], weights[I], llks[I] 132 | # 133 | # return runfile, models, datas, weights, llks, p, d 134 | # 135 | # 136 | # with MapAsync(fun, gen(rootnames), **mapkwargs) as ma: 137 | # for jobid, answer, _, _ in ma: 138 | # runfile, models, datas, weights, llks, p, d = answer 139 | # if verbose: 140 | # print '=> write to %s' % runfile 141 | # with RunFile(runfile, verbose=False) as rundb: 142 | # rundb.begintransaction() 143 | # try: 144 | # rundb.insert("NELDERMEAD", models, datas, weights, llks, p, d) 145 | # rundb.commit() 146 | # except: 147 | # rundb.rollback(crash=True) 148 | # 149 | # 150 | # rd = DepthDispDisplay(targetfile=runfile.replace('.run', '.target')) 151 | # for model, data, llk in zip(models, datas, llks): 152 | # rd.plotmodel(color="k", alpha=0.2, showvp=True, showvs=True, showrh=True, 153 | # showpr=True, *p.inv(model)) 154 | # 155 | # rd.plotdisp(d.waves,d.types,d.modes,d.freqs,d.inv(data), dvalues=None, color="k", alpha=0.2) 156 | # showme() 157 | # plt.close('all') 158 | # 159 | # 160 | -------------------------------------------------------------------------------- /srfpython/HerrMet/plugins/param.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import os 4 | import numpy as np 5 | from srfpython.utils import minmax 6 | from srfpython.HerrMet.paramfile import write_default_paramfile 7 | from srfpython.HerrMet.files import ROOTNAME, HERRMETPARAMFILE, HERRMETPARAMFILELOCAL 8 | 9 | # ------------------------------ defaults 10 | default_parameterization_list = ['mZVSPRRH', 'mZVSVPRH', 'mZVSPRzRHvp', 'mZVSPRzRHz', 'mZVSVPvsRHvp'] 11 | default_parameterization = default_parameterization_list[0] 12 | 13 | # ------------------------------ autorized_keys 14 | authorized_keys = ["-basedon", "-t", "-dvp", "-dvs", "-drh", "-dpr", "-growing", "-op", "-h", "-help"] 15 | 16 | # ------------------------------ help messages 17 | short_help = "--param create a template parameterization file" 18 | 19 | long_help = """\ 20 | --param i f generate a template parameter file to custom in . 21 | need the number of layers and bottom depth in km 22 | -basedon s build parametrization based on an existing mod96 file, require a filename, 23 | if not specified, I take fixed values to build the parameter file 24 | -t s parameterization type to use ({default_parameterization_list}), 25 | default {default_parameterization} 26 | mZVSPRRH = parameterize with 27 | - depth interface (mZ1 = first interface, mZ2, ...), 28 | - VS in each layer (VS0 = first layer, ...), 29 | - VP/VS in each layer (PR0, PR1, ...), 30 | - Density in each layer (RH0, RH1, ...) 31 | mZVSVPRH = parameterize with 32 | - depth interface (mZ1 = first interface, mZ2, ...), 33 | - VS in each layer (VS0 = first layer, ...), 34 | - VP in each layer (VP0, VP1, ...), 35 | - Density in each layer (RH0, RH1, ...) 36 | mZVSPRzRHvp = parameterize with 37 | - depth interface (mZ1 = first interface, mZ2, ...), 38 | - VS in each layer (VS0 = first layer, ...), 39 | - use a fixed relation between VP/VS = f(z) 40 | - use a fixed relation between RH = f(VP) 41 | mZVSPRzRHz = parameterize with 42 | - depth interface (mZ1 = first interface, mZ2, ...), 43 | - VS in each layer (VS0 = first layer, ...), 44 | - use a fixed relation between VP/VS = f(z) 45 | - use a fixed relation between RH = f(z) 46 | mZVSVPvsRHvp = parameterize with 47 | - depth interface (mZ1 = first interface, mZ2, ...), 48 | - VS in each layer (VS0 = first layer, ...), 49 | - use a fixed relation between VP = f(VS) 50 | - use a fixed relation between RH = f(VP) 51 | -dvp f f add prior constraint on the vp offset between layers, 52 | requires the extremal values, km/s 53 | -dvs f f add prior constraint on the vs offset between layers, idem 54 | -drh f f add prior constraint on the density offset between layers, idem, g/cm3 55 | -dpr f f add prior constraint on the vp/vs offset between layers, idem, no unit 56 | -growing shortcut for -dvp 0. 5. -dvs 0. 5. -drh 0. 5. -dpr -5. 0. 57 | -op force overwriting {herrmetparamfilelocal} if exists 58 | -h, -help display the help message for this plugin 59 | """.format(herrmetparamfilelocal=HERRMETPARAMFILELOCAL, 60 | default_parameterization_list=default_parameterization_list, 61 | default_parameterization=default_parameterization) 62 | 63 | # ------------------------------ example usage 64 | example = """\ 65 | ## PARAM 66 | # build parameter file from existing depthmodel, 67 | # use 4 layers, use parametrization mZVSPRRH, 68 | # require vp, vs and density to be growing 69 | # overwrite paramfile if exists ({paramfiles}) and display 70 | 71 | HerrMet --param 4 3. \\ 72 | -basedon /path/to/my/depthmodel.mod96 \\ 73 | -t mZVSPRRH \\ 74 | -growing \\ 75 | -op \\ 76 | --display . 77 | 78 | # >> now edit {herrmetparamfilelocal} and customize it, check with 79 | HerrMet --display . 80 | 81 | # when ok, send the parameterization file to the rootnames 82 | HerrMet --send 83 | """.format(herrmetparamfilelocal=HERRMETPARAMFILELOCAL, 84 | paramfiles=HERRMETPARAMFILE.format(rootname=ROOTNAME.format(node="*"))) 85 | 86 | 87 | # ------------------------------ 88 | def param(argv): 89 | 90 | if '-h' in argv.keys() or "-help" in argv.keys(): 91 | print(long_help) 92 | return 93 | 94 | for k in argv.keys(): 95 | if k in ['main', "_keyorder"]: 96 | continue # private keys 97 | 98 | if k not in authorized_keys: 99 | raise Exception('option %s is not recognized' % k) 100 | 101 | if "-op" not in argv.keys(): 102 | if os.path.exists(HERRMETPARAMFILELOCAL): 103 | raise IOError(HERRMETPARAMFILELOCAL + ' exists already, use -op to overwrite') 104 | 105 | nlayer = int(argv["main"][0]) 106 | zbot = float(argv["main"][1]) 107 | type_ = argv['-t'][0] if "-t" in argv.keys() else default_parameterization 108 | basedon = argv['-basedon'][0] if "-basedon" in argv.keys() else None 109 | if "-growing" in argv.keys(): 110 | assert "-dvs" not in argv.keys() # not compatible with -growing 111 | assert "-dvp" not in argv.keys() # not compatible with -growing 112 | assert "-drh" not in argv.keys() # not compatible with -growing 113 | assert "-dpr" not in argv.keys() # not compatible with -growing 114 | dvp = 0., 5. 115 | dvs = 0., 5. 116 | drh = 0., 5. 117 | dpr = -5., 0. 118 | else: 119 | dvp = minmax(np.asarray(argv['-dvp'], float)) if "-dvp" in argv.keys() else None 120 | dvs = minmax(np.asarray(argv['-dvs'], float)) if "-dvs" in argv.keys() else None 121 | drh = minmax(np.asarray(argv['-drh'], float)) if "-drh" in argv.keys() else None 122 | dpr = minmax(np.asarray(argv['-dpr'], float)) if "-dpr" in argv.keys() else None 123 | 124 | if not type_ in default_parameterization_list: 125 | raise Exception('please pick one type in %s' % str(default_parameterization_list)) 126 | 127 | write_default_paramfile( 128 | nlayer, zbot, which_parameterizer=type_, basedon=basedon, dvp=dvp, dvs=dvs, drh=drh, dpr=dpr) 129 | 130 | print("you can edit {} to adjust parameters boundaries, " 131 | "do not change line orders".format(HERRMETPARAMFILELOCAL)) 132 | print("use option --display to see the depth boundaries of your parameter file") 133 | print("use option --send to copy the parameter file to each temporary directory") 134 | -------------------------------------------------------------------------------- /srfpython/HerrMet/plugins/send.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from srfpython.HerrMet.files import HERRMETPARAMFILELOCAL, HERRMETPARAMFILE, DEFAULTROOTNAMES 3 | import os, glob 4 | 5 | # ------------------------------ defaults 6 | default_rootnames = DEFAULTROOTNAMES 7 | 8 | # ------------------------------ autorized_keys 9 | authorized_keys = ["-op", "-h", "-help"] 10 | 11 | # ------------------------------ help messages 12 | short_help = "--send send the parameterization to the temporary directories" 13 | 14 | long_help = """\ 15 | --send s [s..] send the custom parameterization file {herrmetparamfilelocal} to the specified rootnames, 16 | default {default_rootnames} 17 | -op force overwriting {herrmetparamfile} if exists 18 | -h, -help display the help message for this plugin 19 | """.format( 20 | herrmetparamfilelocal=HERRMETPARAMFILELOCAL, 21 | herrmetparamfile=HERRMETPARAMFILE.format(rootname='[rootname]'), 22 | default_rootnames=default_rootnames) 23 | 24 | # ------------------------------ example usage 25 | example = "" 26 | 27 | 28 | # ------------------------------ 29 | def send(argv, verbose): 30 | 31 | if '-h' in argv.keys() or "-help" in argv.keys(): 32 | print(long_help) 33 | return 34 | 35 | for k in argv.keys(): 36 | if k in ['main', "_keyorder"]: 37 | continue # private keys 38 | 39 | if k not in authorized_keys: 40 | raise Exception('option {} is not recognized'.format(k)) 41 | 42 | if not os.path.exists(HERRMETPARAMFILELOCAL): 43 | raise Exception('please use option --param first') 44 | 45 | rootnames = argv['main'] 46 | if rootnames == []: 47 | rootnames = glob.glob(default_rootnames) 48 | assert len(rootnames) 49 | 50 | for rootname in rootnames: 51 | paramfile = HERRMETPARAMFILE.format(rootname=rootname) 52 | paramdir = os.path.dirname(paramfile) 53 | 54 | if not os.path.isdir(paramdir): 55 | raise IOError(paramdir + ' is not a directory') 56 | 57 | elif os.path.isfile(paramfile): 58 | if not "-op" in argv.keys(): 59 | raise Exception('{} exists already, use -op'.format(paramfile)) 60 | 61 | for rootname in rootnames: 62 | paramfile = HERRMETPARAMFILE.format(rootname=rootname) 63 | 64 | cmd = 'cp {} {}'.format(HERRMETPARAMFILELOCAL, paramfile) 65 | if verbose: 66 | print(cmd) 67 | os.system(cmd) -------------------------------------------------------------------------------- /srfpython/HerrMet/plugins/target.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import os 4 | import numpy as np 5 | from srfpython.depthdisp.dispcurves import Claw, surf96reader, freqspace 6 | from srfpython.HerrMet.files import ROOTNAME, HERRMETTARGETFILE, \ 7 | surf96filename_to_rootname, surf96filename_to_herrmettargetfile, \ 8 | surf96filename_to_nodename 9 | 10 | # ------------------------------ defaults 11 | 12 | # ------------------------------ autorized_keys 13 | authorized_keys = ["-resamp", "-lunc", "-unc", "-ot", "-h", "-help"] 14 | 15 | # ------------------------------ help messages 16 | short_help = "--target set the target data, create temporary directories for each location" 17 | 18 | long_help = """\ 19 | --target s [s..] A target designate a surf96 file containing a set of 20 | dispersion curves to invert for one specific location. 21 | For each surf96 file, I create a directory in . for temporary files 22 | the target file in this directory is a copy of the input surf96 file. 23 | It can be edited before inversion to remove unwanted points or resample dispersion curves... 24 | it the target file is {surf96file}, the temporary directory will be named 25 | {rootname}, this name is referred to as the "rootname" in the other plugins 26 | -resamp f f i s resample the dispersion curve in the target file, 27 | requires fmin(Hz), fmax(Hz), nfreq, fscale 28 | (flin=linear in freq domain, plin=linear in period or log=logarithmic scaling) 29 | -lunc f set constant uncertainties in log domain (uncertainty = value x lunc) 30 | -unc f set constant uncertainty in linear domain (uncertainty = unc) 31 | -ot force overwriting the targetfiles if exist 32 | -h, -help display the help message for this plugin 33 | """.format(surf96file="AAAA.surf96", 34 | rootname=surf96filename_to_rootname("AAAA.surf96")) 35 | 36 | # ------------------------------ example usage 37 | example = """\ 38 | ## TARGET 39 | # get the target dispersion curves, resample it between 0.2-1.5 Hz 40 | # with 15 samples spaced logarithmically in period domain 41 | # adjust uncertainties to 0.1 in logaritmic domain, 42 | # overwrite target files if exist ({herrmettargetfile}) 43 | # and display it 44 | 45 | HerrMet --target {surf96filename} \\ 46 | -resamp 0.2 1.5 15 plog \\ 47 | -lunc 0.1 \\ 48 | -ot \\ 49 | --display 50 | 51 | # >> you may edit one or more target files (among {herrmettargetfile}) 52 | # and remove points that 53 | # do not need to be inverted, check with 54 | 55 | HerrMet --display {rootname} 56 | 57 | """.format( 58 | surf96filename="/path/to/my/data/node???.surf96", 59 | herrmettargetfile=surf96filename_to_herrmettargetfile("/path/to/my/data/node???.surf96"), 60 | rootname=ROOTNAME.format(node="node???")) 61 | 62 | 63 | def target(argv, verbose): 64 | 65 | if '-h' in argv.keys() or "-help" in argv.keys(): 66 | print(long_help) 67 | return 68 | 69 | for k in argv.keys(): 70 | if k in ['main', "_keyorder"]: 71 | continue # private keys 72 | 73 | if k not in authorized_keys: 74 | raise Exception('option %s is not recognized' % k) 75 | 76 | # determine root names from target filess 77 | rootnames = [] 78 | for s96 in argv['main']: 79 | rootname = ROOTNAME.format(node=surf96filename_to_nodename(s96)) 80 | rootnames.append(rootname) 81 | assert len(np.unique(rootnames)) == len(rootnames) # make sure all rootnames are distinct 82 | 83 | # handle already existing files 84 | if "-ot" not in argv.keys(): 85 | for rootname in rootnames: 86 | target_file = HERRMETTARGETFILE.format(rootname=rootname) 87 | if os.path.exists(target_file): 88 | raise Exception('file {} exists already, use -ot to overwrite' % target_file) 89 | 90 | # loop over targets 91 | for rootname, s96 in zip(rootnames, argv['main']): 92 | target_file = HERRMETTARGETFILE.format(rootname=rootname) 93 | target_dir = os.path.dirname(target_file) 94 | 95 | # create directory 96 | if not os.path.isdir(target_dir): 97 | if verbose: 98 | print("creating " + target_dir) 99 | os.makedirs(target_dir) 100 | s96copy = os.path.join(target_dir, os.path.basename(s96)) + ".copy" 101 | cpcmd = 'cp {} {}'.format(s96, s96copy) 102 | if verbose: 103 | print(cpcmd) 104 | os.system(cpcmd) 105 | 106 | s = surf96reader(s96) 107 | 108 | if "-resamp" in argv.keys(): 109 | news = s.copy() 110 | news.clear() # clear all entries 111 | newf = freqspace(freqmin=float(argv["-resamp"][0]), 112 | freqmax=float(argv["-resamp"][1]), 113 | nfreq=int(argv["-resamp"][2]), 114 | scale=argv["-resamp"][3]) 115 | for law in s.get_all(): 116 | law.set_extrapolationmode(1) 117 | stdlaw = Claw(freq=law.freq, value=law.dvalue, extrapolationmode=0) 118 | 119 | newvalues = law(newf) 120 | newdvalues = stdlaw(newf) 121 | 122 | I = ~np.isnan(newvalues) 123 | if I.any(): 124 | N = I.sum() 125 | news.data['WAVE'] = np.concatenate((news.data['WAVE'], np.array([law.wave]).repeat(N))) 126 | news.data['TYPE'] = np.concatenate((news.data['TYPE'], np.array([law.type]).repeat(N))) 127 | news.data['FLAG'] = np.concatenate((news.data['FLAG'], np.array([law.flag]).repeat(N))) 128 | news.data['MODE'] = np.concatenate((news.data['MODE'], np.array([law.mode]).repeat(N))) 129 | news.data['PERIOD'] = np.concatenate((news.data['PERIOD'], 1. / newf[I])) 130 | news.data['VALUE'] = np.concatenate((news.data['VALUE'], newvalues[I])) 131 | news.data['DVALUE'] = np.concatenate((news.data['DVALUE'], newdvalues[I])) 132 | 133 | s = news 134 | # print news 135 | 136 | if "-lunc" in argv.keys(): 137 | # set uncertainties to constant in log domain 138 | lunc = float(argv["-lunc"][0]) 139 | s.data['DVALUE'] = s.data['VALUE'] * lunc 140 | 141 | elif "-unc" in argv.keys(): 142 | # set uncertainties to constant in lin domain 143 | unc = float(argv["-unc"][0]) 144 | s.data['DVALUE'] = np.ones(len(s.data['VALUE'])) * unc 145 | 146 | if verbose: 147 | print("writing " + target_file) 148 | s.write96(target_file) 149 | 150 | # ------------------- 151 | print("please keep only datapoints to invert in " + HERRMETTARGETFILE.format(rootname="*")) 152 | print("use option --display to see the target data") 153 | -------------------------------------------------------------------------------- /srfpython/HerrMet/relation.py: -------------------------------------------------------------------------------- 1 | class Relation(object): 2 | # I need a pickable object to pass a function that was defined from a string... 3 | def __init__(self, name, string): 4 | """ 5 | :param name: name of the relation (i.e. function name) 6 | :param string: expression of the function 7 | version 1 : string = "lambda x: 3 * x + 2" 8 | version 2 : string = "def name(x): return 3 * x + 2" 9 | """ 10 | self.name = name 11 | self.string = string 12 | 13 | if self.string.strip().startswith('lambda'): 14 | self.fun = eval(self.string) 15 | 16 | elif self.string.strip().startswith('def {}('.format(name)): 17 | eval(compile(self.string, '', 'exec')) 18 | self.fun = eval(name) 19 | 20 | else: 21 | raise ValueError("could not compile {} ".format(string)) 22 | 23 | def __getstate__(self): 24 | return self.name, self.string 25 | 26 | def __setstate__(self, state): 27 | name, string = state 28 | Relation.__init__(self, name=name, string=string) 29 | 30 | def __call__(self, *args, **kwargs): 31 | return self.fun(*args, **kwargs) 32 | -------------------------------------------------------------------------------- /srfpython/Herrmann/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obsmax/srfpython/4e3c4e0effca909174b824d0608cee1371404f0e/srfpython/Herrmann/__init__.py -------------------------------------------------------------------------------- /srfpython/Herrmann/quickdisp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys, glob, os 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | from srfpython.depthdisp.depthmodels import depthmodel_from_arrays 7 | from srfpython.Herrmann.Herrmann import HerrmannCaller, Curve 8 | 9 | 10 | ztopvpvsrh = np.asarray(sys.argv[1:], float) 11 | nlayer = len(ztopvpvsrh) // 4 12 | ztop = ztopvpvsrh[:nlayer] #km 13 | vp = ztopvpvsrh[nlayer:2*nlayer] #km/s 14 | vs = ztopvpvsrh[2*nlayer:3*nlayer] #km/s 15 | rh = ztopvpvsrh[3*nlayer:] #g/cm3 16 | 17 | dm = depthmodel_from_arrays( 18 | z=ztop, vp=vp, vs=vs, rh=rh) 19 | 20 | cmin_approx = 0.9 * min(vs) 21 | cmax_approx = 0.9 * max(vs) 22 | 23 | lambda_min_approx = ztop[1] / 3. 24 | lambda_max_approx = ztop[-1] * 3. 25 | 26 | freq_min = cmin_approx / lambda_max_approx 27 | freq_max = cmax_approx / lambda_min_approx 28 | 29 | assert freq_min < freq_max 30 | freqs = np.logspace(np.log10(freq_min), np.log10(freq_max), 30) 31 | 32 | print(f"{ztop=}") 33 | print(f"{vp=}") 34 | print(f"{dm.vs.stairs()=}") 35 | print(f"{dm.rh.stairs()=}") 36 | print(f"{freqs=}") 37 | 38 | 39 | curves = [ 40 | Curve(wave="R", type="C", mode=0, freqs=freqs), 41 | Curve(wave="R", type="C", mode=1, freqs=freqs), 42 | Curve(wave="R", type="C", mode=2, freqs=freqs), 43 | Curve(wave="R", type="C", mode=3, freqs=freqs), 44 | ] 45 | 46 | hc = HerrmannCaller(curves=curves, h=0.0005, ddc=0.0005) 47 | curves = hc(ztop=dm.vp.ztop(), vp=dm.vp.values, vs=dm.vs.values, rh=dm.rh.values) 48 | 49 | 50 | fig = plt.figure() 51 | 52 | ax2 = fig.add_subplot(222) 53 | for curve in curves: 54 | ax2.plot( 55 | curve.freqs, curve.values * 1000., 56 | label="%s%s%d" % (curve.wave, curve.type, curve.mode)) 57 | ax2.set_xlabel('Frequency (Hz)') 58 | ax2.set_ylabel('Phase Velocity (m/s)') 59 | 60 | ax2.legend() 61 | 62 | ax1 = fig.add_subplot(121) 63 | dm.show(ax=ax1, units="m/s/kg.m-3") 64 | ax1.set_ylabel('Depth (m)') 65 | ax1.set_xlabel('Value (m/s, kg/m^3)') 66 | ax1.legend() 67 | plt.show() 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /srfpython/Herrmann/src/Makefile: -------------------------------------------------------------------------------- 1 | # Make file, will be executed by python setuptools 2 | 3 | .DEFAULT_GOAL := all 4 | .PHONY : clean compile test all 5 | 6 | clean: 7 | bash clean.sh; 8 | 9 | compile: 10 | bash compile.sh; 11 | 12 | test: 13 | bash ./test.sh; 14 | 15 | all: clean compile test 16 | -------------------------------------------------------------------------------- /srfpython/Herrmann/src/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -f max_igetmod.o 4 | rm -f max_iputmod.o 5 | rm -f max_lgstr.o 6 | rm -f max_setdsp.o 7 | rm -f max_getdsp.o 8 | rm -f max_setmod.o 9 | rm -f max_mchdep.o 10 | rm -f max_srfdis96.o 11 | rm -f max_srfpre96.o 12 | 13 | rm -f ../bin/max_srfpre96 14 | rm -f ../bin/max_srfdis96 15 | 16 | # remove test files 17 | rm -f in1.txt in2.txt out1.txt out2.txt -------------------------------------------------------------------------------- /srfpython/Herrmann/src/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #--------------------------------- 4 | gfortran -O -c max_igetmod.f90 5 | gfortran -O -c max_iputmod.f90 6 | gfortran -O -c max_lgstr.f90 7 | gfortran -O -c max_setdsp.f90 8 | gfortran -O -c max_getdsp.f90 9 | gfortran -O -c max_setmod.f90 10 | gfortran -O -c max_srfpre96.f90 11 | 12 | 13 | gfortran -O -o max_srfpre96 max_srfpre96.o max_lgstr.o \ 14 | max_igetmod.o max_iputmod.o max_setdsp.o max_setmod.o max_getdsp.o 15 | 16 | 17 | gfortran -o max_srfdis96 max_srfdis96.f90 18 | 19 | 20 | #--------------------------------- 21 | rm -f max_igetmod.o 22 | rm -f max_iputmod.o 23 | rm -f max_lgstr.o 24 | rm -f max_setdsp.o 25 | rm -f max_getdsp.o 26 | rm -f max_setmod.o 27 | rm -f max_srfdis96.o 28 | rm -f max_srfpre96.o 29 | 30 | #--------------------------------- 31 | #move executable files 32 | mkdir -p ../bin 33 | mv max_srfdis96 max_srfpre96 ../bin 34 | -------------------------------------------------------------------------------- /srfpython/Herrmann/src/expected1.txt: -------------------------------------------------------------------------------- 1 | 30 2 | 30 2 2 3 | 0.833 0.855 0.870 0.885 0.901 1.000 1.010 1.020 1.304 1.384 1.447 1.520 1.606 1.778 1.840 1.909 2.041 2.242 2.408 2.609 3.162 3.571 4.006 4.480 5.623 6.667 6.682 7.692 10.000 12.500 4 | 4 30 5 | 5 15 6 | 30 2 2 7 | 0.833 0.855 0.870 0.885 0.901 1.000 1.010 1.020 1.304 1.384 1.447 1.520 1.606 1.778 1.840 1.909 2.041 2.242 2.408 2.609 3.162 3.571 4.006 4.480 5.623 6.667 6.682 7.692 10.000 12.500 8 | 1 30 9 | 1 18 10 | -------------------------------------------------------------------------------- /srfpython/Herrmann/src/expected2.txt: -------------------------------------------------------------------------------- 1 | 1 0 0.880597 0.889447 0.982906 0.984710 2 | 1 0 0.896517 0.905528 0.986155 0.988001 3 | 1 0 0.995025 1.005025 1.006661 1.008782 4 | 1 0 1.004975 1.015075 1.008771 1.010921 5 | 1 0 1.014925 1.025126 1.010889 1.013068 6 | 1 0 1.297512 1.310553 1.074367 1.077468 7 | 1 0 1.377114 1.390955 1.093567 1.096973 8 | 1 0 1.439801 1.454271 1.109164 1.112826 9 | 1 0 1.512438 1.527638 1.127803 1.131785 10 | 1 0 1.598010 1.614070 1.150609 1.154997 11 | 1 0 1.769154 1.786935 1.199308 1.204627 12 | 1 0 1.830846 1.849246 1.217987 1.223685 13 | 1 0 1.899503 1.918593 1.239551 1.245699 14 | 1 0 2.030846 2.051256 1.283278 1.290385 15 | 1 0 2.230846 2.253266 1.356941 1.365790 16 | 1 0 2.396020 2.420100 1.425222 1.435799 17 | 1 0 2.596020 2.622111 1.518289 1.531339 18 | 1 0 3.146269 3.177889 1.839749 1.860914 19 | 1 0 3.553234 3.588945 2.122394 2.147363 20 | 1 0 3.986070 4.026131 2.407068 2.430614 21 | 1 0 4.457712 4.502512 2.646533 2.665092 22 | 1 0 5.595025 5.651257 2.958631 2.967965 23 | 1 0 6.633831 6.700502 3.084423 3.090005 24 | 1 0 6.648757 6.715578 3.085692 3.091238 25 | 1 0 7.653731 7.730653 3.150960 3.154698 26 | 1 0 9.950249 10.050251 3.222917 3.224829 27 | 1 0 12.437811 12.562814 3.256440 3.257573 28 | 1 1 0.896517 0.905528 1.707245 1.720852 29 | 1 1 0.995025 1.005025 1.865707 1.883011 30 | 1 1 1.004975 1.015075 1.882924 1.900632 31 | 1 1 1.014925 1.025126 1.900368 1.918487 32 | 1 1 1.297512 1.310553 2.483222 2.512692 33 | 1 1 1.377114 1.390955 2.661049 2.691020 34 | 1 1 1.439801 1.454271 2.792739 2.821404 35 | 1 1 1.512438 1.527638 2.928381 2.953976 36 | 1 1 1.598010 1.614070 3.058996 3.079870 37 | 1 1 1.769154 1.786935 3.228025 3.239536 38 | 1 1 1.830846 1.849246 3.263829 3.272351 39 | 2 0 0.828856 0.837186 0.952279 0.955576 40 | 2 0 0.850746 0.859297 0.960980 0.964409 41 | 2 0 0.865672 0.874372 0.966978 0.970500 42 | 2 0 0.880597 0.889447 0.973031 0.976646 43 | 2 0 0.896517 0.905528 0.979548 0.983266 44 | 2 0 0.995025 1.005025 1.021472 1.025905 45 | 2 0 1.004975 1.015075 1.025882 1.030397 46 | 2 0 1.014925 1.025126 1.030330 1.034928 47 | 2 0 1.297512 1.310553 1.178850 1.187118 48 | 2 0 1.377114 1.390955 1.232006 1.241952 49 | 2 0 1.439801 1.454271 1.278942 1.290504 50 | 2 0 1.512438 1.527638 1.340066 1.353895 51 | 2 0 1.598010 1.614070 1.423239 1.440390 52 | 2 0 1.769154 1.786935 1.635009 1.660786 53 | 2 0 1.830846 1.849246 1.727121 1.755854 54 | 2 0 1.899503 1.918593 1.835830 1.866214 55 | 2 0 2.030846 2.051256 2.027152 2.050687 56 | 2 0 2.230846 2.253266 2.187799 2.199662 57 | 2 0 2.396020 2.420100 2.264125 2.273685 58 | 2 0 2.596020 2.622111 2.336268 2.344661 59 | 2 0 3.146269 3.177889 2.480058 2.486617 60 | 2 0 3.553234 3.588945 2.554389 2.559997 61 | 2 0 3.986070 4.026131 2.614696 2.619537 62 | 2 0 4.457712 4.502512 2.665512 2.669721 63 | 2 0 5.595025 5.651257 2.749670 2.752877 64 | 2 0 6.633831 6.700502 2.799570 2.802209 65 | 2 0 6.648757 6.715578 2.800165 2.802799 66 | 2 0 7.653731 7.730653 2.834639 2.836888 67 | 2 0 9.950249 10.050251 2.886172 2.887858 68 | 2 0 12.437811 12.562814 2.919785 2.921110 69 | 2 1 0.828856 0.837186 1.532290 1.538793 70 | 2 1 0.850746 0.859297 1.549211 1.555675 71 | 2 1 0.865672 0.874372 1.560444 1.566882 72 | 2 1 0.880597 0.889447 1.571441 1.577855 73 | 2 1 0.896517 0.905528 1.582924 1.589315 74 | 2 1 0.995025 1.005025 1.649139 1.655469 75 | 2 1 1.004975 1.015075 1.655438 1.661771 76 | 2 1 1.014925 1.025126 1.661677 1.668015 77 | 2 1 1.297512 1.310553 1.823056 1.830063 78 | 2 1 1.377114 1.390955 1.865541 1.872869 79 | 2 1 1.439801 1.454271 1.898636 1.906247 80 | 2 1 1.512438 1.527638 1.936792 1.944772 81 | 2 1 1.598010 1.614070 1.981807 1.990303 82 | 2 1 1.769154 1.786935 2.074930 2.085213 83 | 2 1 1.830846 1.849246 2.111620 2.123250 84 | 2 1 1.899503 1.918593 2.157515 2.171819 85 | 2 1 2.030846 2.051256 2.279856 2.304925 86 | 2 1 2.230846 2.253266 2.562873 2.595322 87 | -------------------------------------------------------------------------------- /srfpython/Herrmann/src/max_iputmod.f90: -------------------------------------------------------------------------------- 1 | !*==PUTMOD.spg processed by SPAG 6.72Dc at 15:07 on 5 Dec 2017 2 | SUBROUTINE PUTMOD(Wlun,Mname,Mmax,Title,Iunit,Iiso,Iflsph,Idimen, & 3 | & Icnvel,Lverby) 4 | !----- 5 | ! CHANGES 6 | ! 03 MAY 2002 permit write to standard output 7 | !----- 8 | ! General purpose model input 9 | ! This model specification is designed to be as 10 | ! general as possible 11 | ! 12 | ! Input lines 13 | ! Line 01: MODEL 14 | ! Line 02: Model Name 15 | ! Line 03: ISOTROPIC or ANISOTROPIC or 16 | ! TRANSVERSELY ANISOTROPIC 17 | ! Line 04: Model Units, First character is length (k for kilometer 18 | ! second is mass (g for gm/cc), third is time (s for time) 19 | ! Line 05: FLAT EARTH or SPHERICAL EARTH 20 | ! Line 06: 1-D, 2-D or 3-D 21 | ! Line 07: CONSTANT VELOCITY 22 | ! Line 08: open for future use 23 | ! Line 09: open for future use 24 | ! Line 10: open for future use 25 | ! Line 11: open for future use 26 | ! Lines 12-end: These are specific to the model 27 | ! For ISOTROPIC the entries are 28 | ! Layer Thickness, P-velocity, S-velocity, Density, Qp, Qs, 29 | ! Eta-P, Eta S (Eta is frequency dependence), 30 | ! FreqRefP, FreqRefP 31 | !----- 32 | !MODEL 33 | !TEST MODEL.01 34 | !ISOTROPIC 35 | !KGS 36 | !FLAT EARTH 37 | !1-D 38 | !CONSTANT VELOCITY 39 | !LINE08 40 | !LINE09 41 | !LINE10 42 | !LINE11 43 | ! H VP VS RHO QP QS ETAP ETAS REFP REFS 44 | !1.0 5.0 3.0 2.5 0.0 0.0 0.0 0.0 1.0 1.0 45 | !2.0 5.1 3.1 2.6 0.0 0.0 0.0 0.0 1.0 1.0 46 | !7.0 6.0 3.5 2.8 0.0 0.0 0.0 0.0 1.0 1.0 47 | !10.0 6.5 3.8 2.9 0.0 0.0 0.0 0.0 1.0 1.0 48 | !20.0 7.0 4.0 3.0 0.0 0.0 0.0 0.0 1.0 1.0 49 | !40.0 8.0 4.7 3.3 0.0 0.0 0.0 0.0 1.0 1.0 50 | !----- 51 | !----- 52 | ! wlun I*4 - logical unit for writing model file. This 53 | ! unit is released after the use of this routine 54 | ! mname C*(*) - model name 55 | ! mmax I*4 - number of layers in the model, last layer is 56 | ! halfspace 57 | ! title C*(*) - title of the model file 58 | ! iunit I*4 - 0 Kilometer, Gram, Sec 59 | ! iiso I*4 - 0 isotropic 60 | ! 1 transversely anisotropic 61 | ! 2 general anisotropic 62 | ! iflsph I*4 - 0 flat earth model 63 | ! 1 spherical earth model 64 | ! idimen I*4 - 1 1-D 65 | ! - 2 2-D 66 | ! - 3 3-D 67 | ! icnvel I*4 - 0 constant velocity 68 | ! 1 variable velocity 69 | ! lverby L - .false. quiet output 70 | !------ 71 | IMPLICIT NONE 72 | !*--PUTMOD72 73 | 74 | CHARACTER Mname*(*) 75 | CHARACTER Title*(*) 76 | INTEGER Wlun 77 | INTEGER*4 Mmax , Iunit , Iiso , Iflsph , Idimen , Icnvel 78 | LOGICAL Lverby 79 | !----- 80 | ! STDIN I*4 - logical unit for standard input 81 | ! STDOUT I*4 - logical unit for standard output 82 | !----- 83 | INTEGER lun 84 | INTEGER STDOUT , LER 85 | PARAMETER (STDOUT=6,LER=0) 86 | 87 | INTEGER NL 88 | PARAMETER (NL=200) 89 | COMMON /ISOMOD/ D(NL) , A(NL) , B(NL) , RHO(NL) , QA(NL) , QB(NL) & 90 | & , ETAp(NL) , ETAs(NL) , FREfp(NL) , FREfs(NL) 91 | REAL D , A , B , RHO , QA , QB , ETAp , ETAs , FREfp , FREfs 92 | COMMON /DEPREF/ REFdep 93 | REAL REFdep 94 | 95 | INTEGER LGSTR , lt 96 | INTEGER j 97 | REAL curdep , dout 98 | 99 | LOGICAL ext 100 | CHARACTER cmnt*110 101 | cmnt(1:11) = ' H(KM) ' 102 | cmnt(12:22) = ' VP(KM/S)' 103 | cmnt(23:33) = ' VS(KM/S)' 104 | cmnt(34:44) = ' RHO(GM/CC)' 105 | cmnt(45:55) = ' QP ' 106 | cmnt(56:66) = ' QS ' 107 | cmnt(67:77) = ' ETAP ' 108 | cmnt(78:88) = ' ETAS ' 109 | cmnt(89:99) = ' FREFP ' 110 | cmnt(100:110) = ' FREFS ' 111 | 112 | lt = LGSTR(Title) 113 | !----- 114 | ! test to see if the file exists 115 | !----- 116 | IF ( Mname(1:6) == 'stdout' .OR. Mname(1:6) == 'STDOUT' ) THEN 117 | !----- 118 | ! do not open anything, use standard output 119 | !----- 120 | lun = STDOUT 121 | ELSE 122 | INQUIRE (FILE=Mname,EXIST=ext) 123 | IF ( ext .AND. Lverby ) WRITE (LER,*) & 124 | &'Overwriting Existing model File' 125 | lun = Wlun 126 | !----- 127 | ! open the file 128 | !----- 129 | OPEN (lun,FILE=Mname,STATUS='unknown',FORM='formatted', & 130 | &ACCESS='sequential') 131 | REWIND lun 132 | ENDIF 133 | !----- 134 | ! verify the file type 135 | !----- 136 | !----- 137 | ! LINE 01 138 | !----- 139 | WRITE (lun,'(a)') 'MODEL.01' 140 | !----- 141 | ! LINE 02 142 | !----- 143 | WRITE (lun,'(a)') Title(1:lt) 144 | !----- 145 | ! LINE 03 146 | !----- 147 | IF ( Iiso == 0 ) THEN 148 | WRITE (lun,'(a)') 'ISOTROPIC' 149 | ELSEIF ( Iiso == 1 ) THEN 150 | WRITE (lun,'(a)') 'TRANSVERSE ANISOTROPIC' 151 | ELSEIF ( Iiso == 2 ) THEN 152 | WRITE (lun,'(a)') 'ANISOTROPIC' 153 | ENDIF 154 | !----- 155 | ! LINE 04 156 | !----- 157 | WRITE (lun,'(a)') 'KGS' 158 | !----- 159 | ! LINE 05 160 | !----- 161 | IF ( Iflsph == 0 ) THEN 162 | WRITE (lun,'(a)') 'FLAT EARTH' 163 | ELSEIF ( Iflsph == 1 ) THEN 164 | WRITE (lun,'(a)') 'SPHERICAL EARTH' 165 | ENDIF 166 | !----- 167 | ! LINE 06 168 | !----- 169 | IF ( Idimen == 1 ) THEN 170 | WRITE (lun,'(a)') '1-D' 171 | ELSEIF ( Idimen == 2 ) THEN 172 | WRITE (lun,'(a)') '2-D' 173 | ELSEIF ( Idimen == 3 ) THEN 174 | WRITE (lun,'(a)') '3-D' 175 | ENDIF 176 | !----- 177 | ! LINE 07 178 | !----- 179 | IF ( Icnvel == 0 ) THEN 180 | WRITE (lun,'(a)') 'CONSTANT VELOCITY' 181 | ELSEIF ( Icnvel == 1 ) THEN 182 | WRITE (lun,'(a)') 'VARIABLE VELOCITY' 183 | ENDIF 184 | !----- 185 | ! put lines 8 through 11 186 | !----- 187 | WRITE (lun,'(a)') 'LINE08' 188 | WRITE (lun,'(a)') 'LINE09' 189 | WRITE (lun,'(a)') 'LINE10' 190 | WRITE (lun,'(a)') 'LINE11' 191 | !----- 192 | ! put model specifically for 1-D flat isotropic 193 | !----- 194 | !----- 195 | ! put comment line 196 | !----- 197 | WRITE (lun,'(a)') cmnt(1:110) 198 | curdep = 0.0 199 | 200 | DO j = 1 , Mmax 201 | curdep = curdep + ABS(D(j)) 202 | IF ( curdep.LE.REFdep ) THEN 203 | dout = -D(j) 204 | ELSE 205 | dout = D(j) 206 | ENDIF 207 | 208 | WRITE (lun,'(4f11.4,6g11.3)') dout , A(j) , B(j) , RHO(j) , & 209 | & QA(j) , QB(j) , ETAp(j) , ETAs(j)& 210 | & , FREfp(j) , FREfs(j) 211 | ENDDO 212 | IF ( lun /= STDOUT ) CLOSE (lun) 213 | END 214 | 215 | -------------------------------------------------------------------------------- /srfpython/Herrmann/src/max_lgstr.f90: -------------------------------------------------------------------------------- 1 | !*==LGSTR.spg processed by SPAG 6.72Dc at 15:08 on 5 Dec 2017 2 | FUNCTION LGSTR(Str) 3 | !----- 4 | ! function to find the length of a string 5 | ! this will only be used with file system path names 6 | ! thus the first blank 7 | ! indicates the end of the string 8 | !----- 9 | IMPLICIT NONE 10 | !*--LGSTR10 11 | CHARACTER*(*) Str 12 | INTEGER(kind=4) LGSTR 13 | INTEGER n , i 14 | n = LEN(Str) 15 | LGSTR = 1 16 | DO i = n , 1 , -1 17 | LGSTR = i 18 | IF ( Str(i:i)/=' ' ) GOTO 99999 19 | ENDDO 20 | 99999 END 21 | 22 | -------------------------------------------------------------------------------- /srfpython/Herrmann/src/max_setdsp.f90: -------------------------------------------------------------------------------- 1 | !*==SETDSP.spg processed by SPAG 6.72Dc at 15:08 on 5 Dec 2017 2 | SUBROUTINE SETDSP(Nmdisp) 3 | IMPLICIT NONE 4 | !*--SETDSP4 5 | !*** Start of declarations inserted by SPAG 6 | REAL dval , obserr , per , val 7 | INTEGER ilvry , imode , iporg , LIN , LOT 8 | !*** End of declarations inserted by SPAG 9 | !----- 10 | ! Changes 11 | ! 21 JUL 2002 - ensure proper format for GAMMA 12 | !----- 13 | ! interactively set up dispersion file 14 | !----- 15 | PARAMETER (LIN=5,LOT=6) 16 | CHARACTER Nmdisp*(*) 17 | CHARACTER*1 lorr(2) , porg(3) 18 | CHARACTER ostr*12 19 | DATA lorr/'L' , 'R'/ , porg/'C' , 'U' , 'G'/ 20 | 21 | WRITE (LOT,*) ' Interactively setting up dispersion file:' , & 22 | & Nmdisp 23 | !----- 24 | ! open file 25 | !----- 26 | OPEN (2,FILE=Nmdisp,STATUS='unknown',FORM='formatted', & 27 | &ACCESS='sequential') 28 | REWIND 2 29 | !----- 30 | ! NEW UNITS ARE ALWAYS km AND DATA IS ALWAYS PERIOD 31 | !----- 32 | ! prompt for dispersion information 33 | !----- 34 | WRITE (LOT,*) ' Enter ilvry,iporg,imode,per,val,dval' 35 | WRITE (LOT,*) ' ilvry=1(Love)' 36 | WRITE (LOT,*) ' =2(Rayleigh)' 37 | WRITE (LOT,*) ' iporg=1 (phase velocity km/s)' 38 | WRITE (LOT,*) ' =2 (group velocity km/s)' 39 | WRITE (LOT,*) ' =3 (gamma 1/km)' 40 | WRITE (LOT,*) ' imode (mode number) e.g., 0=fundamental, 1=first' 41 | WRITE (LOT,*) ' per=the period ' 42 | WRITE (LOT,*) ' val=dispersion value, velocity or gamma' 43 | WRITE (LOT,*) ' dval=error in dispersion value' 44 | WRITE (LOT,*) ' (Enter 1.0 if stderr from residuals)' 45 | WRITE (LOT,*) & 46 | &' NOTE: Enter all zeros or negative to terminate input' 47 | 100 READ (LIN,*,END=200,ERR=200) ilvry , iporg , imode , per , val , & 48 | & dval 49 | IF ( ilvry.GT.0 .AND. imode.GE.0 ) THEN 50 | ostr(1:7) = 'SURF96 ' 51 | ostr(8:8) = lorr(ilvry) 52 | ostr(9:9) = ' ' 53 | ostr(10:10) = porg(iporg) 54 | ostr(11:12) = ' X' 55 | obserr = 0.0 56 | IF ( iporg.EQ.1 .OR. iporg.EQ.2 ) THEN 57 | WRITE (2,'(a12,1x,i3,1x,3f11.4)') ostr , imode , per , val ,& 58 | & dval 59 | ELSEIF ( iporg.EQ.3 ) THEN 60 | WRITE (2,'(a12,1x,i3,1x,f11.4,2e11.3)') ostr , imode , per ,& 61 | & val , dval 62 | ENDIF 63 | GOTO 100 64 | ENDIF 65 | 200 CLOSE (2) 66 | END 67 | 68 | -------------------------------------------------------------------------------- /srfpython/Herrmann/src/max_setmod.f90: -------------------------------------------------------------------------------- 1 | !*==SETMOD.spg processed by SPAG 6.72Dc at 15:05 on 5 Dec 2017 2 | SUBROUTINE SETMOD(Nmmodl,Mmax) 3 | IMPLICIT NONE 4 | !*--SETMOD4 5 | !*** Start of declarations inserted by SPAG 6 | REAL A , B , D , DLAm , ETAp , ETAs , FREfp , FREfs , QA , QAQb , & 7 | & QB , REFdep , RHO , v1 , v2 , v3 , v4 , v5 , v6 8 | INTEGER icnvel , idimen , iflsph , iiso , INVdep , ITYpe , iunit ,& 9 | & LGSTR , LIN , LOT , lt , Mmax 10 | !*** End of declarations inserted by SPAG 11 | !----- 12 | ! COMMENTS 13 | ! 07 MAY 2002 - eliminated a write(2 to an unopened file 14 | !----- 15 | ! interactively set up model file 16 | !----- 17 | PARAMETER (LIN=5,LOT=6) 18 | COMMON /PARAM / QAQb , ITYpe , DLAm , INVdep 19 | CHARACTER Nmmodl*(*) 20 | 21 | COMMON /MODTIT/ TITle 22 | CHARACTER TITle*80 23 | INTEGER NL 24 | PARAMETER (NL=100) 25 | COMMON /ISOMOD/ D(NL) , A(NL) , B(NL) , RHO(NL) , QA(NL) , QB(NL) & 26 | & , ETAp(NL) , ETAs(NL) , FREfp(NL) , FREfs(NL) 27 | COMMON /DEPREF/ REFdep 28 | 29 | WRITE (LOT,*) ' Interactively setting up initial model file:' , & 30 | & Nmmodl 31 | !----- 32 | ! get model format 33 | !----- 34 | WRITE (LOT,*) 'Is model flat (0) or spherical (1)' 35 | READ (LIN,*) iflsph 36 | WRITE (LOT,*) 'Enter descriptive title for this model' 37 | READ (LIN,'(a)') TITle 38 | 39 | WRITE (LOT,*) ' Enter d,a,b,rho,qa,qb' 40 | WRITE (LOT,*) ' d=0.0 or EOF indicates halfspace ' , & 41 | &'and end of input' 42 | !----- 43 | ! get model data 44 | !----- 45 | Mmax = 0 46 | 100 READ (LIN,*,ERR=1000,END=200) v1 , v2 , v3 , v4 , v5 , v6 47 | WRITE (LOT,*) v1 , v2 , v3 , v4 , v5 , v6 48 | !----- 49 | ! safety check 50 | !----- 51 | IF ( v2.LT.v3 ) THEN 52 | WRITE (LOT,*) ' Error: P Velocity < S velocity:' , v2 , '<' , & 53 | & v3 54 | WRITE (LOT,*) ' Reenter this layer' 55 | GOTO 100 56 | ENDIF 57 | IF ( v4.LE.0.0 ) THEN 58 | WRITE (LOT,*) 'Error: Density <= 0:' , v4 59 | WRITE (LOT,*) ' Reenter this layer' 60 | GOTO 100 61 | ENDIF 62 | IF ( v5.LT.0.0 .OR. v6.LT.0.0 ) THEN 63 | WRITE (LOT,*) 'Error: qa or qb not >= 0' , v5 , v5 64 | WRITE (LOT,*) ' Reenter this layer' 65 | GOTO 100 66 | ENDIF 67 | Mmax = Mmax + 1 68 | D(Mmax) = v1 69 | A(Mmax) = v2 70 | B(Mmax) = v3 71 | RHO(Mmax) = v4 72 | IF ( v5.GT.1.0 ) v5 = 1.0/v5 73 | IF ( v6.GT.1.0 ) v6 = 1.0/v6 74 | QA(Mmax) = v5 75 | QB(Mmax) = v6 76 | ETAp(Mmax) = 0.0 77 | ETAs(Mmax) = 0.0 78 | FREfp(Mmax) = 1.0 79 | FREfs(Mmax) = 1.0 80 | 81 | IF ( v1.NE.0.0 ) GOTO 100 82 | 200 D(Mmax) = 0.0 83 | 84 | !----- 85 | ! lun I*4 - logical unit for writing model file. This 86 | ! unit is released after the use of this routine 87 | ! nmmodl C*(*) - model name 88 | ! mmax I*4 - number of layers in the model, last layer is 89 | ! halfspace 90 | ! title C*(*) - title of the model file 91 | ! iunit I*4 - 0 Kilometer, Gram, Sec 92 | ! iiso I*4 - 0 isotropic 93 | ! 1 transversely anisotropic 94 | ! 2 general anisotropic 95 | ! iflsph I*4 - 0 flat earth model 96 | ! 1 spherical earth model 97 | ! idimen I*4 - 1 1-D 98 | ! - 2 2-D 99 | ! - 3 3-D 100 | ! icnvel I*4 - 0 constant velocity 101 | ! 1 variable velocity 102 | !------ 103 | iunit = 0 104 | iiso = 0 105 | idimen = 1 106 | icnvel = 0 107 | lt = LGSTR(TITle) 108 | CALL PUTMOD(2,Nmmodl,Mmax,TITle(1:lt),iunit,iiso,iflsph,idimen, & 109 | & icnvel,.TRUE.) 110 | 1000 END 111 | 112 | -------------------------------------------------------------------------------- /srfpython/Herrmann/src/readme.txt: -------------------------------------------------------------------------------- 1 | converted to fortran90 using 2 | https://fortran.uk/plusfortonline.php 3 | -------------------------------------------------------------------------------- /srfpython/Herrmann/src/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #test the modified version of fortran programs max_srfpre96 and max_srfdis96 4 | 5 | 6 | rm -f in.txt out1.txt out2.txt 7 | 8 | # write input arguments to pass to srf_pre96 through stdin 9 | cat << END > in1.txt 10 | 2 2 2 2 11 | SURF96 L C T 0 7.692308 3.152852 0.1 12 | SURF96 L C T 0 4.479947 2.655829 0.1 13 | SURF96 L C T 0 2.609090 1.524800 0.1 14 | SURF96 L C T 0 1.519516 1.129654 0.1 15 | SURF96 L C T 0 0.884956 0.983793 0.1 16 | SURF96 L C T 1 1.605682 3.069108 0.1 17 | SURF96 L C T 1 0.900901 1.713844 0.1 18 | SURF96 L U T 0 12.500000 3.148224 0.1 19 | SURF96 L U T 0 6.681531 2.618293 0.1 20 | SURF96 L U T 0 3.571429 0.983935 0.1 21 | SURF96 L U T 0 1.909009 0.831358 0.1 22 | SURF96 L U T 0 1.020408 0.832491 0.1 23 | SURF96 L U T 1 1.839556 2.590743 0.1 24 | SURF96 L U T 1 1.010101 0.977466 0.1 25 | SURF96 R C T 0 6.666667 2.800877 0.1 26 | SURF96 R C T 0 4.006426 2.617169 0.1 27 | SURF96 R C T 0 2.407717 2.268805 0.1 28 | SURF96 R C T 0 1.446951 1.284619 0.1 29 | SURF96 R C T 0 0.869565 0.968552 0.1 30 | SURF96 R C T 1 2.242243 2.193912 0.1 31 | SURF96 R C T 1 1.384358 1.237185 0.1 32 | SURF96 R C T 1 0.854701 0.962565 0.1 33 | SURF96 R U T 0 10.000000 2.727757 0.1 34 | SURF96 R U T 0 5.623413 2.463522 0.1 35 | SURF96 R U T 0 3.162278 1.964674 0.1 36 | SURF96 R U T 0 1.778279 0.642590 0.1 37 | SURF96 R U T 0 1.000000 0.714381 0.1 38 | SURF96 R U T 1 2.041241 0.947028 0.1 39 | SURF96 R U T 1 1.304237 0.696091 0.1 40 | SURF96 R U T 1 0.833333 0.708612 0.1 41 | END 42 | 43 | # call max_srfpre96, save outputs to be compared with expected ones 44 | ../bin/max_srfpre96 < in1.txt > out1.txt 45 | 46 | # write input arguments to be passed to max_srfdis96, save outputs ... 47 | cat << END > in2.txt 48 | 8 49 | 0.250 0.200 0.200 0.200 0.200 0.480 0.270 50 | 1.850 2.360 2.630 3.150 3.710 4.540 5.480 5.800 51 | 0.860 1.100 1.240 1.470 1.730 2.130 3.130 3.310 52 | 2.470 2.470 2.470 2.470 2.470 2.580 2.580 2.630 53 | 0.005 0.005 54 | END 55 | cat out1.txt >> in2.txt 56 | 57 | ../bin/max_srfdis96 < in2.txt > out2.txt 58 | 59 | # compare output with expectations 60 | if cmp --silent out1.txt expected1.txt; then 61 | echo "test1 ok" 62 | else 63 | echo "error : the output from max_srfpre96 (out1.txt) differs from expected1.txt" \ 64 | exit 1; 65 | fi 66 | 67 | if cmp --silent out2.txt expected2.txt; then 68 | echo "test2 ok" 69 | else 70 | echo "error : the output from max_srfdis96 (out2.txt) differs from expected2.txt"; \ 71 | exit 1; 72 | fi 73 | 74 | rm -f in.txt out1.txt out2.txt 75 | exit 0; 76 | -------------------------------------------------------------------------------- /srfpython/__init__.py: -------------------------------------------------------------------------------- 1 | from srfpython.Herrmann.Herrmann import check_herrmann_codes, recompile_src, HerrmannCaller, Curve 2 | from srfpython.depthdisp.depthmodels import depthmodel1D, depthmodel, depthmodel_from_mod96string, \ 3 | depthmodel_from_mod96, depthmodel_from_arrays, depthspace, gardner74, brocher2005 4 | from srfpython.depthdisp.dispcurves import Claw, Ulaw, freqspace, \ 5 | surf96reader, surf96reader_from_surf96string, surf96reader_from_arrays 6 | from srfpython.inversion.metropolis2 import metropolis 7 | from srfpython.utils import Timer 8 | from srfpython.standalone.display import plt, gcf, gca, pause, showme, logtick 9 | from srfpython.standalone.asciifile import AsciiFile 10 | from srfpython.synthetics.synthetics2 import Green 11 | import numpy as np 12 | import sys, glob, os 13 | -------------------------------------------------------------------------------- /srfpython/bin/HerrMet: -------------------------------------------------------------------------------- 1 | ../HerrMet/HerrMet.py -------------------------------------------------------------------------------- /srfpython/bin/m96: -------------------------------------------------------------------------------- 1 | ../depthdisp/m96.py -------------------------------------------------------------------------------- /srfpython/bin/quickdisp.py: -------------------------------------------------------------------------------- 1 | ../Herrmann/quickdisp.py -------------------------------------------------------------------------------- /srfpython/bin/s96: -------------------------------------------------------------------------------- 1 | ../depthdisp/s96.py -------------------------------------------------------------------------------- /srfpython/bin/sker17: -------------------------------------------------------------------------------- 1 | ../sensitivitykernels/sker17.py -------------------------------------------------------------------------------- /srfpython/bin/srfpython_tester.py: -------------------------------------------------------------------------------- 1 | ../Herrmann/Herrmann.py -------------------------------------------------------------------------------- /srfpython/coordinates.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def haversine(loni, lati, lonj, latj, R=6371.): 5 | """ 6 | Calculate the great circle distance between two points 7 | on the earth (specified in decimal degrees) 8 | source https://stackoverflow.com/questions/15736995/how-can-i-quickly-estimate-the-distance-between-two-latitude-longitude-points 9 | lone, late : coordinates of the first point, in degrees 10 | lons, lats : coordinates of the second point, in degrees 11 | :return distance in km 12 | 13 | consistent with Ll2DGAB 14 | """ 15 | # convert decimal degrees to radians 16 | q = np.pi / 180. 17 | 18 | # haversine formula 19 | dlon = (loni - lonj) 20 | dlat = (lati - latj) 21 | a = np.sin(q * dlat / 2.) ** 2. + np.cos(q * latj) * np.cos(q * lati) * np.sin(q * dlon / 2.) ** 2. 22 | c = 2. * np.arcsin(np.sqrt(a)) 23 | km = R * c 24 | return km -------------------------------------------------------------------------------- /srfpython/depthdisp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obsmax/srfpython/4e3c4e0effca909174b824d0608cee1371404f0e/srfpython/depthdisp/__init__.py -------------------------------------------------------------------------------- /srfpython/depthdisp/disppdfs.py: -------------------------------------------------------------------------------- 1 | from srfpython.utils import discrete_time_primitive 2 | from srfpython.depthdisp.dispcurves import surf96reader, groupbywtm 3 | import numpy as np 4 | 5 | 6 | # ---------------------------------------------------- 7 | class disppdf(object): 8 | #2D histogram for dipsersion curves, see also depthmodels.depthpdf, depthmodels.depthpdf2disppdf 9 | def __init__(self, f, v): 10 | assert np.all(f[1:] > f[:-1]) 11 | assert np.all(v[1:] > v[:-1]) 12 | self.f = f 13 | self.v = v 14 | self.H = np.zeros((len(v), len(f)), float) 15 | 16 | # ------------------------------------------------ 17 | # def write(self, filename): 18 | # assert filename.split('.')[-1] == "dpdf" 19 | # pkl((self.f, self.v, self.H), filename) 20 | 21 | # ------------------------------------------------ 22 | def append(self, law): 23 | self.appendN(law, Ntimes = 1) 24 | 25 | # ------------------------------------------------ 26 | def appendN(self, law, Ntimes=1): 27 | """append the same model Ntimes times in the histogram""" 28 | v = law(self.f) 29 | for i in range(len(self.f)): 30 | if np.isnan(v[i]):continue 31 | j = np.clip(np.searchsorted(self.v, v[i]), 0, len(self.v) - 1) 32 | self.H[j, i] += float(Ntimes) 33 | # if 0 <= j < len(self.v): 34 | # self.H[j, i] += float(Ntimes) 35 | 36 | # ------------------------------------------------ 37 | def appenddat(self, f, v): 38 | self.appenddatN(f, v, Ntimes = 1) 39 | 40 | # ------------------------------------------------ 41 | def appenddatN(self, f, v, Ntimes=1): 42 | if (f != self.f).any(): 43 | v = np.interp(self.f, xp = f, fp = v, left = np.nan, right = np.nan) 44 | for i in range(len(self.f)): 45 | if np.isnan(v[i]):continue 46 | j = np.clip(np.searchsorted(self.v, v[i]), 0, len(self.v) - 1) 47 | self.H[j, i] += float(Ntimes) 48 | 49 | # ------------------------------------------------ 50 | def show(self, ax, norm=True, **kwargs): 51 | H = np.ma.masked_where(self.H == 0., self.H) 52 | if norm: 53 | I = np.zeros(len(self.f)) 54 | for i in range(len(self.f)): 55 | I[i] = discrete_time_primitive(self.v, self.H[:, i], area = True) 56 | I = discrete_time_primitive(self.f, I, area = True) 57 | H /= I 58 | coll, cax = ax.pcolormesh1(1. / self.f, self.v, H, **kwargs) 59 | ax.set_xscale('log') 60 | ax.set_yscale('log') 61 | return coll, cax 62 | 63 | # ------------------------------------------------ 64 | def purcentile(self, p): 65 | assert 0. <= p <= 1. 66 | P = np.zeros_like(self.f) * np.nan 67 | for j, f in enumerate(self.f): 68 | x = self.v 69 | y = np.cumsum(self.H[:, j]) 70 | ymin, ymax = y.min(), y.max() 71 | if ymax > ymin: 72 | y = (y - y.min()) / (y.max() - y.min()) 73 | P[j] = np.interp(p, xp = y, fp = x) 74 | I = ~np.isnan(P) 75 | return self.f[I], P[I] 76 | 77 | # ------------------------------------------------ 78 | def percentile(self, p, return_count=False): 79 | assert 0. <= p <= 1. 80 | v_percentile = np.zeros_like(self.f) * np.nan 81 | 82 | count = np.asarray(np.sum(self.H, axis=0), int) 83 | for j, f in enumerate(self.f): 84 | x = self.v 85 | y = np.cumsum(self.H[:, j]) 86 | ymin, ymax = y.min(), y.max() 87 | if ymax > ymin: 88 | y = (y - y.min()) / (y.max() - y.min()) 89 | v_percentile[j] = np.interp(p, xp = y, fp = x) 90 | 91 | I = ~np.isnan(v_percentile) 92 | if return_count: 93 | return self.f[I], v_percentile[I], count[I] 94 | return self.f[I], v_percentile[I] 95 | 96 | # ------------------------------------------------ 97 | def dispstats(ds, percentiles=[0.16, 0.5, 0.84], Ndisp=200, weights=None, **mapkwargs): 98 | """ 99 | compute statistics on a set of dispersion curves 100 | :param ds: 101 | :param percentiles: 102 | :param Ndisp: 103 | :param weights: 104 | :param mapkwargs: 105 | :return: 106 | """ 107 | assert np.all([0 < p < 1 for p in percentiles]) 108 | assert len(percentiles) == len(np.unique(percentiles)) 109 | if weights is None: 110 | weights = np.ones(len(ds)) 111 | else: 112 | assert len(weights) == len(ds) 113 | 114 | # initiate the depthpdfs 115 | waves, types, modes, freqs, values = ds[0] 116 | 117 | dpdfs = {} 118 | for w, t, m, f, _ in groupbywtm(waves, types, modes, freqs, values): 119 | dpdfs["%s%s%d" % (w, t, m)] = disppdf(f, np.logspace(np.log10(0.08), np.log10(6.0), Ndisp)) 120 | 121 | for weight, (waves, types, modes, freqs, values) in zip(weights, ds): 122 | for w, t, m, f, v in groupbywtm(waves, types, modes, freqs, values): 123 | dpdfs["%s%s%d" % (w, t, m)].appenddatN(f, v, Ntimes=weight) 124 | 125 | for w, t, m, _, _ in groupbywtm(waves, types, modes, freqs, values): 126 | for p in percentiles: 127 | fpc, vpc = dpdfs["%s%s%d" % (w, t, m)].purcentile(p) 128 | wavespc = np.array([w for _ in range(len(fpc))], "|U1") 129 | typespc = np.array([t for _ in range(len(fpc))], "|U1") 130 | modespc = np.array([m for _ in range(len(fpc))], int) 131 | yield p, (wavespc, typespc, modespc, fpc, vpc) 132 | 133 | -------------------------------------------------------------------------------- /srfpython/depthdisp/m96.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | help = '''m96 4 | --show list of mod96 files to display (same plot) 5 | --disp name of mod96 file to use as input 6 | -RU0 rayleigh, group, mode 0 : expects 4 frequency arguments : fstart, fend, nfreq, fscale 7 | -RU1 rayleigh, group, mode 1 : expects 4 frequency arguments : fstart, fend, nfreq, fscale 8 | -RC0 rayleigh, phase, mode 0 : expects 4 frequency arguments : fstart, fend, nfreq, fscale 9 | -LC0 love, phase, mode 0 : expects 4 frequency arguments : fstart, fend, nfreq, fscale 10 | ... 11 | -save name of surf96file to write 12 | --split 13 | -thck thickness of the sublayers in km 14 | -sfx suffix to add before file extension (default split) 15 | -o ignore suffix and overwrite input file 16 | --addlayer 17 | -thck thickness of the sublayers in km 18 | -sfx suffix to add before file extension (default split) 19 | -o ignore suffix and overwrite input file 20 | -inline replace showme by plt.show (e.g. for jupyter) 21 | ''' 22 | 23 | # --------------------------------------------- 24 | if __name__ == "__main__": 25 | import sys, os 26 | if len(sys.argv) == 1: 27 | print(help) 28 | sys.exit() 29 | 30 | from srfpython.standalone.display import gcf, gca, showme, pause, plt, logtick 31 | from srfpython.utils import readargv 32 | from srfpython.depthdisp.dispcurves import surf96reader, Claw, freqspace 33 | from srfpython.depthdisp.depthmodels import depthmodel_from_mod96 34 | 35 | 36 | import numpy as np 37 | argv = readargv() 38 | 39 | # ----------------------------------- 40 | if "inline" in argv.keys(): 41 | showme = plt.show 42 | 43 | # ----------------------------------- 44 | if "help" in argv.keys() or "h" in argv.keys(): 45 | print(help) 46 | sys.exit() 47 | 48 | # ----------------------------------- 49 | elif "split" in argv.keys(): 50 | thickness = argv['thck'][0] 51 | suffix = argv['sfx'][0] if "sfx" in argv.keys() else "split" 52 | 53 | for f in argv['split']: 54 | dm = depthmodel_from_mod96(f) 55 | dm.split(thickness) 56 | if "o" in argv.keys(): 57 | fout = f 58 | else: 59 | fout = f.split('.')[:-1] + [suffix, f.split('.')[-1]] 60 | 61 | fout = ".".join(fout) 62 | assert not os.path.exists(fout) 63 | print(f, ">", fout) 64 | dm.write96(fout) 65 | sys.exit() 66 | 67 | # ----------------------------------- 68 | elif "addlayer" in argv.keys(): 69 | thickness = argv['thck'][0] 70 | suffix = argv['sfx'][0] if "sfx" in argv.keys() else "add" 71 | for f in argv['addlayer']: 72 | dm = depthmodel_from_mod96(f) 73 | dm.add_layer(thickness) 74 | if "o" in argv.keys(): 75 | fout = f 76 | else: 77 | fout = f.split('.')[:-1] + [suffix, f.split('.')[-1]] 78 | fout = ".".join(fout) 79 | assert not os.path.exists(fout) 80 | print(f, ">", fout) 81 | dm.write96(fout) 82 | sys.exit() 83 | 84 | # ----------------------------------- 85 | elif "show" in argv.keys(): 86 | axvp = gcf().add_subplot(1, 4, 1) 87 | axvs = gcf().add_subplot(1, 4, 2, sharey = axvp) 88 | axpr = gcf().add_subplot(1, 4, 3, sharey = axvp) 89 | axrh = gcf().add_subplot(1, 4, 4, sharey = axvp) 90 | for f in argv['show']: 91 | dm = depthmodel_from_mod96(f) 92 | print(f) 93 | 94 | dm.vp.show(axvp, ".-") 95 | dm.vs.show(axvs, ".-") 96 | dm.pr().show(axpr, ".-") 97 | dm.rh.show(axrh, ".-") 98 | 99 | if "gardner74" in argv.keys(): 100 | rh = dm.rh.copy() 101 | rh.values = 1.74 * dm.vp.values ** 0.25 102 | rh.show(axrh) 103 | 104 | showme() 105 | sys.exit() 106 | 107 | # ----------------------------------- 108 | elif "disp" in argv.keys(): 109 | from srfpython.Herrmann.Herrmann import HerrmannCaller, Curve 110 | 111 | for m in argv['disp']: 112 | dm = depthmodel_from_mod96(m) 113 | ztop = dm.vp.ztop() 114 | vp = dm.vp.values 115 | vs = dm.vs.values 116 | rh = dm.rh.values 117 | 118 | #Waves, Types, Modes, Freqs = [], [], [], [] 119 | curves = [] 120 | for k in argv.keys(): 121 | if k[0].upper() in "RL" and k[1].upper() in "UC" and k[2] in "0123456789": 122 | fstart, fend, nfreq, fspace = argv[k] 123 | freqs = freqspace(float(fstart), float(fend), int(nfreq), fspace) 124 | curve = Curve( 125 | wave=k[0], # Waves.append(k[0]) 126 | type=k[1], # Types.append(k[1]) 127 | mode=int(k[2:]), # Modes.append(int(k[2:])) 128 | freqs=freqs) # Freqs.append(freq) 129 | curves.append(curve) 130 | hc = HerrmannCaller(curves=curves) 131 | curves = hc(ztop, vp, vs, rh) 132 | 133 | if "save" in argv.keys(): 134 | sfx = "" 135 | s96out = ".".join(m.split('/')[-1].split('.')[:-1]) + sfx + ".surf96" 136 | while os.path.exists(s96out): 137 | s96out = s96out.split(sfx + '.surf96')[0] 138 | if sfx == "": 139 | sfx = "_1" 140 | else: 141 | sfx = "_%d" % (int(sfx.strip("_")) + 1) 142 | s96out = s96out + sfx + ".surf96" 143 | 144 | print("%s => %s" % (m, s96out)) 145 | 146 | assert s96out.endswith('.surf96') or s96out.endswith('.s96') 147 | 148 | with open(s96out, 'w') as fid: 149 | for curve in curves: 150 | fid.write(str(curve)) 151 | 152 | else: 153 | axvp = gcf().add_subplot(1, 5, 1) 154 | axvs = gcf().add_subplot(1, 5, 2, sharey=axvp) 155 | axpr = gcf().add_subplot(1, 5, 3, sharey=axvp) 156 | axrh = gcf().add_subplot(1, 5, 4, sharey=axvp) 157 | axdsp = gcf().add_subplot(2, 5, 5) 158 | dm.vp.show(axvp) 159 | dm.vs.show(axvs) 160 | dm.pr().show(axpr) 161 | dm.rh.show(axrh) 162 | 163 | for curve in curves: 164 | #for w, t, m, F, V in dispersion_1(ztop, vp, vs, rh, Waves, Types, Modes, Freqs): 165 | axdsp.loglog(1. / curve.freqs, curve.values, label="%s%s%d" % (curve.wave, curve.type, curve.mode)) 166 | 167 | if "save" not in argv.keys(): 168 | logtick(axdsp, "xy") 169 | # plt.legend() 170 | showme() 171 | sys.exit() 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /srfpython/depthdisp/mod96.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class BadFileFormat(Exception): 5 | pass 6 | 7 | 8 | def unpackmod96(string): 9 | """unpack 1D deptmodel depthdisp at mod96 format (see Herrmann's doc) 10 | """ 11 | if not isinstance(string, str): 12 | raise TypeError(type(string)) 13 | 14 | string = [line.strip() for line in string.split('\n')] 15 | 16 | # remove blank lines 17 | # string.remove('') #fucking not working all the time 18 | I = [_ != '' for _ in string] 19 | string = [string[i] for i in np.arange(len(string))[I]] 20 | 21 | # make sure the header is correctly formated 22 | # title = string[1].strip() 23 | error_message = 'header does not correspond to a mod96 file \n{}'.format("\n".join(string)) 24 | if not string[0] == "MODEL.01": 25 | raise BadFileFormat(error_message) 26 | if not string[2].upper() == "ISOTROPIC": 27 | raise BadFileFormat(error_message) 28 | if not string[3].upper() == "KGS": 29 | raise BadFileFormat(error_message) 30 | if not string[4].upper() == "FLAT EARTH": 31 | raise BadFileFormat(error_message) 32 | if not string[5].upper() == "1-D": 33 | raise BadFileFormat(error_message) 34 | if not string[6].upper() == "CONSTANT VELOCITY": 35 | raise BadFileFormat(error_message) 36 | if not string[7] == "LINE08": 37 | raise BadFileFormat(error_message) 38 | if not string[8] == "LINE09": 39 | raise BadFileFormat(error_message) 40 | if not string[9] == "LINE10": 41 | raise BadFileFormat(error_message) 42 | if not string[10] == "LINE11": 43 | raise BadFileFormat(error_message) 44 | if not string[11].startswith("H(KM)"): 45 | raise BadFileFormat(error_message) 46 | 47 | nlayer = len(string) - 12 48 | #H, VP, VS, RHO, QP, QS, ETAP, ETAS, FREFP, FREFS = [np.empty(nlayer, float) for _ in range(10)] 49 | DAT = np.zeros((nlayer, 10), float) 50 | 51 | for n in range(nlayer): 52 | DAT[n, :] = np.asarray(string[12 + n].split(), float) 53 | 54 | H, VP, VS, RHO, QP, QS, ETAP, ETAS, FREFP, FREFS = [DAT[:, j] for j in range(10)] 55 | 56 | assert not H[-1] 57 | assert H[:-1].all() 58 | Z = np.concatenate(([0.], H[:-1].cumsum())) 59 | return nlayer, Z, H, VP, VS, RHO, QP, QS, ETAP, ETAS, FREFP, FREFS 60 | 61 | 62 | def readmod96(filename): 63 | """read 1D deptmodel depthdisp at mod96 format (see Herrmann's doc)""" 64 | with open(filename, 'r') as fid: 65 | L = fid.readlines() 66 | return unpackmod96("".join(L)) 67 | 68 | 69 | def packmod96(Z, VP, VS, RHO, QP=None, QS=None, ETAP=None, ETAS=None, FREFP=None, FREFS=None): 70 | if QP is None: QP = np.zeros_like(VS) 71 | if QS is None: QS = np.zeros_like(VS) 72 | if ETAP is None: ETAP = np.zeros_like(VS) 73 | if ETAS is None: ETAS = np.zeros_like(VS) 74 | if FREFP is None: FREFP = np.ones_like(VS) 75 | if FREFS is None: FREFS = np.ones_like(VS) 76 | strout="""MODEL.01 77 | MODELTITLE 78 | ISOTROPIC 79 | KGS 80 | FLAT EARTH 81 | 1-D 82 | CONSTANT VELOCITY 83 | LINE08 84 | LINE09 85 | LINE10 86 | LINE11 87 | H(KM) VP(KM/S) VS(KM/S) RHO(GM/CC) QP QS ETAP ETAS FREFP FREFS 88 | """ 89 | fmt = "%.12f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f\n" 90 | 91 | H = np.zeros_like(Z) 92 | H[:-1] = Z[1:] - Z[:-1] 93 | H[-1] = 0. 94 | 95 | for tup in zip(H, VP, VS, RHO, QP, QS, ETAP, ETAS, FREFP, FREFS): 96 | strout += fmt % tup 97 | return strout 98 | -------------------------------------------------------------------------------- /srfpython/depthdisp/parametricdispcurves.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from matplotlib import ticker 3 | 4 | 5 | """ 6 | create a arctan-shaped phase dispersion curve in the log(p) - log(c) domain with 4 parameters 7 | """ 8 | 9 | def btan(x): 10 | return np.arctan(x) / np.pi + 1./2. 11 | 12 | class PhaseDispersionLaw(object): 13 | def __init__(self, cmin=2., cmax=3.0, power=1.0, pmid=1.0): 14 | """ 15 | :param cmin: lower phase velocity km/s 16 | :param cmax: upper phase velocity km/s 17 | :param power: sharpness of the dispersion curve at pmid 18 | :param pmid: inflection period (s) 19 | """ 20 | self.cmin = cmin 21 | self.cmax = cmax 22 | self.power = power 23 | self.pmid = pmid 24 | 25 | self.offset = np.log(cmin) 26 | self.gain = np.log(cmax / cmin) 27 | self.power = power 28 | self.inflection=np.log(pmid) 29 | self.eps = 1.e-20 30 | 31 | def __call__(self, freq): 32 | """ 33 | evaluate the phase dispersion law at freq (array, Hz) 34 | """ 35 | logp = np.log(1. / (np.abs(freq) + self.eps)) 36 | logc = self.offset + self.gain * btan(self.power * (logp - self.inflection)) 37 | return np.exp(logc) 38 | 39 | def tester(self, freq): 40 | fmid = 1. / self.pmid 41 | return self.cmin * (self.cmax / self.cmin) ** \ 42 | (.5 + np.arctan(self.power * np.log(fmid / (np.abs(freq) + self.eps))) / np.pi) 43 | 44 | def show(self, ax, freqmin, freqmax, **kwargs): 45 | f = np.logspace(np.log10(freqmin), np.log10(freqmax), 100) 46 | ax.loglog(1. / f, self(f), **kwargs) 47 | 48 | for axis in [ax.xaxis, ax.yaxis]: 49 | axis.set_major_locator(ticker.LogLocator(base = 10., subs=[1., 2., 3., 5.])) 50 | axis.set_minor_locator(ticker.NullLocator()) 51 | axis.set_major_formatter(ticker.StrMethodFormatter('{x}')) 52 | ax.set_xlabel('period (s)') 53 | ax.set_ylabel('velocity (km/s)') 54 | 55 | 56 | class GroupDispersionLaw(PhaseDispersionLaw): 57 | def __init__(self, phasedispersionlaw): 58 | self.pdl = phasedispersionlaw 59 | self.df = 0.01 60 | 61 | def __call__(self, freq): 62 | return self.pdl(freq) / (1. - (np.log(self.pdl(freq+self.df) / self.pdl(freq)) / np.log((freq+self.df)/freq))) 63 | 64 | 65 | if __name__ == '__main__': 66 | import matplotlib.pyplot as plt 67 | c = PhaseDispersionLaw(cmin=2.25, cmax=3.52, power=1.0, pmid=4.0) 68 | u = GroupDispersionLaw(c) 69 | 70 | f = np.logspace(-1., 1., 100, 'plog') 71 | plt.gca().plot(1./f, c(f)) 72 | plt.gca().plot(1./f, c.tester(f)) 73 | plt.show() -------------------------------------------------------------------------------- /srfpython/depthdisp/parametricdispcurves1.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from matplotlib import ticker 3 | 4 | 5 | """ 6 | create a arctan-shaped phase dispersion curve in the log(p) - log(c) domain with 4 parameters 7 | """ 8 | 9 | def btan(x): 10 | return np.arctan(x) / np.pi + 1./2. 11 | 12 | class PhaseDispersionLaw(object): 13 | def __init__(self, cmin=2., cmax=3.0, sharpness=1.0, fmid=1.0): 14 | """ 15 | :param cmin: lower phase velocity km/s 16 | :param cmax: upper phase velocity km/s 17 | :param sharpness: sharpness of the dispersion curve at fmid 18 | :param fmid: inflection frequency (Hz) 19 | """ 20 | self.cmin = cmin 21 | self.cmax = cmax 22 | self.sharpness = sharpness 23 | self.fmid = fmid 24 | self.eps = 1.e-20 25 | 26 | def __call__(self, freq): 27 | """ 28 | evaluate the phase dispersion law at freq (array, Hz) 29 | """ 30 | #return self.cmin * (self.cmax / self.cmin) ** (.5 + np.arctan(self.sharpness * np.log(self.fmid / (np.abs(freq) + self.eps))) / np.pi) 31 | return np.exp(np.log(self.cmin) + np.log(self.cmax / self.cmin) * (btan(self.sharpness * (np.log(self.fmid / (np.abs(freq) + self.eps)))))) 32 | 33 | def expr1(self): 34 | fmt = r"$c(f) = exp \left( ln%s + ln \frac{%s}{%s} \left( { \frac{1}{2} + \frac{1}{\pi} atan\left(%s ln \frac{%s}{|f|}\right) } \right) \right)$" 35 | return fmt % ("{}".format(self.cmin), 36 | "{}".format(self.cmax), 37 | "{}".format(self.cmin), 38 | "{}".format(self.sharpness) if self.sharpness != 1.0 else "", 39 | "{}".format(self.fmid)) 40 | 41 | def expr2(self): 42 | fmt = r"$c(f) = %s \left( \frac{%s}{%s} \right) ^{ \frac{1}{2} + \frac{1}{\pi} atan(%s ln \frac{%s}{|f|}) } $" 43 | return fmt % ("{}".format(self.cmin), 44 | "{}".format(self.cmax), 45 | "{}".format(self.cmin), 46 | "{}".format(self.sharpness) if self.sharpness != 1.0 else "", 47 | "{}".format(self.fmid)) 48 | 49 | def show(self, ax, freqmin, freqmax, **kwargs): 50 | f = np.logspace(np.log10(freqmin), np.log10(freqmax), 100) 51 | ax.loglog(1. / f, self(f), **kwargs) 52 | 53 | for axis in [ax.xaxis, ax.yaxis]: 54 | axis.set_major_locator(ticker.LogLocator(base = 10., subs=[1., 2., 3., 5.])) 55 | axis.set_minor_locator(ticker.NullLocator()) 56 | axis.set_major_formatter(ticker.StrMethodFormatter('{x}')) 57 | ax.set_xlabel('period (s)') 58 | ax.set_ylabel('velocity (km/s)') 59 | 60 | def to_ulaw(self): 61 | return GroupDispersionLaw(self) 62 | 63 | class GroupDispersionLaw(PhaseDispersionLaw): 64 | def __init__(self, phasedispersionlaw): 65 | self.pdl = phasedispersionlaw 66 | self.df = 0.01 67 | 68 | def expr1(self): 69 | fmt = r"$ u(f) = c(f) / (1. - \frac{ln\,c(f+ \delta f) - ln\,c(f)}{ln(f+\delta f)-ln(f)})$" 70 | return fmt 71 | 72 | def __call__(self, freq): 73 | return self.pdl(freq) / (1. - (np.log(self.pdl(freq+self.df) / self.pdl(freq)) / np.log((freq+self.df)/freq))) 74 | 75 | 76 | if __name__ == '__main__': 77 | import matplotlib.pyplot as plt 78 | c = PhaseDispersionLaw(cmin=2.25, cmax=3.52, sharpness=1.1, fmid=0.25) 79 | u = GroupDispersionLaw(c) 80 | 81 | c.show(plt.gca(), 0.05, 1.0, label=c.expr1()) 82 | f = np.logspace(np.log10(0.05), 0., 100, 'plog') 83 | plt.gca().plot(1./f, c(f), label=c.expr2()) 84 | plt.show() 85 | -------------------------------------------------------------------------------- /srfpython/depthdisp/s96.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | help = '''s96 4 | --show list of surf96files to display 5 | -freq plot in frequency domain if specified 6 | --resamp list of surf96files to resample 7 | -fspace new frequency array in Hz, fstart, fend, nfreq, fscale 8 | -sfx file suffix to append, use "" to overwrite input files 9 | -inline replace showme by plt.show (e.g. for jupyter) 10 | #surf96 format 11 | SURF96 {wave} {type} {flag} {mode} {period(s)} {value(km/s)} {dvalue(km/s)} 12 | ''' 13 | 14 | # --------------------------------------------- 15 | if __name__ == "__main__": 16 | import sys 17 | if len(sys.argv) == 1: 18 | print(help) 19 | sys.exit() 20 | 21 | from srfpython.standalone.display import gcf, gca, showme, pause, plt, logtick 22 | from srfpython.depthdisp.dispcurves import surf96reader, Claw, freqspace 23 | from srfpython.utils import readargv 24 | import numpy as np 25 | 26 | argv = readargv() 27 | # ----------------------------------- 28 | if "inline" in argv.keys(): 29 | showme = plt.show 30 | 31 | # ----------------------------------- 32 | if "help" in argv.keys() or "h" in argv.keys(): 33 | print(help) 34 | sys.exit() 35 | 36 | # ----------------------------------- 37 | elif "show" in argv.keys(): 38 | pmin, pmax = np.inf, -np.inf 39 | for f in argv['show']: 40 | s = surf96reader(f) 41 | print(f) 42 | for law in s.get_all(): 43 | print(" %s" % str(law)) 44 | law.show(gca(), period= not "freq" in argv.keys(), label="%s%s%d" % (law.wave, law.type, law.mode))#alpha = 0.5, color = "r" if law.mode else "k") 45 | pmin = min([pmin, 1. / law.freq.max()]) 46 | pmax = max([pmax, 1. / law.freq.min()]) 47 | 48 | gca().set_xscale('log') 49 | gca().set_yscale('log') 50 | logtick(gca(), "xy") 51 | if not "freq" in argv.keys(): 52 | gca().set_xlim(pmin, pmax) 53 | gca().set_xlabel("Period (s)") 54 | 55 | else: 56 | gca().set_xlim(1. / pmax, 1. / pmin) 57 | gca().set_xlabel("Frequency (Hz)") 58 | gca().grid(True) 59 | gca().set_ylabel("Velocity (km/s)") 60 | # plt.legend() 61 | showme() 62 | sys.exit() 63 | 64 | # ----------------------------------- 65 | elif "resamp" in argv.keys(): 66 | def tostr(law, newf): 67 | fmt = "SURF96 {wave} {type} {flag} {mode} {period} {value} {dvalue}" 68 | stdlaw = Claw(freq = law.freq, value = law.dvalue, extrapolationmode = 0) 69 | newv = law(newf) 70 | news = stdlaw(newf) 71 | I = ~np.isnan(newv) 72 | if I.any(): 73 | s = "\n".join([fmt.format(\ 74 | wave = law.wave, 75 | type = law.type, 76 | flag = law.flag, 77 | mode = law.mode, 78 | period = 1./ff, 79 | value = vv, 80 | dvalue = ss) for ff, vv, ss in zip(newf[I], newv[I], news[I])]) 81 | return s 82 | return "" 83 | 84 | sfx = argv["sfx"][0] if "sfx" in argv.keys() else "resamp" 85 | print(argv['fspace']) 86 | newf = freqspace(float(argv['fspace'][0]), float(argv['fspace'][1]), int(argv['fspace'][2]), argv['fspace'][3]) #np.sort(np.unique(np.abs(argv['newf']))) 87 | print(newf) 88 | for f in argv['resamp']: 89 | s = surf96reader(f) 90 | fout = ".".join(f.split('/')[-1].split('.')[:-1] + [sfx] + [f.split('/')[-1].split('.')[-1]]) 91 | print(fout) 92 | out = "" 93 | for law in s.get_all(): 94 | out += "\n" + tostr(law, newf) 95 | out = out.strip('\n').strip() 96 | with open(fout, 'w') as fid: 97 | fid.write(out) 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /srfpython/depthdisp/surf96.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def unpacksurf96(string): 5 | """unpack dispersion curves at surf96 format (see Herrmann's doc)""" 6 | string = [line.strip() for line in string.split('\n')] 7 | if "" in string: 8 | string.remove('') 9 | npoints = len(string) 10 | 11 | datatypes = ['|U1', '|U1', '|U1', int, float, float, float] 12 | WAVE, TYPE, FLAG, MODE, PERIOD, VALUE, DVALUE = [np.empty(npoints, dtype=d) for d in datatypes] 13 | NLC, NLU, NRC, NRU = 0, 0, 0, 0 14 | for n in range(npoints): 15 | l = string[n].split() 16 | WAVE[n], TYPE[n], FLAG[n] = np.asarray(l[1:4], "|U1") 17 | MODE[n] = int(l[4]) 18 | PERIOD[n], VALUE[n], DVALUE[n] = np.asarray(l[5:], float) 19 | if WAVE[n] == "L": 20 | if TYPE[n] == "C": 21 | NLC += 1 22 | elif TYPE[n] == "U": 23 | NLU += 1 24 | elif WAVE[n] == "R": 25 | if TYPE[n] == "C": 26 | NRC += 1 27 | elif TYPE[n] == "U": 28 | NRU += 1 29 | else: 30 | raise Exception('') 31 | return WAVE, TYPE, FLAG, MODE, PERIOD, VALUE, DVALUE, NLC, NLU, NRC, NRU 32 | 33 | 34 | def readsurf96(filename): 35 | """read dispersion depthdisp at surf96 format""" 36 | with open(filename, 'r') as fid: 37 | L = fid.readlines() 38 | return unpacksurf96("".join(L)) 39 | 40 | 41 | def packsurf96(wave, type, flag, mode, period, value, dvalue): 42 | fmt = "SURF96 {wave} {type} {flag} {mode} {period} {value} {dvalue}" 43 | assert np.all([len(_) == len(wave) for _ in [type, flag, mode, period, value, dvalue]]) 44 | mode = np.asarray(mode, int) 45 | 46 | return "\n".join([fmt.format( 47 | wave=w, type=t, mode=m, period=p, 48 | value=v, dvalue=d, flag=f) 49 | for w, t, f, m, p, v, d in 50 | zip(wave, type, flag, mode, period, value, dvalue)]) 51 | -------------------------------------------------------------------------------- /srfpython/inversion/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obsmax/srfpython/4e3c4e0effca909174b824d0608cee1371404f0e/srfpython/inversion/__init__.py -------------------------------------------------------------------------------- /srfpython/inversion/concurenteigsearch.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy import sparse as sp 3 | from scipy.sparse import linalg as splinalg 4 | from srfpython.standalone.multipro8 import * 5 | 6 | # not omptimal : need to recmpute the same eigen values many times 7 | 8 | 9 | def concurent_eig_search(A): 10 | 11 | def search(sign): 12 | # A is readonly in this function 13 | valps = [] 14 | k = 1 15 | while k < A.shape[1]: 16 | if sign > 0: 17 | valp = splinalg.eigsh(A, which='LA', k=k, return_eigenvectors=False)[0] 18 | else: 19 | valp = splinalg.eigsh(A, which='SA', k=k, return_eigenvectors=False)[0] 20 | 21 | if valp * sign > 0: 22 | valps.append(valp) 23 | else: 24 | break 25 | k += 1 26 | return sign, valps 27 | 28 | def job_generator(): 29 | yield Job(1) # one thread searches for positive eigenvalues 30 | yield Job(-1) # the other searches for negative eigenvalues 31 | 32 | with MapAsync(search, job_generator(), Nworkers=2) as ma: 33 | for jobid, (sign, valps), _, _ in ma: 34 | break # the thread that finishes first has won the battle 35 | 36 | return sign, valps 37 | 38 | 39 | if __name__ == '__main__': 40 | 41 | # CM = sp.diags(np.arange(-6, 10., 1)) 42 | CM = sp.csc_matrix(np.random.randn(10, 10)) 43 | print(concurent_eig_search(CM)) 44 | -------------------------------------------------------------------------------- /srfpython/inversion/covmat.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy import sparse as sp 4 | from scipy.sparse import linalg as splinalg 5 | 6 | a = 1.0 7 | b = 0.25 8 | c = 0.01 9 | 10 | d = 0.8 11 | e = 0.5 12 | f = 0.01 13 | 14 | o = 0.01 15 | 16 | C = np.array([ 17 | [a, b, c, d, e, f, o, o, o], 18 | [b, a, b, e, d, e, o, o, o], 19 | [c, b, a, f, e, d, o, o, o], 20 | 21 | [d, e, f, a, b, c, d, e, f], 22 | [e, d, e, b, a, b, e, d, e], 23 | [f, e, d, c, b, a, f, e, d], 24 | 25 | [o, o, o, d, e, f, a, b, c], 26 | [o, o, o, e, d, e, b, a, b], 27 | [o, o, o, f, e, d, c, b, a] 28 | ]) 29 | 30 | 31 | valp, vectp = np.linalg.eigh(C) 32 | I = np.argsort(valp)[::-1] 33 | valp = valp[I] 34 | vectp = vectp[:, I] 35 | 36 | plt.plot(valp) 37 | plt.show() 38 | print(valp) 39 | print(vectp) 40 | 41 | Ipos = valp > 0 42 | Cfix = np.asarray( 43 | np.asmatrix(vectp[:, Ipos]) * \ 44 | np.asmatrix(np.diag(valp[Ipos])) * \ 45 | np.asmatrix(vectp[:, Ipos]).T) 46 | plt.figure() 47 | plt.subplot(121) 48 | plt.colorbar(plt.imshow(C)) 49 | plt.subplot(122, sharex=plt.gca(), sharey=plt.gca()) 50 | plt.colorbar(plt.imshow(Cfix)) 51 | plt.show() 52 | 53 | 54 | exit() 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | C = np.array([ 69 | [1., 1., 0.], 70 | [1., 1., 1.], 71 | [0., 1., 1.]]) 72 | 73 | 74 | 75 | C = sp.csc_matrix(C) 76 | C.prune() 77 | valp, vectp = splinalg.eigsh(C, k=1, which='SA') 78 | print(valp, vectp) 79 | 80 | 81 | exit() 82 | valp, vectp = np.linalg.eigh(C) 83 | I = np.argsort(valp)[::-1] 84 | valp = valp[I] 85 | vectp = vectp[:, I] 86 | 87 | plt.plot(valp) 88 | plt.show() 89 | exit() 90 | 91 | 92 | 93 | r2 = np.sqrt(2.) / 2. 94 | 95 | V = np.array([[r2, -r2], 96 | [r2, r2]]) 97 | V = np.asmatrix(V) 98 | 99 | L = np.array([[1., 0.], 100 | [0., 0.1]]) 101 | 102 | L = np.asmatrix(L) 103 | 104 | C = V * L * V.T 105 | print(C) 106 | 107 | 108 | Cinv = np.linalg.inv(C) 109 | print(Cinv) 110 | 111 | 112 | x = np.linspace(-5., 5., 100) 113 | y = np.linspace(-5., 5., 110) 114 | 115 | x, y = np.meshgrid(x, y) 116 | 117 | X = np.column_stack((x.flat[:], y.flat[:])) 118 | X = np.asmatrix(X) 119 | print(X.shape) 120 | 121 | 122 | K = (Cinv * X.T).T 123 | 124 | K = np.asarray(K) 125 | X = np.asarray(X) 126 | f = np.exp(-.5 * ((K * X).sum(axis=1))) 127 | f = f.reshape(x.shape) 128 | 129 | plt.gca().set_aspect(1.0) 130 | plt.contourf(x, y, f) 131 | plt.show() 132 | -------------------------------------------------------------------------------- /srfpython/inversion/inviter.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | 5 | """ 6 | goal : find the model whose power of 3 fits some data 7 | using linearized approach with a non diagonal covariance matrix to smooth the model 8 | """ 9 | 10 | 11 | def stairs(x, y): 12 | dx = np.median(x[1:] - x[:-1]) 13 | x_ = np.hstack((x[0] - dx / 2, 14 | np.repeat(0.5 * (x[1:] + x[:-1]), 2), 15 | x[-1] + dx / 2.)) 16 | y_ = np.repeat(y, 2) 17 | return x_, y_ 18 | 19 | 20 | def lininvsmooth(xi, di, si, xmodel, modelprior, sigmamodel, 21 | correlation_length=0.1): 22 | 23 | n = len(di) 24 | assert len(xi) == len(si) == n 25 | 26 | m = len(modelprior) 27 | assert len(xmodel) == m 28 | 29 | Cd = np.diag(si ** 2.0) 30 | if correlation_length == 0.: 31 | # no smoothing 32 | Cm = np.diag(sigmamodel ** 2.0) 33 | elif False: 34 | # use a exponential smoothing 35 | Cm = sigmamodel[:, np.newaxis] * sigmamodel * np.exp( 36 | -np.abs((xmodel[:, np.newaxis] - xmodel) / correlation_length)) 37 | else: 38 | # use a gaussian smoothing 39 | Cm = sigmamodel[:, np.newaxis] * sigmamodel * \ 40 | np.exp(-0.5 * ((xmodel[:, np.newaxis] - xmodel) / correlation_length) ** 2.) 41 | 42 | # xmodel_filt = 0.5 * (xmodel[1:] + xmodel[:-1]) 43 | xmodel_filt = xmodel 44 | 45 | def filt(model): 46 | 47 | # return ((model[1:] - model[:-1]) / (xmodel[1:] - xmodel[:-1])) 48 | return model ** 3.0 49 | 50 | def g(model): 51 | # compute the derivative of model 52 | model_filt = filt(model) 53 | 54 | # find the values at xi 55 | dcalc = np.interp(xi, xp=xmodel_filt, fp=model_filt) 56 | 57 | return dcalc 58 | 59 | def FD(model): 60 | fd = np.zeros((n, m), float) 61 | gm = g(model) 62 | for j in range(m): 63 | model_j = model.copy() 64 | model_j[j] += 0.01 65 | 66 | fd[:, j] = (g(model_j) - gm) / 0.01 67 | 68 | return fd 69 | 70 | modeli = modelprior 71 | models = [modeli.copy()] 72 | 73 | if n > m: 74 | Cdinv = np.linalg.inv(Cd) # np.diag(si ** -2.0) 75 | Cminv = np.linalg.inv(Cm) 76 | 77 | for _ in range(100): 78 | 79 | Gi = FD(modeli) 80 | if n <= m: 81 | # over determined problem 82 | CmGiT = np.dot(Cm, Gi.T) 83 | Siinv = np.linalg.inv(Cd + np.dot(Gi, CmGiT)) 84 | # Siinv = np.diag(np.diag(Siinv)) 85 | Hi = np.dot(CmGiT, Siinv) 86 | 87 | else: 88 | # under determined problem 89 | GiTCdinv = np.dot(Gi.T, Cdinv) 90 | Siinv = np.linalg.inv(np.dot(GiTCdinv, Gi) + Cminv) 91 | Hi = np.dot(Siinv, GiTCdinv) 92 | 93 | Xi = di - g(modeli) + np.dot(Gi, (modeli - models[0])) 94 | modeli = models[0] + np.dot(Hi, Xi) 95 | 96 | models.append(modeli.copy()) 97 | if len(models) > 1: 98 | if ((models[-1] - models[-2]) ** 2.0 / float(m)).sum() ** 0.5 < 0.01: 99 | # convergence reached 100 | break 101 | 102 | plt.plot(xi, di, 'ko', label="data") 103 | for i in range(n): 104 | plt.plot([xi[i],xi[i]], [di[i]-si[i], di[i]+si[i]], "k_-") 105 | 106 | for i in range(len(models)): 107 | linewidth = 1 108 | alpha = 0.2 109 | label_model = None 110 | label_fit = None 111 | if i == len(models) - 1: 112 | linewidth = 3 113 | alpha = 1 114 | label_model = "solution" 115 | label_fit = "data fit" 116 | elif i == 0: 117 | linewidth = 1 118 | alpha = 1 119 | label_model = "prior" 120 | 121 | x_, y_ = stairs(xmodel, models[i]) 122 | # plt.plot(xmodel, models[i], 'ro', alpha=0.2) 123 | plt.plot(x_, y_, 'r-', alpha=alpha, linewidth=linewidth, label=label_model) 124 | x__, y__ = stairs(xmodel_filt, filt(models[i])) 125 | # plt.plot(xmodel_filt, filt(models[i]), 'bo', alpha=0.2) 126 | plt.plot(x__, y__, 'b-', alpha=alpha, linewidth=linewidth, label=label_fit) 127 | 128 | 129 | if __name__ == '__main__': 130 | for test in [1, 2]: 131 | if test == 1: 132 | # over determined problem 133 | xi = np.array([0., 1., 2., 3.]) 134 | di = np.array([-2., 1.5, 2.5, -3.5]) 135 | si = np.array([0.1, 0.1, 0.1, 0.1]) 136 | m = 100 137 | elif test == 2: 138 | # under determined problem 139 | xi = np.sort(np.random.rand(100)) * 3. 140 | di = np.cos(5 * xi) + 4 * xi - 2.5 + 0.5 * np.random.randn(len(xi)) 141 | si = 0.5 * np.ones_like(xi) 142 | m = 10 143 | xmodel = np.linspace(xi[0]-0.05, xi[-1]+0.05, m) 144 | modelprior = np.linspace(-0.5, 0.5, m) # + 0.1 * np.random.randn(m) 145 | sigmamodel = 0.5 * np.ones(m) 146 | correlation_length = 0.3 147 | 148 | plt.figure() 149 | lininvsmooth(xi, di, si, xmodel, modelprior, sigmamodel, correlation_length) 150 | plt.gca().set_ylim((min(di)-1, max(di)+1)) 151 | plt.legend() 152 | # plt.ion() 153 | plt.show() 154 | # input('pause') 155 | -------------------------------------------------------------------------------- /srfpython/inversion/invsmooth.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | """ 5 | tester for linear inversion with smoothing 6 | """ 7 | 8 | 9 | def smoothinv(xi, di, si, 10 | xmodel, modelprior, sigmamodel, 11 | correlation_length=0.1): 12 | m = len(xmodel) 13 | n = len(xi) 14 | assert len(modelprior) == len(sigmamodel) == m 15 | 16 | G = np.zeros((n, m), float) 17 | for i in range(n): 18 | j = np.argmin(abs(xmodel - xi[i])) 19 | G[i, j] = 1.0 20 | 21 | Cd = np.diag(si ** 2.0) 22 | if False: 23 | Cm = np.diag(sigmamodel ** 2.0) 24 | elif False: 25 | Cm = sigmamodel[:, np.newaxis] * sigmamodel * np.exp( 26 | -np.abs((xmodel[:, np.newaxis] - xmodel) / correlation_length)) 27 | else: 28 | Cm = sigmamodel[:, np.newaxis] * sigmamodel * np.exp(-0.5 * ((xmodel[:, np.newaxis] - xmodel) / correlation_length) ** 2.) 29 | 30 | CmGT = np.dot(Cm, G.T) 31 | Sinv = np.linalg.inv(Cd + np.dot(G, CmGT)) 32 | # Sinv = np.diag(np.diag(Sinv)) # ??? 33 | 34 | model = modelprior + np.dot(CmGT, np.dot(Sinv, (di - np.dot(G, modelprior)))) 35 | 36 | plt.plot(xi, di, 'ko', label="data") 37 | for i in range(n): 38 | plt.plot([xi[i],xi[i]], [di[i]-si[i], di[i]+si[i]], "k_-") 39 | 40 | xmodel_ = np.hstack((xmodel[0], np.repeat(xmodel[1:], 2), xmodel[-1] + xmodel[1] - xmodel[0])) 41 | 42 | plt.plot(xmodel_, np.repeat(modelprior, 2), 'r-', label="prior") 43 | plt.fill_between(xmodel_, 44 | np.repeat(modelprior - sigmamodel, 2), 45 | np.repeat(modelprior + sigmamodel, 2), 46 | color='r', alpha=0.1) 47 | plt.plot(xmodel_, np.repeat(model, 2), 'b-', label="solution") 48 | return model 49 | 50 | 51 | if __name__ == '__main__': 52 | xi = np.array([0., 1., 2., 3.]) 53 | di = np.array([-1., 1., 1., -1.]) 54 | si = np.array([0.1, 0.1, 0.1, 0.1]) 55 | m = 100 56 | xmodel = np.linspace(xi[0], xi[-1], m) 57 | modelprior = np.linspace(-0.5, 0.5, m) 58 | sigmamodel = 0.25 * np.ones(m) 59 | 60 | correlation_length = 0.1 61 | smoothinv(xi, di, si, xmodel, modelprior, sigmamodel, correlation_length) 62 | 63 | correlation_length = 0.5 64 | smoothinv(xi, di, si, xmodel, modelprior, sigmamodel, correlation_length) 65 | 66 | # modelprior = smoothinv(xi, di, si, xmodel, modelprior, sigmamodel, correlation_length) 67 | # modelprior = smoothinv(xi, di, si, xmodel, modelprior, sigmamodel, correlation_length) 68 | # modelprior = smoothinv(xi, di, si, xmodel, modelprior, sigmamodel, correlation_length) 69 | # modelprior = smoothinv(xi, di, si, xmodel, modelprior, sigmamodel, correlation_length) 70 | # modelprior = smoothinv(xi, di, si, xmodel, modelprior, sigmamodel, correlation_length) 71 | 72 | 73 | # sigmamodel /= 2. 74 | # smoothinv(xi, di, si, xmodel, modelprior, sigmamodel, correlation_length) 75 | 76 | plt.legend() 77 | plt.show() -------------------------------------------------------------------------------- /srfpython/inversion/matinvissue.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | """ 5 | comment on Tarantola 2005, section 3.4.5 p80 6 | on the inversion of a large matrix 7 | """ 8 | 9 | 10 | def Ainv_dot_b(A, b): 11 | """ 12 | computes A^-1 * b without inverting A 13 | for numerical stability 14 | see Tarantola 2005, section 3.4.5 p80 15 | :param A: 16 | :param b: 17 | :return: 18 | """ 19 | return np.linalg.solve(a=A, b=b) 20 | 21 | 22 | # def Ainv_dot_B(A, B): 23 | # ans = np.zeros((A.shape[0], B.shape[1])) 24 | # for j in range(B.shape[1]): 25 | # ans[:, j] = Ainv_dot_b(A, b=B[:, j]) 26 | # return ans 27 | 28 | 29 | # ========== construct a non diagonal covariance matrix 30 | n = 1000 31 | z = np.linspace(0., 3., n) 32 | sigma = np.linspace(0.1, 0.1, n) 33 | l = 1.0 34 | 35 | sigmaT = sigma[:, np.newaxis] 36 | zT = z[:, np.newaxis] 37 | 38 | if l > 0: 39 | # rho = np.exp(-0.5 * ((z - zT) / l) ** 2.0) 40 | rho = np.exp(-np.abs(z - zT) / l) 41 | elif l == 0: 42 | rho = np.diag(np.ones(n)) 43 | else: 44 | raise ValueError 45 | 46 | C = sigma * sigmaT * rho 47 | # L = np.linalg.cholesky(C) 48 | # plt.figure() 49 | # plt.subplot(121) 50 | # plt.imshow(C) 51 | # plt.subplot(122) 52 | # plt.imshow(L) 53 | # plt.show() 54 | # 55 | # 56 | # det = np.linalg.det(C) 57 | # ========== compute the determinant 58 | # print(det, det == 0) # => 0, True 59 | Cinv = np.linalg.inv(C) # => inaccurate 60 | m = np.random.rand(n) 61 | # m = np.ones(n) 62 | 63 | print (np.dot(m, np.dot(Cinv, m))) # => negative ??? 64 | print (np.dot(m, Ainv_dot_b(C, m))) # => looks ok 65 | 66 | x = Ainv_dot_b(C, m) 67 | plt.figure() 68 | plt.subplot(211) 69 | plt.plot(m) 70 | plt.plot(np.dot(C, x)) 71 | plt.subplot(212, sharex=plt.gca()) 72 | plt.plot(m - np.dot(C, x)) 73 | plt.show() -------------------------------------------------------------------------------- /srfpython/inversion/tester1.py: -------------------------------------------------------------------------------- 1 | from srfpython.standalone.display import * 2 | import numpy as np 3 | from metropolis2 import * 4 | 5 | """ 6 | test the 1D LogUni and LogGauss pdfs 7 | """ 8 | 9 | v = np.linspace(-1., 1., 10000) 10 | 11 | if 0: 12 | #nans expected 13 | l0 = LogUni(vinf=0., vsup=0.1, k=10., nanbehavior=2) 14 | l1 = LogUni(vinf=0.1, vsup=0.2, k=30., nanbehavior=2) 15 | l2 = LogGauss(vmean=0.22, vunc=0.12, vinf=0.2, vsup=0.3, k=30., nanbehavior=2) 16 | 17 | V = np.copy(v) 18 | V[-1] = np.nan 19 | else: 20 | #no nans expected 21 | l0 = LogUni(vinf=0., vsup=0.1, k=10., nanbehavior= 0) 22 | l1 = LogUni(vinf=0.1, vsup=0.2, k=30., nanbehavior= 0) 23 | l2 = LogGauss(vmean=0.22, vunc=0.12, vinf=0.2, vsup=0.3, k=30., nanbehavior= 0) 24 | V = np.copy(v) 25 | 26 | 27 | print("l0", l0) 28 | print("l1", l1) 29 | print("l2", l2) 30 | 31 | gcf().add_subplot(211, ylabel="log(pdf)") 32 | gca().plot(v, l0.calln(V), label="l0 (uni, k=10)") 33 | gca().plot(v, l1.calln(V), label="l1 (uni, k=30)") 34 | gca().plot(v, l2.calln(V), label="l2 (trunc. gauss., k=30)") 35 | gca().set_ylim(-100., 2.) 36 | gca().legend() 37 | gcf().add_subplot(212, sharex = gca(), ylabel="pdf") 38 | gca().plot(v, np.exp(l0.calln(V)), label="l0 (uni, k=10)") 39 | gca().plot(v, np.exp(l1.calln(V)), label="l1 (uni, k=30)") 40 | gca().plot(v, np.exp(l2.calln(V)), label="l2 (trunc. gauss., k=30)") 41 | gca().legend() 42 | gca().set_xlim(-.05, .4) 43 | showme() 44 | -------------------------------------------------------------------------------- /srfpython/inversion/tester2.py: -------------------------------------------------------------------------------- 1 | from srfpython.standalone.display import * 2 | import numpy as np 3 | from metropolis2 import * 4 | import time 5 | 6 | ######################################################### 7 | def test2(): 8 | """test ND pdfs""" 9 | x = np.linspace(0., 1., 200) 10 | y = np.linspace(0., 2., 215) 11 | X, Y = np.meshgrid(x, y) 12 | #l = LogUniND([0.1, 0.1], [0.3, 0.5], k = 20.) 13 | #l = LogGaussND([0.2, 0.2], [0.1, 1000.], [0.1, 0.1], [0.3, 0.5], k = 20.) 14 | l = LogGaussNDCov([0.2, 0.2], [0.1, 0.2], [0.1, 0.1], [0.3, 0.5], rho = [[1.0, 0.9], [0.9, 1.0]], k = 20., nanbehavior=0) 15 | Z = l.callargs(X, Y) 16 | gcf().add_subplot(121) 17 | gca().pcolormesh(X, Y, Z) 18 | gcf().add_subplot(122, sharex = gca(), sharey = gca()) 19 | gca().pcolormesh(X, Y, np.exp(Z)) 20 | showme() 21 | 22 | 23 | ######################################################### 24 | def test211(): 25 | """speed test, nans expected""" 26 | l = LogGaussND( 27 | vmeans = [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2], 28 | vuncs = [0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2], 29 | vinfs = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], 30 | vsups = [0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5], 31 | k = 20., 32 | nanbehavior = 1) 33 | start = time.time() 34 | for _ in range(1000): 35 | l.call1([np.nan, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2]) 36 | print(time.time() - start) 37 | 38 | def test212(): 39 | """speed test, no nans expected""" 40 | l = LogGaussND( 41 | vmeans=[0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2], 42 | vuncs=[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2], 43 | vinfs=[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], 44 | vsups=[0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5, 0.3, 0.5], 45 | k=20., 46 | nanbehavior=0) 47 | 48 | start = time.time() 49 | for _ in range(1000): 50 | l.call1( 51 | [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 52 | 0.2, 0.2, 0.2, 0.2, 0.2]) 53 | print(time.time() - start) 54 | 55 | 56 | test2() 57 | test211() 58 | test212() 59 | -------------------------------------------------------------------------------- /srfpython/inversion/tester30.py: -------------------------------------------------------------------------------- 1 | from srfpython.standalone.display import * 2 | from metropolis2 import * 3 | 4 | 5 | """ 6 | test Metropolis algorithm in 1D 7 | """ 8 | 9 | if True: 10 | l = LogGaussND(vmeans=[1.], vuncs=[1.25], 11 | vinfs=[-0.1], vsups=[1.8], 12 | k=10000.0, nanbehavior=0) 13 | logRHOM = l 14 | elif 1: 15 | l = LogUniND(vinfs=[-0.1], vsups=[1.], 16 | k=30.0, nanbehavior=0) 17 | logRHOM = l 18 | 19 | 20 | x = np.linspace(-.5, 3., 1000) 21 | y = np.exp([logRHOM([xx]) for xx in x]) 22 | 23 | A = np.sum(y * (x[1] - x[0])) 24 | gca().plot(x, y / A) 25 | 26 | 27 | def G(model): 28 | return np.array([0.]) 29 | 30 | 31 | def logRHOD(data): 32 | return 0. 33 | 34 | 35 | M0 = np.array([0.]) 36 | MSTD = np.array([20.]) 37 | start = time.time() 38 | models, _, weights, _ = \ 39 | metropolis(M0, MSTD, G, 1, 40 | logRHOD, logRHOM, 41 | nkeep = 50000, 42 | HL = 100, 43 | IK0 = 0.65, 44 | adjustspeed=0.5, 45 | MPMIN = .1, 46 | MPMAX = 10.0) 47 | 48 | print("total time %f" % (time.time() -start)) 49 | models = models.repeat(weights, axis = 0) 50 | hist, bin_edges = np.histogram(models[:, 0], bins = 30, density=True) 51 | for mid, width, height in zip(.5 * (bin_edges[:-1] + bin_edges[1:]), bin_edges[1:]-bin_edges[:-1], hist): 52 | gca().bar(mid, height, width, bottom=0, align='center', color = "k", alpha = .4) 53 | 54 | 55 | gca().set_xlim(-.5, 2.) 56 | showme() 57 | -------------------------------------------------------------------------------- /srfpython/inversion/tester31.py: -------------------------------------------------------------------------------- 1 | from srfpython.standalone.display import * 2 | from srfpython.standalone.multipro8 import * 3 | from metropolis2 import * 4 | import numpy as np 5 | 6 | 7 | """test Metropolis 2D, parallel""" 8 | 9 | #################################################################################### 10 | def histogram2d(xflat, yflat, xbins, ybins): 11 | """quite similar to np.histogram2d with several available normalizations 12 | """ 13 | if len(xflat) - len(yflat): raise ValueError('') 14 | H, X, Y = np.histogram2d(x = xflat, y = yflat, bins=(xbins, ybins), density=True) 15 | 16 | H[np.isnan(H)] = 0. 17 | return X, Y, H.T 18 | 19 | def minmax(X): 20 | return X.min(), X.max() 21 | 22 | 23 | x = np.linspace(0.05, 0.3, 200) 24 | y = np.linspace(0.05, 0.4, 215) 25 | X, Y = np.meshgrid(x, y) 26 | #l = LogUniND([0.1, 0.1], [0.3, 0.5], k = 20.) 27 | #l = LogGaussND([0.2, 0.2], [0.025, 1000.], [0.1, 0.1], [0.3, 0.5], k = 20.) 28 | #l = LogGaussNDCov([0.2, 0.2], [0.01, 0.2], [0.1, 0.1], [0.2, 0.5], rho = [[1.0, 0.9], [0.9, 1.0]], k = 20.) 29 | l = LogGaussNDCov(vmeans = [0.2, 0.2], 30 | vuncs = [0.1, 0.2], 31 | vinfs = [0.1, 0.1], 32 | vsups = [0.2, 0.5], 33 | rho = [[1.0, 0.9], 34 | [0.9, 1.0]], 35 | k = 20., 36 | nanbehavior=0) 37 | Z = l.callargs(X, Y) 38 | #ax1 = gcf().add_subplot(131) 39 | #ax1.pcolormesh(X, Y, Z, cmap = plt.cm.jet)#cmap2isocolor(Z, plt.cm.jet)) 40 | ax2 = gcf().add_subplot(121) 41 | vmin, vmax = minmax(np.exp(Z)) 42 | plt.pcolormesh(X, Y, np.exp(Z), vmin=vmin, vmax=vmax, cmap = plt.cm.jet) 43 | plt.colorbar() 44 | 45 | 46 | ax3 = gcf().add_subplot(122, sharex = ax2, sharey = ax2) 47 | 48 | def gen(): 49 | for nchain in range(1): 50 | M0 = np.random.randn(2) 51 | MSTD = np.asarray([0.05, 0.05]) 52 | yield Job(nchain, M0, MSTD, nkeep = 15000) 53 | 54 | def fun(worker, chainid, M0, MSTD, nkeep): 55 | def G(model): return np.array([0.]) 56 | def logRHOD(data): return 0. 57 | logRHOM = l 58 | models, _, weights, _ = \ 59 | metropolis(M0, MSTD, G, 1, logRHOD, logRHOM, 60 | nkeep = nkeep, 61 | normallaw = worker.randn, 62 | unilaw = worker.rand, 63 | chainid = chainid, 64 | verbose = True) 65 | models = models.repeat(weights, axis = 0) 66 | 67 | return models[:, 0], models[:, 1] 68 | 69 | X, Y = [], [] 70 | with MapAsync(fun, gen(), Nworkers=4, Taskset="0-4") as ma: 71 | for _, (XX, YY), _, _ in ma: 72 | X = np.concatenate((X, XX)) 73 | Y = np.concatenate((Y, YY)) 74 | 75 | 76 | X, Y, H = histogram2d(X, Y, x[::4], y[::4]) 77 | plt.pcolormesh(X, Y, H, cmap = plt.cm.jet) #vmin=vmin, vmax=vmax, 78 | plt.colorbar() 79 | 80 | showme() 81 | -------------------------------------------------------------------------------- /srfpython/inversion/tester32.py: -------------------------------------------------------------------------------- 1 | from srfpython.standalone.display import * 2 | from srfpython.standalone.multipro8 import * 3 | from metropolis2 import * 4 | import numpy as np 5 | 6 | 7 | """ 8 | gaussian regression example : assume incompatible data, and multiple solutions 9 | """ 10 | 11 | #################################################################################### 12 | def histogram2d(xflat, yflat, xbins, ybins): 13 | """quite similar to np.histogram2d with several available normalizations 14 | """ 15 | if len(xflat) - len(yflat): raise ValueError('') 16 | H, X, Y = np.histogram2d(x = xflat, y = yflat, bins=(xbins, ybins), density=True) 17 | 18 | H[np.isnan(H)] = 0. 19 | return X, Y, H.T 20 | 21 | ######################################################### 22 | 23 | 24 | #----------------------- 25 | class Theo(object): 26 | def __init__(self, xpoints): 27 | self.xpoints = xpoints 28 | def __call__(self, m): 29 | #theory 30 | #d = m[0] * self.xpoints + m[1] 31 | d = np.exp(-0.5 * ((self.xpoints - m[0]) / m[1]) ** 2.) 32 | return d 33 | #----------------------- 34 | #data 35 | amin, amax = 0., 1.0 36 | bmin, bmax = 0.05, 0.2 37 | x = np.linspace(0., 1.0, 24) 38 | G = Theo(x) 39 | #----------------------- 40 | y = np.zeros_like(x) 41 | y[:12] = G([0.25, 0.15])[:12] + 0.05 * np.random.randn(len(x[:12])) 42 | y[12:] = G([0.75, 0.08])[12:] + 0.05 * np.random.randn(len(x[12:])) 43 | s = 0.3 * np.ones_like(x) 44 | s[12:] /= 2. 45 | plt.figure(figsize = (12, 6)) 46 | ax1 = gcf().add_subplot(121, xlabel = "mean", ylabel = "std"); ax1 = gca() 47 | ax2 = gcf().add_subplot(122, xlabel = "x", ylabel = "y"); ax2 = gca() 48 | 49 | for xx,yy,ss in zip(x,y,s): 50 | ax2.plot([xx, xx], [yy - ss, yy + ss], "_-", color= [0.5, .5, .5], alpha = 1.0) 51 | ax2.plot(x, y, "wo", markeredgecolor = "k") 52 | showme(0) 53 | #----------------------- 54 | logRHOD = LogGaussND(\ 55 | vmeans = y, 56 | vuncs = s, 57 | vinfs = y * 0. -10., 58 | vsups = y * 0. +10.) 59 | logRHOM = LogUniND(\ 60 | vinfs = [amin, bmin], 61 | vsups = [amax, bmax]) 62 | #----------------------- 63 | if False: 64 | M0 = np.array([np.random.rand() * (amax - amin) + amin, np.random.rand() * (bmax - bmin) + bmin]) 65 | MSTD = np.array([0.1, 0.1]) 66 | nkeep = 10000 67 | models, datas, weights, llks = metropolis(M0, MSTD, G, len(G.xpoints), logRHOD, logRHOM, nkeep = nkeep) 68 | models = models.repeat(weights, axis = 0) 69 | datas = datas.repeat(weights, axis = 0) 70 | llks = llks.repeat(weights) 71 | A = models[:, 0] 72 | B = models[:, 1] 73 | else: #parallel 74 | def gen(): 75 | for nchain in range(48): 76 | M0 = np.array([np.random.rand() * (amax - amin) + amin, np.random.rand() * (bmax - bmin) + bmin]) 77 | MSTD = np.array([0.1, 0.1]) 78 | nkeep = 1000#00 79 | yield Job(nchain, M0, MSTD, nkeep = nkeep) 80 | 81 | def fun(worker, chainid, M0, MSTD, nkeep): 82 | G = Theo(x) 83 | logRHOD = LogGaussND(\ 84 | vmeans = y, 85 | vuncs = s, 86 | vinfs = y * 0. -10., 87 | vsups = y * 0. +10.) 88 | logRHOM = LogUniND(\ 89 | vinfs = [amin, bmin], 90 | vsups = [amax, bmax]) 91 | models, datas, weights, llks = metropolis(M0, MSTD, G, len(G.xpoints), logRHOD, logRHOM, nkeep = nkeep, normallaw = worker.randn, unilaw = worker.rand, chainid = chainid) 92 | models = models.repeat(weights, axis = 0) 93 | datas = datas.repeat(weights, axis = 0) 94 | llks = llks.repeat(weights) 95 | return models, datas, weights, llks 96 | 97 | models = None 98 | datas = None 99 | with MapAsync(fun, gen(), Nworkers=4) as ma: 100 | for _, (ms, ds, ws, ls), _, _ in ma: 101 | if models is None: 102 | models, datas = ms, ds 103 | else: 104 | models = np.concatenate((models, ms), axis = 0) 105 | datas = np.concatenate((datas, ds), axis = 0) 106 | A = models[:, 0] 107 | B = models[:, 1] 108 | #----------------------- data histogram 109 | xbins = np.linspace(x.min(), x.max(), 100) 110 | ybins = np.linspace((y - s).min(), (y + s).max(), 110) 111 | Xbins, Ybins = np.meshgrid(xbins, ybins) 112 | Z = np.zeros_like(Xbins) 113 | J = np.arange(len(xbins)) 114 | G1 = Theo(xbins) 115 | for a, b in zip(A, B): 116 | y = G1([a, b]) 117 | I = np.argmin(abs(y - Ybins), axis = 0) 118 | Z[I, J] += 1 119 | cmap = plt.cm.CMRmap #cmap2isocolor(Z, cmap = plt.cm.CMRmap) 120 | ax2.pcolormesh(xbins, ybins, Z, cmap = cmap) 121 | 122 | #----------------------- model histogram 123 | X, Y, H = histogram2d(A, B, np.linspace(amin, amax, 100), np.linspace(bmin, bmax, 100)) 124 | #cmap = cmap2isocolor(H, cmap = plt.cm.CMRmap) 125 | cmap = plt.cm.CMRmap 126 | ax1.pcolormesh(X, Y, H, cmap = cmap) 127 | 128 | showme() 129 | -------------------------------------------------------------------------------- /srfpython/inversion/tester33.py: -------------------------------------------------------------------------------- 1 | from srfpython.standalone.display import * 2 | from srfpython.standalone.multipro8 import * 3 | from metropolis2 import * 4 | import numpy as np 5 | 6 | 7 | """ 8 | test for failing theory or nans in data array 9 | use the Programming Error exception to test the behavior of the code 10 | use failure test or happy failure to mimic unsuited models 11 | """ 12 | nofail = False #if True, the chain will continue running even though programming error is suspected 13 | nanbehavior = 2 #recommended : means that models or datas with nans are penalized according to the number of nans 14 | #0 means that nans are producing errors, so the metropolis algo cannot compare models since they are all equally bad 15 | 16 | 17 | #################################################################################### 18 | def histogram2d(xflat, yflat, xbins, ybins): 19 | """quite similar to np.histogram2d with several available normalizations 20 | """ 21 | if len(xflat) - len(yflat): raise ValueError('') 22 | H, X, Y = np.histogram2d(x = xflat, y = yflat, bins=(xbins, ybins), density=True) 23 | 24 | H[np.isnan(H)] = 0. 25 | return X, Y, H.T 26 | 27 | ######################################################### 28 | 29 | 30 | #----------------------- 31 | class Theo(object): 32 | def __init__(self, xpoints): 33 | self.xpoints = xpoints 34 | def __call__(self, m): 35 | #theory 36 | if False: 37 | raise Exception('Programming Error test') 38 | 39 | if m[1] >= 0.16: 40 | return np.nan * np.zeros_like(self.xpoints) 41 | raise Exception('Theory failure test') 42 | elif m[1] <= 0.08: 43 | return np.nan * np.zeros_like(self.xpoints) 44 | elif np.random.rand() < 0.01: 45 | return np.nan * np.zeros_like(self.xpoints) #raise Exception('Happy failure test : the failure that occurs just for fun') 46 | d = np.exp(-0.5 * ((self.xpoints - m[0]) / m[1]) ** 2.) 47 | return d 48 | #----------------------- 49 | #data 50 | amin, amax = 0., 1.0 51 | bmin, bmax = 0.05, 0.2 52 | x = np.linspace(0., 1.0, 12) 53 | G = Theo(x) 54 | #----------------------- 55 | y = np.zeros_like(x) 56 | y = np.exp(-0.5 * ((x - 0.5) / 0.1) ** 2.) + 0.1 * np.random.randn(len(x)) 57 | s = 0.3 * np.ones_like(x) 58 | plt.figure(figsize = (12, 6)) 59 | ax1 = gcf().add_subplot(121, xlabel = "mean", ylabel = "std"); ax1 = gca() 60 | ax2 = gcf().add_subplot(122, xlabel = "x", ylabel = "y"); ax2 = gca() 61 | 62 | for xx,yy,ss in zip(x,y,s): 63 | ax2.plot([xx, xx], [yy - ss, yy + ss], "_-", color= [0.5, .5, .5], alpha = 1.0) 64 | ax2.plot(x, y, "wo", markeredgecolor = "k") 65 | showme(0) 66 | #----------------------- 67 | if True: 68 | def gen(): 69 | for nchain in range(12): 70 | M0 = np.array([np.random.rand() * (amax - amin) + amin, np.random.rand() * (bmax - bmin) + bmin]) 71 | MSTD = np.array([0.1, 0.1]) 72 | nkeep = 1000 73 | yield Job(nchain, M0, MSTD, nkeep = nkeep) 74 | 75 | def fun(worker, chainid, M0, MSTD, nkeep): 76 | G = Theo(x) 77 | logRHOD = LogGaussND(\ 78 | vmeans = y, 79 | vuncs = s, 80 | vinfs = y * 0. -10., 81 | vsups = y * 0. +10., 82 | nanbehavior = nanbehavior) 83 | logRHOM = LogUniND(\ 84 | vinfs = [amin, bmin], 85 | vsups = [amax, bmax], 86 | nanbehavior = nanbehavior) 87 | models, datas, weights, llks = metropolis(M0, MSTD, G, len(G.xpoints), logRHOD, logRHOM, nkeep = nkeep, normallaw = worker.randn, unilaw = worker.rand, chainid = chainid, nofail = nofail) 88 | models = models.repeat(weights, axis = 0) 89 | datas = datas.repeat(weights, axis = 0) 90 | llks = llks.repeat(weights) 91 | return models, datas, weights, llks 92 | 93 | models = None 94 | datas = None 95 | with MapAsync(fun, gen()) as ma: 96 | for _, (ms, ds, ws, ls), _, _ in ma: 97 | if models is None: 98 | models, datas = ms, ds 99 | else: 100 | models = np.concatenate((models, ms), axis = 0) 101 | datas = np.concatenate((datas, ds), axis = 0) 102 | A = models[:, 0] 103 | B = models[:, 1] 104 | #----------------------- data histogram 105 | xbins = np.linspace(x.min(), x.max(), 100) 106 | ybins = np.linspace((y - s).min(), (y + s).max(), 110) 107 | Xbins, Ybins = np.meshgrid(xbins, ybins) 108 | Z = np.zeros_like(Xbins) 109 | J = np.arange(len(xbins)) 110 | #G1 = Theo(xbins) 111 | for a, b in zip(A, B): 112 | try: y = np.exp(-0.5 * ((xbins - a) / b) ** 2.)#G1([a, b])#G1([a, b]) 113 | except KeyboardInterrupt: raise 114 | except: continue 115 | I = np.argmin(abs(y - Ybins), axis = 0) 116 | Z[I, J] += 1 117 | 118 | cmap = plt.cm.CMRmap #cmap2isocolor(Z, cmap = plt.cm.CMRmap) 119 | ax2.pcolormesh(xbins, ybins, Z, cmap = cmap) 120 | #----------------------- model histogram 121 | X, Y, H = histogram2d(A, B, np.linspace(amin - 0.33, amax + 0.33, 100), np.linspace(bmin - 0.08, bmax + 0.08, 100))#, normalization="pdf") 122 | cmap = plt.cm.CMRmap #cmap2isocolor(H, cmap = plt.cm.CMRmap) 123 | ax1.pcolormesh(X, Y, H, cmap = cmap) 124 | showme() 125 | 126 | -------------------------------------------------------------------------------- /srfpython/inversion/tester40.py: -------------------------------------------------------------------------------- 1 | from srfpython.standalone.display import * 2 | from srfpython.standalone.multipro8 import * 3 | from metropolis2 import * 4 | import numpy as np 5 | 6 | """add constraint on secondary parameters 7 | x is the parameter to invert 8 | we impose a constraint on x and one on 2*x 9 | """ 10 | 11 | if False: 12 | # prior constraint on x only 13 | l = LogUni(vinf=0., 14 | vsup=2.5, 15 | k=1000.0, 16 | nanbehavior=0) 17 | 18 | 19 | def logRHOM(model): 20 | x = model[0] 21 | return l(x) 22 | 23 | else: 24 | #prior constraint on x 2*x 25 | l = LogUniND(vinfs=[-10., 0.0], 26 | vsups=[10.0, 5.0], #=> x should be only between 0. and 2.5 27 | k=1000.0, 28 | nanbehavior=0) 29 | 30 | 31 | def logRHOM(model): 32 | x = model[0] 33 | y = 2. * x 34 | return l([x, y]) 35 | 36 | 37 | def G(model): 38 | return np.array([0.]) 39 | 40 | 41 | def logRHOD(data): 42 | return 0. 43 | 44 | 45 | x = np.linspace(-10., 10., 1000) 46 | y = np.exp([logRHOM([xx]) for xx in x]) 47 | 48 | A = np.sum(y * (x[1] - x[0])) 49 | gca().plot(x, y / A) 50 | 51 | 52 | M0 = np.array([0.]) 53 | MSTD = np.array([10.]) 54 | models, _, weights, _ = \ 55 | metropolis(M0, MSTD, G, 1, logRHOD, logRHOM, 56 | nkeep=50000, 57 | HL=100, 58 | IK0=0.65, 59 | MPMIN=0.001, 60 | MPMAX=1000.0, 61 | adjustspeed=0.5) 62 | models = models.repeat(weights, axis=0) 63 | #p = PDF(models[:, 0], 200) 64 | #p.plot(gca(), alpha = 0.5) 65 | 66 | hist, bin_edges = np.histogram(models[:, 0], bins =30, density=True) 67 | for mid, width, height in zip(.5 * (bin_edges[:-1] + bin_edges[1:]), bin_edges[1:]-bin_edges[:-1], hist): 68 | gca().bar(mid, height, width, bottom=0, align='center', color = "k", alpha = .4) 69 | 70 | 71 | # compare with the distribution that would be obtained with random.rand 72 | N = models.shape[0] 73 | models = np.random.rand(N).reshape((N, 1)) * 2.5 + 3. 74 | hist, bin_edges = np.histogram(models[:, 0], bins =30, density=True) 75 | for mid, width, height in zip(.5 * (bin_edges[:-1] + bin_edges[1:]), bin_edges[1:]-bin_edges[:-1], hist): 76 | gca().bar(mid, height, width, bottom=0, align='center', color = "g", alpha = .4) 77 | 78 | 79 | showme() 80 | -------------------------------------------------------------------------------- /srfpython/inversion/tester41.py: -------------------------------------------------------------------------------- 1 | from srfpython.standalone.display import * 2 | from srfpython.standalone.multipro8 import * 3 | from metropolis2 import * 4 | import numpy as np 5 | 6 | 7 | """add constraint on secondary parameters, 2D 8 | model = x, y 9 | target = (x ** 2. + y ** 2.) ** 0.5 = 1.0 +- 0.1 10 | constraint = abs(x - y) follows a uniform law between two values 11 | 12 | > a model is [x, y] 13 | > the data is G(model) is [d] 14 | > the prior pdf on the model is bypassed so that additional constraints are added to some relations 15 | between the model parameters 16 | 17 | """ 18 | 19 | 20 | #################################################################################### 21 | def histogram2d(xflat, yflat, xbins, ybins): 22 | """quite similar to np.histogram2d with several available normalizations 23 | """ 24 | if len(xflat) - len(yflat): raise ValueError('') 25 | H, X, Y = np.histogram2d(x = xflat, y = yflat, bins=(xbins, ybins), density=True) 26 | 27 | H[np.isnan(H)] = 0. 28 | return X, Y, H.T 29 | 30 | ######################################################### 31 | 32 | 33 | # data pdf 34 | def G(model): 35 | x, y = model 36 | d = np.sqrt(x ** 2. + y ** 2.) 37 | return np.array([d]) 38 | 39 | 40 | logRHOD = LogGaussND(vmeans=[1.0], 41 | vuncs=[0.1], 42 | vinfs=[0.5], 43 | vsups=[1.5], 44 | k=1000.0, 45 | nanbehavior=0) 46 | 47 | # model pdf 48 | # prior constraint on x y abs(x-y) 49 | l = LogUniND(vinfs=[-10., -10.0, 0.5], 50 | vsups=[10., 10.0, 1.5], 51 | k=1000.0, 52 | nanbehavior=0) 53 | 54 | def logRHOM(model): 55 | x, y = model 56 | return l([x, y, np.abs(x - y)]) 57 | 58 | 59 | if True: 60 | def gen(): 61 | for nchain in range(4): 62 | M0 = np.random.randn(2) 63 | MSTD = np.asarray([1., 1.]) 64 | yield Job(nchain, M0, MSTD) 65 | 66 | def fun(worker, chainid, M0, MSTD): 67 | models, _, weights, _ = \ 68 | metropolis(M0, MSTD, G, 1, logRHOD, logRHOM, 69 | nkeep=10000, 70 | HL=1000, 71 | IK0=0.25, 72 | MPMIN=0.001, 73 | MPMAX=1000.0, 74 | adjustspeed=0.1, 75 | debug=False, 76 | normallaw = worker.randn, 77 | unilaw = worker.rand, 78 | chainid = chainid, 79 | verbose = True) 80 | models = models.repeat(weights, axis = 0) 81 | 82 | return models 83 | 84 | models=None 85 | with MapAsync(fun, gen()) as ma: 86 | for _, m, _, _ in ma: 87 | if models is None: 88 | models = m 89 | else: 90 | models = np.concatenate((models, m), axis=0) 91 | 92 | X, Y, H = histogram2d(models[:, 0], models[:, 1], 100, 100)#, normalization="pdf") 93 | cmap = plt.cm.CMRmap #cmap2isocolor(H, cmap = plt.cm.CMRmap) 94 | gca().pcolormesh(X, Y, H, cmap = cmap) 95 | gca().set_aspect(1.0) 96 | showme() 97 | 98 | -------------------------------------------------------------------------------- /srfpython/inversion/tester50.py: -------------------------------------------------------------------------------- 1 | from srfpython import * 2 | from neldermead2 import * 3 | import numpy as np 4 | 5 | 6 | def gauss2D2(x, y, xo, yo, sigmaj, sigmin, alphadeg): 7 | """plus pratique, pas de coeff de correl 8 | xo, yo = max of the gaussian 9 | sigmaj = standard deviation in the major eigenvector direction 10 | sigmin = standard deviation in the minor eigenvector direction 11 | alphadeg = angle in degrees, counterclockwise from the positive x axis 12 | """ 13 | assert sigmaj >= sigmin 14 | 15 | deg2rad = np.pi / 180. 16 | x = x - xo 17 | y = y - yo 18 | c = np.cos(alphadeg * deg2rad) 19 | s = np.sin(alphadeg * deg2rad) 20 | xp = (y * c - x * s) / sigmin 21 | yp = (x * c + y * s) / sigmaj 22 | return np.exp(-0.5 * (xp ** 2. + yp ** 2.)) 23 | 24 | 25 | class fun2D(): 26 | def __init__(self, N=20): 27 | if False: 28 | self.N = N 29 | self.As = np.random.randn(self.N) 30 | self.xos, self.yos = zip(*[np.random.rand(2) * 20. - 10. for _ in range(self.N)]) 31 | self.sigmamins, self.sigmajs = zip(*[np.sort(np.random.rand(2) * 3. + .1) for _ in range(self.N)]) 32 | self.alphadegs = np.random.rand(self.N) * 360. 33 | else: 34 | self.As = np.array([4., 1.]) 35 | self.xos = np.array([+8.5, +5.0]) 36 | self.yos = np.array([-2.5, -5.0]) 37 | self.sigmamins = np.array([.1, 4.]) 38 | self.sigmajs = np.array([3., 4.]) 39 | self.alphadegs = np.array([35., 0.]) 40 | self.N = len(self.As) 41 | 42 | def __call__(self, m): 43 | x, y = m 44 | z = np.zeros_like(x) 45 | for n in range(self.N): 46 | z += self.As[n] * gauss2D2(x, y, self.xos[n], self.yos[n], self.sigmajs[n], self.sigmamins[n], 47 | self.alphadegs[n]) 48 | 49 | z += 0. * np.cos(x*10.) * np.sin(y*10.) 50 | return z 51 | 52 | 53 | class RosenBrock(object): 54 | "rosenbrock * -1" 55 | def __init__(self, a=1, b=100): 56 | self.a, self.b = a, b 57 | 58 | def __call__(self, m): 59 | x, y = m 60 | return -1 * ((self.a - x) ** 2. + self.b * (y - x ** 2.) ** 2.) 61 | 62 | 63 | def test2D(): 64 | x = np.linspace(-2.5, 10., 300) 65 | y = np.linspace(-10., 2.5, 300) 66 | X, Y = np.meshgrid(x, y) 67 | if True: 68 | f = fun2D() 69 | else: 70 | f = RosenBrock() 71 | Z = f(np.asarray([X, Y])) 72 | 73 | plt.figure(figsize=(12, 6)) 74 | ax0 = gcf().add_subplot(121); 75 | ax0 = gca() 76 | ax1 = gcf().add_subplot(122) 77 | 78 | ax0.pcolormesh(X, Y, Z, vmin=Z.min(), vmax=Z.max(), cmap=plt.get_cmap('nipy_spectral')) 79 | #ax0.contour(X, Y, Z, vmin=Z.min(), vmax=Z.max(), colors="gray") 80 | 81 | ax0.set_aspect(1.0) 82 | 83 | def G(m): 84 | return 0. # fake theory 85 | def logrhod(d): 86 | return 0. # no data misfit 87 | def logrhom(m): 88 | return f(m) # fake prior pdf = the function to maximize 89 | 90 | plt.sca(ax0) 91 | models, datas, llks = neldermead(np.asarray([0., 0.]), 92 | DM=1., 93 | G=G, 94 | ND=1, 95 | logRHOD=logrhod, 96 | logRHOM=logrhom, 97 | alpha=1.5, 98 | beta=0.5, 99 | gamma=2.0, 100 | interrupt=1e-3) 101 | 102 | ax0.plot(models[:, 0], models[:, 1], 'w') 103 | ax1.plot(llks, "ks") 104 | """ 105 | print(models) 106 | print(datas) 107 | print(llks) 108 | 109 | for n, (Mi, llki, (Mis, Dis, llks)) in enumerate(g): 110 | xtri = np.concatenate((Mis[0, :], [Mis[0, 0]])) 111 | ytri = np.concatenate((Mis[1, :], [Mis[1, 0]])) 112 | ax0.plot(xtri, ytri, "w") 113 | ax0.plot(Mi[0], Mi[1], "k.") 114 | ax1.plot(n, llki, "ko") 115 | 116 | print(Mi[0], Mi[1]) 117 | ax0.plot(Mi[0], Mi[1], "g*") 118 | ax1.plot(n, llki, "g*") 119 | ax1.grid(True) 120 | """ 121 | 122 | showme() 123 | 124 | 125 | test2D() 126 | -------------------------------------------------------------------------------- /srfpython/sensitivitykernels/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obsmax/srfpython/4e3c4e0effca909174b824d0608cee1371404f0e/srfpython/sensitivitykernels/__init__.py -------------------------------------------------------------------------------- /srfpython/standalone/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obsmax/srfpython/4e3c4e0effca909174b824d0608cee1371404f0e/srfpython/standalone/__init__.py -------------------------------------------------------------------------------- /srfpython/standalone/asciifile.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from numpy import array, zeros, ones #needed for eval 3 | 4 | """ 5 | an object to manage ascii files with data, metadata with different types 6 | """ 7 | 8 | 9 | demo=""" 10 | #demonstration file 11 | #comments order will not be preserved 12 | #indicate metadata with key word #met 13 | 14 | #met a="array([1])" 15 | #met b=array([1]) 16 | #met c=124.2 17 | #met d=[1,2,3] 18 | 19 | #indicate the field names, units and formating using #fld, #unt and #fmt respectively 20 | #fld FIELD1 FIELD2 FIELD3 21 | #unt km - - 22 | #fmt %.0f %1s %10s 23 | 1. A lklkj 24 | 2. B 123 25 | 26 | 3. C kqklj 27 | """ 28 | 29 | 30 | class AsciiFile_fromstring(object): 31 | 32 | def __init__(self, string): 33 | self.metadata = {} #dictionnary with metadata evaluated from ascii file 34 | self.data = None #structured array, see https://docs.scipy.org/doc/numpy-1.13.0/user/basics.rec.html 35 | self.fields = None 36 | self.formats = None 37 | self.fmtline = "" 38 | self.units = None 39 | self.comments = [] 40 | dtype = None 41 | for l in string.split('\n'): 42 | l = l.strip() 43 | if l == "": continue 44 | elif l.startswith("#"): 45 | if l.startswith("#met"): 46 | l = l.lstrip('#met').split('#')[0] 47 | #key, value = [_.strip() for _ in l.split('=')] 48 | key = l.split('=')[0].strip() 49 | value = "=".join(l.split('=')[1:]) 50 | self.metadata[key] = eval(value) 51 | elif l.startswith('#fld'): 52 | self.fields = np.asarray(l.lstrip("#fld").split(), str) 53 | self.M = len(self.fields) 54 | elif l.startswith('#unt'): 55 | self.units = np.asarray(l.lstrip("#unt").split(), str) 56 | elif l.startswith('#fmt'): 57 | self.formats = np.asarray(l.lstrip("#fmt").split(), str) 58 | self.fmtline = l.replace('#fmt', " ") 59 | self.types = np.empty(len(self.formats), object) 60 | for n, fmt in enumerate(self.formats): 61 | if fmt.endswith('s'): 62 | self.types[n] = "U100" 63 | elif fmt.endswith('f'): 64 | self.types[n] = float 65 | elif fmt.endswith('d'): 66 | self.types[n] = int 67 | else: 68 | raise Exception('unknown column format %s' % fmt) 69 | else: 70 | self.comments.append(l) 71 | 72 | else: 73 | assert self.fields is not None 74 | assert self.formats is not None 75 | dtype = [_ for _ in zip(self.fields, self.types)] 76 | values = tuple(l.split('#')[0].split()) 77 | assert len(values) == self.M 78 | if self.data is None: 79 | self.data = [values] 80 | else: 81 | self.data.append(values) 82 | self.data = np.array(self.data, dtype=dtype) 83 | 84 | def __len__(self): 85 | return len(self.data) 86 | 87 | def __str__(self): 88 | out = "" 89 | if len(self.comments): 90 | out += "\n".join(self.comments) + "\n" 91 | for k, v in self.metadata.items(): 92 | if isinstance(v, str): 93 | out += "#met %s = '%s'\n" % (k, str(v)) 94 | else: 95 | out += "#met %s = %s\n" % (k, str(v)) 96 | out += "#fld " + " ".join(self.fields) + "\n" 97 | out += "#unt " + " ".join(self.units) + "\n" 98 | out += "#fmt " + self.fmtline.lstrip() + "\n" 99 | for i, line in enumerate(self.data): 100 | out += self.fmtline % tuple(line) + "\n" 101 | return out 102 | 103 | def write(self, filename=None): 104 | if filename is None: 105 | print(self.__str__()) 106 | else: 107 | with open(filename, 'w') as fid: 108 | fid.write(self.__str__()) 109 | 110 | def __getitem__(self, item): 111 | if isinstance(item, str): 112 | "item is a field name, return the column" 113 | return self.data[item] 114 | elif isinstance(item, int): 115 | "item is a row number, return the line" 116 | return self.data[item] 117 | raise IndexError('indexing with object of type %s is not implemented' % str(type(item))) 118 | 119 | 120 | class AsciiFile(AsciiFile_fromstring): 121 | def __init__(self, filename): 122 | with open(filename, 'r') as fid: 123 | string = "".join(fid.readlines()) 124 | AsciiFile_fromstring.__init__(self, string) 125 | 126 | 127 | if __name__ == "__main__": 128 | a = AsciiFile_fromstring(demo) 129 | print(a.metadata) 130 | print("---") 131 | print(a.data) 132 | print("---") 133 | print(a) 134 | 135 | -------------------------------------------------------------------------------- /srfpython/standalone/display.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from matplotlib import _pylab_helpers, ticker, __version__ as matplotlibversion 3 | from matplotlib.offsetbox import AnchoredText 4 | import numpy as np 5 | 6 | # ################################################ 7 | gcf = plt.gcf 8 | gca = plt.gca 9 | 10 | 11 | # ______________________________________________ 12 | def pause(message="pause : press enter"): 13 | input(message) 14 | 15 | 16 | # ______________________________________________ 17 | def gcfs(): 18 | "get current figures" 19 | return [w.canvas.figure for w in _pylab_helpers.Gcf.get_all_fig_managers()] 20 | 21 | 22 | # ______________________________________________ 23 | def showme(block=True): 24 | figures = gcfs() 25 | for figure in figures: 26 | figure.canvas.draw() 27 | figure.show() 28 | #if block: pause() # < was needed in HerrMet --manage --display to loop over figures 29 | if block: plt.show() # TODO : find a solution that works for all cases 30 | 31 | 32 | # ______________________________________________ 33 | def chftsz(obj, fontsize): 34 | "recursively change fontsize of an object including all its childrens" 35 | if hasattr(obj, "get_children"): 36 | for subobj in obj.get_children(): 37 | chftsz(subobj, fontsize) 38 | if hasattr(obj, "set_fontsize"): 39 | obj.set_fontsize(fontsize) 40 | 41 | 42 | # ################################################ tickers 43 | def logtick(ax, axis='x', grid = True, color = "k", subs = [1., 2., 5.]): 44 | 45 | if matplotlibversion < "1.2": 46 | print("ERROR : logtick doesn't work with maptplotlib < 1.2") 47 | return 48 | 49 | def myfuncformatter(tick, tickposition=None): 50 | s = "%.6f" % tick 51 | if "." in s: s = s.rstrip('0').rstrip('.') 52 | return s 53 | 54 | for letter in axis: 55 | major_locator = ticker.LogLocator(base=10., subs=subs) 56 | major_formatter = ticker.FuncFormatter(myfuncformatter) 57 | 58 | minor_locator = ticker.LogLocator(base=10., subs=[3., 4., 6., 7., 8., 9.]) 59 | minor_formatter = ticker.NullFormatter() 60 | 61 | if 'x' == letter.lower(): 62 | ax.xaxis.set_major_locator(major_locator) 63 | ax.xaxis.set_major_formatter(major_formatter) 64 | ax.xaxis.set_minor_locator(minor_locator) 65 | ax.xaxis.set_minor_formatter(minor_formatter) 66 | if 'y' == letter.lower(): 67 | ax.yaxis.set_major_locator(major_locator) 68 | ax.yaxis.set_major_formatter(major_formatter) 69 | ax.yaxis.set_minor_locator(minor_locator) 70 | ax.yaxis.set_minor_formatter(minor_formatter) 71 | 72 | if grid: 73 | ax.grid(True, which="major", color=color, linestyle=":") 74 | ax.grid(True, which="minor", color=color, linestyle=":") 75 | 76 | 77 | # ______________________________________________ 78 | def Ntick(ax, N, axis="xy"): 79 | if "x" in axis: 80 | ax.xaxis.set_major_locator(ticker.MaxNLocator(nbins=N)) 81 | if "y" in axis: 82 | ax.yaxis.set_major_locator(ticker.MaxNLocator(nbins=N)) 83 | 84 | 85 | # ################################################ colors 86 | def value2color(value, vmin=0., vmax=1.0, cmap = plt.cm.jet): 87 | index = int(np.floor(cmap.N * (value - vmin) / (vmax - vmin))) 88 | return np.array(cmap(index)[:3]) 89 | 90 | 91 | # ______________________________________________ 92 | def values2colors(values, vmin=0., vmax=1.0, cmap = plt.cm.jet): 93 | indexs = np.floor(cmap.N * (values - vmin) / (vmax - vmin)) 94 | indexs = np.array(indexs, int) 95 | return np.array([cmap(index)[:3] for index in indexs]) 96 | 97 | 98 | # ______________________________________________ 99 | def makecolorbar(vmin, vmax, cmap=None): 100 | if cmap is None: 101 | cmap = plt.get_cmap('jet') 102 | cb = plt.cm.ScalarMappable(norm=None, cmap=cmap) 103 | cb.set_array([vmin, vmax]) 104 | cb.set_clim((vmin, vmax)) 105 | return cb 106 | 107 | # ______________________________________________ 108 | def legendtext(ax, txt, fontsize = 14, loc = 2, multialignment = "left", frameon=True, framealpha=0.5, **kwargs): 109 | "create a legend with text only" 110 | at = AnchoredText(txt, 111 | prop=dict(size=fontsize, multialignment = multialignment, **kwargs), 112 | frameon=frameon, 113 | loc=loc) 114 | at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2") 115 | at.patch.set_alpha(framealpha) 116 | ax.add_artist(at) 117 | return at 118 | 119 | 120 | # _____________________________________ 121 | def textonly(ax, txt, fontsize = 14, loc = 2, multialignment = "left", frameon=True, framealpha=0.5, **kwargs): 122 | "create a legend with text only" 123 | at = AnchoredText(txt, 124 | prop=dict(size=fontsize, multialignment = multialignment, **kwargs), 125 | frameon=frameon, 126 | loc=loc) 127 | at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2") 128 | at.patch.set_alpha(framealpha) 129 | ax.add_artist(at) 130 | return at 131 | 132 | -------------------------------------------------------------------------------- /srfpython/standalone/memtest.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from srfpython.standalone.multipro8 import * 3 | 4 | # shared variable (read only) 5 | bigone = np.ones(1024 ** 3 // 8, float) # 1Gb array 6 | 7 | 8 | def jobgen(): 9 | for i in range(10): 10 | yield Job(i) 11 | 12 | 13 | def fun(i): 14 | # use bigone in readonly without passing it to fun as input 15 | # => the array is shared between all processes 16 | 17 | # this does not work if bigone is modified inside this function 18 | 19 | print(">", bigone[:10]) 20 | start = time.time() 21 | while time.time() - start < 2.: 22 | 0. + 0. 23 | return i 24 | 25 | 26 | with MapAsync(fun, jobgen(), Nworkers=10) as ma: 27 | list(ma) 28 | 29 | 30 | -------------------------------------------------------------------------------- /srfpython/standalone/printcolors.py: -------------------------------------------------------------------------------- 1 | class bcolors: 2 | "source : http://stackoverflow.com/questions/287871/print-in-terminal-with-colors-using-python" 3 | HEADER = '\033[95m' 4 | OKBLUE = '\033[94m' 5 | OKGREEN = '\033[92m' 6 | WARNING = '\033[93m' 7 | FAIL = '\033[91m' 8 | ENDC = '\033[0m' 9 | BOLD = '\033[1m' 10 | UNDERLINE = '\033[4m' 11 | 12 | def printpurple(*args): 13 | for l in args: 14 | print("%s%s%s" % (bcolors.HEADER, l, bcolors.ENDC), '\n') 15 | 16 | def printblue(*args): 17 | for l in args: 18 | print("%s%s%s" % (bcolors.OKBLUE, l, bcolors.ENDC), '\n') 19 | 20 | def printgreen(*args): 21 | for l in args: 22 | print("%s%s%s" % (bcolors.OKGREEN, l, bcolors.ENDC), '\n') 23 | 24 | def printyellow(*args): 25 | for l in args: 26 | print("%s%s%s" % (bcolors.WARNING, l, bcolors.ENDC), '\n') 27 | 28 | def printred(*args): 29 | for l in args: 30 | print("%s%s%s" % (bcolors.FAIL, l, bcolors.ENDC), '\n') 31 | 32 | def printbold(*args): 33 | for l in args: 34 | print("%s%s%s" % (bcolors.BOLD, l, bcolors.ENDC), '\n') 35 | 36 | def printunderline(*args): 37 | for l in args: 38 | print("%s%s%s" % (bcolors.UNDERLINE, l, bcolors.ENDC), '\n') 39 | -------------------------------------------------------------------------------- /srfpython/standalone/readme.txt: -------------------------------------------------------------------------------- 1 | 17-02-2018, ML 2 | 3 | these are components of tetedenoeud 4 | copied locally to allow srfpython to stand alone 5 | tetedenoeud may continue evolving -------------------------------------------------------------------------------- /srfpython/synthetics/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obsmax/srfpython/4e3c4e0effca909174b824d0608cee1371404f0e/srfpython/synthetics/__init__.py -------------------------------------------------------------------------------- /srfpython/synthetics/signalfuncs.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy.signal import detrend as scipydetrend 3 | from scipy.fftpack import fft, ifft, fftfreq 4 | from scipy.signal import iirfilter, sosfilt, zpk2sos 5 | 6 | def detrend(data): 7 | return scipydetrend(data, type="linear") 8 | 9 | 10 | def taperwidth(data, sampling_rate, width): 11 | tap = np.ones_like(data) 12 | Nwidth = int(np.round(width * sampling_rate)) 13 | if not Nwidth : return tap 14 | 15 | t = np.arange(len(data)) / sampling_rate 16 | ttap = 0.5 * (np.sin(np.pi * t[:Nwidth] / float(width) / 1.0 + np.pi / 2.0) + 1.) 17 | tap[:Nwidth] *= ttap[::-1] 18 | tap[-Nwidth:] *= ttap 19 | return tap 20 | 21 | 22 | def gaussbandpass(data, sampling_rate, fcenter, alpha): 23 | npts = len(data) 24 | dt = 1. / sampling_rate 25 | 26 | nu = fftfreq(npts, dt) 27 | G = np.exp(-alpha * (np.abs(nu) / fcenter - 1.) ** 2.) 28 | return np.real(ifft(fft(data) * G)) 29 | 30 | 31 | def bandpass(data, sampling_rate, freqmin, freqmax, corners=4, zerophase=True): 32 | """modified after obspy 33 | """ 34 | fe = 0.5 * sampling_rate 35 | low = freqmin / fe 36 | high = freqmax / fe 37 | # raise for some bad scenarios 38 | if high - 1.0 > -1e-6: 39 | msg = ("Selected high corner frequency ({}) of bandpass is at or " 40 | "above Nyquist ({})").format( 41 | freqmax, fe) 42 | raise ValueError(msg) 43 | if low > 1: 44 | msg = "Selected low corner frequency is above Nyquist." 45 | raise ValueError(msg) 46 | z, p, k = iirfilter(corners, [low, high], btype='band', 47 | ftype='butter', output='zpk') 48 | sos = zpk2sos(z, p, k) 49 | if zerophase: 50 | firstpass = sosfilt(sos, data) 51 | return sosfilt(sos, firstpass[::-1])[::-1] 52 | else: 53 | return sosfilt(sos, data) 54 | -------------------------------------------------------------------------------- /srfpython/synthetics/synthetics.py: -------------------------------------------------------------------------------- 1 | from srfpython.depthdisp.dispcurves import Claw, freqspace 2 | from scipy.fftpack import fftfreq, fft, ifft 3 | from signalfuncs import detrend, taperwidth, gaussbandpass, bandpass 4 | import numpy as np 5 | 6 | raise Exception('see synthetics2') 7 | # --------------------------------------- 8 | class Green(object): 9 | """ 10 | simplistic greens function in a 1D elastic dispersive model 11 | ** account only for the phase dispersion and the gemoetrical spreading of 12 | a mono modal surface wave 13 | """ 14 | def __init__(self, claw, fmin=0.2, fmax=5., order=4.0, dt=1. / 12.): 15 | """ 16 | :param claw: Claw object, phase velocity dispersion laws 17 | :param fmin: lower frequency for butterworth or central freq for gaussian bandpass, (Hz) 18 | :param fmax: upper frequency for butterworth or central freq for gaussian bandpass, (Hz) 19 | :param order: filter order for butterworth or gaussian bandpass 20 | :param dt: sampling interval (s) 21 | """ 22 | self.c = claw # 23 | self.fmin = fmin # 0.2 24 | self.fmax = fmax # 5. 25 | self.order = order # 4. 26 | self.dt = dt # 1. / 12. 27 | 28 | assert self.fmax <= 0.5 / self.dt # nyquist criterion 29 | if self.fmin < self.fmax: 30 | f = freqspace(self.fmin, self.fmax, 100, 'flog') 31 | c = self.c(f) 32 | self.cmin, self.cmax = np.min(c), np.max(c) 33 | else: 34 | self.cmin = self.cmax = self.c(self.fmin) 35 | 36 | # ---------------------------- 37 | def __call__(self, ts, xs, ys, xr, yr): 38 | """ 39 | compute synthetic waveform 40 | :param ts: source time, s 41 | :param xs: source x coordinate, km 42 | :param ys: source y coordinate, km 43 | :param xr: receiver x coordinate, km 44 | :param yr: receiver y coordinate, km 45 | :return starttime: starttime of the trace in s 46 | :return npts: number of samples in the trace 47 | :return dt: sampling interval (s) 48 | :return y: data array 49 | """ 50 | distance = ((xs - xr) ** 2. + (ys - yr) ** 2.) ** 0.5 51 | tmin = np.round(distance / self.cmax - 3. / self.fmin) 52 | tmax = distance / self.cmin + 3. / self.fmin 53 | npts = int(np.ceil((tmax - tmin) / self.dt)) 54 | 55 | starttime = ts + tmin 56 | nu = fftfreq(npts, self.dt) 57 | c = self.c(nu) 58 | I = ~np.isnan(c) 59 | Y = np.zeros(len(nu), complex) 60 | Y[I] = np.exp(-2.j * np.pi * nu[I] * (distance / c[I] - tmin)) 61 | Y /= np.sqrt(distance) # geometrical spreading 62 | y = np.real(ifft(Y)) 63 | 64 | y = detrend(y) 65 | y *= taperwidth(y, 1. / self.dt, 3. / self.fmin) 66 | if self.fmin == self.fmax: 67 | # gaussian bandpass 68 | y = gaussbandpass(y, 1. / self.dt, self.fmin, self.order) 69 | else: 70 | # bandpass 71 | y = bandpass(y, 1. / self.dt, self.fmin, self.fmax, self.order, True) 72 | 73 | return starttime, npts, self.dt, y 74 | 75 | 76 | if __name__ == "__main__": 77 | from srfpython.standalone.display import * 78 | from testlaws import c0, c1, c2, c3 79 | 80 | G0 = Green(c0, fmin=0.2, fmax=2., order=4.0, dt=1. / 12.) 81 | 82 | ts, xs, ys = 0., 0., 0. 83 | for xr in np.arange(1., 20., .25): 84 | yr = 0. 85 | starttime, npts, dt, y = G0(ts, xs, ys, xr, yr) 86 | d = np.sqrt((xs - xr) ** 2. + (ys - yr) ** 2.) 87 | t = starttime + np.arange(npts) * dt 88 | gca().plot(t, 4. * y + d, "k", alpha=.3) 89 | gca().set_xlabel('time (s)') 90 | gca().set_ylabel('distance (km)') 91 | showme() -------------------------------------------------------------------------------- /srfpython/synthetics/testlaws.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from srfpython.depthdisp.dispcurves import mklaws, igroupbywtm 3 | from srfpython.depthdisp.depthmodels import depthmodel_from_arrays 4 | from srfpython.Herrmann.Herrmann import HerrmannCaller, Curve 5 | 6 | # depth model 7 | ztop = [0.00, 0.25, 0.45, 0.65, 0.85, 1.05, 1.53, 1.80] # km, top layer depth 8 | vp = [1.85, 2.36, 2.63, 3.15, 3.71, 4.54, 5.48, 5.80] # km/s 9 | vs = [0.86, 1.10, 1.24, 1.47, 1.73, 2.13, 3.13, 3.31] # km/s 10 | rh = [2.47, 2.47, 2.47, 2.47, 2.47, 2.58, 2.58, 2.63] # g/cm3 11 | 12 | dm = depthmodel_from_arrays(ztop, vp, vs, rh) 13 | 14 | # dipsersion parameters 15 | # f = np.logspace(np.log10(0.1), np.log10(500.), 100) # frequency array, km/s : ERROR : example of missing modes as reported by Herrmann !!!!! 16 | f = np.logspace(np.log10(0.1), np.log10(10.), 100) # frequency array, km/s 17 | 18 | # dispersion curves 19 | curves = [Curve(wave='R', type='C', mode=0, freqs=f), 20 | Curve(wave='R', type='C', mode=1, freqs=f), 21 | Curve(wave='R', type='C', mode=2, freqs=f), 22 | Curve(wave='R', type='C', mode=3, freqs=f), 23 | Curve(wave='R', type='C', mode=4, freqs=f), 24 | Curve(wave='R', type='C', mode=5, freqs=f), 25 | Curve(wave='R', type='C', mode=6, freqs=f)] 26 | 27 | # compute dispersion laws 28 | #Waves, Types, Modes, Freqs = zip(*curves) 29 | #waves, types, modes, freqs = igroupbywtm(Waves, Types, Modes, Freqs) 30 | hc = HerrmannCaller(curves) 31 | #values = dispersion(ztop, vp, vs, rh, waves, types, modes, freqs) 32 | values = hc.disperse(ztop, vp, vs, rh) 33 | laws = mklaws(hc.waves, hc.types, hc.modes, hc.freqs, values, dvalues=None) 34 | c0, c1, c2, c3 = laws[:4] 35 | 36 | if __name__ == "__main__": 37 | from srfpython import * 38 | 39 | plt.figure() 40 | dm.show(gca()) 41 | plt.legend() 42 | 43 | plt.figure() 44 | for law in laws: 45 | law.show(gca(), period=True) 46 | plt.legend() 47 | showme() -------------------------------------------------------------------------------- /srfpython/testbox/default_params.sh: -------------------------------------------------------------------------------- 1 | 2 | HerrMet --param 3 5. -t mZVSPRRH -op ; mv _HerrMet.param 1.param 3 | HerrMet --param 3 5. -t mZVSVPRH -op ; mv _HerrMet.param 2.param 4 | HerrMet --param 3 5. -t mZVSPRzRHvp -op ; mv _HerrMet.param 3.param 5 | HerrMet --param 3 5. -t mZVSPRzRHz -op ; mv _HerrMet.param 4.param 6 | HerrMet --param 3 5. -t mZVSVPvsRHvp -op ; mv _HerrMet.param 5.param 7 | 8 | -------------------------------------------------------------------------------- /srfpython/testbox/performance.prof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obsmax/srfpython/4e3c4e0effca909174b824d0608cee1371404f0e/srfpython/testbox/performance.prof -------------------------------------------------------------------------------- /srfpython/testbox/performance.py: -------------------------------------------------------------------------------- 1 | from srfpython.Herrmann.Herrmann import HerrmannCaller, Curve 2 | import numpy as np 3 | 4 | nlayer = 10 5 | nfreq = 30 6 | ztop = np.linspace(0., 3., nlayer) 7 | vs = np.linspace(1., 3.5, nlayer) 8 | vp = 1.73 * vs 9 | rh = np.linspace(2.5, 3.1, nlayer) 10 | f = np.logspace(-1, 1, nfreq) 11 | 12 | curves = [Curve(wave="R", type="C", mode=0, freqs=f), 13 | Curve(wave="R", type="U", mode=0, freqs=f), 14 | Curve(wave="L", type="C", mode=0, freqs=f), 15 | Curve(wave="L", type="U", mode=0, freqs=f)] 16 | 17 | hc = HerrmannCaller(curves=curves, h=0.005, ddc=0.005) 18 | 19 | for _ in range(100): 20 | hc.disperse(ztop, vp, vs, rh) 21 | -------------------------------------------------------------------------------- /srfpython/testbox/tester.py: -------------------------------------------------------------------------------- 1 | from srfpython import * 2 | 3 | for i in range(10): 4 | ztop = np.sort(np.unique(np.random.rand(10) * 3.)) 5 | ztop[0] = 0. 6 | 7 | vp = np.linspace(1., 5., len(ztop)) 8 | pr = np.linspace(2.15, 1.8, len(ztop)) 9 | rh = np.linspace(2., 3., len(ztop)) 10 | vs = vp / pr 11 | 12 | dm = depthmodel_from_arrays(ztop, vp, vs, rh) 13 | dm.show(gca()) 14 | dm.write96('%03d.mod96' % i) 15 | 16 | Curves = [('R', 'U', 0, freqspace(.2, 1., 15, "log"))] #, \ 17 | # ('R', 'U', 1, freqspace(.2, 1., 15, "log")), \ 18 | # ('L', 'U', 0, freqspace(.2, 1., 15, "log")), \ 19 | # ('L', 'U', 1, freqspace(.2, 1., 15, "log"))] 20 | 21 | waves, types, modes, freqs, values = [[] for _ in range(5)] 22 | for w, t, m, F, V in dispersion_2(ztop, vp, vs, rh, Curves, 23 | h=0.005, dcl=0.005, dcr=0.005, keepnans=False): 24 | 25 | waves = np.concatenate((waves, np.array([w]).repeat(len(F)))) 26 | types = np.concatenate((types, np.array([t]).repeat(len(F)))) 27 | modes = np.concatenate((modes, np.array([m]).repeat(len(F)))) 28 | freqs = np.concatenate((freqs, F)) 29 | values = np.concatenate((values, V)) 30 | 31 | s = surf96reader_from_arrays(waves, types, modes, freqs, values) 32 | s.write96('%03d.surf96' % i) 33 | 34 | -------------------------------------------------------------------------------- /srfpython/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "3.2.0" 2 | 3 | -------------------------------------------------------------------------------- /test/test_pyfiles.py: -------------------------------------------------------------------------------- 1 | """ 2 | Script used to convert all files from python2 to python 3, Pierric Mora 2024 3 | Walks the srfpython/ directory and executes all .py files 4 | """ 5 | raise Exception('security (A lot of files need to be cleaned up first), TODO: move to pytest') 6 | import os 7 | import subprocess 8 | 9 | srfpython_dir = '../srfpython/' 10 | ignore = ('testbox/tester.py', 'synthetics/synthetics.py') 11 | 12 | for root, dirs, files in os.walk(srfpython_dir): 13 | pyfiles = filter(lambda s: s.endswith('.py'), files) 14 | pyfiles = filter(lambda s: all((not(s in skipped) for skipped in ignore)), pyfiles) 15 | for f in pyfiles: 16 | fpath = os.path.join(root, f) 17 | print(f'##########\n#####\n# executing {fpath}...') 18 | r = subprocess.run(('python3', fpath)) 19 | r.check_returncode() 20 | 21 | # clear outpus 22 | subprocess.run(('rm', '-f', '000.mod96', '_HerrMet.param', 'toto.bdd')) 23 | -------------------------------------------------------------------------------- /test/test_tutorials.py: -------------------------------------------------------------------------------- 1 | """ 2 | Script used to convert all files from python2 to python 3, Pierric Mora 2024 3 | Walks the srfpython/ directory and executes all .py files 4 | """ 5 | 6 | import os 7 | import subprocess 8 | 9 | tuto_dir = '../tutorials' 10 | 11 | to_test = ['00_simple_dispersion_example/00_using_scripts/main_script.sh', 12 | '00_simple_dispersion_example/01_using_python_programs/000_create_dephmodel.py', 13 | '00_simple_dispersion_example/01_using_python_programs/001_forward_dispersion.py', 14 | '00_simple_dispersion_example/02_1d_sensitivity_kernel.py', 15 | '01_simple_inversion_example/main_script.sh', 16 | '02_acoustic_scale_inversion_example/main_script.sh', 17 | '03_cube_inversion_example/main_script.sh', 18 | '10_notebooks/00_how_to_use_srfpython.ipynb' 19 | ] 20 | 21 | ignore = ('03_cube_inversion_example', ) 22 | 23 | to_test = filter(lambda s: all((not(skip in s) for skip in ignore)), to_test) 24 | 25 | CWD = os.getcwd() 26 | 27 | for f in to_test: 28 | fpath = os.path.join(tuto_dir, f) 29 | fdir = os.path.dirname(fpath) 30 | fname = os.path.basename(fpath) 31 | os.chdir(fdir) 32 | print(f'##########\n#####\n# executing {fpath}...') 33 | if fpath.endswith('.py'): 34 | r = subprocess.run(('python3', fname)) 35 | elif fpath.endswith('.sh'): 36 | r = subprocess.run(('bash', fname)) 37 | elif fpath.endswith('.ipynb'): 38 | r = subprocess.run(('jupyter', 'nbconvert', '--execute', fname, '--to', 'html')) 39 | r.check_returncode() 40 | os.chdir(CWD) 41 | 42 | # clear outpus 43 | # subprocess.run(('rm', '-f', '000.mod96', '_HerrMet.param', 'toto.bdd')) 44 | -------------------------------------------------------------------------------- /tutorials/00_simple_dispersion_example/00_using_scripts/000_create_model.py: -------------------------------------------------------------------------------- 1 | from srfpython import * 2 | 3 | # ----------------------- 4 | # create 1-D depth model using 4 arrays with same length 5 | # ----------------------- 6 | # top layers array first at 0, positive, growing, km 7 | ztop = np.linspace(0., 2.8, 50) 8 | 9 | # vs in km/s 10 | vs = (3.5 - .86) / (ztop[-1] - ztop[0]) * (ztop - 0.) + .86 + \ 11 | -.7 * np.exp(-ztop / .1) + \ 12 | .08 * np.cos(2. * np.pi * ztop / .5) + \ 13 | .2 * np.sin(2. * np.pi * ztop / 1.) + \ 14 | .1 * np.cos(2. * np.pi * ztop / 2.) + \ 15 | .15 * np.cos(2. * np.pi * ztop / 3.) 16 | 17 | vp, rh = brocher2005(vs) 18 | 19 | # create the depthmodel object, use a subclass that is to be intitiated with arrays 20 | # see also depthmodel, depthmodel1D, depthmodel_from_mod96, ... 21 | dm = depthmodel_from_arrays(ztop, vp, vs, rh) 22 | 23 | # __str__ returns the file content at mod96 format, (see Herrmann CPS documentation) 24 | print(dm) 25 | 26 | dm.write96('model000.mod96') 27 | -------------------------------------------------------------------------------- /tutorials/00_simple_dispersion_example/00_using_scripts/001_show.sh: -------------------------------------------------------------------------------- 1 | m96 --show model000.mod96 2 | -------------------------------------------------------------------------------- /tutorials/00_simple_dispersion_example/00_using_scripts/010_dispers.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | m96 --disp ./model000.mod96 \ 4 | -RU0 .2 2. 20 plog \ 5 | -RU1 .2 2. 20 plog \ 6 | -RC0 .2 2. 20 plog \ 7 | -RC1 .2 2. 20 plog \ 8 | -save 9 | mv model000.surf96 data010.surf96 10 | 11 | -------------------------------------------------------------------------------- /tutorials/00_simple_dispersion_example/00_using_scripts/011_show.sh: -------------------------------------------------------------------------------- 1 | s96 --show data010.surf96 2 | -------------------------------------------------------------------------------- /tutorials/00_simple_dispersion_example/00_using_scripts/main_script.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## simple example on how to compute dispersion curves in a 1d model 4 | # run the following command in a terminal (under the right env) 5 | 6 | # python script to generate a 1d depth model 7 | python3 000_create_model.py 8 | 9 | # display 10 | bash 001_show.sh 11 | 12 | # compute the dispersion curve 13 | bash 010_dispers.sh 14 | 15 | # display the resulting curves 16 | bash 011_show.sh 17 | 18 | -------------------------------------------------------------------------------- /tutorials/00_simple_dispersion_example/01_using_python_programs/000_create_dephmodel.py: -------------------------------------------------------------------------------- 1 | from srfpython import * 2 | 3 | # ----------------------- 4 | # create 1-D depth model using 4 arrays with same length 5 | # ----------------------- 6 | # top layers array first at 0, positive, growing, km 7 | ztop = np.linspace(0., 2.8, 50) 8 | 9 | # vs in km/s 10 | vs = (3.5 - .86) / (ztop[-1] - ztop[0]) * (ztop - 0.) + .86 + \ 11 | -.7 * np.exp(-ztop / .1) + \ 12 | .08 * np.cos(2. * np.pi * ztop / .5) + \ 13 | .2 * np.sin(2. * np.pi * ztop / 1.) + \ 14 | .1 * np.cos(2. * np.pi * ztop / 2.) + \ 15 | .15 * np.cos(2. * np.pi * ztop / 3.) 16 | 17 | vp, rh = brocher2005(vs) 18 | 19 | # create the depthmodel object, use a subclass that is to be intitiated with arrays 20 | # see also depthmodel, depthmodel1D, depthmodel_from_mod96, ... 21 | dm = depthmodel_from_arrays(ztop, vp, vs, rh) 22 | 23 | # __str__ returns the file content at mod96 format, (see Herrmann CPS documentation) 24 | print(dm) 25 | 26 | dm.write96('model000.mod96') 27 | -------------------------------------------------------------------------------- /tutorials/00_simple_dispersion_example/01_using_python_programs/001_forward_dispersion.py: -------------------------------------------------------------------------------- 1 | # ----------------------- 2 | # import all components of srfpython 3 | # ----------------------- 4 | from srfpython import * 5 | 6 | # ----------------------- 7 | # load a 1-D depth model created by 000_create_dephmodel.py 8 | # ----------------------- 9 | dm = depthmodel_from_mod96('./model000.mod96') 10 | 11 | 12 | # __str__ returns the file content at mod96 format, (see Herrmann CPS documentation) 13 | print(dm) 14 | 15 | # ----------------------- 16 | # compute dispersion curves from the depthmodel above 17 | # ----------------------- 18 | 19 | # define the dipsersion curves to compute 20 | f = freqspace(0.2, 3.5, 35, "log") 21 | curves = [Curve(wave='R', type='U', mode=0, freqs=f), 22 | Curve(wave='R', type='U', mode=1, freqs=f), 23 | Curve(wave='R', type='C', mode=0, freqs=f), 24 | Curve(wave='R', type='C', mode=1, freqs=f), 25 | Curve(wave='L', type='U', mode=0, freqs=f), 26 | Curve(wave='L', type='U', mode=1, freqs=f), 27 | Curve(wave='L', type='C', mode=0, freqs=f), 28 | Curve(wave='L', type='C', mode=1, freqs=f)] 29 | 30 | # compute dispersion curves and display 31 | hc = HerrmannCaller(curves=curves) 32 | curves_out = hc( 33 | ztop=dm.vp.z, 34 | vp=dm.vp.values, 35 | vs=dm.vs.values, 36 | rh=dm.rh.values, 37 | keepnans=False) 38 | 39 | fig = plt.figure() 40 | ax = fig.add_subplot(111, xscale="log", yscale="log") 41 | for curve in curves_out: 42 | curve.plot(ax, "+-") 43 | 44 | logtick(ax, "xy") 45 | ax.set_title('figure 2 : Herrmann.py demo') 46 | 47 | plt.legend() 48 | plt.show() 49 | -------------------------------------------------------------------------------- /tutorials/00_simple_dispersion_example/02_1d_sensitivity_kernel.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | from srfpython.depthdisp.depthmodels import depthmodel_from_arrays 5 | from srfpython.sensitivitykernels.sker17 import sker17_1 6 | 7 | """ 8 | python script to compute depth sensitivity kernels 9 | """ 10 | 11 | 12 | # ================== build a 1d velocity model 13 | ztop = np.arange(0., 30., 1.) # top layer array, sorted, in km, 1st at 0.0 14 | vs = np.linspace(1.8, 4.0, len(ztop)) # Vs in each layer from top to half space, km/s 15 | vp = 1.73 * vs # Vp in each layer, km/s 16 | rh = 2.67 * np.ones_like(vs) # Density in each layer g/cm3 17 | 18 | # ================== compute sensitivity kernels for one wave type (RC0) 19 | norm = True # !!! recommended for non uniform layer model (try irregular ztop to see the difference) !!! 20 | generator = sker17_1(ztop, vp, vs, rh, 21 | Waves=["R"], # R=rayleigh 22 | Types=["C"], # C=phase velocity 23 | Modes=[0], # 0=fundamental mode 24 | Freqs=[[0.1, 0.2]], # frequencies at which to compute 1d kernels, in Hz 25 | norm=norm) 26 | 27 | # only one item here 28 | wave, type_, mode, freqs, DLOGVADZ, DLOGVADLOGVS, DLOGVADLOGPR, DLOGVADLOGRH = \ 29 | next(generator) 30 | 31 | # ================== display 32 | plt.figure() 33 | # depth model 34 | ax1 = plt.subplot(121) 35 | dm = depthmodel_from_arrays(ztop, vp, vs, rh) 36 | dm.show(ax1) 37 | ax1.grid(True) 38 | plt.legend() 39 | 40 | # kernels 41 | if norm: 42 | title = r'$ \frac{H}{H_i} \, \frac{d lnV_{{%s%s%d}}}{d lnVs} $' % (wave, type_, mode) 43 | else: 44 | title = r'$ \frac{d lnV_{{%s%s%d}}}{d lnVs} $' % (wave, type_, mode) 45 | 46 | ax2 = plt.subplot(122, sharey=ax1, title=title, xlabel="sensitivity") 47 | ax2.plot(DLOGVADLOGVS[:, 0], ztop, label="%s%s%d@%.2fHz" % (wave, type_, mode, freqs[0])) 48 | ax2.plot(DLOGVADLOGVS[:, 1], ztop, label="%s%s%d@%.2fHz" % (wave, type_, mode, freqs[1])) 49 | ax2.grid(True) 50 | plt.legend() 51 | # plt.ion() 52 | plt.show() 53 | # input('pause') 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/000_create_model.py: -------------------------------------------------------------------------------- 1 | from srfpython import * 2 | 3 | # ----------------------- 4 | # create 1-D depth model using 4 arrays with same length 5 | # ----------------------- 6 | # top layers array first at 0, positive, growing, km 7 | ztop = np.linspace(0., 2.8, 50) 8 | 9 | # vs in km/s 10 | vs = (3.5 - .86) / (ztop[-1] - ztop[0]) * (ztop - 0.) + .86 + \ 11 | -.7 * np.exp(-ztop / .1) + \ 12 | .08 * np.cos(2. * np.pi * ztop / .5) + \ 13 | .2 * np.sin(2. * np.pi * ztop / 1.) + \ 14 | .1 * np.cos(2. * np.pi * ztop / 2.) + \ 15 | .15 * np.cos(2. * np.pi * ztop / 3.) 16 | 17 | vp, rh = brocher2005(vs) 18 | 19 | # create the depthmodel object, use a subclass that is to be intitiated with arrays 20 | # see also depthmodel, depthmodel1D, depthmodel_from_mod96, ... 21 | dm = depthmodel_from_arrays(ztop, vp, vs, rh) 22 | 23 | # __str__ returns the file content at mod96 format, (see Herrmann CPS documentation) 24 | print(dm) 25 | 26 | dm.write96('model000.mod96') 27 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/001_show.sh: -------------------------------------------------------------------------------- 1 | m96 --show model000.mod96 2 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/002_sensitivity.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #rm -f model000.10m.mod96 4 | #m96 --split model000.mod96 -thck 0.01 -sfx 10m 5 | #m96 --show model000.50m.mod96 model000.mod96 6 | 7 | sker17 -m96 model000.mod96 \ 8 | -RU0 .2 2. 50 plog \ 9 | -RC0 .2 2. 50 plog \ 10 | -RU1 .2 2. 50 plog \ 11 | -png 12 | # -norm # use only for irregular depth sampling 13 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/010_dispers.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | m96 --disp ./model000.mod96 -RU0 .2 2. 20 plog -RU1 .2 2. 20 plog -save 4 | mv model000.surf96 data010.surf96 5 | 6 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/011_show.sh: -------------------------------------------------------------------------------- 1 | s96 --show data010.surf96 2 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/100_set_target.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | HerrMet --target data010.surf96 -lunc .1 -ot 3 | #HerrMet --target data010.surf96 -unc .1 -ot 4 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/101_show.sh: -------------------------------------------------------------------------------- 1 | HerrMet --display _HerrMet_data010 2 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/110_template_param.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | HerrMet --param 9 3. -t mZVSPRRH -op \ 3 | -dvp -.5 1.5 \ 4 | -dvs -.5 1.5 \ 5 | -drh -0. 1. \ 6 | -dpr -1.0 0. 7 | 8 | #--param i f generate a template parameter file to custom in . 9 | # need the number of layers and bottom depth in km 10 | # -basedon s build parametrization based on an existing mod96 file, require a filename, 11 | # if not specified, I take fixed values to build the parameter file 12 | # -t s parameterization type to use (['mZVSPRRH', 'mZVSVPRH', 'mZVSPRzRHvp', 'mZVSPRzRHz']), 13 | # default mZVSPRRH 14 | # mZVSPRRH = parameterize with 15 | # - depth interface (mZ1 = first interface, mZ2, ...), 16 | # - VS in each layer (VS0 = first layer, ...), 17 | # - VP/VS in each layer (PR0, PR1, ...), 18 | # - Density in each layer (RH0, RH1, ...) 19 | # mZVSVPRH = parameterize with 20 | # - depth interface (mZ1 = first interface, mZ2, ...), 21 | # - VS in each layer (VS0 = first layer, ...), 22 | # - VP in each layer (VP0, VP1, ...), 23 | # - Density in each layer (RH0, RH1, ...) 24 | # mZVSPRzRHvp = parameterize with 25 | # - depth interface (mZ1 = first interface, mZ2, ...), 26 | # - VS in each layer (VS0 = first layer, ...), 27 | # - use a fixed relation between VP/VS = f(z) 28 | # - use a fixed relation between RH = f(VP) 29 | # mZVSPRzRHz = parameterize with 30 | # - depth interface (mZ1 = first interface, mZ2, ...), 31 | # - VS in each layer (VS0 = first layer, ...), 32 | # - use a fixed relation between VP/VS = f(z) 33 | # - use a fixed relation between RH = f(z) 34 | # -dvp f f add prior constraint on the vp offset between layers, 35 | # requires the extremal values, km/s 36 | # -dvs f f add prior constraint on the vs offset between layers, idem 37 | # -drh f f add prior constraint on the density offset between layers, idem, g/cm3 38 | # -dpr f f add prior constraint on the vp/vs offset between layers, idem, no unit 39 | # -growing shortcut for -dvp 0. 5. -dvs 0. 5. -drh 0. 5. -dpr -5. 0. 40 | # -op force overwriting ./_HerrMet.param if exists 41 | # 42 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/111_param.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cat << END > _HerrMet.param 4 | #met NLAYER = 9 5 | #met TYPE = 'mZVSPRRH' 6 | #met PRIORTYPE = "DVPDVSDRHDPR" 7 | #met DVSMIN = -0.5 8 | #met DVSMAX = +1.5 9 | #met DVPMIN = -0.5 10 | #met DVPMAX = +1.5 11 | #met DPRMIN = -1.0 12 | #met DPRMAX = +0.0 13 | #met DRHMIN = +0.0 14 | #met DRHMAX = +1.0 15 | 16 | #fld KEY VINF VSUP 17 | #unt [] [] [] 18 | #fmt %s %f %f 19 | -Z1 -0.200000 -0.05 20 | -Z2 -0.400000 -0.2 21 | -Z3 -0.800000 -0.400000 22 | -Z4 -1.000000 -0.800000 23 | -Z5 -1.500000 -1.000000 24 | -Z6 -2.000000 -1.500000 25 | -Z7 -2.500000 -2.000000 26 | -Z8 -3.000000 -2.500000 27 | 28 | VS0 0.2 1.500000 29 | VS1 0.2 1.700000 30 | VS2 0.5 2.000000 31 | VS3 0.5 2.500000 32 | VS4 1.0 3.000000 33 | VS5 1.0 3.250000 34 | VS6 1.3 3.500000 35 | VS7 1.3 3.550000 36 | VS8 3.2 3.600000 37 | 38 | PR0 1.800000 3.6 39 | PR1 1.800000 2.3 40 | PR2 1.800000 2.3 41 | PR3 1.800000 2.3 42 | PR4 1.700000 2.3 43 | PR5 1.700000 2.3 44 | PR6 1.600000 2.0 45 | PR7 1.600000 2.0 46 | PR8 1.600000 1.9 47 | 48 | RH0 1.80 2.3 49 | RH1 1.80 2.3 50 | RH2 1.90 2.4 51 | RH3 2.00 2.4 52 | RH4 2.00 2.5 53 | RH5 2.10 2.5 54 | RH6 2.30 2.7 55 | RH7 2.40 2.7 56 | RH8 2.50 2.7 57 | END 58 | 59 | 60 | 61 | #cat << END > _HerrMet.param 62 | ##met NLAYER = 5 63 | ##met TYPE = 'mZVSPRRH' 64 | ##fld KEY VINF VSUP 65 | ##unt - - - 66 | ##fmt %5s %16f %16f 67 | # -Z1 -0.2 -0.05 68 | # -Z2 -1.0 -0.10 69 | # -Z3 -2.5 -0.5 70 | # -Z4 -3.0 -1.2 71 | # VS0 0.100000 3.100000 72 | # VS1 0.200000 3.200000 73 | # VS2 0.300000 3.300000 74 | # VS3 0.400000 3.400000 75 | # VS4 0.50000 3.500000 76 | # PR0 1.90 2.1 77 | # PR1 1.80 2.0 78 | # PR2 1.75 1.9 79 | # PR3 1.71 1.85 80 | # PR4 1.70 1.8 81 | # RH0 1.7 2.5 82 | # RH1 2.0 2.6 83 | # RH2 2.20 2.7 84 | # RH3 2.40 2.7 85 | # RH4 2.50 2.7 86 | #END 87 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/112_show.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | HerrMet --display . 3 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/115_send.sh: -------------------------------------------------------------------------------- 1 | HerrMet --send -op 2 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/117_show.sh: -------------------------------------------------------------------------------- 1 | HerrMet --display -m96 model000.mod96 2 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/120_run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #--run s [s..] start inversion for the required rootnames, default _HerrMet_* 3 | # -mode s set the running mode, default skip 4 | # restart : overwrite the current run file(s) if any 5 | # append : add new models to the exiting run file(s) 6 | # skip : ignore rootnames with existsing run file(s) 7 | # -nchain i number of chains to use, default 12 8 | # -nkeep i number of models to keep per chain, default 100 9 | # [use -w option before --run to control the maximum number of chains to run simultaneously] 10 | 11 | HerrMet -w 8 --run _HerrMet_data010 \ 12 | -mode append \ 13 | -nchain 8 \ 14 | -nkeep 2000 15 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/130_manage.sh: -------------------------------------------------------------------------------- 1 | HerrMet --manage _HerrMet_data010 -stats -plot -100. 2 | 3 | #--manage s [s..] manage run results for given rootnames, default _HerrMet_* 4 | # -stats prints detailed stats for each chain of each runfile 5 | # -plot [f] display the convergence for every chain and every rootname, specify the lower bound 6 | # -inline do not pause (jupyter) 7 | # -delbad f delete bad models, log likelihood below a given threshold, no default 8 | # -delchains i [i...] delete one or more chains using their chainid 9 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/140_display.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | for n in 10 100 1000 4 | do 5 | HerrMet --display _HerrMet_data010 \ 6 | -plot best $n 0 1 \ 7 | -m96 model000.mod96 \ 8 | -overdisp -png 9 | # -pdf best $n 0 1 \ 10 | 11 | mv _HerrMet_data010/_HerrMet.png _HerrMet_data010/_HerrMet_best$n.png 12 | done 13 | 14 | eog _HerrMet_data010/_HerrMet_best*png 15 | 16 | #HerrMet --display _HerrMet_data010 -plot best 1 0 1 -m96 model000.mod96 17 | #HerrMet --display _HerrMet_data010 -plot best 100 0 1 -m96 model000.mod96 -overdisp 18 | #HerrMet --display _HerrMet_data010 -plot best 1000 0 1 -m96 model000.mod96 -overdisp 19 | #HerrMet --display _HerrMet_data010 -plot best 2000 0 1 -m96 model000.mod96 -overdisp -png 20 | #HerrMet --display _HerrMet_data010 -plot best 0 -10 1 -m96 model000.mod96 -overdisp -png 21 | 22 | #HerrMet --display _HerrMet_data010 -plot best 10000 0 1 -m96 model000.mod96 23 | #HerrMet --display _HerrMet_data010 -plot best 10000 0 1 -m96 model000.mod96 -png # -pdf best 10000 0 1 24 | #--display s [s...] display param, target, and run outputs for the required rootnames, default _HerrMet_* 25 | # (use "." to see the parameterzation template ./_HerrMet.param from option --param) 26 | # -plot [s i f i] show the best models on the figure, arguments are : 27 | # first argument = selection mode, last or best 28 | # second argument = highest model number to include (>=0, 0 means all) 29 | # third argument = lowest log likelyhood value to include (<=0.0, 0.0 means all) 30 | # fourth argument = include only one model over "step" (>=1) 31 | # default last 100 0.0 1 32 | # -overdisp recompute dispersion curves of the best models selected with higher resolution 33 | # -pdf [s i f i] compute and show the statistics for the selected models, see -plot for arguments 34 | # default last 0 0.0 1 35 | # use --extract to save pdf outputs 36 | # -png [i] save figure as pngfile instead of displaying it on screen, requires dpi, default 100 37 | # -m96 s [s...] append depth model(s) to the plot from mod96 file(s) 38 | # -cmap colormap, default viridis 39 | # -compact display only vs and the dispersion curves, default False 40 | # -ftsz i set font size, default 10 41 | # -inline do not pause (use in jupyter notebooks) 42 | # 43 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/150_extract.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f ./_HerrMet_data010/*rank*mod96 4 | rm -f ./_HerrMet_data010/*best_*mod96 5 | 6 | # extract the 10 best models and 16% 50% 84% percentiles of the 10^4 best models 7 | HerrMet --extract _HerrMet_data010 \ 8 | -top 10 0 1 \ 9 | -pdf best 1000 0 1 10 | 11 | m96 --show \ 12 | _HerrMet_data010/*rank*.mod96 \ 13 | _HerrMet_data010/_HerrMet.best_1000_0.00_1.p*.mod96 14 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/clear.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | rm -rf model000.mod96 model000.*m.mod96 _HerrMet_data010 data010.surf96 _HerrMet.param sker*png 3 | -------------------------------------------------------------------------------- /tutorials/01_simple_inversion_example/main_script.sh: -------------------------------------------------------------------------------- 1 | echo -e "\n# erase previous test files " 2 | echo " bash clear.sh ..." 3 | bash clear.sh 4 | 5 | 6 | echo -e "\n########## GENERATE A SYNTHETIC MODEL" 7 | echo " # create a depth model => .mod96" 8 | echo " python3 000_create_model.py ..." 9 | python3 000_create_model.py 10 | 11 | echo -e "\n # show it" 12 | echo " bash 001_show.sh ..." 13 | bash 001_show.sh 14 | 15 | echo -e "\n # compute the sensitivity kernels (optional)" 16 | echo " bash 002_sensitivity.sh ..." 17 | bash 002_sensitivity.sh 18 | 19 | echo -e "\n # compute the dispersion curves" 20 | echo " bash 010_dispers.sh ..." 21 | bash 010_dispers.sh 22 | 23 | echo -e "\n # show it" 24 | echo " bash 011_show.sh ..." 25 | bash 011_show.sh 26 | 27 | 28 | echo "########## INVERSE THE SYNTHETIC DATA" 29 | echo -e "\n # set the forward dispersion curves as the inversion data target" 30 | echo " # => create a subdirectory for each target disp. curve (_HerrMet_*)" 31 | echo " bash 100_set_target.sh ..." 32 | bash 100_set_target.sh 33 | 34 | echo -e "\n # show the current state of the inversion in the sub directory : only data for now" 35 | echo " bash 101_show.sh ..." 36 | bash 101_show.sh 37 | 38 | echo -e "\n # build a template parameter file using HerrMet in ." 39 | echo " bash 110_template_param.sh ..." 40 | bash 110_template_param.sh 41 | 42 | echo -e "\n # simulate the user editing the parameter file, here I simply overwrite the template using cat" 43 | echo " bash 111_param.sh ..." 44 | bash 111_param.sh 45 | 46 | echo -e "\n # show the content of . : only parameterization since the targets are in the sub directories (_HerrMet_*)" 47 | echo " bash 112_show.sh ..." 48 | bash 112_show.sh 49 | 50 | echo -e "\n # send the custom parameter file from . to all the subdirectories" 51 | echo " # here there is only one" 52 | echo " bash 115_send.sh ..." 53 | bash 115_send.sh 54 | 55 | echo -e "\n # show the current state of the inversion in the sub directory : data and parameterization" 56 | echo " bash 117_show.sh ..." 57 | bash 117_show.sh 58 | 59 | echo -e "\n # run the inversion in parallel in the subdirectories" 60 | echo " bash 120_run.sh ..." 61 | bash 120_run.sh 62 | 63 | echo -e "\n # show the statistics of the inversion" 64 | echo " bash 130_manage.sh ..." 65 | bash 130_manage.sh 66 | 67 | echo -e "\n # create figures" 68 | echo " bash 140_display.sh ..." 69 | bash 140_display.sh 70 | 71 | echo -e "\n # extract the inversion solution for later use..." 72 | echo " bash 150_extract.sh ..." 73 | bash 150_extract.sh 74 | 75 | -------------------------------------------------------------------------------- /tutorials/02_acoustic_scale_inversion_example/clear.sh: -------------------------------------------------------------------------------- 1 | # sudo apt-get install trash-cli 2 | trash _HerrMet_?layers* 3 | -------------------------------------------------------------------------------- /tutorials/02_acoustic_scale_inversion_example/main_script.sh: -------------------------------------------------------------------------------- 1 | bash clear.sh 2 | 3 | echo "# =========== control the picked dispersion curves" 4 | echo "s96 --show picks.surf96 -freq" 5 | s96 --show picks.surf96 -freq 6 | 7 | echo "# =========== initiate an inversion dir using these picks as targert" 8 | echo "HerrMet --target picks.surf96" 9 | HerrMet --target picks.surf96 10 | 11 | echo "# =========== Prepare several parameterizations for the same inversion" 12 | # cp -av _HerrMet_picks _HerrMet_4layers 13 | cp -av _HerrMet_picks _HerrMet_3layers 14 | mv _HerrMet_picks _HerrMet_2layers 15 | 16 | echo "# =========== Prepare 3 different parameterizations for comparison" 17 | # Note : in most cases, you must edit the parameterization files before inversion 18 | HerrMet --param 2 0.00004 -t mZVSPRRH -op #-growing 19 | HerrMet --send _HerrMet_2layers 20 | 21 | HerrMet --param 3 0.00004 -t mZVSPRRH -op #-growing 22 | HerrMet --send _HerrMet_3layers 23 | 24 | #HerrMet --param 4 0.00004 -t mZVSPRRH -op #-growing 25 | #HerrMet --send _HerrMet_4layers 26 | 27 | echo "# =========== Check the target and prior boundaries" 28 | echo "HerrMet --display" 29 | HerrMet --display -si 30 | 31 | echo "# =========== Run the inversion for all parameterizations" 32 | echo "HerrMet --HerrMet --run" 33 | HerrMet -w 8 --run _HerrMet_?layers -mode restart -nchain 2 -nkeep 2000 34 | 35 | echo "# =========== Display results" 36 | echo "HerrMet --HerrMet --display" 37 | # -compact -si \ 38 | # -overdisp \ 39 | 40 | HerrMet --display _HerrMet_?layers \ 41 | -plot best 1000 0 1 \ 42 | -pdf best 1000 0 1 \ 43 | -png 44 | 45 | echo "# =========== No target Check" 46 | if true; then 47 | # copy each folder 48 | for dr in _HerrMet_*layers; 49 | do cp -av $dr $dr"_notarget" 50 | done 51 | 52 | # run with option -notarget 53 | HerrMet -w 8 --run _HerrMet_?layers_notarget -mode restart -nchain 2 -nkeep 2000 \ 54 | -notarget 55 | 56 | # see the resulting pdf 57 | HerrMet --display _HerrMet_?layers_notarget \ 58 | -pdf best 1000 0 1 \ 59 | -png 60 | fi 61 | 62 | eog ./_HerrMet*/*png 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/000_create_model.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | from srfpython.depthdisp.depthmodels import brocher2005 4 | import os 5 | os.system('mkdir --parents ./model') 6 | """ 7 | build a 3D vs model (vp, rh from Brocher 2005) 8 | """ 9 | 10 | x0 = 0. 11 | y0 = 0. 12 | z0 = 0. 13 | nx = 5 14 | ny = 4 15 | nz = 10 16 | dx = 2.4 # km 17 | dy = 2.2 # km 18 | dz = 0.33 # km 19 | 20 | vs = np.zeros((nz, ny, nx), float) 21 | 22 | z = (z0 + np.arange(nz) * dz)[:, np.newaxis, np.newaxis] 23 | y = (y0 + np.arange(ny) * dy)[np.newaxis, :, np.newaxis] 24 | x = (x0 + np.arange(nx) * dx)[np.newaxis, np.newaxis, :] 25 | 26 | vs = 0.8 + 1.0 * z + 0.4 * \ 27 | np.cos(2. * np.pi * x / 20.) * \ 28 | np.cos(2. * np.pi * y / 20.) * \ 29 | np.cos(2. * np.pi * z / 4.) 30 | 31 | vp, rh = brocher2005(vs) 32 | print('vsmin, vsmax', vs.min(), vs.max()) 33 | 34 | 35 | # ========================== Save 36 | np.savez( 37 | './model/model.npz', 38 | x=x.flat[:], 39 | y=y.flat[:], 40 | z=z.flat[:], 41 | vs=vs, 42 | vp=vp, 43 | rh=rh) 44 | 45 | # ========================== Display 46 | xedges = x0 + np.arange(nx + 1) * dx - dx / 2 47 | yedges = x0 + np.arange(ny + 1) * dy - dy / 2 48 | zedges = z0 + np.arange(nz + 1) * dz - dz / 2; zedges[0] = 0. 49 | 50 | plt.figure() 51 | for i in range(ny): 52 | for j in range(nx): 53 | plt.plot(z.flat[:], vs[:, i, j], 'r') 54 | plt.plot(z.flat[:], vp[:, i, j], 'k') 55 | plt.plot(z.flat[:], rh[:, i, j], 'b') 56 | plt.gca().set_xlabel('z (km)') 57 | 58 | 59 | plt.figure() 60 | plt.colorbar( 61 | plt.pcolormesh(xedges, yedges, vs[0, ...], cmap=plt.get_cmap('jet_r')) 62 | ) 63 | plt.gca().set_xlabel('x (km)') 64 | plt.gca().set_ylabel('y (km)') 65 | 66 | plt.figure() 67 | plt.colorbar( 68 | plt.pcolormesh(xedges, zedges, vs[:, ny // 5, :], cmap=plt.get_cmap('jet_r')) 69 | ) 70 | plt.gca().set_xlabel('x (km)') 71 | plt.gca().set_ylabel('z (km)') 72 | plt.gca().invert_yaxis() 73 | 74 | # plt.ion() 75 | plt.show() 76 | # input('pause') 77 | -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/001_model_to_mod96.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from srfpython.depthdisp.depthmodels import depthmodel_from_arrays 3 | import os 4 | os.system('mkdir --parents ./model/nodes') 5 | 6 | with np.load('./model/model.npz') as loader: 7 | x = loader['x'] 8 | y = loader['y'] 9 | z = loader['z'] 10 | vs = loader['vs'] 11 | vp = loader['vp'] 12 | rh = loader['rh'] 13 | 14 | nx, ny, nz = len(x), len(y), len(z) 15 | 16 | for iy in range(ny): 17 | for ix in range(nx): 18 | nodename = "node_iy%03d_ix%03d" % (iy, ix) 19 | filename = "./model/nodes/{}.mod96".format(nodename) 20 | 21 | dm = depthmodel_from_arrays( 22 | z=z, 23 | vp=vp[:, iy, ix], 24 | vs=vs[:, iy, ix], 25 | rh=rh[:, iy, ix]) 26 | print(filename) 27 | dm.write96(filename=filename) 28 | -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/002_disperse.py: -------------------------------------------------------------------------------- 1 | import sys, glob, os 2 | from srfpython.depthdisp.depthmodels import depthmodel_from_mod96 3 | from srfpython.depthdisp.dispcurves import surf96reader_from_curves 4 | from srfpython.Herrmann.Herrmann import Curve, HerrmannCaller 5 | import numpy as np 6 | 7 | os.system('mkdir --parents ./data') 8 | 9 | 10 | freqs = np.logspace(np.log10(0.1), np.log10(1.), 10) 11 | 12 | 13 | hc = HerrmannCaller(curves=[ 14 | Curve(wave="R", type="U", mode=0, freqs=freqs), 15 | Curve(wave="R", type="C", mode=0, freqs=freqs)]) 16 | # Curve(wave="R", type="U", mode=1, freqs=freqs), overtones not handled yet in optimize 17 | # Curve(wave="R", type="C", mode=1, freqs=freqs)]) overtones not handled yet in optimize 18 | 19 | for fin in glob.glob('./model/nodes/*mod96'): 20 | dm = depthmodel_from_mod96(fin) 21 | curves = hc(ztop=dm.vs.z, vp=dm.vp.values, vs=dm.vs.values, rh=dm.rh.values, keepnans=False) 22 | s96r = surf96reader_from_curves(curves) 23 | 24 | fout = fin.replace('./model/nodes/', './data/').replace('.mod96', '.surf96') 25 | print(fin, '->', fout) 26 | s96r.write96(filename=fout) 27 | -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/100_set_target.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | mkdir inversion 4 | cd inversion || exit 1; 5 | 6 | HerrMet --target ../data/node*.surf96 -lunc .1 -ot -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/111_param.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cd inversion || exit 1; 3 | 4 | cat << END > _HerrMet.param 5 | #met NLAYER = 5 6 | #met TYPE = 'mZVSVPvsRHvp' 7 | #met PRIORTYPE = 'DVPDVSDRH' 8 | #met DVSMIN = -0.5 9 | #met DVSMAX = +1.5 10 | #met DVPMIN = -0.5 11 | #met DVPMAX = +1.5 12 | #met DPRMIN = -1.0 13 | #met DPRMAX = +0.0 14 | #met DRHMIN = +0.0 15 | #met DRHMAX = +1.0 16 | 17 | #met VPvs = 'lambda VS: 0.9409 + 2.0947 * VS - 0.8206 * VS ** 2.0 + 0.2683 * VS ** 3.0 - 0.0251 * VS ** 4.0' 18 | #met RHvp = 'lambda VP: 1.6612 * VP - 0.4721 * VP ** 2.0 + 0.0671 * VP ** 3.0 - 0.0043 * VP ** 4.0 + 0.000106 * VP ** 5.0' 19 | 20 | #fld KEY VINF VSUP 21 | #unt [] [] [] 22 | #fmt %s %f %f 23 | -Z1 -0.5 -0.01 24 | -Z2 -1.0 -0.25 25 | -Z3 -2.0 -0.75 26 | -Z4 -3.0 -1.5 27 | 28 | VS0 0.2 2.0 29 | VS1 0.5 2.5 30 | VS2 1.0 3.0 31 | VS3 1.5 3.25 32 | VS4 2.0 3.9 33 | 34 | 35 | END 36 | -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/112_show.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd inversion || exit 1; 4 | HerrMet --display . -m96 ../model/nodes/node_iy000_ix000.mod96 -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/115_send.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd inversion || exit 1; 4 | HerrMet --send -op 5 | -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/117_show.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd inversion || exit 1; 4 | 5 | HerrMet --display _HerrMet_node_iy002_ix000 -m96 ../model/nodes/node_iy002_ix000.mod96 -png 6 | 7 | eog _HerrMet_node*/_HerrMet.png -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/120_run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #--run s [s..] start inversion for the required rootnames, default _HerrMet_* 3 | # -mode s set the running mode, default skip 4 | # restart : overwrite the current run file(s) if any 5 | # append : add new models to the exiting run file(s) 6 | # skip : ignore rootnames with existsing run file(s) 7 | # -nchain i number of chains to use, default 12 8 | # -nkeep i number of models to keep per chain, default 100 9 | # [use -w option before --run to control the maximum number of chains to run simultaneously] 10 | 11 | cd inversion || exit 1; 12 | 13 | HerrMet -w 12 --run \ 14 | -mode restart \ 15 | -nchain 2 \ 16 | -nkeep 1000 17 | -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/130_manage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd inversion || exit 1; 4 | 5 | HerrMet --manage 6 | 7 | HerrMet --manage -stats -plot -100. 8 | 9 | #--manage s [s..] manage run results for given rootnames, default _HerrMet_* 10 | # -stats prints detailed stats for each chain of each runfile 11 | # -plot [f] display the convergence for every chain and every rootname, specify the lower bound 12 | # -inline do not pause (jupyter) 13 | # -delbad f delete bad models, log likelihood below a given threshold, no default 14 | # -delchains i [i...] delete one or more chains using their chainid 15 | -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/140_display.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cd inversion || exit 1; 3 | 4 | # I use a loop to compare each output with the expected model 5 | for rootname in _HerrMet_node_* 6 | do 7 | node=`awk 'BEGIN {split("'$rootname'",a,"_HerrMet_");print a[2]}'` 8 | echo $node 9 | 10 | HerrMet --display $rootname \ 11 | -plot best 1000 0 1 \ 12 | -pdf best 1000 0 1 \ 13 | -m96 ../model/nodes/$node.mod96 \ 14 | -png \ 15 | || exit 1 ; 16 | # -overdisp \ 17 | done 18 | #eog _HerrMet_*/_HerrMet.png 19 | # 20 | #exit 0; 21 | # 22 | ## If you don't want a m96 file to appear on each plot, the following command is ok 23 | #HerrMet --display \ 24 | # -plot best 1000 0 1 \ 25 | # -pdf best 1000 0 1 \ 26 | # -png 27 | -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/150_extract.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cd inversion || exit 1; 3 | 4 | # remove previous extracted files if any 5 | # find inversion -name "_HerrMet.best_*.p0.??.*96" -delete 6 | 7 | HerrMet --extract \ 8 | -pdf best 1000 0 1 9 | -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/151_compare.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import os 4 | from srfpython.HerrMet.files import ROOTNAME, HERRMETEXTRACTPDFMODELFILE 5 | from srfpython.depthdisp.depthmodels import depthmodel_from_mod96 6 | 7 | with np.load('./model/model.npz') as loader: 8 | x = loader['x'] 9 | y = loader['y'] 10 | z = loader['z'] 11 | vstruth = loader['vs'] 12 | 13 | x0, nx, dx = x[0], len(x), x[1] - x[0] 14 | y0, ny, dy = y[0], len(y), y[1] - y[0] 15 | z0, nz, dz = z[0], len(z), z[1] - z[0] 16 | # ========================== Display 17 | 18 | vsinv = np.zeros_like(vstruth) 19 | for iy in range(ny): 20 | for ix in range(nx): 21 | medfile = HERRMETEXTRACTPDFMODELFILE.format( 22 | rootname=ROOTNAME.format(node="node_iy{:03d}_ix{:03d}".format(iy, ix)), 23 | extract_mode="best", 24 | extract_limit=1000, 25 | extract_llkmin=0, 26 | extract_step=1, 27 | percentile=0.5) 28 | medfile = "./inversion/" +medfile 29 | assert os.path.isfile(medfile) 30 | 31 | dm = depthmodel_from_mod96(medfile) 32 | dm = dm.interp(ztop=z) 33 | vsinv[:, iy, ix] = dm.vs.values 34 | 35 | xedges = x0 + np.arange(nx + 1) * dx - dx / 2 36 | yedges = x0 + np.arange(ny + 1) * dy - dy / 2 37 | zedges = z0 + np.arange(nz + 1) * dz - dz / 2; zedges[0] = 0. 38 | 39 | for vs in vstruth, vsinv: 40 | plt.figure() 41 | for i in range(ny): 42 | for j in range(nx): 43 | plt.plot(z.flat[:], vs[:, i, j], 'r') 44 | plt.gca().set_xlabel('z (km)') 45 | 46 | plt.figure() 47 | plt.colorbar( 48 | plt.pcolormesh(xedges, yedges, vs[0, ...], cmap=plt.get_cmap('jet_r')) 49 | ) 50 | plt.gca().set_xlabel('x (km)') 51 | plt.gca().set_ylabel('y (km)') 52 | 53 | plt.figure() 54 | plt.colorbar( 55 | plt.pcolormesh(xedges, zedges, vs[:, ny // 5, :], cmap=plt.get_cmap('jet_r')) 56 | ) 57 | plt.gca().set_xlabel('x (km)') 58 | plt.gca().set_ylabel('z (km)') 59 | plt.gca().invert_yaxis() 60 | 61 | plt.ion() 62 | plt.show() 63 | input('pause') 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/200_optimize.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | # generate a template file 5 | trash _HerrMet.optimize.param 6 | HerrMet -verbose 0 --optimize -temp 7 | 8 | # edit it and customize it ... 9 | # in this tuto I edit here below : 10 | cat << END > _HerrMet.optimize.param 11 | # ========== recall the grid parameters 12 | nx 5 13 | ny 4 14 | dx 2.4 # km 15 | dy 2.2 # km 16 | 17 | # ========== path to the point-wise inversion data and results 18 | datafiles ./inversion/_HerrMet_node_iy{iy:03d}_ix{ix:03d}/_HerrMet.target 19 | extractfiles ./inversion/_HerrMet_node_iy{iy:03d}_ix{ix:03d}/_HerrMet.best_1000_0.00_1.p0.50.mod96 20 | 21 | # ========== optimization parameters 22 | ndecim 1 # downsamp the grid 23 | newnz 10 # new vertical grid (needed to interpolate the extracted files) 24 | newdz 0.33 # new vertical grid (needed to interpolate the extracted files) 25 | Lh 1.0 # horizontal smoothing distance km 26 | Lv 0.5 # vertical smoothing distance km 27 | vsunc 0.1 # km/s 28 | damping 1.0 # weight of the regularization 29 | END 30 | 31 | cat _HerrMet.optimize.param 32 | -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/201_get_mprior_and_dobs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | # get the target and extract files using the information from _HerrMet.optimize.param 5 | HerrMet --optimize -mprior -dobs -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/202_run_optimize.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | # run the interative inversion 5 | HerrMet --optimize -inv 6 | 7 | # show the results 8 | HerrMet --optimize -show y 10 9 | -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/clear.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | rm -rf data/ inversion/ model/ _HerrMet.optimize.param 3 | -------------------------------------------------------------------------------- /tutorials/03_cube_inversion_example/main_script.sh: -------------------------------------------------------------------------------- 1 | # bash clear.sh 2 | 3 | python3 000_create_model.py 4 | 5 | python3 001_model_to_mod96.py 6 | 7 | python3 002_disperse.py 8 | 9 | bash 100_set_target.sh 10 | 11 | bash 111_param.sh 12 | 13 | bash 112_show.sh 14 | 15 | bash 115_send.sh 16 | 17 | bash 117_show.sh 18 | 19 | bash 120_run.sh 20 | 21 | bash 130_manage.sh 22 | 23 | bash 140_display.sh 24 | 25 | bash 150_extract.sh 26 | 27 | python3 151_compare.py 28 | 29 | bash 200_optimize.sh 30 | 31 | bash 201_get_mprior_and_dobs.sh 32 | 33 | bash 202_run_optimize.sh 34 | -------------------------------------------------------------------------------- /tutorials/10_notebooks/readme.txt: -------------------------------------------------------------------------------- 1 | to run the tutorial 2 | 3 | 1/ activate the environment created for srfpython (assume that jupyter notebook for python 2 was installed) 4 | 5 | source activate srfpython 6 | 7 | 2/ run jupyter notebook in this directory 8 | 9 | jupyter notebook 10 | 11 | 3/ open the desired notebook 12 | 13 | --------------------------------------------------------------------------------