Source code for watex.datasets.gdata

# -*- coding: utf-8 -*-
#   Licence:BSD 3-Clause
#   Author: LKouadio 

from __future__ import annotations 
import numpy as np 
import pandas as pd 
from ..utils.coreutils import  makeCoords 
from ..utils.gistools import ll_to_utm
from ..utils.exmath import fitfunc
from ..utils.box import Boxspace 

__all__ =["make_erp", "make_ves"] 

[docs]def make_erp ( *, n_stations:int= 42, max_rho:float= 1e3 , min_rho:float= 1e0, step:float=20., reflong:float|str='110:29:09.00', reflat:float|str='26:03:05.00' , utm_zone:str='29N', order:str='+', full_coordinates:bool=True, raise_warning:bool=False, as_frame:bool=False, seed:int=None, **coord_kws ): r""" Generate Electrical Resistivity Profiling (ERP) data from stations and coordinates points. To generate samples from specific area, it is better to provide both latitude and longitude values from a single station of this area as arguments passed to parameters `reflat` and `reflong` respectively. Also specify the `utm_zone` for the lat/lon coordinates conversion into UTM if necessary. If not useful, can turn off the parameter `full_coordinates` to ``False``. Parameters ----------- n_stations: int, default=42 number of measurements stations max_rho: float, default=1e3 maximum resistivity value on the survey area in :math:`\Omega.m` min_rho: float, default=1e0 minimum resistivity value on the survey area in :math:`\Omega.m` reflong: float or string or list of [start, stop], default='110:29:09.00' Reference longitude in degree decimal or in DD:MM:SS for the first station considered as the origin of the landmark. reflat: float or string or list of [start, stop], default='26:03:05.00' Reference latitude in degree decimal or in DD:MM:SS for the reference site considered as the landmark origin. If value is given in a list, it can contain the start point and the stop point. step: float or str , default=20 Offset or the distance of seperation between different sites in meters. If the value is given as string type, except the ``km``, it should be considered as a ``m`` value. Only meters and kilometers are accepables. order: str , default='-' Direction of the projection line. By default the projected line is in ascending order i.e. from SW to NE with angle `r` set to ``45`` degrees. Could be ``-`` for descending order. Any other value should be in ascending order. utm_zone: string (##N or ##S), default='29N' utm zone in the form of number and North or South hemisphere, 10S or 03N Must be given if `utm2deg` is set to ``True``. full_coordinates: bool, default=True, Convert latitude and longitude to approximate UTM values. Easting and northing are gotten using the reference ellipsoid =23 with WGS84. If ``False``, easting and northing are not computed and set to null. raise_warning: bool, default=True, Raises warnings if GDAL is not set or the coordinates accurately status. as_frame: bool, default=False, if ``True``, outputs the data into as a pandas dataframe, :class:`~watex.utils.box.Boxspace` object otherwise. seed: int, Optional, It allows reproducing the same data. If value is passed, it reproduces the same data at that sample points. coord_kws: dict, Additional keywords passed to :func:`~watex.utils.coreutils.makeCoords`. Returns -------- (pd.Dataframe | :class:`~watex.utils.box.Boxspace` ) Examples ---------- >>> from watex.datasets.gdata import make_erp >>> erp_data = make_erp (n_stations =50 , step =30 , as_frame =True) >>> erp_data.head(3) Out[256]: station longitude latitude easting northing resistivity 0 0 -13.488511 0.000997 668210.580864 110.183287 225.265306 1 30 -13.488511 0.000997 668210.581109 110.183482 327.204082 2 60 -13.488510 0.000997 668210.581355 110.183676 204.877551 """ stations = np.arange (0 , n_stations * step , step ) resistivity =np.linspace(min_rho, max_rho , n_stations) if seed is not None: np.random.seed(seed) np.random.shuffle(resistivity) rlons, rlats = makeCoords(reflong, reflat, nsites=n_stations, is_utm=True, utm_zone =utm_zone, step = step, raise_warning=raise_warning, **coord_kws) easting = np.zeros_like(rlons) ; northing = np.zeros_like(rlats) if full_coordinates: en = [ll_to_utm (23 , lat , lon ) for lat, lon in zip (rlats, rlons)] _, easting , northing = zip (*en) d = { "station": stations, "longitude":rlons, "latitude": rlats, "easting": easting, "northing": northing, "resistivity": resistivity } dx ={"frame": pd.DataFrame (d), "data": pd.DataFrame (d).values } data = Boxspace(**d, **dx ) return data.frame if as_frame else data
[docs]def make_ves ( *, samples:int= 31, min_rho:float=1e1, max_rho:float= 1e3, max_depth:float= 100., order:str='-', as_frame:bool=False, seed:int=None, iorder:float=3, ): r""" Generate Vertical Electrical Sounding (VES) data from pseudo-depth measurements. For a large pseudo-depth measurements, one can change the number of samples to a large values. The default samples presumed collected is ``samples=31`` measurements in deeper. Parameters ----------- samples: int, default=42 number of measurements depth AB/2 in meters. max_rho: float, default=1e3 maximum resistivity value expected in deeeper on the survey area in :math:`\\Omega.m` min_rho: float, default=1e1 minimum resistivity value expected in deeper on the survey area in :math:`\\Omega.m` order: str , default='-' Direction of the projection line. By default the projected line is in ascending order i.e. from SW to NE with angle `r` set to ``45`` degrees. Could be ``-`` for descending order. Any other value should be in ascending order. max_depth: float, default=100 Value of the measurement in deeper expected to reach by AB/2 in meters. as_frame: bool, default=False, if ``True``, outputs the data into as a pandas dataframe, :class:`~watex.utils.box.Boxspace` object otherwise. seed: int, Optional, It allows reproducing the same data. If value is passed, it reproduces the same data at that sample points. iorder: float, default=3 Inflexion order. If ``None`` should compute using the length of extrema (local + global). Must be lower as possible to let the fitting VES curve more realistic. Returns --------- (pd.Dataframe | :class:`~watex.utils.box.Boxspace` ) Notes ------- when returning the :class:`~watex.utils.box.Boxspace` object, each columns of 'VES' data can be retrieved as an attributes. Check the examples below Examples --------- >>> from watex.datasets.gdata import make_ves >>> b = make_ves (samples =50 , order ='+') # 50 measurements in deeper >>> b.resistivity [:-7] Out[314]: array([429.873 , 434.255 , 438.5707, 442.8203, 447.0042, 451.1228, 457.5775]) >>> b.frame.head(3) Out[315]: AB MN resistivity 0 1.0 0.6 429.872999 1 2.0 0.6 434.255018 2 3.0 0.6 438.570675 """ ix , mnv= [ 4, 16 , 26 , 31 ], [.4 , 1., 5., 10.] abv = [1, 2, 4, 10 ] ix = np.array ( np.array (ix) * samples / 31 , dtype =int ) mnv = np.array(mnv, dtype =float ) * samples / 31 abv = np.array(abv, dtype =float ) * samples / 31 MN_max = max_depth //10 # MN = _generate_ABMN_samples(indexes= ix, fixed_values=mnv, threshold_multiplicator= MN_max ) AB = _generate_ABMN_samples(indexes = ix , fixed_values=abv, threshold_multiplicator=MN_max, kind ="AB") # make resistivity g = np.linspace ( max_rho, min_rho , samples ) if order =='-' else np.linspace (min_rho, max_rho , samples ) if seed is not None: np.random.seed(seed ) np.random.shuffle(g) f, *_ = fitfunc (AB, g, deg= iorder ) resistivity = f (AB ) d= {"AB":AB, "MN": MN, "resistivity":resistivity} dx ={"frame": pd.DataFrame (d), "data": pd.DataFrame (d).values } data = Boxspace(**d, **dx ) return data.frame if as_frame else data
def _generate_ABMN_samples ( indexes, fixed_values, threshold_multiplicator, kind ='MN'): """ Isolated part for 'VES' data generating. """ # use index MN for test MN=list() nsam = np.array (np.diff (indexes ), dtype = int ) for ii, (ind, v) in enumerate (zip (indexes, fixed_values)): if ii==0: s = [ v * threshold_multiplicator / 10 for i in range ( ind ) ] if kind =="MN" else list( np.linspace (1, indexes [0], indexes [0])) else: s = [v* threshold_multiplicator / 10 for i in range ( indexes[ii -1], indexes[ii])] if kind=="MN" else list( np.arange (0, nsam[ii-1] * v, v ) + s[-1] + fixed_values[ii-1]) MN.extend (s) return np.around (MN, 1 )