Source code for hydromodpy.watershed.geology

# -*- coding: utf-8 -*-
"""
 * Copyright (C) 2023-2025 Alexandre Gauvain, Ronan Abhervé, Jean-Raynald de Dreuzy
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
 * which is available at https://www.apache.org/licenses/LICENSE-2.0.
 *
 * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
"""

#%% LIBRAIRIES

# Python
import os
import numpy as np
import rasterio
import whitebox
from hydromodpy.tools import get_logger
wbt = whitebox.WhiteboxTools()
wbt.verbose = False

logger = get_logger(__name__)

#%% CLASS

[docs] class Geology: """ Add geology data in the watershed object. """ def __init__(self, out_path: str, geographic: object, geo_path: str, landsea=None, types_obs='GEO1M.shp', fields_obs='CODE_LEG'): """ Class to clip and extract geology caracteristics from a specific lithology map at the France scale. Source of data: BRGM. Parameters ---------- out_path : str Path of the HydroModPy outputs. geographic : object Variable object of the model domain (watershed). geo_path : str Path of the folder with geology data. landsea : bool If different None. Activate funcitons linked to sea geospatial processing. The default is None. types_obs : str, optional Label of the geological map shapefile at the France scale. The default is 'GEO1M.shp'. fields_obs : TYPE, optional Column field label of the geological map shapefile. The default is 'CODE_LEG'. """ logger.info("Extracting geology data from %s", geo_path) data_folder = os.path.join(out_path,'results_stable/geology/') if not os.path.exists(data_folder): os.makedirs(data_folder) watershed_shp = os.path.join(data_folder,'watershed.shp') self.geol_file = os.path.join(geo_path, types_obs) self.field = fields_obs self.structure_dem_path = os.path.join(data_folder, 'GeoStructure.tif') self.structure_clip = os.path.join(data_folder, 'GeoStructure_clip.tif') # Be careful, column T_M_num not exist in default self.geol_file self.landsea = landsea if self.landsea != None: d_sea_dem_path = os.path.join(data_folder,'Land_Sea.tif') land_sea_clip = os.path.join(data_folder, 'Land_Sea_clip.tif') self.generate_structure_dem(data_folder, geographic) self.geology_array(data_folder) # Problem with this function (sizes of arrays) # self.geology_elevation(geographic) #%% FUNCTIONS
[docs] def generate_structure_dem(self, data_folder, geographic): """ Parameters ---------- data_folder : path Results stable path. geographic : object Variable object of the model domain (watershed). Returns ------- self Add some variable in Geology class self object. """ wbt.vector_polygons_to_raster(self.geol_file, self.structure_dem_path , field=self.field, nodata=None, base=geographic.watershed_buff_dem) wbt.clip_raster_to_polygon(self.structure_dem_path, geographic.watershed_shp, self.structure_clip) if self.landsea != None: wbt.vector_polygons_to_raster(self.geol_file, data_folder + 'Land_Sea.tif', field="T_M_num", nodata=None, base=geographic.watershed_buff_dem) wbt.clip_raster_to_polygon(data_folder + 'Land_Sea.tif', geographic.watershed_shp, data_folder + 'Land_Sea_clip.tif') return self
[docs] def geology_array(self, data_folder): """ Parameters ---------- data_folder : path Results stable path for geology. Returns ------- self Add some variable in Geology class self object. """ with rasterio.open(self.structure_dem_path) as src: dem_data = src.read(1) if self.landsea != None: with rasterio.open(data_folder + 'Land_Sea.tif') as dem_T_M: dem_data_T_M = dem_T_M.read(1) dem_data = dem_data.astype(float, copy=False) dem_data[dem_data_T_M==0] = 1 # Condidering that the part imerged by the sea is a superficial formation self.geology_array = dem_data.astype(int) self.geology_code = np.intersect1d(self.geology_array, self.geology_array) with rasterio.open(self.structure_dem_path) as src_clip: dem_data_clip = src_clip.read(1).astype(float) if self.landsea != None: with rasterio.open(data_folder + 'Land_Sea_clip.tif') as dem_T_M_clip: dem_data_T_M_clip = dem_T_M_clip.read(1) dem_data_clip[dem_data_T_M_clip==0] = 1 # Condidering that the part imerged by the sea is a superficial formation dem_data_clip[dem_data_clip<0]= np.nan self.geology_array_clip = dem_data_clip.astype(int) #self.geology_array[self.geology_array<=100] = int(1) #self.geology_array_clip[self.geology_array_clip<=100] = int(1) self.geology_code_clip = np.intersect1d(self.geology_array_clip, self.geology_array_clip) self.geology_code = self.geology_code_clip[self.geology_code_clip>=0] """ # Double geology self.geology_code = [int(1),int(2)] for i in self.geology_code: if i ==1: self.geology_array[self.geology_array<=100] = int(i) self.geology_array_clip[self.geology_array_clip<=100] = int(i) """ return self
[docs] def geology_elevation(self, geographic): """ Parameters ---------- geographic : object Variable object of the model domain (watershed). Returns ------- self Add some variable in Geology class self object. """ self.geology_elevation = np.ones(len(self.geology_code)) for i in range(0,len(self.geology_code)): self.geology_elevation[i]= np.min(geographic.dem_data[self.geology_array==self.geology_code[i]]) #idxs = self.geology_elevation.argsort() #self.geology_elevation = self.geology_elevation[idxs[:]] #self.geology_code = self.geology_code[idxs[:]] return self
[docs] def geo_to_K(self, K_geo_values): """ Parameters ---------- K_geo_values : list List of K values according to geology code number. Returns ------- self Add some variable in Geology class self object. """ self.K_array = self.geology_array for i in range(0,len(self.geology_code)): self.K_array[self.geology_array==self.geology_code[i]] = K_geo_values[i] """ geology_array: 2D arrays - code of geology entities K_geo_values: 1D array (same size that geology code variable) correspondence between geology codes and hydraulique conductivity values """ return self
#%% NOTES