def __call__(self, expr): V = self.space if isinstance(expr, (ScalarFunction, VectorFunction)): if expr.space is V: return expr elif isinstance(expr.projection_of, Projection): if expr.projection_of.projector.space is V: return expr if isinstance(V, (ScalarFunctionSpace, VectorFunctionSpace)): name = 'Proj_' + random_string( 4 ) F = element_of(V, name) else: raise TypeError('Only scalar and vector space are handled') F.set_as_projection(Projection(self, expr)) return F
def __new__(cls, expr, domain, eval=True): if eval: expr = Integral(expr, domain) obj = Basic.__new__(cls, expr, domain) # compute dim from fields if available ls = list(expr.atoms((ScalarField, VectorField))) if ls: F = ls[0] space = F.space else: tag = random_string( 3 ) space_name = 'space_{}'.format(tag) space = ScalarFunctionSpace(space_name, domain) # TODO vector case obj._ldim = domain.dim obj._space = space return obj
def is_linear_expression(expr, args, integral=True, 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, ScalarTestFunction): left = ScalarTestFunction(arg.space, name='l_' + tag) right = ScalarTestFunction(arg.space, name='r_' + tag) elif isinstance(arg, VectorTestFunction): left = VectorTestFunction(arg.space, name='l_' + tag) right = VectorTestFunction(arg.space, name='r_' + tag) else: raise TypeError('argument must be a TestFunction') left_args += [left] right_args += [right] # ... # ... check addition newargs = [left + right for left, right in zip(left_args, right_args)] newexpr = expr.subs(zip(args, newargs)) left_expr = expr.subs(zip(args, left_args)) right_expr = expr.subs(zip(args, right_args)) a = newexpr b = left_expr + right_expr if not ((a - b).expand() == 0): # TODO use a warning or exception? if debug: print('Failed to assert addition property') print('{} != {}'.format(a.expand(), b.expand())) 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) atoms = list(newexpr.atoms(BasicOperator)) subs = [e.func(*e.args, evaluate=True) for e in atoms] newexpr = newexpr.subs(zip(atoms, subs)) left_expr = expr.subs(zip(args, left_args)) left_expr = coeff * left_expr.subs(arg, left) if not ((newexpr - left_expr).expand() == 0): # TODO use a warning or exception? if debug: print('Failed to assert multiplication property') print('{} != {}'.format(newexpr, left_expr)) return False # ... return True
def linearize(form, fields, trials=None): """ Parameters ---------- form : LinearForm Linear form F(v; u) to be linearized. F is nonlinear in the parameter u fields : [Scalar|Vector]TestFunction or tuple Function u with respect to which F should be differentiated. Tuple if element of ProductSpace. trials : [Scalar|Vector]TestFunction or tuple Trial function to be used in resulting bilinear form. Results ------- a : BilinearForm a(u, v) is bilinear form obtained from linearization of F(v; u). """ if not isinstance(form, LinearForm): raise TypeError('> Expecting a LinearForm') # ... if not isinstance(fields, (list, tuple, Tuple)): fields = [fields] for field in fields: if not isinstance(field, (ScalarTestFunction, VectorTestFunction)): raise TypeError('> Expecting a TestFunction', field) # ... if trials: if not isinstance(trials, (list, tuple, Tuple)): trials = [trials] for trial in trials: if not isinstance(trial, (ScalarTestFunction, VectorTestFunction)): raise TypeError('> Expecting a TestFunction', trial) else: trials = [ x.space.element(x.name + '_trial_' + random_string(4)) for x in fields ] # ... eps = Constant('eps_' + random_string(4)) new_fields = [field + eps * trial for field, trial in zip(fields, trials)] integrals = form.expr.args if isinstance(form.expr, Add) else [form.expr] new_integrals = [] for I in integrals: g0 = I.expr g1 = I.expr.subs(zip(fields, new_fields)).expand() dg_du = ((g1 - g0) / eps).series(eps, 0, 2).subs(eps, 0) if dg_du: new_I = integral(I.domain, dg_du) new_integrals.append(new_I) bilinear_expr = reduce(add, new_integrals) tests = form.variables return BilinearForm((trials, tests), bilinear_expr)
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, ScalarTestFunction): left = ScalarTestFunction(arg.space, name='l_' + tag) right = ScalarTestFunction(arg.space, name='r_' + tag) elif isinstance(arg, VectorTestFunction): left = VectorTestFunction(arg.space, name='l_' + tag) right = VectorTestFunction(arg.space, name='r_' + tag) else: raise TypeError('argument must be a TestFunction') 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) integrals = newexpr.atoms(DomainIntegral, BoundaryIntegral) for a in integrals: newexpr,_ = newexpr._xreplace({a:integral(a.domain, a.expr)}) 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( newexpr == left_expr + right_expr ): # TODO use a warning or exception? if debug: print('Failed to assert addition property') print(newexpr , left_expr + right_expr) # 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