def interpolate(v, V): """ Return interpolation of a given function into a given finite element space. *Arguments* v a :py:class:`Function <dolfin.functions.function.Function>` or an :py:class:`Expression <dolfin.functions.expression.Expression>` V a :py:class:`FunctionSpace (standard, mixed, etc.) <dolfin.functions.functionspace.FunctionSpaceBase>` *Example of usage* .. code-block:: python v = Expression("sin(pi*x[0])") V = FunctionSpace(mesh, "Lagrange", 1) Iv = interpolate(v, V) """ # Check arguments if not isinstance(V, FunctionSpaceBase): cpp.dolfin_error( "interpolation.py", "compute interpolation", "Illegal function space for interpolation, not a FunctionSpace (%s)" % str(v)) # Compute interpolation Pv = Function(V) Pv.interpolate(v) return Pv
def _butcher_scheme_generator_adm(a, b, c, time, solution, rhs_form, adj): """ Generates a list of forms and solutions for a given Butcher tableau *Arguments* a (2 dimensional numpy array) The a matrix of the Butcher tableau. b (1-2 dimensional numpy array) The b vector of the Butcher tableau. If b is 2 dimensional the scheme includes an error estimator and can be used in adaptive solvers. c (1 dimensional numpy array) The c vector the Butcher tableau. time (_Constant_) A Constant holding the time at the start of the time step solution (_Function_) The prognostic variable rhs_form (ufl.Form) A UFL form representing the rhs for a time differentiated equation adj (_Function_) The derivative of the functional with respect to y_n+1 """ a = _check_abc(a, b, c) size = a.shape[0] DX = _check_form(rhs_form) # Get test function arguments, coefficients = ufl.algorithms.\ extract_arguments_and_coefficients(rhs_form) v = arguments[0] # Create time step dt = Constant(0.1) # rhs forms dolfin_stage_forms = [] ufl_stage_forms = [] # Stage solutions k = [ Function(solution.function_space(), name="k_%d" % i) for i in range(size) ] kbar = [Function(solution.function_space(), name="kbar_%d"%i) \ for i in range(size)] # Create the stage forms y_ = solution ydot = solution.copy() time_ = time time_dep_expressions = _time_dependent_expressions(rhs_form, time) zero_ = ufl.zero(*y_.shape()) forward_forms = [] stage_solutions = [] jacobian_indices = [] # The recomputation of the forward run: for i, ki in enumerate(k): # Check whether the stage is explicit explicit = a[i, i] == 0 # Evaluation arguments for the ith stage evalargs = y_ + dt * sum([float(a[i,j]) * k[j] \ for j in range(i+1)], zero_) time = time_ + dt * c[i] replace_dict = _replace_dict_time_dependent_expression(\ time_dep_expressions, time_, dt, c[i]) replace_dict[y_] = evalargs replace_dict[time_] = time stage_form = ufl.replace(rhs_form, replace_dict) forward_forms.append(stage_form) if explicit: stage_forms = [stage_form] jacobian_indices.append(-1) else: # Create a F=0 form and differentiate it stage_form_implicit = stage_form - ufl.inner(ki, v) * DX stage_forms = [stage_form_implicit, derivative(\ stage_form_implicit, ki)] jacobian_indices.append(0) ufl_stage_forms.append(stage_forms) dolfin_stage_forms.append([Form(form) for form in stage_forms]) stage_solutions.append(ki) for i, kbari in reversed(list(enumerate(kbar))): # Check whether the stage is explicit explicit = a[i, i] == 0 # And now the adjoint linearisation: stage_form_adm = ufl.inner(dt * b[i] * adj, v)*DX + sum(\ [dt * float(a[j,i]) * safe_action(safe_adjoint(derivative(\ forward_forms[j], y_)), kbar[j]) for j in range(i, size)]) if explicit: stage_forms_adm = [stage_form_adm] jacobian_indices.append(-1) else: # Create a F=0 form and differentiate it stage_form_adm -= ufl.inner(kbar[i], v) * DX stage_forms_adm = [ stage_form_adm, derivative(stage_form_adm, kbari) ] jacobian_indices.append(1) ufl_stage_forms.append(stage_forms_adm) dolfin_stage_forms.append([Form(form) for form in stage_forms_adm]) stage_solutions.append(kbari) # Only one last stage if len(b.shape) == 1: last_stage = Form(ufl.inner(adj, v)*DX + sum(\ [safe_action(safe_adjoint(derivative(forward_forms[i], y_)), kbar[i]) \ for i in range(size)])) else: raise Exception("Not sure what to do here") human_form = "unimplemented" return ufl_stage_forms, dolfin_stage_forms, jacobian_indices, last_stage,\ stage_solutions, dt, human_form, adj
def _butcher_scheme_generator_tlm(a, b, c, time, solution, rhs_form, perturbation): """ Generates a list of forms and solutions for a given Butcher tableau *Arguments* a (2 dimensional numpy array) The a matrix of the Butcher tableau. b (1-2 dimensional numpy array) The b vector of the Butcher tableau. If b is 2 dimensional the scheme includes an error estimator and can be used in adaptive solvers. c (1 dimensional numpy array) The c vector the Butcher tableau. time (_Constant_) A Constant holding the time at the start of the time step solution (_Function_) The prognostic variable rhs_form (ufl.Form) A UFL form representing the rhs for a time differentiated equation perturbation (_Function_) The perturbation in the initial condition of the solution """ a = _check_abc(a, b, c) size = a.shape[0] DX = _check_form(rhs_form) # Get test function arguments, coefficients = ufl.algorithms.\ extract_arguments_and_coefficients(rhs_form) v = arguments[0] # Create time step dt = Constant(0.1) # rhs forms dolfin_stage_forms = [] ufl_stage_forms = [] # Stage solutions k = [ Function(solution.function_space(), name="k_%d" % i) for i in range(size) ] kdot = [Function(solution.function_space(), name="kdot_%d"%i) \ for i in range(size)] # Create the stage forms y_ = solution ydot = solution.copy() time_ = time time_dep_expressions = _time_dependent_expressions(rhs_form, time) zero_ = ufl.zero(*y_.shape()) forward_forms = [] stage_solutions = [] jacobian_indices = [] for i, ki in enumerate(k): # Check whether the stage is explicit explicit = a[i, i] == 0 # Evaluation arguments for the ith stage evalargs = y_ + dt * sum([float(a[i,j]) * k[j] \ for j in range(i+1)], zero_) time = time_ + dt * c[i] replace_dict = _replace_dict_time_dependent_expression(time_dep_expressions, \ time_, dt, c[i]) replace_dict[y_] = evalargs replace_dict[time_] = time stage_form = ufl.replace(rhs_form, replace_dict) forward_forms.append(stage_form) # The recomputation of the forward run: if explicit: stage_forms = [stage_form] jacobian_indices.append(-1) else: # Create a F=0 form and differentiate it stage_form_implicit = stage_form - ufl.inner(ki, v) * DX stage_forms = [ stage_form_implicit, derivative(stage_form_implicit, ki) ] jacobian_indices.append(0) ufl_stage_forms.append(stage_forms) dolfin_stage_forms.append([Form(form) for form in stage_forms]) stage_solutions.append(ki) # And now the tangent linearisation: stage_form_tlm = safe_action(derivative(stage_form, y_), perturbation) + \ sum([dt*float(a[i,j]) * safe_action(derivative(\ forward_forms[j], y_), kdot[j]) for j in range(i+1)]) if explicit: stage_forms_tlm = [stage_form_tlm] jacobian_indices.append(-1) else: # Create a F=0 form and differentiate it stage_form_tlm -= ufl.inner(kdot[i], v) * DX stage_forms_tlm = [ stage_form_tlm, derivative(stage_form_tlm, kdot[i]) ] jacobian_indices.append(1) ufl_stage_forms.append(stage_forms_tlm) dolfin_stage_forms.append([Form(form) for form in stage_forms_tlm]) stage_solutions.append(kdot[i]) # Only one last stage if len(b.shape) == 1: last_stage = Form(ufl.inner(perturbation + sum(\ [dt*float(bi)*kdoti for bi, kdoti in zip(b, kdot)], zero_), v)*DX) else: raise Exception("Not sure what to do here") human_form = [] for i in range(size): kterm = " + ".join("%sh*k_%s" % ("" if a[i,j] == 1.0 else \ "%s*"% a[i,j], j) \ for j in range(size) if a[i,j] != 0) if c[i] in [0.0, 1.0]: cih = " + h" if c[i] == 1.0 else "" else: cih = " + %s*h" % c[i] kdotterm = " + ".join("%(a)sh*action(derivative(f(t_n%(cih)s, y_n + "\ "%(kterm)s), kdot_%(i)s" % \ {"a": ("" if a[i,j] == 1.0 else "%s*"% a[i,j], j), "i": i, "cih": cih, "kterm": kterm} \ for j in range(size) if a[i,j] != 0) if len(kterm) == 0: human_form.append("k_%(i)s = f(t_n%(cih)s, y_n)" % { "i": i, "cih": cih }) human_form.append("kdot_%(i)s = action(derivative("\ "f(t_n%(cih)s, y_n), y_n), ydot_n)" % \ {"i": i, "cih": cih}) else: human_form.append("k_%(i)s = f(t_n%(cih)s, y_n + %(kterm)s)" % \ {"i": i, "cih": cih, "kterm": kterm}) human_form.append("kdot_%(i)s = action(derivative(f(t_n%(cih)s, "\ "y_n + %(kterm)s), y_n) + %(kdotterm)s" % \ {"i": i, "cih": cih, "kterm": kterm, "kdotterm": kdotterm}) parentheses = "(%s)" if np.sum(b > 0) > 1 else "%s" human_form.append("ydot_{n+1} = ydot_n + h*" + parentheses % (" + ".join(\ "%skdot_%s" % ("" if b[i] == 1.0 else "%s*" % b[i], i) \ for i in range(size) if b[i] > 0))) human_form = "\n".join(human_form) return ufl_stage_forms, dolfin_stage_forms, jacobian_indices, last_stage, \ stage_solutions, dt, human_form, perturbation
def _butcher_scheme_generator(a, b, c, time, solution, rhs_form): """ Generates a list of forms and solutions for a given Butcher tableau *Arguments* a (2 dimensional numpy array) The a matrix of the Butcher tableau. b (1-2 dimensional numpy array) The b vector of the Butcher tableau. If b is 2 dimensional the scheme includes an error estimator and can be used in adaptive solvers. c (1 dimensional numpy array) The c vector the Butcher tableau. time (_Constant_) A Constant holding the time at the start of the time step solution (_Function_) The prognostic variable rhs_form (ufl.Form) A UFL form representing the rhs for a time differentiated equation """ a = _check_abc(a, b, c) size = a.shape[0] DX = _check_form(rhs_form) # Get test function arguments, coefficients = ufl.algorithms.\ extract_arguments_and_coefficients(rhs_form) v = arguments[0] # Create time step dt = Constant(0.1) # rhs forms dolfin_stage_forms = [] ufl_stage_forms = [] # Stage solutions k = [ Function(solution.function_space(), name="k_%d" % i) for i in range(size) ] jacobian_indices = [] # Create the stage forms y_ = solution time_ = time time_dep_expressions = _time_dependent_expressions(rhs_form, time) zero_ = ufl.zero(*y_.shape()) for i, ki in enumerate(k): # Check whether the stage is explicit explicit = a[i, i] == 0 # Evaluation arguments for the ith stage evalargs = y_ + dt * sum([float(a[i,j]) * k[j] \ for j in range(i+1)], zero_) time = time_ + dt * c[i] replace_dict = _replace_dict_time_dependent_expression(time_dep_expressions, \ time_, dt, c[i]) replace_dict[y_] = evalargs replace_dict[time_] = time stage_form = ufl.replace(rhs_form, replace_dict) if explicit: stage_forms = [stage_form] jacobian_indices.append(-1) else: # Create a F=0 form and differentiate it stage_form -= ufl.inner(ki, v) * DX stage_forms = [stage_form, derivative(stage_form, ki)] jacobian_indices.append(0) ufl_stage_forms.append(stage_forms) dolfin_stage_forms.append([Form(form) for form in stage_forms]) # Only one last stage if len(b.shape) == 1: last_stage = Form(ufl.inner(y_+sum([dt*float(bi)*ki for bi, ki in \ zip(b, k)], zero_), v)*DX) else: # FIXME: Add support for addaptivity in RKSolver and MultiStageScheme last_stage = [Form(ufl.inner(y_+sum([dt*float(bi)*ki for bi, ki in \ zip(b[0,:], k)], zero_), v)*DX), Form(ufl.inner(y_+sum([dt*float(bi)*ki for bi, ki in \ zip(b[1,:], k)], zero_), v)*DX)] # Create the Function holding the solution at end of time step #k.append(solution.copy()) # Generate human form of MultiStageScheme human_form = [] for i in range(size): kterm = " + ".join("%sh*k_%s" % ("" if a[i,j] == 1.0 else \ "%s*"% a[i,j], j) \ for j in range(size) if a[i,j] != 0) if c[i] in [0.0, 1.0]: cih = " + h" if c[i] == 1.0 else "" else: cih = " + %s*h" % c[i] if len(kterm) == 0: human_form.append("k_%(i)s = f(t_n%(cih)s, y_n)" % { "i": i, "cih": cih }) else: human_form.append("k_%(i)s = f(t_n%(cih)s, y_n + %(kterm)s)" % \ {"i": i, "cih": cih, "kterm": kterm}) parentheses = "(%s)" if np.sum(b > 0) > 1 else "%s" human_form.append("y_{n+1} = y_n + h*" + parentheses % (" + ".join(\ "%sk_%s" % ("" if b[i] == 1.0 else "%s*" % b[i], i) \ for i in range(size) if b[i] > 0))) human_form = "\n".join(human_form) return ufl_stage_forms, dolfin_stage_forms, jacobian_indices, last_stage, \ k, dt, human_form, None
def _rush_larsen_scheme_generator(rhs_form, solution, time, order, generalized): """ Generates a list of forms and solutions for a given Butcher tableau *Arguments* rhs_form (ufl.Form) A UFL form representing the rhs for a time differentiated equation solution (_Function_) The prognostic variable time (_Constant_) A Constant holding the time at the start of the time step order (int) The order of the scheme generalized (bool) If True generate a generalized Rush Larsen scheme, linearizing all components. """ DX = _check_form(rhs_form) if DX != ufl.dP: raise TypeError("Expected a form with a Pointintegral.") # Create time step dt = Constant(0.1) # Get test function arguments = rhs_form.arguments() coefficients = rhs_form.coefficients() # Get time dependent expressions time_dep_expressions = _time_dependent_expressions(rhs_form, time) # Extract rhs expressions from form rhs_integrand = rhs_form.integrals()[0].integrand() rhs_exprs, v = extract_tested_expressions(rhs_integrand) vector_rhs = len(v.ufl_shape) > 0 and v.ufl_shape[0] > 1 system_size = v.ufl_shape[0] if vector_rhs else 1 # Fix for indexing of v for scalar expressions v = v if vector_rhs else [v] # Extract linear terms if not using generalized Rush Larsen if not generalized: linear_terms = _find_linear_terms(rhs_exprs, solution) else: linear_terms = [True for _ in range(system_size)] # Wrap the rhs expressions into a ufl vector type rhs_exprs = ufl.as_vector([rhs_exprs[i] for i in range(system_size)]) rhs_jac = ufl.diff(rhs_exprs, solution) # Takes time! if vector_rhs: diff_rhs_exprs = [expand_indices(expand_derivatives(rhs_jac[ind, ind]))\ for ind in range(system_size)] else: diff_rhs_exprs = [expand_indices(expand_derivatives(rhs_jac[0]))] solution = [solution] ufl_stage_forms = [] dolfin_stage_forms = [] dt_stage_offsets = [] # Stage solutions (3 per order rhs, linearized, and final step) # If 2nd order the final step for 1 step is a stage if order == 1: stage_solutions = [] rl_ufl_form = _rush_larsen_step(rhs_exprs, diff_rhs_exprs, linear_terms, \ system_size, solution, None, dt, time, 1.0, \ 0.0, v, DX, time_dep_expressions) elif order == 2: # Stage solution for order 2 if vector_rhs: stage_solutions = [ Function(solution.function_space(), name="y_1/2") ] else: stage_solutions = [ Function(solution[0].function_space(), name="y_1/2") ] stage_form = _rush_larsen_step(rhs_exprs, diff_rhs_exprs, linear_terms, \ system_size, solution, None, dt, time, 0.5, \ 0.0, v, DX, time_dep_expressions) rl_ufl_form = _rush_larsen_step(rhs_exprs, diff_rhs_exprs, linear_terms, \ system_size, solution, stage_solutions[0], dt,\ time, 1.0, 0.5, v, DX, time_dep_expressions) ufl_stage_forms.append([stage_form]) dolfin_stage_forms.append([Form(stage_form)]) # Get last stage form last_stage = Form(rl_ufl_form) human_form = "%srush larsen %s" % ("generalized " if generalized else "", str(order)) return rhs_form, linear_terms, ufl_stage_forms, dolfin_stage_forms, last_stage, \ stage_solutions, dt, dt_stage_offsets, human_form, None