Source code for wrfhydropy.core.domain

import pathlib
import shutil

from .ioutils import \
    WrfHydroStatic, \
    WrfHydroTs
from .namelist import JSONNamelist


[docs]class Domain(object): """Class for a WRF-Hydro domain, which constitutes all domain-specific files needed for a setup. """
[docs] def __init__(self, domain_top_dir: str, domain_config: str, compatible_version: str = None, hydro_namelist_patch_file: str = 'hydro_namelist_patches.json', hrldas_namelist_patch_file: str = 'hrldas_namelist_patches.json' ): """Instantiate a Domain object Args: domain_top_dir: Parent directory containing all domain directories and files. domain_config: The domain configuration to use, options are 'NWM', 'Gridded', or 'Reach' compatible_version: String indicating the compatible model version, required if no .version file included in domain_top_dir. hydro_namelist_patch_file: Filename of json file containing namelist patches for hydro namelist hrldas_namelist_patch_file: Filename of json file containing namelist patches for hrldas namelist """ # Instantiate arguments to object # Make file paths self.domain_top_dir = pathlib.Path(domain_top_dir).absolute() """pathlib.Path: pathlib.Paths to *.TBL files generated at compile-time.""" self.domain_config = domain_config.lower() """str: Specified configuration for which the domain is to be used, e.g. 'NWM_ana'""" self.compatible_version = compatible_version """str: Source-code version for which the domain is to be used.""" # Check .version file if compatible_version not specified if self.compatible_version is None: try: with self.domain_top_dir.joinpath('.version').open() as f: self.compatible_version = f.read() except FileNotFoundError: raise FileNotFoundError('file .version not found in directory ' + str(self.domain_top_dir) + ' and compatible_version not ' 'specified') # Load namelist patches hydro_namelist_patch_file = self.domain_top_dir.joinpath(hydro_namelist_patch_file) hrldas_namelist_patch_file = self.domain_top_dir.joinpath(hrldas_namelist_patch_file) self.hydro_namelist_patches = JSONNamelist(str(hydro_namelist_patch_file)) """Namelist: Domain-specific hydro namelist settings.""" self.hydro_namelist_patches = self.hydro_namelist_patches.get_config(self.domain_config) self.hrldas_namelist_patches = JSONNamelist(str(hrldas_namelist_patch_file)) """Namelist: Domain-specific hrldas namelist settings.""" self.hrldas_namelist_patches = self.hrldas_namelist_patches.get_config(self.domain_config) self.hydro_files = list() """list: Files specified in hydro_nlist section of the domain namelist patches""" self.nudging_files = list() """list: Files specified in nudging_nlist section of the domain namelist patches""" self.lsm_files = list() """list: Files specified in noahlsm_offline section of the domain namelist patches""" self.nudging_dir = None """pathlib.Path: path to the nudging obs directory""" self.forcing_dir = None """pathlib.Path: path to the forcing directory""" ### # Create file paths from hydro namelist domain_hydro_nlist = self.hydro_namelist_patches['hydro_nlist'] for key, value in domain_hydro_nlist.items(): file_path = self.domain_top_dir.joinpath(str(value)) if file_path.is_file() is True: if file_path.suffix == '.nc': self.hydro_files.append(WrfHydroStatic(file_path)) else: self.hydro_files.append(file_path) # Create file paths from nudging namelist domain_nudging_nlist = self.hydro_namelist_patches['nudging_nlist'] for key, value in domain_nudging_nlist.items(): file_path = self.domain_top_dir.joinpath(str(value)) if file_path.is_file() is True: if file_path.suffix == '.nc': self.nudging_files.append(WrfHydroStatic(file_path)) else: self.nudging_files.append(file_path) if key == 'timeslicepath' and value != '': self.nudging_dir = file_path self.nudging_files.append(WrfHydroTs(file_path.glob('*'))) # Create file paths from lsm namelist domain_lsm_nlist = \ self.hrldas_namelist_patches["noahlsm_offline"] for key, value in domain_lsm_nlist.items(): file_path = self.domain_top_dir.joinpath(str(value)) if file_path.is_file() is True: if file_path.suffix == '.nc': self.lsm_files.append(WrfHydroStatic(file_path)) else: self.lsm_files.append(file_path) if key == 'indir': self.forcing_dir = file_path self.forcing_data = WrfHydroTs(self.forcing_dir.glob('*'))
[docs] def copy_files(self, dest_dir: str, symlink: bool = True): """Copy domain files to a new directory Args: dir: The destination directory for domain files symlink: Symlink domain files instead of copy """ # Convert dir to pathlib.Path dest_dir = pathlib.Path(dest_dir) # Make directory if it does not exist. if not dest_dir.is_dir(): dest_dir.mkdir(parents=True) # Create symlinks/copies # Symlink/copy in forcing from_dir = self.forcing_dir to_dir = dest_dir.joinpath(from_dir.name) if symlink: to_dir.symlink_to(from_dir, target_is_directory=True) else: shutil.copytree(str(from_dir), str(to_dir)) # create DOMAIN directory and symlink in files # Symlink in hydro_files for from_path in self.hydro_files: # Get new file path for run directory, relative to the top-level domain directory # This is needed to ensure the path matches the domain namelist try: relative_path = from_path.relative_to(self.domain_top_dir) except ValueError: pass else: to_path = dest_dir.joinpath(relative_path) if to_path.parent.is_dir() is False: to_path.parent.mkdir(parents=True) if symlink: to_path.symlink_to(from_path) else: shutil.copy(str(from_path), str(to_path)) # Symlink in nudging files # handling nudging obs files # Users may signal "None" by the null string (''), treat them the same. if not (self.nudging_dir is None or self.nudging_dir is ''): from_dir = self.nudging_dir try: to_dir = dest_dir.joinpath(from_dir.relative_to(self.domain_top_dir)) except ValueError: pass else: if symlink: to_dir.symlink_to(from_dir, target_is_directory=True) else: shutil.copy(str(from_dir), str(to_dir)) for from_path in self.nudging_files: # Get new file path for run directory, relative to the top-level domain directory # This is needed to ensure the path matches the domain namelist if type(from_path) is not WrfHydroTs: try: relative_path = from_path.relative_to(self.domain_top_dir) except ValueError: pass else: to_path = dest_dir.joinpath(relative_path) if to_path.parent.is_dir() is False: to_path.parent.mkdir(parents=True) if symlink: to_path.symlink_to(from_path) else: shutil.copy(str(from_path), str(to_path)) # Symlink in lsm files for from_path in self.lsm_files: # Get new file path for run directory, relative to the top-level domain directory # This is needed to ensure the path matches the domain namelist try: relative_path = from_path.relative_to(self.domain_top_dir) except ValueError: pass else: to_path = dest_dir.joinpath(relative_path) if to_path.parent.is_dir() is False: to_path.parent.mkdir(parents=True) if symlink: to_path.symlink_to(from_path) else: shutil.copy(str(from_path), str(to_path)) model_files = [*self.hydro_files, *self.nudging_files, *self.lsm_files] for ff in model_files: if type(ff) is not WrfHydroTs: if 'RESTART' in str(ff.name): to_path = dest_dir.joinpath(ff.name).absolute() if symlink: to_path.symlink_to(ff) else: shutil.copy(str(ff), str(to_path)) if 'HYDRO_RST' in str(ff.name): to_path = dest_dir.joinpath(ff.name).absolute() if symlink: to_path.symlink_to(ff) else: shutil.copy(str(ff), str(to_path)) if 'nudgingLastObs' in str(ff.name): to_path = dest_dir.joinpath(ff.name).absolute() if symlink: to_path.symlink_to(ff) else: shutil.copy(str(ff), str(to_path))