|
1 |
| -Introduction |
2 |
| ------------------------------------------------ |
| 1 | +# Developing FloPy for MF6 |
3 | 2 |
|
4 |
| -This file provides an overview of how FloPy for MODFLOW 6 (FPMF6) works under the hood and is intended for anyone who wants to add a new package, new model type, or new features to this library. FloPy library files that support MODFLOW 6 can be found in the flopy/mf6 folder and sub-folders. |
| 3 | +<!-- START doctoc generated TOC please keep comment here to allow auto update --> |
| 4 | +<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> |
5 | 5 |
|
6 |
| -Package Meta-Data and Package Files |
7 |
| ------------------------------------------------ |
| 6 | +- [Introduction](#introduction) |
| 7 | +- [Code generation](#code-generation) |
| 8 | +- [Input specification](#input-specification) |
8 | 9 |
|
9 |
| -FPMF6 uses meta-data files located in flopy/mf6/data/dfn to define the model and package types supported by MODFLOW 6. When additional model and package types are added to MODFLOW 6, additional meta-data files can be added to this folder and flopy/mf6/utils/createpackages.py can be run to add new packages to the FloPy library. createpackages.py uses flopy/mf6/data/mfstructure.py to read meta-data files (*.dfn) and use that meta-data to create the package files found in flopy/mf6/modflow (do not directly modify any of the files in this folder, they are all automatically generated). The automatically generated package files contain an interface for accessing package data and data documentation generated from the meta-data files. Additionally, meta-data describing package data types and shapes is stored in the dfn attribute. flopy/mf6/data/mfstructure.py can load structure information using the dfn attribute (instead of loading it from the meta-data files). This allows for flopy to be installed without the dfn files. |
| 10 | +<!-- END doctoc generated TOC please keep comment here to allow auto update --> |
10 | 11 |
|
11 |
| -All meta-data can be accessed from the flopy.mf6.data.mfstructure.MFStructure class. This is a singleton class, meaning only one instance of this class can be created. The class contains a sim_struct attribute (which is a flopy.mf6.data.mfstructure.MFSimulationStructure object) which contains all of the meta-data for all package files. Meta-data is stored in a structured format. MFSimulationStructure contains MFModelStructure and MFInputFileStructure objects, which contain the meta-data for each model type and each "simulation-level" package (tdis, ims, ...). MFModelStructure contains model specific meta-data and a MFInputFileStructure object for each package in that model. MFInputFileStructure contains package specific meta-data and a MFBlockStructure object for each block contained in the package file. MFBlockStructure contains block specific meta-data and a MFDataStructure object for each data structure defined in the block, and MFDataStructure contains data structure specific meta-data and a MFDataItemStructure object for each data item contained in the data structure. Data structures define the structure of data that is naturally grouped together, for example, the data in a numpy recarray. Data item structures define the structure of specific pieces of data, for example, a single column of a numpy recarray. The meta-data defined in these classes provides all the information FloPy needs to read and write MODFLOW 6 package and name files, create the Flopy interface, and check the data for various constraints. |
| 12 | +## Introduction |
12 | 13 |
|
| 14 | +This file provides an overview of how FloPy's MODFLOW 6 module `flopy.mf6` works under the hood. It is intended for FloPy maintainers, as well as anyone who wants to add a new package, new model, or new features to this library. |
13 | 15 |
|
14 |
| -*** |
15 |
| -MFStructure --+ MFSimulationStructure --+ MFModelStructure --+ MFInputFileStructure --+ MFBlockStructure --+ MFDataStructure --+ MFDataItemStructure |
| 16 | +## Code generation |
16 | 17 |
|
17 |
| -Figure 1: FPMF6 generic data structure classes. Lines connecting classes show a relationship defined between the two connected classes. A "*" next to the class means that the class is a sub-class of the connected class. A "+" next to the class means that the class is contained within the connected class. |
18 |
| -*** |
| 18 | +MODFLOW 6 describes its input specification with definition (DFN) files. |
19 | 19 |
|
20 |
| -Package and Data Base Classes |
21 |
| ------------------------------------------------ |
| 20 | +Definition files describe components (e.g. simulations, models, packages) in the MODFLOW 6 input hierarchy. Definition files are used to generate both source code and documentation. |
22 | 21 |
|
23 |
| -The package and data classes are related as shown below in figure 2. On the top of the figure 2 is the MFPackage class, which is the base class for all packages. MFPackage contains generic methods for building data objects and reading and writing the package to a file. MFPackage contains a MFInputFileStructure object that defines how the data is structured in the package file. MFPackage also contains a dictionary of blocks (MFBlock). The MFBlock class is a generic class used to represent a block within a package. MFBlock contains a MFBlockStructure object that defines how the data in the block is structured. MFBlock also contains a dictionary of data objects (subclasses of MFData) contained in the block and a list of block headers (MFBlockHeader) for that block. Block headers contain the block's name and optionally data items (eg. iprn). |
| 22 | +FloPy can generate a MODFLOW 6 compatibility layer for itself, given a set of definition files: |
| 23 | + |
| 24 | +- `flopy/mf6/utils/createpackages.py`: assumes definition files are in `flopy/mf6/data/dfn` |
| 25 | +- `flopy/mf6/utils/generate_classes.py`: downloads DFNs then runs `createpackages.py` |
| 26 | + |
| 27 | +For instance, to sync with DFNs from the MODFLOW 6 develop branch: |
24 | 28 |
|
| 29 | +```shell |
| 30 | +python -m flopy.mf6.utils.generate_classes --ref develop --no-backup |
| 31 | +``` |
25 | 32 |
|
26 |
| -*** |
27 |
| -MFPackage --+ MFBlock --+ MFData |
| 33 | +Generated files are created in `flopy/mf6/modflow/`. |
28 | 34 |
|
29 |
| -MFPackage --+ MFInputFileStructure |
| 35 | +The code generation utility downloads DFN files, loads them, and uses Jinja to generate corresponding source files. A definition file typically maps 1-1 to a source file and component class, but 1-many is also possible (e.g. a model definition file yields a model class/file and namefile package class/file). |
30 | 36 |
|
31 |
| -MFBlock --+ MFBlockStructure |
| 37 | +**Note**: Code generation requires a few extra dependencies, grouped in the `codegen` optional dependency group: `Jinja2` and `modflow-devtools`. |
32 | 38 |
|
33 |
| -MFData --+ MFDataStructure |
| 39 | +## Input specification |
34 | 40 |
|
35 |
| -MFData --* MFArray --* MFTransientArray |
| 41 | +The `flopy.mf6.data.mfstructure.MFStructure` class represents an input specification. The class is a singleton, meaning only one instance of this class can be created. The class contains a sim_struct attribute (which is a flopy.mf6.data.mfstructure.MFSimulationStructure object) which contains all of the meta-data for all package files. Meta-data is stored in a structured format. MFSimulationStructure contains MFModelStructure and MFInputFileStructure objects, which contain the meta-data for each model type and each "simulation-level" package (tdis, ims, ...). MFModelStructure contains model specific meta-data and a MFInputFileStructure object for each package in that model. MFInputFileStructure contains package specific meta-data and a MFBlockStructure object for each block contained in the package file. MFBlockStructure contains block specific meta-data and a MFDataStructure object for each data structure defined in the block, and MFDataStructure contains data structure specific meta-data and a MFDataItemStructure object for each data item contained in the data structure. Data structures define the structure of data that is naturally grouped together, for example, the data in a numpy recarray. Data item structures define the structure of specific pieces of data, for example, a single column of a numpy recarray. The meta-data defined in these classes provides all the information FloPy needs to read and write MODFLOW 6 package and name files, create the Flopy interface, and check the data for various constraints. |
36 | 42 |
|
37 |
| -MFData --* MFList --* MFTransientList |
| 43 | +```mermaid |
| 44 | +classDiagram |
| 45 | + MFStructure *-- "1" MFSimulationStructure : has |
| 46 | + MFSimulationStructure *-- "1+" MFModelStructure : has |
| 47 | + MFModelStructure *-- "1" MFInputFileStructure : has |
| 48 | + MFInputFileStructure *-- "1+" MFBlockStructure : has |
| 49 | + MFBlockStructure *-- "1+" MFDataStructure : has |
| 50 | + MFDataStructure *-- "1+" MFDataItemStructure : has |
| 51 | +``` |
38 | 52 |
|
39 |
| -MFData --* MFScalar --* MFTransientScalar |
| 53 | +Figure 1: Generic data structure hierarchy. Connections show composition relationships. |
| 54 | + |
| 55 | +The package and data classes are related as shown below in figure 2. On the top of the figure 2 is the MFPackage class, which is the base class for all packages. MFPackage contains generic methods for building data objects and reading and writing the package to a file. MFPackage contains a MFInputFileStructure object that defines how the data is structured in the package file. MFPackage also contains a dictionary of blocks (MFBlock). The MFBlock class is a generic class used to represent a block within a package. MFBlock contains a MFBlockStructure object that defines how the data in the block is structured. MFBlock also contains a dictionary of data objects (subclasses of MFData) contained in the block and a list of block headers (MFBlockHeader) for that block. Block headers contain the block's name and optionally data items (eg. iprn). |
40 | 56 |
|
41 |
| -MFTransientData --* MFTransientArray, MFTransientList, MFTransientScalar |
| 57 | +```mermaid |
| 58 | +classDiagram |
| 59 | +
|
| 60 | +MFPackage *-- "1+" MFBlock : has |
| 61 | +MFBlock *-- "1+" MFData : has |
| 62 | +MFPackage *-- "1" MFInputFileStructure : has |
| 63 | +MFBlock *-- "1" MFBlockStructure : has |
| 64 | +MFData *-- "1" MFDataStructure : has |
| 65 | +MFData <|-- MFArray |
| 66 | +MFArray <|-- MFTransientArray |
| 67 | +MFData <|-- MFList |
| 68 | +MFList <|-- MFTransientList |
| 69 | +MFData <|-- MFScalar |
| 70 | +MFScalar <|-- MFTransientScalar |
| 71 | +MFTransientData <|-- MFTransientArray |
| 72 | +MFTransientData <|-- MFTransientList |
| 73 | +MFTransientData <|-- MFTransientScalar |
| 74 | +``` |
42 | 75 |
|
43 | 76 | Figure 2: FPMF6 package and data classes. Lines connecting classes show a relationship defined between the two connected classes. A "*" next to the class means that the class is a sub-class of the connected class. A "+" next to the class means that the class is contained within the connected class.
|
44 |
| -*** |
45 | 77 |
|
46 | 78 | There are three main types of data, MFList, MFArray, and MFScalar data. All three of these data types are derived from the MFData abstract base class. MFList data is the type of data stored in a spreadsheet with different column headings. For example, the data describing a flow barrier are of type MFList. MFList data is stored in numpy recarrays. MFArray data is data of a single type (eg. all integer values). For example, the model's HK values are of type MFArray. MFArrays are stored in numpy ndarrays. MFScalar data is a single data item. Most MFScalar data are options. All MFData subclasses contain an MFDataStructure object that defines the expected structure and types of the data.
|
47 | 79 |
|
|
0 commit comments