From 1b421c317d32ae260a3cea42245c70b958be061d Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Mon, 28 Sep 2026 13:44:12 +0200 Subject: [PATCH 01/17] Remove obsolete legacy test artifacts Delete the unmaintained old/ snapshots and bin/run_tests.sh. The script references test modules that no longer exist, so it advertises a broken workflow while the deleted snapshots duplicate history already preserved by Git. --- bin/run_tests.sh | 18 - old/form.py | 2210 -------------------------------------- old/test_calculus.py.old | 161 --- old/test_expr_1d.py.old | 429 -------- old/test_expr_2d.py | 471 -------- old/test_expr_3d.py.old | 589 ---------- old/test_form_2d.py | 1487 ------------------------- old/test_form_3d.py | 110 -- old/test_tensorize_2d.py | 136 --- 9 files changed, 5611 deletions(-) delete mode 100755 bin/run_tests.sh delete mode 100644 old/form.py delete mode 100644 old/test_calculus.py.old delete mode 100644 old/test_expr_1d.py.old delete mode 100644 old/test_expr_2d.py delete mode 100644 old/test_expr_3d.py.old delete mode 100644 old/test_form_2d.py delete mode 100644 old/test_form_3d.py delete mode 100644 old/test_tensorize_2d.py diff --git a/bin/run_tests.sh b/bin/run_tests.sh deleted file mode 100755 index da2ed3e0..00000000 --- a/bin/run_tests.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -python3 -m pytest sympde/core/tests/test_geometry.py -python3 -m pytest sympde/core/tests/test_derivatives.py -python3 -m pytest sympde/core/tests/test_space.py -python3 -m pytest sympde/core/tests/test_mapping.py -python3 -m pytest sympde/core/tests/test_model_1d.py -python3 -m pytest sympde/core/tests/test_model_2d.py - -#python3 -m pytest sympde/core/tests/test_expr_1d.py -python3 -m pytest sympde/core/tests/test_expr_2d.py -#python3 -m pytest sympde/core/tests/test_expr_3d.py - -python3 -m pytest sympde/printing/tests/test_latex.py - -python3 -m pytest sympde/gallery/tests/test_poisson.py -python3 -m pytest sympde/gallery/tests/test_stokes.py -python3 -m pytest sympde/gallery/tests/test_wave.py diff --git a/old/form.py b/old/form.py deleted file mode 100644 index f2ac7cd4..00000000 --- a/old/form.py +++ /dev/null @@ -1,2210 +0,0 @@ -# coding: utf-8 - -# TODO - transpose of BilinearForm -# - add unknown status if only one space is given to the BilinearForm -# => can not be evaluated except if it is called on a couple test/trial -# - check that a BilinearForm is bilinear (using Constant) -# - check that a LinearForm is linear -# - add is_symmetric property for BilinearForm - -from itertools import groupby - -from sympy.core import Basic -from sympy.core import Symbol -from sympy.core import Function -from sympy.simplify.simplify import simplify -from sympy import collect -from sympy.series.order import Order -from sympy.core import Expr, Add, Mul, Pow -from sympy import S -from sympy.core.containers import Tuple -from sympy import Indexed, IndexedBase, Matrix, ImmutableDenseMatrix -from sympy import expand -from sympy import Integer, Float -from sympy.core.expr import AtomicExpr -from sympy.physics.quantum import TensorProduct -from sympy.series.series import series - -from sympde.core.basic import _coeffs_registery -from sympde.core.basic import CalculusFunction -from sympde.core.basic import Constant -from sympde.core.algebra import (Dot_1d, - Dot_2d, Inner_2d, Cross_2d, - Dot_3d, Inner_3d, Cross_3d) -from sympde.core.utils import random_string - -from sympde.calculus import Dot, Inner, Cross -from sympde.calculus import Grad, Rot, Curl, Div -from sympde.calculus import Bracket -from sympde.calculus import Laplace -from sympde.calculus.core import _generic_ops - -from sympde.topology import BasicDomain, Domain, MappedDomain, Union, Interval -from sympde.topology import BoundaryVector, NormalVector, TangentVector, Boundary -from sympde.topology.derivatives import _partial_derivatives -from sympde.topology.derivatives import partial_derivative_as_symbol -from sympde.topology.derivatives import sort_partial_derivatives -from sympde.topology.derivatives import get_atom_derivatives -from sympde.topology.derivatives import dx, dy, dz -from sympde.topology.derivatives import (Grad_1d, Div_1d, - Grad_2d, Curl_2d, Rot_2d, Div_2d, - Grad_3d, Curl_3d, Div_3d) -from sympde.topology.derivatives import Bracket_2d -from sympde.topology.derivatives import Laplace_1d, Laplace_2d, Laplace_3d -from sympde.topology.derivatives import Hessian_1d, Hessian_2d, Hessian_3d -from sympde.topology.space import FunctionSpace -from sympde.topology.space import ProductSpace -from sympde.topology.space import TestFunction -from sympde.topology.space import VectorTestFunction -from sympde.topology.space import IndexedTestTrial -from sympde.topology.space import Unknown, VectorUnknown -from sympde.topology.space import Trace -from sympde.topology.space import Field, VectorField, IndexedVectorField -from sympde.topology.measure import CanonicalMeasure -from sympde.topology.measure import CartesianMeasure -from sympde.topology.measure import Measure - -from .errors import UnconsistentError -from .errors import UnconsistentLinearExpressionError - - -#============================================================================== -def _initialize_measure(measure, coordinates): - if not( measure is None ): - return measure - - if not( coordinates is None ): - return Measure(coordinates) - - else: - raise NotImplementedError('') - -#============================================================================== -def _initialize_boundary(expr): - - traces = expr.atoms(Trace) - boundaries = [trace.boundary for trace in traces] - boundaries = list(set(boundaries)) # remove redanduncy - - boundary = None - if len(boundaries) == 0: - boundary = None - - elif len(boundaries) == 1: - boundary = boundaries[0] - - elif (len(boundaries) > 1): - if not is_sum_of_form_calls(expr): - msg = '> BilinearForm can not be defined on different boundaries' - raise UnconsistentError(msg) - - boundary = Union(*boundaries) - - # ... - if isinstance(boundary, Boundary): - # ... - if isinstance(expr, Add) and not is_sum_of_form_calls(expr): - args = expr.args - args = [a for a in args if not a.atoms(Trace)] - if args: - msg = '> Only boundary terms, using traces, are allowed' - raise UnconsistentError(msg) - # ... - # ... - - return boundary - - -#============================================================================== -class BasicForm(Expr): - _name = None - _boundary = None - - # TODO use .atoms - @property - def fields(self): - ls = [a for a in self.expr.free_symbols if isinstance(a, (Field, VectorField))] - # no redanduncy - return sorted(list(set(ls))) - - # TODO use .atoms - @property - def constants(self): - ls = [a for a in self.expr.free_symbols if isinstance(a, Constant)] - # no redanduncy - return list(set(ls)) - - @property - def domain(self): - return self._domain - - @property - def boundary(self): - return self._boundary - - @property - def measure(self): - return self._measure - - @property - def mapping(self): - return self._mapping - - @property - def name(self): - return self._name - - -#============================================================================== -# TODO we should check that the only free symbols are fields, constants or coordinates -class Integral(BasicForm): - """ - - Examples - - """ - _ldim = None - _coordinates = None - def __new__(cls, expr, domain, measure=None, name=None): - # ... treat union of domains - # TODO improve - unions = expr.atoms(Union) - if unions: - if not( len(unions) == 1 ): - raise NotImplementedError('only one union is available for the moment') - - domains = [] - for i in list(unions): - domains += list(i._args) - domains = set(domains) - if len(domains) > 1: - forms = [] - for domain in domains: - i = list(unions)[0] - _expr = expr.replace(i, domain) - form = Integral(_expr, domain, measure=measure, - name=None) - - forms.append(form) - - expr = Add(*forms) - # ... - - - if not isinstance(domain, BasicDomain): - raise TypeError('> Expecting a BasicDomain object for domain') - - # ... check that there are no test functions in the expression - ls = [a for a in expr.free_symbols if isinstance(a, (TestFunction, VectorTestFunction))] - if not(len(ls) == 0): - raise TypeError('Cannot use test functions in Integral') - # ... - - # ... - coordinates = domain.coordinates - ldim = domain.dim - # ... - - # compute dim from fields if available - ls = list(expr.atoms((Field, VectorField))) - if ls: - F = ls[0] - space = F.space - - else: - tag = random_string( 3 ) - space_name = 'space_{}'.format(tag) - space = FunctionSpace(space_name, domain) - # TODO vector case - - # check if we are using a mapping - mapping = None - if isinstance( domain, MappedDomain ): - mapping = domain.mapping - - measure = _initialize_measure(measure, coordinates) - - # get boundary terms - boundary = _initialize_boundary(expr) - - obj = Basic.__new__(cls, expr) - obj._ldim = ldim - obj._coordinates = coordinates - obj._boundary = boundary - obj._domain = domain - obj._measure = measure - obj._mapping = mapping - obj._space = space - obj._name = name - - return obj - - @property - def expr(self): - return self._args[0] - - @property - def ldim(self): - return self._ldim - - @property - def space(self): - return self._space - - @property - def coordinates(self): - return self._coordinates - - def _sympystr(self, printer): - sstr = printer.doprint - expr = self.expr - return sstr(expr) - - # TODO how to implement this? - def __call__(self, *args): - raise NotImplementedError('') - - -#============================================================================== -class LinearForm(BasicForm): - """ - - Examples - - """ - def __new__(cls, arguments, expr, measure=None, name=None, check=False): - # ... treat union of domains - # TODO improve - unions = expr.atoms(Union) - if unions: - if not( len(unions) == 1 ): - raise NotImplementedError('only one union is available for the moment') - - domains = [] - for i in list(unions): - domains += list(i._args) - domains = set(domains) - if len(domains) > 1: - forms = [] - for domain in domains: - i = list(unions)[0] - _expr = expr.replace(i, domain) - _name = None - if not( name is None ): - _name = '{name}_{domain}'.format(name=name, domain=domain.name) - - form = LinearForm(arguments, _expr, measure=measure, - name=_name) - - forms.append(form(arguments)) - - expr = Add(*forms) - # ... - - # ... - calls = list(expr.atoms(FormCall)) - if check and not calls: - if not is_linear_form(expr, arguments): - msg = '> Expression is not linear' - raise UnconsistentLinearExpressionError(msg) - # ... - - args = _sanitize_form_arguments(arguments, expr, is_linear=True) - obj = Basic.__new__(cls, args, expr) - - # TODO must check that all domains are the same - domain = obj.test_spaces[0].domain - - # check if we are using a mapping - mapping = None - if isinstance( domain, MappedDomain ): - mapping = domain.mapping - - measure = _initialize_measure(measure, obj.coordinates) - - # get boundary terms - boundary = _initialize_boundary(expr) - - obj._domain = domain - obj._boundary = boundary - obj._measure = measure - obj._mapping = mapping - obj._name = name - - return obj - - @property - def variables(self): - return self._args[0] - - @property - def expr(self): - return self._args[1] - - @property - def test_functions(self): - return self.variables - - @property - def ldim(self): - return self.test_spaces[0].ldim - - @property - def coordinates(self): - return self.test_spaces[0].coordinates - - @property - def test_spaces(self): - return [u.space for u in self.test_functions] - - def _sympystr(self, printer): - sstr = printer.doprint - expr = self.expr - return sstr(expr) - - def __call__(self, *args): - args = Tuple(*args) - - if isinstance(self.expr, FormCall): - call = self.expr - return FormCall(call.expr, args) - - return FormCall(self, args) - - def _eval_nseries(self, x, n, logx): - return self.expr._eval_nseries(x, n, logx) - -#============================================================================== -class BilinearForm(BasicForm): - """ - - Examples - - """ - - def __new__(cls, arguments, expr, measure=None, name=None, check=False): - # ... treat union of domains - # TODO improve - unions = expr.atoms(Union) - if unions: - if not( len(unions) == 1 ): - raise NotImplementedError('only one union is available for the moment') - - domains = [] - for i in list(unions): - domains += list(i._args) - domains = set(domains) - if len(domains) > 1: - forms = [] - for domain in domains: - i = list(unions)[0] - _expr = expr.replace(i, domain) - form = BilinearForm(arguments, _expr, measure=measure, - name=None) - - forms.append(form(*arguments)) - - expr = Add(*forms) - # ... - - # ... - if not isinstance(arguments, (tuple, list, Tuple)): - raise TypeError('(test, trial) must be a tuple, list or Tuple') - - if not(len(arguments) == 2): - raise ValueError('Expecting a couple (test, trial)') - # ... - - # ... - calls = list(expr.atoms(FormCall)) - if check and not calls: - if not is_bilinear_form(expr, arguments): - msg = '> Expression is not bilinear' - raise UnconsistentLinearExpressionError(msg) - # ... - - args = _sanitize_form_arguments(arguments, expr, is_bilinear=True) - obj = Basic.__new__(cls, args, expr) - - # TODO must check that all domains are the same - domain = obj.test_spaces[0].domain - - # check if we are using a mapping - mapping = None - if isinstance( domain, MappedDomain ): - mapping = domain.mapping - - measure = _initialize_measure(measure, obj.coordinates) - - # get boundary terms - boundary = _initialize_boundary(expr) - - obj._domain = domain - obj._boundary = boundary - obj._measure = measure - obj._mapping = mapping - obj._name = name - - return obj - - @property - def variables(self): - return self._args[0] - - @property - def expr(self): - return self._args[1] - - @property - def test_functions(self): - return self.variables[0] - - @property - def trial_functions(self): - return self.variables[1] - - @property - def ldim(self): - return self.test_spaces[0].ldim - - @property - def coordinates(self): - return self.test_spaces[0].coordinates - - @property - def test_spaces(self): - return [u.space for u in self.test_functions] - - @property - def trial_spaces(self): - return [u.space for u in self.trial_functions] - - def _sympystr(self, printer): - sstr = printer.doprint - expr = self.expr - return sstr(expr) - - def __call__(self, *args): - if not(len(args) == 2): - raise ValueError('Expecting a couple (test, trial)') - - # ... - expr = self - if isinstance(self.expr, FormCall): - expr = self.expr.expr - # ... - - are_dummy = lambda xs: [isinstance(i, (TestFunction, VectorTestFunction)) - for i in xs] - - # ... - test_functions = args[0] - if not isinstance(test_functions, (tuple, list, Tuple)): - test_functions = [test_functions] - test_functions = Tuple(*test_functions) - # ... - - # ... - trial_functions = args[1] - if not isinstance(trial_functions, (tuple, list, Tuple)): - trial_functions = [trial_functions] - trial_functions = Tuple(*trial_functions) - # ... - - # ... - if not all(are_dummy(test_functions)) and not all(are_dummy(trial_functions)): - # This should return an Integral - raise NotImplementedError('') - - else: - free_variables = None - target = None - if not any(are_dummy(test_functions)): - assert(all(are_dummy(trial_functions))) - - args = trial_functions - free_variables = test_functions - target = 'test' - - elif not any(are_dummy(trial_functions)): - assert(all(are_dummy(test_functions))) - - args = test_functions - free_variables = trial_functions - target = 'trial' - - if not( free_variables is None ): - if target == 'test': - target = expr.variables[0] - - elif target == 'trial': - target = expr.variables[1] - - expr = expr.expr - - for old, new in zip(target, free_variables): - expr = expr.subs(old, new) - - expr = LinearForm(args, expr, check=False) - # ... - - return FormCall(expr, args) - - -#============================================================================== -class Norm(Integral): - def __new__(cls, expr, domain, kind='l2', measure=None, - name=None): - # ... - tests = expr.atoms((TestFunction, VectorTestFunction)) - if tests: - msg = '> Expecting an Expression without test functions' - raise UnconsistentArgumentsError(msg) - - if not isinstance(expr, (Expr, Matrix, ImmutableDenseMatrix)): - msg = '> Expecting Expr, Matrix, ImmutableDenseMatrix' - raise UnconsistentArgumentsError(msg) - - # ... - - # ... - if not(kind in ['l2', 'h1']): - raise ValueError('> Only L2, H1 norms are available') - # ... - - # ... - if name is None: - name = random_string( 3 ) - - name = '{kind}norm_{name}'.format(kind=kind, name=name) - # ... - - # ... - is_vector = isinstance(expr, (Matrix, Tuple, list, tuple)) - if is_vector: - expr = Matrix(expr) - # ... - - # ... - exponent = None - if kind == 'l2': - exponent = 2 - - if not is_vector: - expr = expr*expr - - else: - if not( expr.shape[1] == 1 ): - raise ValueError('Wrong expression for Matrix. must be a row') - - v = Tuple(*expr[:,0]) - expr = Dot(v, v) - - elif kind == 'h1': - exponent = 2 - - if not is_vector: - expr = Dot(Grad(expr), Grad(expr)) - - else: - if not( expr.shape[1] == 1 ): - raise ValueError('Wrong expression for Matrix. must be a row') - - v = Tuple(*expr[:,0]) - expr = Inner(Grad(v), Grad(v)) - # ... - - obj = Integral.__new__(cls, expr, domain, measure=name, name=name) - - obj._exponent = exponent - - return obj - - @property - def exponent(self): - return self._exponent - - -#============================================================================== -class BilinearAtomicForm(BilinearForm, AtomicExpr): - """ - - Examples - - """ - - def _sympystr(self, printer): - sstr = printer.doprint - name = sstr(self.name) - - test = [sstr(i) for i in self.test_functions] - test = ','.join(i for i in test) - - trial = [sstr(i) for i in self.trial_functions] - trial = ','.join(i for i in trial) - - return '{name}({test},{trial})'.format(name=name, trial=trial, test=test) - -#============================================================================== -class Mass(BilinearAtomicForm): - """ - - Examples - - """ - def __new__(cls, test, trial): - - test_trial = [test, trial] - expr = test * trial - - return BilinearForm.__new__(cls, test_trial, expr, name='Mass') - -#============================================================================== -class Stiffness(BilinearAtomicForm): - """ - - Examples - - """ - def __new__(cls, test, trial): - - test_trial = [test, trial] - - coordl = test.space.coordinates.name - coordr = trial.space.coordinates.name - if not(coordl == coordr): - raise ValueError('> Incompatible coordinates') - - ops = {'x': dx, 'y': dy, 'z': dz} - d = ops[coordl] - - expr = d(test) * d(trial) - - return BilinearForm.__new__(cls, test_trial, expr, name='Stiffness') - -#============================================================================== -class Advection(BilinearAtomicForm): - """ - - Examples - - """ - def __new__(cls, test, trial): - - test_trial = [test, trial] - - coordl = test.space.coordinates.name - coordr = trial.space.coordinates.name - if not(coordl == coordr): - raise ValueError('> Incompatible coordinates') - - ops = {'x': dx, 'y': dy, 'z': dz} - d = ops[coordl] - - expr = test * d(trial) - - return BilinearForm.__new__(cls, test_trial, expr, name='Advection') - -#============================================================================== -class AdvectionT(BilinearAtomicForm): - """ - - Examples - - """ - def __new__(cls, test, trial): - - test_trial = [test, trial] - - coordl = test.space.coordinates.name - coordr = trial.space.coordinates.name - if not(coordl == coordr): - raise ValueError('> Incompatible coordinates') - - ops = {'x': dx, 'y': dy, 'z': dz} - d = ops[coordl] - - expr = d(test) * trial - - return BilinearForm.__new__(cls, test_trial, expr, name='AdvectionT') - -#============================================================================== -class Bilaplacian(BilinearAtomicForm): - """ - - Examples - - """ - def __new__(cls, test, trial): - - test_trial = [test, trial] - - coordl = test.space.coordinates.name - coordr = trial.space.coordinates.name - if not(coordl == coordr): - raise ValueError('> Incompatible coordinates') - - ops = {'x': dx, 'y': dy, 'z': dz} - d = ops[coordl] - - expr = d(d(test)) * d(d(trial)) - - return BilinearForm.__new__(cls, test_trial, expr, name='Bilaplacian') - - -#============================================================================== -class Kron(BilinearAtomicForm): - - """.""" - - def __new__(cls, ls): - - ln = len(ls) - dim = len(ls[0]) - obj = Basic.__new__(cls, ls) - if dim >= 3: - raise NotImplementedError('TODO') - - args1 = ['A%s'%i for i in range(ln)] - args2 = ['B%s'%i for i in range(ln)] - try: - import importlib - package = importlib.import_module("sympde.codegen.templates.kron") - except: - raise ImportError('could not import kron_dot') - name = 'kron_dot_2d' - template = getattr(package,name) - body = [template['body'].format(MAT1=args1[i],MAT2=args2[i]) for i in range(ln)] - body = '\n'.join(i for i in body) - args = ','.join(arg for arg in args1+args2) - function = template['function'].format(___MAT_ARGS___=args,__BODY__=body) - args_types = ','.join('double[:,:]' for i in range(2*ln)) - header = template['header'].format(__ARGS_TYPES__=args_types) - dot = compile(function,'','single') - dic = {} - eval(dot,dic) - _dot = dic[name] - setattr(obj, '_dot',_dot) - return obj - - @property - def args(self): - return self._args[0] - - def dot(self, x): - space = x.space - args = list(zip(*self.args)) - args1 = args[0] - args2 = args[1] - args1 = [arg._data for arg in args1] - args2 = [arg._data for arg in args2] - #args1 = [arg._data.T for arg in args1] - #args2 = [arg._data.T for arg in args2] - starts = space.starts - ends = space.ends - pads = space.pads - - from spl.linalg.stencil import StencilVector - Y = StencilVector(space) - X_tmp = StencilVector(space) - #self._dot(starts,ends,pads,x._data.T,Y._data.T,X_tmp._data.T,*args1,*args2) - args = list(args1) + list(args2) - self._dot(starts,ends,pads,x._data,Y._data,X_tmp._data,*args) - return Y - - - def __str__(self): - return 'Kron' - - def _sympystr(self, printer): - return 'Kron' - - -#============================================================================== -class FormCall(AtomicExpr): - - is_commutative = False - - def __new__(cls, expr, args): - - # ... - if not isinstance(args, (list, tuple, Tuple)): - args = [args] - # ... - - # ... - name = expr.name - if isinstance( expr, BilinearForm ): - expr = subs_form(expr, args) - - if not isinstance(expr, BilinearForm): - expr = BilinearForm(args, expr, name=name, check=False) - - elif isinstance( expr, LinearForm ): - expr = subs_form(expr, args) - - if not isinstance(expr, LinearForm): - expr = LinearForm(args, expr, name=name, check=False) - - else: - raise TypeError('> Expecting BilinearForm, LinearForm') - # ... - - # ... - args = Tuple(*args) - obj = Basic.__new__(cls, expr, args) - # ... - - return obj - - @property - def expr(self): - return self._args[0] - - @property - def arguments(self): - return self._args[1] - - -def is_mul_of_form_call(expr): - if not isinstance(expr, Mul): - return False - - are_calls = [isinstance(i, FormCall) for i in expr.args] - any_are_calls = any(are_calls) - if not any_are_calls: - return False - - if (isinstance(any_are_calls, (list, tuple, Tuple)) and - (len(any_are_calls) > 1)): - raise TypeError('> Cannot multiply calls of Bilinear/Linear forms') - - return True - -def is_sum_of_form_calls(expr): - if isinstance(expr, FormCall): return True - if not isinstance(expr, Add): return False - - are_valid = [isinstance(i, FormCall) or is_mul_of_form_call(i) for i in expr.args] - - all_are_valid = all(are_valid) - if any(are_valid) and not(all_are_valid): - raise TypeError('> Invalid expression') - - return all_are_valid - - -def _sanitize_form_arguments(arguments, expr, is_bilinear=False, is_linear=False): - - is_linear = is_linear or (len(expr.atoms(LinearForm)) > 0) - is_bilinear = is_bilinear or (len(expr.atoms(BilinearForm)) > 0) - - # ... - if is_bilinear or is_linear: - - if is_bilinear: - test_functions = arguments[0] - - elif is_linear: - test_functions = arguments - - if isinstance(test_functions, (TestFunction, VectorTestFunction)): - test_functions = [test_functions] - - elif isinstance(test_functions, (tuple, list, Tuple)): - are_valid = [isinstance(i, (TestFunction, VectorTestFunction)) for i in test_functions] - if not all(are_valid): - raise TypeError('> Wrong arguments for test functions') - - else: - msg = 'Wrong type for test function(s). given {}'.format(type(test_functions)) - raise TypeError(msg) - - test_functions = Tuple(*test_functions) - # ... - - # ... - if is_bilinear: - - trial_functions = arguments[1] - if isinstance(trial_functions, (TestFunction, VectorTestFunction)): - trial_functions = [trial_functions] - - elif isinstance(trial_functions, (tuple, list, Tuple)): - are_valid = [isinstance(i, (TestFunction, VectorTestFunction)) for i in trial_functions] - if not all(are_valid): - raise TypeError('> Wrong arguments for trial functions') - - else: - msg = 'Wrong type for trial function(s). given {}'.format(type(trial_functions)) - raise TypeError(msg) - - trial_functions = Tuple(*trial_functions) - # ... - - if is_bilinear: - args = [test_functions, trial_functions] - args = Tuple(*args) - - else: - args = Tuple(*test_functions) - - return args - - -# ... -def atomize(expr, dim=None): - """ - """ - if not isinstance(expr, (Expr, - _partial_derivatives, _generic_ops, - TestFunction, VectorTestFunction, Indexed, - Field, Constant, Symbol, Function, - VectorField, - BoundaryVector, Trace, - Integer, Float, Matrix, ImmutableDenseMatrix, - list, tuple, Tuple)): - msg = ('> Wrong input type.') - - raise TypeError(msg, ', given ', expr, type(expr)) - - # ... replace a FormCall by its expression - calls = expr.atoms(FormCall) - for call in calls: - expr = expr.subs(call, call.expr) - # ... - -# print('> expr [atomize] = ', expr, type(expr)) - - # ... compute dim if None - if dim is None: - ls = [i for i in expr.free_symbols if isinstance(i, (TestFunction, - VectorTestFunction, - Field, - VectorField))] - -# ls = expr.atoms((TestFunction, VectorTestFunction, Field)) -# ls = list(ls) - if ls: - atom = ls[0] - if atom.space is None: - raise ValueError('Expecting atom to be associated to a space') - - dim = atom.space.ldim - # ... - - if isinstance(expr, (list, tuple, Tuple)): - args = [atomize(i, dim=dim) for i in expr] - return Tuple(*args) - - elif isinstance(expr, Add): - args = [atomize(i, dim=dim) for i in expr.args] - return Add(*args) - - elif isinstance(expr, Mul): - coeffs = [i for i in expr.args if isinstance(i, _coeffs_registery)] - vectors = [i for i in expr.args if not(i in coeffs)] - - i = S.One - if coeffs: - i = Mul(*coeffs) - - j = S.One - if vectors: - args = [atomize(i, dim=dim) for i in vectors] - j = Mul(*args) - - return Mul(i, j) - - elif isinstance(expr, Pow): - - b = atomize(expr.base, dim=dim) - e = expr.exp - - return Pow(b, e) - - elif isinstance(expr, BasicForm): - - return atomize(expr.expr, dim=dim) - - elif isinstance(expr, Trace): - # TODO treate different spaces - if expr.order == 0: - return atomize(expr.expr, dim=dim) - - elif expr.order == 1: - # TODO must be passed as key word to atomize - normal_vector_name = 'n' - n = NormalVector(normal_vector_name) - M = atomize(expr.expr, dim=dim) - if dim == 1: - return M - else: - if isinstance(M, (Add, Mul)): - ls = M.atoms(Tuple) - for i in ls: - M = M.subs(i, Matrix(i)) - M = simplify(M) - - e = 0 - for i in range(0, dim): - e += M[i] * n[i] - return e - - else: - raise ValueError('> Only traces of order 0 and 1 are available') - - elif isinstance(expr, _generic_ops): - # if i = Dot(...) then type(i) is Grad - op = type(expr) - new = eval('{0}_{1}d'.format(op, dim)) - - args = [atomize(i, dim=dim) for i in expr.args] - return new(*args) - - elif isinstance(expr, Matrix): - n,m = expr.shape - lines = [] - for i in range(0, n): - line = [] - for j in range(0, m): - line.append(atomize(expr[i,j], dim=dim)) - lines.append(line) - return Matrix(lines) - - return expr -# ... - -# ... -def _evaluate_core(a, verbose=False, variables=None, M=None): - - # ... - if not isinstance(a, (BasicForm, Add, Mul)): - msg = 'Expecting a BasicForm, Add or Mul. Given {}'.format(type(a)) - raise TypeError(msg) - # ... - - # ... - variables = [] - if isinstance(a, (BilinearForm, LinearForm)): - variables = a.variables - - elif isinstance(a, FormCall): - variables = a.variables - # ... - - # ... - def _get_size_and_starts(ls): - n = 0 - d_indices = {} - for x in ls: - d_indices[x] = n - if isinstance(x, TestFunction): - n += 1 - - elif isinstance(x, VectorTestFunction): - for j in range(0, x.shape[0]): - d_indices[x[j]] = n + j - - n += x.shape[0] - - return n, d_indices - # ... - - # ... - tests = [] - trials = [] - # ... - - # ... - if isinstance(a, BilinearForm): - tests = list(a.test_functions) - n_rows, test_indices = _get_size_and_starts(a.test_functions) - - trials = list(a.trial_functions) - n_cols, trial_indices = _get_size_and_starts(a.trial_functions) - - lines = [] - for i in range(0, n_rows): - line = [] - for j in range(0, n_cols): - line.append(0) - lines.append(line) - - M = Matrix(lines) - - elif isinstance(a, LinearForm): - tests = list(a.test_functions) - n_rows, test_indices = _get_size_and_starts(a.test_functions) - - lines = [0 for i in range(0, n_rows)] - M = Matrix(lines) - # ... - - # ... - if isinstance(a, Add): - args = [_evaluate_core(i, verbose=verbose, variables=variables, M=M) - for i in a.args] - - return Add(*args) - - elif isinstance(a, Mul): - # a coeff can be a symbol, otherwise the expression c1 * a - # raises an error - coeffs = [i for i in a.args if isinstance(i, _coeffs_registery) or isinstance(i, Symbol)] - vectors = [i for i in a.args if not(i in coeffs)] - - i = S.One - if coeffs: - i = Mul(*coeffs) - - j = S.One - if vectors: - args = [_evaluate_core(i, verbose=verbose, variables=variables, M=M) - for i in vectors] - j = Mul(*args) - - return Mul(i, j) - # ... - - dim = a.ldim - expr = a.expr - - # convert generic operators to atomic ones - expr = atomize(expr, dim=dim) - - # we need to expand the expression so that we have a sum of product - expr = expand(expr) - - if verbose: - print('> atomized >>> {0}'.format(expr)) - - # ... - def __evaluate_core_LinearForm(expr, M): - # ... - def treat_form(arg, M): - atoms = list(arg.atoms(TestFunction)) - atoms += list(arg.atoms(VectorTestFunction)) - atoms += list(arg.atoms(IndexedTestTrial)) - - for atom in atoms: - if atom in test_indices: - i_row = test_indices[atom] - - else: - raise ValueError('> Could not find {}'.format(atom)) - - M[i_row] += arg - return M - # ... - - # ... - if isinstance(expr, Add): - args = expr.args - for arg in args: - M = treat_form(arg, M) - - elif isinstance(expr, Mul): - M = treat_form(expr, M) - - else: - raise TypeError('> wrong type, given {}'.format(type(expr))) - # ... - - return M - # ... - - # ... - def __evaluate_core_BilinearForm(expr, M): - - # ... - def treat_form(arg, M): - atoms = list(arg.atoms(TestFunction)) - atoms += list(arg.atoms(VectorTestFunction)) - atoms += list(arg.atoms(IndexedTestTrial)) - - for atom in atoms: - if atom in test_indices: - i_row = test_indices[atom] - - elif atom in trial_indices: - i_col = trial_indices[atom] - - else: - raise ValueError('> Could not find {}'.format(atom)) - - M[i_row, i_col] += arg - return M - # ... - - # ... - if isinstance(expr, Add): - args = expr.args - for arg in args: - if isinstance(arg, Mul): - M = treat_form(arg, M) - - elif isinstance(expr, Mul): - M = treat_form(expr, M) - - else: - raise TypeError('> wrong type, given {}'.format(type(expr))) - # ... - - return M - # ... - - # ... - if isinstance(a, BilinearForm): - M = __evaluate_core_BilinearForm(expr, M) - - # returning scalars when possibl - if (n_rows == 1) and (n_cols == 1): - return M[0, 0] - - elif isinstance(a, LinearForm): - M = __evaluate_core_LinearForm(expr, M) - - # returning scalars when possibl - if (n_rows == 1): - return M[0] - - elif isinstance(a, Integral): - return expr - # ... - - return M -# ... - -# ... -def _evaluate_bnd(a, bnd_calls, verbose=False): - if verbose: - print('> bnd calls = ', bnd_calls) - - a_expr = a - if isinstance(a, BasicForm) and is_sum_of_form_calls(a.expr): - # TODO treat Mul node - if isinstance(a.boundary, Union): - if isinstance(a.expr, Add): - newargs = [] - for i in a.expr.args: - - expr = i.expr - if isinstance(expr, BasicForm): - expr = expr.expr - - if is_sum_of_form_calls(expr): - newargs += expr.args - - else: - newargs.append(i) - - a_expr = Add(*newargs) - - elif isinstance(a.expr, Mul): - raise NotImplementedError('') - - else: - a_expr = a.expr - - else: - a_expr = a.expr - - if isinstance(a_expr, FormCall): - a_expr = a_expr.expr.expr - - # ... - boundaries = [] - groups = [] - keyfunc = lambda call: call.expr.boundary - for bnd, g in groupby(bnd_calls, keyfunc): - ls = list(g) - a_bnd = _extract_linear_combination(a_expr, ls) - groups.append(a_bnd) - boundaries.append(bnd) - - if verbose: - print('> groups = ', groups) - print('> boundaries = ', boundaries) - # ... - - - # ... - groups_M = [] - for bnd, ai in zip(boundaries, groups): - a_bnd = ai - for call in ai.atoms(FormCall): - a_bnd = a_bnd.subs(call, call.expr) - - M_bnd = _evaluate_core(a_bnd, verbose=verbose) - - groups_M.append(BoundaryExpression(bnd, M_bnd)) - - if verbose: - print('> groups_M = ', groups_M) - # ... - - return groups_M -# ... - -def _extract_linear_combination(expr, ls): - """returns a new expression for terms that are in ls only.""" - # something like a1 + a2 or a1 + alpha * a2 - if isinstance(expr, Add): - args = [] - for arg in expr.args: - # somthing like alpha*a4 - if isinstance(arg, Mul): - m_args = [i for i in arg.args if i in ls] - if m_args: - args += [arg] - - elif arg in ls: - args += [arg] - - expr = Add(*args) - return expr - -# TODO check that a is a Form, FormCall or linear combination of them -def evaluate(a, verbose=False): - # ... - _calls = a.atoms(FormCall) - calls = [] - for call in _calls: - mycalls = call.expr.atoms(FormCall) - if mycalls: - calls += list(mycalls) - else: - calls += [call] - - # remove redundancy - calls = list(set(calls)) - # ... - - bnd_calls = [] - if calls: - bnd_calls = [a for a in calls if a.expr.boundary] - calls = [a for a in calls if not(a in bnd_calls)] - - if verbose: - print('> calls = ', calls) - - expr_bnd = [] - if bnd_calls: - expr_bnd = _evaluate_bnd(a, bnd_calls, verbose=verbose) - - bnd_done = [i.target for i in expr_bnd] - - expr_domain = [] - if calls: - # TODO - must check that calls have the same domein - # - shall we need to add a groupby here too? - domain = calls[0].expr.domain - - a_expr = a - if (isinstance(a, BasicForm) and is_sum_of_form_calls(a.expr) and - bnd_calls): - a_expr = a.expr - - a = _extract_linear_combination(a_expr, calls) - if verbose: - print('> a = ', a) - - # ... replace a FormCall by its expression - for call in calls: - a = a.subs(call, call.expr) - # ... - - expr = _evaluate_core(a, verbose=verbose) - boundary = list(a.atoms(Boundary)) - if not boundary: - expr_domain = [DomainExpression(domain, expr)] - - else: - boundary = boundary[0] - expr_domain = [BoundaryExpression(boundary, expr)] - - elif isinstance(a, BasicForm): - boundary = list(a.atoms(Boundary)) - - if not boundary: - domain = a.domain - expr = _evaluate_core(a, verbose=verbose) - expr_domain = [DomainExpression(domain, expr)] - - # TODO nitsch case -# else: -# expr_domain = [] -# boundary = [i for i in boundary if not(i in bnd_done)] -# for bnd in boundary: -# expr_domain += [BoundaryExpression(bnd, expr)] - - return expr_bnd + expr_domain - - -#============================================================================== -class KernelExpression(Basic): - def __new__(cls, target, expr): - return Basic.__new__(cls, target, expr) - - @property - def target(self): - return self._args[0] - - @property - def expr(self): - return self._args[1] - -#============================================================================== -class DomainExpression(KernelExpression): - pass - -#============================================================================== -class BoundaryExpression(KernelExpression): - pass - - -#============================================================================== -# TODO - get dim from atoms -# - check coefficinets/functions -def _tensorize_core(expr, dim, tests, trials): - - if isinstance(expr, Add): - args = [_tensorize_core(i, dim, tests, trials) for i in expr.args] - return Add(*args) - - elif isinstance(expr, Mul): - coeffs = [i for i in expr.args if isinstance(i, _coeffs_registery)] - args = [i for i in expr.args if not(i in coeffs)] - - d_atoms = {} - _coordinates = ['x', 'y', 'z'] - _coordinates = [Symbol(i) for i in _coordinates] - test_trial = list(tests) + list(trials) - for a in test_trial: - d_atoms[a] = [] - - new = S.One - for i in range(0, dim): - coord = _coordinates[i] - Di = Interval(coordinate=coord) - Vi = FunctionSpace('V_{}'.format(i), domain=Di) - - ai = TestFunction(Vi, '{test}{i}'.format(test=a.name, i=i)) - d_atoms[a].append(ai) - - new *= ai - expr = expr.subs({a: new}) - - # make sure we have sum of products - expr = expand(expr) - - # ... - # TODO - improve this later - # - must distinguish between test/trial - assert(len(tests) == 1) - assert(len(trials) == 1) - - v = tests[0] - u = trials[0] - - ops = {'x': dx, 'y': dy, 'z': dz} - - for ui,vi in zip(d_atoms[u], d_atoms[v]): - coord = ui.space.coordinates.name - d = ops[coord] - - # ... Mass - old = vi*ui - new = Mass(vi,ui) - - expr = expr.subs({old: new}) - # ... - - # ... Stiffness - old = d(vi)*d(ui) - new = Stiffness(vi,ui) - - expr = expr.subs({old: new}) - # ... - - # ... Advection - old = vi*d(ui) - new = Advection(vi,ui) - - expr = expr.subs({old: new}) - # ... - - # ... Transpose of Advection - old = d(vi)*ui - new = AdvectionT(vi,ui) - - expr = expr.subs({old: new}) - # ... - - # ... Bilaplacian - old = d(d(vi))*d(d(ui)) - new = Bilaplacian(vi,ui) - - expr = expr.subs({old: new}) - # ... - - expr = subs_mul(expr) - # ... - - return expr - -#============================================================================== -def _tensorize_weights(expr): - - if isinstance(expr, Add): - args = [] - for term in expr.args: - #print('> ', term, type(term)) - arg = _tensorize_weights(term) - args.append(arg) - expr = Add(*args) - - elif isinstance(expr, Mul): - args = [] - for term in expr.args: -# print('>> ', term, type(term)) - arg = _tensorize_weights(term) - args.append(arg) - - tensor = [a for a in args if isinstance(a, TensorProduct)] - weights = [a for a in args if not( a in tensor )] - - if tensor: - - tensor = tensor[0] - forms = tensor.args - - coords = [a.coordinates for a in forms] - - # print(forms) - # print(coords) - # print(weights) - - # # ... - # d_args = {} - # for x in coords: - # d_args[x] = [] - # - # for x in coords: - # for a in weights: - # # TODO improve for functions => separability - # ls = a.atoms(Symbol) - # if x in ls: - # print('found ', x, ' in ', a) - # # ... - - expr = Mul(*args) - - elif isinstance(expr, TensorProduct): - args = [] - for term in expr.args: -# print('>>> ', term, type(term)) - arg = _tensorize_weights(term) -# if not( arg is S.One ): -# args.append(arg) - if isinstance(term, BilinearAtomicForm): - coords = term.domain.coordinates - #print(coords) - expr = TensorProduct(*args) - - return expr - -#============================================================================== -def tensorize(a): - - if not isinstance(a, BilinearForm): - raise TypeError('Expecting a BilinearForm') - - # ... - def _get_size_and_starts(ls): - n = 0 - d_indices = {} - for x in ls: - d_indices[x] = n - if isinstance(x, TestFunction): - n += 1 - - elif isinstance(x, VectorTestFunction): - for j in range(0, x.shape[0]): - d_indices[x[j]] = n + j - - n += x.shape[0] - - return n, d_indices - # ... - - if is_sum_of_form_calls(a.expr): - # ... - n_rows, test_indices = _get_size_and_starts(a.test_functions) - n_cols, trial_indices = _get_size_and_starts(a.trial_functions) - - lines = [] - for i in range(0, n_rows): - line = [] - for j in range(0, n_cols): - line.append(0) - lines.append(line) - - M = Matrix(lines) - # ... - - calls = a.atoms(FormCall) - for call in calls: - t = tensorize(call.expr) - - atoms = call.arguments - i_row = None - i_col = None - l_row = 1 - l_col = 1 - for atom in atoms: - if atom in test_indices: - i_row = test_indices[atom] - - if isinstance(atom, VectorTestFunction): - l_row = atom.shape[0] - - elif atom in trial_indices: - i_col = trial_indices[atom] - - if isinstance(atom, VectorTestFunction): - l_col = atom.shape[0] - - else: - raise ValueError('> Could not find {}'.format(atom)) - - if isinstance(t, (Matrix, ImmutableDenseMatrix)): - M_loc = M[i_row:i_row+l_row, i_col:i_col+l_col] - if M_loc.shape == t.shape: - M_loc += t - - # TODO must check if a trial/test is used as test/trial - elif M_loc.shape == t.shape[::-1]: - M_loc += t.transpose() - - else: - raise ValueError('Wrong sizes') - - M[i_row:i_row+l_row, i_col:i_col+l_col] += M_loc - - else: - raise NotImplementedError('TODO') - - return M - - dim = a.ldim - domain = a.domain - tests = a.test_functions - trials = a.trial_functions - - assert(len(a.test_spaces) == 1) - assert(len(a.trial_spaces) == 1) - assert(len(tests) == 1) - assert(len(trials) == 1) - - V = a.test_spaces[0] - U = a.trial_spaces[0] - - # the result of evaluate is a list of KernelExpression - kernels = evaluate(a) - kernels = [i.expr for i in kernels] - - expressions = [] - for kernel in kernels: - if isinstance(kernel, (Matrix, ImmutableDenseMatrix)): - - n_rows, n_cols = kernel.shape - - # ... subs indexed test/trial functions by a new symbol - tmp_tests = [] - tmp_trials = [] - for i_row in range(0, n_rows): - for i_col in range(0, n_cols): - e = kernel[i_row,i_col] - indexed = e.atoms(IndexedTestTrial) - for ui in indexed: - i = ui.indices - if len(i) > 1: - raise ValueError('Expecting one index') - i = i[0] - - space_name = 'VTmp{}'.format(i) - Vi = FunctionSpace(space_name, V.domain) - vi = TestFunction(Vi, '{test}{i}'.format(test=ui.base.name, i=i)) - e = e.subs({ui: vi}) - - if ui.base in tests: - tmp_tests.append(vi) - - elif ui.base in trials: - tmp_trials.append(vi) - - kernel[i_row,i_col] = e - # ... - - tmp_tests += [i for i in tests if not(i in tmp_tests)] - tmp_trials += [i for i in trials if not(i in tmp_trials)] - - # ... - lines = [] - for i_row in range(0, n_rows): - line = [] - for i_col in range(0, n_cols): - e = kernel[i_row,i_col] - - atoms = e.atoms(TestFunction) - _tests = [i for i in atoms if i in tmp_tests] - _trials = [i for i in atoms if i in tmp_trials] - - eij = _tensorize_core(e, dim, _tests, _trials) - - line.append(eij) - - lines.append(line) - - expr = Matrix(lines) - # ... - - else: - expr = _tensorize_core(kernel, dim, tests, trials) - - expressions.append(expr) - # ... - - # TODO - # looking for weighted atomic forms - # this should be done if a flag is True - # and used for LinearOperator Kron -# expr = _tensorize_weights(expr) - - return expr - -#============================================================================== -def subs_mul(expr): - """substitute Mul with TensorProduct""" - - if isinstance(expr,(Add, Mul)): - args = expr.args - args = [subs_mul(arg) for arg in args] - - if isinstance(expr, Mul): - args = expr.args - forms = [i for i in args if isinstance(i, BilinearAtomicForm)] - others = [i for i in args if not( i in forms )] - - t = TensorProduct(*forms) - m = Mul(*others) - return m*t - - elif isinstance(expr, Add): - - return Add(*args) - else: - - return expr - -#============================================================================== -# form here is a BilinearForm -def subs_form(form, newargs): -# print('>>> subs_form : ', form) - - if isinstance( form, BilinearForm ): - calls = form.expr.atoms(FormCall) - if calls: - return subs_form(form.expr, newargs) - - else: - return _subs_bilinear_form_core(form, newargs) - - elif isinstance( form, LinearForm ): - calls = form.expr.atoms(FormCall) - if calls: - return subs_form(form.expr, newargs) - - else: - return _subs_linear_form_core(form, newargs) - - elif isinstance( form, FormCall ): - return form - - elif isinstance( form, Add ): - args = [subs_form(a, newargs) for a in form.args] - return Add(*args) - - elif isinstance( form, Mul ): - coeffs = [i for i in form.args if isinstance(i, _coeffs_registery)] - vectors = [i for i in form.args if not(i in coeffs)] - - i = S.One - if coeffs: - i = Mul(*coeffs) - - j = S.One - if vectors: - args = [subs_form(a, newargs) for a in vectors] - j = Mul(*args) - - return Mul(i, j) - - elif isinstance( form, Pow ): - - b = subs_form(form.base, newargs) - e = form.exp - - return Pow(b, e) - - else: - return form - - -#============================================================================== -def _subs_bilinear_form_core(form, newargs): - # ... - test_trial = _sanitize_form_arguments(newargs, form, is_bilinear=True) - - if not isinstance(test_trial, (tuple, list, Tuple)): - raise TypeError('(test, trial) must be a tuple, list or Tuple') - - if not(len(test_trial) == 2): - raise ValueError('Expecting a couple (test, trial)') - # ... - - # ... - test_functions = test_trial[0] - if isinstance(test_functions, (TestFunction, VectorTestFunction)): - test_functions = [test_functions] - - elif isinstance(test_functions, (tuple, list, Tuple)): - test_functions = Tuple(*test_functions) - # ... - - # ... - trial_functions = test_trial[1] - if isinstance(trial_functions, (TestFunction, VectorTestFunction)): - trial_functions = [trial_functions] - - elif isinstance(trial_functions, (tuple, list, Tuple)): - trial_functions = Tuple(*trial_functions) - # ... - - # in order to avoid problems when swapping indices, we need to create - # temp symbols - - # ... - d_tmp = {} - for x in trial_functions: - name = random_string( 6 ) - if isinstance(x, TestFunction): - X = TestFunction(x.space, name=name) - - elif isinstance(x, VectorTestFunction): - X = VectorTestFunction(x.space, name=name) - - else: - raise TypeError('Only TestFunction and VectorTestFunction are available') - - d_tmp[X] = x - # ... - - expr = form.expr - - # ... replacing trial functions by tmp symbols - for k,v in zip(form.trial_functions, d_tmp): - expr = expr.subs(k,v) - # ... - - # ... replacing test functions - for k,v in zip(form.test_functions, test_functions): - expr = expr.subs(k,v) - # ... - - # ... replacing trial functions from tmp symbols - for k,v in d_tmp.items(): - expr = expr.subs(k,v) - # ... - - # ... - if len(test_functions) == 1: test_functions = test_functions[0] - if len(trial_functions) == 1: trial_functions = trial_functions[0] - - test_trial = (test_functions, trial_functions) - # ... - - return BilinearForm(test_trial, expr, name=form.name, check=False) - - -#============================================================================== -def _subs_linear_form_core(form, newargs): - - # ... - test_functions = _sanitize_form_arguments(newargs, form, is_linear=True) - # TODO is it ok to do this? - test_functions = test_functions[0] - - if isinstance(test_functions, (TestFunction, VectorTestFunction)): - test_functions = [test_functions] - - elif isinstance(test_functions, (tuple, list, Tuple)): - test_functions = list(*test_functions) - # ... - - expr = form.expr - - # ... replacing test functions - for k,v in zip(form.test_functions, test_functions): - expr = expr.subs(k,v) - # ... - - if len(test_functions) == 1: test_functions = test_functions[0] - - return LinearForm(test_functions, expr, name=form.name, check=False) - -#============================================================================== -def is_linear_expression(expr, args, debug=True): - """checks if an expression is linear with respect to the given arguments.""" - # ... - left_args = [] - right_args = [] - for arg in args: - tag = random_string( 4 ) - - if isinstance(arg, TestFunction): - left = TestFunction(arg.space, name='l_' + tag) - right = TestFunction(arg.space, name='r_' + tag) - - elif isinstance(arg, VectorTestFunction): - left = VectorTestFunction(arg.space, name='l_' + tag) - right = VectorTestFunction(arg.space, name='r_' + tag) - - elif isinstance(arg, Field): - left = Field('l_' + tag, space=arg.space) - right = Field('r_' + tag, space=arg.space) - - elif isinstance(arg, VectorField): - left = VectorField(arg.space, 'l_' + tag) - right = VectorField(arg.space, 'r_' + tag) - - else: - raise TypeError('') - - left_args += [left] - right_args += [right] - # ... - - # ... check addition - newexpr = expr - for arg, left, right in zip(args, left_args, right_args): - newarg = left + right - newexpr = newexpr.subs(arg, newarg) - - left_expr = expr - for arg, left in zip(args, left_args): - left_expr = left_expr.subs(arg, left) - - right_expr = expr - for arg, right in zip(args, right_args): - right_expr = right_expr.subs(arg, right) - - if not( expand(newexpr) == expand(left_expr) + expand(right_expr) ): - # TODO use a warning or exception? - if debug: - print('Failed to assert addition property') - -# print('===========') -# print(arg, left, right) -# -# print(expand(newexpr)) -# print(expand(left_expr)) -# print(expand(right_expr)) -# print(expand(newexpr) - expand(left_expr) - expand(right_expr)) -# import sys; sys.exit(0) - - - return False - # ... - - # ... check multiplication - tag = random_string( 4 ) - coeff = Constant('alpha_' + tag) - - newexpr = expr - for arg, left in zip(args, left_args): - newarg = coeff * left - newexpr = newexpr.subs(arg, newarg) - - left_expr = expr - for arg, left in zip(args, left_args): - left_expr = left_expr.subs(arg, left) - - left_expr = coeff * left_expr.subs(arg, left) - - if not( expand(newexpr) == expand(left_expr)): - # TODO use a warning or exception? - if debug: - print('Failed to assert multiplication property') - - return False - # ... - - return True - - -#============================================================================== -def is_bilinear_form(expr, args): - """checks if an expression is bilinear with respect to the given arguments.""" - # ... - test_trial = _sanitize_form_arguments(args, expr, is_bilinear=True) - - if not isinstance(test_trial, (tuple, list, Tuple)): - raise TypeError('(test, trial) must be a tuple, list or Tuple') - - if not(len(test_trial) == 2): - raise ValueError('Expecting a couple (test, trial)') - # ... - - # ... - test_functions = test_trial[0] - if isinstance(test_functions, (TestFunction, VectorTestFunction)): - test_functions = [test_functions] - - elif isinstance(test_functions, (tuple, list, Tuple)): - test_functions = Tuple(*test_functions) - # ... - - # ... - trial_functions = test_trial[1] - if isinstance(trial_functions, (TestFunction, VectorTestFunction)): - trial_functions = [trial_functions] - - elif isinstance(trial_functions, (tuple, list, Tuple)): - trial_functions = Tuple(*trial_functions) - # ... - - # ... - if not is_linear_expression(expr, test_functions): - msg = ' Expression is not linear w.r.t [{}]'.format(test_functions) - raise UnconsistentLinearExpressionError(msg) - # ... - - # ... - if not is_linear_expression(expr, trial_functions): - msg = ' Expression is not linear w.r.t [{}]'.format(trial_functions) - raise UnconsistentLinearExpressionError(msg) - # ... - - return True - -#============================================================================== -def is_linear_form(expr, args): - """checks if an expression is linear with respect to the given arguments.""" - # ... - test_functions = _sanitize_form_arguments(args, expr, is_linear=True) - # TODO is it ok to do this? - test_functions = test_functions[0] - - if isinstance(test_functions, (TestFunction, VectorTestFunction)): - test_functions = [test_functions] - - elif isinstance(test_functions, (tuple, list, Tuple)): - test_functions = list(*test_functions) - # ... - - # ... - if not is_linear_expression(expr, test_functions): - msg = ' Expression is not linear w.r.t [{}]'.format(test_functions) - raise UnconsistentLinearExpressionError(msg) - # ... - - return True - - -#============================================================================== -def linearize(form, fields, trials=None): - """linearize a LinearForm around the fields.""" - # ... - if not isinstance(form, LinearForm): - raise TypeError('> Expecting a LinearForm') - - if not isinstance(fields, (list, tuple, Tuple)): - fields = [fields] - - for f in fields: - if not isinstance(f, (Field, VectorField)): - raise TypeError('{} is not Field/VectorField'.format(f)) - - if not(trials is None): - if not isinstance(trials, (list, tuple, Tuple)): - trials = [trials] - - assert( all([isinstance(i, (str, TestFunction, VectorTestFunction)) for i in trials]) ) - assert( len(fields) == len(trials) ) - - newtrials = [] - for i in trials: - if isinstance(i, (TestFunction, VectorTestFunction)): - newtrials += [i.name] - - else: - newtrials += [i] - - trials = newtrials - # ... - - expr = form.expr - test_functions = form.test_functions - fields = Tuple(*fields) - - # ... replace a FormCall by its expression - calls = expr.atoms(FormCall) - for call in calls: - expr = expr.subs(call, call.expr) - # ... - - # ... - trial_functions = [] - newargs = [] - eps = Constant('eps_' + random_string( 4 )) - for i,x in enumerate(fields): - tag = random_string( 4 ) - - if trials is None: - name = x.name + '_' + tag - else: - name = trials[i] - - if isinstance(x, Field): - trial = TestFunction(x.space, name=name) - - elif isinstance(x, VectorField): - trial = VectorTestFunction(x.space, name=name) - - else: - raise TypeError('Only TestFunction and VectorTestFunction are available') - - newargs += [x + eps*trial] - trial_functions += [trial] - # ... - - # ... - newexpr = expr - for k,v in zip(fields, newargs): - newexpr = newexpr.subs(k,v) - # ... - - newexpr = expand(newexpr) - - e = newexpr.series(eps, 0, 2) - d = collect(e, eps, evaluate=False) - expr = d[eps] - -# print('> linearize = ', expr) -# import sys; sys.exit(0) - - test_trial = (test_functions, trial_functions) - return BilinearForm(test_trial, expr, check=True) diff --git a/old/test_calculus.py.old b/old/test_calculus.py.old deleted file mode 100644 index 23770185..00000000 --- a/old/test_calculus.py.old +++ /dev/null @@ -1,161 +0,0 @@ -# coding: utf-8 - -import numpy as np - -from sympy.core.containers import Tuple -from sympy import symbols -from sympy import Symbol -from sympy import Lambda - -from sympde.core import (dx, dy, dz) -from sympde.core import LinearOperator -from sympde.core import ScalarField -from sympde.core import grad, dot, inner -from sympde.core import get_index_derivatives - - -# ... -def test_0(): - print('============ test_0 ==============') - - x,y, a = symbols('x y a') - - # ... - expr = x+y - print('> expr := {0}'.format(expr)) - - expr = LinearOperator(expr) - print('> evaluated := {0}'.format(expr)) - print('') - # ... - - # ... - expr = 2*x+y - print('> expr := {0}'.format(expr)) - - expr = LinearOperator(expr) - print('> evaluated := {0}'.format(expr)) - print('') - # ... - - # ... - expr = a*x+y - print('> expr := {0}'.format(expr)) - - expr = LinearOperator(expr) - print('> evaluated := {0}'.format(expr)) - # ... - - # ... - expr = 2*a*x+y - print('> expr := {0}'.format(expr)) - - expr = LinearOperator(expr) - print('> evaluated := {0}'.format(expr)) - # ... -# ... - -# ... -def test_1(): - print('============ test_1 ==============') - - u, v, a = symbols('u v a') - - # ... - expr = u+v - print('> expr := {0}'.format(expr)) - - expr = dx(expr) - print('> evaluated := {0}'.format(expr)) - print('') - # ... - - # ... - expr = 2*u*v - print('> expr := {0}'.format(expr)) - - expr = dx(expr) - print('> evaluated := {0}'.format(expr)) - print('') - # ... - - # ... dx should not operate on u^2, - # since we consider only linearized weak formulations - expr = u*u - print('> expr := {0}'.format(expr)) - - expr = dx(expr) - print('> evaluated := {0}'.format(expr)) - print('') - # ... -# ... - -# ... -def test_2(): - print('============ test_2 ==============') - - u, v = symbols('u v') - F = ScalarField('F') - - # ... - expr = F*v*u - print('> expr := {0}'.format(expr)) - - expr = dx(expr) - print('> evaluated := {0}'.format(expr)) - print('') - # ... -# ... - -# ... -def test_3(): - print('============ test_3 ==============') - - u = symbols('u') - - # ... - expr = dx(u) - d = get_index_derivatives(expr) - assert(d['x'] == 1) - assert(d['y'] == 0) - assert(d['z'] == 0) - # ... - - # ... - expr = dx(dy(u)) - d = get_index_derivatives(expr) - assert(d['x'] == 1) - assert(d['y'] == 1) - assert(d['z'] == 0) - # ... - - # ... - expr = dx(dy(dx(u))) - d = get_index_derivatives(expr) - assert(d['x'] == 2) - assert(d['y'] == 1) - assert(d['z'] == 0) - # ... - - print('') -# ... - -# ... -def test_poisson(): - print('============ test_poisson ==============') - - u, v = symbols('u v') - - # ... - expr = inner(grad(v), grad(u)) - print('> expr := {0}'.format(expr)) - # ... -# ... - -# ..................................................... -if __name__ == '__main__': - test_0() - test_1() - test_2() - test_3() - test_poisson() diff --git a/old/test_expr_1d.py.old b/old/test_expr_1d.py.old deleted file mode 100644 index 9659e9bc..00000000 --- a/old/test_expr_1d.py.old +++ /dev/null @@ -1,429 +0,0 @@ -# coding: utf-8 - -# TODO split the asserts between algebraic and weak formulations ones -# TODO: - __call__ examples are not working anymore - -from sympy.core.containers import Tuple -from sympy import symbols -from sympy import Symbol -from sympy import Function -from sympy import Matrix -from sympy import pi, cos, sin -from sympy import srepr -from sympy.physics.quantum import TensorProduct - -from sympde.core import dx, dy, dz -from sympde.core import Constant -from sympde.core import ScalarField -from sympde.core import grad, dot, cross, rot, curl, div -from sympde.core import FunctionSpace -from sympde.core import ProductSpace -from sympde.core import ScalarTestFunction -from sympde.core import VectorTestFunction -from sympde.core import BilinearForm, LinearForm, Integral -from sympde.core import atomize -from sympde.core import evaluate -from sympde.core import tensorize -from sympde.core import Mass, Stiffness, Advection, AdvectionT -from sympde.core import Unknown -from sympde.core import Domain - -DIM = 1 -domain = Domain('Omega', dim=DIM) - - -# ... -def test_atomize_1d_1(): - print('============ test_atomize_1d_1 =============') - - V = FunctionSpace('V', domain) - - v = ScalarTestFunction(V, name='v') - w = ScalarTestFunction(V, name='w') - c = Constant('c') - F = ScalarField('F', space=V) - x = Symbol('x') - f = Function('f') - - # ... - assert(atomize(grad(v)) == dx(v)) - assert(atomize(grad(c*v)) == c*dx(v)) - assert(atomize(grad(F*v)) == F*dx(v) + v*dx(F)) - assert(atomize(f(x)*grad(v)) == dx(v)*f(x)) - - assert(atomize(dot(grad(v), grad(w))) == dx(v)*dx(w)) - # ... - - # ... - assert(atomize(grad(v*w)) == w*dx(v) + v*dx(w)) - assert(atomize(div(grad(v*w))) == 2*dx(v)*dx(w) + dx(dx(v))*w + dx(dx(w))*v) - # ... - -# expr = div(grad(v*w)) -# print('> input >>> {0}'.format(expr)) -# print('> atomized >>> {0}'.format(atomize(expr))) -# print(expr.is_commutative) -# ... - -# ... -def test_evaluate_1d_1(): - print('============ test_evaluate_1d_1 =============') - - V = FunctionSpace('V', domain) - U = FunctionSpace('U', domain) - - v = ScalarTestFunction(V, name='v') - u = ScalarTestFunction(U, name='u') - c = Constant('c') - F = ScalarField('F', space=V) - - Ni, Ni_x = symbols('Ni Ni_x') - Nj, Nj_x = symbols('Nj Nj_x') - - # ... - a = BilinearForm((v,u), dot(grad(v), grad(u))) - assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x) - # ... - - # ... - a = BilinearForm((v,u), dot(grad(v), grad(u)) + c*v*u) - assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + c*Ni*Nj) - # ... - - # ... - a = BilinearForm((v,u), dot(grad(v), grad(u)) + F*v*u) - assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + F*Ni*Nj) - # ... - - # ... - a = BilinearForm((v,u), dot(grad(F*v), grad(u))) - assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == F*Ni_x*Nj_x + Ni*Nj_x*dx(F)) - # ... -# ... - -# ... -def test_calls_1d_3(): - print('============ test_calls_1d_3 =============') - - V1 = FunctionSpace('V1', domain) - V2 = FunctionSpace('V2', domain) - U1 = FunctionSpace('U1', domain) - U2 = FunctionSpace('U2', domain) - - v1 = ScalarTestFunction(V1, name='v1') - v2 = ScalarTestFunction(V2, name='v2') - u1 = ScalarTestFunction(U1, name='u1') - u2 = ScalarTestFunction(U2, name='u2') - - V = ProductSpace(V1, V2) - U = ProductSpace(U1, U2) - - x = V1.coordinates - - v1v2 = VectorTestFunction(V, name='v1v2') - u1u2 = VectorTestFunction(U, name='u1u2') - - # ... - a1 = BilinearForm((v1, u1), u1*v1, name='a1') - - expr = a1(v2, u2) - # ... - - # ... - a1 = BilinearForm((v1, u1), u1*v1, name='a1') - a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') - - expr = a1(v2, u2) + a2(v2, u2) - # ... - - # ... - a1 = BilinearForm((v1, u1), u1*v1, name='a1') - a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') - - expr = a1(v1, u2) + a2(v2, u1) - # ... - - # ... - l1 = LinearForm(v1, x*v1, name='l1') - - expr = l1(v2) - # ... - - # ... - l1 = LinearForm(v1, x*v1, name='l1') - l2 = LinearForm(v2, cos(x)*v2, name='l2') - - expr = l1(u1) + l2(u2) - # ... -# ... - -# ... -def test_evaluate_1d_3(): - print('============ test_evaluate_1d_3 =============') - - V1 = FunctionSpace('V1', domain) - U1 = FunctionSpace('U1', domain) - V2 = FunctionSpace('V2', domain) - U2 = FunctionSpace('U2', domain) - - v1 = ScalarTestFunction(V1, name='v1') - u1 = ScalarTestFunction(U1, name='u1') - v2 = ScalarTestFunction(V2, name='v2') - u2 = ScalarTestFunction(U2, name='u2') - - V = ProductSpace(V1, V2) - U = ProductSpace(U1, U2) - - v1v2 = VectorTestFunction(V, name='v1v2') - u1u2 = VectorTestFunction(U, name='u1u2') - - c = Constant('c') - - Ni, Ni_x = symbols('Ni Ni_x') - Nj, Nj_x = symbols('Nj Nj_x') - - basis = {v1v2: 'Ni', u1u2: 'Nj'} - - # ... - expr = v1*u1 + dx(v2)*dx(u2) - a = BilinearForm(((v1, v2), (u1, u2)), expr) - - expected = Matrix([[Ni*Nj, 0], [0, Ni_x*Nj_x]]) - assert(evaluate(a, basis=basis) == expected) - # ... - - # ... - expr = v1*u1 + dx(v2)*dx(u2) + dx(v2)*u1 + v1*dx(u2) - a = BilinearForm(((v1, v2), (u1, u2)), expr) - - expected = Matrix([[Ni*Nj, Ni_x*Nj], [Ni*Nj_x, Ni_x*Nj_x]]) - assert(evaluate(a, basis=basis) == expected) - # ... - -# expr = v1*u1 + dx(v2)*dx(u2) + dx(v2)*u1 + v1*dx(u2) -# expr = BilinearForm(((v1, v2), (u1, u2)), expr) -# print('> input >>> {0}'.format(expr)) -# print('> normal form >>> {0}'.format(evaluate(expr, basis=basis))) - -# ... - -# ... -def test_bilinear_form_1d_10(): - print('============ test_bilinear_form_1d_10 =============') - - U = FunctionSpace('U', domain) - V = FunctionSpace('V', domain) - - u = ScalarTestFunction(U, name='u') - v = ScalarTestFunction(V, name='v') - - u1 = ScalarTestFunction(U, name='u1') - v1 = ScalarTestFunction(V, name='v1') - - Ni, Ni_x = symbols('Ni Ni_x') - Nj, Nj_x = symbols('Nj Nj_x') - - c1 = Symbol('c1') - c2 = Symbol('c2') - - a = BilinearForm((v,u), dot(grad(u), grad(v))) - b = BilinearForm((v,u), u*v) - adv = BilinearForm((v,u), dx(u)*v) - - # ... - expected = Ni*Nj + Ni_x*Nj_x - assert(evaluate(a + b, basis={v: 'Nj', u: 'Ni'}) == expected) - # ... - - # ... - expected = 2*Ni_x*Nj_x - assert(evaluate(2 * a, basis={v: 'Nj', u: 'Ni'}) == expected) - # ... - - # ... - expected = c1*Ni_x*Nj_x - assert(evaluate(c1*a, basis={v: 'Nj', u: 'Ni'}) == expected) - # ... - - # ... - expected = c2*Ni*Nj + c1*Ni_x*Nj_x - assert(evaluate(c1*a + c2*b, basis={v: 'Nj', u: 'Ni'}) == expected) - # ... - - # ... - expected = Ni_x*Nj_x*c1 + c2*(Ni*Nj + Ni_x*Nj) - assert(evaluate(c1*a + c2*(b + adv), basis={v: 'Nj', u: 'Ni'}) == expected) - # ... - -# expr = adv(v1, u1) -# print('> input >>> {0}'.format(expr)) -# print('> evaluated >>> {0}'.format(evaluate(expr, basis={V: 'Nj', U: 'Ni'}) )) -# print('') -# ... - -# ... -def test_linear_form_1d_10(): - print('============ test_linear_form_1d_10 =============') - - V = FunctionSpace('V', domain) - - v = ScalarTestFunction(V, name='v') - - x = V.coordinates - f = Function('f') - - Ni, Ni_x, Ni_xx = symbols('Ni Ni_x Ni_xx') - - c1 = Symbol('c1') - c2 = Symbol('c2') - - # ... - expected = cos(2*pi*x)*Ni - assert(evaluate(LinearForm(v, cos(2*pi*x)*v), - basis={v: 'Ni'}) == expected) - # ... - - # ... - expected = f(x)*Ni - assert(evaluate(LinearForm(v, f(x)*v), - basis={v: 'Ni'}) == expected) - # ... - - # ... - expected = cos(2*pi*x)*Ni_x - assert(evaluate(LinearForm(v, cos(2*pi*x)*dx(v)), - basis={v: 'Ni'}) == expected) - # ... - - # ... - expected = f(x)*Ni_xx - assert(evaluate(LinearForm(v, f(x)*dx(dx(v))), - basis={v: 'Ni'}) == expected) - # ... - -# expr = LinearForm(v, cos(2*pi*x)*dx(v)) -# print('> input >>> {0}'.format(expr)) -# print('> evaluated >>> {0}'.format(evaluate(expr, basis={V: 'Ni'}) )) -# print('') -# ... - -# ... -def test_function_form_1d_10(): - print('============ test_function_form_1d_10 =============') - - V = FunctionSpace('V', domain) - - F = ScalarField('F', space=V) - - x = V.coordinates - f = Function('f') - - Ni, Ni_x, Ni_xx = symbols('Ni Ni_x Ni_xx') - - c1 = Symbol('c1') - c2 = Symbol('c2') - - # ... - expected = -2*pi*sin(2*pi*x) - assert(evaluate(Integral(grad(cos(2*pi*x)), coordinates=[x])) == expected) - # ... - - # ... - expected = F-cos(2*pi*x) - assert(evaluate(Integral(F-cos(2*pi*x))) == expected) - # ... - - # ... - expected = (F-cos(2*pi*x))**2 - assert(evaluate(Integral((F-cos(2*pi*x))**2)) == expected) - # ... - - # ... - expected = dx(F) + 2*pi*sin(2*pi*x) - assert(evaluate(Integral(grad(F-cos(2*pi*x)))) == expected) - # ... - - # ... - expected = (dx(F) + 2*pi*sin(2*pi*x))**2 - assert(evaluate(Integral((grad(F-cos(2*pi*x)))**2)) == expected) - # ... - -# expr = Integral() -# print('> input >>> {0}'.format(expr)) -# print('> evaluated >>> {0}'.format(evaluate(expr) )) -# print('') -# ... - -# ... -def test_tensorize_1d_1(): - print('============ test_tensorize_1d_1 =============') - - V = FunctionSpace('V', domain) - V_0 = FunctionSpace('V_0', domain, coordinates=['x']) - - v = ScalarTestFunction(V, name='v') - u = ScalarTestFunction(V, name='u') - - v0 = ScalarTestFunction(V_0, name='v0') - u0 = ScalarTestFunction(V_0, name='u0') - - c = Constant('c') - - # ... - expected = Mass(v0, u0) - assert(tensorize(BilinearForm((v,u), u*v)) == expected) - # ... - - # ... - expected = Stiffness(v0, u0) - assert(tensorize(BilinearForm((v,u), dx(u)*dx(v))) == expected) - # ... - - # ... - expected = Advection(v0,u0) - assert(tensorize(BilinearForm((v,u), dx(u) * v)) == expected) - # ... - - # ... - expected = Advection(v0,u0) + AdvectionT(v0,u0) + TensorProduct(c ,Stiffness(v0,u0)) - assert(tensorize(BilinearForm((v,u), dx(v) * u + v * dx(u) + c * dx(v)*dx(u))) == expected) - # ... - -# expr = dx(v) * u + v * dx(u) + c * dx(v)*dx(u) -# expr = BilinearForm((v,u), expr) -# -# print('> input >>> {0}'.format(expr)) -# print('> tensorized >>> {0}'.format(tensorize(expr))) -# ... - -# ... -def test_unknown_1d_1(): - print('============ test_unknown_1d_1 =============') - - domain = Domain('Omega', dim=DIM) - - v = Unknown('v', domain) - c = Constant('c') - - # ... - assert(atomize(grad(v)) == dx(v)) - assert(atomize(grad(c*v)) == c*dx(v)) - # ... -# ... - -# ..................................................... -if __name__ == '__main__': - test_atomize_1d_1() - test_evaluate_1d_1() - - test_evaluate_1d_3() - - # TODO bug -# test_bilinear_form_1d_10() - test_linear_form_1d_10() - test_function_form_1d_10() - - test_tensorize_1d_1() - test_calls_1d_3() - - test_unknown_1d_1() diff --git a/old/test_expr_2d.py b/old/test_expr_2d.py deleted file mode 100644 index d11dad6c..00000000 --- a/old/test_expr_2d.py +++ /dev/null @@ -1,471 +0,0 @@ -# coding: utf-8 - -# TODO - split the asserts between algebraic and weak formulations ones -# - add assert for grad in vector case -# TODO: - __call__ examples are not working anymore - -from sympy import Symbol -from sympy.core.containers import Tuple -from sympy import symbols -from sympy import IndexedBase -from sympy import Matrix -from sympy import Function -from sympy import pi, cos, sin -from sympy import srepr -from sympy.physics.quantum import TensorProduct - -from sympde.core import dx, dy, dz -from sympde.core import Constant -from sympde.core import ScalarField -from sympde.core import grad, dot, inner, cross, rot, curl, div -from sympde.core import FunctionSpace -from sympde.core import ProductSpace -from sympde.core import ScalarTestFunction -from sympde.core import VectorTestFunction -from sympde.core import BilinearForm, LinearForm, Integral -from sympde.core import atomize -from sympde.core import evaluate -from sympde.core import tensorize -from sympde.core import Mass, Stiffness, Advection, AdvectionT -from sympde.core import Unknown -from sympde.core import FormCall -from sympde.core import Domain, Boundary, NormalVector, TangentVector -from sympde.core import Trace, trace_0, trace_1 - -DIM = 2 -domain = Domain('Omega', dim=DIM) - -# ... -def test_atomize_2d_1(): - print('============ test_atomize_2d_1 =============') - - V = FunctionSpace('V', domain) - - v = ScalarTestFunction(V, name='v') - w = ScalarTestFunction(V, name='w') - c = Constant('c') - F = ScalarField('F', space=V) - - # ... - assert(atomize(grad(v)) == Tuple(dx(v), - dy(v))) - assert(atomize(grad(c*v)) == Tuple(c*dx(v), - c*dy(v))) - assert(atomize(grad(F*v)) == Tuple(F*dx(v) + v*dx(F), - F*dy(v) + v*dy(F))) - - assert(atomize(dot(grad(v), grad(w))) == dx(v)*dx(w) + dy(v)*dy(w)) - # ... - -# expr = grad(F*v) -# print('> input >>> {0}'.format(expr)) -# print('> atomized >>> {0}'.format(atomize(expr))) -# ... - -# ... -def test_evaluate_2d_1(): - print('============ test_evaluate_2d_1 =============') - - V = FunctionSpace('V', domain) - U = FunctionSpace('U', domain) - - v = ScalarTestFunction(V, name='v') - u = ScalarTestFunction(U, name='u') - - x,y = V.coordinates - - c = Constant('c') - F = ScalarField('F', space=V) - f1 = Function('f1') - f2 = Function('f2') - - Ni, Ni_x, Ni_y = symbols('Ni Ni_x Ni_y') - Nj, Nj_x, Nj_y = symbols('Nj Nj_x Nj_y') - - bx, by = symbols('bx by') - b = Tuple(bx, by) - - f = Tuple(f1(x,y), f2(x,y)) - - a00 = Constant('a00') - a10 = Constant('a10') - a01 = Constant('a01') - a11 = Constant('a11') - A = Matrix([[a00, a01], [a10, a11]]) - - # ... - a = BilinearForm((v,u), dot(grad(v), grad(u))) - assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + Ni_y*Nj_y) - # ... - - # ... - a = BilinearForm((v,u), dot(grad(v), grad(u)) + c*v*u) - assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + Ni_y*Nj_y + c*Ni*Nj) - # ... - - # ... - a = BilinearForm((v,u), dot(grad(v), grad(u)) + F*v*u) - assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + Ni_y*Nj_y + F*Ni*Nj) - # ... - - # ... - a = BilinearForm((v,u), dot(grad(F*v), grad(u))) - assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == F*Ni_x*Nj_x + F*Ni_y*Nj_y + Ni*Nj_x*dx(F) + Ni*Nj_y*dy(F)) - # ... - -# ... - -# ... -def test_atomize_2d_2(): - print('============ test_atomize_2d_2 =============') - - V = FunctionSpace('V', domain, is_block=True, shape=2) - - v = VectorTestFunction(V, name='v') - - assert(atomize(rot(v)) == -dx(v[1]) + dy(v[0])) - assert(atomize(div(v)) == dx(v[0]) + dy(v[1])) - -# expr = div(v) -# print('> input >>> {0}'.format(expr)) -# print('> atomized >>> {0}'.format(atomize(expr))) -# ... - -# ... -def test_evaluate_2d_3(): - print('============ test_evaluate_2d_3 =============') - - V1 = FunctionSpace('V1', domain) - U1 = FunctionSpace('U1', domain) - V2 = FunctionSpace('V2', domain) - U2 = FunctionSpace('U2', domain) - - v1 = ScalarTestFunction(V1, name='v1') - u1 = ScalarTestFunction(U1, name='u1') - v2 = ScalarTestFunction(V2, name='v2') - u2 = ScalarTestFunction(U2, name='u2') - - V = ProductSpace(V1, V2) - U = ProductSpace(U1, U2) - - v1v2 = VectorTestFunction(V, name='v1v2') - u1u2 = VectorTestFunction(U, name='u1u2') - - c = Constant('c') - - Ni, Ni_x, Ni_y = symbols('Ni Ni_x Ni_y') - Nj, Nj_x, Nj_y = symbols('Nj Nj_x Nj_y') - - basis = {v1v2: 'Ni', u1u2: 'Nj'} - - # ... - expr = v1*u1 + dx(v2)*dx(u2) - a = BilinearForm(((v1, v2), (u1, u2)), expr) - - expected = Matrix([[Ni*Nj, 0], [0, Ni_x*Nj_x]]) - assert(evaluate(a, basis=basis) == expected) - # ... - - # ... - expr = v1*u1 + dy(v2)*u1 + v1*dx(u2) + dx(v2)*dx(u2) - a = BilinearForm(((v1, v2), (u1, u2)), expr) - - expected = Matrix([[Ni*Nj, Ni_y*Nj], [Ni*Nj_x, Ni_x*Nj_x]]) - assert(evaluate(a, basis=basis) == expected) - # ... - -# expr = v1*u1 + dy(v2)*u1 + v1*dx(u2) + dx(v2)*dx(u2) -# expr = BilinearForm(((v1, v2), (u1, u2)), expr) -# print('> input >>> {0}'.format(expr)) -# print('> normal form >>> {0}'.format(evaluate(expr, basis=basis))) -# ... - -# ... -#def test_bilinear_form_2d_10(): -# print('============ test_bilinear_form_2d_10 =============') -# -# U = FunctionSpace('U', domain) -# V = FunctionSpace('V', domain) -# -# u = ScalarTestFunction(U, name='u') -# v = ScalarTestFunction(V, name='v') -# -# u1 = ScalarTestFunction(U, name='u1') -# v1 = ScalarTestFunction(V, name='v1') -# -# Ni, Ni_x, Ni_y = symbols('Ni Ni_x Ni_y') -# Nj, Nj_x, Nj_y = symbols('Nj Nj_x Nj_y') -# -# c1 = Symbol('c1') -# c2 = Symbol('c2') -# -# a = BilinearForm((v,u), inner(grad(u), grad(v))) -# b = BilinearForm((v,u), u*v) -# adv = BilinearForm((v,u), dx(u)*v) -# -# # ... -# expected = Ni*Nj + Ni_x*Nj_x + Ni_y*Nj_y -# assert(evaluate(a + b, basis={v: 'Nj', u: 'Ni'}) == expected) -# # ... -# -# # ... -# expected = 2*Ni_x*Nj_x + 2*Ni_y*Nj_y -# assert(evaluate(2 * a, basis={v: 'Nj', u: 'Ni'}) == expected) -# # ... -# -# # ... -# expected = c1*(Ni_x*Nj_x + Ni_y*Nj_y) -# assert(evaluate(c1*a, basis={v: 'Nj', u: 'Ni'}) == expected) -# # ... -# -# # ... -# expected = Ni*Nj*c2 + c1*(Ni_x*Nj_x + Ni_y*Nj_y) -# assert(evaluate(c1*a + c2*b, basis={v: 'Nj', u: 'Ni'}) == expected) -# # ... -# -# # ... -# expected = c1*(Ni_x*Nj_x + Ni_y*Nj_y) + c2*(Ni*Nj + Ni_x*Nj) -# assert(evaluate(c1*a + c2*(b + adv), basis={v: 'Nj', u: 'Ni'}) == expected) -# # ... -# -## expr = c1*a + c2*(b + adv) -## print('> input >>> {0}'.format(expr)) -## print('> evaluated >>> {0}'.format(evaluate(expr, basis={v: 'Nj', u: 'Ni'}) )) -## print('') -# ... - -# ... -def test_linear_form_2d_10(): - print('============ test_linear_form_2d_10 =============') - - V = FunctionSpace('V', domain) - - v = ScalarTestFunction(V, name='v') - - x,y = V.coordinates - f = Function('f') - g = Function('g') - - Ni, Ni_x, Ni_y = symbols('Ni Ni_x Ni_y') - Nj, Nj_x, Nj_y = symbols('Nj Nj_x Nj_y') - - c1 = Symbol('c1') - c2 = Symbol('c2') - - bx, by = symbols('bx by') - b = Tuple(bx, by) - fg = Tuple(f(x,y), g(x,y)) - - a = LinearForm(v, cos(2*pi*x)*cos(4*pi*y)*v) - - # ... - expected = cos(2*pi*x)*cos(4*pi*y)*Ni - assert(evaluate(LinearForm(v, cos(2*pi*x)*cos(4*pi*y)*v), - basis={v: 'Ni'}) == expected) - # ... - - # ... - expected = f(x,y)*Ni - assert(evaluate(LinearForm(v, f(x,y)*v), - basis={v: 'Ni'}) == expected) - # ... - - # ... - expected = bx*Ni_x + by*Ni_y + f(x,y)*Ni - assert(evaluate(LinearForm(v, dot(b, grad(v)) + f(x,y)*v), - basis={v: 'Ni'}) == expected) - # ... - - # ... - expected = f(x,y)*Ni_x + g(x,y)*Ni_y - assert(evaluate(LinearForm(v, dot(fg, grad(v))), - basis={v: 'Ni'}) == expected) - # ... - -# expr = -# print('> input >>> {0}'.format(expr)) -# print('> evaluated >>> {0}'.format(evaluate(expr, basis={v: 'Ni'}) )) -# print('') -# ... - -# ... -def test_function_form_2d_10(): - print('============ test_function_form_2d_10 =============') - - V = FunctionSpace('V', domain) - - F = ScalarField('F', space=V) - - x,y = V.coordinates - - f = Function('f') - g = Function('g') - - Ni, Ni_x, Ni_y = symbols('Ni Ni_x Ni_y') - Nj, Nj_x, Nj_y = symbols('Nj Nj_x Nj_y') - - c1 = Symbol('c1') - c2 = Symbol('c2') - - bx, by = symbols('bx by') - b = Tuple(bx, by) - fg = Tuple(f(x,y), g(x,y)) - - # ... - expected = 4*pi**2*sin(2*pi*x)**2*cos(3*pi*y)**2 + 9*pi**2*sin(3*pi*y)**2*cos(2*pi*x)**2 - e = cos(2*pi*x)*cos(3*pi*y) - assert(evaluate(Integral(dot(grad(e), grad(e)), coordinates=[x,y])) == expected) - # ... - - # ... - expected = F - cos(2*pi*x)*cos(3*pi*y) - assert(evaluate(Integral(F-cos(2*pi*x)*cos(3*pi*y))) == expected) - # ... - - # ... - expected = (F - cos(2*pi*x)*cos(3*pi*y))**2 - assert(evaluate(Integral((F - cos(2*pi*x)*cos(3*pi*y))**2)) == expected) - # ... - - # ... - expected = (dx(F) + 2*pi*sin(2*pi*x)*cos(3*pi*y))**2 + (dy(F) + 3*pi*sin(3*pi*y)*cos(2*pi*x))**2 - e = F -cos(2*pi*x)*cos(3*pi*y) - assert(evaluate(Integral(dot(grad(e), grad(e)))) == expected) - # ... - -# e = F -cos(2*pi*x)*cos(3*pi*y) -# expr = Integral(dot(grad(e), grad(e))) -# print('> input >>> {0}'.format(expr)) -# print('> evaluated >>> {0}'.format(evaluate(expr) )) -# print('') -# ... - -# ... -def test_tensorize_2d_1(): - print('============ test_tensorize_2d_1 =============') - - V = FunctionSpace('V', domain) - V_0 = FunctionSpace('V_0', domain, coordinates=['x']) - V_1 = FunctionSpace('V_1', domain, coordinates=['y']) - - v = ScalarTestFunction(V, name='v') - u = ScalarTestFunction(V, name='u') - - v0 = ScalarTestFunction(V_0, name='v0') - u0 = ScalarTestFunction(V_0, name='u0') - - v1 = ScalarTestFunction(V_1, name='v1') - u1 = ScalarTestFunction(V_1, name='u1') - - c = Constant('c') - - bx = Constant('bx') - by = Constant('by') - b = Tuple(bx, by) - - # ... - expected = TensorProduct(Mass(v1, u1), Mass(v0, u0)) - assert(tensorize(BilinearForm((v,u), u*v)) == expected) - # ... - - # ... - expected = TensorProduct(Mass(v1, u1), Stiffness(v0, u0)) - assert(tensorize(BilinearForm((v,u), dx(u)*dx(v))) == expected) - # ... - - # ... - expected = TensorProduct(Advection(v1, u1), Mass(v0, u0)) - assert(tensorize(BilinearForm((v,u), dy(u) * v)) == expected) - # ... - - # ... - expected = TensorProduct(Mass(v1,u1), Advection(v0,u0)) - assert(tensorize(BilinearForm((v,u), dx(u) * v)) == expected) - # ... - - # ... - expected = TensorProduct(Mass(v1,u1), Stiffness(v0,u0)) + TensorProduct(Stiffness(v1,u1), Mass(v0,u0)) - assert(tensorize(BilinearForm((v,u), dot(grad(v), grad(u)))) == expected) - # ... - - # ... - expected = (TensorProduct(Advection(v1,u1), Mass(v0,u0)) + - TensorProduct(Mass(v1,u1), Advection(v0,u0)) + - TensorProduct(Mass(v1,u1), Stiffness(v0,u0)) + - TensorProduct(Stiffness(v1,u1), Mass(v0,u0))) - assert(tensorize(BilinearForm((v,u), dot(grad(v), grad(u)) + dx(u)*v + dy(u)*v)) == expected) - # ... - - # ... - expected = (TensorProduct(bx, Mass(v1,u1), AdvectionT(v0,u0)) + - TensorProduct(by, AdvectionT(v1,u1), Mass(v0,u0))) - assert(tensorize(BilinearForm((v,u), dot(b, grad(v)) * u)) == expected) - # ... - - # ... - expected = (TensorProduct(bx**2,Mass(v1,u1),Stiffness(v0,u0)) + - TensorProduct(bx,by,Advection(v1,u1),AdvectionT(v0,u0)) + - TensorProduct(bx,by,AdvectionT(v1,u1),Advection(v0,u0)) + - TensorProduct(by**2,Stiffness(v1,u1),Mass(v0,u0))) - assert(tensorize(BilinearForm((v,u), dot(b, grad(v)) * dot(b, grad(u)))) == expected) - # ... - -# expr = dot(b, grad(v)) * u -# expr = BilinearForm((v,u), expr) -# -# print('> input >>> {0}'.format(expr)) -# print('> tensorized >>> {0}'.format(tensorize(expr))) -# ... - - -# ... -def test_tensorize_2d_2(): - print('============ test_tensorize_2d_2 =============') - - V = FunctionSpace('V', domain, is_block=True, shape=2) -# V_0 = FunctionSpace('V_0', domain, coordinates=['x']) -# V_1 = FunctionSpace('V_1', domain, coordinates=['y']) - - v = VectorTestFunction(V, name='v') - u = VectorTestFunction(V, name='u') - -# v0 = ScalarTestFunction(V_0, name='v0') -# u0 = ScalarTestFunction(V_0, name='u0') -# -# v1 = ScalarTestFunction(V_1, name='v1') -# u1 = ScalarTestFunction(V_1, name='u1') - - c = Constant('c') - - bx = Constant('bx') - by = Constant('by') - b = Tuple(bx, by) - -# # ... -# expected = Mass(v1, u1)*Mass(v0, u0) -# assert(tensorize(BilinearForm((v,u), div(v) * div(u))) == expected) -# # ... - -# expr = div(v) * div(u) + rot(v) * rot(u) -# expr = BilinearForm((v,u), expr) -# -# print('> input >>> {0}'.format(expr)) -# print('> tensorized >>> {0}'.format(tensorize(expr))) -# ... - -# ... -def test_unknown_2d_1(): - print('============ test_unknown_2d_1 =============') - - domain = Domain('Omega', dim=DIM) - - v = Unknown('v', domain) - c = Constant('c') - - # ... - assert(atomize(grad(v)) == Tuple(dx(v), - dy(v))) - assert(atomize(grad(c*v)) == Tuple(c*dx(v), - c*dy(v))) - # ... -# ... diff --git a/old/test_expr_3d.py.old b/old/test_expr_3d.py.old deleted file mode 100644 index 94af95c1..00000000 --- a/old/test_expr_3d.py.old +++ /dev/null @@ -1,589 +0,0 @@ -# coding: utf-8 - -# TODO - split the asserts between algebraic and weak formulations ones -# - add assert for grad in vector case -# TODO: - __call__ examples are not working anymore - -from sympy import Symbol -from sympy.core.containers import Tuple -from sympy import symbols -from sympy import IndexedBase -from sympy import Matrix -from sympy import Function -from sympy import pi, cos, sin -from sympy.physics.quantum import TensorProduct - -from sympde.core import dx, dy, dz -from sympde.core import Constant -from sympde.core import ScalarField -from sympde.core import grad, dot, inner, cross, rot, curl, div -from sympde.core import FunctionSpace -from sympde.core import ProductSpace -from sympde.core import ScalarTestFunction -from sympde.core import VectorTestFunction -from sympde.core import BilinearForm, LinearForm, Integral -from sympde.core import atomize -from sympde.core import evaluate -from sympde.core import tensorize -from sympde.core import Mass, Stiffness, Advection, AdvectionT -from sympde.core import Unknown -from sympde.core import Domain - -DIM = 3 -domain = Domain('Omega', dim=DIM) - - -# ... -def test_atomize_3d_1(): - print('============ test_atomize_3d_1 =============') - - V = FunctionSpace('V', domain) - - v = ScalarTestFunction(V, name='v') - w = ScalarTestFunction(V, name='w') - c = Constant('c') - F = ScalarField('F', space=V) - - # ... - assert(atomize(grad(v)) == Tuple(dx(v), - dy(v), - dz(v))) - assert(atomize(grad(c*v)) == Tuple(c*dx(v), - c*dy(v), - c*dz(v))) - assert(atomize(grad(F*v)) == Tuple(F*dx(v) + v*dx(F), - F*dy(v) + v*dy(F), - F*dz(v) + v*dz(F))) - - assert(atomize(dot(grad(v), grad(w))) == dx(v)*dx(w) + dy(v)*dy(w) + dz(v)*dz(w)) - # ... - -# expr = grad(F*v) -# print('> input >>> {0}'.format(expr)) -# print('> atomized >>> {0}'.format(atomize(expr))) -# ... - -# ... -def test_evaluate_3d_1(): - print('============ test_evaluate_3d_1 =============') - - V = FunctionSpace('V', domain) - U = FunctionSpace('U', domain) - - v = ScalarTestFunction(V, name='v') - u = ScalarTestFunction(U, name='u') - - x,y,z = V.coordinates - - c = Constant('c') - F = ScalarField('F', space=V) - f1 = Function('f1') - f2 = Function('f2') - f3 = Function('f3') - - Ni, Ni_x, Ni_y, Ni_z = symbols('Ni Ni_x Ni_y Ni_z') - Nj, Nj_x, Nj_y, Nj_z = symbols('Nj Nj_x Nj_y Nj_z') - - bx, by, bz = symbols('bx by bz') - b = Tuple(bx, by, bz) - - f = Tuple(f1(x,y,z), f2(x,y,z), f3(x,y,z)) - - a00 = Constant('a00') - a10 = Constant('a10') - a20 = Constant('a20') - a01 = Constant('a01') - a11 = Constant('a11') - a21 = Constant('a21') - a02 = Constant('a02') - a12 = Constant('a12') - a22 = Constant('a22') - A = Matrix([[a00, a01, a02], [a10, a11, a12], [a20, a21, a22]]) - - # ... - a = BilinearForm((v,u), dot(grad(v), grad(u))) - assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z) - # ... - - # ... - a = BilinearForm((v,u), dot(grad(v), grad(u)) + c*v*u) - assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z + c*Ni*Nj) - # ... - - # ... - a = BilinearForm((v,u), dot(grad(v), grad(u)) + F*v*u) - assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z + F*Ni*Nj) - # ... - - # ... - a = BilinearForm((v,u), dot(grad(F*v), grad(u))) - assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == F*Ni_x*Nj_x + F*Ni_y*Nj_y + F*Ni_z*Nj_z + Ni*Nj_x*dx(F) + Ni*Nj_y*dy(F) + Ni*Nj_z*dz(F)) - # ... - -# ... - -# ... -def test_atomize_3d_2(): - print('============ test_atomize_3d_2 =============') - - V = FunctionSpace('V', domain, is_vector=True, shape=3) - - v = VectorTestFunction(V, name='v') - - assert(atomize(curl(v)) == Tuple( dy(v[2]) - dz(v[1]), - -dx(v[2]) + dz(v[0]), - dx(v[1]) - dy(v[0]))) - assert(atomize(div(v)) == dx(v[0]) + dy(v[1]) + dz(v[2])) - -# expr = curl(v) -# print('> input >>> {0}'.format(expr)) -# print('> atomized >>> {0}'.format(atomize(expr))) -# ... - -# ... -#def test_bilinear_form_3d_10(): -# print('============ test_bilinear_form_3d_10 =============') -# -# U = FunctionSpace('U', domain) -# V = FunctionSpace('V', domain) -# -# u = ScalarTestFunction(U, name='u') -# v = ScalarTestFunction(V, name='v') -# -# u1 = ScalarTestFunction(U, name='u1') -# v1 = ScalarTestFunction(V, name='v1') -# -# Ni, Ni_x, Ni_y, Ni_z = symbols('Ni Ni_x Ni_y Ni_z') -# Nj, Nj_x, Nj_y, Nj_z = symbols('Nj Nj_x Nj_y Nj_z') -# -# c1 = Symbol('c1') -# c2 = Symbol('c2') -# -# a = BilinearForm((v,u), inner(grad(u), grad(v))) -# b = BilinearForm((v,u), u*v) -# adv = BilinearForm((v,u), dx(u)*v) -# -# # ... -# expected = Ni*Nj + Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z -# assert(evaluate(a + b, basis={v: 'Nj', u: 'Ni'}) == expected) -# # ... -# -# # ... -# expected = Ni*Nj + Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z -# assert(evaluate(a + b, basis={v: 'Nj', u: 'Ni'}) == expected) -# # ... -# -# # ... -# expected = 2*Ni_x*Nj_x + 2*Ni_y*Nj_y + 2*Ni_z*Nj_z -# assert(evaluate(2 * a, basis={v: 'Nj', u: 'Ni'}) == expected) -# # ... -# -# # ... -# expected = c1*(Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z) -# assert(evaluate(c1*a, basis={v: 'Nj', u: 'Ni'}) == expected) -# # ... -# -# # ... -# expected = Ni*Nj*c2 + c1*(Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z) -# assert(evaluate(c1*a + c2*b, basis={v: 'Nj', u: 'Ni'}) == expected) -# # ... -# -# # ... -# expected = c1*(Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z) + c2*(Ni*Nj + Ni_x*Nj) -# assert(evaluate(c1*a + c2*(b + adv), basis={v: 'Nj', u: 'Ni'}) == expected) -# # ... -# -# # ... -# assert(evaluate(a(u1, v1), basis={v: 'Nj', u: 'Ni'}) == evaluate(a(v1, u1), basis={v: 'Nj', u: 'Ni'})) -# # ... -# -## # ... TODO debug -## expected = Ni_x*Nj -## assert(evaluate(adv(v1, u1), basis={v: 'Nj', u: 'Ni'}) == expected) -## -## expected = Nj_x*Ni -## assert(evaluate(adv(u1, v1), basis={v: 'Nj', u: 'Ni'}) == expected) -## # ... -# -## expr = c1*a + c2*(b + adv) -## print('> input >>> {0}'.format(expr)) -## print('> evaluated >>> {0}'.format(evaluate(expr, basis={v: 'Nj', u: 'Ni'}) )) -## print('') -# ... - -# ... -def test_linear_form_3d_10(): - print('============ test_linear_form_3d_10 =============') - - V = FunctionSpace('V', domain) - - v = ScalarTestFunction(V, name='v') - x,y,z = V.coordinates - - f = Function('f') - g = Function('g') - r = Function('r') - - Ni, Ni_x, Ni_y, Ni_z = symbols('Ni Ni_x Ni_y Ni_z') - Nj, Nj_x, Nj_y, Nj_z = symbols('Nj Nj_x Nj_y Nj_z') - - c1 = Symbol('c1') - c2 = Symbol('c2') - - bx, by, bz = symbols('bx by bz') - b = Tuple(bx, by, bz) - fgr = Tuple(f(x,y,z), g(x,y,z), r(x,y,z)) - - a = LinearForm(v, cos(2*pi*x)*cos(4*pi*y)*cos(5*pi*z)*v) - - # ... - expected = cos(2*pi*x)*cos(4*pi*y)*cos(5*pi*z)*Ni - assert(evaluate(LinearForm(v, cos(2*pi*x)*cos(4*pi*y)*cos(5*pi*z)*v), - basis={v: 'Ni'}) == expected) - # ... - - # ... - expected = f(x,y,z)*Ni - assert(evaluate(LinearForm(v, f(x,y,z)*v), - basis={v: 'Ni'}) == expected) - # ... - - # ... - expected = bx*Ni_x + by*Ni_y + bz*Ni_z + f(x,y,z)*Ni - assert(evaluate(LinearForm(v, dot(b, grad(v)) + f(x,y,z)*v), - basis={v: 'Ni'}) == expected) - # ... - - # ... - expected = f(x,y,z)*Ni_x + g(x,y,z)*Ni_y + r(x,y,z)*Ni_z - assert(evaluate(LinearForm(v, dot(fgr, grad(v))), - basis={v: 'Ni'}) == expected) - # ... - -# expr = c1*a + c2*(b + adv) -# print('> input >>> {0}'.format(expr)) -# print('> evaluated >>> {0}'.format(evaluate(expr, basis={v: 'Ni'}) )) -# print('') -# ... - -# ... -def test_function_form_3d_10(): - print('============ test_function_form_3d_10 =============') - - V = FunctionSpace('V', domain) - - F = ScalarField('F', space=V) - - x,y,z = V.coordinates - - f = Function('f') - g = Function('g') - r = Function('r') - - Ni, Ni_x, Ni_y, Ni_z = symbols('Ni Ni_x Ni_y Ni_z') - Nj, Nj_x, Nj_y, Nj_z = symbols('Nj Nj_x Nj_y Nj_z') - - c1 = Symbol('c1') - c2 = Symbol('c2') - - bx, by, bz = symbols('bx by bz') - b = Tuple(bx, by, bz) - fgr = Tuple(f(x,y,z), g(x,y,z), r(x,y,z)) - - # ... - expected = cos(2*pi*x)*cos(3*pi*y)*cos(5*pi*z) - assert(evaluate(Integral(cos(2*pi*x)*cos(3*pi*y)*cos(5*pi*z), coordinates=[x,y,z])) == expected) - # ... - - # ... - expected = x**2 + y**2 + 1 - e = x*y + z - assert(evaluate(Integral(dot(grad(e), grad(e)), coordinates=[x,y,z])) == expected) - # ... - - # ... - expected = F - cos(2*pi*x)*cos(3*pi*y)*cos(5*pi*z) - assert(evaluate(Integral(F-cos(2*pi*x)*cos(3*pi*y)*cos(5*pi*z))) == expected) - # ... - - # ... - expected = (F - x*y - z)**2 - assert(evaluate(Integral((F - x*y - z)**2)) == expected) - # ... - - # ... - expected = dx(F)**2 + dy(F)**2 + dz(F)**2 - assert(evaluate(Integral(dot(grad(F), grad(F)))) == expected) - # ... - - # ... - expected = (-x + dy(F))**2 + (-y + dx(F))**2 + (dz(F) - 1)**2 - e = F - (x*y + z) - assert(evaluate(Integral(dot(grad(e), grad(e)), coordinates=[x,y,z])) == expected) - # ... - - # ... TODO debug. => infinite recursion!!! why? - # must be a problem with Mul treatements -# e = cos(2*pi*x)*cos(3*pi*y)*cos(5*pi*z) -# e = cos(2*pi*x)*cos(3*pi*y)*z -# e = x*y*z - # ... - -# e = F - (x*y + z) -# expr = Integral(dot(grad(e), grad(e)), coordinates=[x,y,z]) -# print('> input >>> {0}'.format(expr)) -# print('> evaluated >>> {0}'.format(evaluate(expr) )) -# print('') -# ... - -# ... -def test_calls_3d_3(): - print('============ test_calls_3d_3 =============') - - V1 = FunctionSpace('V1', domain) - V2 = FunctionSpace('V2', domain) - U1 = FunctionSpace('U1', domain) - U2 = FunctionSpace('U2', domain) - W1 = FunctionSpace('W1', domain, is_block=True, shape=3) - W2 = FunctionSpace('W2', domain, is_block=True, shape=3) - T1 = FunctionSpace('T1', domain, is_block=True, shape=3) - T2 = FunctionSpace('T2', domain, is_block=True, shape=3) - - v1 = ScalarTestFunction(V1, name='v1') - v2 = ScalarTestFunction(V2, name='v2') - u1 = ScalarTestFunction(U1, name='u1') - u2 = ScalarTestFunction(U2, name='u2') - w1 = VectorTestFunction(W1, name='w1') - w2 = VectorTestFunction(W2, name='w2') - t1 = VectorTestFunction(T1, name='t1') - t2 = VectorTestFunction(T2, name='t2') - - V = ProductSpace(V1, V2) - U = ProductSpace(U1, U2) - - x,y,z = V1.coordinates - - v1v2 = VectorTestFunction(V, name='v1v2') - u1u2 = VectorTestFunction(U, name='u1u2') - - # ... - a1 = BilinearForm((v1, u1), u1*v1, name='a1') - - expr = a1(v2, u2) - # ... - - # ... - a1 = BilinearForm((v1, u1), u1*v1, name='a1') - a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') - - expr = a1(v2, u2) + a2(v2, u2) - # ... - - # ... - a1 = BilinearForm((v1, u1), u1*v1, name='a1') - a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') - - expr = a1(v1, u2) + a2(v2, u1) - # ... - - # ... - a1 = BilinearForm((v1, u1), u1*v1, name='a1') - a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') - a3 = BilinearForm((w1, t1), dot(curl(w1), curl(t1)) + div(w1)*div(t1), name='a3') - a4 = BilinearForm((w1, u1), div(w1)*u1, name='a4') - - expr = a3(w2,t2) + a2(v2,u2) + a4(w2,u2) - # ... - - # ... - l1 = LinearForm(v1, x*y*z*v1, name='l1') - - expr = l1(v2) - # ... - - # ... - l1 = LinearForm(v1, x*y*z*v1, name='l1') - l2 = LinearForm(v2, cos(x+y+z)*v2, name='l2') - - expr = l1(u1) + l2(u2) - # ... -# ... - -# ... -def test_evaluate_3d_3(): - print('============ test_evaluate_3d_3 =============') - - V1 = FunctionSpace('V1', domain) - U1 = FunctionSpace('U1', domain) - V2 = FunctionSpace('V2', domain) - U2 = FunctionSpace('U2', domain) - - v1 = ScalarTestFunction(V1, name='v1') - u1 = ScalarTestFunction(U1, name='u1') - v2 = ScalarTestFunction(V2, name='v2') - u2 = ScalarTestFunction(U2, name='u2') - - V = ProductSpace(V1, V2) - U = ProductSpace(U1, U2) - - v1v2 = VectorTestFunction(V, name='v1v2') - u1u2 = VectorTestFunction(U, name='u1u2') - - c = Constant('c') - - Ni, Ni_x, Ni_y, Ni_z = symbols('Ni Ni_x Ni_y Ni_z') - Nj, Nj_x, Nj_y, Nj_z = symbols('Nj Nj_x Nj_y Nj_z') - - basis = {v1v2: 'Ni', u1u2: 'Nj'} - - # ... - expr = v1*u1 + dz(v2)*dz(u2) - a = BilinearForm(((v1, v2), (u1, u2)), expr) - - expected = Matrix([[Ni*Nj, 0], [0, Ni_z*Nj_z]]) - assert(evaluate(a, basis=basis) == expected) - # ... - - # ... - expr = v1*u1 + dx(v2)*dx(u1) + dy(v1)*dy(u2) + dz(v2)*dz(u2) - a = BilinearForm(((v1, v2), (u1, u2)), expr) - - expected = Matrix([[Ni*Nj, Ni_x*Nj_x], [Ni_y*Nj_y, Ni_z*Nj_z]]) - assert(evaluate(a, basis=basis) == expected) - # ... - -# expr = v1*u1 + dx(v2)*dx(u1) + dy(v1)*dy(u2) + dz(v2)*dz(u2) -# expr = BilinearForm(((v1, v2), (u1, u2)), expr) -# print('> input >>> {0}'.format(expr)) -# print('> normal form >>> {0}'.format(evaluate(expr, basis=basis))) -# ... - -# ... -def test_tensorize_3d_1(): - print('============ test_tensorize_3d_1 =============') - - V = FunctionSpace('V', domain) - V_0 = FunctionSpace('V_0', domain, coordinates=['x']) - V_1 = FunctionSpace('V_1', domain, coordinates=['y']) - V_2 = FunctionSpace('V_2', domain, coordinates=['z']) - - v = ScalarTestFunction(V, name='v') - u = ScalarTestFunction(V, name='u') - - v0 = ScalarTestFunction(V_0, name='v0') - u0 = ScalarTestFunction(V_0, name='u0') - - v1 = ScalarTestFunction(V_1, name='v1') - u1 = ScalarTestFunction(V_1, name='u1') - - v2 = ScalarTestFunction(V_2, name='v2') - u2 = ScalarTestFunction(V_2, name='u2') - - c = Constant('c') - - bx = Constant('bx') - by = Constant('by') - bz = Constant('bz') - b = Tuple(bx, by, bz) - - # ... - expected = TensorProduct(Mass(v2,u2),Mass(v1,u1),Mass(v0,u0)) - assert(tensorize(BilinearForm((v,u), u*v)) == expected) - # ... - - # ... - expected = TensorProduct(Mass(v2,u2),Mass(v1,u1),Stiffness(v0,u0)) - assert(tensorize(BilinearForm((v,u), dx(u)*dx(v))) == expected) - # ... - - # ... - expected = TensorProduct(Mass(v2,u2),Advection(v1,u1),Mass(v0,u0)) - assert(tensorize(BilinearForm((v,u), dy(u) * v)) == expected) - # ... - - # ... - expected = TensorProduct(Mass(v2,u2),Mass(v1,u1),Advection(v0,u0)) - assert(tensorize(BilinearForm((v,u), dx(u) * v)) == expected) - # ... - - # ... - expected = (TensorProduct(Mass(v2,u2),Mass(v1,u1),Stiffness(v0,u0)) + - TensorProduct(Mass(v2,u2),Stiffness(v1,u1),Mass(v0,u0)) + - TensorProduct(Stiffness(v2,u2),Mass(v1,u1),Mass(v0,u0))) - assert(tensorize(BilinearForm((v,u), dot(grad(v), grad(u)))) == expected) - # ... - - # ... - expected = (TensorProduct(Mass(v2,u2),Advection(v1,u1),Mass(v0,u0)) + - TensorProduct(Mass(v2,u2),Mass(v1,u1),Advection(v0,u0)) + - TensorProduct(Mass(v2,u2),Mass(v1,u1),Stiffness(v0,u0)) + - TensorProduct(Mass(v2,u2),Stiffness(v1,u1),Mass(v0,u0)) + - TensorProduct(Stiffness(v2,u2),Mass(v1,u1),Mass(v0,u0))) - assert(tensorize(BilinearForm((v,u), dot(grad(v), grad(u)) + dx(u)*v + dy(u)*v)) == expected) - # ... - - # ... - expected = (TensorProduct(bx,Mass(v2,u2),Mass(v1,u1),AdvectionT(v0,u0)) + - TensorProduct(by,Mass(v2,u2),AdvectionT(v1,u1),Mass(v0,u0)) + - TensorProduct(bz,AdvectionT(v2,u2),Mass(v1,u1),Mass(v0,u0))) - - assert(tensorize(BilinearForm((v,u), dot(b, grad(v)) * u)) == expected) - # ... - - # ... - expected = (TensorProduct(bx**2,Mass(v2,u2),Mass(v1,u1),Stiffness(v0,u0)) + - TensorProduct(bx,by,Mass(v2,u2),Advection(v1,u1),AdvectionT(v0,u0)) + - TensorProduct(bx,by,Mass(v2,u2),AdvectionT(v1,u1),Advection(v0,u0)) + - TensorProduct(bx,bz,Advection(v2,u2),Mass(v1,u1),AdvectionT(v0,u0)) + - TensorProduct(bx,bz,AdvectionT(v2,u2),Mass(v1,u1),Advection(v0,u0)) + - TensorProduct(by**2,Mass(v2,u2),Stiffness(v1,u1),Mass(v0,u0)) + - TensorProduct(by,bz,Advection(v2,u2),AdvectionT(v1,u1),Mass(v0,u0)) + - TensorProduct(by,bz,AdvectionT(v2,u2),Advection(v1,u1),Mass(v0,u0)) + - TensorProduct(bz**2,Stiffness(v2,u2),Mass(v1,u1),Mass(v0,u0))) - - assert(tensorize(BilinearForm((v,u), dot(b, grad(v)) * dot(b, grad(u)))) == expected) - # ... - -# expr = dot(b, grad(v)) * dot(b, grad(u)) -# expr = BilinearForm((v,u), expr) -# -# print('> input >>> {0}'.format(expr)) -# print('> tensorized >>> {0}'.format(tensorize(expr))) -# ... - -# ... -def test_unknown_3d_1(): - print('============ test_unknown_3d_1 =============') - - domain = Domain('Omega', dim=DIM) - - v = Unknown('v', domain) - c = Constant('c') - - # ... - assert(atomize(grad(v)) == Tuple(dx(v), - dy(v), - dz(v))) - assert(atomize(grad(c*v)) == Tuple(c*dx(v), - c*dy(v), - c*dz(v))) - # ... -# ... - -# ..................................................... -if __name__ == '__main__': - test_atomize_3d_1() - test_evaluate_3d_1() - - test_atomize_3d_2() - -# test_bilinear_form_3d_10() # TODO not working, since args are the same - test_linear_form_3d_10() - test_function_form_3d_10() - - test_evaluate_3d_3() - - test_tensorize_3d_1() - test_calls_3d_3() - - test_unknown_3d_1() diff --git a/old/test_form_2d.py b/old/test_form_2d.py deleted file mode 100644 index 2087c33c..00000000 --- a/old/test_form_2d.py +++ /dev/null @@ -1,1487 +0,0 @@ -# coding: utf-8 - -# TODO - split the asserts between algebraic and weak formulations ones -# - add assert for grad in vector case -# TODO: - __call__ examples are not working anymore - -import pytest - -from sympy import Symbol -from sympy.core.containers import Tuple -from sympy import symbols -from sympy import IndexedBase -from sympy import Matrix -from sympy import Function -from sympy import pi, cos, sin, exp -from sympy import srepr -from sympy.physics.quantum import TensorProduct - -from sympde.core import Constant -from sympde.calculus import grad, dot, inner, cross, rot, curl, div -from sympde.calculus import laplace, hessian, bracket, convect -from sympde.topology import (dx, dy, dz) -from sympde.topology import FunctionSpace, VectorFunctionSpace -from sympde.topology import Field, VectorField -from sympde.topology import ProductSpace -from sympde.topology import TestFunction -from sympde.topology import VectorTestFunction -from sympde.topology import Unknown -from sympde.topology import InteriorDomain, Union -from sympde.topology import Boundary, NormalVector, TangentVector -from sympde.topology import Domain -from sympde.topology import Trace, trace_0, trace_1 -from sympde.topology import Mapping -from sympde.topology import Square -from sympde.topology import ElementDomain -from sympde.topology import Area - -from sympde.expr import BilinearForm, LinearForm, Integral -from sympde.expr import atomize -from sympde.expr import evaluate -from sympde.expr import Mass, Stiffness, Advection, AdvectionT -from sympde.expr import Projection -from sympde.expr import Norm -from sympde.expr import FormCall -from sympde.expr import is_linear_form, is_bilinear_form -from sympde.expr import linearize - -from sympde.expr.errors import UnconsistentError -from sympde.expr.errors import UnconsistentLinearExpressionError -from sympde.expr.errors import UnconsistentLhsError -from sympde.expr.errors import UnconsistentRhsError -from sympde.expr.errors import UnconsistentBCError - -DIM = 2 -VERBOSE = False -VERBOSE = True - -#============================================================================== -def test_boundary_2d_1(): - domain = Domain('Omega', dim=DIM) - - V1 = FunctionSpace('V1', domain) - V2 = FunctionSpace('V2', domain) - U1 = FunctionSpace('U1', domain) - U2 = FunctionSpace('U2', domain) - W1 = VectorFunctionSpace('W1', domain) - W2 = VectorFunctionSpace('W2', domain) - T1 = VectorFunctionSpace('T1', domain) - T2 = VectorFunctionSpace('T2', domain) - - v1 = TestFunction(V1, name='v1') - v2 = TestFunction(V2, name='v2') - u1 = TestFunction(U1, name='u1') - u2 = TestFunction(U2, name='u2') - w1 = VectorTestFunction(W1, name='w1') - w2 = VectorTestFunction(W2, name='w2') - t1 = VectorTestFunction(T1, name='t1') - t2 = VectorTestFunction(T2, name='t2') - - x,y = V1.coordinates - - alpha = Constant('alpha') - - B1 = Boundary(r'\Gamma_1', domain) - B2 = Boundary(r'\Gamma_2', domain) - B3 = Boundary(r'\Gamma_3', domain) - - # ... - with pytest.raises(UnconsistentError): - expr = dot(grad(v1), grad(u1)) + v1*trace_0(u1, B1) - a = BilinearForm((v1,u1), expr, name='a') - # ... - - # ... - with pytest.raises(UnconsistentError): - expr = v1*trace_0(u1, B3) + v1*trace_1(grad(u1), B3) + u1*trace_0(v1, B2) - a1 = BilinearForm((v1, u1), expr, name='a1') - # ... - - # ... - expr = dot(grad(v1), grad(u1)) - a_0 = BilinearForm((v1,u1), expr, name='a_0') - - expr = v1*trace_0(u1, B1) - a_bnd = BilinearForm((v1, u1), expr, name='a_bnd') - - expr = a_0(v1,u1) + a_bnd(v1,u1) - a = BilinearForm((v1,u1), expr, name='a') - print(a) - print(evaluate(a, verbose=True)) - print('') -# import sys; sys.exit(0) - # ... - - - # ... - expr = v1*trace_0(u1, B1) + v1*trace_1(grad(u1), B1) - a1 = BilinearForm((v1, u1), expr, name='a1') - - expr = u1*trace_1(grad(v1), B2) - a2 = BilinearForm((v1, u1), expr, name='a2') - - expr = a1(v2, u2) + a2(v2, u2) - # as expected, we can define the form call, but we cannot create a Bilinear - # form out of it. - # TODO add assert on exception type -# a = BilinearForm((v2, u2), expr, name='a') - - print(expr) - print('') - # ... - - # ... - expr = v1*trace_0(u1, B1) - a0 = BilinearForm((v1, u1), expr, name='a0') - - expr = v1*trace_1(grad(u1), B1) - a1 = BilinearForm((v1, u1), expr, name='a1') - - expr = v1*trace_1(grad(u1), B2) - a2 = BilinearForm((v1, u1), expr, name='a2') - - expr = dot(grad(u1), grad(v1)) - a3 = BilinearForm((v1, u1), expr, name='a3') - - expr = u1*v1 - a4 = BilinearForm((v1, u1), expr, name='a4') - - # TODO Mul not treated yet -# expr = a0(v2, u2) + a1(v2, u2) + alpha * a2(v2, u2) + a3(v2, u2) + alpha*a4(v2, u2) -# a = BilinearForm((v2, u2), expr, name='a') -## print(expr) -# print(evaluate(expr, verbose=True)) -# print('') -# -# print(evaluate(a, verbose=True)) -# print('') - - -# expr = a(v2, u2) + a1(v2, u2) -# b = BilinearForm((v2, u2), expr, name='b') -# print(b) -# print(evaluate(b, verbose=True)) - # ... - - # ... - g = Tuple(x**2, y**2) - expr = v1*trace_1(g, B1) - l1 = LinearForm(v1, expr, name='l1') - print(l1) -# print(atomize(l1)) -# print(evaluate(l1)) - print('') - # ... - -#============================================================================== -def test_boundary_2d_2(): - Omega_1 = InteriorDomain('Omega_1', dim=2) - - B1 = Boundary('B1', Omega_1) - B2 = Boundary('B2', Omega_1) - B3 = Boundary('B3', Omega_1) - - domain = Domain('Omega', interiors=[Omega_1], - boundaries=[B1, B2, B3]) - - V = FunctionSpace('V', domain) - v = TestFunction(V, name='v') - u = TestFunction(V, name='u') - - x,y = V.coordinates - - alpha = Constant('alpha') - - # ... - print('==== l0 ====') - l0 = LinearForm(v, x*y*v, name='l0') - - print(evaluate(l0, verbose=VERBOSE)) - print('') - # ... - - # ... - print('==== l1 ====') - g = Tuple(x**2, y**2) - l1 = LinearForm(v, v*trace_1(g, domain.boundary)) - - print(evaluate(l1, verbose=VERBOSE)) - print('') - # ... - - # ... - print('==== l2 ====') - B_neumann = Union(B1, B2) - g = Tuple(x**2, y**2) - l2 = LinearForm(v, v*trace_1(g, B_neumann), name='l2') - - print(evaluate(l2, verbose=VERBOSE)) - print('') - # ... - - # ... - print('==== l3 ====') - l3 = LinearForm(v, l2(v)) - - assert(l3(v).__str__ == l2(v).__str__) - - print(evaluate(l3, verbose=VERBOSE)) - print('') - # ... - - # ... - print('==== l4 ====') - l4 = LinearForm(v, l0(v) + l2(v)) - - print(evaluate(l4, verbose=VERBOSE)) - print('') - # ... - -# # ... -# print('==== a1 ====') -# a1 = BilinearForm((v, u), v*trace_0(u, domain.boundary)) -# -# print(evaluate(a1, verbose=VERBOSE)) -# print('') -# # ... - - -#============================================================================== -def test_calls_2d(): - domain = Domain('Omega', dim=DIM) - - V1 = FunctionSpace('V1', domain) - V2 = FunctionSpace('V2', domain) - U1 = FunctionSpace('U1', domain) - U2 = FunctionSpace('U2', domain) - W1 = VectorFunctionSpace('W1', domain) - W2 = VectorFunctionSpace('W2', domain) - T1 = VectorFunctionSpace('T1', domain) - T2 = VectorFunctionSpace('T2', domain) - - v1 = TestFunction(V1, name='v1') - v2 = TestFunction(V2, name='v2') - u1 = TestFunction(U1, name='u1') - u2 = TestFunction(U2, name='u2') - w1 = VectorTestFunction(W1, name='w1') - w2 = VectorTestFunction(W2, name='w2') - t1 = VectorTestFunction(T1, name='t1') - t2 = VectorTestFunction(T2, name='t2') - - V = ProductSpace(V1, V2) - U = ProductSpace(U1, U2) - - x,y = V1.coordinates - - alpha = Constant('alpha') - - F = Field('F', space=V1) - - # ... - a1 = BilinearForm((v1, u1), u1*v1, name='a1') - print(a1) - print(atomize(a1)) - print(evaluate(a1)) - print('') - - expr = a1(v2, u2) - a = BilinearForm((v2, u2), expr, name='a') - print(a) - print(atomize(a)) - print(evaluate(a)) - print('') - # ... - - # ... - a = BilinearForm((v1, u1), dot(grad(v1), grad(u1)), name='a') - - print(a) - print(atomize(a)) - print(evaluate(a)) - print('') - # ... - - # ... - a1 = BilinearForm((v1, u1), dot(grad(v1), grad(u1)), name='a1') - - expr = a1(v2, u2) - a = BilinearForm((v2, u2), expr, name='a') - print(a) - print(atomize(a)) - print(evaluate(a)) - print('') - # ... - - # ... - a1 = BilinearForm((v1, u1), u1*v1, name='a1') - a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') - - expr = a1(v2, u2) + a2(v2, u2) - a = BilinearForm((v2, u2), expr, name='a') - print(a) - print(atomize(a)) - print(evaluate(a)) - print('') - # ... - - # ... - a1 = BilinearForm((v1, u1), u1*v1, name='a1') - a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') - - expr = a1(v1, u2) - print('> before = ', expr) - expr = expr.subs(u2, u1) - print('> after = ', expr) - print('') - - expr = a1(v1, u2) + a1(v2, u2) - print('> before = ', expr) - expr = expr.subs(u2, u1) - print('> after = ', expr) - print('') - # ... - - # ... - a1 = BilinearForm((v1, u1), u1*v1, name='a1') - a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') - - expr = a1(v1, u2) + a2(v2, u1) - a = BilinearForm(((v1,v2),(u1,u2)), expr, name='a') - print(a) - print(atomize(a)) - print(evaluate(a)) - print('') - # ... - - # ... - a = BilinearForm((w1, t1), rot(w1)*rot(t1) + div(w1)*div(t1), name='a') - print(a) - print(atomize(a)) - print(evaluate(a)) - # ... - - # ... - a1 = BilinearForm((v1, u1), u1*v1, name='a1') - a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') - a3 = BilinearForm((w1, t1), rot(w1)*rot(t1) + div(w1)*div(t1), name='a3') - a4 = BilinearForm((w1, u1), div(w1)*u1, name='a4') - - expr = a3(w2,t2) + a2(v2,u2) + a4(w2,u2) - a = BilinearForm(((w2,v2),(t2,u2)), expr, name='a') - print(a) - print(atomize(a)) - print(evaluate(a)) - # ... - - # ... - a1 = BilinearForm((v1, u1), laplace(u1)*laplace(v1), name='a1') - print(a1) - print(atomize(a1)) - print(evaluate(a1)) - print('') - # ... - - # ... - a1 = BilinearForm((v1, u1), inner(hessian(u1),hessian(v1)), name='a1') - print('================================') - print(a1) - print(atomize(a1)) - print(evaluate(a1)) - print('') - # ... - - # ... - l1 = LinearForm(v1, x*y*v1, name='11') - - expr = l1(v2) - l = LinearForm(v2, expr, name='1') - print(l) - print(atomize(l)) - print(evaluate(l)) - # ... - - # ... - l1 = LinearForm(v1, x*y*v1, name='l1') - l2 = LinearForm(v2, cos(x+y)*v2, name='l2') - - expr = l1(u1) + l2(u2) - l = LinearForm((u1,u2), expr, name='1') - print(l) - print(atomize(l)) - print(evaluate(l)) - # ... - - # ... - l1 = LinearForm(v1, x*y*v1, name='l1') - l2 = LinearForm(v2, cos(x+y)*v2, name='l2') - - expr = l1(u1) + alpha * l2(u2) - l = LinearForm((u1,u2), expr, name='1') - print(l) - print(atomize(l)) - print(evaluate(l)) - # ... - - # ... - l1 = LinearForm(v1, x*y*v1, name='l1') - l2 = LinearForm(w1, div(w1), name='l2') - - expr = l1(v2) + l2(w2) - l = LinearForm((v2,w2), expr, name='1') - print(l) - print(atomize(l)) - print(evaluate(l)) - # ... - - # ... - I1 = Integral(x*y, domain, name='I1') - - print(I1) - print(atomize(I1)) - print(evaluate(I1)) - # ... - - # ... - expr = F - cos(2*pi*x)*cos(3*pi*y) - expr = dot(grad(expr), grad(expr)) - I2 = Integral(expr, domain, name='I2') - - print(I2) - print(atomize(I2)) - print(evaluate(I2)) - # ... - - # ... - expr = F - cos(2*pi*x)*cos(3*pi*y) - expr = dot(grad(expr), grad(expr)) - I2 = Integral(expr, domain, name='I2') - - print(I2) - print(atomize(I2)) - print(evaluate(I2)) - # ... - - # ... stokes - V = VectorFunctionSpace('V', domain) - W = FunctionSpace('W', domain) - - v = VectorTestFunction(V, name='v') - u = VectorTestFunction(V, name='u') - p = TestFunction(W, name='p') - q = TestFunction(W, name='q') - - a = BilinearForm((v,u), inner(grad(v), grad(u)), name='a') - b = BilinearForm((v,p), div(v)*p, name='b') - A = BilinearForm(((v,q),(u,p)), a(v,u) - b(v,p) + b(u,q), name='A') - - print(A) - print(atomize(A)) - print(evaluate(A)) - # ... - -#============================================================================== -def test_projection_2d(): - domain = Domain('Omega', dim=DIM) - - V = FunctionSpace('V', domain) - x,y = domain.coordinates - - alpha = Constant('alpha') - - u = Projection(x**2+alpha*y, V, name='u') - - -#============================================================================== -def test_norm_2d(): - domain = Domain('Omega', dim=DIM) - - x,y = domain.coordinates - V = FunctionSpace('V', domain) - F = Field('F', V) - - # ... - expr = x*y - l2_norm_u = Norm(expr, domain, kind='l2') - h1_norm_u = Norm(expr, domain, kind='h1') - - print('> l2 norm = ', evaluate(l2_norm_u)) - print('> h1 norm = ', evaluate(h1_norm_u)) - print('') - # ... - - # ... - expr = sin(pi*x)*sin(pi*y) - l2_norm_u = Norm(expr, domain, kind='l2') - h1_norm_u = Norm(expr, domain, kind='h1') - - print('> l2 norm = ', evaluate(l2_norm_u)) - print('> h1 norm = ', evaluate(h1_norm_u)) - print('') - # ... - - # ... - expr = F-x*y - l2_norm_u = Norm(expr, domain, kind='l2') - h1_norm_u = Norm(expr, domain, kind='h1') - - print('> l2 norm = ', evaluate(l2_norm_u)) - print('> h1 norm = ', evaluate(h1_norm_u)) - print('') - # ... - - # ... - expr = F-sin(pi*x)*sin(pi*y) - l2_norm_u = Norm(expr, domain, kind='l2') - h1_norm_u = Norm(expr, domain, kind='h1') - - print('> l2 norm = ', evaluate(l2_norm_u)) - print('> h1 norm = ', evaluate(h1_norm_u)) - print('') - # ... - - # ... - expr = F-sin(0.5*pi*(1.-x))*sin(pi*y) - l2_norm_u = Norm(expr, domain, kind='l2') - h1_norm_u = Norm(expr, domain, kind='h1') - - print('> l2 norm = ', evaluate(l2_norm_u)) - print('> h1 norm = ', evaluate(h1_norm_u)) - print('') - # ... - - # ... - expr = F-cos(0.5*pi*x)*sin(pi*y) - l2_norm_u = Norm(expr, domain, kind='l2') - h1_norm_u = Norm(expr, domain, kind='h1') - - print('> l2 norm = ', evaluate(l2_norm_u)) - print('> h1 norm = ', evaluate(h1_norm_u)) - print('') - # ... - - -#============================================================================== -def test_vector_2d_1(): - domain = Domain('Omega', dim=DIM) - - W1 = VectorFunctionSpace('W1', domain) - T1 = VectorFunctionSpace('T1', domain) - - w1 = VectorTestFunction(W1, name='w1') - t1 = VectorTestFunction(T1, name='t1') - - x,y = W1.coordinates - - F = VectorField(W1, 'F') - -# # ... -# l1 = LinearForm(w1, dot(w1, F), name='l1') -# print(l1) -# print(atomize(l1)) -# print(evaluate(l1)) -# print('') -# # ... -# -# # ... -# l2 = LinearForm(w1, rot(w1)*rot(F) + div(w1)*div(F), name='l2') -# print(l2) -# print(atomize(l2)) -# print(evaluate(l2)) -# print('') -# # ... - - # ... - f = Tuple(sin(pi*x)*sin(pi*y), sin(pi*x)*sin(pi*y)) - error = Matrix([F[0]-f[0], F[1]-f[1]]) - l2_norm = Norm(error, domain, kind='l2') - print(l2_norm) - print(atomize(l2_norm)) - print(evaluate(l2_norm)) - print('') - # ... - - # ... - f = Tuple(sin(pi*x)*sin(pi*y), sin(pi*x)*sin(pi*y)) - error = Matrix([F[0]-f[0], F[1]-f[1]]) - h1_norm = Norm(error, domain, kind='h1') - print(h1_norm) - print(atomize(h1_norm)) - print(evaluate(h1_norm)) - print('') - # ... - -#============================================================================== -def test_expr_mapping_2d(): - - F = Mapping('F', DIM) - patch = Domain('Omega', dim=DIM) - domain = F(patch) - - V = FunctionSpace('V', domain) - v = TestFunction(V, name='v') - u = TestFunction(V, name='u') - - x,y = V.coordinates - - a = BilinearForm((v,u), dot(grad(v), grad(u))) - assert(a.mapping is F) - - l = LinearForm(v, x*y*v) - assert(l.mapping is F) - -#============================================================================== -def test_system_2d(): - - domain = Square() - - V = FunctionSpace('V', domain) - x,y = V.coordinates - - u,v,p,q = [TestFunction(V, name=i) for i in ['u','v','p','q']] - - a1,a2,b1,b2 = [Constant(i, real=True) for i in ['a1','a2','b1','b2']] - - # ... - a = BilinearForm((v,u), dot(grad(u), grad(v))) - m = BilinearForm((v,u), u*v) - - expr = a(p,u) + a1*m(p,u) + b1*m(p,v) + a(q,v) + a2*m(q,u) + b2*m(q,v) - b = BilinearForm(((p,q), (u,v)), expr) - - print(evaluate(b, verbose=True)) - # ... - - # ... - f1 = x*y - f2 = x+y - l1 = LinearForm(p, f1*p) - l2 = LinearForm(q, f2*q) - - expr = l1(p) + l2(q) - l = LinearForm((p,q), expr) - - print(evaluate(l, verbose=True)) - # ... - -#============================================================================== -def test_curldiv_2d(): - - domain = Square() - - W1 = VectorFunctionSpace('W1', domain) - T1 = VectorFunctionSpace('T1', domain) - - w1 = VectorTestFunction(W1, name='w1') - t1 = VectorTestFunction(T1, name='t1') - - mu = Constant('mu') - - # ... - a = BilinearForm((w1, t1), rot(w1)*rot(t1) + mu*div(w1)*div(t1), name='a') - print(a) - print(atomize(a)) - print(evaluate(a)) - # ... - - -#============================================================================== -def test_calls_2d_2(): - - domain = Square() - - V = FunctionSpace('V', domain) - x,y = V.coordinates - - u,v = [TestFunction(V, name=i) for i in ['u','v']] - Un = Field('Un', V) - - # ... - a = BilinearForm((v,u), dot(grad(u), grad(v))) - - expr = a(v, Un) - print(evaluate(expr, verbose=True)) - # ... - - # ... - l = LinearForm(v, a(v, Un)) - - print(evaluate(l, verbose=True)) - # ... - -#============================================================================== -def test_calls_2d_3(): - - domain = Square() - - V = FunctionSpace('V', domain) - - x,y = domain.coordinates - - pn = Field('pn', V) - wn = Field('wn', V) - - dp = TestFunction(V, name='dp') - dw = TestFunction(V, name='dw') - tau = TestFunction(V, name='tau') - sigma = TestFunction(V, name='sigma') - - Re = Constant('Re', real=True) - dt = Constant('dt', real=True) - alpha = Constant('alpha', real=True) - - l1 = LinearForm(tau, bracket(pn, wn)*tau - 1./Re * dot(grad(tau), grad(wn))) - - # ... - l = LinearForm((tau, sigma), dt*l1(tau)) - - print(evaluate(l, verbose=True)) - # ... - -#============================================================================== -def test_evaluation_2d_1(): - domain = Domain('Omega', dim=2) - B_neumann = Boundary(r'\Gamma_1', domain) - - V = FunctionSpace('V', domain) - W = VectorFunctionSpace('W', domain) - - p,q = [TestFunction(V, name=i) for i in ['p', 'q']] - u,v = [VectorTestFunction(W, name=i) for i in ['u', 'v']] - - alpha = Constant('alpha') - - x,y = V.coordinates - F = Field('F', space=V) - - a1 = BilinearForm((p, q), dot(grad(p), grad(q))) - m = BilinearForm((p, q), p*q) - a2 = BilinearForm((p, q), a1(p,q) + alpha*m(p,q)) - a3 = BilinearForm((u, v), rot(u)*rot(v) + alpha*div(u)*div(v)) - - a11 = BilinearForm((v,u), inner(grad(v), grad(u))) - a12 = BilinearForm((v,p), div(v)*p) - a4 = BilinearForm(((v,q),(u,p)), a11(v,u) - a12(v,p) + a12(u,q)) - - l0 = LinearForm(p, F*p) - l_neu = LinearForm(p, p*trace_1(grad(F), B_neumann)) - l = LinearForm(p, l0(p) + l_neu(p)) - - # ... - print(a1) - print(evaluate(a1)) - print('') - # ... - - # ... - print(a2) - print(evaluate(a2)) - print('') - # ... - - # ... - print(a3) - print(evaluate(a3)) - print('') - # ... - - # ... - print(a4) - print(evaluate(a4)) - print('') - # ... - - # ... - print(l) - print(evaluate(l)) - print('') - # ... - -#============================================================================== -def test_evaluation_2d_2(): - domain = Square() - x,y = domain.coordinates - - f0 = Tuple(2*pi**2*sin(pi*x)*sin(pi*y), - 2*pi**2*sin(pi*x)*sin(pi*y)) - - f1 = cos(pi*x)*cos(pi*y) - - W = VectorFunctionSpace('W', domain) - V = FunctionSpace('V', domain) - X = ProductSpace(W, V) - - # TODO improve: naming are not given the same way - F = VectorField(W, name='F') - G = Field('G', V) - - u,v = [VectorTestFunction(W, name=i) for i in ['u', 'v']] - p,q = [ TestFunction(V, name=i) for i in ['p', 'q']] - - a0 = BilinearForm((v,u), inner(grad(v), grad(u))) - a1 = BilinearForm((q,p), p*q) - a = BilinearForm(((v,q),(u,p)), a0(v,u) + a1(q,p)) - - l0 = LinearForm(v, dot(f0, v)) - l1 = LinearForm(q, f1*q) - l = LinearForm((v,q), l0(v) + l1(q)) - - # ... - print(a) - print(evaluate(a)) - print('') - # ... - - # ... - print(l) - print(evaluate(l)) - print('') - # ... - -#============================================================================== -def test_linearity_2d_1(): - domain = Square() - x,y = domain.coordinates - - alpha = Constant('alpha') - - f1 = x*y - f2 = x+y - f = Tuple(f1, f2) - - V = FunctionSpace('V', domain) - - # TODO improve: naming are not given the same way - G = Field('G', V) - - p,q = [TestFunction(V, name=i) for i in ['p', 'q']] - - ##################################### - # linear expressions - ##################################### - # ... - expr = p - assert(is_linear_form(expr, p)) - # ... - - # ... - expr = alpha*p - assert(is_linear_form(expr, p)) - # ... - - # ... - expr = dx(p) - assert(is_linear_form(expr, p)) - # ... - - # ... - expr = dot(grad(p), f) - assert(is_linear_form(expr, p)) - # ... - - # ... - expr = laplace(p) - assert(is_linear_form(expr, p)) - # ... - - # ... - expr = alpha*p + dot(grad(p), f) + dx(p) + laplace(p) - assert(is_linear_form(expr, p)) - # ... - ##################################### - - ##################################### - # nonlinear expressions - ##################################### - # ... - with pytest.raises(UnconsistentLinearExpressionError): - expr = p**2 - is_linear_form(expr, p) - # ... - - # ... - with pytest.raises(UnconsistentLinearExpressionError): - expr = dot(grad(p), grad(p)) - is_linear_form(expr, p) - # ... - ##################################### - -# expr = dot(grad(p), grad(p)) -# print(is_linear_form(expr, p)) - - -#============================================================================== -def test_bilinearity_2d_1(): - domain = Square() - x,y = domain.coordinates - - alpha = Constant('alpha') - beta = Constant('beta') - - f1 = x*y - f2 = x+y - f = Tuple(f1, f2) - - V = FunctionSpace('V', domain) - - # TODO improve: naming are not given the same way - G = Field('G', V) - - p,q = [TestFunction(V, name=i) for i in ['p', 'q']] - - ##################################### - # linear expressions - ##################################### - # ... - expr = p*q - assert(is_bilinear_form(expr, (p,q))) - # ... - - # ... - expr = dot(grad(p), grad(q)) - assert(is_bilinear_form(expr, (p,q))) - # ... - - # ... - expr = alpha*dot(grad(p), grad(q)) + beta*p*q + laplace(p)*laplace(q) - assert(is_bilinear_form(expr, (p,q))) - # ... - ##################################### - - ##################################### - # nonlinear expressions - ##################################### - # ... - with pytest.raises(UnconsistentLinearExpressionError): - expr = alpha*dot(grad(p**2), grad(q)) + beta*p*q - is_bilinear_form(expr, (p,q)) - # ... - ##################################### - -# expr = p*q -# print(is_bilinear_form(expr, (p,q))) - -#============================================================================== -def test_linearity_2d_2(): - domain = Domain('Omega', dim=DIM) - - V1 = FunctionSpace('V1', domain) - V2 = FunctionSpace('V2', domain) - U1 = FunctionSpace('U1', domain) - U2 = FunctionSpace('U2', domain) - W1 = VectorFunctionSpace('W1', domain) - W2 = VectorFunctionSpace('W2', domain) - T1 = VectorFunctionSpace('T1', domain) - T2 = VectorFunctionSpace('T2', domain) - - v1 = TestFunction(V1, name='v1') - v2 = TestFunction(V2, name='v2') - u1 = TestFunction(U1, name='u1') - u2 = TestFunction(U2, name='u2') - w1 = VectorTestFunction(W1, name='w1') - w2 = VectorTestFunction(W2, name='w2') - t1 = VectorTestFunction(T1, name='t1') - t2 = VectorTestFunction(T2, name='t2') - - V = ProductSpace(V1, V2) - U = ProductSpace(U1, U2) - - x,y = V1.coordinates - - alpha = Constant('alpha') - - F = Field('F', space=V1) - - # ... - l1 = LinearForm(v1, x*y*v1, check=True) - - l = LinearForm(v2, l1(v2), check=True) - # ... - - # ... - l1 = LinearForm(v1, x*y*v1, check=True) - l2 = LinearForm(v2, cos(x+y)*v2, check=True) - - l = LinearForm((u1,u2), l1(u1) + l2(u2), check=True) - # ... - - # ... - l1 = LinearForm(v1, x*y*v1, check=True) - l2 = LinearForm(v2, cos(x+y)*v2, check=True) - - l = LinearForm((u1,u2), l1(u1) + alpha * l2(u2), check=True) - # ... - - # ... - l1 = LinearForm(v1, x*y*v1, check=True) - l2 = LinearForm(w1, div(w1), check=True) - - l = LinearForm((v2,w2), l1(v2) + l2(w2), check=True) - # ... - - ################################ - # non bilinear forms - ################################ - # ... - with pytest.raises(UnconsistentLinearExpressionError): - l = LinearForm(v1, x*y*v1**2, check=True) - # ... - - # ... - with pytest.raises(UnconsistentLinearExpressionError): - l = LinearForm(v1, x*y, check=True) - # ... - ################################ - -#============================================================================== -def test_bilinearity_2d_2(): - domain = Domain('Omega', dim=DIM) - - V1 = FunctionSpace('V1', domain) - V2 = FunctionSpace('V2', domain) - U1 = FunctionSpace('U1', domain) - U2 = FunctionSpace('U2', domain) - W1 = VectorFunctionSpace('W1', domain) - W2 = VectorFunctionSpace('W2', domain) - T1 = VectorFunctionSpace('T1', domain) - T2 = VectorFunctionSpace('T2', domain) - - v1 = TestFunction(V1, name='v1') - v2 = TestFunction(V2, name='v2') - u1 = TestFunction(U1, name='u1') - u2 = TestFunction(U2, name='u2') - w1 = VectorTestFunction(W1, name='w1') - w2 = VectorTestFunction(W2, name='w2') - t1 = VectorTestFunction(T1, name='t1') - t2 = VectorTestFunction(T2, name='t2') - - V = ProductSpace(V1, V2) - U = ProductSpace(U1, U2) - - x,y = V1.coordinates - - alpha = Constant('alpha') - - F = Field('F', space=V1) - - # ... - a1 = BilinearForm((v1, u1), u1*v1, check=True) - a = BilinearForm((v2, u2), a1(v2, u2), check=True) - # ... - - # ... - a = BilinearForm((v1, u1), dot(grad(v1), grad(u1)), check=True) - # ... - - # ... - a1 = BilinearForm((v1, u1), dot(grad(v1), grad(u1)), check=True) - a = BilinearForm((v2, u2), a1(v2, u2), check=True) - # ... - - # ... - a1 = BilinearForm((v1, u1), u1*v1) - a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), check=True) - a = BilinearForm((v2, u2), a1(v2, u2) + a2(v2, u2), check=True) - # ... - - # ... - a1 = BilinearForm((v1, u1), u1*v1, check=True) - a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), check=True) - # ... - - # ... - a1 = BilinearForm((v1, u1), u1*v1, check=True) - a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), check=True) - a = BilinearForm(((v1,v2),(u1,u2)), a1(v1, u2) + a2(v2, u1), check=True) - # ... - - # ... - a = BilinearForm((w1, t1), rot(w1)*rot(t1) + div(w1)*div(t1), check=True) - # ... - - # ... - a1 = BilinearForm((v1, u1), u1*v1, check=True) - a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), check=True) - a3 = BilinearForm((w1, t1), rot(w1)*rot(t1) + div(w1)*div(t1), check=True) - a4 = BilinearForm((w1, u1), div(w1)*u1, check=True) - - a = BilinearForm(((w2,v2),(t2,u2)), a3(w2,t2) + a2(v2,u2) + a4(w2,u2), check=True) - # ... - - # ... - a1 = BilinearForm((v1, u1), laplace(u1)*laplace(v1), check=True) - # ... - - # ... - a1 = BilinearForm((v1, u1), inner(hessian(u1),hessian(v1)), check=True) - # ... - - # ... stokes - V = VectorFunctionSpace('V', domain) - W = FunctionSpace('W', domain) - - v = VectorTestFunction(V, name='v') - u = VectorTestFunction(V, name='u') - p = TestFunction(W, name='p') - q = TestFunction(W, name='q') - - a = BilinearForm((v,u), inner(grad(v), grad(u)), check=True) - b = BilinearForm((v,p), div(v)*p, check=True) - A = BilinearForm(((v,q),(u,p)), a(v,u) - b(v,p) + b(u,q), check=True) - # ... - - ################################ - # non bilinear forms - ################################ - # ... - with pytest.raises(UnconsistentLinearExpressionError): - a = BilinearForm((v1, u1), dot(grad(v1), grad(u1)) + v1, check=True) - # ... - - # ... - with pytest.raises(UnconsistentLinearExpressionError): - a = BilinearForm((v1, u1), v1**2*u1, check=True) - # ... - - # ... - with pytest.raises(UnconsistentLinearExpressionError): - a = BilinearForm((v1, u1), dot(grad(v1), grad(v1)), check=True) - # ... - ################################ - -#============================================================================== -#def test_nonlinear_2d_1(): -# -# domain = Square() -# -# V = FunctionSpace('V', domain) -# x,y = V.coordinates -# -# u,v = [TestFunction(V, name=i) for i in ['u','v']] -# Un = Field('Un', V) -# -# from sympy import diff as sympy_diff -# -# def diff(L, u): -# ls = [] -# expr = evaluate(L) -# for i in expr: -# e = sympy_diff(i.expr, u) -# ls.append(e) -# -# if len(ls) == 1: -# return ls[0] -# -# else: -# return ls -# -# # ... -# expr = Un**2 * dot(grad(Un), grad(v)) -# l = LinearForm(v, expr) -# -# a = diff(l, Un) -# print(a) -# # ... - -#============================================================================== -def test_linearize_2d_1(): - domain = Domain('Omega', dim=DIM) - x,y = domain.coordinates - - V1 = FunctionSpace('V1', domain) - W1 = VectorFunctionSpace('W1', domain) - - v1 = TestFunction(V1, name='v1') - w1 = VectorTestFunction(W1, name='w1') - - alpha = Constant('alpha') - - F = Field('F', space=V1) - G = VectorField(W1, 'G') - - # ... - l = LinearForm(v1, F**2*v1, check=True) - a = linearize(l, F, trials='u1') - print(a) - # ... - - # ... - l = LinearForm(v1, dot(grad(F), grad(F))*v1, check=True) - a = linearize(l, F, trials='u1') - print(a) - # ... - - # ... - l = LinearForm(v1, exp(-F)*v1, check=True) - a = linearize(l, F, trials='u1') - print(a) - # ... - - # ... - l = LinearForm(v1, cos(F)*v1, check=True) - a = linearize(l, F, trials='u1') - print(a) - # ... - - # ... - l = LinearForm(v1, cos(F**2)*v1, check=True) - a = linearize(l, F, trials='u1') - print(a) - # ... - - # ... - l = LinearForm(v1, F**2*dot(grad(F), grad(v1)), check=True) - a = linearize(l, F, trials='u1') - print(a) - # ... - - # ... - l = LinearForm(w1, dot(rot(G), grad(G))*w1, check=True) - a = linearize(l, G, trials='u1') - print(a) - # ... - -#============================================================================== -def test_linearize_2d_2(): - domain = Domain('Omega', dim=DIM) - x,y = domain.coordinates - - V1 = FunctionSpace('V1', domain) - - v1 = TestFunction(V1, name='v1') - - alpha = Constant('alpha') - - F = Field('F', space=V1) - G = Field('G', space=V1) - - # ... - l1 = LinearForm(v1, F**2*v1, check=True) - l = LinearForm(v1, l1(v1)) - - a = linearize(l, F, trials='u1') - print(a) - - expected = linearize(l1, F, trials='u1') - assert( linearize(l, F, trials='u1') == expected ) - # ... - -#============================================================================== -def test_linearize_2d_3(): - """steady Euler equation.""" - domain = Domain('Omega', dim=DIM) - x,y = domain.coordinates - - U = VectorFunctionSpace('U', domain) - W = FunctionSpace('W', domain) - - v = VectorTestFunction(U, name='v') - phi = TestFunction(W, name='phi') - q = TestFunction(W, name='q') - - U_0 = VectorField(U, name='U_0') - Rho_0 = Field('Rho_0', W) - P_0 = Field('P_0', W) - - # ... - expr = div(Rho_0*U_0) * phi - l1 = LinearForm(phi, expr, check=True) - - expr = Rho_0*dot(convect(U_0, grad(U_0)), v) + dot(grad(P_0), v) - l2 = LinearForm(v, expr, check=True) - - expr = dot(U_0, grad(P_0)) * q + P_0 * div(U_0) * q - l3 = LinearForm(q, expr, check=True) - # ... - - a1 = linearize(l1, [Rho_0, U_0], trials=['d_rho', 'd_u']) - print(a1) - print('') - - a2 = linearize(l2, [Rho_0, U_0, P_0], trials=['d_rho', 'd_u', 'd_p']) - print(a2) - print('') - - a3 = linearize(l3, [P_0, U_0], trials=['d_p', 'd_u']) - print(a3) - print('') - - l = LinearForm((phi, v, q), l1(phi) + l2(v) + l3(q)) - a = linearize(l, [Rho_0, U_0, P_0], trials=['d_rho', 'd_u', 'd_p']) - print(a) - -#============================================================================== -def test_area_2d_1(): - - domain = Domain('Omega', dim=2) - x,y = domain.coordinates - - mu = Constant('mu' , is_real=True) - - e = ElementDomain(domain) - area = Area(e) - - V = FunctionSpace('V', domain) - - u,v = [TestFunction(V, name=i) for i in ['u', 'v']] - - # ... - a = BilinearForm((v,u), area * u * v) - # ... - -#============================================================================== -def test_stabilization_2d_1(): - - domain = Domain('Omega', dim=2) - x,y = domain.coordinates - - kappa = Constant('kappa', is_real=True) - mu = Constant('mu' , is_real=True) - - b1 = 1. - b2 = 0. - b = Tuple(b1, b2) - - # right hand side - f = x*y - - e = ElementDomain() - area = Area(e) - - V = FunctionSpace('V', domain) - - u,v = [TestFunction(V, name=i) for i in ['u', 'v']] - - # ... - expr = kappa * dot(grad(u), grad(v)) + dot(b, grad(u)) * v - a = BilinearForm((v,u), expr) - # ... - - # ... - expr = f * v - l = LinearForm(v, expr) - # ... - - # ... - expr = (- kappa * laplace(u) + dot(b, grad(u))) * dot(b, grad(v)) - s1 = BilinearForm((v,u), expr) - - expr = - f * dot(b, grad(v)) - l1 = LinearForm(v, expr) - # ... - - # ... - expr = (- kappa * laplace(u) + dot(b, grad(u))) * ( dot(b, grad(v)) - kappa * laplace(v)) - s2 = BilinearForm((v,u), expr) - - expr = - f * ( dot(b, grad(v)) - kappa * laplace(v)) - l2 = LinearForm(v, expr) - # ... - - # ... - expr = (- kappa * laplace(u) + dot(b, grad(u))) * ( dot(b, grad(v)) + kappa * laplace(v)) - s3 = BilinearForm((v,u), expr) - - expr = - f * ( dot(b, grad(v)) + kappa * laplace(v)) - l3 = LinearForm(v, expr) - # ... - - # ... - expr = a(v,u) + mu*area*s1(v,u) - a1 = BilinearForm((v,u), expr) - # ... - - # ... - expr = a(v,u) + mu*area*s2(v,u) - a2 = BilinearForm((v,u), expr) - # ... - - # ... - expr = a(v,u) + mu*area*s3(v,u) - a3 = BilinearForm((v,u), expr) - # ... - - print(a1) - print(evaluate(a1, verbose=True)) - print('') - - print(a2) - print(evaluate(a2, verbose=True)) - print('') - - print(a3) - print(evaluate(a3, verbose=True)) - print('') - -#============================================================================== -def test_user_function_2d_1(): - - domain = Domain('Omega', dim=2) - x,y = domain.coordinates - - kappa = Constant('kappa', is_real=True) - mu = Constant('mu' , is_real=True) - - # right hand side - f = Function('f') - - V = FunctionSpace('V', domain) - - u,v = [TestFunction(V, name=i) for i in ['u', 'v']] - - # ... - expr = dot(grad(u), grad(v)) + f(x,y) * u * v - a = BilinearForm((v,u), expr) - - print(a) - print(evaluate(a, verbose=True)) - print('') - # ... - - # ... - expr = f(x,y) * v - l = LinearForm(v, expr) - - print(l) - print(evaluate(l, verbose=True)) - print('') - # ... - -#============================================================================== -# CLEAN UP SYMPY NAMESPACE -#============================================================================== - -def teardown_module(): - from sympy import cache - cache.clear_cache() - -def teardown_function(): - from sympy import cache - cache.clear_cache() - -#test_user_function_2d_1() - -#test_area_2d_1() -#test_stabilization_2d_1() - -#test_linearize_2d_1() -#test_linearize_2d_2() -#test_linearize_2d_3() - -#test_linearity_2d_1() -#test_linearity_2d_2() -#test_bilinearity_2d_1() -#test_bilinearity_2d_2() - -#test_boundary_2d_1() -#test_boundary_2d_2() -#test_projection_2d() -#test_norm_2d() -#test_vector_2d_1() -#test_expr_mapping_2d() -#test_system_2d() -#test_curldiv_2d() -#test_calls_2d() -#test_calls_2d_2() -#test_calls_2d_3() -#test_evaluation_2d_1() -#test_evaluation_2d_2() diff --git a/old/test_form_3d.py b/old/test_form_3d.py deleted file mode 100644 index 575bd92b..00000000 --- a/old/test_form_3d.py +++ /dev/null @@ -1,110 +0,0 @@ -# coding: utf-8 - -# TODO - split the asserts between algebraic and weak formulations ones -# - add assert for grad in vector case -# TODO: - __call__ examples are not working anymore - -import pytest - -from sympy import Symbol -from sympy.core.containers import Tuple -from sympy import symbols -from sympy import IndexedBase -from sympy import Matrix -from sympy import Function -from sympy import pi, cos, sin -from sympy import srepr -from sympy.physics.quantum import TensorProduct - -from sympde.core import Constant -from sympde.calculus import grad, dot, inner, cross, rot, curl, div -from sympde.calculus import laplace, hessian -from sympde.topology import (dx, dy, dz) -from sympde.topology import FunctionSpace, VectorFunctionSpace -from sympde.topology import Field, VectorField -from sympde.topology import ProductSpace -from sympde.topology import TestFunction -from sympde.topology import VectorTestFunction -from sympde.topology import Unknown -from sympde.topology import Domain, Boundary, NormalVector, TangentVector -from sympde.topology import Trace, trace_0, trace_1 - -from sympde.expr import BilinearForm, LinearForm, Integral -from sympde.expr import atomize -from sympde.expr import evaluate -from sympde.expr import tensorize -from sympde.expr import Mass, Stiffness, Advection, AdvectionT -from sympde.expr import Projection -from sympde.expr import Norm -from sympde.expr import FormCall - -from sympde.expr.errors import UnconsistentError -from sympde.expr.errors import UnconsistentLhsError -from sympde.expr.errors import UnconsistentRhsError -from sympde.expr.errors import UnconsistentBCError - - -DIM = 3 -domain = Domain('Omega', dim=DIM) - - -#============================================================================== -def test_tensorize_3d(): - - V = FunctionSpace('V', domain) - U = FunctionSpace('U', domain) - W1 = VectorFunctionSpace('W1', domain) - T1 = VectorFunctionSpace('T1', domain) - - v = TestFunction(V, name='v') - u = TestFunction(U, name='u') - w1 = VectorTestFunction(W1, name='w1') - t1 = VectorTestFunction(T1, name='t1') - - x,y,z = domain.coordinates - - alpha = Constant('alpha') - - # ... - expr = dot(grad(v), grad(u)) - a = BilinearForm((v,u), expr, name='a') - print(a) - print(tensorize(a)) - print('') - # ... - - # ... - expr = x*dx(v)*dx(u) + y*dy(v)*dy(u) - a = BilinearForm((v,u), expr, name='a') - print(a) - print(tensorize(a)) - print('') - # ... - - # ... - expr = sin(x)*dx(v)*dx(u) - a = BilinearForm((v,u), expr, name='a') - print(a) - print(tensorize(a)) - print('') - # ... - - # ... - expr = dot(curl(w1), curl(t1)) + div(w1)*div(t1) - a = BilinearForm((w1, t1), expr, name='a') - print(a) - print(tensorize(a)) - print('') - # ... - -#============================================================================== -# CLEAN UP SYMPY NAMESPACE -#============================================================================== - -def teardown_module(): - from sympy import cache - cache.clear_cache() - -def teardown_function(): - from sympy import cache - cache.clear_cache() diff --git a/old/test_tensorize_2d.py b/old/test_tensorize_2d.py deleted file mode 100644 index ab7cb485..00000000 --- a/old/test_tensorize_2d.py +++ /dev/null @@ -1,136 +0,0 @@ -# coding: utf-8 - -# TODO - tensorize is not working due to the last changes on calculus - -import pytest - -from sympy import Symbol -from sympy.core.containers import Tuple -from sympy import symbols -from sympy import IndexedBase -from sympy import Matrix -from sympy import Function -from sympy import pi, cos, sin -from sympy import srepr -from sympy.physics.quantum import TensorProduct - -from sympde.core import Constant -from sympde.calculus import grad, dot, inner, cross, rot, curl, div -from sympde.calculus import laplace, hessian, bracket -from sympde.topology import (dx, dy, dz) -from sympde.topology import FunctionSpace, VectorFunctionSpace -from sympde.topology import Field, VectorField -from sympde.topology import ProductSpace -from sympde.topology import TestFunction -from sympde.topology import VectorTestFunction -from sympde.topology import Unknown -from sympde.topology import InteriorDomain, Union -from sympde.topology import Boundary, NormalVector, TangentVector -from sympde.topology import Domain -from sympde.topology import Trace, trace_0, trace_1 -from sympde.topology import Mapping -from sympde.topology import Square - -from sympde.expr import BilinearForm, LinearForm, Integral -from sympde.expr import atomize -from sympde.expr import evaluate -from sympde.expr import tensorize -from sympde.expr import Mass, Stiffness, Advection, AdvectionT -from sympde.expr import Projection -from sympde.expr import Norm -from sympde.expr import FormCall - -from sympde.expr.errors import UnconsistentError -from sympde.expr.errors import UnconsistentLhsError -from sympde.expr.errors import UnconsistentRhsError -from sympde.expr.errors import UnconsistentBCError - -DIM = 2 -VERBOSE = False -VERBOSE = True - -#============================================================================== -def test_tensorize_2d(): - domain = Domain('Omega', dim=DIM) - - V = FunctionSpace('V', domain) - U = FunctionSpace('U', domain) - W1 = VectorFunctionSpace('W1', domain) - T1 = VectorFunctionSpace('T1', domain) - - v = TestFunction(V, name='v') - u = TestFunction(U, name='u') - w1 = VectorTestFunction(W1, name='w1') - t1 = VectorTestFunction(T1, name='t1') - - x,y = domain.coordinates - - alpha = Constant('alpha') - - # ... - expr = dot(grad(v), grad(u)) - a = BilinearForm((v,u), expr, name='a') - print(a) - print(tensorize(a)) - print('') - # ... - - # ... - expr = x*dx(v)*dx(u) + y*dy(v)*dy(u) - a = BilinearForm((v,u), expr, name='a') - print(a) - print(tensorize(a)) - print('') - # ... - - # ... - expr = sin(x)*dx(v)*dx(u) - a = BilinearForm((v,u), expr, name='a') - print(a) - print(tensorize(a)) - print('') - # ... - - # ... -# expr = rot(w1)*rot(t1) + div(w1)*div(t1) - expr = rot(w1)*rot(t1) #+ div(w1)*div(t1) - a = BilinearForm((w1, t1), expr, name='a') - print(a) - print(tensorize(a)) - print('') - # ... - -#============================================================================== -def test_tensorize_2d_stokes(): - domain = Domain('Omega', dim=DIM) - - # ... abstract model - V = VectorFunctionSpace('V', domain) - W = FunctionSpace('W', domain) - - v = VectorTestFunction(V, name='v') - u = VectorTestFunction(V, name='u') - p = TestFunction(W, name='p') - q = TestFunction(W, name='q') - - a = BilinearForm((v,u), inner(grad(v), grad(u)), name='a') - b = BilinearForm((v,p), div(v)*p, name='b') - A = BilinearForm(((v,q),(u,p)), a(v,u) - b(v,p) + b(u,q), name='A') - # ... - - print(A) - print(tensorize(A)) - print('') - - -#============================================================================== -# CLEAN UP SYMPY NAMESPACE -#============================================================================== - -def teardown_module(): - from sympy import cache - cache.clear_cache() - -def teardown_function(): - from sympy import cache - cache.clear_cache() From 7ffffcd4c2651450421d5337cb2e60610e3f3688 Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Mon, 28 Sep 2026 13:44:30 +0200 Subject: [PATCH 02/17] Modernize project metadata and test CI Move pytest configuration and development dependencies into pyproject.toml, test installed packages across supported Python versions, and collect coverage as a CI artifact. Keep the tested SymPy upper bound in place while https://github.com/pyccel/sympde/issues/106 tracks the compatibility work needed for current releases. --- .github/workflows/continuous-integration.yml | 92 ++++++++++++++++---- README.rst | 19 +++- pyproject.toml | 54 ++++++++++-- pytest.ini | 8 -- 4 files changed, 140 insertions(+), 33 deletions(-) delete mode 100644 pytest.ini diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 77cbe2a8..0a4ab65a 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -1,35 +1,95 @@ -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions - name: Unit tests on: push: - branches: [ master ] + branches: [master] + paths: + - 'sympde/**' + - 'pyproject.toml' + - '.github/workflows/continuous-integration.yml' pull_request: - branches: [ master ] + branches: [master] + paths: + - 'sympde/**' + - 'pyproject.toml' + - '.github/workflows/continuous-integration.yml' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: unit-tests-${{ github.ref }} + cancel-in-progress: true jobs: test: name: ${{ matrix.os }} / Python ${{ matrix.python-version }} runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: - os: [ ubuntu-latest, macos-latest ] - python-version: [3.9, '3.10', '3.11', '3.12', '3.13'] + include: + - {os: ubuntu-24.04, python-version: '3.9'} + - {os: ubuntu-24.04, python-version: '3.10'} + - {os: ubuntu-24.04, python-version: '3.11'} + - {os: ubuntu-24.04, python-version: '3.12'} + - {os: ubuntu-24.04, python-version: '3.13'} + - {os: ubuntu-24.04, python-version: '3.14'} + - {os: macos-14, python-version: '3.10'} + - {os: macos-14, python-version: '3.12'} + - {os: macos-14, python-version: '3.14'} + steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v6 + - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - - name: Upgrade pip + cache: pip + cache-dependency-path: pyproject.toml + + - name: Install project and test dependencies run: | python -m pip install --upgrade pip - python -m pip uninstall -y sympde - - name: Install SymPDE - run: | - python -m pip install . - - name: Test with pytest + python -m pip install ".[test]" + + - name: Run tests from outside the source tree + working-directory: ${{ runner.temp }} + run: >- + python -m pytest -n auto --dist loadgroup + --pyargs sympde -ra + + coverage: + name: Coverage / Python 3.14 + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.14' + cache: pip + cache-dependency-path: pyproject.toml + + - name: Install project and test dependencies run: | - cd - pytest -n auto --dist loadgroup --pyargs sympde -ra + python -m pip install --upgrade pip + python -m pip install ".[test]" + + - name: Run tests with coverage + working-directory: ${{ runner.temp }} + run: >- + python -m pytest -n auto --dist loadgroup + --cov sympde --cov-report term-missing --cov-report xml + --pyargs sympde -ra + + - name: Upload coverage report + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: ${{ runner.temp }}/coverage.xml diff --git a/README.rst b/README.rst index 1d4f0496..afa1bde7 100644 --- a/README.rst +++ b/README.rst @@ -66,7 +66,20 @@ To check out a specific branch/tag/commit named ````, just use ``git checko In order to make changes to the library, and see these changes when the package is imported, SymPDE should be installed in **editable** mode:: - python3 -m pip install --editable . + python3 -m pip install --editable ".[test]" + +Running the tests +^^^^^^^^^^^^^^^^^ + +The complete test suite can be run from any directory with:: + + python3 -m pytest -n auto --dist loadgroup --pyargs sympde -ra + +The documentation dependencies are installed separately and the HTML pages +are built with warnings treated as errors:: + + python3 -m pip install --editable ".[docs]" + python3 -m sphinx -W --keep-going -b html doc doc/_build/html For developers @@ -74,7 +87,7 @@ For developers Because many important features of SymPDE are only tested in Psydac, new PRs should also be tested against the test suite of Psydac. This can be done by opening a PR in Psydac, where the only change consists of installing the corresponding branch of SymPDE. -To achieve this, one just needs to modify the line corresponding to ``sympde`` in the ``pyproject.yaml`` file. +To achieve this, one just needs to modify the line corresponding to ``sympde`` in the ``pyproject.toml`` file. For instance, to test a new SymPDE branch called ``my_feature``, one should write @@ -100,7 +113,7 @@ Also, pay attention to the words ``head`` and ``tags`` in the path: the former i .. |docs| image:: https://readthedocs.org/projects/sympde/badge/?version=latest :alt: Documentation Status - :target: http://sympde.readthedocs.io/en/latest/?badge=latest + :target: https://sympde.readthedocs.io/en/latest/?badge=latest .. |binder| image:: https://mybinder.org/badge_logo.svg :alt: Run notebooks in Binder diff --git a/pyproject.toml b/pyproject.toml index e45220c4..37fc4b6f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools >= 64.0", "wheel"] +requires = ["setuptools >= 77.0", "wheel"] build-backend = "setuptools.build_meta" [project] @@ -8,25 +8,43 @@ version = "0.20.0" description = "Symbolic calculus for partial differential equations (and variational forms)" readme = "README.rst" requires-python = ">= 3.9" -license = {file = "LICENSE"} +license = "MIT" +license-files = ["LICENSE"] authors = [{name = "Ahmed Ratnani", email = "ratnaniahmed@gmail.com"}] maintainers = [ {name = "Yaman Güçlü", email = "yaman.guclu@gmail.com"}, {name = "Said Hadjout"}, ] -keywords = ["math"] -classifiers = ["Programming Language :: Python :: 3"] +keywords = ["finite elements", "partial differential equations", "symbolic mathematics"] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Science/Research", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Topic :: Scientific/Engineering :: Mathematics", +] dependencies = [ 'sympy >= 1.5, < 1.10', 'h5py', - 'pytest', - 'pytest-xdist', 'pyyaml', 'numpy', 'matplotlib' ] +[project.optional-dependencies] +test = [ + "pytest >= 8", + "pytest-cov >= 5", + "pytest-xdist >= 3", +] +docs = [ + "sphinx >= 7", + "sphinxcontrib-bibtex >= 2.6", +] + [project.urls] +Documentation = "https://sympde.readthedocs.io/" +Issues = "https://github.com/pyccel/sympde/issues" Repository = "https://github.com/pyccel/sympde" [tool.setuptools.packages.find] @@ -35,3 +53,27 @@ namespaces = false [tool.setuptools.package-data] "*" = ["README.rst"] + +[tool.pytest.ini_options] +minversion = "8.0" +addopts = ["--strict-markers"] +python_files = ["test_*.py"] +python_classes = [] +python_functions = ["test_*"] + +[tool.coverage.run] +branch = true +source = ["sympde"] +omit = ["*/tests/*"] + +[tool.coverage.report] +ignore_errors = true +exclude_also = [ + "def __repr__", + "if self\\.debug", + "raise AssertionError", + "raise NotImplementedError", + "if False:", + "if __name__ == .__main__.:", + "@(abc\\.)?abstractmethod", +] diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index a1500aee..00000000 --- a/pytest.ini +++ /dev/null @@ -1,8 +0,0 @@ -# this file shows to pytest what to collect -# here we avoid collecting test classes (which are not used in SPL) -# this is to avoid getting the warning on TestFunction -# TODO can we exlude TestFunction from python_classes pattern? -[pytest] -python_files = test_*.py -python_classes = -python_functions = test_* From 496d895cbf44603a7cb41a373099d6d8028376f7 Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Mon, 28 Sep 2026 15:02:28 +0200 Subject: [PATCH 03/17] Remove obsolete TODO file Delete the unreferenced 2019 roadmap, which describes removed APIs and work that has since been implemented. Active work is tracked through GitHub issues. Refs #181. --- TODO.rst | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 TODO.rst diff --git a/TODO.rst b/TODO.rst deleted file mode 100644 index 1f4b09f4..00000000 --- a/TODO.rst +++ /dev/null @@ -1,27 +0,0 @@ -- add BasicDerivable class for all sympde objects that can be differentiate with respect to the coordinates - -- add a coordinates system - -- remove Unknown and VectorUnknown - -Linearity -********* - -- must check that BilinearForm and LinearForm are really linear, by calling them and then applying atomize - -- this verification must be done at the __new__ as long as the flag check_linearity is True. The later is an argument of the __new__ method for BilinearForm and LinearForm - - -Weak formulation -**************** - -- add the concept of weak formulation - -- a weak formulation does not need to be linear/bilinear. - -- add linearize function that returns either LinearForm or BilinearForm - -Kron -**** - -the kronecker features must be upgraded as well as the tensorize function From d0de215c6bcbe99623b017dbecf8bcf7e13bc9e0 Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Tue, 29 Sep 2026 16:59:43 +0200 Subject: [PATCH 04/17] Align repository test workflow with Psydac Separate test automation from documentation builds and run it for every pull request update. --- .github/workflows/continuous-integration.yml | 95 -------------------- .github/workflows/testing.yml | 95 ++++++++++++++++++++ README.rst | 4 +- 3 files changed, 97 insertions(+), 97 deletions(-) delete mode 100644 .github/workflows/continuous-integration.yml create mode 100644 .github/workflows/testing.yml diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml deleted file mode 100644 index 0a4ab65a..00000000 --- a/.github/workflows/continuous-integration.yml +++ /dev/null @@ -1,95 +0,0 @@ -name: Unit tests - -on: - push: - branches: [master] - paths: - - 'sympde/**' - - 'pyproject.toml' - - '.github/workflows/continuous-integration.yml' - pull_request: - branches: [master] - paths: - - 'sympde/**' - - 'pyproject.toml' - - '.github/workflows/continuous-integration.yml' - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: unit-tests-${{ github.ref }} - cancel-in-progress: true - -jobs: - test: - name: ${{ matrix.os }} / Python ${{ matrix.python-version }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - - {os: ubuntu-24.04, python-version: '3.9'} - - {os: ubuntu-24.04, python-version: '3.10'} - - {os: ubuntu-24.04, python-version: '3.11'} - - {os: ubuntu-24.04, python-version: '3.12'} - - {os: ubuntu-24.04, python-version: '3.13'} - - {os: ubuntu-24.04, python-version: '3.14'} - - {os: macos-14, python-version: '3.10'} - - {os: macos-14, python-version: '3.12'} - - {os: macos-14, python-version: '3.14'} - - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v6 - with: - python-version: ${{ matrix.python-version }} - cache: pip - cache-dependency-path: pyproject.toml - - - name: Install project and test dependencies - run: | - python -m pip install --upgrade pip - python -m pip install ".[test]" - - - name: Run tests from outside the source tree - working-directory: ${{ runner.temp }} - run: >- - python -m pytest -n auto --dist loadgroup - --pyargs sympde -ra - - coverage: - name: Coverage / Python 3.14 - runs-on: ubuntu-24.04 - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: '3.14' - cache: pip - cache-dependency-path: pyproject.toml - - - name: Install project and test dependencies - run: | - python -m pip install --upgrade pip - python -m pip install ".[test]" - - - name: Run tests with coverage - working-directory: ${{ runner.temp }} - run: >- - python -m pytest -n auto --dist loadgroup - --cov sympde --cov-report term-missing --cov-report xml - --pyargs sympde -ra - - - name: Upload coverage report - uses: actions/upload-artifact@v4 - with: - name: coverage-report - path: ${{ runner.temp }}/coverage.xml diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml new file mode 100644 index 00000000..f485da49 --- /dev/null +++ b/.github/workflows/testing.yml @@ -0,0 +1,95 @@ +# This workflow installs SymPDE and runs its tests with supported Python versions. +# It follows the testing layout used by Psydac while omitting Psydac-specific +# MPI, HDF5, PETSc, and example jobs. + +name: Unit tests + +on: + push: + branches: [ master ] + paths: + - 'sympde/**' + - 'pyproject.toml' + - '.github/workflows/testing.yml' + + pull_request: + branches: [ master ] + types: + - opened + - reopened + - synchronize + - ready_for_review + + workflow_dispatch: + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-24.04, macos-14 ] + python-version: [ '3.9', '3.10', '3.11', '3.12', '3.13', '3.14' ] + isMerge: + - ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + exclude: + - { isMerge: false, python-version: '3.9', os: macos-14 } + - { isMerge: false, python-version: '3.10', os: macos-14 } + - { isMerge: false, python-version: '3.11', os: ubuntu-24.04 } + - { isMerge: false, python-version: '3.12', os: macos-14 } + - { isMerge: false, python-version: '3.13', os: ubuntu-24.04 } + - { isMerge: false, python-version: '3.14', os: macos-14 } + + name: ${{ matrix.os }} / Python ${{ matrix.python-version }} + + steps: + - uses: actions/checkout@v6 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + cache-dependency-path: | + pyproject.toml + + - name: Upgrade pip, setuptools, and wheel + run: | + pip install --upgrade pip setuptools wheel + + - name: Install project + run: | + pip install .[test] + pip freeze + + - name: Initialize test directory + run: | + mkdir scratch + + - name: Run coverage tests on macOS + if: matrix.os == 'macos-14' + working-directory: ./scratch + run: >- + pytest -n auto --dist loadgroup + --cov sympde --cov-report term-missing --cov-report xml + --pyargs sympde -ra + + - name: Run tests on Ubuntu + if: matrix.os == 'ubuntu-24.04' + working-directory: ./scratch + run: >- + pytest -n auto --dist loadgroup + --pyargs sympde -ra + + - name: Upload coverage report + if: matrix.os == 'macos-14' + uses: actions/upload-artifact@v4 + with: + name: coverage-report-python-${{ matrix.python-version }} + path: scratch/coverage.xml + + - name: Print detailed coverage results on macOS + if: matrix.os == 'macos-14' + working-directory: ./scratch + run: | + coverage report --ignore-errors --show-missing --sort=cover diff --git a/README.rst b/README.rst index afa1bde7..2312b200 100644 --- a/README.rst +++ b/README.rst @@ -107,9 +107,9 @@ Do not forget the comma at the end of the line, as this is an item in a list. Also, pay attention to the words ``head`` and ``tags`` in the path: the former is used for Git branches, the latter is used for Git tags (which may or may not correspond to GitHub releases). -.. |CI status| image:: https://github.com/pyccel/sympde/actions/workflows/continuous-integration.yml/badge.svg?branch=master&event=push +.. |CI status| image:: https://github.com/pyccel/sympde/actions/workflows/testing.yml/badge.svg?branch=master&event=push :alt: CI status - :target: https://github.com/pyccel/sympde/actions/workflows/continuous-integration.yml + :target: https://github.com/pyccel/sympde/actions/workflows/testing.yml .. |docs| image:: https://readthedocs.org/projects/sympde/badge/?version=latest :alt: Documentation Status From 8f666146cd54fbfada94f584cb6c6616412bd48e Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Tue, 29 Sep 2026 20:38:49 +0200 Subject: [PATCH 05/17] Update README.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yaman Güçlü --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2312b200..a1dbdfdc 100644 --- a/README.rst +++ b/README.rst @@ -58,7 +58,7 @@ To check out a specific branch/tag/commit named ````, just use ``git checko To install the source files in the virtual environment just run:: - python3 -m pip install . + pip install . Further changes to the cloned directory are not reflected in the installed package. This is why we call it a **static** installation. From f94e244f893bb055901f95dea5c61e409f3a3d30 Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Tue, 29 Sep 2026 20:39:06 +0200 Subject: [PATCH 06/17] Update README.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yaman Güçlü --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index a1dbdfdc..dfd7ea52 100644 --- a/README.rst +++ b/README.rst @@ -73,7 +73,7 @@ Running the tests The complete test suite can be run from any directory with:: - python3 -m pytest -n auto --dist loadgroup --pyargs sympde -ra + pytest -n auto --dist loadgroup --pyargs sympde -ra The documentation dependencies are installed separately and the HTML pages are built with warnings treated as errors:: From 6927706bb16914f92b4489bf7c6e84ee7d5e45aa Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Tue, 29 Sep 2026 20:39:21 +0200 Subject: [PATCH 07/17] Update README.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yaman Güçlü --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index dfd7ea52..f0972fa3 100644 --- a/README.rst +++ b/README.rst @@ -66,7 +66,7 @@ To check out a specific branch/tag/commit named ````, just use ``git checko In order to make changes to the library, and see these changes when the package is imported, SymPDE should be installed in **editable** mode:: - python3 -m pip install --editable ".[test]" + pip install --editable ".[test]" Running the tests ^^^^^^^^^^^^^^^^^ From 0d40ac6548daf26a84b91b886a7a72ab2c85a462 Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Tue, 29 Sep 2026 20:40:38 +0200 Subject: [PATCH 08/17] Update .github/workflows/testing.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yaman Güçlü --- .github/workflows/testing.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index f485da49..6ff2d056 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -30,15 +30,6 @@ jobs: matrix: os: [ ubuntu-24.04, macos-14 ] python-version: [ '3.9', '3.10', '3.11', '3.12', '3.13', '3.14' ] - isMerge: - - ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - exclude: - - { isMerge: false, python-version: '3.9', os: macos-14 } - - { isMerge: false, python-version: '3.10', os: macos-14 } - - { isMerge: false, python-version: '3.11', os: ubuntu-24.04 } - - { isMerge: false, python-version: '3.12', os: macos-14 } - - { isMerge: false, python-version: '3.13', os: ubuntu-24.04 } - - { isMerge: false, python-version: '3.14', os: macos-14 } name: ${{ matrix.os }} / Python ${{ matrix.python-version }} From 9da2d3af7ed80e381dfbc0319bc7fc08f3fa80bd Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Tue, 29 Sep 2026 20:46:34 +0200 Subject: [PATCH 09/17] change CI os to latest --- .github/workflows/testing.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 6ff2d056..61fb8c34 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -28,7 +28,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-24.04, macos-14 ] + os: [ ubuntu-latest, macos-latest ] python-version: [ '3.9', '3.10', '3.11', '3.12', '3.13', '3.14' ] name: ${{ matrix.os }} / Python ${{ matrix.python-version }} @@ -58,7 +58,7 @@ jobs: mkdir scratch - name: Run coverage tests on macOS - if: matrix.os == 'macos-14' + if: runner.os == 'macOS' working-directory: ./scratch run: >- pytest -n auto --dist loadgroup @@ -66,21 +66,21 @@ jobs: --pyargs sympde -ra - name: Run tests on Ubuntu - if: matrix.os == 'ubuntu-24.04' + if: runner.os == 'Linux' working-directory: ./scratch run: >- pytest -n auto --dist loadgroup --pyargs sympde -ra - name: Upload coverage report - if: matrix.os == 'macos-14' + if: runner.os == 'macOS' uses: actions/upload-artifact@v4 with: - name: coverage-report-python-${{ matrix.python-version }} + name: coverage-report-${{ matrix.os }}-python-${{ matrix.python-version }} path: scratch/coverage.xml - name: Print detailed coverage results on macOS - if: matrix.os == 'macos-14' + if: runner.os == 'macOS' working-directory: ./scratch run: | coverage report --ignore-errors --show-missing --sort=cover From 6a3b418a79651e4fdbcae47c806a7c6b02bd3c15 Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Tue, 29 Sep 2026 20:50:18 +0200 Subject: [PATCH 10/17] Defer documentation setup to update_docs --- README.rst | 9 +-------- pyproject.toml | 5 ----- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/README.rst b/README.rst index f0972fa3..f09cfe63 100644 --- a/README.rst +++ b/README.rst @@ -75,13 +75,6 @@ The complete test suite can be run from any directory with:: pytest -n auto --dist loadgroup --pyargs sympde -ra -The documentation dependencies are installed separately and the HTML pages -are built with warnings treated as errors:: - - python3 -m pip install --editable ".[docs]" - python3 -m sphinx -W --keep-going -b html doc doc/_build/html - - For developers ************** @@ -113,7 +106,7 @@ Also, pay attention to the words ``head`` and ``tags`` in the path: the former i .. |docs| image:: https://readthedocs.org/projects/sympde/badge/?version=latest :alt: Documentation Status - :target: https://sympde.readthedocs.io/en/latest/?badge=latest + :target: http://sympde.readthedocs.io/en/latest/?badge=latest .. |binder| image:: https://mybinder.org/badge_logo.svg :alt: Run notebooks in Binder diff --git a/pyproject.toml b/pyproject.toml index 37fc4b6f..7f3269d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,13 +37,8 @@ test = [ "pytest-cov >= 5", "pytest-xdist >= 3", ] -docs = [ - "sphinx >= 7", - "sphinxcontrib-bibtex >= 2.6", -] [project.urls] -Documentation = "https://sympde.readthedocs.io/" Issues = "https://github.com/pyccel/sympde/issues" Repository = "https://github.com/pyccel/sympde" From afd2464407522e59cbc6b816260fee63e76a3e5a Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Wed, 30 Sep 2026 12:41:11 +0200 Subject: [PATCH 11/17] restore old/ and move TODO.rst into it# --- old/TODO.rst | 27 + old/form.py | 2210 ++++++++++++++++++++++++++++++++++++++ old/test_calculus.py.old | 161 +++ old/test_expr_1d.py.old | 429 ++++++++ old/test_expr_2d.py | 471 ++++++++ old/test_expr_3d.py.old | 589 ++++++++++ old/test_form_2d.py | 1487 +++++++++++++++++++++++++ old/test_form_3d.py | 110 ++ old/test_tensorize_2d.py | 136 +++ 9 files changed, 5620 insertions(+) create mode 100644 old/TODO.rst create mode 100644 old/form.py create mode 100644 old/test_calculus.py.old create mode 100644 old/test_expr_1d.py.old create mode 100644 old/test_expr_2d.py create mode 100644 old/test_expr_3d.py.old create mode 100644 old/test_form_2d.py create mode 100644 old/test_form_3d.py create mode 100644 old/test_tensorize_2d.py diff --git a/old/TODO.rst b/old/TODO.rst new file mode 100644 index 00000000..1f4b09f4 --- /dev/null +++ b/old/TODO.rst @@ -0,0 +1,27 @@ +- add BasicDerivable class for all sympde objects that can be differentiate with respect to the coordinates + +- add a coordinates system + +- remove Unknown and VectorUnknown + +Linearity +********* + +- must check that BilinearForm and LinearForm are really linear, by calling them and then applying atomize + +- this verification must be done at the __new__ as long as the flag check_linearity is True. The later is an argument of the __new__ method for BilinearForm and LinearForm + + +Weak formulation +**************** + +- add the concept of weak formulation + +- a weak formulation does not need to be linear/bilinear. + +- add linearize function that returns either LinearForm or BilinearForm + +Kron +**** + +the kronecker features must be upgraded as well as the tensorize function diff --git a/old/form.py b/old/form.py new file mode 100644 index 00000000..f2ac7cd4 --- /dev/null +++ b/old/form.py @@ -0,0 +1,2210 @@ +# coding: utf-8 + +# TODO - transpose of BilinearForm +# - add unknown status if only one space is given to the BilinearForm +# => can not be evaluated except if it is called on a couple test/trial +# - check that a BilinearForm is bilinear (using Constant) +# - check that a LinearForm is linear +# - add is_symmetric property for BilinearForm + +from itertools import groupby + +from sympy.core import Basic +from sympy.core import Symbol +from sympy.core import Function +from sympy.simplify.simplify import simplify +from sympy import collect +from sympy.series.order import Order +from sympy.core import Expr, Add, Mul, Pow +from sympy import S +from sympy.core.containers import Tuple +from sympy import Indexed, IndexedBase, Matrix, ImmutableDenseMatrix +from sympy import expand +from sympy import Integer, Float +from sympy.core.expr import AtomicExpr +from sympy.physics.quantum import TensorProduct +from sympy.series.series import series + +from sympde.core.basic import _coeffs_registery +from sympde.core.basic import CalculusFunction +from sympde.core.basic import Constant +from sympde.core.algebra import (Dot_1d, + Dot_2d, Inner_2d, Cross_2d, + Dot_3d, Inner_3d, Cross_3d) +from sympde.core.utils import random_string + +from sympde.calculus import Dot, Inner, Cross +from sympde.calculus import Grad, Rot, Curl, Div +from sympde.calculus import Bracket +from sympde.calculus import Laplace +from sympde.calculus.core import _generic_ops + +from sympde.topology import BasicDomain, Domain, MappedDomain, Union, Interval +from sympde.topology import BoundaryVector, NormalVector, TangentVector, Boundary +from sympde.topology.derivatives import _partial_derivatives +from sympde.topology.derivatives import partial_derivative_as_symbol +from sympde.topology.derivatives import sort_partial_derivatives +from sympde.topology.derivatives import get_atom_derivatives +from sympde.topology.derivatives import dx, dy, dz +from sympde.topology.derivatives import (Grad_1d, Div_1d, + Grad_2d, Curl_2d, Rot_2d, Div_2d, + Grad_3d, Curl_3d, Div_3d) +from sympde.topology.derivatives import Bracket_2d +from sympde.topology.derivatives import Laplace_1d, Laplace_2d, Laplace_3d +from sympde.topology.derivatives import Hessian_1d, Hessian_2d, Hessian_3d +from sympde.topology.space import FunctionSpace +from sympde.topology.space import ProductSpace +from sympde.topology.space import TestFunction +from sympde.topology.space import VectorTestFunction +from sympde.topology.space import IndexedTestTrial +from sympde.topology.space import Unknown, VectorUnknown +from sympde.topology.space import Trace +from sympde.topology.space import Field, VectorField, IndexedVectorField +from sympde.topology.measure import CanonicalMeasure +from sympde.topology.measure import CartesianMeasure +from sympde.topology.measure import Measure + +from .errors import UnconsistentError +from .errors import UnconsistentLinearExpressionError + + +#============================================================================== +def _initialize_measure(measure, coordinates): + if not( measure is None ): + return measure + + if not( coordinates is None ): + return Measure(coordinates) + + else: + raise NotImplementedError('') + +#============================================================================== +def _initialize_boundary(expr): + + traces = expr.atoms(Trace) + boundaries = [trace.boundary for trace in traces] + boundaries = list(set(boundaries)) # remove redanduncy + + boundary = None + if len(boundaries) == 0: + boundary = None + + elif len(boundaries) == 1: + boundary = boundaries[0] + + elif (len(boundaries) > 1): + if not is_sum_of_form_calls(expr): + msg = '> BilinearForm can not be defined on different boundaries' + raise UnconsistentError(msg) + + boundary = Union(*boundaries) + + # ... + if isinstance(boundary, Boundary): + # ... + if isinstance(expr, Add) and not is_sum_of_form_calls(expr): + args = expr.args + args = [a for a in args if not a.atoms(Trace)] + if args: + msg = '> Only boundary terms, using traces, are allowed' + raise UnconsistentError(msg) + # ... + # ... + + return boundary + + +#============================================================================== +class BasicForm(Expr): + _name = None + _boundary = None + + # TODO use .atoms + @property + def fields(self): + ls = [a for a in self.expr.free_symbols if isinstance(a, (Field, VectorField))] + # no redanduncy + return sorted(list(set(ls))) + + # TODO use .atoms + @property + def constants(self): + ls = [a for a in self.expr.free_symbols if isinstance(a, Constant)] + # no redanduncy + return list(set(ls)) + + @property + def domain(self): + return self._domain + + @property + def boundary(self): + return self._boundary + + @property + def measure(self): + return self._measure + + @property + def mapping(self): + return self._mapping + + @property + def name(self): + return self._name + + +#============================================================================== +# TODO we should check that the only free symbols are fields, constants or coordinates +class Integral(BasicForm): + """ + + Examples + + """ + _ldim = None + _coordinates = None + def __new__(cls, expr, domain, measure=None, name=None): + # ... treat union of domains + # TODO improve + unions = expr.atoms(Union) + if unions: + if not( len(unions) == 1 ): + raise NotImplementedError('only one union is available for the moment') + + domains = [] + for i in list(unions): + domains += list(i._args) + domains = set(domains) + if len(domains) > 1: + forms = [] + for domain in domains: + i = list(unions)[0] + _expr = expr.replace(i, domain) + form = Integral(_expr, domain, measure=measure, + name=None) + + forms.append(form) + + expr = Add(*forms) + # ... + + + if not isinstance(domain, BasicDomain): + raise TypeError('> Expecting a BasicDomain object for domain') + + # ... check that there are no test functions in the expression + ls = [a for a in expr.free_symbols if isinstance(a, (TestFunction, VectorTestFunction))] + if not(len(ls) == 0): + raise TypeError('Cannot use test functions in Integral') + # ... + + # ... + coordinates = domain.coordinates + ldim = domain.dim + # ... + + # compute dim from fields if available + ls = list(expr.atoms((Field, VectorField))) + if ls: + F = ls[0] + space = F.space + + else: + tag = random_string( 3 ) + space_name = 'space_{}'.format(tag) + space = FunctionSpace(space_name, domain) + # TODO vector case + + # check if we are using a mapping + mapping = None + if isinstance( domain, MappedDomain ): + mapping = domain.mapping + + measure = _initialize_measure(measure, coordinates) + + # get boundary terms + boundary = _initialize_boundary(expr) + + obj = Basic.__new__(cls, expr) + obj._ldim = ldim + obj._coordinates = coordinates + obj._boundary = boundary + obj._domain = domain + obj._measure = measure + obj._mapping = mapping + obj._space = space + obj._name = name + + return obj + + @property + def expr(self): + return self._args[0] + + @property + def ldim(self): + return self._ldim + + @property + def space(self): + return self._space + + @property + def coordinates(self): + return self._coordinates + + def _sympystr(self, printer): + sstr = printer.doprint + expr = self.expr + return sstr(expr) + + # TODO how to implement this? + def __call__(self, *args): + raise NotImplementedError('') + + +#============================================================================== +class LinearForm(BasicForm): + """ + + Examples + + """ + def __new__(cls, arguments, expr, measure=None, name=None, check=False): + # ... treat union of domains + # TODO improve + unions = expr.atoms(Union) + if unions: + if not( len(unions) == 1 ): + raise NotImplementedError('only one union is available for the moment') + + domains = [] + for i in list(unions): + domains += list(i._args) + domains = set(domains) + if len(domains) > 1: + forms = [] + for domain in domains: + i = list(unions)[0] + _expr = expr.replace(i, domain) + _name = None + if not( name is None ): + _name = '{name}_{domain}'.format(name=name, domain=domain.name) + + form = LinearForm(arguments, _expr, measure=measure, + name=_name) + + forms.append(form(arguments)) + + expr = Add(*forms) + # ... + + # ... + calls = list(expr.atoms(FormCall)) + if check and not calls: + if not is_linear_form(expr, arguments): + msg = '> Expression is not linear' + raise UnconsistentLinearExpressionError(msg) + # ... + + args = _sanitize_form_arguments(arguments, expr, is_linear=True) + obj = Basic.__new__(cls, args, expr) + + # TODO must check that all domains are the same + domain = obj.test_spaces[0].domain + + # check if we are using a mapping + mapping = None + if isinstance( domain, MappedDomain ): + mapping = domain.mapping + + measure = _initialize_measure(measure, obj.coordinates) + + # get boundary terms + boundary = _initialize_boundary(expr) + + obj._domain = domain + obj._boundary = boundary + obj._measure = measure + obj._mapping = mapping + obj._name = name + + return obj + + @property + def variables(self): + return self._args[0] + + @property + def expr(self): + return self._args[1] + + @property + def test_functions(self): + return self.variables + + @property + def ldim(self): + return self.test_spaces[0].ldim + + @property + def coordinates(self): + return self.test_spaces[0].coordinates + + @property + def test_spaces(self): + return [u.space for u in self.test_functions] + + def _sympystr(self, printer): + sstr = printer.doprint + expr = self.expr + return sstr(expr) + + def __call__(self, *args): + args = Tuple(*args) + + if isinstance(self.expr, FormCall): + call = self.expr + return FormCall(call.expr, args) + + return FormCall(self, args) + + def _eval_nseries(self, x, n, logx): + return self.expr._eval_nseries(x, n, logx) + +#============================================================================== +class BilinearForm(BasicForm): + """ + + Examples + + """ + + def __new__(cls, arguments, expr, measure=None, name=None, check=False): + # ... treat union of domains + # TODO improve + unions = expr.atoms(Union) + if unions: + if not( len(unions) == 1 ): + raise NotImplementedError('only one union is available for the moment') + + domains = [] + for i in list(unions): + domains += list(i._args) + domains = set(domains) + if len(domains) > 1: + forms = [] + for domain in domains: + i = list(unions)[0] + _expr = expr.replace(i, domain) + form = BilinearForm(arguments, _expr, measure=measure, + name=None) + + forms.append(form(*arguments)) + + expr = Add(*forms) + # ... + + # ... + if not isinstance(arguments, (tuple, list, Tuple)): + raise TypeError('(test, trial) must be a tuple, list or Tuple') + + if not(len(arguments) == 2): + raise ValueError('Expecting a couple (test, trial)') + # ... + + # ... + calls = list(expr.atoms(FormCall)) + if check and not calls: + if not is_bilinear_form(expr, arguments): + msg = '> Expression is not bilinear' + raise UnconsistentLinearExpressionError(msg) + # ... + + args = _sanitize_form_arguments(arguments, expr, is_bilinear=True) + obj = Basic.__new__(cls, args, expr) + + # TODO must check that all domains are the same + domain = obj.test_spaces[0].domain + + # check if we are using a mapping + mapping = None + if isinstance( domain, MappedDomain ): + mapping = domain.mapping + + measure = _initialize_measure(measure, obj.coordinates) + + # get boundary terms + boundary = _initialize_boundary(expr) + + obj._domain = domain + obj._boundary = boundary + obj._measure = measure + obj._mapping = mapping + obj._name = name + + return obj + + @property + def variables(self): + return self._args[0] + + @property + def expr(self): + return self._args[1] + + @property + def test_functions(self): + return self.variables[0] + + @property + def trial_functions(self): + return self.variables[1] + + @property + def ldim(self): + return self.test_spaces[0].ldim + + @property + def coordinates(self): + return self.test_spaces[0].coordinates + + @property + def test_spaces(self): + return [u.space for u in self.test_functions] + + @property + def trial_spaces(self): + return [u.space for u in self.trial_functions] + + def _sympystr(self, printer): + sstr = printer.doprint + expr = self.expr + return sstr(expr) + + def __call__(self, *args): + if not(len(args) == 2): + raise ValueError('Expecting a couple (test, trial)') + + # ... + expr = self + if isinstance(self.expr, FormCall): + expr = self.expr.expr + # ... + + are_dummy = lambda xs: [isinstance(i, (TestFunction, VectorTestFunction)) + for i in xs] + + # ... + test_functions = args[0] + if not isinstance(test_functions, (tuple, list, Tuple)): + test_functions = [test_functions] + test_functions = Tuple(*test_functions) + # ... + + # ... + trial_functions = args[1] + if not isinstance(trial_functions, (tuple, list, Tuple)): + trial_functions = [trial_functions] + trial_functions = Tuple(*trial_functions) + # ... + + # ... + if not all(are_dummy(test_functions)) and not all(are_dummy(trial_functions)): + # This should return an Integral + raise NotImplementedError('') + + else: + free_variables = None + target = None + if not any(are_dummy(test_functions)): + assert(all(are_dummy(trial_functions))) + + args = trial_functions + free_variables = test_functions + target = 'test' + + elif not any(are_dummy(trial_functions)): + assert(all(are_dummy(test_functions))) + + args = test_functions + free_variables = trial_functions + target = 'trial' + + if not( free_variables is None ): + if target == 'test': + target = expr.variables[0] + + elif target == 'trial': + target = expr.variables[1] + + expr = expr.expr + + for old, new in zip(target, free_variables): + expr = expr.subs(old, new) + + expr = LinearForm(args, expr, check=False) + # ... + + return FormCall(expr, args) + + +#============================================================================== +class Norm(Integral): + def __new__(cls, expr, domain, kind='l2', measure=None, + name=None): + # ... + tests = expr.atoms((TestFunction, VectorTestFunction)) + if tests: + msg = '> Expecting an Expression without test functions' + raise UnconsistentArgumentsError(msg) + + if not isinstance(expr, (Expr, Matrix, ImmutableDenseMatrix)): + msg = '> Expecting Expr, Matrix, ImmutableDenseMatrix' + raise UnconsistentArgumentsError(msg) + + # ... + + # ... + if not(kind in ['l2', 'h1']): + raise ValueError('> Only L2, H1 norms are available') + # ... + + # ... + if name is None: + name = random_string( 3 ) + + name = '{kind}norm_{name}'.format(kind=kind, name=name) + # ... + + # ... + is_vector = isinstance(expr, (Matrix, Tuple, list, tuple)) + if is_vector: + expr = Matrix(expr) + # ... + + # ... + exponent = None + if kind == 'l2': + exponent = 2 + + if not is_vector: + expr = expr*expr + + else: + if not( expr.shape[1] == 1 ): + raise ValueError('Wrong expression for Matrix. must be a row') + + v = Tuple(*expr[:,0]) + expr = Dot(v, v) + + elif kind == 'h1': + exponent = 2 + + if not is_vector: + expr = Dot(Grad(expr), Grad(expr)) + + else: + if not( expr.shape[1] == 1 ): + raise ValueError('Wrong expression for Matrix. must be a row') + + v = Tuple(*expr[:,0]) + expr = Inner(Grad(v), Grad(v)) + # ... + + obj = Integral.__new__(cls, expr, domain, measure=name, name=name) + + obj._exponent = exponent + + return obj + + @property + def exponent(self): + return self._exponent + + +#============================================================================== +class BilinearAtomicForm(BilinearForm, AtomicExpr): + """ + + Examples + + """ + + def _sympystr(self, printer): + sstr = printer.doprint + name = sstr(self.name) + + test = [sstr(i) for i in self.test_functions] + test = ','.join(i for i in test) + + trial = [sstr(i) for i in self.trial_functions] + trial = ','.join(i for i in trial) + + return '{name}({test},{trial})'.format(name=name, trial=trial, test=test) + +#============================================================================== +class Mass(BilinearAtomicForm): + """ + + Examples + + """ + def __new__(cls, test, trial): + + test_trial = [test, trial] + expr = test * trial + + return BilinearForm.__new__(cls, test_trial, expr, name='Mass') + +#============================================================================== +class Stiffness(BilinearAtomicForm): + """ + + Examples + + """ + def __new__(cls, test, trial): + + test_trial = [test, trial] + + coordl = test.space.coordinates.name + coordr = trial.space.coordinates.name + if not(coordl == coordr): + raise ValueError('> Incompatible coordinates') + + ops = {'x': dx, 'y': dy, 'z': dz} + d = ops[coordl] + + expr = d(test) * d(trial) + + return BilinearForm.__new__(cls, test_trial, expr, name='Stiffness') + +#============================================================================== +class Advection(BilinearAtomicForm): + """ + + Examples + + """ + def __new__(cls, test, trial): + + test_trial = [test, trial] + + coordl = test.space.coordinates.name + coordr = trial.space.coordinates.name + if not(coordl == coordr): + raise ValueError('> Incompatible coordinates') + + ops = {'x': dx, 'y': dy, 'z': dz} + d = ops[coordl] + + expr = test * d(trial) + + return BilinearForm.__new__(cls, test_trial, expr, name='Advection') + +#============================================================================== +class AdvectionT(BilinearAtomicForm): + """ + + Examples + + """ + def __new__(cls, test, trial): + + test_trial = [test, trial] + + coordl = test.space.coordinates.name + coordr = trial.space.coordinates.name + if not(coordl == coordr): + raise ValueError('> Incompatible coordinates') + + ops = {'x': dx, 'y': dy, 'z': dz} + d = ops[coordl] + + expr = d(test) * trial + + return BilinearForm.__new__(cls, test_trial, expr, name='AdvectionT') + +#============================================================================== +class Bilaplacian(BilinearAtomicForm): + """ + + Examples + + """ + def __new__(cls, test, trial): + + test_trial = [test, trial] + + coordl = test.space.coordinates.name + coordr = trial.space.coordinates.name + if not(coordl == coordr): + raise ValueError('> Incompatible coordinates') + + ops = {'x': dx, 'y': dy, 'z': dz} + d = ops[coordl] + + expr = d(d(test)) * d(d(trial)) + + return BilinearForm.__new__(cls, test_trial, expr, name='Bilaplacian') + + +#============================================================================== +class Kron(BilinearAtomicForm): + + """.""" + + def __new__(cls, ls): + + ln = len(ls) + dim = len(ls[0]) + obj = Basic.__new__(cls, ls) + if dim >= 3: + raise NotImplementedError('TODO') + + args1 = ['A%s'%i for i in range(ln)] + args2 = ['B%s'%i for i in range(ln)] + try: + import importlib + package = importlib.import_module("sympde.codegen.templates.kron") + except: + raise ImportError('could not import kron_dot') + name = 'kron_dot_2d' + template = getattr(package,name) + body = [template['body'].format(MAT1=args1[i],MAT2=args2[i]) for i in range(ln)] + body = '\n'.join(i for i in body) + args = ','.join(arg for arg in args1+args2) + function = template['function'].format(___MAT_ARGS___=args,__BODY__=body) + args_types = ','.join('double[:,:]' for i in range(2*ln)) + header = template['header'].format(__ARGS_TYPES__=args_types) + dot = compile(function,'','single') + dic = {} + eval(dot,dic) + _dot = dic[name] + setattr(obj, '_dot',_dot) + return obj + + @property + def args(self): + return self._args[0] + + def dot(self, x): + space = x.space + args = list(zip(*self.args)) + args1 = args[0] + args2 = args[1] + args1 = [arg._data for arg in args1] + args2 = [arg._data for arg in args2] + #args1 = [arg._data.T for arg in args1] + #args2 = [arg._data.T for arg in args2] + starts = space.starts + ends = space.ends + pads = space.pads + + from spl.linalg.stencil import StencilVector + Y = StencilVector(space) + X_tmp = StencilVector(space) + #self._dot(starts,ends,pads,x._data.T,Y._data.T,X_tmp._data.T,*args1,*args2) + args = list(args1) + list(args2) + self._dot(starts,ends,pads,x._data,Y._data,X_tmp._data,*args) + return Y + + + def __str__(self): + return 'Kron' + + def _sympystr(self, printer): + return 'Kron' + + +#============================================================================== +class FormCall(AtomicExpr): + + is_commutative = False + + def __new__(cls, expr, args): + + # ... + if not isinstance(args, (list, tuple, Tuple)): + args = [args] + # ... + + # ... + name = expr.name + if isinstance( expr, BilinearForm ): + expr = subs_form(expr, args) + + if not isinstance(expr, BilinearForm): + expr = BilinearForm(args, expr, name=name, check=False) + + elif isinstance( expr, LinearForm ): + expr = subs_form(expr, args) + + if not isinstance(expr, LinearForm): + expr = LinearForm(args, expr, name=name, check=False) + + else: + raise TypeError('> Expecting BilinearForm, LinearForm') + # ... + + # ... + args = Tuple(*args) + obj = Basic.__new__(cls, expr, args) + # ... + + return obj + + @property + def expr(self): + return self._args[0] + + @property + def arguments(self): + return self._args[1] + + +def is_mul_of_form_call(expr): + if not isinstance(expr, Mul): + return False + + are_calls = [isinstance(i, FormCall) for i in expr.args] + any_are_calls = any(are_calls) + if not any_are_calls: + return False + + if (isinstance(any_are_calls, (list, tuple, Tuple)) and + (len(any_are_calls) > 1)): + raise TypeError('> Cannot multiply calls of Bilinear/Linear forms') + + return True + +def is_sum_of_form_calls(expr): + if isinstance(expr, FormCall): return True + if not isinstance(expr, Add): return False + + are_valid = [isinstance(i, FormCall) or is_mul_of_form_call(i) for i in expr.args] + + all_are_valid = all(are_valid) + if any(are_valid) and not(all_are_valid): + raise TypeError('> Invalid expression') + + return all_are_valid + + +def _sanitize_form_arguments(arguments, expr, is_bilinear=False, is_linear=False): + + is_linear = is_linear or (len(expr.atoms(LinearForm)) > 0) + is_bilinear = is_bilinear or (len(expr.atoms(BilinearForm)) > 0) + + # ... + if is_bilinear or is_linear: + + if is_bilinear: + test_functions = arguments[0] + + elif is_linear: + test_functions = arguments + + if isinstance(test_functions, (TestFunction, VectorTestFunction)): + test_functions = [test_functions] + + elif isinstance(test_functions, (tuple, list, Tuple)): + are_valid = [isinstance(i, (TestFunction, VectorTestFunction)) for i in test_functions] + if not all(are_valid): + raise TypeError('> Wrong arguments for test functions') + + else: + msg = 'Wrong type for test function(s). given {}'.format(type(test_functions)) + raise TypeError(msg) + + test_functions = Tuple(*test_functions) + # ... + + # ... + if is_bilinear: + + trial_functions = arguments[1] + if isinstance(trial_functions, (TestFunction, VectorTestFunction)): + trial_functions = [trial_functions] + + elif isinstance(trial_functions, (tuple, list, Tuple)): + are_valid = [isinstance(i, (TestFunction, VectorTestFunction)) for i in trial_functions] + if not all(are_valid): + raise TypeError('> Wrong arguments for trial functions') + + else: + msg = 'Wrong type for trial function(s). given {}'.format(type(trial_functions)) + raise TypeError(msg) + + trial_functions = Tuple(*trial_functions) + # ... + + if is_bilinear: + args = [test_functions, trial_functions] + args = Tuple(*args) + + else: + args = Tuple(*test_functions) + + return args + + +# ... +def atomize(expr, dim=None): + """ + """ + if not isinstance(expr, (Expr, + _partial_derivatives, _generic_ops, + TestFunction, VectorTestFunction, Indexed, + Field, Constant, Symbol, Function, + VectorField, + BoundaryVector, Trace, + Integer, Float, Matrix, ImmutableDenseMatrix, + list, tuple, Tuple)): + msg = ('> Wrong input type.') + + raise TypeError(msg, ', given ', expr, type(expr)) + + # ... replace a FormCall by its expression + calls = expr.atoms(FormCall) + for call in calls: + expr = expr.subs(call, call.expr) + # ... + +# print('> expr [atomize] = ', expr, type(expr)) + + # ... compute dim if None + if dim is None: + ls = [i for i in expr.free_symbols if isinstance(i, (TestFunction, + VectorTestFunction, + Field, + VectorField))] + +# ls = expr.atoms((TestFunction, VectorTestFunction, Field)) +# ls = list(ls) + if ls: + atom = ls[0] + if atom.space is None: + raise ValueError('Expecting atom to be associated to a space') + + dim = atom.space.ldim + # ... + + if isinstance(expr, (list, tuple, Tuple)): + args = [atomize(i, dim=dim) for i in expr] + return Tuple(*args) + + elif isinstance(expr, Add): + args = [atomize(i, dim=dim) for i in expr.args] + return Add(*args) + + elif isinstance(expr, Mul): + coeffs = [i for i in expr.args if isinstance(i, _coeffs_registery)] + vectors = [i for i in expr.args if not(i in coeffs)] + + i = S.One + if coeffs: + i = Mul(*coeffs) + + j = S.One + if vectors: + args = [atomize(i, dim=dim) for i in vectors] + j = Mul(*args) + + return Mul(i, j) + + elif isinstance(expr, Pow): + + b = atomize(expr.base, dim=dim) + e = expr.exp + + return Pow(b, e) + + elif isinstance(expr, BasicForm): + + return atomize(expr.expr, dim=dim) + + elif isinstance(expr, Trace): + # TODO treate different spaces + if expr.order == 0: + return atomize(expr.expr, dim=dim) + + elif expr.order == 1: + # TODO must be passed as key word to atomize + normal_vector_name = 'n' + n = NormalVector(normal_vector_name) + M = atomize(expr.expr, dim=dim) + if dim == 1: + return M + else: + if isinstance(M, (Add, Mul)): + ls = M.atoms(Tuple) + for i in ls: + M = M.subs(i, Matrix(i)) + M = simplify(M) + + e = 0 + for i in range(0, dim): + e += M[i] * n[i] + return e + + else: + raise ValueError('> Only traces of order 0 and 1 are available') + + elif isinstance(expr, _generic_ops): + # if i = Dot(...) then type(i) is Grad + op = type(expr) + new = eval('{0}_{1}d'.format(op, dim)) + + args = [atomize(i, dim=dim) for i in expr.args] + return new(*args) + + elif isinstance(expr, Matrix): + n,m = expr.shape + lines = [] + for i in range(0, n): + line = [] + for j in range(0, m): + line.append(atomize(expr[i,j], dim=dim)) + lines.append(line) + return Matrix(lines) + + return expr +# ... + +# ... +def _evaluate_core(a, verbose=False, variables=None, M=None): + + # ... + if not isinstance(a, (BasicForm, Add, Mul)): + msg = 'Expecting a BasicForm, Add or Mul. Given {}'.format(type(a)) + raise TypeError(msg) + # ... + + # ... + variables = [] + if isinstance(a, (BilinearForm, LinearForm)): + variables = a.variables + + elif isinstance(a, FormCall): + variables = a.variables + # ... + + # ... + def _get_size_and_starts(ls): + n = 0 + d_indices = {} + for x in ls: + d_indices[x] = n + if isinstance(x, TestFunction): + n += 1 + + elif isinstance(x, VectorTestFunction): + for j in range(0, x.shape[0]): + d_indices[x[j]] = n + j + + n += x.shape[0] + + return n, d_indices + # ... + + # ... + tests = [] + trials = [] + # ... + + # ... + if isinstance(a, BilinearForm): + tests = list(a.test_functions) + n_rows, test_indices = _get_size_and_starts(a.test_functions) + + trials = list(a.trial_functions) + n_cols, trial_indices = _get_size_and_starts(a.trial_functions) + + lines = [] + for i in range(0, n_rows): + line = [] + for j in range(0, n_cols): + line.append(0) + lines.append(line) + + M = Matrix(lines) + + elif isinstance(a, LinearForm): + tests = list(a.test_functions) + n_rows, test_indices = _get_size_and_starts(a.test_functions) + + lines = [0 for i in range(0, n_rows)] + M = Matrix(lines) + # ... + + # ... + if isinstance(a, Add): + args = [_evaluate_core(i, verbose=verbose, variables=variables, M=M) + for i in a.args] + + return Add(*args) + + elif isinstance(a, Mul): + # a coeff can be a symbol, otherwise the expression c1 * a + # raises an error + coeffs = [i for i in a.args if isinstance(i, _coeffs_registery) or isinstance(i, Symbol)] + vectors = [i for i in a.args if not(i in coeffs)] + + i = S.One + if coeffs: + i = Mul(*coeffs) + + j = S.One + if vectors: + args = [_evaluate_core(i, verbose=verbose, variables=variables, M=M) + for i in vectors] + j = Mul(*args) + + return Mul(i, j) + # ... + + dim = a.ldim + expr = a.expr + + # convert generic operators to atomic ones + expr = atomize(expr, dim=dim) + + # we need to expand the expression so that we have a sum of product + expr = expand(expr) + + if verbose: + print('> atomized >>> {0}'.format(expr)) + + # ... + def __evaluate_core_LinearForm(expr, M): + # ... + def treat_form(arg, M): + atoms = list(arg.atoms(TestFunction)) + atoms += list(arg.atoms(VectorTestFunction)) + atoms += list(arg.atoms(IndexedTestTrial)) + + for atom in atoms: + if atom in test_indices: + i_row = test_indices[atom] + + else: + raise ValueError('> Could not find {}'.format(atom)) + + M[i_row] += arg + return M + # ... + + # ... + if isinstance(expr, Add): + args = expr.args + for arg in args: + M = treat_form(arg, M) + + elif isinstance(expr, Mul): + M = treat_form(expr, M) + + else: + raise TypeError('> wrong type, given {}'.format(type(expr))) + # ... + + return M + # ... + + # ... + def __evaluate_core_BilinearForm(expr, M): + + # ... + def treat_form(arg, M): + atoms = list(arg.atoms(TestFunction)) + atoms += list(arg.atoms(VectorTestFunction)) + atoms += list(arg.atoms(IndexedTestTrial)) + + for atom in atoms: + if atom in test_indices: + i_row = test_indices[atom] + + elif atom in trial_indices: + i_col = trial_indices[atom] + + else: + raise ValueError('> Could not find {}'.format(atom)) + + M[i_row, i_col] += arg + return M + # ... + + # ... + if isinstance(expr, Add): + args = expr.args + for arg in args: + if isinstance(arg, Mul): + M = treat_form(arg, M) + + elif isinstance(expr, Mul): + M = treat_form(expr, M) + + else: + raise TypeError('> wrong type, given {}'.format(type(expr))) + # ... + + return M + # ... + + # ... + if isinstance(a, BilinearForm): + M = __evaluate_core_BilinearForm(expr, M) + + # returning scalars when possibl + if (n_rows == 1) and (n_cols == 1): + return M[0, 0] + + elif isinstance(a, LinearForm): + M = __evaluate_core_LinearForm(expr, M) + + # returning scalars when possibl + if (n_rows == 1): + return M[0] + + elif isinstance(a, Integral): + return expr + # ... + + return M +# ... + +# ... +def _evaluate_bnd(a, bnd_calls, verbose=False): + if verbose: + print('> bnd calls = ', bnd_calls) + + a_expr = a + if isinstance(a, BasicForm) and is_sum_of_form_calls(a.expr): + # TODO treat Mul node + if isinstance(a.boundary, Union): + if isinstance(a.expr, Add): + newargs = [] + for i in a.expr.args: + + expr = i.expr + if isinstance(expr, BasicForm): + expr = expr.expr + + if is_sum_of_form_calls(expr): + newargs += expr.args + + else: + newargs.append(i) + + a_expr = Add(*newargs) + + elif isinstance(a.expr, Mul): + raise NotImplementedError('') + + else: + a_expr = a.expr + + else: + a_expr = a.expr + + if isinstance(a_expr, FormCall): + a_expr = a_expr.expr.expr + + # ... + boundaries = [] + groups = [] + keyfunc = lambda call: call.expr.boundary + for bnd, g in groupby(bnd_calls, keyfunc): + ls = list(g) + a_bnd = _extract_linear_combination(a_expr, ls) + groups.append(a_bnd) + boundaries.append(bnd) + + if verbose: + print('> groups = ', groups) + print('> boundaries = ', boundaries) + # ... + + + # ... + groups_M = [] + for bnd, ai in zip(boundaries, groups): + a_bnd = ai + for call in ai.atoms(FormCall): + a_bnd = a_bnd.subs(call, call.expr) + + M_bnd = _evaluate_core(a_bnd, verbose=verbose) + + groups_M.append(BoundaryExpression(bnd, M_bnd)) + + if verbose: + print('> groups_M = ', groups_M) + # ... + + return groups_M +# ... + +def _extract_linear_combination(expr, ls): + """returns a new expression for terms that are in ls only.""" + # something like a1 + a2 or a1 + alpha * a2 + if isinstance(expr, Add): + args = [] + for arg in expr.args: + # somthing like alpha*a4 + if isinstance(arg, Mul): + m_args = [i for i in arg.args if i in ls] + if m_args: + args += [arg] + + elif arg in ls: + args += [arg] + + expr = Add(*args) + return expr + +# TODO check that a is a Form, FormCall or linear combination of them +def evaluate(a, verbose=False): + # ... + _calls = a.atoms(FormCall) + calls = [] + for call in _calls: + mycalls = call.expr.atoms(FormCall) + if mycalls: + calls += list(mycalls) + else: + calls += [call] + + # remove redundancy + calls = list(set(calls)) + # ... + + bnd_calls = [] + if calls: + bnd_calls = [a for a in calls if a.expr.boundary] + calls = [a for a in calls if not(a in bnd_calls)] + + if verbose: + print('> calls = ', calls) + + expr_bnd = [] + if bnd_calls: + expr_bnd = _evaluate_bnd(a, bnd_calls, verbose=verbose) + + bnd_done = [i.target for i in expr_bnd] + + expr_domain = [] + if calls: + # TODO - must check that calls have the same domein + # - shall we need to add a groupby here too? + domain = calls[0].expr.domain + + a_expr = a + if (isinstance(a, BasicForm) and is_sum_of_form_calls(a.expr) and + bnd_calls): + a_expr = a.expr + + a = _extract_linear_combination(a_expr, calls) + if verbose: + print('> a = ', a) + + # ... replace a FormCall by its expression + for call in calls: + a = a.subs(call, call.expr) + # ... + + expr = _evaluate_core(a, verbose=verbose) + boundary = list(a.atoms(Boundary)) + if not boundary: + expr_domain = [DomainExpression(domain, expr)] + + else: + boundary = boundary[0] + expr_domain = [BoundaryExpression(boundary, expr)] + + elif isinstance(a, BasicForm): + boundary = list(a.atoms(Boundary)) + + if not boundary: + domain = a.domain + expr = _evaluate_core(a, verbose=verbose) + expr_domain = [DomainExpression(domain, expr)] + + # TODO nitsch case +# else: +# expr_domain = [] +# boundary = [i for i in boundary if not(i in bnd_done)] +# for bnd in boundary: +# expr_domain += [BoundaryExpression(bnd, expr)] + + return expr_bnd + expr_domain + + +#============================================================================== +class KernelExpression(Basic): + def __new__(cls, target, expr): + return Basic.__new__(cls, target, expr) + + @property + def target(self): + return self._args[0] + + @property + def expr(self): + return self._args[1] + +#============================================================================== +class DomainExpression(KernelExpression): + pass + +#============================================================================== +class BoundaryExpression(KernelExpression): + pass + + +#============================================================================== +# TODO - get dim from atoms +# - check coefficinets/functions +def _tensorize_core(expr, dim, tests, trials): + + if isinstance(expr, Add): + args = [_tensorize_core(i, dim, tests, trials) for i in expr.args] + return Add(*args) + + elif isinstance(expr, Mul): + coeffs = [i for i in expr.args if isinstance(i, _coeffs_registery)] + args = [i for i in expr.args if not(i in coeffs)] + + d_atoms = {} + _coordinates = ['x', 'y', 'z'] + _coordinates = [Symbol(i) for i in _coordinates] + test_trial = list(tests) + list(trials) + for a in test_trial: + d_atoms[a] = [] + + new = S.One + for i in range(0, dim): + coord = _coordinates[i] + Di = Interval(coordinate=coord) + Vi = FunctionSpace('V_{}'.format(i), domain=Di) + + ai = TestFunction(Vi, '{test}{i}'.format(test=a.name, i=i)) + d_atoms[a].append(ai) + + new *= ai + expr = expr.subs({a: new}) + + # make sure we have sum of products + expr = expand(expr) + + # ... + # TODO - improve this later + # - must distinguish between test/trial + assert(len(tests) == 1) + assert(len(trials) == 1) + + v = tests[0] + u = trials[0] + + ops = {'x': dx, 'y': dy, 'z': dz} + + for ui,vi in zip(d_atoms[u], d_atoms[v]): + coord = ui.space.coordinates.name + d = ops[coord] + + # ... Mass + old = vi*ui + new = Mass(vi,ui) + + expr = expr.subs({old: new}) + # ... + + # ... Stiffness + old = d(vi)*d(ui) + new = Stiffness(vi,ui) + + expr = expr.subs({old: new}) + # ... + + # ... Advection + old = vi*d(ui) + new = Advection(vi,ui) + + expr = expr.subs({old: new}) + # ... + + # ... Transpose of Advection + old = d(vi)*ui + new = AdvectionT(vi,ui) + + expr = expr.subs({old: new}) + # ... + + # ... Bilaplacian + old = d(d(vi))*d(d(ui)) + new = Bilaplacian(vi,ui) + + expr = expr.subs({old: new}) + # ... + + expr = subs_mul(expr) + # ... + + return expr + +#============================================================================== +def _tensorize_weights(expr): + + if isinstance(expr, Add): + args = [] + for term in expr.args: + #print('> ', term, type(term)) + arg = _tensorize_weights(term) + args.append(arg) + expr = Add(*args) + + elif isinstance(expr, Mul): + args = [] + for term in expr.args: +# print('>> ', term, type(term)) + arg = _tensorize_weights(term) + args.append(arg) + + tensor = [a for a in args if isinstance(a, TensorProduct)] + weights = [a for a in args if not( a in tensor )] + + if tensor: + + tensor = tensor[0] + forms = tensor.args + + coords = [a.coordinates for a in forms] + + # print(forms) + # print(coords) + # print(weights) + + # # ... + # d_args = {} + # for x in coords: + # d_args[x] = [] + # + # for x in coords: + # for a in weights: + # # TODO improve for functions => separability + # ls = a.atoms(Symbol) + # if x in ls: + # print('found ', x, ' in ', a) + # # ... + + expr = Mul(*args) + + elif isinstance(expr, TensorProduct): + args = [] + for term in expr.args: +# print('>>> ', term, type(term)) + arg = _tensorize_weights(term) +# if not( arg is S.One ): +# args.append(arg) + if isinstance(term, BilinearAtomicForm): + coords = term.domain.coordinates + #print(coords) + expr = TensorProduct(*args) + + return expr + +#============================================================================== +def tensorize(a): + + if not isinstance(a, BilinearForm): + raise TypeError('Expecting a BilinearForm') + + # ... + def _get_size_and_starts(ls): + n = 0 + d_indices = {} + for x in ls: + d_indices[x] = n + if isinstance(x, TestFunction): + n += 1 + + elif isinstance(x, VectorTestFunction): + for j in range(0, x.shape[0]): + d_indices[x[j]] = n + j + + n += x.shape[0] + + return n, d_indices + # ... + + if is_sum_of_form_calls(a.expr): + # ... + n_rows, test_indices = _get_size_and_starts(a.test_functions) + n_cols, trial_indices = _get_size_and_starts(a.trial_functions) + + lines = [] + for i in range(0, n_rows): + line = [] + for j in range(0, n_cols): + line.append(0) + lines.append(line) + + M = Matrix(lines) + # ... + + calls = a.atoms(FormCall) + for call in calls: + t = tensorize(call.expr) + + atoms = call.arguments + i_row = None + i_col = None + l_row = 1 + l_col = 1 + for atom in atoms: + if atom in test_indices: + i_row = test_indices[atom] + + if isinstance(atom, VectorTestFunction): + l_row = atom.shape[0] + + elif atom in trial_indices: + i_col = trial_indices[atom] + + if isinstance(atom, VectorTestFunction): + l_col = atom.shape[0] + + else: + raise ValueError('> Could not find {}'.format(atom)) + + if isinstance(t, (Matrix, ImmutableDenseMatrix)): + M_loc = M[i_row:i_row+l_row, i_col:i_col+l_col] + if M_loc.shape == t.shape: + M_loc += t + + # TODO must check if a trial/test is used as test/trial + elif M_loc.shape == t.shape[::-1]: + M_loc += t.transpose() + + else: + raise ValueError('Wrong sizes') + + M[i_row:i_row+l_row, i_col:i_col+l_col] += M_loc + + else: + raise NotImplementedError('TODO') + + return M + + dim = a.ldim + domain = a.domain + tests = a.test_functions + trials = a.trial_functions + + assert(len(a.test_spaces) == 1) + assert(len(a.trial_spaces) == 1) + assert(len(tests) == 1) + assert(len(trials) == 1) + + V = a.test_spaces[0] + U = a.trial_spaces[0] + + # the result of evaluate is a list of KernelExpression + kernels = evaluate(a) + kernels = [i.expr for i in kernels] + + expressions = [] + for kernel in kernels: + if isinstance(kernel, (Matrix, ImmutableDenseMatrix)): + + n_rows, n_cols = kernel.shape + + # ... subs indexed test/trial functions by a new symbol + tmp_tests = [] + tmp_trials = [] + for i_row in range(0, n_rows): + for i_col in range(0, n_cols): + e = kernel[i_row,i_col] + indexed = e.atoms(IndexedTestTrial) + for ui in indexed: + i = ui.indices + if len(i) > 1: + raise ValueError('Expecting one index') + i = i[0] + + space_name = 'VTmp{}'.format(i) + Vi = FunctionSpace(space_name, V.domain) + vi = TestFunction(Vi, '{test}{i}'.format(test=ui.base.name, i=i)) + e = e.subs({ui: vi}) + + if ui.base in tests: + tmp_tests.append(vi) + + elif ui.base in trials: + tmp_trials.append(vi) + + kernel[i_row,i_col] = e + # ... + + tmp_tests += [i for i in tests if not(i in tmp_tests)] + tmp_trials += [i for i in trials if not(i in tmp_trials)] + + # ... + lines = [] + for i_row in range(0, n_rows): + line = [] + for i_col in range(0, n_cols): + e = kernel[i_row,i_col] + + atoms = e.atoms(TestFunction) + _tests = [i for i in atoms if i in tmp_tests] + _trials = [i for i in atoms if i in tmp_trials] + + eij = _tensorize_core(e, dim, _tests, _trials) + + line.append(eij) + + lines.append(line) + + expr = Matrix(lines) + # ... + + else: + expr = _tensorize_core(kernel, dim, tests, trials) + + expressions.append(expr) + # ... + + # TODO + # looking for weighted atomic forms + # this should be done if a flag is True + # and used for LinearOperator Kron +# expr = _tensorize_weights(expr) + + return expr + +#============================================================================== +def subs_mul(expr): + """substitute Mul with TensorProduct""" + + if isinstance(expr,(Add, Mul)): + args = expr.args + args = [subs_mul(arg) for arg in args] + + if isinstance(expr, Mul): + args = expr.args + forms = [i for i in args if isinstance(i, BilinearAtomicForm)] + others = [i for i in args if not( i in forms )] + + t = TensorProduct(*forms) + m = Mul(*others) + return m*t + + elif isinstance(expr, Add): + + return Add(*args) + else: + + return expr + +#============================================================================== +# form here is a BilinearForm +def subs_form(form, newargs): +# print('>>> subs_form : ', form) + + if isinstance( form, BilinearForm ): + calls = form.expr.atoms(FormCall) + if calls: + return subs_form(form.expr, newargs) + + else: + return _subs_bilinear_form_core(form, newargs) + + elif isinstance( form, LinearForm ): + calls = form.expr.atoms(FormCall) + if calls: + return subs_form(form.expr, newargs) + + else: + return _subs_linear_form_core(form, newargs) + + elif isinstance( form, FormCall ): + return form + + elif isinstance( form, Add ): + args = [subs_form(a, newargs) for a in form.args] + return Add(*args) + + elif isinstance( form, Mul ): + coeffs = [i for i in form.args if isinstance(i, _coeffs_registery)] + vectors = [i for i in form.args if not(i in coeffs)] + + i = S.One + if coeffs: + i = Mul(*coeffs) + + j = S.One + if vectors: + args = [subs_form(a, newargs) for a in vectors] + j = Mul(*args) + + return Mul(i, j) + + elif isinstance( form, Pow ): + + b = subs_form(form.base, newargs) + e = form.exp + + return Pow(b, e) + + else: + return form + + +#============================================================================== +def _subs_bilinear_form_core(form, newargs): + # ... + test_trial = _sanitize_form_arguments(newargs, form, is_bilinear=True) + + if not isinstance(test_trial, (tuple, list, Tuple)): + raise TypeError('(test, trial) must be a tuple, list or Tuple') + + if not(len(test_trial) == 2): + raise ValueError('Expecting a couple (test, trial)') + # ... + + # ... + test_functions = test_trial[0] + if isinstance(test_functions, (TestFunction, VectorTestFunction)): + test_functions = [test_functions] + + elif isinstance(test_functions, (tuple, list, Tuple)): + test_functions = Tuple(*test_functions) + # ... + + # ... + trial_functions = test_trial[1] + if isinstance(trial_functions, (TestFunction, VectorTestFunction)): + trial_functions = [trial_functions] + + elif isinstance(trial_functions, (tuple, list, Tuple)): + trial_functions = Tuple(*trial_functions) + # ... + + # in order to avoid problems when swapping indices, we need to create + # temp symbols + + # ... + d_tmp = {} + for x in trial_functions: + name = random_string( 6 ) + if isinstance(x, TestFunction): + X = TestFunction(x.space, name=name) + + elif isinstance(x, VectorTestFunction): + X = VectorTestFunction(x.space, name=name) + + else: + raise TypeError('Only TestFunction and VectorTestFunction are available') + + d_tmp[X] = x + # ... + + expr = form.expr + + # ... replacing trial functions by tmp symbols + for k,v in zip(form.trial_functions, d_tmp): + expr = expr.subs(k,v) + # ... + + # ... replacing test functions + for k,v in zip(form.test_functions, test_functions): + expr = expr.subs(k,v) + # ... + + # ... replacing trial functions from tmp symbols + for k,v in d_tmp.items(): + expr = expr.subs(k,v) + # ... + + # ... + if len(test_functions) == 1: test_functions = test_functions[0] + if len(trial_functions) == 1: trial_functions = trial_functions[0] + + test_trial = (test_functions, trial_functions) + # ... + + return BilinearForm(test_trial, expr, name=form.name, check=False) + + +#============================================================================== +def _subs_linear_form_core(form, newargs): + + # ... + test_functions = _sanitize_form_arguments(newargs, form, is_linear=True) + # TODO is it ok to do this? + test_functions = test_functions[0] + + if isinstance(test_functions, (TestFunction, VectorTestFunction)): + test_functions = [test_functions] + + elif isinstance(test_functions, (tuple, list, Tuple)): + test_functions = list(*test_functions) + # ... + + expr = form.expr + + # ... replacing test functions + for k,v in zip(form.test_functions, test_functions): + expr = expr.subs(k,v) + # ... + + if len(test_functions) == 1: test_functions = test_functions[0] + + return LinearForm(test_functions, expr, name=form.name, check=False) + +#============================================================================== +def is_linear_expression(expr, args, debug=True): + """checks if an expression is linear with respect to the given arguments.""" + # ... + left_args = [] + right_args = [] + for arg in args: + tag = random_string( 4 ) + + if isinstance(arg, TestFunction): + left = TestFunction(arg.space, name='l_' + tag) + right = TestFunction(arg.space, name='r_' + tag) + + elif isinstance(arg, VectorTestFunction): + left = VectorTestFunction(arg.space, name='l_' + tag) + right = VectorTestFunction(arg.space, name='r_' + tag) + + elif isinstance(arg, Field): + left = Field('l_' + tag, space=arg.space) + right = Field('r_' + tag, space=arg.space) + + elif isinstance(arg, VectorField): + left = VectorField(arg.space, 'l_' + tag) + right = VectorField(arg.space, 'r_' + tag) + + else: + raise TypeError('') + + left_args += [left] + right_args += [right] + # ... + + # ... check addition + newexpr = expr + for arg, left, right in zip(args, left_args, right_args): + newarg = left + right + newexpr = newexpr.subs(arg, newarg) + + left_expr = expr + for arg, left in zip(args, left_args): + left_expr = left_expr.subs(arg, left) + + right_expr = expr + for arg, right in zip(args, right_args): + right_expr = right_expr.subs(arg, right) + + if not( expand(newexpr) == expand(left_expr) + expand(right_expr) ): + # TODO use a warning or exception? + if debug: + print('Failed to assert addition property') + +# print('===========') +# print(arg, left, right) +# +# print(expand(newexpr)) +# print(expand(left_expr)) +# print(expand(right_expr)) +# print(expand(newexpr) - expand(left_expr) - expand(right_expr)) +# import sys; sys.exit(0) + + + return False + # ... + + # ... check multiplication + tag = random_string( 4 ) + coeff = Constant('alpha_' + tag) + + newexpr = expr + for arg, left in zip(args, left_args): + newarg = coeff * left + newexpr = newexpr.subs(arg, newarg) + + left_expr = expr + for arg, left in zip(args, left_args): + left_expr = left_expr.subs(arg, left) + + left_expr = coeff * left_expr.subs(arg, left) + + if not( expand(newexpr) == expand(left_expr)): + # TODO use a warning or exception? + if debug: + print('Failed to assert multiplication property') + + return False + # ... + + return True + + +#============================================================================== +def is_bilinear_form(expr, args): + """checks if an expression is bilinear with respect to the given arguments.""" + # ... + test_trial = _sanitize_form_arguments(args, expr, is_bilinear=True) + + if not isinstance(test_trial, (tuple, list, Tuple)): + raise TypeError('(test, trial) must be a tuple, list or Tuple') + + if not(len(test_trial) == 2): + raise ValueError('Expecting a couple (test, trial)') + # ... + + # ... + test_functions = test_trial[0] + if isinstance(test_functions, (TestFunction, VectorTestFunction)): + test_functions = [test_functions] + + elif isinstance(test_functions, (tuple, list, Tuple)): + test_functions = Tuple(*test_functions) + # ... + + # ... + trial_functions = test_trial[1] + if isinstance(trial_functions, (TestFunction, VectorTestFunction)): + trial_functions = [trial_functions] + + elif isinstance(trial_functions, (tuple, list, Tuple)): + trial_functions = Tuple(*trial_functions) + # ... + + # ... + if not is_linear_expression(expr, test_functions): + msg = ' Expression is not linear w.r.t [{}]'.format(test_functions) + raise UnconsistentLinearExpressionError(msg) + # ... + + # ... + if not is_linear_expression(expr, trial_functions): + msg = ' Expression is not linear w.r.t [{}]'.format(trial_functions) + raise UnconsistentLinearExpressionError(msg) + # ... + + return True + +#============================================================================== +def is_linear_form(expr, args): + """checks if an expression is linear with respect to the given arguments.""" + # ... + test_functions = _sanitize_form_arguments(args, expr, is_linear=True) + # TODO is it ok to do this? + test_functions = test_functions[0] + + if isinstance(test_functions, (TestFunction, VectorTestFunction)): + test_functions = [test_functions] + + elif isinstance(test_functions, (tuple, list, Tuple)): + test_functions = list(*test_functions) + # ... + + # ... + if not is_linear_expression(expr, test_functions): + msg = ' Expression is not linear w.r.t [{}]'.format(test_functions) + raise UnconsistentLinearExpressionError(msg) + # ... + + return True + + +#============================================================================== +def linearize(form, fields, trials=None): + """linearize a LinearForm around the fields.""" + # ... + if not isinstance(form, LinearForm): + raise TypeError('> Expecting a LinearForm') + + if not isinstance(fields, (list, tuple, Tuple)): + fields = [fields] + + for f in fields: + if not isinstance(f, (Field, VectorField)): + raise TypeError('{} is not Field/VectorField'.format(f)) + + if not(trials is None): + if not isinstance(trials, (list, tuple, Tuple)): + trials = [trials] + + assert( all([isinstance(i, (str, TestFunction, VectorTestFunction)) for i in trials]) ) + assert( len(fields) == len(trials) ) + + newtrials = [] + for i in trials: + if isinstance(i, (TestFunction, VectorTestFunction)): + newtrials += [i.name] + + else: + newtrials += [i] + + trials = newtrials + # ... + + expr = form.expr + test_functions = form.test_functions + fields = Tuple(*fields) + + # ... replace a FormCall by its expression + calls = expr.atoms(FormCall) + for call in calls: + expr = expr.subs(call, call.expr) + # ... + + # ... + trial_functions = [] + newargs = [] + eps = Constant('eps_' + random_string( 4 )) + for i,x in enumerate(fields): + tag = random_string( 4 ) + + if trials is None: + name = x.name + '_' + tag + else: + name = trials[i] + + if isinstance(x, Field): + trial = TestFunction(x.space, name=name) + + elif isinstance(x, VectorField): + trial = VectorTestFunction(x.space, name=name) + + else: + raise TypeError('Only TestFunction and VectorTestFunction are available') + + newargs += [x + eps*trial] + trial_functions += [trial] + # ... + + # ... + newexpr = expr + for k,v in zip(fields, newargs): + newexpr = newexpr.subs(k,v) + # ... + + newexpr = expand(newexpr) + + e = newexpr.series(eps, 0, 2) + d = collect(e, eps, evaluate=False) + expr = d[eps] + +# print('> linearize = ', expr) +# import sys; sys.exit(0) + + test_trial = (test_functions, trial_functions) + return BilinearForm(test_trial, expr, check=True) diff --git a/old/test_calculus.py.old b/old/test_calculus.py.old new file mode 100644 index 00000000..23770185 --- /dev/null +++ b/old/test_calculus.py.old @@ -0,0 +1,161 @@ +# coding: utf-8 + +import numpy as np + +from sympy.core.containers import Tuple +from sympy import symbols +from sympy import Symbol +from sympy import Lambda + +from sympde.core import (dx, dy, dz) +from sympde.core import LinearOperator +from sympde.core import ScalarField +from sympde.core import grad, dot, inner +from sympde.core import get_index_derivatives + + +# ... +def test_0(): + print('============ test_0 ==============') + + x,y, a = symbols('x y a') + + # ... + expr = x+y + print('> expr := {0}'.format(expr)) + + expr = LinearOperator(expr) + print('> evaluated := {0}'.format(expr)) + print('') + # ... + + # ... + expr = 2*x+y + print('> expr := {0}'.format(expr)) + + expr = LinearOperator(expr) + print('> evaluated := {0}'.format(expr)) + print('') + # ... + + # ... + expr = a*x+y + print('> expr := {0}'.format(expr)) + + expr = LinearOperator(expr) + print('> evaluated := {0}'.format(expr)) + # ... + + # ... + expr = 2*a*x+y + print('> expr := {0}'.format(expr)) + + expr = LinearOperator(expr) + print('> evaluated := {0}'.format(expr)) + # ... +# ... + +# ... +def test_1(): + print('============ test_1 ==============') + + u, v, a = symbols('u v a') + + # ... + expr = u+v + print('> expr := {0}'.format(expr)) + + expr = dx(expr) + print('> evaluated := {0}'.format(expr)) + print('') + # ... + + # ... + expr = 2*u*v + print('> expr := {0}'.format(expr)) + + expr = dx(expr) + print('> evaluated := {0}'.format(expr)) + print('') + # ... + + # ... dx should not operate on u^2, + # since we consider only linearized weak formulations + expr = u*u + print('> expr := {0}'.format(expr)) + + expr = dx(expr) + print('> evaluated := {0}'.format(expr)) + print('') + # ... +# ... + +# ... +def test_2(): + print('============ test_2 ==============') + + u, v = symbols('u v') + F = ScalarField('F') + + # ... + expr = F*v*u + print('> expr := {0}'.format(expr)) + + expr = dx(expr) + print('> evaluated := {0}'.format(expr)) + print('') + # ... +# ... + +# ... +def test_3(): + print('============ test_3 ==============') + + u = symbols('u') + + # ... + expr = dx(u) + d = get_index_derivatives(expr) + assert(d['x'] == 1) + assert(d['y'] == 0) + assert(d['z'] == 0) + # ... + + # ... + expr = dx(dy(u)) + d = get_index_derivatives(expr) + assert(d['x'] == 1) + assert(d['y'] == 1) + assert(d['z'] == 0) + # ... + + # ... + expr = dx(dy(dx(u))) + d = get_index_derivatives(expr) + assert(d['x'] == 2) + assert(d['y'] == 1) + assert(d['z'] == 0) + # ... + + print('') +# ... + +# ... +def test_poisson(): + print('============ test_poisson ==============') + + u, v = symbols('u v') + + # ... + expr = inner(grad(v), grad(u)) + print('> expr := {0}'.format(expr)) + # ... +# ... + +# ..................................................... +if __name__ == '__main__': + test_0() + test_1() + test_2() + test_3() + test_poisson() diff --git a/old/test_expr_1d.py.old b/old/test_expr_1d.py.old new file mode 100644 index 00000000..9659e9bc --- /dev/null +++ b/old/test_expr_1d.py.old @@ -0,0 +1,429 @@ +# coding: utf-8 + +# TODO split the asserts between algebraic and weak formulations ones +# TODO: - __call__ examples are not working anymore + +from sympy.core.containers import Tuple +from sympy import symbols +from sympy import Symbol +from sympy import Function +from sympy import Matrix +from sympy import pi, cos, sin +from sympy import srepr +from sympy.physics.quantum import TensorProduct + +from sympde.core import dx, dy, dz +from sympde.core import Constant +from sympde.core import ScalarField +from sympde.core import grad, dot, cross, rot, curl, div +from sympde.core import FunctionSpace +from sympde.core import ProductSpace +from sympde.core import ScalarTestFunction +from sympde.core import VectorTestFunction +from sympde.core import BilinearForm, LinearForm, Integral +from sympde.core import atomize +from sympde.core import evaluate +from sympde.core import tensorize +from sympde.core import Mass, Stiffness, Advection, AdvectionT +from sympde.core import Unknown +from sympde.core import Domain + +DIM = 1 +domain = Domain('Omega', dim=DIM) + + +# ... +def test_atomize_1d_1(): + print('============ test_atomize_1d_1 =============') + + V = FunctionSpace('V', domain) + + v = ScalarTestFunction(V, name='v') + w = ScalarTestFunction(V, name='w') + c = Constant('c') + F = ScalarField('F', space=V) + x = Symbol('x') + f = Function('f') + + # ... + assert(atomize(grad(v)) == dx(v)) + assert(atomize(grad(c*v)) == c*dx(v)) + assert(atomize(grad(F*v)) == F*dx(v) + v*dx(F)) + assert(atomize(f(x)*grad(v)) == dx(v)*f(x)) + + assert(atomize(dot(grad(v), grad(w))) == dx(v)*dx(w)) + # ... + + # ... + assert(atomize(grad(v*w)) == w*dx(v) + v*dx(w)) + assert(atomize(div(grad(v*w))) == 2*dx(v)*dx(w) + dx(dx(v))*w + dx(dx(w))*v) + # ... + +# expr = div(grad(v*w)) +# print('> input >>> {0}'.format(expr)) +# print('> atomized >>> {0}'.format(atomize(expr))) +# print(expr.is_commutative) +# ... + +# ... +def test_evaluate_1d_1(): + print('============ test_evaluate_1d_1 =============') + + V = FunctionSpace('V', domain) + U = FunctionSpace('U', domain) + + v = ScalarTestFunction(V, name='v') + u = ScalarTestFunction(U, name='u') + c = Constant('c') + F = ScalarField('F', space=V) + + Ni, Ni_x = symbols('Ni Ni_x') + Nj, Nj_x = symbols('Nj Nj_x') + + # ... + a = BilinearForm((v,u), dot(grad(v), grad(u))) + assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x) + # ... + + # ... + a = BilinearForm((v,u), dot(grad(v), grad(u)) + c*v*u) + assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + c*Ni*Nj) + # ... + + # ... + a = BilinearForm((v,u), dot(grad(v), grad(u)) + F*v*u) + assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + F*Ni*Nj) + # ... + + # ... + a = BilinearForm((v,u), dot(grad(F*v), grad(u))) + assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == F*Ni_x*Nj_x + Ni*Nj_x*dx(F)) + # ... +# ... + +# ... +def test_calls_1d_3(): + print('============ test_calls_1d_3 =============') + + V1 = FunctionSpace('V1', domain) + V2 = FunctionSpace('V2', domain) + U1 = FunctionSpace('U1', domain) + U2 = FunctionSpace('U2', domain) + + v1 = ScalarTestFunction(V1, name='v1') + v2 = ScalarTestFunction(V2, name='v2') + u1 = ScalarTestFunction(U1, name='u1') + u2 = ScalarTestFunction(U2, name='u2') + + V = ProductSpace(V1, V2) + U = ProductSpace(U1, U2) + + x = V1.coordinates + + v1v2 = VectorTestFunction(V, name='v1v2') + u1u2 = VectorTestFunction(U, name='u1u2') + + # ... + a1 = BilinearForm((v1, u1), u1*v1, name='a1') + + expr = a1(v2, u2) + # ... + + # ... + a1 = BilinearForm((v1, u1), u1*v1, name='a1') + a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') + + expr = a1(v2, u2) + a2(v2, u2) + # ... + + # ... + a1 = BilinearForm((v1, u1), u1*v1, name='a1') + a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') + + expr = a1(v1, u2) + a2(v2, u1) + # ... + + # ... + l1 = LinearForm(v1, x*v1, name='l1') + + expr = l1(v2) + # ... + + # ... + l1 = LinearForm(v1, x*v1, name='l1') + l2 = LinearForm(v2, cos(x)*v2, name='l2') + + expr = l1(u1) + l2(u2) + # ... +# ... + +# ... +def test_evaluate_1d_3(): + print('============ test_evaluate_1d_3 =============') + + V1 = FunctionSpace('V1', domain) + U1 = FunctionSpace('U1', domain) + V2 = FunctionSpace('V2', domain) + U2 = FunctionSpace('U2', domain) + + v1 = ScalarTestFunction(V1, name='v1') + u1 = ScalarTestFunction(U1, name='u1') + v2 = ScalarTestFunction(V2, name='v2') + u2 = ScalarTestFunction(U2, name='u2') + + V = ProductSpace(V1, V2) + U = ProductSpace(U1, U2) + + v1v2 = VectorTestFunction(V, name='v1v2') + u1u2 = VectorTestFunction(U, name='u1u2') + + c = Constant('c') + + Ni, Ni_x = symbols('Ni Ni_x') + Nj, Nj_x = symbols('Nj Nj_x') + + basis = {v1v2: 'Ni', u1u2: 'Nj'} + + # ... + expr = v1*u1 + dx(v2)*dx(u2) + a = BilinearForm(((v1, v2), (u1, u2)), expr) + + expected = Matrix([[Ni*Nj, 0], [0, Ni_x*Nj_x]]) + assert(evaluate(a, basis=basis) == expected) + # ... + + # ... + expr = v1*u1 + dx(v2)*dx(u2) + dx(v2)*u1 + v1*dx(u2) + a = BilinearForm(((v1, v2), (u1, u2)), expr) + + expected = Matrix([[Ni*Nj, Ni_x*Nj], [Ni*Nj_x, Ni_x*Nj_x]]) + assert(evaluate(a, basis=basis) == expected) + # ... + +# expr = v1*u1 + dx(v2)*dx(u2) + dx(v2)*u1 + v1*dx(u2) +# expr = BilinearForm(((v1, v2), (u1, u2)), expr) +# print('> input >>> {0}'.format(expr)) +# print('> normal form >>> {0}'.format(evaluate(expr, basis=basis))) + +# ... + +# ... +def test_bilinear_form_1d_10(): + print('============ test_bilinear_form_1d_10 =============') + + U = FunctionSpace('U', domain) + V = FunctionSpace('V', domain) + + u = ScalarTestFunction(U, name='u') + v = ScalarTestFunction(V, name='v') + + u1 = ScalarTestFunction(U, name='u1') + v1 = ScalarTestFunction(V, name='v1') + + Ni, Ni_x = symbols('Ni Ni_x') + Nj, Nj_x = symbols('Nj Nj_x') + + c1 = Symbol('c1') + c2 = Symbol('c2') + + a = BilinearForm((v,u), dot(grad(u), grad(v))) + b = BilinearForm((v,u), u*v) + adv = BilinearForm((v,u), dx(u)*v) + + # ... + expected = Ni*Nj + Ni_x*Nj_x + assert(evaluate(a + b, basis={v: 'Nj', u: 'Ni'}) == expected) + # ... + + # ... + expected = 2*Ni_x*Nj_x + assert(evaluate(2 * a, basis={v: 'Nj', u: 'Ni'}) == expected) + # ... + + # ... + expected = c1*Ni_x*Nj_x + assert(evaluate(c1*a, basis={v: 'Nj', u: 'Ni'}) == expected) + # ... + + # ... + expected = c2*Ni*Nj + c1*Ni_x*Nj_x + assert(evaluate(c1*a + c2*b, basis={v: 'Nj', u: 'Ni'}) == expected) + # ... + + # ... + expected = Ni_x*Nj_x*c1 + c2*(Ni*Nj + Ni_x*Nj) + assert(evaluate(c1*a + c2*(b + adv), basis={v: 'Nj', u: 'Ni'}) == expected) + # ... + +# expr = adv(v1, u1) +# print('> input >>> {0}'.format(expr)) +# print('> evaluated >>> {0}'.format(evaluate(expr, basis={V: 'Nj', U: 'Ni'}) )) +# print('') +# ... + +# ... +def test_linear_form_1d_10(): + print('============ test_linear_form_1d_10 =============') + + V = FunctionSpace('V', domain) + + v = ScalarTestFunction(V, name='v') + + x = V.coordinates + f = Function('f') + + Ni, Ni_x, Ni_xx = symbols('Ni Ni_x Ni_xx') + + c1 = Symbol('c1') + c2 = Symbol('c2') + + # ... + expected = cos(2*pi*x)*Ni + assert(evaluate(LinearForm(v, cos(2*pi*x)*v), + basis={v: 'Ni'}) == expected) + # ... + + # ... + expected = f(x)*Ni + assert(evaluate(LinearForm(v, f(x)*v), + basis={v: 'Ni'}) == expected) + # ... + + # ... + expected = cos(2*pi*x)*Ni_x + assert(evaluate(LinearForm(v, cos(2*pi*x)*dx(v)), + basis={v: 'Ni'}) == expected) + # ... + + # ... + expected = f(x)*Ni_xx + assert(evaluate(LinearForm(v, f(x)*dx(dx(v))), + basis={v: 'Ni'}) == expected) + # ... + +# expr = LinearForm(v, cos(2*pi*x)*dx(v)) +# print('> input >>> {0}'.format(expr)) +# print('> evaluated >>> {0}'.format(evaluate(expr, basis={V: 'Ni'}) )) +# print('') +# ... + +# ... +def test_function_form_1d_10(): + print('============ test_function_form_1d_10 =============') + + V = FunctionSpace('V', domain) + + F = ScalarField('F', space=V) + + x = V.coordinates + f = Function('f') + + Ni, Ni_x, Ni_xx = symbols('Ni Ni_x Ni_xx') + + c1 = Symbol('c1') + c2 = Symbol('c2') + + # ... + expected = -2*pi*sin(2*pi*x) + assert(evaluate(Integral(grad(cos(2*pi*x)), coordinates=[x])) == expected) + # ... + + # ... + expected = F-cos(2*pi*x) + assert(evaluate(Integral(F-cos(2*pi*x))) == expected) + # ... + + # ... + expected = (F-cos(2*pi*x))**2 + assert(evaluate(Integral((F-cos(2*pi*x))**2)) == expected) + # ... + + # ... + expected = dx(F) + 2*pi*sin(2*pi*x) + assert(evaluate(Integral(grad(F-cos(2*pi*x)))) == expected) + # ... + + # ... + expected = (dx(F) + 2*pi*sin(2*pi*x))**2 + assert(evaluate(Integral((grad(F-cos(2*pi*x)))**2)) == expected) + # ... + +# expr = Integral() +# print('> input >>> {0}'.format(expr)) +# print('> evaluated >>> {0}'.format(evaluate(expr) )) +# print('') +# ... + +# ... +def test_tensorize_1d_1(): + print('============ test_tensorize_1d_1 =============') + + V = FunctionSpace('V', domain) + V_0 = FunctionSpace('V_0', domain, coordinates=['x']) + + v = ScalarTestFunction(V, name='v') + u = ScalarTestFunction(V, name='u') + + v0 = ScalarTestFunction(V_0, name='v0') + u0 = ScalarTestFunction(V_0, name='u0') + + c = Constant('c') + + # ... + expected = Mass(v0, u0) + assert(tensorize(BilinearForm((v,u), u*v)) == expected) + # ... + + # ... + expected = Stiffness(v0, u0) + assert(tensorize(BilinearForm((v,u), dx(u)*dx(v))) == expected) + # ... + + # ... + expected = Advection(v0,u0) + assert(tensorize(BilinearForm((v,u), dx(u) * v)) == expected) + # ... + + # ... + expected = Advection(v0,u0) + AdvectionT(v0,u0) + TensorProduct(c ,Stiffness(v0,u0)) + assert(tensorize(BilinearForm((v,u), dx(v) * u + v * dx(u) + c * dx(v)*dx(u))) == expected) + # ... + +# expr = dx(v) * u + v * dx(u) + c * dx(v)*dx(u) +# expr = BilinearForm((v,u), expr) +# +# print('> input >>> {0}'.format(expr)) +# print('> tensorized >>> {0}'.format(tensorize(expr))) +# ... + +# ... +def test_unknown_1d_1(): + print('============ test_unknown_1d_1 =============') + + domain = Domain('Omega', dim=DIM) + + v = Unknown('v', domain) + c = Constant('c') + + # ... + assert(atomize(grad(v)) == dx(v)) + assert(atomize(grad(c*v)) == c*dx(v)) + # ... +# ... + +# ..................................................... +if __name__ == '__main__': + test_atomize_1d_1() + test_evaluate_1d_1() + + test_evaluate_1d_3() + + # TODO bug +# test_bilinear_form_1d_10() + test_linear_form_1d_10() + test_function_form_1d_10() + + test_tensorize_1d_1() + test_calls_1d_3() + + test_unknown_1d_1() diff --git a/old/test_expr_2d.py b/old/test_expr_2d.py new file mode 100644 index 00000000..d11dad6c --- /dev/null +++ b/old/test_expr_2d.py @@ -0,0 +1,471 @@ +# coding: utf-8 + +# TODO - split the asserts between algebraic and weak formulations ones +# - add assert for grad in vector case +# TODO: - __call__ examples are not working anymore + +from sympy import Symbol +from sympy.core.containers import Tuple +from sympy import symbols +from sympy import IndexedBase +from sympy import Matrix +from sympy import Function +from sympy import pi, cos, sin +from sympy import srepr +from sympy.physics.quantum import TensorProduct + +from sympde.core import dx, dy, dz +from sympde.core import Constant +from sympde.core import ScalarField +from sympde.core import grad, dot, inner, cross, rot, curl, div +from sympde.core import FunctionSpace +from sympde.core import ProductSpace +from sympde.core import ScalarTestFunction +from sympde.core import VectorTestFunction +from sympde.core import BilinearForm, LinearForm, Integral +from sympde.core import atomize +from sympde.core import evaluate +from sympde.core import tensorize +from sympde.core import Mass, Stiffness, Advection, AdvectionT +from sympde.core import Unknown +from sympde.core import FormCall +from sympde.core import Domain, Boundary, NormalVector, TangentVector +from sympde.core import Trace, trace_0, trace_1 + +DIM = 2 +domain = Domain('Omega', dim=DIM) + +# ... +def test_atomize_2d_1(): + print('============ test_atomize_2d_1 =============') + + V = FunctionSpace('V', domain) + + v = ScalarTestFunction(V, name='v') + w = ScalarTestFunction(V, name='w') + c = Constant('c') + F = ScalarField('F', space=V) + + # ... + assert(atomize(grad(v)) == Tuple(dx(v), + dy(v))) + assert(atomize(grad(c*v)) == Tuple(c*dx(v), + c*dy(v))) + assert(atomize(grad(F*v)) == Tuple(F*dx(v) + v*dx(F), + F*dy(v) + v*dy(F))) + + assert(atomize(dot(grad(v), grad(w))) == dx(v)*dx(w) + dy(v)*dy(w)) + # ... + +# expr = grad(F*v) +# print('> input >>> {0}'.format(expr)) +# print('> atomized >>> {0}'.format(atomize(expr))) +# ... + +# ... +def test_evaluate_2d_1(): + print('============ test_evaluate_2d_1 =============') + + V = FunctionSpace('V', domain) + U = FunctionSpace('U', domain) + + v = ScalarTestFunction(V, name='v') + u = ScalarTestFunction(U, name='u') + + x,y = V.coordinates + + c = Constant('c') + F = ScalarField('F', space=V) + f1 = Function('f1') + f2 = Function('f2') + + Ni, Ni_x, Ni_y = symbols('Ni Ni_x Ni_y') + Nj, Nj_x, Nj_y = symbols('Nj Nj_x Nj_y') + + bx, by = symbols('bx by') + b = Tuple(bx, by) + + f = Tuple(f1(x,y), f2(x,y)) + + a00 = Constant('a00') + a10 = Constant('a10') + a01 = Constant('a01') + a11 = Constant('a11') + A = Matrix([[a00, a01], [a10, a11]]) + + # ... + a = BilinearForm((v,u), dot(grad(v), grad(u))) + assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + Ni_y*Nj_y) + # ... + + # ... + a = BilinearForm((v,u), dot(grad(v), grad(u)) + c*v*u) + assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + Ni_y*Nj_y + c*Ni*Nj) + # ... + + # ... + a = BilinearForm((v,u), dot(grad(v), grad(u)) + F*v*u) + assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + Ni_y*Nj_y + F*Ni*Nj) + # ... + + # ... + a = BilinearForm((v,u), dot(grad(F*v), grad(u))) + assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == F*Ni_x*Nj_x + F*Ni_y*Nj_y + Ni*Nj_x*dx(F) + Ni*Nj_y*dy(F)) + # ... + +# ... + +# ... +def test_atomize_2d_2(): + print('============ test_atomize_2d_2 =============') + + V = FunctionSpace('V', domain, is_block=True, shape=2) + + v = VectorTestFunction(V, name='v') + + assert(atomize(rot(v)) == -dx(v[1]) + dy(v[0])) + assert(atomize(div(v)) == dx(v[0]) + dy(v[1])) + +# expr = div(v) +# print('> input >>> {0}'.format(expr)) +# print('> atomized >>> {0}'.format(atomize(expr))) +# ... + +# ... +def test_evaluate_2d_3(): + print('============ test_evaluate_2d_3 =============') + + V1 = FunctionSpace('V1', domain) + U1 = FunctionSpace('U1', domain) + V2 = FunctionSpace('V2', domain) + U2 = FunctionSpace('U2', domain) + + v1 = ScalarTestFunction(V1, name='v1') + u1 = ScalarTestFunction(U1, name='u1') + v2 = ScalarTestFunction(V2, name='v2') + u2 = ScalarTestFunction(U2, name='u2') + + V = ProductSpace(V1, V2) + U = ProductSpace(U1, U2) + + v1v2 = VectorTestFunction(V, name='v1v2') + u1u2 = VectorTestFunction(U, name='u1u2') + + c = Constant('c') + + Ni, Ni_x, Ni_y = symbols('Ni Ni_x Ni_y') + Nj, Nj_x, Nj_y = symbols('Nj Nj_x Nj_y') + + basis = {v1v2: 'Ni', u1u2: 'Nj'} + + # ... + expr = v1*u1 + dx(v2)*dx(u2) + a = BilinearForm(((v1, v2), (u1, u2)), expr) + + expected = Matrix([[Ni*Nj, 0], [0, Ni_x*Nj_x]]) + assert(evaluate(a, basis=basis) == expected) + # ... + + # ... + expr = v1*u1 + dy(v2)*u1 + v1*dx(u2) + dx(v2)*dx(u2) + a = BilinearForm(((v1, v2), (u1, u2)), expr) + + expected = Matrix([[Ni*Nj, Ni_y*Nj], [Ni*Nj_x, Ni_x*Nj_x]]) + assert(evaluate(a, basis=basis) == expected) + # ... + +# expr = v1*u1 + dy(v2)*u1 + v1*dx(u2) + dx(v2)*dx(u2) +# expr = BilinearForm(((v1, v2), (u1, u2)), expr) +# print('> input >>> {0}'.format(expr)) +# print('> normal form >>> {0}'.format(evaluate(expr, basis=basis))) +# ... + +# ... +#def test_bilinear_form_2d_10(): +# print('============ test_bilinear_form_2d_10 =============') +# +# U = FunctionSpace('U', domain) +# V = FunctionSpace('V', domain) +# +# u = ScalarTestFunction(U, name='u') +# v = ScalarTestFunction(V, name='v') +# +# u1 = ScalarTestFunction(U, name='u1') +# v1 = ScalarTestFunction(V, name='v1') +# +# Ni, Ni_x, Ni_y = symbols('Ni Ni_x Ni_y') +# Nj, Nj_x, Nj_y = symbols('Nj Nj_x Nj_y') +# +# c1 = Symbol('c1') +# c2 = Symbol('c2') +# +# a = BilinearForm((v,u), inner(grad(u), grad(v))) +# b = BilinearForm((v,u), u*v) +# adv = BilinearForm((v,u), dx(u)*v) +# +# # ... +# expected = Ni*Nj + Ni_x*Nj_x + Ni_y*Nj_y +# assert(evaluate(a + b, basis={v: 'Nj', u: 'Ni'}) == expected) +# # ... +# +# # ... +# expected = 2*Ni_x*Nj_x + 2*Ni_y*Nj_y +# assert(evaluate(2 * a, basis={v: 'Nj', u: 'Ni'}) == expected) +# # ... +# +# # ... +# expected = c1*(Ni_x*Nj_x + Ni_y*Nj_y) +# assert(evaluate(c1*a, basis={v: 'Nj', u: 'Ni'}) == expected) +# # ... +# +# # ... +# expected = Ni*Nj*c2 + c1*(Ni_x*Nj_x + Ni_y*Nj_y) +# assert(evaluate(c1*a + c2*b, basis={v: 'Nj', u: 'Ni'}) == expected) +# # ... +# +# # ... +# expected = c1*(Ni_x*Nj_x + Ni_y*Nj_y) + c2*(Ni*Nj + Ni_x*Nj) +# assert(evaluate(c1*a + c2*(b + adv), basis={v: 'Nj', u: 'Ni'}) == expected) +# # ... +# +## expr = c1*a + c2*(b + adv) +## print('> input >>> {0}'.format(expr)) +## print('> evaluated >>> {0}'.format(evaluate(expr, basis={v: 'Nj', u: 'Ni'}) )) +## print('') +# ... + +# ... +def test_linear_form_2d_10(): + print('============ test_linear_form_2d_10 =============') + + V = FunctionSpace('V', domain) + + v = ScalarTestFunction(V, name='v') + + x,y = V.coordinates + f = Function('f') + g = Function('g') + + Ni, Ni_x, Ni_y = symbols('Ni Ni_x Ni_y') + Nj, Nj_x, Nj_y = symbols('Nj Nj_x Nj_y') + + c1 = Symbol('c1') + c2 = Symbol('c2') + + bx, by = symbols('bx by') + b = Tuple(bx, by) + fg = Tuple(f(x,y), g(x,y)) + + a = LinearForm(v, cos(2*pi*x)*cos(4*pi*y)*v) + + # ... + expected = cos(2*pi*x)*cos(4*pi*y)*Ni + assert(evaluate(LinearForm(v, cos(2*pi*x)*cos(4*pi*y)*v), + basis={v: 'Ni'}) == expected) + # ... + + # ... + expected = f(x,y)*Ni + assert(evaluate(LinearForm(v, f(x,y)*v), + basis={v: 'Ni'}) == expected) + # ... + + # ... + expected = bx*Ni_x + by*Ni_y + f(x,y)*Ni + assert(evaluate(LinearForm(v, dot(b, grad(v)) + f(x,y)*v), + basis={v: 'Ni'}) == expected) + # ... + + # ... + expected = f(x,y)*Ni_x + g(x,y)*Ni_y + assert(evaluate(LinearForm(v, dot(fg, grad(v))), + basis={v: 'Ni'}) == expected) + # ... + +# expr = +# print('> input >>> {0}'.format(expr)) +# print('> evaluated >>> {0}'.format(evaluate(expr, basis={v: 'Ni'}) )) +# print('') +# ... + +# ... +def test_function_form_2d_10(): + print('============ test_function_form_2d_10 =============') + + V = FunctionSpace('V', domain) + + F = ScalarField('F', space=V) + + x,y = V.coordinates + + f = Function('f') + g = Function('g') + + Ni, Ni_x, Ni_y = symbols('Ni Ni_x Ni_y') + Nj, Nj_x, Nj_y = symbols('Nj Nj_x Nj_y') + + c1 = Symbol('c1') + c2 = Symbol('c2') + + bx, by = symbols('bx by') + b = Tuple(bx, by) + fg = Tuple(f(x,y), g(x,y)) + + # ... + expected = 4*pi**2*sin(2*pi*x)**2*cos(3*pi*y)**2 + 9*pi**2*sin(3*pi*y)**2*cos(2*pi*x)**2 + e = cos(2*pi*x)*cos(3*pi*y) + assert(evaluate(Integral(dot(grad(e), grad(e)), coordinates=[x,y])) == expected) + # ... + + # ... + expected = F - cos(2*pi*x)*cos(3*pi*y) + assert(evaluate(Integral(F-cos(2*pi*x)*cos(3*pi*y))) == expected) + # ... + + # ... + expected = (F - cos(2*pi*x)*cos(3*pi*y))**2 + assert(evaluate(Integral((F - cos(2*pi*x)*cos(3*pi*y))**2)) == expected) + # ... + + # ... + expected = (dx(F) + 2*pi*sin(2*pi*x)*cos(3*pi*y))**2 + (dy(F) + 3*pi*sin(3*pi*y)*cos(2*pi*x))**2 + e = F -cos(2*pi*x)*cos(3*pi*y) + assert(evaluate(Integral(dot(grad(e), grad(e)))) == expected) + # ... + +# e = F -cos(2*pi*x)*cos(3*pi*y) +# expr = Integral(dot(grad(e), grad(e))) +# print('> input >>> {0}'.format(expr)) +# print('> evaluated >>> {0}'.format(evaluate(expr) )) +# print('') +# ... + +# ... +def test_tensorize_2d_1(): + print('============ test_tensorize_2d_1 =============') + + V = FunctionSpace('V', domain) + V_0 = FunctionSpace('V_0', domain, coordinates=['x']) + V_1 = FunctionSpace('V_1', domain, coordinates=['y']) + + v = ScalarTestFunction(V, name='v') + u = ScalarTestFunction(V, name='u') + + v0 = ScalarTestFunction(V_0, name='v0') + u0 = ScalarTestFunction(V_0, name='u0') + + v1 = ScalarTestFunction(V_1, name='v1') + u1 = ScalarTestFunction(V_1, name='u1') + + c = Constant('c') + + bx = Constant('bx') + by = Constant('by') + b = Tuple(bx, by) + + # ... + expected = TensorProduct(Mass(v1, u1), Mass(v0, u0)) + assert(tensorize(BilinearForm((v,u), u*v)) == expected) + # ... + + # ... + expected = TensorProduct(Mass(v1, u1), Stiffness(v0, u0)) + assert(tensorize(BilinearForm((v,u), dx(u)*dx(v))) == expected) + # ... + + # ... + expected = TensorProduct(Advection(v1, u1), Mass(v0, u0)) + assert(tensorize(BilinearForm((v,u), dy(u) * v)) == expected) + # ... + + # ... + expected = TensorProduct(Mass(v1,u1), Advection(v0,u0)) + assert(tensorize(BilinearForm((v,u), dx(u) * v)) == expected) + # ... + + # ... + expected = TensorProduct(Mass(v1,u1), Stiffness(v0,u0)) + TensorProduct(Stiffness(v1,u1), Mass(v0,u0)) + assert(tensorize(BilinearForm((v,u), dot(grad(v), grad(u)))) == expected) + # ... + + # ... + expected = (TensorProduct(Advection(v1,u1), Mass(v0,u0)) + + TensorProduct(Mass(v1,u1), Advection(v0,u0)) + + TensorProduct(Mass(v1,u1), Stiffness(v0,u0)) + + TensorProduct(Stiffness(v1,u1), Mass(v0,u0))) + assert(tensorize(BilinearForm((v,u), dot(grad(v), grad(u)) + dx(u)*v + dy(u)*v)) == expected) + # ... + + # ... + expected = (TensorProduct(bx, Mass(v1,u1), AdvectionT(v0,u0)) + + TensorProduct(by, AdvectionT(v1,u1), Mass(v0,u0))) + assert(tensorize(BilinearForm((v,u), dot(b, grad(v)) * u)) == expected) + # ... + + # ... + expected = (TensorProduct(bx**2,Mass(v1,u1),Stiffness(v0,u0)) + + TensorProduct(bx,by,Advection(v1,u1),AdvectionT(v0,u0)) + + TensorProduct(bx,by,AdvectionT(v1,u1),Advection(v0,u0)) + + TensorProduct(by**2,Stiffness(v1,u1),Mass(v0,u0))) + assert(tensorize(BilinearForm((v,u), dot(b, grad(v)) * dot(b, grad(u)))) == expected) + # ... + +# expr = dot(b, grad(v)) * u +# expr = BilinearForm((v,u), expr) +# +# print('> input >>> {0}'.format(expr)) +# print('> tensorized >>> {0}'.format(tensorize(expr))) +# ... + + +# ... +def test_tensorize_2d_2(): + print('============ test_tensorize_2d_2 =============') + + V = FunctionSpace('V', domain, is_block=True, shape=2) +# V_0 = FunctionSpace('V_0', domain, coordinates=['x']) +# V_1 = FunctionSpace('V_1', domain, coordinates=['y']) + + v = VectorTestFunction(V, name='v') + u = VectorTestFunction(V, name='u') + +# v0 = ScalarTestFunction(V_0, name='v0') +# u0 = ScalarTestFunction(V_0, name='u0') +# +# v1 = ScalarTestFunction(V_1, name='v1') +# u1 = ScalarTestFunction(V_1, name='u1') + + c = Constant('c') + + bx = Constant('bx') + by = Constant('by') + b = Tuple(bx, by) + +# # ... +# expected = Mass(v1, u1)*Mass(v0, u0) +# assert(tensorize(BilinearForm((v,u), div(v) * div(u))) == expected) +# # ... + +# expr = div(v) * div(u) + rot(v) * rot(u) +# expr = BilinearForm((v,u), expr) +# +# print('> input >>> {0}'.format(expr)) +# print('> tensorized >>> {0}'.format(tensorize(expr))) +# ... + +# ... +def test_unknown_2d_1(): + print('============ test_unknown_2d_1 =============') + + domain = Domain('Omega', dim=DIM) + + v = Unknown('v', domain) + c = Constant('c') + + # ... + assert(atomize(grad(v)) == Tuple(dx(v), + dy(v))) + assert(atomize(grad(c*v)) == Tuple(c*dx(v), + c*dy(v))) + # ... +# ... diff --git a/old/test_expr_3d.py.old b/old/test_expr_3d.py.old new file mode 100644 index 00000000..94af95c1 --- /dev/null +++ b/old/test_expr_3d.py.old @@ -0,0 +1,589 @@ +# coding: utf-8 + +# TODO - split the asserts between algebraic and weak formulations ones +# - add assert for grad in vector case +# TODO: - __call__ examples are not working anymore + +from sympy import Symbol +from sympy.core.containers import Tuple +from sympy import symbols +from sympy import IndexedBase +from sympy import Matrix +from sympy import Function +from sympy import pi, cos, sin +from sympy.physics.quantum import TensorProduct + +from sympde.core import dx, dy, dz +from sympde.core import Constant +from sympde.core import ScalarField +from sympde.core import grad, dot, inner, cross, rot, curl, div +from sympde.core import FunctionSpace +from sympde.core import ProductSpace +from sympde.core import ScalarTestFunction +from sympde.core import VectorTestFunction +from sympde.core import BilinearForm, LinearForm, Integral +from sympde.core import atomize +from sympde.core import evaluate +from sympde.core import tensorize +from sympde.core import Mass, Stiffness, Advection, AdvectionT +from sympde.core import Unknown +from sympde.core import Domain + +DIM = 3 +domain = Domain('Omega', dim=DIM) + + +# ... +def test_atomize_3d_1(): + print('============ test_atomize_3d_1 =============') + + V = FunctionSpace('V', domain) + + v = ScalarTestFunction(V, name='v') + w = ScalarTestFunction(V, name='w') + c = Constant('c') + F = ScalarField('F', space=V) + + # ... + assert(atomize(grad(v)) == Tuple(dx(v), + dy(v), + dz(v))) + assert(atomize(grad(c*v)) == Tuple(c*dx(v), + c*dy(v), + c*dz(v))) + assert(atomize(grad(F*v)) == Tuple(F*dx(v) + v*dx(F), + F*dy(v) + v*dy(F), + F*dz(v) + v*dz(F))) + + assert(atomize(dot(grad(v), grad(w))) == dx(v)*dx(w) + dy(v)*dy(w) + dz(v)*dz(w)) + # ... + +# expr = grad(F*v) +# print('> input >>> {0}'.format(expr)) +# print('> atomized >>> {0}'.format(atomize(expr))) +# ... + +# ... +def test_evaluate_3d_1(): + print('============ test_evaluate_3d_1 =============') + + V = FunctionSpace('V', domain) + U = FunctionSpace('U', domain) + + v = ScalarTestFunction(V, name='v') + u = ScalarTestFunction(U, name='u') + + x,y,z = V.coordinates + + c = Constant('c') + F = ScalarField('F', space=V) + f1 = Function('f1') + f2 = Function('f2') + f3 = Function('f3') + + Ni, Ni_x, Ni_y, Ni_z = symbols('Ni Ni_x Ni_y Ni_z') + Nj, Nj_x, Nj_y, Nj_z = symbols('Nj Nj_x Nj_y Nj_z') + + bx, by, bz = symbols('bx by bz') + b = Tuple(bx, by, bz) + + f = Tuple(f1(x,y,z), f2(x,y,z), f3(x,y,z)) + + a00 = Constant('a00') + a10 = Constant('a10') + a20 = Constant('a20') + a01 = Constant('a01') + a11 = Constant('a11') + a21 = Constant('a21') + a02 = Constant('a02') + a12 = Constant('a12') + a22 = Constant('a22') + A = Matrix([[a00, a01, a02], [a10, a11, a12], [a20, a21, a22]]) + + # ... + a = BilinearForm((v,u), dot(grad(v), grad(u))) + assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z) + # ... + + # ... + a = BilinearForm((v,u), dot(grad(v), grad(u)) + c*v*u) + assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z + c*Ni*Nj) + # ... + + # ... + a = BilinearForm((v,u), dot(grad(v), grad(u)) + F*v*u) + assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z + F*Ni*Nj) + # ... + + # ... + a = BilinearForm((v,u), dot(grad(F*v), grad(u))) + assert(evaluate(a, basis={v: 'Ni', u: 'Nj'}) == F*Ni_x*Nj_x + F*Ni_y*Nj_y + F*Ni_z*Nj_z + Ni*Nj_x*dx(F) + Ni*Nj_y*dy(F) + Ni*Nj_z*dz(F)) + # ... + +# ... + +# ... +def test_atomize_3d_2(): + print('============ test_atomize_3d_2 =============') + + V = FunctionSpace('V', domain, is_vector=True, shape=3) + + v = VectorTestFunction(V, name='v') + + assert(atomize(curl(v)) == Tuple( dy(v[2]) - dz(v[1]), + -dx(v[2]) + dz(v[0]), + dx(v[1]) - dy(v[0]))) + assert(atomize(div(v)) == dx(v[0]) + dy(v[1]) + dz(v[2])) + +# expr = curl(v) +# print('> input >>> {0}'.format(expr)) +# print('> atomized >>> {0}'.format(atomize(expr))) +# ... + +# ... +#def test_bilinear_form_3d_10(): +# print('============ test_bilinear_form_3d_10 =============') +# +# U = FunctionSpace('U', domain) +# V = FunctionSpace('V', domain) +# +# u = ScalarTestFunction(U, name='u') +# v = ScalarTestFunction(V, name='v') +# +# u1 = ScalarTestFunction(U, name='u1') +# v1 = ScalarTestFunction(V, name='v1') +# +# Ni, Ni_x, Ni_y, Ni_z = symbols('Ni Ni_x Ni_y Ni_z') +# Nj, Nj_x, Nj_y, Nj_z = symbols('Nj Nj_x Nj_y Nj_z') +# +# c1 = Symbol('c1') +# c2 = Symbol('c2') +# +# a = BilinearForm((v,u), inner(grad(u), grad(v))) +# b = BilinearForm((v,u), u*v) +# adv = BilinearForm((v,u), dx(u)*v) +# +# # ... +# expected = Ni*Nj + Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z +# assert(evaluate(a + b, basis={v: 'Nj', u: 'Ni'}) == expected) +# # ... +# +# # ... +# expected = Ni*Nj + Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z +# assert(evaluate(a + b, basis={v: 'Nj', u: 'Ni'}) == expected) +# # ... +# +# # ... +# expected = 2*Ni_x*Nj_x + 2*Ni_y*Nj_y + 2*Ni_z*Nj_z +# assert(evaluate(2 * a, basis={v: 'Nj', u: 'Ni'}) == expected) +# # ... +# +# # ... +# expected = c1*(Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z) +# assert(evaluate(c1*a, basis={v: 'Nj', u: 'Ni'}) == expected) +# # ... +# +# # ... +# expected = Ni*Nj*c2 + c1*(Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z) +# assert(evaluate(c1*a + c2*b, basis={v: 'Nj', u: 'Ni'}) == expected) +# # ... +# +# # ... +# expected = c1*(Ni_x*Nj_x + Ni_y*Nj_y + Ni_z*Nj_z) + c2*(Ni*Nj + Ni_x*Nj) +# assert(evaluate(c1*a + c2*(b + adv), basis={v: 'Nj', u: 'Ni'}) == expected) +# # ... +# +# # ... +# assert(evaluate(a(u1, v1), basis={v: 'Nj', u: 'Ni'}) == evaluate(a(v1, u1), basis={v: 'Nj', u: 'Ni'})) +# # ... +# +## # ... TODO debug +## expected = Ni_x*Nj +## assert(evaluate(adv(v1, u1), basis={v: 'Nj', u: 'Ni'}) == expected) +## +## expected = Nj_x*Ni +## assert(evaluate(adv(u1, v1), basis={v: 'Nj', u: 'Ni'}) == expected) +## # ... +# +## expr = c1*a + c2*(b + adv) +## print('> input >>> {0}'.format(expr)) +## print('> evaluated >>> {0}'.format(evaluate(expr, basis={v: 'Nj', u: 'Ni'}) )) +## print('') +# ... + +# ... +def test_linear_form_3d_10(): + print('============ test_linear_form_3d_10 =============') + + V = FunctionSpace('V', domain) + + v = ScalarTestFunction(V, name='v') + x,y,z = V.coordinates + + f = Function('f') + g = Function('g') + r = Function('r') + + Ni, Ni_x, Ni_y, Ni_z = symbols('Ni Ni_x Ni_y Ni_z') + Nj, Nj_x, Nj_y, Nj_z = symbols('Nj Nj_x Nj_y Nj_z') + + c1 = Symbol('c1') + c2 = Symbol('c2') + + bx, by, bz = symbols('bx by bz') + b = Tuple(bx, by, bz) + fgr = Tuple(f(x,y,z), g(x,y,z), r(x,y,z)) + + a = LinearForm(v, cos(2*pi*x)*cos(4*pi*y)*cos(5*pi*z)*v) + + # ... + expected = cos(2*pi*x)*cos(4*pi*y)*cos(5*pi*z)*Ni + assert(evaluate(LinearForm(v, cos(2*pi*x)*cos(4*pi*y)*cos(5*pi*z)*v), + basis={v: 'Ni'}) == expected) + # ... + + # ... + expected = f(x,y,z)*Ni + assert(evaluate(LinearForm(v, f(x,y,z)*v), + basis={v: 'Ni'}) == expected) + # ... + + # ... + expected = bx*Ni_x + by*Ni_y + bz*Ni_z + f(x,y,z)*Ni + assert(evaluate(LinearForm(v, dot(b, grad(v)) + f(x,y,z)*v), + basis={v: 'Ni'}) == expected) + # ... + + # ... + expected = f(x,y,z)*Ni_x + g(x,y,z)*Ni_y + r(x,y,z)*Ni_z + assert(evaluate(LinearForm(v, dot(fgr, grad(v))), + basis={v: 'Ni'}) == expected) + # ... + +# expr = c1*a + c2*(b + adv) +# print('> input >>> {0}'.format(expr)) +# print('> evaluated >>> {0}'.format(evaluate(expr, basis={v: 'Ni'}) )) +# print('') +# ... + +# ... +def test_function_form_3d_10(): + print('============ test_function_form_3d_10 =============') + + V = FunctionSpace('V', domain) + + F = ScalarField('F', space=V) + + x,y,z = V.coordinates + + f = Function('f') + g = Function('g') + r = Function('r') + + Ni, Ni_x, Ni_y, Ni_z = symbols('Ni Ni_x Ni_y Ni_z') + Nj, Nj_x, Nj_y, Nj_z = symbols('Nj Nj_x Nj_y Nj_z') + + c1 = Symbol('c1') + c2 = Symbol('c2') + + bx, by, bz = symbols('bx by bz') + b = Tuple(bx, by, bz) + fgr = Tuple(f(x,y,z), g(x,y,z), r(x,y,z)) + + # ... + expected = cos(2*pi*x)*cos(3*pi*y)*cos(5*pi*z) + assert(evaluate(Integral(cos(2*pi*x)*cos(3*pi*y)*cos(5*pi*z), coordinates=[x,y,z])) == expected) + # ... + + # ... + expected = x**2 + y**2 + 1 + e = x*y + z + assert(evaluate(Integral(dot(grad(e), grad(e)), coordinates=[x,y,z])) == expected) + # ... + + # ... + expected = F - cos(2*pi*x)*cos(3*pi*y)*cos(5*pi*z) + assert(evaluate(Integral(F-cos(2*pi*x)*cos(3*pi*y)*cos(5*pi*z))) == expected) + # ... + + # ... + expected = (F - x*y - z)**2 + assert(evaluate(Integral((F - x*y - z)**2)) == expected) + # ... + + # ... + expected = dx(F)**2 + dy(F)**2 + dz(F)**2 + assert(evaluate(Integral(dot(grad(F), grad(F)))) == expected) + # ... + + # ... + expected = (-x + dy(F))**2 + (-y + dx(F))**2 + (dz(F) - 1)**2 + e = F - (x*y + z) + assert(evaluate(Integral(dot(grad(e), grad(e)), coordinates=[x,y,z])) == expected) + # ... + + # ... TODO debug. => infinite recursion!!! why? + # must be a problem with Mul treatements +# e = cos(2*pi*x)*cos(3*pi*y)*cos(5*pi*z) +# e = cos(2*pi*x)*cos(3*pi*y)*z +# e = x*y*z + # ... + +# e = F - (x*y + z) +# expr = Integral(dot(grad(e), grad(e)), coordinates=[x,y,z]) +# print('> input >>> {0}'.format(expr)) +# print('> evaluated >>> {0}'.format(evaluate(expr) )) +# print('') +# ... + +# ... +def test_calls_3d_3(): + print('============ test_calls_3d_3 =============') + + V1 = FunctionSpace('V1', domain) + V2 = FunctionSpace('V2', domain) + U1 = FunctionSpace('U1', domain) + U2 = FunctionSpace('U2', domain) + W1 = FunctionSpace('W1', domain, is_block=True, shape=3) + W2 = FunctionSpace('W2', domain, is_block=True, shape=3) + T1 = FunctionSpace('T1', domain, is_block=True, shape=3) + T2 = FunctionSpace('T2', domain, is_block=True, shape=3) + + v1 = ScalarTestFunction(V1, name='v1') + v2 = ScalarTestFunction(V2, name='v2') + u1 = ScalarTestFunction(U1, name='u1') + u2 = ScalarTestFunction(U2, name='u2') + w1 = VectorTestFunction(W1, name='w1') + w2 = VectorTestFunction(W2, name='w2') + t1 = VectorTestFunction(T1, name='t1') + t2 = VectorTestFunction(T2, name='t2') + + V = ProductSpace(V1, V2) + U = ProductSpace(U1, U2) + + x,y,z = V1.coordinates + + v1v2 = VectorTestFunction(V, name='v1v2') + u1u2 = VectorTestFunction(U, name='u1u2') + + # ... + a1 = BilinearForm((v1, u1), u1*v1, name='a1') + + expr = a1(v2, u2) + # ... + + # ... + a1 = BilinearForm((v1, u1), u1*v1, name='a1') + a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') + + expr = a1(v2, u2) + a2(v2, u2) + # ... + + # ... + a1 = BilinearForm((v1, u1), u1*v1, name='a1') + a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') + + expr = a1(v1, u2) + a2(v2, u1) + # ... + + # ... + a1 = BilinearForm((v1, u1), u1*v1, name='a1') + a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') + a3 = BilinearForm((w1, t1), dot(curl(w1), curl(t1)) + div(w1)*div(t1), name='a3') + a4 = BilinearForm((w1, u1), div(w1)*u1, name='a4') + + expr = a3(w2,t2) + a2(v2,u2) + a4(w2,u2) + # ... + + # ... + l1 = LinearForm(v1, x*y*z*v1, name='l1') + + expr = l1(v2) + # ... + + # ... + l1 = LinearForm(v1, x*y*z*v1, name='l1') + l2 = LinearForm(v2, cos(x+y+z)*v2, name='l2') + + expr = l1(u1) + l2(u2) + # ... +# ... + +# ... +def test_evaluate_3d_3(): + print('============ test_evaluate_3d_3 =============') + + V1 = FunctionSpace('V1', domain) + U1 = FunctionSpace('U1', domain) + V2 = FunctionSpace('V2', domain) + U2 = FunctionSpace('U2', domain) + + v1 = ScalarTestFunction(V1, name='v1') + u1 = ScalarTestFunction(U1, name='u1') + v2 = ScalarTestFunction(V2, name='v2') + u2 = ScalarTestFunction(U2, name='u2') + + V = ProductSpace(V1, V2) + U = ProductSpace(U1, U2) + + v1v2 = VectorTestFunction(V, name='v1v2') + u1u2 = VectorTestFunction(U, name='u1u2') + + c = Constant('c') + + Ni, Ni_x, Ni_y, Ni_z = symbols('Ni Ni_x Ni_y Ni_z') + Nj, Nj_x, Nj_y, Nj_z = symbols('Nj Nj_x Nj_y Nj_z') + + basis = {v1v2: 'Ni', u1u2: 'Nj'} + + # ... + expr = v1*u1 + dz(v2)*dz(u2) + a = BilinearForm(((v1, v2), (u1, u2)), expr) + + expected = Matrix([[Ni*Nj, 0], [0, Ni_z*Nj_z]]) + assert(evaluate(a, basis=basis) == expected) + # ... + + # ... + expr = v1*u1 + dx(v2)*dx(u1) + dy(v1)*dy(u2) + dz(v2)*dz(u2) + a = BilinearForm(((v1, v2), (u1, u2)), expr) + + expected = Matrix([[Ni*Nj, Ni_x*Nj_x], [Ni_y*Nj_y, Ni_z*Nj_z]]) + assert(evaluate(a, basis=basis) == expected) + # ... + +# expr = v1*u1 + dx(v2)*dx(u1) + dy(v1)*dy(u2) + dz(v2)*dz(u2) +# expr = BilinearForm(((v1, v2), (u1, u2)), expr) +# print('> input >>> {0}'.format(expr)) +# print('> normal form >>> {0}'.format(evaluate(expr, basis=basis))) +# ... + +# ... +def test_tensorize_3d_1(): + print('============ test_tensorize_3d_1 =============') + + V = FunctionSpace('V', domain) + V_0 = FunctionSpace('V_0', domain, coordinates=['x']) + V_1 = FunctionSpace('V_1', domain, coordinates=['y']) + V_2 = FunctionSpace('V_2', domain, coordinates=['z']) + + v = ScalarTestFunction(V, name='v') + u = ScalarTestFunction(V, name='u') + + v0 = ScalarTestFunction(V_0, name='v0') + u0 = ScalarTestFunction(V_0, name='u0') + + v1 = ScalarTestFunction(V_1, name='v1') + u1 = ScalarTestFunction(V_1, name='u1') + + v2 = ScalarTestFunction(V_2, name='v2') + u2 = ScalarTestFunction(V_2, name='u2') + + c = Constant('c') + + bx = Constant('bx') + by = Constant('by') + bz = Constant('bz') + b = Tuple(bx, by, bz) + + # ... + expected = TensorProduct(Mass(v2,u2),Mass(v1,u1),Mass(v0,u0)) + assert(tensorize(BilinearForm((v,u), u*v)) == expected) + # ... + + # ... + expected = TensorProduct(Mass(v2,u2),Mass(v1,u1),Stiffness(v0,u0)) + assert(tensorize(BilinearForm((v,u), dx(u)*dx(v))) == expected) + # ... + + # ... + expected = TensorProduct(Mass(v2,u2),Advection(v1,u1),Mass(v0,u0)) + assert(tensorize(BilinearForm((v,u), dy(u) * v)) == expected) + # ... + + # ... + expected = TensorProduct(Mass(v2,u2),Mass(v1,u1),Advection(v0,u0)) + assert(tensorize(BilinearForm((v,u), dx(u) * v)) == expected) + # ... + + # ... + expected = (TensorProduct(Mass(v2,u2),Mass(v1,u1),Stiffness(v0,u0)) + + TensorProduct(Mass(v2,u2),Stiffness(v1,u1),Mass(v0,u0)) + + TensorProduct(Stiffness(v2,u2),Mass(v1,u1),Mass(v0,u0))) + assert(tensorize(BilinearForm((v,u), dot(grad(v), grad(u)))) == expected) + # ... + + # ... + expected = (TensorProduct(Mass(v2,u2),Advection(v1,u1),Mass(v0,u0)) + + TensorProduct(Mass(v2,u2),Mass(v1,u1),Advection(v0,u0)) + + TensorProduct(Mass(v2,u2),Mass(v1,u1),Stiffness(v0,u0)) + + TensorProduct(Mass(v2,u2),Stiffness(v1,u1),Mass(v0,u0)) + + TensorProduct(Stiffness(v2,u2),Mass(v1,u1),Mass(v0,u0))) + assert(tensorize(BilinearForm((v,u), dot(grad(v), grad(u)) + dx(u)*v + dy(u)*v)) == expected) + # ... + + # ... + expected = (TensorProduct(bx,Mass(v2,u2),Mass(v1,u1),AdvectionT(v0,u0)) + + TensorProduct(by,Mass(v2,u2),AdvectionT(v1,u1),Mass(v0,u0)) + + TensorProduct(bz,AdvectionT(v2,u2),Mass(v1,u1),Mass(v0,u0))) + + assert(tensorize(BilinearForm((v,u), dot(b, grad(v)) * u)) == expected) + # ... + + # ... + expected = (TensorProduct(bx**2,Mass(v2,u2),Mass(v1,u1),Stiffness(v0,u0)) + + TensorProduct(bx,by,Mass(v2,u2),Advection(v1,u1),AdvectionT(v0,u0)) + + TensorProduct(bx,by,Mass(v2,u2),AdvectionT(v1,u1),Advection(v0,u0)) + + TensorProduct(bx,bz,Advection(v2,u2),Mass(v1,u1),AdvectionT(v0,u0)) + + TensorProduct(bx,bz,AdvectionT(v2,u2),Mass(v1,u1),Advection(v0,u0)) + + TensorProduct(by**2,Mass(v2,u2),Stiffness(v1,u1),Mass(v0,u0)) + + TensorProduct(by,bz,Advection(v2,u2),AdvectionT(v1,u1),Mass(v0,u0)) + + TensorProduct(by,bz,AdvectionT(v2,u2),Advection(v1,u1),Mass(v0,u0)) + + TensorProduct(bz**2,Stiffness(v2,u2),Mass(v1,u1),Mass(v0,u0))) + + assert(tensorize(BilinearForm((v,u), dot(b, grad(v)) * dot(b, grad(u)))) == expected) + # ... + +# expr = dot(b, grad(v)) * dot(b, grad(u)) +# expr = BilinearForm((v,u), expr) +# +# print('> input >>> {0}'.format(expr)) +# print('> tensorized >>> {0}'.format(tensorize(expr))) +# ... + +# ... +def test_unknown_3d_1(): + print('============ test_unknown_3d_1 =============') + + domain = Domain('Omega', dim=DIM) + + v = Unknown('v', domain) + c = Constant('c') + + # ... + assert(atomize(grad(v)) == Tuple(dx(v), + dy(v), + dz(v))) + assert(atomize(grad(c*v)) == Tuple(c*dx(v), + c*dy(v), + c*dz(v))) + # ... +# ... + +# ..................................................... +if __name__ == '__main__': + test_atomize_3d_1() + test_evaluate_3d_1() + + test_atomize_3d_2() + +# test_bilinear_form_3d_10() # TODO not working, since args are the same + test_linear_form_3d_10() + test_function_form_3d_10() + + test_evaluate_3d_3() + + test_tensorize_3d_1() + test_calls_3d_3() + + test_unknown_3d_1() diff --git a/old/test_form_2d.py b/old/test_form_2d.py new file mode 100644 index 00000000..2087c33c --- /dev/null +++ b/old/test_form_2d.py @@ -0,0 +1,1487 @@ +# coding: utf-8 + +# TODO - split the asserts between algebraic and weak formulations ones +# - add assert for grad in vector case +# TODO: - __call__ examples are not working anymore + +import pytest + +from sympy import Symbol +from sympy.core.containers import Tuple +from sympy import symbols +from sympy import IndexedBase +from sympy import Matrix +from sympy import Function +from sympy import pi, cos, sin, exp +from sympy import srepr +from sympy.physics.quantum import TensorProduct + +from sympde.core import Constant +from sympde.calculus import grad, dot, inner, cross, rot, curl, div +from sympde.calculus import laplace, hessian, bracket, convect +from sympde.topology import (dx, dy, dz) +from sympde.topology import FunctionSpace, VectorFunctionSpace +from sympde.topology import Field, VectorField +from sympde.topology import ProductSpace +from sympde.topology import TestFunction +from sympde.topology import VectorTestFunction +from sympde.topology import Unknown +from sympde.topology import InteriorDomain, Union +from sympde.topology import Boundary, NormalVector, TangentVector +from sympde.topology import Domain +from sympde.topology import Trace, trace_0, trace_1 +from sympde.topology import Mapping +from sympde.topology import Square +from sympde.topology import ElementDomain +from sympde.topology import Area + +from sympde.expr import BilinearForm, LinearForm, Integral +from sympde.expr import atomize +from sympde.expr import evaluate +from sympde.expr import Mass, Stiffness, Advection, AdvectionT +from sympde.expr import Projection +from sympde.expr import Norm +from sympde.expr import FormCall +from sympde.expr import is_linear_form, is_bilinear_form +from sympde.expr import linearize + +from sympde.expr.errors import UnconsistentError +from sympde.expr.errors import UnconsistentLinearExpressionError +from sympde.expr.errors import UnconsistentLhsError +from sympde.expr.errors import UnconsistentRhsError +from sympde.expr.errors import UnconsistentBCError + +DIM = 2 +VERBOSE = False +VERBOSE = True + +#============================================================================== +def test_boundary_2d_1(): + domain = Domain('Omega', dim=DIM) + + V1 = FunctionSpace('V1', domain) + V2 = FunctionSpace('V2', domain) + U1 = FunctionSpace('U1', domain) + U2 = FunctionSpace('U2', domain) + W1 = VectorFunctionSpace('W1', domain) + W2 = VectorFunctionSpace('W2', domain) + T1 = VectorFunctionSpace('T1', domain) + T2 = VectorFunctionSpace('T2', domain) + + v1 = TestFunction(V1, name='v1') + v2 = TestFunction(V2, name='v2') + u1 = TestFunction(U1, name='u1') + u2 = TestFunction(U2, name='u2') + w1 = VectorTestFunction(W1, name='w1') + w2 = VectorTestFunction(W2, name='w2') + t1 = VectorTestFunction(T1, name='t1') + t2 = VectorTestFunction(T2, name='t2') + + x,y = V1.coordinates + + alpha = Constant('alpha') + + B1 = Boundary(r'\Gamma_1', domain) + B2 = Boundary(r'\Gamma_2', domain) + B3 = Boundary(r'\Gamma_3', domain) + + # ... + with pytest.raises(UnconsistentError): + expr = dot(grad(v1), grad(u1)) + v1*trace_0(u1, B1) + a = BilinearForm((v1,u1), expr, name='a') + # ... + + # ... + with pytest.raises(UnconsistentError): + expr = v1*trace_0(u1, B3) + v1*trace_1(grad(u1), B3) + u1*trace_0(v1, B2) + a1 = BilinearForm((v1, u1), expr, name='a1') + # ... + + # ... + expr = dot(grad(v1), grad(u1)) + a_0 = BilinearForm((v1,u1), expr, name='a_0') + + expr = v1*trace_0(u1, B1) + a_bnd = BilinearForm((v1, u1), expr, name='a_bnd') + + expr = a_0(v1,u1) + a_bnd(v1,u1) + a = BilinearForm((v1,u1), expr, name='a') + print(a) + print(evaluate(a, verbose=True)) + print('') +# import sys; sys.exit(0) + # ... + + + # ... + expr = v1*trace_0(u1, B1) + v1*trace_1(grad(u1), B1) + a1 = BilinearForm((v1, u1), expr, name='a1') + + expr = u1*trace_1(grad(v1), B2) + a2 = BilinearForm((v1, u1), expr, name='a2') + + expr = a1(v2, u2) + a2(v2, u2) + # as expected, we can define the form call, but we cannot create a Bilinear + # form out of it. + # TODO add assert on exception type +# a = BilinearForm((v2, u2), expr, name='a') + + print(expr) + print('') + # ... + + # ... + expr = v1*trace_0(u1, B1) + a0 = BilinearForm((v1, u1), expr, name='a0') + + expr = v1*trace_1(grad(u1), B1) + a1 = BilinearForm((v1, u1), expr, name='a1') + + expr = v1*trace_1(grad(u1), B2) + a2 = BilinearForm((v1, u1), expr, name='a2') + + expr = dot(grad(u1), grad(v1)) + a3 = BilinearForm((v1, u1), expr, name='a3') + + expr = u1*v1 + a4 = BilinearForm((v1, u1), expr, name='a4') + + # TODO Mul not treated yet +# expr = a0(v2, u2) + a1(v2, u2) + alpha * a2(v2, u2) + a3(v2, u2) + alpha*a4(v2, u2) +# a = BilinearForm((v2, u2), expr, name='a') +## print(expr) +# print(evaluate(expr, verbose=True)) +# print('') +# +# print(evaluate(a, verbose=True)) +# print('') + + +# expr = a(v2, u2) + a1(v2, u2) +# b = BilinearForm((v2, u2), expr, name='b') +# print(b) +# print(evaluate(b, verbose=True)) + # ... + + # ... + g = Tuple(x**2, y**2) + expr = v1*trace_1(g, B1) + l1 = LinearForm(v1, expr, name='l1') + print(l1) +# print(atomize(l1)) +# print(evaluate(l1)) + print('') + # ... + +#============================================================================== +def test_boundary_2d_2(): + Omega_1 = InteriorDomain('Omega_1', dim=2) + + B1 = Boundary('B1', Omega_1) + B2 = Boundary('B2', Omega_1) + B3 = Boundary('B3', Omega_1) + + domain = Domain('Omega', interiors=[Omega_1], + boundaries=[B1, B2, B3]) + + V = FunctionSpace('V', domain) + v = TestFunction(V, name='v') + u = TestFunction(V, name='u') + + x,y = V.coordinates + + alpha = Constant('alpha') + + # ... + print('==== l0 ====') + l0 = LinearForm(v, x*y*v, name='l0') + + print(evaluate(l0, verbose=VERBOSE)) + print('') + # ... + + # ... + print('==== l1 ====') + g = Tuple(x**2, y**2) + l1 = LinearForm(v, v*trace_1(g, domain.boundary)) + + print(evaluate(l1, verbose=VERBOSE)) + print('') + # ... + + # ... + print('==== l2 ====') + B_neumann = Union(B1, B2) + g = Tuple(x**2, y**2) + l2 = LinearForm(v, v*trace_1(g, B_neumann), name='l2') + + print(evaluate(l2, verbose=VERBOSE)) + print('') + # ... + + # ... + print('==== l3 ====') + l3 = LinearForm(v, l2(v)) + + assert(l3(v).__str__ == l2(v).__str__) + + print(evaluate(l3, verbose=VERBOSE)) + print('') + # ... + + # ... + print('==== l4 ====') + l4 = LinearForm(v, l0(v) + l2(v)) + + print(evaluate(l4, verbose=VERBOSE)) + print('') + # ... + +# # ... +# print('==== a1 ====') +# a1 = BilinearForm((v, u), v*trace_0(u, domain.boundary)) +# +# print(evaluate(a1, verbose=VERBOSE)) +# print('') +# # ... + + +#============================================================================== +def test_calls_2d(): + domain = Domain('Omega', dim=DIM) + + V1 = FunctionSpace('V1', domain) + V2 = FunctionSpace('V2', domain) + U1 = FunctionSpace('U1', domain) + U2 = FunctionSpace('U2', domain) + W1 = VectorFunctionSpace('W1', domain) + W2 = VectorFunctionSpace('W2', domain) + T1 = VectorFunctionSpace('T1', domain) + T2 = VectorFunctionSpace('T2', domain) + + v1 = TestFunction(V1, name='v1') + v2 = TestFunction(V2, name='v2') + u1 = TestFunction(U1, name='u1') + u2 = TestFunction(U2, name='u2') + w1 = VectorTestFunction(W1, name='w1') + w2 = VectorTestFunction(W2, name='w2') + t1 = VectorTestFunction(T1, name='t1') + t2 = VectorTestFunction(T2, name='t2') + + V = ProductSpace(V1, V2) + U = ProductSpace(U1, U2) + + x,y = V1.coordinates + + alpha = Constant('alpha') + + F = Field('F', space=V1) + + # ... + a1 = BilinearForm((v1, u1), u1*v1, name='a1') + print(a1) + print(atomize(a1)) + print(evaluate(a1)) + print('') + + expr = a1(v2, u2) + a = BilinearForm((v2, u2), expr, name='a') + print(a) + print(atomize(a)) + print(evaluate(a)) + print('') + # ... + + # ... + a = BilinearForm((v1, u1), dot(grad(v1), grad(u1)), name='a') + + print(a) + print(atomize(a)) + print(evaluate(a)) + print('') + # ... + + # ... + a1 = BilinearForm((v1, u1), dot(grad(v1), grad(u1)), name='a1') + + expr = a1(v2, u2) + a = BilinearForm((v2, u2), expr, name='a') + print(a) + print(atomize(a)) + print(evaluate(a)) + print('') + # ... + + # ... + a1 = BilinearForm((v1, u1), u1*v1, name='a1') + a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') + + expr = a1(v2, u2) + a2(v2, u2) + a = BilinearForm((v2, u2), expr, name='a') + print(a) + print(atomize(a)) + print(evaluate(a)) + print('') + # ... + + # ... + a1 = BilinearForm((v1, u1), u1*v1, name='a1') + a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') + + expr = a1(v1, u2) + print('> before = ', expr) + expr = expr.subs(u2, u1) + print('> after = ', expr) + print('') + + expr = a1(v1, u2) + a1(v2, u2) + print('> before = ', expr) + expr = expr.subs(u2, u1) + print('> after = ', expr) + print('') + # ... + + # ... + a1 = BilinearForm((v1, u1), u1*v1, name='a1') + a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') + + expr = a1(v1, u2) + a2(v2, u1) + a = BilinearForm(((v1,v2),(u1,u2)), expr, name='a') + print(a) + print(atomize(a)) + print(evaluate(a)) + print('') + # ... + + # ... + a = BilinearForm((w1, t1), rot(w1)*rot(t1) + div(w1)*div(t1), name='a') + print(a) + print(atomize(a)) + print(evaluate(a)) + # ... + + # ... + a1 = BilinearForm((v1, u1), u1*v1, name='a1') + a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), name='a2') + a3 = BilinearForm((w1, t1), rot(w1)*rot(t1) + div(w1)*div(t1), name='a3') + a4 = BilinearForm((w1, u1), div(w1)*u1, name='a4') + + expr = a3(w2,t2) + a2(v2,u2) + a4(w2,u2) + a = BilinearForm(((w2,v2),(t2,u2)), expr, name='a') + print(a) + print(atomize(a)) + print(evaluate(a)) + # ... + + # ... + a1 = BilinearForm((v1, u1), laplace(u1)*laplace(v1), name='a1') + print(a1) + print(atomize(a1)) + print(evaluate(a1)) + print('') + # ... + + # ... + a1 = BilinearForm((v1, u1), inner(hessian(u1),hessian(v1)), name='a1') + print('================================') + print(a1) + print(atomize(a1)) + print(evaluate(a1)) + print('') + # ... + + # ... + l1 = LinearForm(v1, x*y*v1, name='11') + + expr = l1(v2) + l = LinearForm(v2, expr, name='1') + print(l) + print(atomize(l)) + print(evaluate(l)) + # ... + + # ... + l1 = LinearForm(v1, x*y*v1, name='l1') + l2 = LinearForm(v2, cos(x+y)*v2, name='l2') + + expr = l1(u1) + l2(u2) + l = LinearForm((u1,u2), expr, name='1') + print(l) + print(atomize(l)) + print(evaluate(l)) + # ... + + # ... + l1 = LinearForm(v1, x*y*v1, name='l1') + l2 = LinearForm(v2, cos(x+y)*v2, name='l2') + + expr = l1(u1) + alpha * l2(u2) + l = LinearForm((u1,u2), expr, name='1') + print(l) + print(atomize(l)) + print(evaluate(l)) + # ... + + # ... + l1 = LinearForm(v1, x*y*v1, name='l1') + l2 = LinearForm(w1, div(w1), name='l2') + + expr = l1(v2) + l2(w2) + l = LinearForm((v2,w2), expr, name='1') + print(l) + print(atomize(l)) + print(evaluate(l)) + # ... + + # ... + I1 = Integral(x*y, domain, name='I1') + + print(I1) + print(atomize(I1)) + print(evaluate(I1)) + # ... + + # ... + expr = F - cos(2*pi*x)*cos(3*pi*y) + expr = dot(grad(expr), grad(expr)) + I2 = Integral(expr, domain, name='I2') + + print(I2) + print(atomize(I2)) + print(evaluate(I2)) + # ... + + # ... + expr = F - cos(2*pi*x)*cos(3*pi*y) + expr = dot(grad(expr), grad(expr)) + I2 = Integral(expr, domain, name='I2') + + print(I2) + print(atomize(I2)) + print(evaluate(I2)) + # ... + + # ... stokes + V = VectorFunctionSpace('V', domain) + W = FunctionSpace('W', domain) + + v = VectorTestFunction(V, name='v') + u = VectorTestFunction(V, name='u') + p = TestFunction(W, name='p') + q = TestFunction(W, name='q') + + a = BilinearForm((v,u), inner(grad(v), grad(u)), name='a') + b = BilinearForm((v,p), div(v)*p, name='b') + A = BilinearForm(((v,q),(u,p)), a(v,u) - b(v,p) + b(u,q), name='A') + + print(A) + print(atomize(A)) + print(evaluate(A)) + # ... + +#============================================================================== +def test_projection_2d(): + domain = Domain('Omega', dim=DIM) + + V = FunctionSpace('V', domain) + x,y = domain.coordinates + + alpha = Constant('alpha') + + u = Projection(x**2+alpha*y, V, name='u') + + +#============================================================================== +def test_norm_2d(): + domain = Domain('Omega', dim=DIM) + + x,y = domain.coordinates + V = FunctionSpace('V', domain) + F = Field('F', V) + + # ... + expr = x*y + l2_norm_u = Norm(expr, domain, kind='l2') + h1_norm_u = Norm(expr, domain, kind='h1') + + print('> l2 norm = ', evaluate(l2_norm_u)) + print('> h1 norm = ', evaluate(h1_norm_u)) + print('') + # ... + + # ... + expr = sin(pi*x)*sin(pi*y) + l2_norm_u = Norm(expr, domain, kind='l2') + h1_norm_u = Norm(expr, domain, kind='h1') + + print('> l2 norm = ', evaluate(l2_norm_u)) + print('> h1 norm = ', evaluate(h1_norm_u)) + print('') + # ... + + # ... + expr = F-x*y + l2_norm_u = Norm(expr, domain, kind='l2') + h1_norm_u = Norm(expr, domain, kind='h1') + + print('> l2 norm = ', evaluate(l2_norm_u)) + print('> h1 norm = ', evaluate(h1_norm_u)) + print('') + # ... + + # ... + expr = F-sin(pi*x)*sin(pi*y) + l2_norm_u = Norm(expr, domain, kind='l2') + h1_norm_u = Norm(expr, domain, kind='h1') + + print('> l2 norm = ', evaluate(l2_norm_u)) + print('> h1 norm = ', evaluate(h1_norm_u)) + print('') + # ... + + # ... + expr = F-sin(0.5*pi*(1.-x))*sin(pi*y) + l2_norm_u = Norm(expr, domain, kind='l2') + h1_norm_u = Norm(expr, domain, kind='h1') + + print('> l2 norm = ', evaluate(l2_norm_u)) + print('> h1 norm = ', evaluate(h1_norm_u)) + print('') + # ... + + # ... + expr = F-cos(0.5*pi*x)*sin(pi*y) + l2_norm_u = Norm(expr, domain, kind='l2') + h1_norm_u = Norm(expr, domain, kind='h1') + + print('> l2 norm = ', evaluate(l2_norm_u)) + print('> h1 norm = ', evaluate(h1_norm_u)) + print('') + # ... + + +#============================================================================== +def test_vector_2d_1(): + domain = Domain('Omega', dim=DIM) + + W1 = VectorFunctionSpace('W1', domain) + T1 = VectorFunctionSpace('T1', domain) + + w1 = VectorTestFunction(W1, name='w1') + t1 = VectorTestFunction(T1, name='t1') + + x,y = W1.coordinates + + F = VectorField(W1, 'F') + +# # ... +# l1 = LinearForm(w1, dot(w1, F), name='l1') +# print(l1) +# print(atomize(l1)) +# print(evaluate(l1)) +# print('') +# # ... +# +# # ... +# l2 = LinearForm(w1, rot(w1)*rot(F) + div(w1)*div(F), name='l2') +# print(l2) +# print(atomize(l2)) +# print(evaluate(l2)) +# print('') +# # ... + + # ... + f = Tuple(sin(pi*x)*sin(pi*y), sin(pi*x)*sin(pi*y)) + error = Matrix([F[0]-f[0], F[1]-f[1]]) + l2_norm = Norm(error, domain, kind='l2') + print(l2_norm) + print(atomize(l2_norm)) + print(evaluate(l2_norm)) + print('') + # ... + + # ... + f = Tuple(sin(pi*x)*sin(pi*y), sin(pi*x)*sin(pi*y)) + error = Matrix([F[0]-f[0], F[1]-f[1]]) + h1_norm = Norm(error, domain, kind='h1') + print(h1_norm) + print(atomize(h1_norm)) + print(evaluate(h1_norm)) + print('') + # ... + +#============================================================================== +def test_expr_mapping_2d(): + + F = Mapping('F', DIM) + patch = Domain('Omega', dim=DIM) + domain = F(patch) + + V = FunctionSpace('V', domain) + v = TestFunction(V, name='v') + u = TestFunction(V, name='u') + + x,y = V.coordinates + + a = BilinearForm((v,u), dot(grad(v), grad(u))) + assert(a.mapping is F) + + l = LinearForm(v, x*y*v) + assert(l.mapping is F) + +#============================================================================== +def test_system_2d(): + + domain = Square() + + V = FunctionSpace('V', domain) + x,y = V.coordinates + + u,v,p,q = [TestFunction(V, name=i) for i in ['u','v','p','q']] + + a1,a2,b1,b2 = [Constant(i, real=True) for i in ['a1','a2','b1','b2']] + + # ... + a = BilinearForm((v,u), dot(grad(u), grad(v))) + m = BilinearForm((v,u), u*v) + + expr = a(p,u) + a1*m(p,u) + b1*m(p,v) + a(q,v) + a2*m(q,u) + b2*m(q,v) + b = BilinearForm(((p,q), (u,v)), expr) + + print(evaluate(b, verbose=True)) + # ... + + # ... + f1 = x*y + f2 = x+y + l1 = LinearForm(p, f1*p) + l2 = LinearForm(q, f2*q) + + expr = l1(p) + l2(q) + l = LinearForm((p,q), expr) + + print(evaluate(l, verbose=True)) + # ... + +#============================================================================== +def test_curldiv_2d(): + + domain = Square() + + W1 = VectorFunctionSpace('W1', domain) + T1 = VectorFunctionSpace('T1', domain) + + w1 = VectorTestFunction(W1, name='w1') + t1 = VectorTestFunction(T1, name='t1') + + mu = Constant('mu') + + # ... + a = BilinearForm((w1, t1), rot(w1)*rot(t1) + mu*div(w1)*div(t1), name='a') + print(a) + print(atomize(a)) + print(evaluate(a)) + # ... + + +#============================================================================== +def test_calls_2d_2(): + + domain = Square() + + V = FunctionSpace('V', domain) + x,y = V.coordinates + + u,v = [TestFunction(V, name=i) for i in ['u','v']] + Un = Field('Un', V) + + # ... + a = BilinearForm((v,u), dot(grad(u), grad(v))) + + expr = a(v, Un) + print(evaluate(expr, verbose=True)) + # ... + + # ... + l = LinearForm(v, a(v, Un)) + + print(evaluate(l, verbose=True)) + # ... + +#============================================================================== +def test_calls_2d_3(): + + domain = Square() + + V = FunctionSpace('V', domain) + + x,y = domain.coordinates + + pn = Field('pn', V) + wn = Field('wn', V) + + dp = TestFunction(V, name='dp') + dw = TestFunction(V, name='dw') + tau = TestFunction(V, name='tau') + sigma = TestFunction(V, name='sigma') + + Re = Constant('Re', real=True) + dt = Constant('dt', real=True) + alpha = Constant('alpha', real=True) + + l1 = LinearForm(tau, bracket(pn, wn)*tau - 1./Re * dot(grad(tau), grad(wn))) + + # ... + l = LinearForm((tau, sigma), dt*l1(tau)) + + print(evaluate(l, verbose=True)) + # ... + +#============================================================================== +def test_evaluation_2d_1(): + domain = Domain('Omega', dim=2) + B_neumann = Boundary(r'\Gamma_1', domain) + + V = FunctionSpace('V', domain) + W = VectorFunctionSpace('W', domain) + + p,q = [TestFunction(V, name=i) for i in ['p', 'q']] + u,v = [VectorTestFunction(W, name=i) for i in ['u', 'v']] + + alpha = Constant('alpha') + + x,y = V.coordinates + F = Field('F', space=V) + + a1 = BilinearForm((p, q), dot(grad(p), grad(q))) + m = BilinearForm((p, q), p*q) + a2 = BilinearForm((p, q), a1(p,q) + alpha*m(p,q)) + a3 = BilinearForm((u, v), rot(u)*rot(v) + alpha*div(u)*div(v)) + + a11 = BilinearForm((v,u), inner(grad(v), grad(u))) + a12 = BilinearForm((v,p), div(v)*p) + a4 = BilinearForm(((v,q),(u,p)), a11(v,u) - a12(v,p) + a12(u,q)) + + l0 = LinearForm(p, F*p) + l_neu = LinearForm(p, p*trace_1(grad(F), B_neumann)) + l = LinearForm(p, l0(p) + l_neu(p)) + + # ... + print(a1) + print(evaluate(a1)) + print('') + # ... + + # ... + print(a2) + print(evaluate(a2)) + print('') + # ... + + # ... + print(a3) + print(evaluate(a3)) + print('') + # ... + + # ... + print(a4) + print(evaluate(a4)) + print('') + # ... + + # ... + print(l) + print(evaluate(l)) + print('') + # ... + +#============================================================================== +def test_evaluation_2d_2(): + domain = Square() + x,y = domain.coordinates + + f0 = Tuple(2*pi**2*sin(pi*x)*sin(pi*y), + 2*pi**2*sin(pi*x)*sin(pi*y)) + + f1 = cos(pi*x)*cos(pi*y) + + W = VectorFunctionSpace('W', domain) + V = FunctionSpace('V', domain) + X = ProductSpace(W, V) + + # TODO improve: naming are not given the same way + F = VectorField(W, name='F') + G = Field('G', V) + + u,v = [VectorTestFunction(W, name=i) for i in ['u', 'v']] + p,q = [ TestFunction(V, name=i) for i in ['p', 'q']] + + a0 = BilinearForm((v,u), inner(grad(v), grad(u))) + a1 = BilinearForm((q,p), p*q) + a = BilinearForm(((v,q),(u,p)), a0(v,u) + a1(q,p)) + + l0 = LinearForm(v, dot(f0, v)) + l1 = LinearForm(q, f1*q) + l = LinearForm((v,q), l0(v) + l1(q)) + + # ... + print(a) + print(evaluate(a)) + print('') + # ... + + # ... + print(l) + print(evaluate(l)) + print('') + # ... + +#============================================================================== +def test_linearity_2d_1(): + domain = Square() + x,y = domain.coordinates + + alpha = Constant('alpha') + + f1 = x*y + f2 = x+y + f = Tuple(f1, f2) + + V = FunctionSpace('V', domain) + + # TODO improve: naming are not given the same way + G = Field('G', V) + + p,q = [TestFunction(V, name=i) for i in ['p', 'q']] + + ##################################### + # linear expressions + ##################################### + # ... + expr = p + assert(is_linear_form(expr, p)) + # ... + + # ... + expr = alpha*p + assert(is_linear_form(expr, p)) + # ... + + # ... + expr = dx(p) + assert(is_linear_form(expr, p)) + # ... + + # ... + expr = dot(grad(p), f) + assert(is_linear_form(expr, p)) + # ... + + # ... + expr = laplace(p) + assert(is_linear_form(expr, p)) + # ... + + # ... + expr = alpha*p + dot(grad(p), f) + dx(p) + laplace(p) + assert(is_linear_form(expr, p)) + # ... + ##################################### + + ##################################### + # nonlinear expressions + ##################################### + # ... + with pytest.raises(UnconsistentLinearExpressionError): + expr = p**2 + is_linear_form(expr, p) + # ... + + # ... + with pytest.raises(UnconsistentLinearExpressionError): + expr = dot(grad(p), grad(p)) + is_linear_form(expr, p) + # ... + ##################################### + +# expr = dot(grad(p), grad(p)) +# print(is_linear_form(expr, p)) + + +#============================================================================== +def test_bilinearity_2d_1(): + domain = Square() + x,y = domain.coordinates + + alpha = Constant('alpha') + beta = Constant('beta') + + f1 = x*y + f2 = x+y + f = Tuple(f1, f2) + + V = FunctionSpace('V', domain) + + # TODO improve: naming are not given the same way + G = Field('G', V) + + p,q = [TestFunction(V, name=i) for i in ['p', 'q']] + + ##################################### + # linear expressions + ##################################### + # ... + expr = p*q + assert(is_bilinear_form(expr, (p,q))) + # ... + + # ... + expr = dot(grad(p), grad(q)) + assert(is_bilinear_form(expr, (p,q))) + # ... + + # ... + expr = alpha*dot(grad(p), grad(q)) + beta*p*q + laplace(p)*laplace(q) + assert(is_bilinear_form(expr, (p,q))) + # ... + ##################################### + + ##################################### + # nonlinear expressions + ##################################### + # ... + with pytest.raises(UnconsistentLinearExpressionError): + expr = alpha*dot(grad(p**2), grad(q)) + beta*p*q + is_bilinear_form(expr, (p,q)) + # ... + ##################################### + +# expr = p*q +# print(is_bilinear_form(expr, (p,q))) + +#============================================================================== +def test_linearity_2d_2(): + domain = Domain('Omega', dim=DIM) + + V1 = FunctionSpace('V1', domain) + V2 = FunctionSpace('V2', domain) + U1 = FunctionSpace('U1', domain) + U2 = FunctionSpace('U2', domain) + W1 = VectorFunctionSpace('W1', domain) + W2 = VectorFunctionSpace('W2', domain) + T1 = VectorFunctionSpace('T1', domain) + T2 = VectorFunctionSpace('T2', domain) + + v1 = TestFunction(V1, name='v1') + v2 = TestFunction(V2, name='v2') + u1 = TestFunction(U1, name='u1') + u2 = TestFunction(U2, name='u2') + w1 = VectorTestFunction(W1, name='w1') + w2 = VectorTestFunction(W2, name='w2') + t1 = VectorTestFunction(T1, name='t1') + t2 = VectorTestFunction(T2, name='t2') + + V = ProductSpace(V1, V2) + U = ProductSpace(U1, U2) + + x,y = V1.coordinates + + alpha = Constant('alpha') + + F = Field('F', space=V1) + + # ... + l1 = LinearForm(v1, x*y*v1, check=True) + + l = LinearForm(v2, l1(v2), check=True) + # ... + + # ... + l1 = LinearForm(v1, x*y*v1, check=True) + l2 = LinearForm(v2, cos(x+y)*v2, check=True) + + l = LinearForm((u1,u2), l1(u1) + l2(u2), check=True) + # ... + + # ... + l1 = LinearForm(v1, x*y*v1, check=True) + l2 = LinearForm(v2, cos(x+y)*v2, check=True) + + l = LinearForm((u1,u2), l1(u1) + alpha * l2(u2), check=True) + # ... + + # ... + l1 = LinearForm(v1, x*y*v1, check=True) + l2 = LinearForm(w1, div(w1), check=True) + + l = LinearForm((v2,w2), l1(v2) + l2(w2), check=True) + # ... + + ################################ + # non bilinear forms + ################################ + # ... + with pytest.raises(UnconsistentLinearExpressionError): + l = LinearForm(v1, x*y*v1**2, check=True) + # ... + + # ... + with pytest.raises(UnconsistentLinearExpressionError): + l = LinearForm(v1, x*y, check=True) + # ... + ################################ + +#============================================================================== +def test_bilinearity_2d_2(): + domain = Domain('Omega', dim=DIM) + + V1 = FunctionSpace('V1', domain) + V2 = FunctionSpace('V2', domain) + U1 = FunctionSpace('U1', domain) + U2 = FunctionSpace('U2', domain) + W1 = VectorFunctionSpace('W1', domain) + W2 = VectorFunctionSpace('W2', domain) + T1 = VectorFunctionSpace('T1', domain) + T2 = VectorFunctionSpace('T2', domain) + + v1 = TestFunction(V1, name='v1') + v2 = TestFunction(V2, name='v2') + u1 = TestFunction(U1, name='u1') + u2 = TestFunction(U2, name='u2') + w1 = VectorTestFunction(W1, name='w1') + w2 = VectorTestFunction(W2, name='w2') + t1 = VectorTestFunction(T1, name='t1') + t2 = VectorTestFunction(T2, name='t2') + + V = ProductSpace(V1, V2) + U = ProductSpace(U1, U2) + + x,y = V1.coordinates + + alpha = Constant('alpha') + + F = Field('F', space=V1) + + # ... + a1 = BilinearForm((v1, u1), u1*v1, check=True) + a = BilinearForm((v2, u2), a1(v2, u2), check=True) + # ... + + # ... + a = BilinearForm((v1, u1), dot(grad(v1), grad(u1)), check=True) + # ... + + # ... + a1 = BilinearForm((v1, u1), dot(grad(v1), grad(u1)), check=True) + a = BilinearForm((v2, u2), a1(v2, u2), check=True) + # ... + + # ... + a1 = BilinearForm((v1, u1), u1*v1) + a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), check=True) + a = BilinearForm((v2, u2), a1(v2, u2) + a2(v2, u2), check=True) + # ... + + # ... + a1 = BilinearForm((v1, u1), u1*v1, check=True) + a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), check=True) + # ... + + # ... + a1 = BilinearForm((v1, u1), u1*v1, check=True) + a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), check=True) + a = BilinearForm(((v1,v2),(u1,u2)), a1(v1, u2) + a2(v2, u1), check=True) + # ... + + # ... + a = BilinearForm((w1, t1), rot(w1)*rot(t1) + div(w1)*div(t1), check=True) + # ... + + # ... + a1 = BilinearForm((v1, u1), u1*v1, check=True) + a2 = BilinearForm((v1, u1), dx(u1)*dx(v1), check=True) + a3 = BilinearForm((w1, t1), rot(w1)*rot(t1) + div(w1)*div(t1), check=True) + a4 = BilinearForm((w1, u1), div(w1)*u1, check=True) + + a = BilinearForm(((w2,v2),(t2,u2)), a3(w2,t2) + a2(v2,u2) + a4(w2,u2), check=True) + # ... + + # ... + a1 = BilinearForm((v1, u1), laplace(u1)*laplace(v1), check=True) + # ... + + # ... + a1 = BilinearForm((v1, u1), inner(hessian(u1),hessian(v1)), check=True) + # ... + + # ... stokes + V = VectorFunctionSpace('V', domain) + W = FunctionSpace('W', domain) + + v = VectorTestFunction(V, name='v') + u = VectorTestFunction(V, name='u') + p = TestFunction(W, name='p') + q = TestFunction(W, name='q') + + a = BilinearForm((v,u), inner(grad(v), grad(u)), check=True) + b = BilinearForm((v,p), div(v)*p, check=True) + A = BilinearForm(((v,q),(u,p)), a(v,u) - b(v,p) + b(u,q), check=True) + # ... + + ################################ + # non bilinear forms + ################################ + # ... + with pytest.raises(UnconsistentLinearExpressionError): + a = BilinearForm((v1, u1), dot(grad(v1), grad(u1)) + v1, check=True) + # ... + + # ... + with pytest.raises(UnconsistentLinearExpressionError): + a = BilinearForm((v1, u1), v1**2*u1, check=True) + # ... + + # ... + with pytest.raises(UnconsistentLinearExpressionError): + a = BilinearForm((v1, u1), dot(grad(v1), grad(v1)), check=True) + # ... + ################################ + +#============================================================================== +#def test_nonlinear_2d_1(): +# +# domain = Square() +# +# V = FunctionSpace('V', domain) +# x,y = V.coordinates +# +# u,v = [TestFunction(V, name=i) for i in ['u','v']] +# Un = Field('Un', V) +# +# from sympy import diff as sympy_diff +# +# def diff(L, u): +# ls = [] +# expr = evaluate(L) +# for i in expr: +# e = sympy_diff(i.expr, u) +# ls.append(e) +# +# if len(ls) == 1: +# return ls[0] +# +# else: +# return ls +# +# # ... +# expr = Un**2 * dot(grad(Un), grad(v)) +# l = LinearForm(v, expr) +# +# a = diff(l, Un) +# print(a) +# # ... + +#============================================================================== +def test_linearize_2d_1(): + domain = Domain('Omega', dim=DIM) + x,y = domain.coordinates + + V1 = FunctionSpace('V1', domain) + W1 = VectorFunctionSpace('W1', domain) + + v1 = TestFunction(V1, name='v1') + w1 = VectorTestFunction(W1, name='w1') + + alpha = Constant('alpha') + + F = Field('F', space=V1) + G = VectorField(W1, 'G') + + # ... + l = LinearForm(v1, F**2*v1, check=True) + a = linearize(l, F, trials='u1') + print(a) + # ... + + # ... + l = LinearForm(v1, dot(grad(F), grad(F))*v1, check=True) + a = linearize(l, F, trials='u1') + print(a) + # ... + + # ... + l = LinearForm(v1, exp(-F)*v1, check=True) + a = linearize(l, F, trials='u1') + print(a) + # ... + + # ... + l = LinearForm(v1, cos(F)*v1, check=True) + a = linearize(l, F, trials='u1') + print(a) + # ... + + # ... + l = LinearForm(v1, cos(F**2)*v1, check=True) + a = linearize(l, F, trials='u1') + print(a) + # ... + + # ... + l = LinearForm(v1, F**2*dot(grad(F), grad(v1)), check=True) + a = linearize(l, F, trials='u1') + print(a) + # ... + + # ... + l = LinearForm(w1, dot(rot(G), grad(G))*w1, check=True) + a = linearize(l, G, trials='u1') + print(a) + # ... + +#============================================================================== +def test_linearize_2d_2(): + domain = Domain('Omega', dim=DIM) + x,y = domain.coordinates + + V1 = FunctionSpace('V1', domain) + + v1 = TestFunction(V1, name='v1') + + alpha = Constant('alpha') + + F = Field('F', space=V1) + G = Field('G', space=V1) + + # ... + l1 = LinearForm(v1, F**2*v1, check=True) + l = LinearForm(v1, l1(v1)) + + a = linearize(l, F, trials='u1') + print(a) + + expected = linearize(l1, F, trials='u1') + assert( linearize(l, F, trials='u1') == expected ) + # ... + +#============================================================================== +def test_linearize_2d_3(): + """steady Euler equation.""" + domain = Domain('Omega', dim=DIM) + x,y = domain.coordinates + + U = VectorFunctionSpace('U', domain) + W = FunctionSpace('W', domain) + + v = VectorTestFunction(U, name='v') + phi = TestFunction(W, name='phi') + q = TestFunction(W, name='q') + + U_0 = VectorField(U, name='U_0') + Rho_0 = Field('Rho_0', W) + P_0 = Field('P_0', W) + + # ... + expr = div(Rho_0*U_0) * phi + l1 = LinearForm(phi, expr, check=True) + + expr = Rho_0*dot(convect(U_0, grad(U_0)), v) + dot(grad(P_0), v) + l2 = LinearForm(v, expr, check=True) + + expr = dot(U_0, grad(P_0)) * q + P_0 * div(U_0) * q + l3 = LinearForm(q, expr, check=True) + # ... + + a1 = linearize(l1, [Rho_0, U_0], trials=['d_rho', 'd_u']) + print(a1) + print('') + + a2 = linearize(l2, [Rho_0, U_0, P_0], trials=['d_rho', 'd_u', 'd_p']) + print(a2) + print('') + + a3 = linearize(l3, [P_0, U_0], trials=['d_p', 'd_u']) + print(a3) + print('') + + l = LinearForm((phi, v, q), l1(phi) + l2(v) + l3(q)) + a = linearize(l, [Rho_0, U_0, P_0], trials=['d_rho', 'd_u', 'd_p']) + print(a) + +#============================================================================== +def test_area_2d_1(): + + domain = Domain('Omega', dim=2) + x,y = domain.coordinates + + mu = Constant('mu' , is_real=True) + + e = ElementDomain(domain) + area = Area(e) + + V = FunctionSpace('V', domain) + + u,v = [TestFunction(V, name=i) for i in ['u', 'v']] + + # ... + a = BilinearForm((v,u), area * u * v) + # ... + +#============================================================================== +def test_stabilization_2d_1(): + + domain = Domain('Omega', dim=2) + x,y = domain.coordinates + + kappa = Constant('kappa', is_real=True) + mu = Constant('mu' , is_real=True) + + b1 = 1. + b2 = 0. + b = Tuple(b1, b2) + + # right hand side + f = x*y + + e = ElementDomain() + area = Area(e) + + V = FunctionSpace('V', domain) + + u,v = [TestFunction(V, name=i) for i in ['u', 'v']] + + # ... + expr = kappa * dot(grad(u), grad(v)) + dot(b, grad(u)) * v + a = BilinearForm((v,u), expr) + # ... + + # ... + expr = f * v + l = LinearForm(v, expr) + # ... + + # ... + expr = (- kappa * laplace(u) + dot(b, grad(u))) * dot(b, grad(v)) + s1 = BilinearForm((v,u), expr) + + expr = - f * dot(b, grad(v)) + l1 = LinearForm(v, expr) + # ... + + # ... + expr = (- kappa * laplace(u) + dot(b, grad(u))) * ( dot(b, grad(v)) - kappa * laplace(v)) + s2 = BilinearForm((v,u), expr) + + expr = - f * ( dot(b, grad(v)) - kappa * laplace(v)) + l2 = LinearForm(v, expr) + # ... + + # ... + expr = (- kappa * laplace(u) + dot(b, grad(u))) * ( dot(b, grad(v)) + kappa * laplace(v)) + s3 = BilinearForm((v,u), expr) + + expr = - f * ( dot(b, grad(v)) + kappa * laplace(v)) + l3 = LinearForm(v, expr) + # ... + + # ... + expr = a(v,u) + mu*area*s1(v,u) + a1 = BilinearForm((v,u), expr) + # ... + + # ... + expr = a(v,u) + mu*area*s2(v,u) + a2 = BilinearForm((v,u), expr) + # ... + + # ... + expr = a(v,u) + mu*area*s3(v,u) + a3 = BilinearForm((v,u), expr) + # ... + + print(a1) + print(evaluate(a1, verbose=True)) + print('') + + print(a2) + print(evaluate(a2, verbose=True)) + print('') + + print(a3) + print(evaluate(a3, verbose=True)) + print('') + +#============================================================================== +def test_user_function_2d_1(): + + domain = Domain('Omega', dim=2) + x,y = domain.coordinates + + kappa = Constant('kappa', is_real=True) + mu = Constant('mu' , is_real=True) + + # right hand side + f = Function('f') + + V = FunctionSpace('V', domain) + + u,v = [TestFunction(V, name=i) for i in ['u', 'v']] + + # ... + expr = dot(grad(u), grad(v)) + f(x,y) * u * v + a = BilinearForm((v,u), expr) + + print(a) + print(evaluate(a, verbose=True)) + print('') + # ... + + # ... + expr = f(x,y) * v + l = LinearForm(v, expr) + + print(l) + print(evaluate(l, verbose=True)) + print('') + # ... + +#============================================================================== +# CLEAN UP SYMPY NAMESPACE +#============================================================================== + +def teardown_module(): + from sympy import cache + cache.clear_cache() + +def teardown_function(): + from sympy import cache + cache.clear_cache() + +#test_user_function_2d_1() + +#test_area_2d_1() +#test_stabilization_2d_1() + +#test_linearize_2d_1() +#test_linearize_2d_2() +#test_linearize_2d_3() + +#test_linearity_2d_1() +#test_linearity_2d_2() +#test_bilinearity_2d_1() +#test_bilinearity_2d_2() + +#test_boundary_2d_1() +#test_boundary_2d_2() +#test_projection_2d() +#test_norm_2d() +#test_vector_2d_1() +#test_expr_mapping_2d() +#test_system_2d() +#test_curldiv_2d() +#test_calls_2d() +#test_calls_2d_2() +#test_calls_2d_3() +#test_evaluation_2d_1() +#test_evaluation_2d_2() diff --git a/old/test_form_3d.py b/old/test_form_3d.py new file mode 100644 index 00000000..575bd92b --- /dev/null +++ b/old/test_form_3d.py @@ -0,0 +1,110 @@ +# coding: utf-8 + +# TODO - split the asserts between algebraic and weak formulations ones +# - add assert for grad in vector case +# TODO: - __call__ examples are not working anymore + +import pytest + +from sympy import Symbol +from sympy.core.containers import Tuple +from sympy import symbols +from sympy import IndexedBase +from sympy import Matrix +from sympy import Function +from sympy import pi, cos, sin +from sympy import srepr +from sympy.physics.quantum import TensorProduct + +from sympde.core import Constant +from sympde.calculus import grad, dot, inner, cross, rot, curl, div +from sympde.calculus import laplace, hessian +from sympde.topology import (dx, dy, dz) +from sympde.topology import FunctionSpace, VectorFunctionSpace +from sympde.topology import Field, VectorField +from sympde.topology import ProductSpace +from sympde.topology import TestFunction +from sympde.topology import VectorTestFunction +from sympde.topology import Unknown +from sympde.topology import Domain, Boundary, NormalVector, TangentVector +from sympde.topology import Trace, trace_0, trace_1 + +from sympde.expr import BilinearForm, LinearForm, Integral +from sympde.expr import atomize +from sympde.expr import evaluate +from sympde.expr import tensorize +from sympde.expr import Mass, Stiffness, Advection, AdvectionT +from sympde.expr import Projection +from sympde.expr import Norm +from sympde.expr import FormCall + +from sympde.expr.errors import UnconsistentError +from sympde.expr.errors import UnconsistentLhsError +from sympde.expr.errors import UnconsistentRhsError +from sympde.expr.errors import UnconsistentBCError + + +DIM = 3 +domain = Domain('Omega', dim=DIM) + + +#============================================================================== +def test_tensorize_3d(): + + V = FunctionSpace('V', domain) + U = FunctionSpace('U', domain) + W1 = VectorFunctionSpace('W1', domain) + T1 = VectorFunctionSpace('T1', domain) + + v = TestFunction(V, name='v') + u = TestFunction(U, name='u') + w1 = VectorTestFunction(W1, name='w1') + t1 = VectorTestFunction(T1, name='t1') + + x,y,z = domain.coordinates + + alpha = Constant('alpha') + + # ... + expr = dot(grad(v), grad(u)) + a = BilinearForm((v,u), expr, name='a') + print(a) + print(tensorize(a)) + print('') + # ... + + # ... + expr = x*dx(v)*dx(u) + y*dy(v)*dy(u) + a = BilinearForm((v,u), expr, name='a') + print(a) + print(tensorize(a)) + print('') + # ... + + # ... + expr = sin(x)*dx(v)*dx(u) + a = BilinearForm((v,u), expr, name='a') + print(a) + print(tensorize(a)) + print('') + # ... + + # ... + expr = dot(curl(w1), curl(t1)) + div(w1)*div(t1) + a = BilinearForm((w1, t1), expr, name='a') + print(a) + print(tensorize(a)) + print('') + # ... + +#============================================================================== +# CLEAN UP SYMPY NAMESPACE +#============================================================================== + +def teardown_module(): + from sympy import cache + cache.clear_cache() + +def teardown_function(): + from sympy import cache + cache.clear_cache() diff --git a/old/test_tensorize_2d.py b/old/test_tensorize_2d.py new file mode 100644 index 00000000..ab7cb485 --- /dev/null +++ b/old/test_tensorize_2d.py @@ -0,0 +1,136 @@ +# coding: utf-8 + +# TODO - tensorize is not working due to the last changes on calculus + +import pytest + +from sympy import Symbol +from sympy.core.containers import Tuple +from sympy import symbols +from sympy import IndexedBase +from sympy import Matrix +from sympy import Function +from sympy import pi, cos, sin +from sympy import srepr +from sympy.physics.quantum import TensorProduct + +from sympde.core import Constant +from sympde.calculus import grad, dot, inner, cross, rot, curl, div +from sympde.calculus import laplace, hessian, bracket +from sympde.topology import (dx, dy, dz) +from sympde.topology import FunctionSpace, VectorFunctionSpace +from sympde.topology import Field, VectorField +from sympde.topology import ProductSpace +from sympde.topology import TestFunction +from sympde.topology import VectorTestFunction +from sympde.topology import Unknown +from sympde.topology import InteriorDomain, Union +from sympde.topology import Boundary, NormalVector, TangentVector +from sympde.topology import Domain +from sympde.topology import Trace, trace_0, trace_1 +from sympde.topology import Mapping +from sympde.topology import Square + +from sympde.expr import BilinearForm, LinearForm, Integral +from sympde.expr import atomize +from sympde.expr import evaluate +from sympde.expr import tensorize +from sympde.expr import Mass, Stiffness, Advection, AdvectionT +from sympde.expr import Projection +from sympde.expr import Norm +from sympde.expr import FormCall + +from sympde.expr.errors import UnconsistentError +from sympde.expr.errors import UnconsistentLhsError +from sympde.expr.errors import UnconsistentRhsError +from sympde.expr.errors import UnconsistentBCError + +DIM = 2 +VERBOSE = False +VERBOSE = True + +#============================================================================== +def test_tensorize_2d(): + domain = Domain('Omega', dim=DIM) + + V = FunctionSpace('V', domain) + U = FunctionSpace('U', domain) + W1 = VectorFunctionSpace('W1', domain) + T1 = VectorFunctionSpace('T1', domain) + + v = TestFunction(V, name='v') + u = TestFunction(U, name='u') + w1 = VectorTestFunction(W1, name='w1') + t1 = VectorTestFunction(T1, name='t1') + + x,y = domain.coordinates + + alpha = Constant('alpha') + + # ... + expr = dot(grad(v), grad(u)) + a = BilinearForm((v,u), expr, name='a') + print(a) + print(tensorize(a)) + print('') + # ... + + # ... + expr = x*dx(v)*dx(u) + y*dy(v)*dy(u) + a = BilinearForm((v,u), expr, name='a') + print(a) + print(tensorize(a)) + print('') + # ... + + # ... + expr = sin(x)*dx(v)*dx(u) + a = BilinearForm((v,u), expr, name='a') + print(a) + print(tensorize(a)) + print('') + # ... + + # ... +# expr = rot(w1)*rot(t1) + div(w1)*div(t1) + expr = rot(w1)*rot(t1) #+ div(w1)*div(t1) + a = BilinearForm((w1, t1), expr, name='a') + print(a) + print(tensorize(a)) + print('') + # ... + +#============================================================================== +def test_tensorize_2d_stokes(): + domain = Domain('Omega', dim=DIM) + + # ... abstract model + V = VectorFunctionSpace('V', domain) + W = FunctionSpace('W', domain) + + v = VectorTestFunction(V, name='v') + u = VectorTestFunction(V, name='u') + p = TestFunction(W, name='p') + q = TestFunction(W, name='q') + + a = BilinearForm((v,u), inner(grad(v), grad(u)), name='a') + b = BilinearForm((v,p), div(v)*p, name='b') + A = BilinearForm(((v,q),(u,p)), a(v,u) - b(v,p) + b(u,q), name='A') + # ... + + print(A) + print(tensorize(A)) + print('') + + +#============================================================================== +# CLEAN UP SYMPY NAMESPACE +#============================================================================== + +def teardown_module(): + from sympy import cache + cache.clear_cache() + +def teardown_function(): + from sympy import cache + cache.clear_cache() From b370bf86ba4d4d70985e4c1363f326497bec265c Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Wed, 30 Sep 2026 12:47:11 +0200 Subject: [PATCH 12/17] change README to md --- README.md | 100 +++++++++++++++++++++++++++++++++++++++++++ README.rst | 113 ------------------------------------------------- pyproject.toml | 4 +- 3 files changed, 102 insertions(+), 115 deletions(-) create mode 100644 README.md delete mode 100644 README.rst diff --git a/README.md b/README.md new file mode 100644 index 00000000..48989a4b --- /dev/null +++ b/README.md @@ -0,0 +1,100 @@ +# SymPDE + +[![CI status](https://github.com/pyccel/sympde/actions/workflows/testing.yml/badge.svg?branch=master&event=push)](https://github.com/pyccel/sympde/actions/workflows/testing.yml) +[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/pyccel/sympde/master) +[![Documentation Status](https://readthedocs.org/projects/sympde/badge/?version=latest)](http://sympde.readthedocs.io/en/latest/?badge=latest) + +**SymPDE** is a symbolic calculus library for partial differential equations and variational forms. +It can be used to provide capabilities similar to the [FEniCS](https://fenicsproject.org/) project by extending and writing your own *printing* functions. + +Examples of its use can be found in [Psydac](https://github.com/pyccel/psydac) and [Gelato](https://github.com/pyccel/gelato). + +## Installation + +### Set up a virtual environment + +We always recommend working in a Python virtual environment. +To create a new one, we recommend the [`venv`](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/#creating-a-virtual-environment) package: + +```bash +python3 -m venv +``` + +Here, `` is the location where the virtual environment will be created. +A new directory will be created at that location. + +To activate the environment from a new terminal session, run: + +```bash +source /bin/activate +``` + +### Option 1: Install from PyPI + +Make sure that the preferred virtual environment is activated, then run: + +```bash +pip3 install sympde +``` + +This downloads the correct version of SymPDE from [PyPI](https://pypi.org/project/sympde/) and installs it in the virtual environment. + +### Option 2: Install from sources + +First, clone the repository with Git and change to the repository directory: + +```bash +git clone https://github.com/pyccel/sympde.git +cd sympde +``` + +To check out a specific branch, tag, or commit named ``, run `git checkout `. + +- **Static mode** + + Install the source files in the virtual environment with: + + ```bash + pip install . + ``` + + Further changes to the cloned directory are not reflected in the installed package. This is why we call it a **static** installation. + +- **Editable mode** + + To make changes to the library and see them when the package is imported, install SymPDE in **editable** mode: + + ```bash + pip install --editable ".[test]" + ``` + +### Running the tests + +The complete test suite can be run from any directory with: + +```bash +pytest -n auto --dist loadgroup --pyargs sympde -ra +``` + +## For developers + +Because many important SymPDE features are only tested in Psydac, new pull requests should also be tested against the Psydac test suite. +This can be done by opening a pull request in Psydac whose only change is to install the corresponding SymPDE branch. +To achieve this, modify the line corresponding to `sympde` in Psydac's `pyproject.toml` file. + +For instance, to test a new SymPDE branch called `my_feature`, use: + +```python +# Our packages from PyPI +'sympde @ https://github.com/pyccel/sympde/archive/refs/heads/my_feature.zip', +``` + +Similarly, to test an unreleased version of SymPDE called `v0.18.4-trunk`, use: + +```python +# Our packages from PyPI +'sympde @ https://github.com/pyccel/sympde/archive/refs/tags/v0.18.4-trunk.zip', +``` + +Do not forget the comma at the end of the line, as this is an item in a list. +Also note the words `heads` and `tags` in the paths: the former is used for Git branches, while the latter is used for Git tags, which may or may not correspond to GitHub releases. diff --git a/README.rst b/README.rst deleted file mode 100644 index f09cfe63..00000000 --- a/README.rst +++ /dev/null @@ -1,113 +0,0 @@ -SymPDE -====== - -|CI status| |binder| |docs| - -**SymPDE** is a symbolic calculus library for partial differential equations and variational forms. -It can be used to have similar capabilities as the fenics_ project, by extending and writing your own *printing* functions. - -An example of use can be found in psydac_ or gelato_. - -.. _psydac: https://github.com/pyccel/psydac -.. _gelato: https://github.com/pyccel/gelato -.. _fenics: https://fenicsproject.org/ - - -Installation -************ - -Set up a virtual environment -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -We always recommend working in a Python virtual environment. -To create a new one we recommend the venv_ package:: - - python3 -m venv - -.. _venv: https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/#creating-a-virtual-environment - -where ```` is the location to create the virtual environment. -(A new directory will be created at the required location.) - -In order to activate the environment from a new terminal session just run the command :: - - source /bin/activate - -Option 1: Install from PyPI -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Make sure that the preferred virtual environment is activated. Then simply run :: - - pip3 install sympde - -This will download the correct version of SymPDE from PyPI_ and install it in the virtual environment. - -.. _PyPI: https://pypi.org/project/sympde/ - -Option 2: Install from sources -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -First, clone the repository with Git to download the source files, and change the current directory:: - - git clone https://github.com/pyccel/sympde.git - cd sympde - -To check out a specific branch/tag/commit named ````, just use ``git checkout ``. - -* **Static mode** - - To install the source files in the virtual environment just run:: - - pip install . - - Further changes to the cloned directory are not reflected in the installed package. This is why we call it a **static** installation. - -* **Editable mode** - - In order to make changes to the library, and see these changes when the package is imported, SymPDE should be installed in **editable** mode:: - - pip install --editable ".[test]" - -Running the tests -^^^^^^^^^^^^^^^^^ - -The complete test suite can be run from any directory with:: - - pytest -n auto --dist loadgroup --pyargs sympde -ra - -For developers -************** - -Because many important features of SymPDE are only tested in Psydac, new PRs should also be tested against the test suite of Psydac. -This can be done by opening a PR in Psydac, where the only change consists of installing the corresponding branch of SymPDE. -To achieve this, one just needs to modify the line corresponding to ``sympde`` in the ``pyproject.toml`` file. - -For instance, to test a new SymPDE branch called ``my_feature``, one should write - -.. code-block:: python - - # Our packages from PyPi - 'sympde @ https://github.com/pyccel/sympde/archive/refs/heads/my_feature.zip', - -Similarly, to test an unreleased version of SymPDE called ``v0.18.4-trunk``, one should write - -.. code-block:: python - - # Our packages from PyPi - 'sympde @ https://github.com/pyccel/sympde/archive/refs/tags/v0.18.4-trunk.zip', - -Do not forget the comma at the end of the line, as this is an item in a list. -Also, pay attention to the words ``head`` and ``tags`` in the path: the former is used for Git branches, the latter is used for Git tags (which may or may not correspond to GitHub releases). - - -.. |CI status| image:: https://github.com/pyccel/sympde/actions/workflows/testing.yml/badge.svg?branch=master&event=push - :alt: CI status - :target: https://github.com/pyccel/sympde/actions/workflows/testing.yml - -.. |docs| image:: https://readthedocs.org/projects/sympde/badge/?version=latest - :alt: Documentation Status - :target: http://sympde.readthedocs.io/en/latest/?badge=latest - -.. |binder| image:: https://mybinder.org/badge_logo.svg - :alt: Run notebooks in Binder - :target: https://mybinder.org/v2/gh/pyccel/sympde/master diff --git a/pyproject.toml b/pyproject.toml index 7f3269d7..a0641808 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" name = "sympde" version = "0.20.0" description = "Symbolic calculus for partial differential equations (and variational forms)" -readme = "README.rst" +readme = "README.md" requires-python = ">= 3.9" license = "MIT" license-files = ["LICENSE"] @@ -47,7 +47,7 @@ include = ["sympde*"] namespaces = false [tool.setuptools.package-data] -"*" = ["README.rst"] +"*" = ["README.md"] [tool.pytest.ini_options] minversion = "8.0" From 7fde16b92d65a0e92b228c6c66436f156c2af777 Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Wed, 30 Sep 2026 12:58:30 +0200 Subject: [PATCH 13/17] create AUTHORS file --- AUTHORS | 20 ++++++++++++++++++++ pyproject.toml | 4 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 AUTHORS diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..5bf8479b --- /dev/null +++ b/AUTHORS @@ -0,0 +1,20 @@ +Maintainers +----------- +* Yaman Güçlü (original author, project lead) +* Said Hadjout (original author) + +Contributors +------------ +* Ahmed Ratnani (original author) +* Antoine Lavandier +* Martin Campos Pinto +* Tom Caruso +* Jalal Lakhlili +* Alisa Kirkinskaia +* Elena Moral Sánchez +* Alexander Hoffmann +* Valentin Carlier +* Paul Rigor +* Frederik Schnack +* Francesco Patrizi +* Patrick Lagarrigue diff --git a/pyproject.toml b/pyproject.toml index a0641808..ecd04efc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,8 +9,8 @@ description = "Symbolic calculus for partial differential equations (and var readme = "README.md" requires-python = ">= 3.9" license = "MIT" -license-files = ["LICENSE"] -authors = [{name = "Ahmed Ratnani", email = "ratnaniahmed@gmail.com"}] +license-files = ["LICENSE", "AUTHORS"] +authors = [{name = "SymPDE development team"}] maintainers = [ {name = "Yaman Güçlü", email = "yaman.guclu@gmail.com"}, {name = "Said Hadjout"}, From f85db9ad657a5998744f2a96b3110899041c4a0a Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Wed, 30 Sep 2026 13:02:31 +0200 Subject: [PATCH 14/17] add CHANGELOG.md --- CHANGELOG.md | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..c481f87e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,78 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +## [0.20.0] - 2026-09-07 + +### Added + +- #185: Store interface orientations when exporting domain connectivity, allowing them to be restored when loading a domain. +- #185: Add consistency checks when constructing mapped domains. + +### Changed + +- #185: Require an explicit orientation when constructing multipatch interfaces, including through `Interface`, `Domain.join()`, and `Domain.from_file()`. This is a breaking change for callers and domain files that omitted orientation information. +- #185: Clean up expression evaluation and expand its API documentation. +- [DEVELOPER] Run tests in parallel with `pytest-xdist`, while keeping the HDF5 gallery tests serial. + +## [0.19.3] - 2026-07-17 + +### Fixed + +- #187: Avoid redundant symbolic expansion in `is_linear_expression()`, fixing severe slowdowns for some expressions. + +### Changed + +- #187: Refactor and document `is_linear_expression()` and remove its unused `integral` argument. + +## [0.19.2] - 2025-04-02 + +### Changed + +- #177: Drop support for Python 3.8 and require Python 3.9 or newer. +- #177: Add testing and installation support for Python 3.13. + +## [0.19.1] - 2025-03-05 + +### Added + +- #173: Add `Domain.subdomains` and `Domain.mappings`, which consistently return tuples for both single-patch and multipatch domains. +- #173: Allow `Domain.join()` to be called with a single patch. +- [DEVELOPER] Add terminal-expression tests for exact Navier–Stokes solutions. + +### Fixed + +- #170: Mark domain coordinates as real SymPy symbols, avoiding code-generation problems for complex expressions. +- #174: Fix README markup so the project description renders correctly on PyPI. + +### Changed + +- #172: Expand the source-installation and virtual-environment instructions. + +## [0.19.0] - 2024-08-14 + +### Added + +- #154: Add support and continuous-integration testing for Python 3.12. +- #158: Accept NumPy scalar values as parameters of analytical mappings. +- #155: Allow `Domain.join()` connectivity entries to reference patch objects directly instead of only their indices. + +### Changed + +- #155: Document `Domain.join()` and make joined-domain construction less dependent on patch ordering. +- #164: Document how SymPDE branches can be tested against the Psydac test suite. +- #165: Replace the obsolete build badge with the GitHub Actions CI badge. + +### Fixed + +- #167: Fix README markup rejected by the PyPI uploader. + +### Removed + +- #165: Remove the obsolete Travis CI configuration. + +[0.20.0]: https://github.com/pyccel/sympde/compare/v0.19.3...v0.20.0 +[0.19.3]: https://github.com/pyccel/sympde/compare/v0.19.2...v0.19.3 +[0.19.2]: https://github.com/pyccel/sympde/compare/v0.19.1...v0.19.2 +[0.19.1]: https://github.com/pyccel/sympde/compare/v0.19.0...v0.19.1 +[0.19.0]: https://github.com/pyccel/sympde/compare/v0.18.3...v0.19.0 From c4e0dbda0107f9eccc06a37926897abf19e75b0a Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Wed, 30 Sep 2026 14:30:18 +0200 Subject: [PATCH 15/17] AUTHORS by lines added --- AUTHORS | 3 --- 1 file changed, 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 5bf8479b..97ffc109 100644 --- a/AUTHORS +++ b/AUTHORS @@ -9,12 +9,9 @@ Contributors * Antoine Lavandier * Martin Campos Pinto * Tom Caruso -* Jalal Lakhlili * Alisa Kirkinskaia * Elena Moral Sánchez * Alexander Hoffmann * Valentin Carlier * Paul Rigor * Frederik Schnack -* Francesco Patrizi -* Patrick Lagarrigue From 4544e957a7b61969b8581653a28f08538945c5cf Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Thu, 1 Oct 2026 09:57:21 +0200 Subject: [PATCH 16/17] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yaman Güçlü --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 48989a4b..764fae61 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ source /bin/activate Make sure that the preferred virtual environment is activated, then run: ```bash -pip3 install sympde +pip install sympde ``` This downloads the correct version of SymPDE from [PyPI](https://pypi.org/project/sympde/) and installs it in the virtual environment. From 7527eed8ef3bd18734abb3351e9f67d92dd6d192 Mon Sep 17 00:00:00 2001 From: Frederik Schnack Date: Thu, 1 Oct 2026 10:01:30 +0200 Subject: [PATCH 17/17] change AUTHORS --- AUTHORS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 97ffc109..d61f2333 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,11 +1,12 @@ Maintainers ----------- * Yaman Güçlü (original author, project lead) -* Said Hadjout (original author) +* Martin Campos Pinto Contributors ------------ * Ahmed Ratnani (original author) +* Said Hadjout (original author) * Antoine Lavandier * Martin Campos Pinto * Tom Caruso