diff --git a/flopy/mf6/data/mfstructure.py b/flopy/mf6/data/mfstructure.py index 34a78a780e..047f2697f8 100644 --- a/flopy/mf6/data/mfstructure.py +++ b/flopy/mf6/data/mfstructure.py @@ -13,6 +13,8 @@ import numpy as np +from flopy.mf6.inspect import get_solution_packages + from ..mfbase import PackageContainer, StructException numeric_index_text = ( @@ -2461,6 +2463,11 @@ def tag_read_as_arrays(self): package_struct.read_as_arrays = True +def _get_solution_packages(): + pkgs = get_solution_packages() + return {k.lower().replace("modflow", ""): "*" for k in pkgs.keys()} + + class MFStructure: """ Singleton class for accessing the contents of the json structure file @@ -2492,7 +2499,9 @@ def __new__(cls, internal_request=False, load_from_dfn_files=False): cls._instance.sim_struct = None cls._instance.dimension_dict = {} cls._instance.load_from_dfn_files = load_from_dfn_files - cls._instance.flopy_dict = {} + cls._instance.flopy_dict = { + "solution_packages": _get_solution_packages() + } # Read metadata from file cls._instance.valid = cls._instance.__load_structure() @@ -2509,9 +2518,6 @@ def __load_structure(self): # set up structure classes self.sim_struct = MFSimulationStructure() - # initialize flopy dict keys - MFStructure().flopy_dict["solution_packages"] = {} - if self.load_from_dfn_files: mf_dfn = Dfn() dfn_files = mf_dfn.get_file_list() @@ -2542,44 +2548,12 @@ def __load_structure(self): "parameter_name": line_lst[6], } MFStructure().flopy_dict[line_lst[3]] = sp_dict - elif line_lst[2] == "solution_package": - MFStructure().flopy_dict["solution_packages"][ - line_lst[3] - ] = line_lst[4:] - if len(MFStructure().flopy_dict["solution_packages"]) == 0: - MFStructure().flopy_dict["solution_packages"]["ims"] = ["*"] - warnings.warn( - "Package definition files (dfn) do not define a solution " - "package. This can happen if your dfn files are out of " - "sync. Auto-loaded default IMS solution package metadata." - " In the future auto-loading default metadata will be " - "deprecated.", - DeprecationWarning, - ) - # process each file for file in dfn_files: self.sim_struct.process_dfn(DfnFile(file)) self.sim_struct.tag_read_as_arrays() else: - package_list = PackageContainer.package_list() - for package in package_list: - # process header - for entry in package.dfn[0][1:]: - if ( - isinstance(entry, list) - and entry[0] == "solution_package" - ): - MFStructure().flopy_dict["solution_packages"][ - package.package_abbr - ] = entry[1:] - # process each package + for package in PackageContainer.package_list(): self.sim_struct.process_dfn(DfnPackage(package)) self.sim_struct.tag_read_as_arrays() - return True - - @staticmethod - def __valid_line(line): - if len(line.strip()) > 1 and line[0] != "#": - return True - return False + return True \ No newline at end of file diff --git a/flopy/mf6/inspect.py b/flopy/mf6/inspect.py new file mode 100644 index 0000000000..525fdff5ba --- /dev/null +++ b/flopy/mf6/inspect.py @@ -0,0 +1,46 @@ +from collections.abc import Mapping + + +def get_classes(predicate=None) -> Mapping[str, type]: + import flopy.mf6.modflow as modflow + from flopy.utils.inspect import get_classes as _get_classes + + return _get_classes( + modflow, + lambda cls: hasattr(cls, "dfn") and (predicate(cls) if predicate else True), + ) + + +def get_multi_packages() -> Mapping[str, type]: + def _filter(cls): + return ( + len(cls.dfn) > 0 + and len(cls.dfn[0]) >= 2 + and cls.dfn[0][1] == "multi-package" + ) + + return get_classes(_filter) + + +def get_solution_packages() -> Mapping[str, type]: + def _filter(cls): + return ( + len(cls.dfn) > 0 + and len(cls.dfn[0]) >= 2 + and len(cls.dfn[0][1]) > 0 + and cls.dfn[0][1][0] == "solution_package" + ) + + return get_classes(_filter) + + +def get_sub_packages() -> Mapping[str, type]: + def _filter(cls): + return ( + len(cls.dfn) > 0 + and len(cls.dfn[0]) >= 2 + and len(cls.dfn[0][1]) > 0 + and cls.dfn[0][1][0] == "subpackage" + ) + + return get_classes(_filter) diff --git a/flopy/utils/inspect.py b/flopy/utils/inspect.py new file mode 100644 index 0000000000..1ded3b83e9 --- /dev/null +++ b/flopy/utils/inspect.py @@ -0,0 +1,8 @@ +import inspect +from collections.abc import Mapping + + +def get_classes(module, predicate=None) -> Mapping[str, type]: + """Find classes in a module which satisfy a predicate.""" + classes = inspect.getmembers(module, inspect.isclass) + return {name: cls for name, cls in classes if predicate(cls)}