def diagnostic_solve(self, u0, h, s, dirichlet_ids, tol=1e-6, **kwargs): r"""Solve for the ice velocity from the thickness and surface elevation Parameters ---------- u0 : firedrake.Function Initial guess for the ice velocity; the Dirichlet boundaries are taken from `u0` h : firedrake.Function Ice thickness s : firedrake.Function Ice surface elevation dirichlet_ids : list of int list of integer IDs denoting the parts of the boundary where Dirichlet boundary conditions should be applied tol : float dimensionless tolerance for when to terminate Newton's method Returns ------- u : firedrake.Function Ice velocity Other parameters ---------------- **kwargs All other keyword arguments will be passed on to the `viscosity`, `friction`, `gravity`, and `terminus` functions that were set when this model object was initialized """ u = u0.copy(deepcopy=True) boundary_ids = u.ufl_domain().exterior_facets.unique_markers side_wall_ids = kwargs.get('side_wall_ids', []) kwargs['side_wall_ids'] = side_wall_ids kwargs['ice_front_ids'] = list( set(boundary_ids) - set(dirichlet_ids) - set(side_wall_ids)) bcs = firedrake.DirichletBC(u.function_space(), firedrake.as_vector((0, 0)), dirichlet_ids) params = {'quadrature_degree': self.quadrature_degree(u, h, **kwargs)} action = self.action(u=u, h=h, s=s, **kwargs) scale = self.scale(u=u, h=h, s=s, **kwargs) problem = MinimizationProblem(action, scale, u, bcs, params) solver = NewtonSolver(problem, tol) solver.solve() return u
def setup(self, **kwargs): for name, field in kwargs.items(): if name in self._fields.keys(): self._fields[name].assign(field) else: if isinstance(field, firedrake.Constant): self._fields[name] = firedrake.Constant(field) elif isinstance(field, firedrake.Function): self._fields[name] = field.copy(deepcopy=True) else: raise TypeError( "Input %s field has type %s, must be Constant or Function!" % (name, type(field)) ) # Create homogeneous BCs for the Dirichlet part of the boundary u = self._fields["velocity"] V = u.function_space() # NOTE: This will have to change when we do Stokes! if hasattr(V._ufl_element, "_sub_element"): bcs = firedrake.DirichletBC(V, Constant((0, 0)), self._dirichlet_ids) else: bcs = firedrake.DirichletBC(V, Constant(0), self._dirichlet_ids) if not self._dirichlet_ids: bcs = None # Find the numeric IDs for the ice front boundary_ids = u.ufl_domain().exterior_facets.unique_markers ice_front_ids_comp = set(self._dirichlet_ids + self._side_wall_ids) ice_front_ids = list(set(boundary_ids) - ice_front_ids_comp) # Create the action and scale functionals _kwargs = {"side_wall_ids": self._side_wall_ids, "ice_front_ids": ice_front_ids} action = self._model.action(**self._fields, **_kwargs) scale = self._model.scale(**self._fields, **_kwargs) # Set up a minimization problem and solver quadrature_degree = self._model.quadrature_degree(**self._fields) params = {"quadrature_degree": quadrature_degree} problem = MinimizationProblem(action, scale, u, bcs, params) self._solver = NewtonSolver( problem, self._tolerance, solver_parameters=self._solver_parameters, max_iterations=self._max_iterations, )
def setup(self, **kwargs): for name, field in kwargs.items(): if name in self._fields.keys(): self._fields[name].assign(field) else: self._fields[name] = utilities.copy(field) # Create homogeneous BCs for the Dirichlet part of the boundary u = self._fields.get('velocity', self._fields.get('u')) V = u.function_space() # NOTE: This will have to change when we do Stokes! bcs = firedrake.DirichletBC(V, Constant((0, 0)), self._dirichlet_ids) if not self._dirichlet_ids: bcs = None # Find the numeric IDs for the ice front boundary_ids = u.ufl_domain().exterior_facets.unique_markers ice_front_ids_comp = set(self._dirichlet_ids + self._side_wall_ids) ice_front_ids = list(set(boundary_ids) - ice_front_ids_comp) # Create the action and scale functionals _kwargs = { 'side_wall_ids': self._side_wall_ids, 'ice_front_ids': ice_front_ids } action = self._model.action(**self._fields, **_kwargs) scale = self._model.scale(**self._fields, **_kwargs) # Set up a minimization problem and solver quadrature_degree = self._model.quadrature_degree(**self._fields) params = {'quadrature_degree': quadrature_degree} problem = MinimizationProblem(action, scale, u, bcs, params) self._solver = NewtonSolver(problem, self._tolerance, solver_parameters=self._solver_parameters, max_iterations=self._max_iterations)
class IcepackSolver: def __init__(self, model, fields, solver_parameters, dirichlet_ids=[], side_wall_ids=[]): r"""Diagnostic solver implementation using hand-written Newton line search optimization algorithm""" self._model = model self._fields = fields self._solver_parameters = solver_parameters.copy() self._tolerance = self._solver_parameters.pop('tolerance', 1e-12) self._max_iterations = self._solver_parameters.pop( 'max_iterations', 50) self._dirichlet_ids = dirichlet_ids self._side_wall_ids = side_wall_ids def setup(self, **kwargs): for name, field in kwargs.items(): if name in self._fields.keys(): self._fields[name].assign(field) else: if isinstance(field, firedrake.Constant): self._fields[name] = firedrake.Constant(field) elif isinstance(field, firedrake.Function): self._fields[name] = field.copy(deepcopy=True) else: raise TypeError( 'Input fields must be Constant or Function!') # Create homogeneous BCs for the Dirichlet part of the boundary u = self._fields.get('velocity', self._fields.get('u')) V = u.function_space() # NOTE: This will have to change when we do Stokes! bcs = firedrake.DirichletBC(V, Constant((0, 0)), self._dirichlet_ids) if not self._dirichlet_ids: bcs = None # Find the numeric IDs for the ice front boundary_ids = u.ufl_domain().exterior_facets.unique_markers ice_front_ids_comp = set(self._dirichlet_ids + self._side_wall_ids) ice_front_ids = list(set(boundary_ids) - ice_front_ids_comp) # Create the action and scale functionals _kwargs = { 'side_wall_ids': self._side_wall_ids, 'ice_front_ids': ice_front_ids } action = self._model.action(**self._fields, **_kwargs) scale = self._model.scale(**self._fields, **_kwargs) # Set up a minimization problem and solver quadrature_degree = self._model.quadrature_degree(**self._fields) params = {'quadrature_degree': quadrature_degree} problem = MinimizationProblem(action, scale, u, bcs, params) self._solver = NewtonSolver(problem, self._tolerance, solver_parameters=self._solver_parameters, max_iterations=self._max_iterations) def solve(self, **kwargs): r"""Solve the diagnostic model physics for the ice velocity""" if not hasattr(self, '_solver'): self.setup(**kwargs) else: for name, field in kwargs.items(): self._fields[name].assign(field) # Solve the minimization problem and return the velocity field self._solver.solve() u = self._fields.get('velocity', self._fields.get('u')) return u.copy(deepcopy=True)