########################################################################################################################
# Copyright 2021 the authors (see AUTHORS file for full list). #
# #
# This file is part of OpenCMP. #
# #
# OpenCMP is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public #
# License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option) any #
# later version. #
# #
# OpenCMP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied #
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more #
# details. #
# #
# You should have received a copy of the GNU Lesser General Public License along with OpenCMP. If not, see #
# <https://www.gnu.org/licenses/>. #
########################################################################################################################
import ngsolve as ngs
from ngsolve import Parameter, Preconditioner
from typing import List, Optional
from .base_solver import Solver
from typing import Tuple
"""
Module for the stationary solver class.
"""
[docs]class StationarySolver(Solver):
"""
Stationary solver.
"""
def _apply_boundary_conditions(self) -> None:
self.model.apply_dirichlet_bcs_to(self.gfu)
def _assemble(self) -> None:
for i in range(len(self.a)):
self.a[i].Assemble()
self.L[i].Assemble()
self._update_preconditioners()
def _create_linear_and_bilinear_forms(self) -> None:
U, V = self.model.get_trial_and_test_functions()
# Bilinear form
self.a = []
a_coeff_terms = self.model.construct_bilinear_time_coefficient(U, V, Parameter(1.0), 0)
a_ode_terms = self.model.construct_bilinear_time_ODE(U, V)
for i in range(self.model.num_weak_forms):
a = ngs.BilinearForm(self.model.fes)
a += a_coeff_terms[i]
a += a_ode_terms[i]
self.a.append(a)
# Linear form
# NOTE: No IMEX terms since IMEX should only be used with transient solves.
self.L = []
L_terms = self.model.construct_linear(V, None, Parameter(1.0), 0)
for i in range(self.model.num_weak_forms):
L = ngs.LinearForm(self.model.fes)
L += L_terms[i]
self.L.append(L)
def _create_preconditioners(self) -> None:
self.preconditioners = self.model.construct_preconditioners(self.a)
def _update_preconditioners(self, precond_lst: List[Optional[Preconditioner]] = None) -> None:
for preconditioner in self.preconditioners:
if preconditioner is not None:
preconditioner.Update()
def _load_and_apply_initial_conditions(self) -> None:
self.gfu_0_list: List[ngs.GridFunction] = [self.model.construct_gfu()]
def _log_timestep(self, accepted: bool, error_abs: float, error_rel: float, component: str) -> None:
# Print nothing since it's a single iteration
pass
def _re_assemble(self) -> None:
self._assemble()
def _single_solve(self) -> None:
# performs a single linear solve in order to determine the current iterate value
self.model.solve_single_step(self.a, self.L, self.preconditioners, self.gfu)
def _startup(self) -> None:
# Not applicable.
pass
def _update_time_step(self) -> Tuple[bool, float, float, str]:
# Do nothing since it's a stationary solver
return True, -1.0, -1.0, ''