Skip to content

Design simplification #728

@pavelkomarov

Description

@pavelkomarov

I have some suggestions after reading through more of the documentation:

  • More of the objects' parameters, like the Controller's tfinal and a State's q values and a Solver's BCs, should be arguments to the respective constructors. I don't want to have to futz with object parameters after object creation, and I don't want to be able to create an object that isn't usable because something isn't yet set. Take inspiration from scikit-learn, with those long parameter lists, mostly kwargs set to defaults, with BIG docstrings explaining how each controls the object.
  • There should be fewer ways to do things. I want one right way. That way can be flexible, but right now, e.g., initializing a Solution from a file, a frame number in memory, from a lower-level list of dimensions, etc. constitute a lot of pretty different methods, each of which takes brain space. Give me one function or one constructor with well-documented parameters to handle the different cases. Removing support for less-used options or folding them in to others will greatly shorten the code and make it easier to maintain. For example, a Controller can iterate over basically a linspace of times, or over a list of output times, or just give an output frame every kth iteration. If you say "Always give me a list", then that covers the first two use cases (because I can in-line a linspace call somewhere), and you can remove the other two paths from the code.
  • States take a Domain, Patch, Grid, or list of Dimensions at initialization, and then the Solution, which contains States also takes geometry. Why? Can't it get the geometry by asking its sub-objects for their geometries? Maybe there is a good reason, but I found this confusing and possibly redundant.
  • The documentation says Patch "contains a reference to a nearly identical Grid object". If they're nearly identical, why are there two, neither inheriting from the other? Remember the Zen of Python, "There should be one-- and preferably only one --obvious way to do it."
  • Limiters are still confusing to me. The fact they're set by number instead of by name or enum makes them all the more abstruse. Instead of a dictionary from int->function, do string->function or something.
  • problem_data feels like it should belong to the Solver for a given problem, not to the State.
  • What is the difference between compute_p and compute_F? I get the sense p is defined over the whole geometry, and F can only be a single value. But they're both derived quantities. I say the concepts should be merged: You can either compute a derived quantity over the whole field, or you can sum out a scalar value.
  • I'm finding myself not using the run_app_from_main utility. It's easier to call run on a Controller and then call the plot function or do anything else I want with it afterward. I feel like trying to make a command-line utility with htmlplot=True and other specially-named arguments isn't necessary and again gives me an extra way to do things (also hides where some things are actually happening), when my degrees of freedom already feel overwhelming.

Of all of them, the first is the most important.

In my opinion, on the surface, at the level of examples, it should be far fewer than 300 lines to get going. A lot of complexity can be abstracted or deduplicated away. Seduce me as a user.

That said, I think the division of things into the various .py files makes pretty good sense. The fact the Riemann Solvers live in a totally different package was my most major point of confusion. There is just a lot of code. I find myself greping to find things often.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions