# Source code for sfepy.discrete.conditions

```"""
The Dirichlet, periodic and linear combination boundary condition
classes, as well as the initial condition class.
"""
from __future__ import absolute_import
import numpy as nm

from sfepy.base.base import basestr, Container, Struct, is_sequence
from sfepy.discrete.functions import Function
import six

[docs]def get_condition_value(val, functions, kind, name):
"""
Check a boundary/initial condition value type and return the value or
corresponding function.
"""
if type(val) == str:
if functions is not None:
try:
fun = functions[val]

except IndexError:
raise ValueError('unknown function %s given for %s %s!'
% (val, kind, name))

else:
raise ValueError('no functions given for %s %s!' % (kind, name))

elif (isinstance(val, Function) or nm.isscalar(val)
or isinstance(val, nm.ndarray)):
fun = val

elif is_sequence(val):
fun = nm.array(val)

else:
raise ValueError('unknown value type for %s %s!'
% (kind, name))

return fun

def _get_region(name, regions, bc_name):
try:
region = regions[name]
except IndexError:
msg = "no region '%s' used in condition %s!" % (name, bc_name)
raise IndexError(msg)

return region

[docs]class Conditions(Container):
"""
Container for various conditions.
"""
[docs]    @staticmethod
def from_conf(conf, regions):
conds = []
for key, cc in six.iteritems(conf):
times = cc.get('times', None)

if key.startswith("ebc"):
region = _get_region(cc.region, regions, cc.name)
cond = EssentialBC(cc.name, region, cc.dofs, key=key,
times=times)

elif key.startswith("epbc"):
rs = [_get_region(ii, regions, cc.name) for ii in cc.region]
cond = PeriodicBC(cc.name, rs, cc.dofs, cc.match, key=key,
times=times)

elif key.startswith('lcbc'):
if isinstance(cc.region, basestr):
rs = [_get_region(cc.region, regions, cc.name), None]

else:
rs = [_get_region(ii, regions, cc.name)
for ii in cc.region]

cond = LinearCombinationBC(cc.name, rs, cc.dofs,
cc.dof_map_fun, cc.kind,
key=key,
times=times,
arguments=cc.get('arguments', None))

elif key.startswith('dgebc'):
region = _get_region(cc.region, regions, cc.name)
cond = DGEssentialBC(cc.name, region, cc.dofs, key=key,
times=times)

elif key.startswith('dgepbc'):
rs = [_get_region(ii, regions, cc.name) for ii in cc.region]
cond = DGPeriodicBC(cc.name, rs, cc.dofs, cc.match, key=key,
times=times)

elif 'ic' in key:
region = _get_region(cc.region, regions, cc.name)
cond = InitialCondition(cc.name, region, cc.dofs, key=key)

else:
raise ValueError('unknown condition type! (%s)' % key)

conds.append(cond)

obj = Conditions(conds)
return obj

[docs]    def group_by_variables(self, groups=None):
"""
Group boundary conditions of each variable. Each condition is a
group is a single condition.

Parameters
----------
groups : dict, optional
If present, update the `groups` dictionary.

Returns
-------
out : dict
The dictionary with variable names as keys and lists of
single condition instances as values.
"""
if groups is None:
out = {}

else:
out = groups

for cond in self:
for single_cond in cond.iter_single():
vname = single_cond.dofs[0].split('.')[0]
out.setdefault(vname, Conditions()).append(single_cond)

return out

[docs]    def canonize_dof_names(self, dofs):
"""
Canonize the DOF names using the full list of DOFs of a
variable.
"""
for cond in self:
cond.canonize_dof_names(dofs)

[docs]    def sort(self):
"""
Sort boundary conditions by their key.
"""
self._objs.sort(key=lambda a: a.key)
self.update()

[docs]    def zero_dofs(self):
"""
Set all boundary condition values to zero, if applicable.
"""
for cond in self:
if isinstance(cond, EssentialBC):
cond.zero_dofs()

def _canonize(dofs, all_dofs):
"""
Helper function.
"""
vname, dd = dofs.split('.')

if dd == 'all':
cdofs = all_dofs

elif dd[0] == '[':
cdofs = [vname + '.' + ii.strip()
for ii in dd[1:-1].split(',')]

else:
cdofs = [dofs]

return cdofs

[docs]class Condition(Struct):
"""
Common boundary condition methods.
"""
def __init__(self, name, **kwargs):
Struct.__init__(self, name=name, **kwargs)
self.is_single = False

[docs]    def iter_single(self):
"""
Create a single condition instance for each item in self.dofs
and yield it.
"""
for dofs, val in six.iteritems(self.dofs):
single_cond = self.copy(name=self.name)
single_cond.is_single = True
if 'grad' in dofs:
# extract variable name from grad.<var-name>.all dofs
dofs = ".".join((dofs.split(".")[1:]))
# mark condition as diff
single_cond.diff = 1

single_cond.dofs = [dofs, val]
yield single_cond

[docs]    def canonize_dof_names(self, dofs):
"""
Canonize the DOF names using the full list of DOFs of a
variable.

Assumes single condition instance.
"""
self.dofs[0] = _canonize(self.dofs[0], dofs)

[docs]class EssentialBC(Condition):
"""
Essential boundary condidion.

Parameters
----------
name : str
The boundary condition name.
region : Region instance
The region where the boundary condition is applied.
dofs : dict
The boundary condition specification defining the constrained
DOFs and their values.
key : str, optional
The sorting key.
times : list or str, optional
The list of time intervals or a function returning True at time
steps, when the condition applies.
"""
def __init__(self, name, region, dofs, key='', times=None):
Condition.__init__(self, name=name, region=region, dofs=dofs, key=key,
times=times)

[docs]    def zero_dofs(self):
"""
Set all essential boundary condition values to zero.
"""
if self.is_single:
self.dofs[1] = 0.0

else:
new_dofs = {}
for key in six.iterkeys(self.dofs):
new_dofs[key] = 0.0

self.dofs = new_dofs

[docs]class PeriodicBC(Condition):
"""
Periodic boundary condidion.

Parameters
----------
name : str
The boundary condition name.
regions : list of two Region instances
The master region and the slave region where the DOFs should match.
dofs : dict
The boundary condition specification defining the DOFs in the master
region and the corresponding DOFs in the slave region.
match : str
The name of function for matching corresponding nodes in the
two regions.
key : str, optional
The sorting key.
times : list or str, optional
The list of time intervals or a function returning True at time
steps, when the condition applies.
"""
def __init__(self, name, regions, dofs, match, key='', times=None):
Condition.__init__(self, name=name, regions=regions, dofs=dofs,
match=match, key=key, times=times)

[docs]    def canonize_dof_names(self, dofs):
"""
Canonize the DOF names using the full list of DOFs of a
variable.

Assumes single condition instance.
"""
self.dofs[0] = _canonize(self.dofs[0], dofs)
self.dofs[1] = _canonize(self.dofs[1], dofs)

[docs]class DGPeriodicBC(PeriodicBC):
"""
This class is empty, it serves the same purpose
as PeriodicBC, and is created only for branching in
dof_info.py
"""
pass

[docs]class DGEssentialBC(EssentialBC):
"""
This class is empty, it serves the same purpose
as EssentialBC, and is created only for branching in
dof_info.py
"""

def __init__(self, *args, diff=0, **kwargs):
EssentialBC.__init__(self, *args, **kwargs)
self.diff = diff

[docs]class LinearCombinationBC(Condition):
"""
Linear combination boundary condidion.

Parameters
----------
name : str
The boundary condition name.
regions : list of two Region instances
The constrained (master) DOFs region and the new (slave) DOFs
region. The latter can be None if new DOFs are not field variable DOFs.
dofs : dict
The boundary condition specification defining the constrained
DOFs and the new DOFs (can be None).
dof_map_fun : str
The name of function for mapping the constrained DOFs to new DOFs (can
be None).
kind : str
The linear combination condition kind.
key : str, optional
The sorting key.
times : list or str, optional
The list of time intervals or a function returning True at time
steps, when the condition applies.
arguments: tuple, optional
Additional arguments, depending on the condition kind.
"""
def __init__(self, name, regions, dofs, dof_map_fun, kind, key='',
times=None, arguments=None):
Condition.__init__(self, name=name, regions=regions, dofs=dofs,
dof_map_fun=dof_map_fun, kind=kind,
key=key, times=times, arguments=arguments)

[docs]    def get_var_names(self):
"""
Get names of variables corresponding to the constrained and new DOFs.
"""
names = [self.dofs[0].split('.')[0]]
if self.dofs[1] is not None:
names.append(self.dofs[1].split('.')[0])

return names

[docs]    def canonize_dof_names(self, dofs0, dofs1=None):
"""
Canonize the DOF names using the full list of DOFs of a
variable.

Assumes single condition instance.
"""
self.dofs[0] = _canonize(self.dofs[0], dofs0)

if self.dofs[1] is not None:
self.dofs[1] = _canonize(self.dofs[1], dofs1)

[docs]class InitialCondition(Condition):
"""
Initial condidion.

Parameters
----------
name : str
The initial condition name.
region : Region instance
The region where the initial condition is applied.
dofs : dict
The initial condition specification defining the constrained
DOFs and their values.
key : str, optional
The sorting key.
"""
def __init__(self, name, region, dofs, key=''):
Condition.__init__(self, name=name, region=region, dofs=dofs, key=key)
```