def derivative(form, coefficient, argument=None, coefficient_derivatives=None): """UFL form operator: Compute the Gateaux derivative of *form* w.r.t. *coefficient* in direction of *argument*. If the argument is omitted, a new ``Argument`` is created in the same space as the coefficient, with argument number one higher than the highest one in the form. The resulting form has one additional ``Argument`` in the same finite element space as the coefficient. A tuple of ``Coefficient`` s may be provided in place of a single ``Coefficient``, in which case the new ``Argument`` argument is based on a ``MixedElement`` created from this tuple. An indexed ``Coefficient`` from a mixed space may be provided, in which case the argument should be in the corresponding subspace of the coefficient space. If provided, *coefficient_derivatives* should be a mapping from ``Coefficient`` instances to their derivatives w.r.t. *coefficient*. """ coefficients, arguments = _handle_derivative_arguments(form, coefficient, argument) if coefficient_derivatives is None: coefficient_derivatives = ExprMapping() else: cd = [] for k in sorted_expr(coefficient_derivatives.keys()): cd += [as_ufl(k), as_ufl(coefficient_derivatives[k])] coefficient_derivatives = ExprMapping(*cd) # Got a form? Apply derivatives to the integrands in turn. if isinstance(form, Form): integrals = [] for itg in form.integrals(): if not isinstance(coefficient, SpatialCoordinate): fd = CoefficientDerivative(itg.integrand(), coefficients, arguments, coefficient_derivatives) else: fd = CoordinateDerivative(itg.integrand(), coefficients, arguments, coefficient_derivatives) integrals.append(itg.reconstruct(fd)) return Form(integrals) elif isinstance(form, Expr): # What we got was in fact an integrand if not isinstance(coefficient, SpatialCoordinate): return CoefficientDerivative(form, coefficients, arguments, coefficient_derivatives) else: return CoordinateDerivative(form, coefficients, arguments, coefficient_derivatives) error("Invalid argument type %s." % str(type(form)))
def coordinate_derivative(self, o, f, dummy_w, dummy_v, dummy_cd): o_ = o.ufl_operands key = (CoordinateDerivative, o_[0]) return CoordinateDerivative(map_expr_dag(self, o_[0], vcache=self.vcaches[key], rcache=self.rcaches[key]), o_[1], o_[2], o_[3])
def scale_coordinate_derivative(o, scale): o_ = o.ufl_operands if isinstance(o, CoordinateDerivative): return CoordinateDerivative( scale_coordinate_derivative(o_[0], scale), o_[1], o_[2], o_[3]) else: return scale * o
def attach_coordinate_derivatives(integral, coordinate_derivatives): if coordinate_derivatives is None: return integral if isinstance(integral, Integral): integrand = integral.integrand() # apply the stored coordinate derivatives back onto the integrand for tup in reversed(coordinate_derivatives): integrand = CoordinateDerivative(integrand, tup[0], tup[1], tup[2]) return integral.reconstruct(integrand=integrand) else: error("Invalid type %s" % (integral.__class__.__name__,))
def attach_coordinate_derivatives(form, coordinate_derivatives): if coordinate_derivatives is None: return form if isinstance(form, Form): cds = coordinate_derivatives new_integrals = [attach_coordinate_derivatives(integ, cds) for integ in form.integrals()] return Form(new_integrals) elif isinstance(form, Integral): integral = form integrand = integral.integrand() # apply the stored coordinate derivatives back onto the integrand for tup in reversed(coordinate_derivatives): integrand = CoordinateDerivative(integrand, tup[0], tup[1], tup[2]) return integral.reconstruct(integrand=integrand) else: error("Invalid type %s" % (form.__class__.__name__,))
def coordinate_derivative(self, o, f, dummy_w, dummy_v, dummy_cd): o_ = o.ufl_operands return CoordinateDerivative(map_expr_dag(self, o_[0]), o_[1], o_[2], o_[3])
def coordinate_derivative(self, o): o = o.ufl_operands return CoordinateDerivative(map_expr_dag(self, o[0]), o[1], o[2], o[3])