Repository: stfc/PSyclone

Issue:
include element_order from an LFRic module in PSyAD test harness
The test harness hard codes element_order to 1. However, it may have a different value and this has caused errors when validating some of the PSyAD-generated LFRic adjoint kernels. The value should instead be included from the appropriate module file `finite_element_config_mod`. 

Discussion:

Patch:
diff --git a/changelog b/changelog
index 621f560a1..92402e14c 100644
--- a/changelog
+++ b/changelog
@@ -479,6 +479,9 @@
 	162) PR #2187 towards #1618. Remove builtin use statements when
 	lowering.
 
+	163) PR #2191 for #2185. Fix element order used in PSyAD test
+	harness.
+
 release 2.3.1 17th of June 2022
 
 	1) PR #1747 for #1720. Adds support for If blocks to PSyAD.
diff --git a/src/psyclone/domain/lfric/algorithm/lfric_alg.py b/src/psyclone/domain/lfric/algorithm/lfric_alg.py
index 4cca91f5e..f29a5bf17 100644
--- a/src/psyclone/domain/lfric/algorithm/lfric_alg.py
+++ b/src/psyclone/domain/lfric/algorithm/lfric_alg.py
@@ -61,11 +61,6 @@ class LFRicAlg:
     layer from Kernel metadata.
 
     '''
-
-    #: The order of the finite-element scheme that will be used by any
-    #: generated algorithm layer.
-    _ELEMENT_ORDER = "1"
-
     def create_from_kernel(self, name, kernel_path):
         '''
         Generates LFRic algorithm PSyIR that calls the supplied kernel through
@@ -240,9 +235,10 @@ class LFRicAlg:
 
     def _create_function_spaces(self, prog, fspaces):
         '''
-        Adds PSyIR to the supplied Routine that declares and intialises the
-        specified function spaces. The order of these spaces is set by the
-        `_ELEMENT_ORDER` class constant.
+        Adds PSyIR to the supplied Routine that declares and intialises
+        the specified function spaces. The order of these spaces is
+        set by the element_order variable which is provided by the
+        LFRic finite_element_config_mod module.
 
         :param prog: the routine to which to add declarations and \
                      initialisation.
@@ -252,20 +248,19 @@ class LFRicAlg:
 
         :raises InternalError: if a function space is supplied that is not a \
                                recognised LFRic function space.
+
         '''
         table = prog.symbol_table
 
         reader = FortranReader()
 
         # The order of the finite-element scheme.
-        table.add_lfric_precision_symbol("i_def")
-        data_type_class = LFRicTypes("LFRicIntegerScalarDataType")
-        order = table.new_symbol("element_order", tag="element_order",
-                                 symbol_type=DataSymbol,
-                                 datatype=data_type_class(),
-                                 constant_value=Literal(
-                                     self._ELEMENT_ORDER,
-                                     data_type_class()))
+        fe_config_mod = table.new_symbol(
+            "finite_element_config_mod", symbol_type=ContainerSymbol)
+        order = table.new_symbol(
+            "element_order", tag="element_order",
+            symbol_type=DataSymbol, datatype=DeferredType(),
+            interface=ImportInterface(fe_config_mod))
 
         fs_cont_mod = table.new_symbol("fs_continuity_mod",
                                        symbol_type=ContainerSymbol)


Test patch:
diff --git a/src/psyclone/tests/domain/lfric/algorithm/lfric_alg_test.py b/src/psyclone/tests/domain/lfric/algorithm/lfric_alg_test.py
index 8aa1aa826..dbc5f56cf 100644
--- a/src/psyclone/tests/domain/lfric/algorithm/lfric_alg_test.py
+++ b/src/psyclone/tests/domain/lfric/algorithm/lfric_alg_test.py
@@ -126,6 +126,9 @@ def test_create_function_spaces_no_spaces(lfric_alg, prog):
     ''' Check that a Routine is populated as expected, even when there
     are no actual function spaces. '''
     lfric_alg._create_function_spaces(prog, [])
+    fe_config_mod = prog.symbol_table.lookup("finite_element_config_mod")
+    element_order = prog.symbol_table.lookup("element_order")
+    assert element_order.interface.container_symbol == fe_config_mod
     assert prog.symbol_table.lookup("element_order")
     assert isinstance(prog.symbol_table.lookup("fs_continuity_mod"),
                       ContainerSymbol)
@@ -144,6 +147,9 @@ def test_create_function_spaces(lfric_alg, prog, fortran_writer):
     ''' Check that a Routine is populated correctly when valid function-space
     names are supplied. '''
     lfric_alg._create_function_spaces(prog, ["w3", "w1"])
+    fe_config_mod = prog.symbol_table.lookup("finite_element_config_mod")
+    element_order = prog.symbol_table.lookup("element_order")
+    assert element_order.interface.container_symbol == fe_config_mod
     fs_mod_sym = prog.symbol_table.lookup("fs_continuity_mod")
     gen = fortran_writer(prog)
     for space in ["w1", "w3"]:
diff --git a/src/psyclone/tests/psyad/domain/lfric/test_lfric_adjoint_harness.py b/src/psyclone/tests/psyad/domain/lfric/test_lfric_adjoint_harness.py
index d9ec943d9..4bcc6c86f 100644
--- a/src/psyclone/tests/psyad/domain/lfric/test_lfric_adjoint_harness.py
+++ b/src/psyclone/tests/psyad/domain/lfric/test_lfric_adjoint_harness.py
@@ -356,10 +356,11 @@ def test_init_scalar_value(monkeypatch):
     # property of the datatype.
     sym4 = DataSymbol("my_var", LFRicTypes("LFRicRealScalarDataType")())
 
-    class broken_type:
+    class BrokenType:
+        '''Utility class to provide an unsupported type.'''
         def __init__(self):
             self.name = "wrong"
-    monkeypatch.setattr(sym4.datatype, "intrinsic", broken_type())
+    monkeypatch.setattr(sym4.datatype, "intrinsic", BrokenType())
     with pytest.raises(InternalError) as err:
         _init_scalar_value(sym4, routine, {})
     assert ("scalars of REAL, INTEGER or BOOLEAN type are supported but got "
@@ -495,6 +496,7 @@ def test_generate_lfric_adjoint_harness(fortran_reader, fortran_writer):
     tl_psyir = fortran_reader.psyir_from_source(TL_CODE)
     psyir = generate_lfric_adjoint_harness(tl_psyir)
     gen = fortran_writer(psyir).lower()
+    assert "use finite_element_config_mod, only : element_order" in gen
     assert "module adjoint_test_mod" in gen
     assert "subroutine adjoint_test(mesh, chi, panel_id)" in gen
     # We should have a field, a copy of that field and an inner-product value