Refactor FloPy Simulation, Model, Package #37
Replies: 8 comments 14 replies
-
a few more:
|
Beta Was this translation helpful? Give feedback.
-
Another: we have long discussed converting DFNs to TOML, YAML or some other standard data interchange format. Maybe also opportunities to shrink/revise the DFN specification |
Beta Was this translation helpful? Give feedback.
-
Another from discussion with @langevin-usgs and @jdhughes-usgs: review input file path management. Any component, many blocks, variables, and even parts of variables (e.g. array layers) can be associated with input files (see MF6IO appendix for more details on |
Beta Was this translation helpful? Give feedback.
-
I was playing a bit with "Move static methods to modules". I figured that the # _model_factory.py with an underscore so it's internal
_models_by_type: dict[str, type["MFModel"]] = {}
def register_model_type(model_type: str, model_class: type["MFModel"]) -> None:
_models_by_type[model_type] = model_class
def get_model_class(model_type: str) -> type["MFModel"] | None:
_models_by_type.get(model_type) I don't think it needs to be anything more, and it can be internal this way. We can do a similar setup for the parts of package, because that does exactly the same. |
Beta Was this translation helpful? Give feedback.
-
we can do an incremental deployment once we have a full initial prototype: first internally (flopy tests, mf6 tests, mf6 example models) before considering a public release |
Beta Was this translation helpful? Give feedback.
-
eventually we want to rewrite tutorials/examples where each is more focused/finer-grained/shorter |
Beta Was this translation helpful? Give feedback.
-
I was looking a bit at |
Beta Was this translation helpful? Give feedback.
-
Some items on the topic of parity between flopy3 and flopy4 input files... in general we want to shoot for functionally identical, with possible cosmetic differences. Floating point precision:
Other possible criteria to consider:
|
Beta Was this translation helpful? Give feedback.
-
We will need to make quite some adjustments in the FloPy code base. We will need to refactor the current code base and split out certain functionality into a more modular approach, before we can actually implement some of the new ideas that we have. This discussion aims to make a breakdown of the work that is still to be done. From there we can start estimating the work.
Work with minimal impact on the API
Refactor
PackageContainer
to composition over inheritance ✅I have been playing with the idea of doing a refactor and keeping as much in place as possible. I agree that
PackageContainer
andPackageInterface
are daunting classes, but we can separate the functionality in a more modular fashion to simplify our intentions.What we see in the current flopy design, is the overuse of inheritance where composition would most likely be sufficient. We see that both simulation, model, and package are inheriting from
PackageContainer
, while having aPackageContainer
as a field would be sufficient. Inheritance should be used when there is also functionality that expects any kind ofPackageContainer
, no matter what the subclass is. I have not found such code. In this case inheritance was used to share functionality among different types of classes. Which can also be achieved with composition, as thePackageContainer
doesn't need anything from its subclass and there are no abstract methods inPackageContainer
.During modflowpy/flopy#2324, I came to the point that it was very well possible to do this refactor, but I have doubts on which functions can actually be removed, because they are supposed to be for internal use only. There are options to either just remove them, keep them, or
@deprecate
them.Move functions out of
PackageInterface
that can be done modularWe could also look at other types of functions that could move out, like the
export
functionality. It would make more sense to do this in a similar fashion tocattrs
with a module and single-dispatch functions. The functions that can go out ofPackageInterface
are:plot()
,export()
, andcheck()
.It is possible to do this with minimal user impact by keeping the
plot()
function, but@deprecate
them in favor of the modular version. Theplot()
function inPackageInterface
would simply point to the modular version.Add type hints to critical public classes
I do expect that refactoring is a tough job at the moment, because there are no type hints in the code. VS Code cannot follow the methods and properties when renaming or moving and doesn't give any error messages when functions no longer exist. I recommend adding type hints in the classes we want to refactor, and let mypy run over it.
This can be done with minimal impact on backwards compatibility, as we are just adding type hints, and not removing anything for the user.
Move static methods to modules
Some functions are now decorated as
@staticmethod
, but they don't really apply to their class and could just as well be a global function in a module. E.g.Package.add_to_dtype()
doesn't seem to use anything from thePackage
class and could just as well be a separate function.Similar to making functions like
plot()
more modular, the same accounts for these@staticmethod
s. We could keep the old ones for now and@deprecate
them. Then simply point to the new modular version.Let generate_classes.py use
jinja
✅The code that is now generated with print statements and
write()
functions. It would be so much easier to use jinja, so it is clearer to read the initial file that is being used for generation. The jinja package handles template generation better thanwrite()
with raw strings.Generate dfn classes on user install
See #35.
This idea would have minimal impact on the user, as it is being performed during get-modflow. So no changes in the API.
Work with likely more impact on the user
Use XArray / Dask to speed up performance
See #49.
Use
attrs
for property generationThere is quite some boilerplate code for variable getters and setters. The
attrs
package could help with this and simplify the code.Introducing attr itself and simply replacing the things that we have would not have any impact on the user's code, but if we decide to move / remove certain variables, it will.
Beta Was this translation helpful? Give feedback.
All reactions