Skip to content

Conversation

ddundo
Copy link
Member

@ddundo ddundo commented Nov 23, 2024

Closes #238. Closes #22.

Summary (so far):

  • Introduced goalie.solver.Solver that all user-defined problems should inherit from
  • MeshSeq now only has these methods left: count_elements, count_vertices, plot, set_meshes
  • get_solver no longer requires a nested solver function (Clean up wrapping of getter functions #22)
  • Renamed AdjointMeshSeq and GoalOrientedMeshSeq to AdjointSolver and GoalOritentedSolver, respectively
Example workflow

class MySolver(Solver):
    def get_function_spaces(self, mesh):
        ...
        
    def get_solver(self, index):
        # No longer has a nested solver function
        ...
        
    def get_initial_conditions(self):
        ...
        
time_partition = ... # as before
mesh_sequence = MeshSeq(list_of_meshes)
solver = MySolver(time_partition, mesh_sequence)
solver.solve_forward()
solver.fixed_point_iteration(adaptor)


Won't do in this PR:

  • Rename Solver and its methods? Maybe Model would be better and then rename get_initial_condition to initial_condition, etc.? Can introduce a Model class in another PR. This would require Passing information to user-defined get_* functions as kwargs #279 or a similar solution
  • Pass field_names and field_types to Solver so that it's self-contained

@ddundo
Copy link
Member Author

ddundo commented Nov 29, 2024

@acse-ej321 we very briefly discussed this on the meeting and @jwallwork23 is in principle in favour of this. If you are as well, maybe you could try this approach for your enriched mesh seq issue and see if that solves it? I think it should since the two are now separated :)

@jwallwork23
Copy link
Member

Please change branch target to develop.

@ddundo ddundo changed the base branch from main to develop January 17, 2025 11:02
@ddundo
Copy link
Member Author

ddundo commented Jan 27, 2025

@jwallwork23 @acse-ej321 could you please take a look at the small commit 73f3610 where I added the Model class and updated the burgers.py demo? Since the Model class is now separate from Solver, I added time_partition, fields, function_spaces, and meshes to the signatures of get_ functions.

Do you agree with this? I find it a bit messy, but I don't have a different suggestion.

@acse-ej321
Copy link
Collaborator

@jwallwork23 @acse-ej321 could you please take a look at the small commit 73f3610 where I added the Model class and updated the burgers.py demo? Since the Model class is now separate from Solver, I added time_partition, fields, function_spaces, and meshes to the signatures of get_ functions.

Do you agree with this? I find it a bit messy, but I don't have a different suggestion.

@dundo just a few quick observations:

  • The Model class itself is still appealing partially from a separation of concerns and, as @jwallwork23 noted last week, it also somewhat isolates the user functions related to the problem definition independent of the time or space discretisation. But, as you have noticed, this makes the variables passed to the methods messy.
  • Some ideas (though I don't think they make it any less messy):
    • if we added get_field_names to the Model and move field_types and steady to the Solver the TimePartition class would be just related to the time discrimination
    • get_initial_condition like get_function_space takes mesh and function_space in the arguments; or just mesh and/or internally calls get_function_spaces(mesh)
    • if you strip the arguments for get_solver back to those independent of Solver, I think you get: mesh,t_start,t_end,dt,initial_condition; - this is still messy but potentially independent from the time and space discritisation used.
    • if you strip the arguments for get_qoi back you get: mesh,dt,solution or solutions

Your unstated question is a good one: whether the benefit of making the user input mostly independent is outweighed by added complexity to the API?

@ddundo
Copy link
Member Author

ddundo commented Jan 31, 2025

Thanks @acse-ej321!

  • if we added get_field_names to the Model and move field_types and steady to the Solver the TimePartition class would be just related to the time discrimination

I agree but I don't want to make changes related to #181 in this PR since this will require more discussion I think.

  • get_initial_condition like get_function_space takes mesh and function_space in the arguments; or just mesh and/or internally calls get_function_spaces(mesh)

Solver already builds and stores function spaces (in Solver._fs) so I don't want to call get_function_spaces again since that will rebuild them.

  • if you strip the arguments for get_solver back to those independent of Solver, I think you get: mesh,t_start,t_end,dt,initial_condition; - this is still messy but potentially independent from the time and space discritisation used.

So you would prefer not to pass a TimePartition instance as an argument? I don't see a problem with doing that, to be honest :)

  • if you strip the arguments for get_qoi back you get: mesh,dt,solution or solutions

I would prefer to keep arguments the same in all methods and to pass everything

  1. for simplicity
  2. and because someone might actually use them. For example, we currently don't use Solver.function_spaces in get_qoi in any of our demos, but we definitely might want to

@ddundo ddundo mentioned this pull request Mar 14, 2025
@ddundo ddundo marked this pull request as draft April 18, 2025 15:25
Comment on lines 36 to 44
class BurgersModel(Model):
def get_initial_condition(self, time_partition, meshes, fields, function_spaces):
fs = function_spaces["u"][0]
x, y = SpatialCoordinate(meshes[0])
return {"u": Function(fs).interpolate(as_vector([sin(pi * x), 0]))}

def get_solver(
self, index, time_partition, meshes, field_functions, function_spaces
):
Copy link
Member Author

Choose a reason for hiding this comment

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

We have a Model class which is separate from the Solver class, so we need to pass time_partition, meshes, field_functions, and function_spaces from the Solver to Model's get_* methods.

Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer not to keep passing all these arguments repeatedly. Could we not pass the time_partition to the __init__ method of the Model? Also, we should be able to determine the fields and function spaces using that information, no? Then we'd only need to pass meshes and indices to these methods.

Comment on lines 57 to 71
qoi = mesh_seq.get_qoi(index)
qoi = self.get_qoi(
index, time_partition, meshes, field_functions, function_spaces
)
while t < t_end - 1.0e-05:
solve(F == 0, u, ad_block_tag="u")
mesh_seq.J += qoi(t)
yield
self.J += qoi(t)
Copy link
Member Author

Choose a reason for hiding this comment

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

Time-integrated qoi requires us to communicate J from the Model to the Solver.

Similarly for goal-oriented error estimation, where we currently use GoalOrientedMeshSeq.read_forms({"field": Form}). We need to modify it so that {"field": Form} gets passed from Model to Solver

Copy link
Member Author

Choose a reason for hiding this comment

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

Simplest solution would be to pass J as an argument to get_* functions as well. I think this is fine since we plan to add QoIs for Hessian-based adaptations too (#280)

Copy link
Member

Choose a reason for hiding this comment

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

I think the way we handle the J attribute needs some rethinking anyway. How about you draft something and then we can comment further on that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
refactor A suggested reworking of the code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Introduce a helper Solver class Clean up wrapping of getter functions
3 participants