diff --git a/patches/apply_patches.sh b/patches/apply_patches.sh index e7a0b5f373139932981fa0e491924b685b6076ff..4abe4fa9de8f80bac0465ccfa7724035ce586063 100755 --- a/patches/apply_patches.sh +++ b/patches/apply_patches.sh @@ -10,6 +10,7 @@ popd pushd python/ufl git apply ../../patches/ufl/conditional-uflid.patch +git apply ../../patches/ufl/0001-Remove-special-case-for-variable-in-ufl2dot.patch popd pushd python/ufl diff --git a/patches/ufl/0001-Remove-special-case-for-variable-in-ufl2dot.patch b/patches/ufl/0001-Remove-special-case-for-variable-in-ufl2dot.patch new file mode 100644 index 0000000000000000000000000000000000000000..db9fb4e5452f7c1f83834105005725b0387700cb --- /dev/null +++ b/patches/ufl/0001-Remove-special-case-for-variable-in-ufl2dot.patch @@ -0,0 +1,31 @@ +From 6f2931706f28cd29e3ed72851a7712815a23f474 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ren=C3=A9=20He=C3=9F?= <rene.hess@iwr.uni-heidelberg.de> +Date: Thu, 9 Nov 2017 14:13:34 +0100 +Subject: [PATCH] Remove special case for variable in ufl2dot + +--- + ufl/formatting/ufl2dot.py | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/ufl/formatting/ufl2dot.py b/ufl/formatting/ufl2dot.py +index 5fdca148..e0387a9b 100644 +--- a/ufl/formatting/ufl2dot.py ++++ b/ufl/formatting/ufl2dot.py +@@ -176,13 +176,8 @@ def build_entities(e, nodes, edges, nodeoffset, prefix="", labeller=None): + if labeller is None: + labeller = ReprLabeller() + +- # Special-case Variable instances +- if isinstance(e, Variable): # FIXME: Is this really necessary? +- ops = (e._expression,) +- label = "variable %d" % e._label._count +- else: +- ops = e.ufl_operands +- label = labeller(e) ++ ops = e.ufl_operands ++ label = labeller(e) + + # Create node for parent e + nodename = "%sn%04d" % (prefix, len(nodes) + nodeoffset) +-- +2.11.0 diff --git a/python/dune/perftool/pdelab/argument.py b/python/dune/perftool/pdelab/argument.py index 5b745af247fd202d9f261ef6873fbf1d7932e923..5c1eef4dc859ce36d78c6c35df0f418db90bbcc6 100644 --- a/python/dune/perftool/pdelab/argument.py +++ b/python/dune/perftool/pdelab/argument.py @@ -9,7 +9,6 @@ from dune.perftool.options import get_option from dune.perftool.generation import (domain, function_mangler, iname, - globalarg, valuearg, get_global_context_value, kernel_cached, diff --git a/python/dune/perftool/pdelab/driver/instationary.py b/python/dune/perftool/pdelab/driver/instationary.py index 9a8eaea45002d6c177c0ffcfeaf2beec9e0594e1..fe2cbc5a5a819c7e274759ab9e91cc61d1b14e34 100644 --- a/python/dune/perftool/pdelab/driver/instationary.py +++ b/python/dune/perftool/pdelab/driver/instationary.py @@ -79,6 +79,8 @@ def time_loop(): return ["", "double T = {}.get<double>(\"instat.T\", 1.0);".format(ini), "double dt = {}.get<double>(\"instat.dt\", 0.1);".format(ini), + "int step_number(0);" + "int output_every_nth = {}.get<int>(\"instat.output_every_nth\", 1);".format(ini), "while (time<T-1e-8){", " // Assemble constraints for new time step", " {}.setTime({}+dt);".format(params, time), @@ -92,8 +94,11 @@ def time_loop(): " {} = {}new;".format(vector, vector), " time += dt;", "", - " // Output to VTK File", - " {}.write({}, Dune::VTK::appendedraw);".format(vtk_sequence_writer, time), + " step_number += 1;", + " if (step_number%output_every_nth == 0){", + " // Output to VTK File", + " {}.write({}, Dune::VTK::appendedraw);".format(vtk_sequence_writer, time), + " }", "}", ""] diff --git a/python/dune/perftool/pdelab/parameter.py b/python/dune/perftool/pdelab/parameter.py index b4a18094159ad1b98ad48336b82e6d1f6de44741..cb3f0154b3906278761976db5961513080d024a3 100644 --- a/python/dune/perftool/pdelab/parameter.py +++ b/python/dune/perftool/pdelab/parameter.py @@ -5,6 +5,7 @@ from dune.perftool.generation import (class_basename, constructor_parameter, generator_factory, get_backend, + get_global_context_value, initializer_list, kernel_cached, preamble, @@ -38,8 +39,11 @@ def define_parameterclass(name): def name_paramclass(): - define_parameterclass("param") - return "param" + formdata = get_global_context_value("formdata") + from dune.perftool.pdelab.driver.gridoperator import name_parameters + name = name_parameters(formdata) + define_parameterclass(name) + return name @class_member(classtag="parameterclass") diff --git a/python/dune/perftool/ufl/execution.py b/python/dune/perftool/ufl/execution.py index 1a0ac249cf4bcb1ebd13312c01a2d5249c515618..30a5b915721d81147ded0fba9946dc0e2f23ae05 100644 --- a/python/dune/perftool/ufl/execution.py +++ b/python/dune/perftool/ufl/execution.py @@ -12,7 +12,7 @@ from ufl import * class TrialFunction(ufl.Coefficient): """ A coefficient that always takes the reserved index 0 """ def __init__(self, element, count=None): - if count and count is not 0: + if count is not None and count != 0: raise PerftoolUFLError("The trial function must be the coefficient of index 0 in uflpdelab") ufl.Coefficient.__init__(self, element, count=0) @@ -20,12 +20,14 @@ class TrialFunction(ufl.Coefficient): class Coefficient(ufl.Coefficient): """ A coefficient that honors the reserved index 0. """ def __init__(self, element, count=None): - if count and count is 0: + if count == 0: raise PerftoolUFLError("The coefficient of index 0 is reserved for the trial function in uflpdelab") - if count and count is 1: + if count == 1: raise PerftoolUFLError("The coefficient of index 1 is reserved for the jacobian apply vector in uflpdelab") - if not count and ufl.Coefficient._globalcount < 2: - count = 2 + if count == 2: + raise PerftoolUFLError("The coefficient of index 2 is reserved for the time variable in uflpdelab") + if count is None and ufl.Coefficient._globalcount < 3: + count = 3 ufl.Coefficient.__init__(self, element, count) @@ -43,3 +45,7 @@ def TestFunctions(element): def TrialFunctions(element): return split(TrialFunction(element)) + + +def get_time(cell): + return Constant(cell, count=2) diff --git a/python/dune/perftool/ufl/visitor.py b/python/dune/perftool/ufl/visitor.py index 7a3b15d201c5968b0eb4524964e4270523d9be1b..2099adb46803f2b8b3afd4c6817da54d0cf33d6e 100644 --- a/python/dune/perftool/ufl/visitor.py +++ b/python/dune/perftool/ufl/visitor.py @@ -3,13 +3,18 @@ This module defines the main visitor algorithm transforming ufl expressions to pymbolic and loopy. """ from dune.perftool.error import PerftoolUFLError -from dune.perftool.generation import get_global_context_value, domain +from dune.perftool.generation import (get_global_context_value, + domain, + globalarg, + valuearg, + ) from dune.perftool.ufl.flatoperators import get_operands from dune.perftool.ufl.modified_terminals import (ModifiedTerminalTracker, Restriction, ) from dune.perftool.tools import maybe_wrap_subscript from dune.perftool.options import get_option +from dune.perftool.pdelab.parameter import name_paramclass, name_time from loopy import Reduction from pymbolic.primitives import (Call, @@ -27,7 +32,8 @@ from ufl import (VectorElement, TensorElement, TensorProductElement, ) -from ufl.classes import (FixedIndex, +from ufl.classes import (Coefficient, + FixedIndex, IndexSum, JacobianDeterminant, ) @@ -152,6 +158,14 @@ class UFL2LoopyVisitor(ModifiedTerminalTracker): else: return self.interface.pymbolic_apply_function(o.ufl_element(), restriction, index) + # In this case it represents the time variable + elif o.count() == 2: + param = name_paramclass() + time = name_time() + name = param + "." + time + valuearg(name, dtype=np.float64) + return Variable(name) + # Check if this is a parameter function else: raise NotImplementedError("Handling non-symbolic parameter functions is currently reevaluated!") diff --git a/test/heatequation/CMakeLists.txt b/test/heatequation/CMakeLists.txt index 7cddb801d7b307261b3ebd208e8115fc9a5d4c9f..a1ada8fad3c359de05b63ce17dca4c4c39d042c7 100644 --- a/test/heatequation/CMakeLists.txt +++ b/test/heatequation/CMakeLists.txt @@ -7,6 +7,11 @@ dune_add_formcompiler_system_test(UFLFILE heatequation.ufl INIFILE heatequation.mini ) +dune_add_formcompiler_system_test(UFLFILE heatequation_time_dependent_bc.ufl + BASENAME heatequation_time_dependent_bc + INIFILE heatequation_time_dependent_bc.mini + ) + #===== # DG #===== diff --git a/test/heatequation/heatequation_time_dependent_bc.mini b/test/heatequation/heatequation_time_dependent_bc.mini new file mode 100644 index 0000000000000000000000000000000000000000..191cc52f1c9ff806496affb5eb6a7d8ebbdb25d9 --- /dev/null +++ b/test/heatequation/heatequation_time_dependent_bc.mini @@ -0,0 +1,25 @@ +__name = heatequation_time_dependent_bc_{__exec_suffix} +__exec_suffix = implicit, explicit | expand scheme + +lowerleft = 0.0 0.0 +upperright = 1.0 1.0 +elements = 16 16 +elementType = simplical + +[wrapper.vtkcompare] +name = {__name} +reference = heatequation_ref +extension = vtu + +[formcompiler] +explicit_time_stepping = 0, 1 | expand scheme +compare_l2errorsquared = 2e-4 + +[instat] +T = 1.0 +dt = 1e-1 +nth = 1 + + +# Disable explicit tests for now +{__exec_suffix} == explicit | exclude diff --git a/test/heatequation/heatequation_time_dependent_bc.ufl b/test/heatequation/heatequation_time_dependent_bc.ufl new file mode 100644 index 0000000000000000000000000000000000000000..ac0079253cc170c757da9ae772eec8e4fd1a6087 --- /dev/null +++ b/test/heatequation/heatequation_time_dependent_bc.ufl @@ -0,0 +1,22 @@ +cell = triangle + +x = SpatialCoordinate(cell) +time = get_time(cell) + +nu = 1.0/10 + +c = (0.5-x[0])**2 + (0.5-x[1])**2 +g = exp(-nu*time) * exp(-1.*c) +f = 4*(1.-c)*g - nu*g + +V = FiniteElement("CG", "triangle", 1) +u = TrialFunction(V) +v = TestFunction(V) + +mass = (u*v)*dx +poisson = (inner(grad(u), grad(v)) - f*v)*dx + +forms = [mass, poisson] +dirichlet_expression = g +is_dirichlet = 1 +exact_solution = g