def test_2kern_trans(kernel_outputdir): ''' Check that we generate correct code when we transform two kernels within a single invoke. ''' psy, invoke = get_invoke("4.5.2_multikernel_invokes.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.walk(Kern) assert len(kernels) == 5 ktrans = Dynamo0p3KernelConstTrans() _, _ = ktrans.apply(kernels[1], {"number_of_layers": 100}) _, _ = ktrans.apply(kernels[2], {"number_of_layers": 100}) # Generate the code (this triggers the generation of new kernels) code = str(psy.gen).lower() # Find the tags added to the kernel/module names for match in re.finditer('use testkern_any_space_2(.+?)_mod', code): tag = match.group(1) assert ("use testkern_any_space_2{0}_mod, only: " "testkern_any_space_2{0}_code".format(tag) in code) assert "call testkern_any_space_2{0}_code(".format(tag) in code filepath = os.path.join(str(kernel_outputdir), "testkern_any_space_2{0}_mod.f90".format(tag)) assert os.path.isfile(filepath) assert "nlayers = 100" in open(filepath).read() assert "use testkern_any_space_2_mod, only" not in code assert "call testkern_any_space_2_code(" not in code assert LFRicBuild(kernel_outputdir).code_compiles(psy)
def trans(psy): '''PSyclone transformation script for the Dynamo0.3 API to make the kernel values of ndofs, nlayers and nquadrature-point sizes constant. ''' const_trans = Dynamo0p3KernelConstTrans() fortran_writer = FortranWriter() for invoke in psy.invokes.invoke_list: print("invoke '{0}'".format(invoke.name)) schedule = invoke.schedule for kernel in schedule.coded_kernels(): print(" kernel '{0}'".format(kernel.name.lower())) try: const_trans.apply(kernel, number_of_layers=NUMBER_OF_LAYERS, element_order=ELEMENT_ORDER, quadrature=CONSTANT_QUADRATURE) except TransformationError: print(" Failed to modify kernel '{0}'".format(kernel.name)) kernel_schedule = kernel.get_kernel_schedule() kern_code = fortran_writer(kernel_schedule) print(kern_code) return psy
def trans(psy): '''PSyclone transformation script for the Dynamo0.3 API to make the kernel values of ndofs, nlayers and nquadrature-point sizes constant. :param psy: a PSyclone PSy object which captures the algorithm and \ kernel information required by PSyclone. :type psy: subclass of :py:class:`psyclone.psyGen.PSy` ''' const_trans = Dynamo0p3KernelConstTrans() for invoke in psy.invokes.invoke_list: print("invoke '{0}'".format(invoke.name)) schedule = invoke.schedule for kernel in schedule.coded_kernels(): print(" kernel '{0}'".format(kernel.name.lower())) try: const_trans.apply( kernel, { "number_of_layers": NUMBER_OF_LAYERS, "element_order": ELEMENT_ORDER, "quadrature": CONSTANT_QUADRATURE }) except TransformationError: print(" Failed to modify kernel '{0}'".format(kernel.name)) return psy
def test_kernel_module_name(mod_name, sub_name, kernel_outputdir, monkeypatch): '''Check that there is no limitation on kernel and module names. In particular check that the names do not have to conform to the <name>_mod, <name>_code convention. ''' _, invoke = get_invoke("1_single_invoke.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.coded_kernels() kern = kernels[0] ktrans = Dynamo0p3KernelConstTrans() _, _ = ktrans.apply(kern, {"number_of_layers": 100}) # Modify the kernel module and subroutine names. monkeypatch.setattr(kern, "_module_name", mod_name) monkeypatch.setattr(kern, "_name", sub_name) # Generate the code - no exception should be raised when the names # do not conform to the <name>_mod, >name>_code convention. kern.rename_and_write()
def test_kern_case_insensitive(mod_name, sub_name, kernel_outputdir, monkeypatch): '''Check that the test to see if a kernel conforms to the <name>_mod, <name>_code convention is case insensitive. This check also tests that the removal of _mod to create part of the output filename is case insensitive. ''' _, invoke = get_invoke("1_single_invoke.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.walk(Kern) kern = kernels[0] ktrans = Dynamo0p3KernelConstTrans() _, _ = ktrans.apply(kern, {"number_of_layers": 100}) monkeypatch.setattr(kern, "_module_name", mod_name) monkeypatch.setattr(kern, "_name", sub_name) # Generate the code - this should not raise an exception. kern.rename_and_write() filename = os.path.join(str(kernel_outputdir), mod_name[:8] + "_0_mod.f90") assert os.path.isfile(filename)
def test_kernel_conformance_error(mod_name, sub_name, kernel_outputdir, monkeypatch): '''Check that an exception is raised if a kernel does not conform to the <name>_mod, <name>_code convention and is output via a PSyIR back-end. This limitation is the subject of issue #393. ''' _, invoke = get_invoke("1_single_invoke.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.coded_kernels() kern = kernels[0] ktrans = Dynamo0p3KernelConstTrans() _, _ = ktrans.apply(kern, number_of_layers=100) # Modify the kernel module and subroutine names. monkeypatch.setattr(kern, "_module_name", mod_name) monkeypatch.setattr(kern, "_name", sub_name) # Generate the code - this should raise an error as the kernel # does not conform to the <name>_mod, >name>_code convention. with pytest.raises(NotImplementedError) as excinfo: kern.rename_and_write() assert ("PSyclone back-end code generation relies on kernel modules " "conforming to the <name>_mod and <name>_code convention. " "However, found '{0}', '{1}'.".format(mod_name, sub_name) in str(excinfo))