-
Notifications
You must be signed in to change notification settings - Fork 0
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
Time-dependent GO adaptation demo and time-dependent constants #137
Conversation
goalie/go_mesh_seq.py
Outdated
if not timedep_const: | ||
forms = enriched_mesh_seq.form(i, mapping) | ||
if not isinstance(forms, dict): | ||
raise TypeError( | ||
"The function defined by get_form should return a dictionary" | ||
f", not type '{type(forms)}'." | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After my changes, this check is never done if timedep_const=True
. But I thought that we could find a better place for this to live anyway so I left it for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surely forms
needs to be defined in the timedep_const
case? Did you have an idea of the 'better place' to put this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup! See #169 :)
I cancelled the workflow because it looked like the GO demo was taking a while (takes about 2-3 minutes for me locally). We should cut it down even further (e.g. use only one fp iteration, decrease Edit: During testing, the mesh resolution, timestep and number of fp iterations are now modified to cut down the time. This helped but it's still quite long: 172s for the GO demo and 105s for the solve_forward one. Locally it takes 48s and 12s, respectively. I am surprised that it takes so long since it's solving it on a super coarse mesh (5x5). So feedback is welcome on how to get this down further :) Edit2: I further reduced it (6 subintervals and increased timestep during testing). They take 18s and 6s for me locally. I cancelled the workflow now to not waste resources - will check the time here after your review when I push other changes. |
3ddc983
to
06403d5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really great work, thanks so much @ddundo!
I have various minor comments. My main comment is the one suggesting that we actually adopt time
as a third (compulsory) argument to form
. Interested to hear what you think about this.
goalie/go_mesh_seq.py
Outdated
if not timedep_const: | ||
forms = enriched_mesh_seq.form(i, mapping) | ||
if not isinstance(forms, dict): | ||
raise TypeError( | ||
"The function defined by get_form should return a dictionary" | ||
f", not type '{type(forms)}'." | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surely forms
needs to be defined in the timedep_const
case? Did you have an idea of the 'better place' to put this?
demos/bubble_shear-goal.py
Outdated
|
||
|
||
def get_form(mesh_seq): | ||
def form(index, form_fields, err_ind_time=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should just add time
as an argument to form
in general? For problems where the form doesn't vary with time, it will just be ignored. IMO it would be better to only pass solution fields (and their lagged counterparts) through the second argument and always determine other variables based on the current time. I guess this would imply some refactoring, including the other demos.
It seems odd to reference error indicators in the form expression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you do end up making this change then it would be handy to fix #140 while you're at it if you don't mind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ddundo I like @jwallwork23's idea of adding time
as an argument in form
. Passing time
directly vs a flag for time would cut down potentially on extra variables and make the intent clear and possibly easier to follow. I can help with demo refractoring if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry @acse-ej321, I just saw this! Please see the new comment I left explaining my reasoning here. I agree that this suggestion is much nicer but I think it's also much more inefficient - unless I'm missing something! Please correct me if I'm wrong :)
demos/bubble_shear-goal.py
Outdated
complexities = np.zeros(len(mesh_seq)) | ||
for i, metric in enumerate(metrics): | ||
complexities[i] = metric.complexity() | ||
mesh_seq[i] = adapt(mesh_seq[i], metric) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Side note: this makes me think about #122.
Thanks a lot for reviewing this @jwallwork23! I addressed the minor comments in the new commit.
I might be missing an obvious solution... but if we make this change, I don't see how we would separate out the problems where we do and do not have these time-dependent constants. So in Edit: And to reply to this related comment here:
If I understood you right, this would mean calling
to something like
I'm trying to avoid this for the same reason as in the first part of this comment. |
Good point. I guess we need |
@ddundo @jwallwork23 - I don't think you would need to go to that extreme in changing the where I pass
and define it in
Firedrake will automatically assemble the |
@acse-ej321 I may be misunderstanding (please correct me!), but if you take a look at L125-L180 in https://github.com/firedrakeproject/firedrake/blob/master/firedrake/solving.py, when you do |
I went to test how expensive this is. I called
Was this referring to calling So in summary: now I don't see a downside to making |
Yes, in general we should create the NVP and repeatedly its solve method rather than calling the |
Okay how about this: we introduce a Some comments:
|
Thanks @jwallwork23, I'll do as you suggested :) |
Actually sorry, I'm not sure I see how that would allow us to address the last paragraph of #55 (comment). That is, in the gray_scott_split.py demo, in
which means that when we are in
So in your suggestion @jwallwork23, what would this E.g. if we had Edit: sorry, I jumped a step ahead... this is what I do locally in my glacier example, where I then completely removed
but rather just pass the correct fields in |
Sorry @ddundo I'm confused.
Edit: (I'm struggling to follow what you're saying without a code example...) |
Yeah, sorry about that... I realised I jumped ahead after I wrote it. I will have more time over the weekend so I will code up your suggestion and post an update :) I'm just trying to avoid refactoring in the future. Thanks again both for the input! |
I was trying out @jwallwork23's suggestion now and I have 2 ugly solutions to offer. So to summarise, the suggestion was:
So this would look something like this:
So we need to somehow get
Am I missing a more elegant solution? :) |
Introduce R-space time `Function`; pull in recent changes from `main`. --------- Co-authored-by: Davor Dundovic <[email protected]> Co-authored-by: acse-ej321 <[email protected]> Co-authored-by: acse-ej321 <[email protected]> Co-authored-by: ddundo <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ddundo Would you mind addressing my comment and rebasing on top of main
?
I've done it but I didn't update the bubble shear demos. I'd prefer to wait for #164 to be merged before making further changes, since that properly takes care of #55, which overlaps with changes in this PR. So I think it would make sense to prioritise that PR before this one for that reason :) |
I converted this to ready for review to draw more attention to it :) as I mentioned in the meeting (and as discussed in the long thread above), it remains to decide how to communicate these "time-dependent constants" within Goalie. The two new demos fail - I haven't updated them yet to |
Hi @jwallwork23 @stephankramer @acse-ej321, here is the summary of the issue :) I will also start by saying that the PR is longish because there are 2 demos, but it is enough to just look at one of them (either one) for the purposes of the discussion here In this specific bubble shear case example, we have a background velocity field that we do not solve for - we just update it at each timestep. How goalie is currently set up, when we call So the problem we need to solve is how to update these fields in Here is the idea that I had how we could do this automatically, without requiring extra effort from the user. We could identify these changing fields and extract them from the So we could extract and save a copy of these fields at each exported timestep, before then using them in
|
Apologies for the delay getting back to you @ddundo. This sounds like a great approach to me. It'd be preferable if you could break down the efforts into several small PRs, if possible. e.g., start by splitting up the |
Thanks @jwallwork23! I'll do it in steps as you suggested :) |
Closes #28.
In this PR I add a bubble shear goal-oriented adaptation demo. It involves a time-varying velocity field which is prescribed and not solved for. So to ease into the GO demo, I also add a simple
solve_forward
bubble shear demo to introduce the idea of "time-dependent" constants.Related to #73 discussion: I added a check in
GoalOrientedMeshSequence.indicate_errors
to see whether the user flagged in theirget_form
that there are time-dependent constants. In that case, I recompile the form for each exported timestep, which should update these fields. By "flag" I mean that the form function contains the kwargerr_ind_time
, i.e.:def form(index, fields, err_ind_time=None)
. I am not fully happy with this so I also didn't fully tidy up the go_mesh_seq.py code, as I hope to get feedback from you on how to improve this - but here is my reasoning behind it:indicate_errors()
. Instead we can (and should) update the time-dependent constants inget_solver
.err_ind_time
is unique enough to be sure that the user won't randomly choose it.Overall, I think it's a good solution but I am happy to keep #73 open and explore other ideas.
I will make 2 comments in the code myself where things are left undone.
And I tried to keep the demos cheap (to prevent the testing suite taking too long) so the results could be better, but they still look good I'd say!