Source code for welltestpy.data.campaignlib

"""Welltestpy subpackage providing flow datastructures for field-campaigns."""
from copy import deepcopy as dcopy

from ..tools import plotter
from . import data_io, testslib, varlib

__all__ = ["FieldSite", "Campaign"]


[docs]class FieldSite: """Class for a field site. This is a class for a field site. It has a name and a description. Parameters ---------- name : :class:`str` Name of the field site. description : :class:`str`, optional Description of the field site. Default: ``"no description"`` coordinates : :class:`Variable`, optional Coordinates of the field site (lat, lon). Default: ``None`` """ def __init__(self, name, description="Field site", coordinates=None): self.name = data_io._formstr(name) self.description = str(description) self._coordinates = None self.coordinates = coordinates @property def info(self): """:class:`str`: Info about the field site.""" info = "" info += "----" + "\n" info += "Field-site: " + str(self.name) + "\n" info += "Description: " + str(self.description) + "\n" info += "--" + "\n" if self._coordinates is not None: info += self._coordinates.info + "\n" info += "----" + "\n" return info @property def pos(self): """:class:`numpy.ndarray`: Position of the field site.""" if self._coordinates is not None: return self._coordinates.value return None @property def coordinates(self): """:class:`numpy.ndarray`: Coordinates of the field site.""" if self._coordinates is not None: return self._coordinates return None @coordinates.setter def coordinates(self, coordinates): if coordinates is not None: if isinstance(coordinates, varlib.Variable): self._coordinates = dcopy(coordinates) else: self._coordinates = varlib.CoordinatesVar( coordinates[0], coordinates[1] ) else: self._coordinates = None def __repr__(self): """Representation.""" return self.name
[docs] def save(self, path="", name=None): """Save a field site to file. This writes the field site to a csv file. Parameters ---------- path : :class:`str`, optional Path where the variable should be saved. Default: ``""`` name : :class:`str`, optional Name of the file. If ``None``, the name will be generated by ``"Field_"+name``. Default: ``None`` Notes ----- The file will get the suffix ``".fds"``. """ return data_io.save_fieldsite(self, path, name)
[docs]class Campaign: """Class for a well based campaign. This is a class for a well based test campaign on a field site. It has a name, a description and a timeframe. Parameters ---------- name : :class:`str` Name of the campaign. fieldsite : :class:`str` or :class:`Variable`, optional The field site. Default: ``"Fieldsite"`` wells : :class:`dict`, optional The wells within the field site. Keys are the well names and values are an instance of :class:`Well`. Default: ``None`` wells : :class:`dict`, optional The tests within the campaign. Keys are the test names and values are an instance of :class:`Test`. Default: ``None`` timeframe : :class:`str`, optional Timeframe of the campaign. Default: ``None`` description : :class:`str`, optional Description of the field site. Default: ``"Welltest campaign"`` """ def __init__( self, name, fieldsite="Fieldsite", wells=None, tests=None, timeframe=None, description="Welltest campaign", ): self.name = data_io._formstr(name) self.description = str(description) self._fieldsite = None self.fieldsite = fieldsite self.__wells = {} self.wells = wells self.__tests = {} self.tests = tests self.timeframe = str(timeframe) @property def fieldsite(self): """:class:`FieldSite`: Field site where the campaign was realised.""" return self._fieldsite @fieldsite.setter def fieldsite(self, fieldsite): if fieldsite is not None: if isinstance(fieldsite, FieldSite): self._fieldsite = dcopy(fieldsite) else: self._fieldsite = FieldSite(str(fieldsite)) else: self._fieldsite = None @property def wells(self): """:class:`dict`: Wells within the campaign.""" return self.__wells @wells.setter def wells(self, wells): if wells is not None: if isinstance(wells, dict): for k in wells.keys(): if not isinstance(wells[k], varlib.Well): raise ValueError( "Campaign: some 'wells' are not of " + "type Well" ) if not k == wells[k].name: raise ValueError( "Campaign: 'well'-keys should be " + "the Well name" ) self.__wells = dcopy(wells) elif isinstance(wells, (list, tuple)): for wel in wells: if not isinstance(wel, varlib.Well): raise ValueError( "Campaign: some 'wells' " + "are not of type u" ) self.__wells = {} for wel in wells: self.__wells[wel.name] = dcopy(wel) else: raise ValueError( "Campaign: 'wells' should be given " + "as dictionary or list" ) else: self.__wells = {} self.__updatewells()
[docs] def add_well( self, name, radius, coordinates, welldepth=1.0, aquiferdepth=None ): """Add a single well to the campaign. Parameters ---------- name : :class:`str` Name of the Variable. radius : :class:`Variable` or :class:`float` Value of the Variable. coordinates : :class:`Variable` or :class:`numpy.ndarray` Value of the Variable. welldepth : :class:`Variable` or :class:`float`, optional Depth of the well. Default: 1.0 aquiferdepth : :class:`Variable` or :class:`float`, optional Depth of the aquifer at the well. Default: ``"None"`` """ well = varlib.Well(name, radius, coordinates, welldepth, aquiferdepth) self.addwells(well)
[docs] def addwells(self, wells): """Add some specified wells. This will add wells to the campaign. Parameters ---------- wells : :class:`dict` Wells to be added. """ if isinstance(wells, dict): for k in wells.keys(): if not isinstance(wells[k], varlib.Well): raise ValueError( "Campaign_addwells: some 'wells' " + "are not of type Well" ) if k in tuple(self.__wells.keys()): raise ValueError( "Campaign_addwells: some 'wells' " + "are already present" ) if not k == wells[k].name: raise ValueError( "Campaign_addwells: 'well'-keys " + "should be the Well name" ) for k in wells.keys(): self.__wells[k] = dcopy(wells[k]) elif isinstance(wells, (list, tuple)): for wel in wells: if not isinstance(wel, varlib.Well): raise ValueError( "Campaign_addwells: some 'wells' " + "are not of type Well" ) if wel.name in tuple(self.__wells.keys()): raise ValueError( "Campaign_addwells: some 'wells' " + "are already present" ) for wel in wells: self.__wells[wel.name] = dcopy(wel) elif isinstance(wells, varlib.Well): self.__wells[wells.name] = dcopy(wells) else: raise ValueError( "Campaign_addwells: 'wells' should be " + "given as dictionary, list or single 'Well'" )
[docs] def delwells(self, wells): """Delete some specified wells. This will delete wells from the campaign. You can give a list of wells or a single well by name. Parameters ---------- wells : :class:`list` of :class:`str` or :class:`str` Wells to be deleted. """ if isinstance(wells, (list, tuple)): for wel in wells: if wel in tuple(self.__wells.keys()): del self.__wells[wel] else: if wells in tuple(self.__wells.keys()): del self.__wells[wells]
@property def tests(self): """:class:`dict`: Tests within the campaign.""" return self.__tests @tests.setter def tests(self, tests): if tests is not None: if isinstance(tests, dict): for k in tests.keys(): if not isinstance(tests[k], testslib.Test): raise ValueError( "Campaign: 'tests' are not of " + "type Test" ) if not k == tests[k].name: raise ValueError( "Campaign: 'tests'-keys " + "should be the Test name" ) self.__tests = dcopy(tests) elif isinstance(tests, (list, tuple)): for tes in tests: if not isinstance(tes, testslib.Test): raise ValueError( "Campaign: some 'tests' are not of " + "type Test" ) self.__tests = {} for tes in tests: self.__tests[tes.name] = dcopy(tes) elif isinstance(tests, testslib.Test): self.__tests[tests.name] = dcopy(tests) else: raise ValueError( "Campaign: 'tests' should be given " + "as dictionary, list or 'Test'" ) else: self.__tests = {}
[docs] def addtests(self, tests): """Add some specified tests. This will add tests to the campaign. Parameters ---------- tests : :class:`dict` Tests to be added. """ if isinstance(tests, dict): for k in tests.keys(): if not isinstance(tests[k], testslib.Test): raise ValueError( "Campaign_addtests: some 'tests' " + "are not of type Test" ) if k in tuple(self.__tests.keys()): raise ValueError( "Campaign_addtests: some 'tests' " + "are already present" ) if not k == tests[k].name: raise ValueError( "Campaign_addtests: 'tests'-keys " + "should be the Test name" ) for k in tests.keys(): self.__tests[k] = dcopy(tests[k]) elif isinstance(tests, (list, tuple)): for tes in tests: if not isinstance(tes, testslib.Test): raise ValueError( "Campaign_addtests: some 'tests' " + "are not of type Test" ) if tes.name in tuple(self.__tests.keys()): raise ValueError( "Campaign_addtests: some 'tests' " + "are already present" ) for tes in tests: self.__tests[tes.name] = dcopy(tes) elif isinstance(tests, testslib.Test): if tests.name in tuple(self.__tests.keys()): raise ValueError("Campaign.addtests: 'test' already present") self.__tests[tests.name] = dcopy(tests) else: raise ValueError( "Campaign_addtests: 'tests' should be " + "given as dictionary, list or single 'Test'" )
[docs] def deltests(self, tests): """Delete some specified tests. This will delete tests from the campaign. You can give a list of tests or a single test by name. Parameters ---------- tests : :class:`list` of :class:`str` or :class:`str` Tests to be deleted. """ if isinstance(tests, (list, tuple)): for tes in tests: if tes in tuple(self.__tests.keys()): del self.__tests[tes] else: if tests in tuple(self.__tests.keys()): del self.__tests[tests]
def __updatewells(self): pass
[docs] def plot(self, select_tests=None, **kwargs): """Generate a plot of the tests within the campaign. This will plot an overview of the tests within the campaign. Parameters ---------- select_tests : :class:`list`, optional Tests that should be plotted. If None, all will be displayed. Default: ``None`` **kwargs Keyword-arguments forwarded to :py:func:`~welltestpy.tools.campaign_plot` """ return plotter.campaign_plot(self, select_tests, **kwargs)
[docs] def plot_wells(self, **kwargs): """Generate a plot of the wells within the campaign. This will plot an overview of the wells within the campaign. Parameters ---------- **kwargs Keyword-arguments forwarded to :py:func:`~welltestpy.tools.campaign_well_plot`. """ return plotter.campaign_well_plot(self, **kwargs)
[docs] def diagnostic_plot(self, pumping_test, observation_well, **kwargs): """Generate a diagnostic plot. Parameters ---------- pumping_test : :class:`str` The pumping well that is saved in the campaign. observation_well : :class:`str` Observation point to make the diagnostic plot. **kwargs Keyword-arguments forwarded to :py:func:`~welltestpy.tools.campaign_well_plot`. """ # check if this is a pumping test if pumping_test in self.tests: if not isinstance(self.tests[pumping_test], testslib.PumpingTest): raise ValueError( f"diagnostic_plot: test '{pumping_test}' is not of instance PumpingTest!" ) # check if the well is present if observation_well in self.wells: return self.tests[pumping_test].diagnostic_plot( observation_well=observation_well, **kwargs ) else: raise ValueError( f"diagnostic_plot: well '{observation_well}' could not be found!" ) else: raise ValueError( f"diagnostic_plot: test '{pumping_test}' could not be found!" )
def __repr__(self): """Representation.""" return ( f"Campaign '{self.name}' at '{self.fieldsite}' with " f"{len(self.wells)} wells and " f"{len(self.tests)} tests" )
[docs] def save(self, path="", name=None): """Save the campaign to file. This writes the campaign to a csv file. Parameters ---------- path : :class:`str`, optional Path where the variable should be saved. Default: ``""`` name : :class:`str`, optional Name of the file. If ``None``, the name will be generated by ``"Cmp_"+name``. Default: ``None`` Notes ----- The file will get the suffix ``".cmp"``. """ return data_io.save_campaign(self, path, name)