Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add headland inversion example #371

Open
wants to merge 17 commits into
base: master
Choose a base branch
from

Conversation

cpjordan
Copy link
Contributor

Add an inversion example where the velocity is used in the loss formulation, with different methods for constraining the Manning's field e.g. constant, region-based, independent points scheme

cpjordan and others added 9 commits July 19, 2024 12:42
- t passed to cost_fn(t) was out of sync by one timestep so the optimal result was not correct for channel inversion
- Now need to pass the cost function through the export_func rather than through update_forcings
- Typo fixed in Tohoku Makefile as well
- Details are in the README - inversion of Manning field using different field representations:
    - Constant
    - Region-based
    - Independent Points Scheme
    - Free specification at all points in the domain (Hessian regularised)
- Also fix hanging in parallel when using weighting of stations in inversion examples
@cpjordan
Copy link
Contributor Author

@stephankramer @thangel

There are three aspects of this pull request which is intended to provide another example for model calibration using the adjoint-based approach:

  1. Calibrating with velocity magnitude instead of elevation
  2. Showing how to calibrate with a constant value across the domain, regions, independent point scheme in addition to the default of allowing the calibration parameter (e.g. Manning) to vary at every node
  3. Fixing the remaining hanging problems when running in parallel and adding a callback instead of using update_forcings or export_func to embed the loss function

Feedback would be appreciated as to whether this is valuable and anything to change. My thoughts:

  • It would be nice if we didn't need a separate script for the inversion tools for velocity, but I'm wary of trying to cover all scenarios and overcomplicating things in one script
  • The exporting is not very nice when we want to export for the region-based or independent points scheme. Exporting could perhaps be separate from the Inversion Manager class?

Please tag anyone else who this might concern/interest!

Copy link
Contributor

@stephankramer stephankramer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great case and should be a very useful example. I've given some feedback. The inversion_tools_vel module needs some more thought - happy to discuss further...

@@ -15,6 +16,32 @@
import os


class CostFunctionCallback(DiagnosticCallback):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect. Maybe we should provide something like this in a more generic way: there's nothing about cost_function that means it specifically has to be a cost function, I mean any other user defined callback function could use exactly the same code - but let's deal with that potentially in a different PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely. I can update this in a later PR!

thetis/inversion_tools.py Show resolved Hide resolved
examples/headland_inversion/Makefile Outdated Show resolved Hide resolved
examples/headland_inversion/Makefile Outdated Show resolved Hide resolved
examples/headland_inversion/Makefile Outdated Show resolved Hide resolved
examples/headland_inversion/README.md Show resolved Hide resolved
examples/headland_inversion/inverse_problem.py Outdated Show resolved Hide resolved
examples/headland_inversion/inverse_problem.py Outdated Show resolved Hide resolved
examples/headland_inversion/inverse_problem.py Outdated Show resolved Hide resolved
@@ -0,0 +1,827 @@
import firedrake as fd
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs some more thought. It seems this module is just a copy of the original inversion_tools.py with modifications needed to accommodate vector values instead of scalars. This unfortunately not the way to develop code in a sustainable way, as we have now effectively doubled the amount of code that needs to be maintained. What happens if we further down the line want to further develop/fix bugs/make changes in the scalar inversion tools - or there are interface changes in the internal bits of Thetis that are being used in this module. Do I fix both modules, or do we let things diverge? I also can't easily see where this module is actually different from the original. As a general rule, "Copying code" is almost never the answer - except maybe sometimes for quickly getting something to work, but then if you want to keep it, you need to go back and figure out how to refactor and integrate the two without duplication

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, agree with everything you've said. It is indeed just a copy with modifications for outputting the control and gradients as well as updating from elevation -> velocity.

I intentionally didn't merge this script with the base one because I wasn't sure how would be best to go about certain aspects:

  • Do we assume that the calibration parameter is always elevation or velocity (probably) and then automatically detect whether we are dealing with a scalar or vector field? What if we want to use both elevation and velocity data for calibration? Do we limit it to one just now and leave this as a future problem?
  • Is the way I am exporting things optimal? It's a bit of a pain because exporting is only set up for when the control parameter is the whole field, but the way I have dealt with it feels horrible. It seems like exporting might be nicer outside of the InversionManager and StationObservationManager classes...

I will work on this on the second batch of commits!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made the final updates to deal with this. It is assumed that the field for loss evaluation is either velocity or elevation (default). The exporting is fine in any case, though I'd still be tempted to update it in the future.

One extra thing I did was change the base DiagnosticCallback so that the simulation start time is an attribute when exporting to hdf5. This is easier/more direct to load than taking the units string of the variable data and something that a few people had asked me about.

- Add more introduction
- Take the general inversion information out of the full nodal flexibility case
- Add some references
- Small README update also
- Adds necessary shapefiles for forward run
- So that we don't need geopandas as a dependency
- The forward run is tested during the inversion run anyway
- Also fix a lint issue in inversion script
- This is easier to directly load than the units 'time since initial time'
- still keep the units
@cpjordan cpjordan marked this pull request as ready for review September 19, 2024 13:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants