Source code for watex.geology.geology

# -*- coding: utf-8 -*-
# License: BSD-3-Clause
# Author: LKouadio <etanoyau@gmail.com>

import os
import re
import warnings 
import numpy as np 

import pandas as pd
from .core import (
    GeoBase, 
    get_agso_properties 
    )
from ..utils.funcutils import ( 
    repr_callable_obj, 
    smart_strobj_recognition
    )
from ..utils.plotutils import ( 
    get_color_palette 
    )
from ..exceptions import ( 
    StrataError,
    NotFittedError, 
    )

from .._watexlog import watexlog  
_logger =watexlog().get_watex_logger(__name__)


[docs] def setstructures(self , configfile:str =None , fillna:int =0 ): """ configure the geological structures as a property object and load attributes. :param configfile: is a configure file from 'AGS0' data :param fillna: fill NaN values in the AGS0 file. The default values to fill is `0` for False. :return: ``self`` for method chaining. .. note:: Each geological strutures can be retrieved as an attribute. For instance to get the code, the label and the pattern density of the 'amphibolite', one can use:: >>> from watex.geology import Structures >>> sobj = Structures().fit() >>> sobj.amphibolite.code ... 'AMP' >>> sobj.amphibolite.label_ ... 'AMP' >>> sobj.amphibolite.pat_density_ ... nan # not set >>> # To get all the key (attributes of the structures ), uses: >>> sobj.keys ... """ df= pd.DataFrame (get_agso_properties(configfile) ) df.fillna (fillna, inplace =True) # rename columns df.columns = df.columns.str.lower().map ( lambda c: 'name' if c =='__description' else c ) # collect name and sanitize attributes regex =re.compile (r'[ -@*#&+/]', flags=re.IGNORECASE) keys = df.name.str.lower().map(lambda o: regex.sub('_', o)) for kk , nn in enumerate (keys): d= {f'{k}_': v for k, v in dict(df.iloc[kk, :]).items()} obj = type (nn, (), d) setattr(self, nn, obj ) # set the keys and names as attributes setattr(self, 'names_', tuple (keys.values)) setattr(self, 'keys_', tuple(df.columns) ) return self
#XXXTODO
[docs] class Geology: """ Geology class deals with all concerns the structures during investigation sites""" def __init__(self, geofn = None, **kwargs)-> None: self._logging =watexlog().get_watex_logger(self.__class__.__name__) pass
[docs] class Structures(GeoBase): """ This class is an auxilliary class to supplement geodatabase , if the GeodataBase doesnt reply to SQL request , then use this class to secah information about structures . If SQL is done as well , program won't call this class as rescure . Containers of more than 150 geological strutures. ================== ============ ========================================= Attributes Type Explanation ================== ============ ========================================= names array_like names of all geological strutures codes array_like names of all geological codes **code str code of specific geological structure **label str label of specific structure **name str label of specific structure **pattern str pattern of specific structure **pat_size str pattern size of specific structure **pat_density str pattern density l of specific structure **pat_thickness str pttern thickess of specific structure **color str color of specific structure ================== ============ ========================================= .. note:: To get the attribute value, merely replace the param "**" by the *name of struture* following by dot ".". See examples: Examples ---------- * To get the names of different strutures, write the script below:: >>> from watex.geology.geology import Structures >>> geo_structure = Structures().fit() >>> geo_structure.names_ # get the list of all geological strutures * To extract color and to get the code of structure like `tonalite`:: >>> from watex.geology.geology import Structures >>> sobj = Structures().fit() >>> sobj.tonalite.pat_thickness_ ... 0. # -> not implemented >>> sobj.tonalite.code_ >>> ...'TNL' >>> sobj.tonalite.color_ ... ''RB128' """ codef =['code','label','__description','pattern', 'pat_size', 'pat_density', 'pat_thickness','color'] def __init__(self, configfile =None , **kwds) : super().__init__(**kwds) self.configfile = configfile for key in list(kwds.keys()): self.__setattr__(key, kwds[key]) @property def coerce(self): """ Force configuration if auto getting the property file fails.""" codef =['code','label','__description','pattern', 'pat_size', 'pat_density','pat_thickness','color'] if self.configfile is None : self.configfile = os.path.join( 'watex/etc', 'agso'.upper() + '.csv' ) if not os.path.isfile (self.configfile ): raise FileNotFoundError("Structure property file not found!") with open(self.configfile, 'r', encoding ='utf8') as f: data = f.readlines() h0 = data[0].strip().split(',') h0 =[_code.lower() for _code in h0] self.data_=data[1:] if sorted(h0) != sorted(codef): warnings.warn("Unable to decode the geological structures!") raise StrataError("Inappropriate structure file:" f" {os.path.basename (self.configfile)!r}") self.data_ = [ geos.strip().split(',') for ii, geos in enumerate(self.data_)] self.data_= np.array (self.data_) # sanitize the geonames . self.__setattr__('names_', np.array( [name.replace('"', '') for name in self.data_[:, 2]] )) self.__setattr__('codes_', self.data_[:, 0]) # set for all values in geofomations codes # count starting from one . for ii, codeff in enumerate(self.codef [1:],1) : if codeff.find('pat') >=0 : for jj, pp in enumerate(self.data_[:, ii]): if pp == '' or pp ==' ' : # replace all None value by 0. # later will filled it self.data_[:, ii][jj]=0. self.__setattr__(codeff, np.array( [float(pp) for pp in self.data_[:, ii]])) else : self.__setattr__(codeff,np.array( [name.replace('"', '') for name in self.data_[:, ii]] )) DECODE ={} # change RGBA color palette into Matplotlib color mpl_colorsp= [ get_color_palette(rgb) for rgb in self.data_[:,-1]] for jj, decode in enumerate(self.data_): for ii, codec in enumerate( self.codef) : if codec =='__description' : codec = 'name' if codec =='color': DECODE[codec]= mpl_colorsp[jj] else : DECODE [codec]= decode[ii] self.__setattr__(decode[2].strip( ).replace('"', '').replace(' ', '_'), DECODE) self.__setattr__(decode[0].strip( ).replace('"', '').replace(' ', '_'), DECODE) DECODE ={} return self
[docs] def fit(self, **kwd ): """ Fit and set the geological strutures as object attributes and `kwd` arguments refer to the argument below. Parameters ----------- configfile: str is a configure file from 'AGS0' data fillna: float, fill NaN values in the AGS0 file. The default values to fill is `0` for False. Notes ----- Each geological strutures can be retrieved as an attribute. For instance to get the code, the label and the pattern density of the 'amphibolite'. Example -------- >>> from watex.geology import Structures >>> sobj = Structures().fit() >>> sobj.amphibolite.code ... 'AMP' >>> sobj.amphibolite.label_ ... 'AMP' >>> sobj.amphibolite.pat_density_ ... 0. # not set >>> # To get all the key (attributes of the structures ), uses:: >>> sobj.keys """ try: setstructures(self, **kwd) except : self.coerce return self
def __repr__(self): """ Pretty format for programmer guidance following the API... """ return repr_callable_obj (self, skip = self.names_) def __getattr__(self, name): if name.endswith ('_'): if name not in self.__dict__.keys(): if name in ( 'keys_', 'names_', 'label_', 'code_', 'pattern_', 'pat_size_', 'pat_density_', 'pat_thickness_','color_'): raise NotFittedError ( f'Fit the {self.__class__.__name__!r} object first' ) rv = smart_strobj_recognition(name, self.__dict__, deep =True) appender = "" if rv is None else f'. Do you mean {rv!r}' raise AttributeError ( f'{self.__class__.__name__!r} object has no attribute {name!r}' f'{appender}{"" if rv is None else "?"}' )
[docs] class Structural(GeoBase) : """ Geology strutural conventions class. Note that the given structural objects are quite less than the litterature More structural object can be added as the structures is known. All geological structural informations are geostructral object. Holds the following informations: ========================== ========== ================================== Attributes Type Explanation ========================== ========== ================================== boudin_axis geos_obj boudin fold_axial_plane geos_obj axial plan of structural fold. banding_gneissosity geos_obj gneissossity of boudin plan s_fabric geos_obj fabric plan fault_plane geos_obj fault plan fracture_joint_set geos_obj fracture joint undifferentiated_plane geos_obj unnamed geological structure sharp_contact geos_obj sharp contact `various discrepancy` contact `stratigraphy discrepancy` fracture or fault discrepancies ========================== ========= ================================== More attributes can be added by inputing a key word dictionary :Example: >>> from watex.geology import Structural >>> s=Structural().fit() >>> s.boudin_axis.code_ ... 'lsb' >>> s.boudin_axis.name_ ... 'Boudin Axis' >>> s.boudin_axis.color_ ... 'R128GB' """ def __init__(self, configfile =None, **kwds): super().__init__(**kwds) self.configfile = configfile for key in list(kwds.keys()): self.__setattr__(key, kwds[key]) pass
[docs] def fit(self, configfile= None , **kwd): """ Configure the structural data and set each object as attributes """ if self.verbose : self._logging.info('Set structural main geological informations. ') is_prop=False if configfile is not None: self.configfile = configfile if self.configfile is None: self.configfile = self.configfile = os.path.join( 'watex/etc', 'agso_stcodes'.upper() + '.csv' ) # hide configfile if the one of the package is used is_prop =True setstructures(self, configfile =self.configfile, **kwd) self.configfile = None if is_prop else self.configfile return self
def __repr__(self): """ Pretty format for programmer guidance following the API... """ return repr_callable_obj (self, skip = self.names_) def __getattr__(self, name): if name.endswith ('_'): if name not in self.__dict__.keys(): if name in ( 'keys_', 'names_', 'label_', 'code_', 'pattern_', 'pat_size_', 'pat_density_', 'pat_thickness_','color_'): raise NotFittedError ( f'Fit the {self.__class__.__name__!r} object first' ) rv = smart_strobj_recognition(name, self.__dict__, deep =True) appender = "" if rv is None else f'. Do you mean {rv!r}' raise AttributeError ( f'{self.__class__.__name__!r} object has no attribute {name!r}' f'{appender}{"" if rv is None else "?"}' )