# -*- coding: utf-8 -*-
# This file is part of the pyMOR project (http://www.pymor.org).
# Copyright 2013-2017 pyMOR developers and contributors. All rights reserved.
# License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
from pymor.core.interfaces import ImmutableInterface
from pymor.analyticalproblems.elliptic import EllipticProblem
from pymor.domaindescriptions.basic import RectDomain
from pymor.functions.basic import ConstantFunction
import numpy as np
[docs]class ParabolicProblem(ImmutableInterface):
"""Affinely decomposed linear parabolic problem.
The problem consists in solving ::
| Kd Kv
| ∂_t u(x, t, μ) - ∇ ⋅ ∑ θ_{d,k}(μ) ⋅ d_k(x) ∇ u(x, t, μ) + ∇ ⋅ ∑ θ_{v,k}(μ) v_k(x) u(x, t, μ)
| k=0 k=0
|
| Kr
| + ∑ θ_{r,k}(μ) r_k(x) u(x, t, μ) = f(x, t, μ)
| k=0
|
| u(x, 0, μ) = u_0(x, μ)
for u with t in [0, T], x in Ω.
Parameters
----------
domain
A |DomainDescription| of the domain the problem is posed on.
rhs
The |Function| f(x, t, μ). `rhs.dim_domain` has to agree with the
dimension of `domain`, whereas `rhs.shape_range` has to be `()`.
diffusion_functions
List containing the |Functions| d_k(x), each having `shape_range`
of either `()` or `(dim domain, dim domain)`.
diffusion_functionals
List containing the |ParameterFunctionals| θ_{d,k}(μ). If
`len(diffusion_functions) == 1`, `diffusion_functionals` is allowed
to be `None`, in which case no parameter dependence is assumed.
advection_functions
List containing the |Functions| v_k(x), each having `shape_range`
of `(dim domain,)`.
advection_functionals
List containing the |ParameterFunctionals| θ_{v,k}(μ). If
`len(advection_functions) == 1`, `advection_functionals` is allowed
to be `None`, in which case no parameter dependence is assumed.
reaction_functions
List containing the |Functions| r_k(x), each having `shape_range`
of `()`.
reaction_functionals
List containing the |ParameterFunctionals| θ_{r,k}(μ). If
`len(reaction_functions) == 1`, `reaction_functionals` is allowed
to be `None`, in which case no parameter dependence is assumed.
dirichlet_data
|Function| providing the Dirichlet boundary values.
neumann_data
|Function| providing the Neumann boundary values.
robin_data
Tuple of two |Functions| providing the Robin parameter and boundary values.
initial_data
|Function| providing the initial values.
T
The final time T.
parameter_space
|ParameterSpace| for the problem.
name
Name of the problem.
Attributes
----------
domain
rhs
diffusion_functions
diffusion_functionals
advection_functions
advection_functionals
reaction_functions
reaction_functionals
dirichlet_data
neumann_data
robin_data
initial_data
T
"""
def __init__(self, domain=RectDomain(), rhs=ConstantFunction(dim_domain=2),
diffusion_functions=None,
diffusion_functionals=None,
advection_functions=None,
advection_functionals=None,
reaction_functions=None,
reaction_functionals=None,
dirichlet_data=None, neumann_data=None, robin_data=None,
initial_data=ConstantFunction(dim_domain=2), T=1,
parameter_space=None, name=None):
assert diffusion_functions is None or isinstance(diffusion_functions, (tuple, list))
assert advection_functions is None or isinstance(advection_functions, (tuple, list))
assert reaction_functions is None or isinstance(reaction_functions, (tuple, list))
assert diffusion_functionals is None and diffusion_functions is None \
or diffusion_functionals is None and len(diffusion_functions) == 1 \
or len(diffusion_functionals) == len(diffusion_functions)
assert advection_functionals is None and advection_functions is None \
or advection_functionals is None and len(advection_functions) == 1 \
or len(advection_functionals) == len(advection_functions)
assert reaction_functionals is None and reaction_functions is None \
or reaction_functionals is None and len(reaction_functions) == 1 \
or len(reaction_functionals) == len(reaction_functions)
# for backward compatibility:
if (diffusion_functions is None and advection_functions is None and reaction_functions is None):
diffusion_functions = (ConstantFunction(dim_domain=2),)
# dim_domain:
if diffusion_functions is not None:
dim_domain = diffusion_functions[0].dim_domain
assert rhs.dim_domain == dim_domain
if diffusion_functions is not None:
for f in diffusion_functions:
assert f.dim_domain == dim_domain
if advection_functions is not None:
for f in advection_functions:
assert f.dim_domain == dim_domain
if reaction_functions is not None:
for f in reaction_functions:
assert f.dim_domain == dim_domain
assert dirichlet_data is None or dirichlet_data.dim_domain == dim_domain
assert neumann_data is None or neumann_data.dim_domain == dim_domain
assert robin_data is None or (isinstance(robin_data, tuple) and len(robin_data) == 2)
assert robin_data is None or np.all([f.dim_domain == dim_domain for f in robin_data])
assert initial_data is None or initial_data.dim_domain == dim_domain
self.domain = domain
self.rhs = rhs
self.diffusion_functions = diffusion_functions
self.diffusion_functionals = diffusion_functionals
self.advection_functions = advection_functions
self.advection_functionals = advection_functionals
self.reaction_functions = reaction_functions
self.reaction_functionals = reaction_functionals
self.dirichlet_data = dirichlet_data
self.neumann_data = neumann_data
self.robin_data = robin_data
self.initial_data = initial_data
self.T = T
self.parameter_space = parameter_space
self.name = name
@classmethod
def from_elliptic(cls, elliptic_problem, initial_data=ConstantFunction(dim_domain=2), T=1):
assert isinstance(elliptic_problem, EllipticProblem)
return cls(elliptic_problem.domain, elliptic_problem.rhs,
elliptic_problem.diffusion_functions,
elliptic_problem.diffusion_functionals,
elliptic_problem.advection_functions,
elliptic_problem.advection_functionals,
elliptic_problem.reaction_functions,
elliptic_problem.reaction_functionals,
elliptic_problem.dirichlet_data, elliptic_problem.neumann_data,
elliptic_problem.robin_data,
initial_data, T, elliptic_problem.parameter_space,
'ParabolicProblem_from_{}'.format(elliptic_problem.name))
def elliptic_part(self):
return EllipticProblem(
domain=self.domain,
rhs=self.rhs,
diffusion_functions=self.diffusion_functions,
diffusion_functionals=self.diffusion_functionals,
advection_functions=self.advection_functions,
advection_functionals=self.advection_functionals,
reaction_functions=self.reaction_functions,
reaction_functionals=self.reaction_functionals,
dirichlet_data=self.dirichlet_data,
neumann_data=self.neumann_data,
parameter_space=self.parameter_space,
name='{}_elliptic_part'.format(self.name))