From 918ce103e83bd1cdb964f8c3321d2d67d08ca166 Mon Sep 17 00:00:00 2001 From: marqh Date: Wed, 24 Jan 2024 17:00:00 +0000 Subject: [PATCH 1/8] add python for test case scripting --- xios_examples/read_axis_resample/test_resample_cases.py | 1 + 1 file changed, 1 insertion(+) diff --git a/xios_examples/read_axis_resample/test_resample_cases.py b/xios_examples/read_axis_resample/test_resample_cases.py index 93e92b2..bc09e06 100644 --- a/xios_examples/read_axis_resample/test_resample_cases.py +++ b/xios_examples/read_axis_resample/test_resample_cases.py @@ -85,6 +85,7 @@ def test_resample(self): subprocess.run(['mpiexec', '-n', '1', './resample.exe', ':', '-n', '1', './xios_server.exe'], cwd=this_dir, check=True) + infile], cwd=this_dir) # load the result netCDF file rootgrp = netCDF4.Dataset('{}/axis_output.nc'.format(this_dir), 'r') From 40c3e3f28d3e6b6823eff355099ba77be45e5b45 Mon Sep 17 00:00:00 2001 From: marqh Date: Wed, 24 Jan 2024 12:14:37 +0000 Subject: [PATCH 2/8] resample usage example --- .../read_axis_resample/axis_input.cdl | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 xios_examples/read_axis_resample/axis_input.cdl diff --git a/xios_examples/read_axis_resample/axis_input.cdl b/xios_examples/read_axis_resample/axis_input.cdl new file mode 100644 index 0000000..8ba3391 --- /dev/null +++ b/xios_examples/read_axis_resample/axis_input.cdl @@ -0,0 +1,32 @@ +netcdf axis_input { +dimensions: + z = 10 ; + z_resample = 4 ; +variables: + float z(z) ; + z:long_name = "original z coordinate" ; + z:units = "1"; + float z_resample(z_resample) ; + z_resample:long_name = "resampled z coordinate" ; + z_resample:units = "1"; + double original_data(z) ; + original_data:long_name = "input data values" ; + original_data:units = "1"; + double resample_data(z_resample) ; + resample_data:long_name = "expected resampled data values" ; + resample_data:units = "1"; + +// global attributes: + :title = "Input data for XIOS Axis resampling; data is a square function of the z coordinate." ; + +data: + + z = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ; + + z_resample = 1.5, 3.5, 5.5, 7.5 ; + + original_data = 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 ; + + resample_data = 2.25, 12.25, 30.25, 56.25 ; + +} From 110f6a9cfcbd177c4ce73b3874e5fde8aa058f4b Mon Sep 17 00:00:00 2001 From: marqh Date: Tue, 30 Jan 2024 11:45:07 +0000 Subject: [PATCH 3/8] extend to new test scenario --- .../read_axis_resample/test_resample_cases.py | 59 +++------------- xios_examples/read_domain_resample/Makefile | 56 +++++++++++++++ .../read_domain_resample/__init__.py | 3 + xios_examples/read_domain_resample/iodef.xml | 7 ++ xios_examples/read_domain_resample/xios.xml | 22 ++++++ xios_examples/shared_testing.py | 68 +++++++++++++++++++ 6 files changed, 164 insertions(+), 51 deletions(-) create mode 100644 xios_examples/read_domain_resample/Makefile create mode 100644 xios_examples/read_domain_resample/__init__.py create mode 100644 xios_examples/read_domain_resample/iodef.xml create mode 100644 xios_examples/read_domain_resample/xios.xml create mode 100644 xios_examples/shared_testing.py diff --git a/xios_examples/read_axis_resample/test_resample_cases.py b/xios_examples/read_axis_resample/test_resample_cases.py index bc09e06..872800c 100644 --- a/xios_examples/read_axis_resample/test_resample_cases.py +++ b/xios_examples/read_axis_resample/test_resample_cases.py @@ -7,59 +7,16 @@ import glob import unittest +import xios_examples.shared_testing as xshared + this_path = os.path.realpath(__file__) this_dir = os.path.dirname(this_path) -class TestResample(unittest.TestCase): - """ - UnitTest class to contain tests, - 1 test case function per input `.cdl` file - - """ - @classmethod - def setUpClass(cls): - """ - First, build the fortran code only once for this class. - - """ - subprocess.run(['make', 'clean'], cwd=this_dir, check=True) - subprocess.run(['make'], cwd=this_dir, check=True) - if os.environ.get('MVER', '') == 'XIOS3/trunk': - with open(os.path.join(this_dir, 'iodef.xml'), 'r') as ioin: - iodef_in = ioin.read() - # patch in transport protocol choice for XIOS3 - # needed for CI runners - in2 = '' - in3 = ('\n' - ' p2p') - iodef_out = iodef_in.replace(in2, in3) - with open(os.path.join(this_dir, 'iodef.xml'), 'w') as ioout: - ioout.write(iodef_out) - - def tearDown(self): - """ - After each test function, - report any errors from XIOS, then - remove the input and output netCDF files. - - """ - - for ef in glob.glob('{}/*.err'.format(this_dir)): - print(ef) - with open(ef, 'r') as efile: - print(efile.read(), flush=True) - - os.remove('{}/axis_input.nc'.format(this_dir)) - os.remove('{}/axis_output.nc'.format(this_dir)) +class TestResampleAxis(xshared._TestCase): + test_dir = this_dir + transient_inputs = ['axis_input.nc'] + transient_outputs = ['axis_output.nc'] - @classmethod - def tearDownClass(cls): - """ - Finally, clean the build for this class, after all tests have run. - - """ - subprocess.run(['make', 'clean'], cwd=this_dir) # A list of input `.cdl` files where XIOS is known to produce different # output from the expected output data @@ -110,6 +67,6 @@ def test_resample(self): # add the test as an attribute (function) to the test class if tname in known_failures: # set decorator @unittest.expectedFailure - setattr(TestResample, tname, unittest.expectedFailure(make_a_test(f))) + setattr(TestResampleAxis, tname, unittest.expectedFailure(make_a_test(f))) else: - setattr(TestResample, tname, make_a_test(f)) + setattr(TestResampleAxis, tname, make_a_test(f)) diff --git a/xios_examples/read_domain_resample/Makefile b/xios_examples/read_domain_resample/Makefile new file mode 100644 index 0000000..0824ec0 --- /dev/null +++ b/xios_examples/read_domain_resample/Makefile @@ -0,0 +1,56 @@ +# Make file for the resample demonstartion XIOS programme +# Targets provided our detailed below... +# +# all: (default) Build the resample programme +# clean: Delete all final products and working files +# run: run the programme +# +# Environment Variables expected by this MakeFile: +# +# NETCDF_LIB_DIR: the directories for the netCDF lib files +# encoded as a -L string, e.g. +# "-L/dir1 -L/dir2" +# NETCDF_INC_DIR: the directories for the netCDF include files +# encoded as a -I string, e.g. +# "-I/dir3 -I/dir4" +# (note, this is for consistency with the XIOS build process +# required for the CI build machine. +# this is not required for other directories) +# +# XIOS_INCDIR: The directory for XIOS include files +# XIOS_LIBDIR: The directory for XIOS lib files +# XIOS_BINDIR: The directory for XIOS binary files + +FCFLAGS = -g -ffree-line-length-none + +FC = mpif90 # compiler driver for MPI programs + +# compiler flag, includes +FCFLAGS += -I$(XIOS_INCDIR) $(NETCDF_INCDIR) + +# loader flags +LDFLAGS = \ + -L$(XIOS_LIBDIR) \ + $(NETCDF_LIBDIR) \ + -lxios \ + -lnetcdf \ + -lnetcdff \ + -lstdc++ + +all: resample + +# fortran compilation +%.o: %.F90 + $(FC) $(FCFLAGS) -c $< + +# fortran linking +resample: resample.o + $(FC) -o resample.exe resample.o $(LDFLAGS) \ + && ln -fs $(XIOS_BINDIR)/xios_server.exe . + +run: + mpiexec -n 1 ./resample.exe : -n 1 ./xios_server.exe + +# cleanup +clean: + rm -f *.exe *.o *.mod *.MOD *.out *.err *.nc diff --git a/xios_examples/read_domain_resample/__init__.py b/xios_examples/read_domain_resample/__init__.py new file mode 100644 index 0000000..df083e3 --- /dev/null +++ b/xios_examples/read_domain_resample/__init__.py @@ -0,0 +1,3 @@ +""" +Enable this folder to be a module path, for imports and test discovery. +""" diff --git a/xios_examples/read_domain_resample/iodef.xml b/xios_examples/read_domain_resample/iodef.xml new file mode 100644 index 0000000..c57fc1d --- /dev/null +++ b/xios_examples/read_domain_resample/iodef.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/xios_examples/read_domain_resample/xios.xml b/xios_examples/read_domain_resample/xios.xml new file mode 100644 index 0000000..9ec1df0 --- /dev/null +++ b/xios_examples/read_domain_resample/xios.xml @@ -0,0 +1,22 @@ + + + + + performance + + + 1.0 + + + + + true + + 100 + + + true + + + + diff --git a/xios_examples/shared_testing.py b/xios_examples/shared_testing.py new file mode 100644 index 0000000..e7d7468 --- /dev/null +++ b/xios_examples/shared_testing.py @@ -0,0 +1,68 @@ +import copy +import glob +import netCDF4 +import numpy as np +import os +import subprocess +import unittest + +this_path = os.path.realpath(__file__) +this_dir = os.path.dirname(this_path) + +class _TestCase(unittest.TestCase): + """ + UnitTest class to contain tests, + 1 test case function per input `.cdl` file + + """ + test_dir = this_dir + transient_inputs = [] + transient_outputs = [] + + @classmethod + def setUpClass(cls): + """ + First, build the fortran code only once for this class. + + """ + subprocess.run(['make', 'clean'], cwd=cls.test_dir) + subprocess.run(['make'], cwd=cls.test_dir) + if os.environ.get('MVER', '') == 'XIOS3/trunk': + with open(os.path.join(this_dir, 'iodef.xml'), 'r') as ioin: + iodef_in = ioin.read() + # patch in transport protocol choice for XIOS3 + # needed for CI runners + in2 = '' + in3 = ('\n' + ' p2p') + iodef_out = iodef_in.replace(in2, in3) + with open(os.path.join(this_dir, 'iodef.xml'), 'w') as ioout: + ioout.write(iodef_out) + + def tearDown(self): + """ + After each test function, + report any errors from XIOS, then + remove the input and output netCDF files. + + """ + + for ef in glob.glob('{}/*.err'.format(this_dir)): + print(ef) + with open(ef, 'r') as efile: + print(efile.read(), flush=True) + + for t_in in self.transient_inputs: + os.remove('{}/{}'.format(self.test_dir, t_in)) + for t_out in self.transient_outputs: + os.remove('{}/{}'.format(self.test_dir, t_out)) + + @classmethod + def tearDownClass(cls): + """ + Finally, clean the build for this class, after all tests have run. + + """ + subprocess.run(['make', 'clean'], cwd=cls.test_dir) + From 833f1bcc8d18ddb598d5292003921649a92cb3c0 Mon Sep 17 00:00:00 2001 From: marqh Date: Wed, 31 Jan 2024 11:39:09 +0000 Subject: [PATCH 4/8] axis but domain read fails xios --- .../domain_input_edge_simple_square_ten.cdl | 51 +++++++++ .../domain_input_simple_square_ten.cdl | 51 +++++++++ xios_examples/read_domain_resample/main.xml | 50 +++++++++ .../read_domain_resample/resample.F90 | 106 ++++++++++++++++++ .../test_resample_cases.py | 70 ++++++++++++ xios_examples/shared_testing.py | 8 +- 6 files changed, 334 insertions(+), 2 deletions(-) create mode 100644 xios_examples/read_domain_resample/domain_input_edge_simple_square_ten.cdl create mode 100644 xios_examples/read_domain_resample/domain_input_simple_square_ten.cdl create mode 100644 xios_examples/read_domain_resample/main.xml create mode 100644 xios_examples/read_domain_resample/resample.F90 create mode 100644 xios_examples/read_domain_resample/test_resample_cases.py diff --git a/xios_examples/read_domain_resample/domain_input_edge_simple_square_ten.cdl b/xios_examples/read_domain_resample/domain_input_edge_simple_square_ten.cdl new file mode 100644 index 0000000..2b4f8b2 --- /dev/null +++ b/xios_examples/read_domain_resample/domain_input_edge_simple_square_ten.cdl @@ -0,0 +1,51 @@ +netcdf domain_input { +dimensions: + x = 5 ; + y = 5 ; + x_resample = 4 ; + y_resample = 4 ; +variables: + float x(x) ; + x:long_name = "original x coordinate" ; + x:units = "1"; + float y(y) ; + y:long_name = "original y coordinate" ; + y:units = "1"; + float x_resample(x_resample) ; + x_resample:long_name = "resampled x coordinate" ; + x_resample:units = "1"; + float y_resample(y_resample) ; + y_resample:long_name = "resampled y coordinate" ; + y_resample:units = "1"; + double original_data(y,x) ; + original_data:long_name = "input data values" ; + original_data:units = "1"; + double resample_data(y_resample,x_resample) ; + resample_data:long_name = "expected resampled data values" ; + resample_data:units = "1"; + +// global attributes: + :title = "Input data for XIOS Domain resampling; data is a square function of the x & y coordinates; x^2+y^2." ; + +data: + + x = 0, 2, 4, 6, 8 ; + + y = 0, 2, 4, 6, 8 ; + + x_resample = 1, 3, 5, 7 ; + + y_resample = 1, 3, 5, 7 ; + + original_data = 0, 4, 16, 36, 64, + 4, 8, 20, 40, 68, + 16, 20, 36, 52, 80, + 36, 40, 52, 72, 100, + 64, 68, 80, 100, 128 ; + + resample_data = 1, 9, 25, 49, + 10, 18, 34, 58, + 26, 34, 50, 74, + 50, 58, 74, 98 ; + +} diff --git a/xios_examples/read_domain_resample/domain_input_simple_square_ten.cdl b/xios_examples/read_domain_resample/domain_input_simple_square_ten.cdl new file mode 100644 index 0000000..37435fe --- /dev/null +++ b/xios_examples/read_domain_resample/domain_input_simple_square_ten.cdl @@ -0,0 +1,51 @@ +netcdf domain_input { +dimensions: + x = 5 ; + y = 5 ; + x_resample = 2 ; + y_resample = 2 ; +variables: + float x(x) ; + x:long_name = "original x coordinate" ; + x:units = "1"; + float y(y) ; + y:long_name = "original y coordinate" ; + y:units = "1"; + float x_resample(x_resample) ; + x_resample:long_name = "resampled x coordinate" ; + x_resample:units = "1"; + float y_resample(y_resample) ; + y_resample:long_name = "resampled y coordinate" ; + y_resample:units = "1"; + double original_data(y,x) ; + original_data:long_name = "input data values" ; + original_data:units = "1"; + double resample_data(y_resample,x_resample) ; + resample_data:long_name = "expected resampled data values" ; + resample_data:units = "1"; + +// global attributes: + :title = "Input data for XIOS Domain resampling; data is a square function of the x & y coordinates; x^2+y^2." ; + +data: + + x = 0, 2, 4, 6, 8 ; + + y = 0, 2, 4, 6, 8 ; + + x_resample = 3, 5 ; + + y_resample = 3, 5 ; + + original_data = 0, 4, 16, 36, 64, + 4, 8, 20, 40, 68, + 16, 20, 36, 52, 80, + 36, 40, 52, 72, 100, + 64, 68, 80, 100, 128 ; + + resample_data = 9, 25, + 18, 34, + 34, 50, + 58, 74 ; + +} diff --git a/xios_examples/read_domain_resample/main.xml b/xios_examples/read_domain_resample/main.xml new file mode 100644 index 0000000..ba0bad0 --- /dev/null +++ b/xios_examples/read_domain_resample/main.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xios_examples/read_domain_resample/resample.F90 b/xios_examples/read_domain_resample/resample.F90 new file mode 100644 index 0000000..b39f710 --- /dev/null +++ b/xios_examples/read_domain_resample/resample.F90 @@ -0,0 +1,106 @@ +!----------------------------------------------------------------------------- +! (C) Crown copyright 2020 Met Office. All rights reserved. +! The file LICENCE, distributed with this code, contains details of the terms +! under which the code may be used. +!----------------------------------------------------------------------------- +!> Read 2D data on a domain and resample using the axis_input.nc file +!> +program resample + use xios + use mpi + + implicit none + + integer :: comm = -1 + integer :: rank = -1 + integer :: npar = 0 + + call initialise() + call simulate() + call finalise() +contains + + subroutine initialise() + + type(xios_date) :: origin + type(xios_date) :: start + type(xios_duration) :: tstep + integer :: mpi_error + + ! Arbitrary datetime setup, required for XIOS but unused + origin = xios_date(2022, 2, 2, 12, 0, 0) + start = xios_date(2022, 12, 13, 12, 0, 0) + tstep = xios_hour + + ! Initialise MPI and XIOS + call MPI_INIT(mpi_error) + + call xios_initialize('client', return_comm=comm) + + call MPI_Comm_rank(comm, rank, mpi_error) + call MPI_Comm_size(comm, npar, mpi_error) + + call xios_context_initialize('main', comm) + call xios_set_time_origin(origin) + call xios_set_start_date(start) + call xios_set_timestep(tstep) + + call xios_close_context_definition() + + end subroutine initialise + + subroutine finalise() + + integer :: mpi_error + + ! Finalise XIOS and MPI + call xios_context_finalize() + call MPI_Comm_free(comm, mpi_error) + call xios_finalize() + call MPI_Finalize(mpi_error) + + end subroutine finalise + + subroutine simulate() + + type(xios_date) :: current + integer :: ts + integer :: lenx + integer :: lenrx + integer :: leny + integer :: lenry + + ! Allocatable arrays, size is taken from input file + double precision, dimension (:,:), allocatable :: inodata + double precision, dimension (:,:), allocatable :: inedata + + call xios_get_axis_attr('x', n_glo=lenx) + call xios_get_axis_attr('x_resample', n_glo=lenrx) + call xios_get_axis_attr('y', n_glo=leny) + call xios_get_axis_attr('y_resample', n_glo=lenry) + + allocate ( inodata(leny, lenx) ) + allocate ( inedata(lenry, lenrx) ) + + ! Load data from the input file + call xios_recv_field('odatain', inodata) + call xios_recv_field('edatain', inedata) + + do ts=1, 1 + call xios_update_calendar(ts) + call xios_get_current_date(current) + ! Send (copy) the original data to the output file. + ! The interpolate_axis and field-ref in main.xml will + ! also write the interpolated data into the output file. + call xios_send_field('odata', inodata) + ! Send (copy) the expected data to the output file. + ! The diff field in main.xml will also output a diff variable. + call xios_send_field('edata', inedata) + enddo + + deallocate (inodata) + deallocate (inedata) + + end subroutine simulate + +end program resample diff --git a/xios_examples/read_domain_resample/test_resample_cases.py b/xios_examples/read_domain_resample/test_resample_cases.py new file mode 100644 index 0000000..577932f --- /dev/null +++ b/xios_examples/read_domain_resample/test_resample_cases.py @@ -0,0 +1,70 @@ +import copy +import glob +import netCDF4 +import numpy as np +import os +import subprocess +import unittest + +import xios_examples.shared_testing as xshared + +this_path = os.path.realpath(__file__) +this_dir = os.path.dirname(this_path) + +class TestResampleDomain(xshared._TestCase): + test_dir = this_dir + transient_inputs = ['domain_input.nc'] + transient_outputs = ['domain_output.nc'] + +# A list of input `.cdl` files where XIOS is known to produce different +# output from the expected output data +# for future investigation / ToDo +known_failures = []#['test_axis_input_edge_simple_square_ten.cdl'] + +# iterate through `.cdl` files in this test case folder +for f in glob.glob('{}/*.cdl'.format(this_dir)): + def make_a_test(inf): + """ + this function makes a test case and returns it as a function. + + """ + # always copy for value, don't pass by reference. + infile = copy.copy(inf) + # expected by the fortran XIOS resample program's main.xml + outfile = TestResampleDomain.transient_inputs[0] + def test_resample(self): + # create a netCDF file from the `.cdl` input + subprocess.run(['ncgen', '-k', 'nc4', '-o', outfile, + infile], cwd=this_dir) + # run the compiled Fortran XIOS programme + subprocess.run(['mpiexec', '-n', '1', './resample.exe', ':', + '-n', '1', './xios_server.exe'], cwd=this_dir) + # load the result netCDF file + runfile = '{}/{}'.format(this_dir, + TestResampleDomain.transient_outputs[0]) + self.assertTrue(os.path.exists(runfile)) + rootgrp = netCDF4.Dataset(runfile, 'r') + # read data from the resampled, expected & diff variables + diff = rootgrp['resampled_minus_resample'][:] + # prepare message for failure + msg = ('the expected resample data array\n {exp}\n ' + 'differs from the resampled data array\n {res} \n ' + 'with diff \n {diff}\n') + msg = msg.format(exp=rootgrp['resample_data'][:], + res=rootgrp['resampled_data'][:], + diff=diff) + if np.any(diff): + # print message for fail case, + # as expected failures do not report msg. + print(msg) + # assert that all of the `diff` varaible values are zero + self.assertTrue(not np.any(diff), msg=msg) + return test_resample + # unique name for the test + tname = 'test_{}'.format(os.path.basename(f)) + # add the test as an attribute (function) to the test class + if tname in known_failures: + # set decorator @unittest.expectedFailure + setattr(TestResampleDomain, tname, unittest.expectedFailure(make_a_test(f))) + else: + setattr(TestResampleDomain, tname, make_a_test(f)) diff --git a/xios_examples/shared_testing.py b/xios_examples/shared_testing.py index e7d7468..501a140 100644 --- a/xios_examples/shared_testing.py +++ b/xios_examples/shared_testing.py @@ -54,9 +54,13 @@ def tearDown(self): print(efile.read(), flush=True) for t_in in self.transient_inputs: - os.remove('{}/{}'.format(self.test_dir, t_in)) + rf = '{}/{}'.format(self.test_dir, t_in) + if os.path.exists(rf): + os.remove(rf) for t_out in self.transient_outputs: - os.remove('{}/{}'.format(self.test_dir, t_out)) + rf = '{}/{}'.format(self.test_dir, t_out) + if os.path.exists(rf): + os.remove(rf) @classmethod def tearDownClass(cls): From 054e097c6afeca73ca1d59a0b217bf353d238aeb Mon Sep 17 00:00:00 2001 From: marqh Date: Tue, 6 Feb 2024 11:29:01 +0000 Subject: [PATCH 5/8] new domain examples + shared code --- .gitignore | 1 + .../read_axis_resample/test_resample_cases.py | 73 +++++++++-------- .../read_domain_resample/axis_check.xml | 33 ++++++++ .../domain_input_edge_simple_square_ten.cdl | 4 +- .../domain_input_simple_square_ten.cdl | 8 +- xios_examples/read_domain_resample/iodef.xml | 2 + xios_examples/read_domain_resample/main.xml | 32 ++++---- .../read_domain_resample/resample.F90 | 43 ++++++++-- .../test_resample_cases.py | 79 ++++++++++--------- 9 files changed, 169 insertions(+), 106 deletions(-) create mode 100644 .gitignore create mode 100644 xios_examples/read_domain_resample/axis_check.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..abd32e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*__pycache__* \ No newline at end of file diff --git a/xios_examples/read_axis_resample/test_resample_cases.py b/xios_examples/read_axis_resample/test_resample_cases.py index 872800c..9792f37 100644 --- a/xios_examples/read_axis_resample/test_resample_cases.py +++ b/xios_examples/read_axis_resample/test_resample_cases.py @@ -17,6 +17,42 @@ class TestResampleAxis(xshared._TestCase): transient_inputs = ['axis_input.nc'] transient_outputs = ['axis_output.nc'] +def make_a_test(inf): + """ + this function makes a test case and returns it as a function. + + """ + # always copy for value, don't pass by reference. + infile = copy.copy(inf) + # expected by the fortran XIOS resample program's main.xml + outfile = 'axis_input.nc' + def test_resample(self): + # create a netCDF file from the `.cdl` input + subprocess.run(['ncgen', '-k', 'nc4', '-o', 'axis_input.nc', + infile], cwd=this_dir) + # run the compiled Fortran XIOS programme + subprocess.run(['mpiexec', '-n', '1', './resample.exe', ':', + '-n', '1', './xios_server.exe'], cwd=this_dir) + # load the result netCDF file + rootgrp = netCDF4.Dataset('{}/axis_output.nc'.format(this_dir), + 'r') + # read data from the resampled, expected & diff variables + diff = rootgrp['resampled_minus_resample'][:] + # prepare message for failure + msg = ('the expected resample data array\n {exp}\n ' + 'differs from the resampled data array\n {res} \n ' + 'with diff \n {diff}\n') + msg = msg.format(exp=rootgrp['resample_data'][:], + res=rootgrp['resampled_data'][:], + diff=diff) + if np.any(diff): + # print message for fail case, + # as expected failures do not report msg. + print(msg) + # assert that all of the `diff` varaible values are zero + self.assertTrue(not np.any(diff), msg=msg) + return test_resample + # A list of input `.cdl` files where XIOS is known to produce different # output from the expected output data @@ -25,43 +61,6 @@ class TestResampleAxis(xshared._TestCase): # iterate through `.cdl` files in this test case folder for f in glob.glob('{}/*.cdl'.format(this_dir)): - def make_a_test(inf): - """ - this function makes a test case and returns it as a function. - - """ - # always copy for value, don't pass by reference. - infile = copy.copy(inf) - # expected by the fortran XIOS resample program's main.xml - outfile = 'axis_input.nc' - def test_resample(self): - # create a netCDF file from the `.cdl` input - subprocess.run(['ncgen', '-k', 'nc4', '-o', 'axis_input.nc', - infile], cwd=this_dir, check=True) - # run the compiled Fortran XIOS programme - subprocess.run(['mpiexec', '-n', '1', './resample.exe', ':', - '-n', '1', './xios_server.exe'], - cwd=this_dir, check=True) - infile], cwd=this_dir) - # load the result netCDF file - rootgrp = netCDF4.Dataset('{}/axis_output.nc'.format(this_dir), - 'r') - # read data from the resampled, expected & diff variables - diff = rootgrp['resampled_minus_resample'][:] - # prepare message for failure - msg = ('the expected resample data array\n {exp}\n ' - 'differs from the resampled data array\n {res} \n ' - 'with diff \n {diff}\n') - msg = msg.format(exp=rootgrp['resample_data'][:], - res=rootgrp['resampled_data'][:], - diff=diff) - if np.any(diff): - # print message for fail case, - # as expected failures do not report msg. - print(msg) - # assert that all of the `diff` varaible values are zero - self.assertTrue(not np.any(diff), msg=msg) - return test_resample # unique name for the test tname = 'test_{}'.format(os.path.basename(f)) # add the test as an attribute (function) to the test class diff --git a/xios_examples/read_domain_resample/axis_check.xml b/xios_examples/read_domain_resample/axis_check.xml new file mode 100644 index 0000000..b198d5b --- /dev/null +++ b/xios_examples/read_domain_resample/axis_check.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xios_examples/read_domain_resample/domain_input_edge_simple_square_ten.cdl b/xios_examples/read_domain_resample/domain_input_edge_simple_square_ten.cdl index 2b4f8b2..791be5f 100644 --- a/xios_examples/read_domain_resample/domain_input_edge_simple_square_ten.cdl +++ b/xios_examples/read_domain_resample/domain_input_edge_simple_square_ten.cdl @@ -39,11 +39,11 @@ data: original_data = 0, 4, 16, 36, 64, 4, 8, 20, 40, 68, - 16, 20, 36, 52, 80, + 16, 20, 32, 52, 80, 36, 40, 52, 72, 100, 64, 68, 80, 100, 128 ; - resample_data = 1, 9, 25, 49, + resample_data = 2, 10, 26, 50, 10, 18, 34, 58, 26, 34, 50, 74, 50, 58, 74, 98 ; diff --git a/xios_examples/read_domain_resample/domain_input_simple_square_ten.cdl b/xios_examples/read_domain_resample/domain_input_simple_square_ten.cdl index 37435fe..dec064a 100644 --- a/xios_examples/read_domain_resample/domain_input_simple_square_ten.cdl +++ b/xios_examples/read_domain_resample/domain_input_simple_square_ten.cdl @@ -39,13 +39,11 @@ data: original_data = 0, 4, 16, 36, 64, 4, 8, 20, 40, 68, - 16, 20, 36, 52, 80, + 16, 20, 32, 52, 80, 36, 40, 52, 72, 100, 64, 68, 80, 100, 128 ; - resample_data = 9, 25, - 18, 34, - 34, 50, - 58, 74 ; + resample_data = 18, 34, + 34, 50 ; } diff --git a/xios_examples/read_domain_resample/iodef.xml b/xios_examples/read_domain_resample/iodef.xml index c57fc1d..37acd4d 100644 --- a/xios_examples/read_domain_resample/iodef.xml +++ b/xios_examples/read_domain_resample/iodef.xml @@ -2,6 +2,8 @@ + + diff --git a/xios_examples/read_domain_resample/main.xml b/xios_examples/read_domain_resample/main.xml index ba0bad0..3dafcb3 100644 --- a/xios_examples/read_domain_resample/main.xml +++ b/xios_examples/read_domain_resample/main.xml @@ -2,36 +2,34 @@ - - - - - + - + + + + + + + - - - + - - - + - - - + + rdata-edata + @@ -41,8 +39,8 @@ - - + + diff --git a/xios_examples/read_domain_resample/resample.F90 b/xios_examples/read_domain_resample/resample.F90 index b39f710..e9ba0d4 100644 --- a/xios_examples/read_domain_resample/resample.F90 +++ b/xios_examples/read_domain_resample/resample.F90 @@ -26,6 +26,10 @@ subroutine initialise() type(xios_date) :: start type(xios_duration) :: tstep integer :: mpi_error + integer :: lenx + integer :: lenrx + integer :: leny + integer :: lenry ! Arbitrary datetime setup, required for XIOS but unused origin = xios_date(2022, 2, 2, 12, 0, 0) @@ -40,11 +44,38 @@ subroutine initialise() call MPI_Comm_rank(comm, rank, mpi_error) call MPI_Comm_size(comm, npar, mpi_error) + ! use the axis_check context to obtain sizing information on all arrays + ! for use in defining the main context interpretation + call xios_context_initialize('axis_check', comm) + call xios_set_time_origin(origin) + call xios_set_start_date(start) + call xios_set_timestep(tstep) + + call xios_close_context_definition() + + call xios_get_axis_attr('x', n_glo=lenx) + call xios_get_axis_attr('x_resample', n_glo=lenrx) + call xios_get_axis_attr('y', n_glo=leny) + call xios_get_axis_attr('y_resample', n_glo=lenry) + + print *, 'x, y', lenx, ', ', leny + print *, 'rx, ry', lenrx, ', ', lenry + + ! ensure to finalize this checking context before initialising + ! the domain context for further use + call xios_context_finalize() + + ! initialize the main context for interacting with the data. call xios_context_initialize('main', comm) call xios_set_time_origin(origin) call xios_set_start_date(start) call xios_set_timestep(tstep) + call xios_set_domain_attr("original_domain", ni=lenx, nj=leny, ibegin=0, jbegin=0) + call xios_set_domain_attr("resampled_domain", ni=lenrx, nj=lenry, ibegin=0, jbegin=0) + + print *, 'closing context definition for main' + call xios_close_context_definition() end subroutine initialise @@ -74,10 +105,11 @@ subroutine simulate() double precision, dimension (:,:), allocatable :: inodata double precision, dimension (:,:), allocatable :: inedata - call xios_get_axis_attr('x', n_glo=lenx) - call xios_get_axis_attr('x_resample', n_glo=lenrx) - call xios_get_axis_attr('y', n_glo=leny) - call xios_get_axis_attr('y_resample', n_glo=lenry) + call xios_get_domain_attr('original_domain', ni_glo=lenx) + call xios_get_domain_attr('original_domain', nj_glo=leny) + call xios_get_domain_attr('resampled_domain', ni_glo=lenrx) + call xios_get_domain_attr('resampled_domain', nj_glo=lenry) + print *, 'x, y', lenx, ', ', leny allocate ( inodata(leny, lenx) ) allocate ( inedata(lenry, lenrx) ) @@ -90,11 +122,8 @@ subroutine simulate() call xios_update_calendar(ts) call xios_get_current_date(current) ! Send (copy) the original data to the output file. - ! The interpolate_axis and field-ref in main.xml will - ! also write the interpolated data into the output file. call xios_send_field('odata', inodata) ! Send (copy) the expected data to the output file. - ! The diff field in main.xml will also output a diff variable. call xios_send_field('edata', inedata) enddo diff --git a/xios_examples/read_domain_resample/test_resample_cases.py b/xios_examples/read_domain_resample/test_resample_cases.py index 577932f..dd434d0 100644 --- a/xios_examples/read_domain_resample/test_resample_cases.py +++ b/xios_examples/read_domain_resample/test_resample_cases.py @@ -21,47 +21,50 @@ class TestResampleDomain(xshared._TestCase): # for future investigation / ToDo known_failures = []#['test_axis_input_edge_simple_square_ten.cdl'] + +def make_a_test(inf): + """ + this function makes a test case and returns it as a function. + + """ + # always copy for value, don't pass by reference. + infile = copy.copy(inf) + # expected by the fortran XIOS resample program's main.xml + outfile = TestResampleDomain.transient_inputs[0] + def test_resample(self): + # create a netCDF file from the `.cdl` input + subprocess.run(['ncgen', '-k', 'nc4', '-o', outfile, + infile], cwd=this_dir) + # run the compiled Fortran XIOS programme + subprocess.run(['mpiexec', '-n', '1', './resample.exe', ':', + '-n', '1', './xios_server.exe'], cwd=this_dir) + # load the result netCDF file + runfile = '{}/{}'.format(this_dir, + TestResampleDomain.transient_outputs[0]) + self.assertTrue(os.path.exists(runfile)) + rootgrp = netCDF4.Dataset(runfile, 'r') + # read data from the resampled, expected & diff variables + diff = rootgrp['resampled_minus_resample'][:] + # prepare message for failure + msg = ('the expected resample data array\n {exp}\n ' + 'differs from the resampled data array\n {res} \n ' + 'with diff \n {diff}\n') + msg = msg.format(exp=rootgrp['resample_data'][:], + res=rootgrp['resampled_data'][:], + diff=diff) + if np.any(diff): + # print message for fail case, + # as expected failures do not report msg. + print(msg) + # assert that all of the `diff` varaible values are zero + self.assertTrue(not np.any(diff), msg=msg) + return test_resample + + # iterate through `.cdl` files in this test case folder for f in glob.glob('{}/*.cdl'.format(this_dir)): - def make_a_test(inf): - """ - this function makes a test case and returns it as a function. - - """ - # always copy for value, don't pass by reference. - infile = copy.copy(inf) - # expected by the fortran XIOS resample program's main.xml - outfile = TestResampleDomain.transient_inputs[0] - def test_resample(self): - # create a netCDF file from the `.cdl` input - subprocess.run(['ncgen', '-k', 'nc4', '-o', outfile, - infile], cwd=this_dir) - # run the compiled Fortran XIOS programme - subprocess.run(['mpiexec', '-n', '1', './resample.exe', ':', - '-n', '1', './xios_server.exe'], cwd=this_dir) - # load the result netCDF file - runfile = '{}/{}'.format(this_dir, - TestResampleDomain.transient_outputs[0]) - self.assertTrue(os.path.exists(runfile)) - rootgrp = netCDF4.Dataset(runfile, 'r') - # read data from the resampled, expected & diff variables - diff = rootgrp['resampled_minus_resample'][:] - # prepare message for failure - msg = ('the expected resample data array\n {exp}\n ' - 'differs from the resampled data array\n {res} \n ' - 'with diff \n {diff}\n') - msg = msg.format(exp=rootgrp['resample_data'][:], - res=rootgrp['resampled_data'][:], - diff=diff) - if np.any(diff): - # print message for fail case, - # as expected failures do not report msg. - print(msg) - # assert that all of the `diff` varaible values are zero - self.assertTrue(not np.any(diff), msg=msg) - return test_resample # unique name for the test - tname = 'test_{}'.format(os.path.basename(f)) + tname = 'test_{}'.format(os.path.splitext(os.path.basename(f))[0]) # add the test as an attribute (function) to the test class if tname in known_failures: # set decorator @unittest.expectedFailure From 34fe202008a1d26bb12ce8bc88b3519c291220f0 Mon Sep 17 00:00:00 2001 From: marqh Date: Tue, 6 Feb 2024 13:59:22 +0000 Subject: [PATCH 6/8] test runner refactor --- .../read_axis_resample/test_resample_cases.py | 46 +++------------- .../test_resample_cases.py | 50 +++--------------- xios_examples/shared_testing.py | 52 +++++++++++++++++-- 3 files changed, 62 insertions(+), 86 deletions(-) diff --git a/xios_examples/read_axis_resample/test_resample_cases.py b/xios_examples/read_axis_resample/test_resample_cases.py index 9792f37..cb69032 100644 --- a/xios_examples/read_axis_resample/test_resample_cases.py +++ b/xios_examples/read_axis_resample/test_resample_cases.py @@ -17,55 +17,21 @@ class TestResampleAxis(xshared._TestCase): transient_inputs = ['axis_input.nc'] transient_outputs = ['axis_output.nc'] -def make_a_test(inf): - """ - this function makes a test case and returns it as a function. - - """ - # always copy for value, don't pass by reference. - infile = copy.copy(inf) - # expected by the fortran XIOS resample program's main.xml - outfile = 'axis_input.nc' - def test_resample(self): - # create a netCDF file from the `.cdl` input - subprocess.run(['ncgen', '-k', 'nc4', '-o', 'axis_input.nc', - infile], cwd=this_dir) - # run the compiled Fortran XIOS programme - subprocess.run(['mpiexec', '-n', '1', './resample.exe', ':', - '-n', '1', './xios_server.exe'], cwd=this_dir) - # load the result netCDF file - rootgrp = netCDF4.Dataset('{}/axis_output.nc'.format(this_dir), - 'r') - # read data from the resampled, expected & diff variables - diff = rootgrp['resampled_minus_resample'][:] - # prepare message for failure - msg = ('the expected resample data array\n {exp}\n ' - 'differs from the resampled data array\n {res} \n ' - 'with diff \n {diff}\n') - msg = msg.format(exp=rootgrp['resample_data'][:], - res=rootgrp['resampled_data'][:], - diff=diff) - if np.any(diff): - # print message for fail case, - # as expected failures do not report msg. - print(msg) - # assert that all of the `diff` varaible values are zero - self.assertTrue(not np.any(diff), msg=msg) - return test_resample - # A list of input `.cdl` files where XIOS is known to produce different # output from the expected output data # for future investigation / ToDo -known_failures = ['test_axis_input_edge_simple_square_ten.cdl'] +known_failures = ['test_axis_input_edge_simple_square_ten'] # iterate through `.cdl` files in this test case folder for f in glob.glob('{}/*.cdl'.format(this_dir)): # unique name for the test - tname = 'test_{}'.format(os.path.basename(f)) + tname = 'test_{}'.format(os.path.splitext(os.path.basename(f))[0]) # add the test as an attribute (function) to the test class if tname in known_failures: # set decorator @unittest.expectedFailure - setattr(TestResampleAxis, tname, unittest.expectedFailure(make_a_test(f))) + setattr(TestResampleAxis, tname, + unittest.expectedFailure(TestResampleAxis.make_a_resample_test(f))) else: - setattr(TestResampleAxis, tname, make_a_test(f)) + setattr(TestResampleAxis, tname, + TestResampleAxis.make_a_resample_test(f)) diff --git a/xios_examples/read_domain_resample/test_resample_cases.py b/xios_examples/read_domain_resample/test_resample_cases.py index dd434d0..95cb204 100644 --- a/xios_examples/read_domain_resample/test_resample_cases.py +++ b/xios_examples/read_domain_resample/test_resample_cases.py @@ -16,50 +16,12 @@ class TestResampleDomain(xshared._TestCase): transient_inputs = ['domain_input.nc'] transient_outputs = ['domain_output.nc'] + # A list of input `.cdl` files where XIOS is known to produce different # output from the expected output data # for future investigation / ToDo -known_failures = []#['test_axis_input_edge_simple_square_ten.cdl'] - - -def make_a_test(inf): - """ - this function makes a test case and returns it as a function. - - """ - # always copy for value, don't pass by reference. - infile = copy.copy(inf) - # expected by the fortran XIOS resample program's main.xml - outfile = TestResampleDomain.transient_inputs[0] - def test_resample(self): - # create a netCDF file from the `.cdl` input - subprocess.run(['ncgen', '-k', 'nc4', '-o', outfile, - infile], cwd=this_dir) - # run the compiled Fortran XIOS programme - subprocess.run(['mpiexec', '-n', '1', './resample.exe', ':', - '-n', '1', './xios_server.exe'], cwd=this_dir) - # load the result netCDF file - runfile = '{}/{}'.format(this_dir, - TestResampleDomain.transient_outputs[0]) - self.assertTrue(os.path.exists(runfile)) - rootgrp = netCDF4.Dataset(runfile, 'r') - # read data from the resampled, expected & diff variables - diff = rootgrp['resampled_minus_resample'][:] - # prepare message for failure - msg = ('the expected resample data array\n {exp}\n ' - 'differs from the resampled data array\n {res} \n ' - 'with diff \n {diff}\n') - msg = msg.format(exp=rootgrp['resample_data'][:], - res=rootgrp['resampled_data'][:], - diff=diff) - if np.any(diff): - # print message for fail case, - # as expected failures do not report msg. - print(msg) - # assert that all of the `diff` varaible values are zero - self.assertTrue(not np.any(diff), msg=msg) - return test_resample - +known_failures = ['test_domain_input_edge_simple_square_ten', + 'test_domain_input_simple_square_ten'] # iterate through `.cdl` files in this test case folder for f in glob.glob('{}/*.cdl'.format(this_dir)): @@ -68,6 +30,8 @@ def test_resample(self): # add the test as an attribute (function) to the test class if tname in known_failures: # set decorator @unittest.expectedFailure - setattr(TestResampleDomain, tname, unittest.expectedFailure(make_a_test(f))) + setattr(TestResampleDomain, tname, + unittest.expectedFailure(TestResampleDomain.make_a_resample_test(f))) else: - setattr(TestResampleDomain, tname, make_a_test(f)) + setattr(TestResampleDomain, tname, + TestResampleDomain.make_a_resample_test(f)) diff --git a/xios_examples/shared_testing.py b/xios_examples/shared_testing.py index 501a140..90a4e46 100644 --- a/xios_examples/shared_testing.py +++ b/xios_examples/shared_testing.py @@ -9,6 +9,7 @@ this_path = os.path.realpath(__file__) this_dir = os.path.dirname(this_path) + class _TestCase(unittest.TestCase): """ UnitTest class to contain tests, @@ -46,6 +47,9 @@ def tearDown(self): report any errors from XIOS, then remove the input and output netCDF files. + Use environment variable 'files' to avoid clean up of transient files + note; this can cause multi-test classes to fail with ncgen errors, use + for single test functions only. """ for ef in glob.glob('{}/*.err'.format(this_dir)): @@ -55,11 +59,11 @@ def tearDown(self): for t_in in self.transient_inputs: rf = '{}/{}'.format(self.test_dir, t_in) - if os.path.exists(rf): + if os.path.exists(rf) and not os.environ.get("files"): os.remove(rf) for t_out in self.transient_outputs: rf = '{}/{}'.format(self.test_dir, t_out) - if os.path.exists(rf): + if os.path.exists(rf) and not os.environ.get("files"): os.remove(rf) @classmethod @@ -67,6 +71,48 @@ def tearDownClass(cls): """ Finally, clean the build for this class, after all tests have run. + Use environment variable 'logs' to avoid clean up, e.g. to keep logs """ - subprocess.run(['make', 'clean'], cwd=cls.test_dir) + if not os.environ.get('logs'): + subprocess.run(['make', 'clean'], cwd=cls.test_dir) + + @classmethod + def make_a_resample_test(cls, inf): + """ + this function makes a test case and returns it as a test function, + suitable to be dynamically added to a TestCase for running. + + """ + # always copy for value, don't pass by reference. + infile = copy.copy(inf) + # expected by the fortran XIOS resample program's main.xml + inputfile = cls.transient_inputs[0] + outputfile = cls.transient_outputs[0] + def test_resample(self): + # create a netCDF file from the `.cdl` input + subprocess.run(['ncgen', '-k', 'nc4', '-o', inputfile, + infile], cwd=cls.test_dir) + # run the compiled Fortran XIOS programme + subprocess.run(['mpiexec', '-n', '1', './resample.exe', ':', + '-n', '1', './xios_server.exe'], cwd=cls.test_dir) + # load the result netCDF file + runfile = '{}/{}'.format(cls.test_dir, outputfile) + assert(os.path.exists(runfile)) + rootgrp = netCDF4.Dataset(runfile, 'r') + # read data from the resampled, expected & diff variables + diff = rootgrp['resampled_minus_resample'][:] + # prepare message for failure + msg = ('the expected resample data array\n {exp}\n ' + 'differs from the resampled data array\n {res} \n ' + 'with diff \n {diff}\n') + msg = msg.format(exp=rootgrp['resample_data'][:], + res=rootgrp['resampled_data'][:], + diff=diff) + if np.any(diff): + # print message for fail case, + # as expected failures do not report msg. + print(msg) + # assert that all of the `diff` varaible values are zero + self.assertTrue(not np.any(diff), msg=msg) + return test_resample From e97f7a5065f000b1a7951bd27db4994fe6d3719b Mon Sep 17 00:00:00 2001 From: marqh Date: Tue, 6 Feb 2024 17:26:31 +0000 Subject: [PATCH 7/8] linear interpolate domain and add tolerance float compare --- .../read_axis_resample/test_resample_cases.py | 1 + .../domain_input_simple_linear.cdl | 49 +++++++++++++++++++ xios_examples/read_domain_resample/main.xml | 2 +- .../read_domain_resample/resample.F90 | 17 +++---- .../test_resample_cases.py | 1 + xios_examples/shared_testing.py | 15 +++--- 6 files changed, 68 insertions(+), 17 deletions(-) create mode 100644 xios_examples/read_domain_resample/domain_input_simple_linear.cdl diff --git a/xios_examples/read_axis_resample/test_resample_cases.py b/xios_examples/read_axis_resample/test_resample_cases.py index cb69032..87bf604 100644 --- a/xios_examples/read_axis_resample/test_resample_cases.py +++ b/xios_examples/read_axis_resample/test_resample_cases.py @@ -16,6 +16,7 @@ class TestResampleAxis(xshared._TestCase): test_dir = this_dir transient_inputs = ['axis_input.nc'] transient_outputs = ['axis_output.nc'] + rtol = 5e-04 # A list of input `.cdl` files where XIOS is known to produce different diff --git a/xios_examples/read_domain_resample/domain_input_simple_linear.cdl b/xios_examples/read_domain_resample/domain_input_simple_linear.cdl new file mode 100644 index 0000000..e271c6d --- /dev/null +++ b/xios_examples/read_domain_resample/domain_input_simple_linear.cdl @@ -0,0 +1,49 @@ +netcdf domain_input { +dimensions: + x = 5 ; + y = 5 ; + x_resample = 2 ; + y_resample = 2 ; +variables: + float x(x) ; + x:long_name = "original x coordinate" ; + x:units = "1"; + float y(y) ; + y:long_name = "original y coordinate" ; + y:units = "1"; + float x_resample(x_resample) ; + x_resample:long_name = "resampled x coordinate" ; + x_resample:units = "1"; + float y_resample(y_resample) ; + y_resample:long_name = "resampled y coordinate" ; + y_resample:units = "1"; + double original_data(y,x) ; + original_data:long_name = "input data values" ; + original_data:units = "1"; + double resample_data(y_resample,x_resample) ; + resample_data:long_name = "expected resampled data values" ; + resample_data:units = "1"; + +// global attributes: + :title = "Input data for XIOS Domain resampling; data is a sum of the x & y coordinates; x + y ." ; + +data: + + x = 0, 2, 4, 6, 8 ; + + y = 0, 2, 4, 6, 8 ; + + x_resample = 3, 5 ; + + y_resample = 3, 5 ; + + original_data = 0, 2, 4, 6, 8, + 2, 4, 6, 8, 10, + 4, 6, 8, 10, 12, + 6, 8, 10, 12, 14, + 8, 10, 12, 14, 16 ; + + resample_data = 6, 8, + 8, 10 ; + +} diff --git a/xios_examples/read_domain_resample/main.xml b/xios_examples/read_domain_resample/main.xml index 3dafcb3..409027a 100644 --- a/xios_examples/read_domain_resample/main.xml +++ b/xios_examples/read_domain_resample/main.xml @@ -6,7 +6,7 @@ - + diff --git a/xios_examples/read_domain_resample/resample.F90 b/xios_examples/read_domain_resample/resample.F90 index e9ba0d4..3874f47 100644 --- a/xios_examples/read_domain_resample/resample.F90 +++ b/xios_examples/read_domain_resample/resample.F90 @@ -58,15 +58,12 @@ subroutine initialise() call xios_get_axis_attr('y', n_glo=leny) call xios_get_axis_attr('y_resample', n_glo=lenry) - print *, 'x, y', lenx, ', ', leny - print *, 'rx, ry', lenrx, ', ', lenry - - ! ensure to finalize this checking context before initialising - ! the domain context for further use - call xios_context_finalize() + ! print *, 'x, y', lenx, ', ', leny + ! print *, 'rx, ry', lenrx, ', ', lenry ! initialize the main context for interacting with the data. call xios_context_initialize('main', comm) + call xios_set_time_origin(origin) call xios_set_start_date(start) call xios_set_timestep(tstep) @@ -74,8 +71,6 @@ subroutine initialise() call xios_set_domain_attr("original_domain", ni=lenx, nj=leny, ibegin=0, jbegin=0) call xios_set_domain_attr("resampled_domain", ni=lenrx, nj=lenry, ibegin=0, jbegin=0) - print *, 'closing context definition for main' - call xios_close_context_definition() end subroutine initialise @@ -84,7 +79,10 @@ subroutine finalise() integer :: mpi_error - ! Finalise XIOS and MPI + ! Finalise all XIOS contexts and MPI + call xios_set_current_context('axis_check') + call xios_context_finalize() + call xios_set_current_context('main') call xios_context_finalize() call MPI_Comm_free(comm, mpi_error) call xios_finalize() @@ -109,7 +107,6 @@ subroutine simulate() call xios_get_domain_attr('original_domain', nj_glo=leny) call xios_get_domain_attr('resampled_domain', ni_glo=lenrx) call xios_get_domain_attr('resampled_domain', nj_glo=lenry) - print *, 'x, y', lenx, ', ', leny allocate ( inodata(leny, lenx) ) allocate ( inedata(lenry, lenrx) ) diff --git a/xios_examples/read_domain_resample/test_resample_cases.py b/xios_examples/read_domain_resample/test_resample_cases.py index 95cb204..52aa494 100644 --- a/xios_examples/read_domain_resample/test_resample_cases.py +++ b/xios_examples/read_domain_resample/test_resample_cases.py @@ -15,6 +15,7 @@ class TestResampleDomain(xshared._TestCase): test_dir = this_dir transient_inputs = ['domain_input.nc'] transient_outputs = ['domain_output.nc'] + rtol = 5e-03 # A list of input `.cdl` files where XIOS is known to produce different diff --git a/xios_examples/shared_testing.py b/xios_examples/shared_testing.py index 90a4e46..e6f8d9b 100644 --- a/xios_examples/shared_testing.py +++ b/xios_examples/shared_testing.py @@ -19,6 +19,7 @@ class _TestCase(unittest.TestCase): test_dir = this_dir transient_inputs = [] transient_outputs = [] + rtol = 5e-03 @classmethod def setUpClass(cls): @@ -92,27 +93,29 @@ def make_a_resample_test(cls, inf): def test_resample(self): # create a netCDF file from the `.cdl` input subprocess.run(['ncgen', '-k', 'nc4', '-o', inputfile, - infile], cwd=cls.test_dir) + infile], cwd=cls.test_dir, check=True) # run the compiled Fortran XIOS programme subprocess.run(['mpiexec', '-n', '1', './resample.exe', ':', - '-n', '1', './xios_server.exe'], cwd=cls.test_dir) + '-n', '1', './xios_server.exe'], + cwd=cls.test_dir, check=True) # load the result netCDF file runfile = '{}/{}'.format(cls.test_dir, outputfile) assert(os.path.exists(runfile)) rootgrp = netCDF4.Dataset(runfile, 'r') # read data from the resampled, expected & diff variables diff = rootgrp['resampled_minus_resample'][:] + expected = rootgrp['resample_data'][:] + result = rootgrp['resampled_data'][:] # prepare message for failure msg = ('the expected resample data array\n {exp}\n ' 'differs from the resampled data array\n {res} \n ' 'with diff \n {diff}\n') - msg = msg.format(exp=rootgrp['resample_data'][:], - res=rootgrp['resampled_data'][:], - diff=diff) + msg = msg.format(exp=expected, res=result, diff=diff) if np.any(diff): # print message for fail case, # as expected failures do not report msg. print(msg) # assert that all of the `diff` varaible values are zero - self.assertTrue(not np.any(diff), msg=msg) + # self.assertTrue(not np.any(diff), msg=msg) + self.assertTrue(np.allclose(result, expected, rtol=cls.rtol), msg=msg) return test_resample From f0eda8d5017458431f2e4bb851258e74e348d284 Mon Sep 17 00:00:00 2001 From: marqh Date: Thu, 15 Feb 2024 09:27:19 +0000 Subject: [PATCH 8/8] re-introduce XIOS3 with individual test skip patterns --- .github/workflows/buildTest.yml | 3 +-- .../read_axis_resample/test_resample_cases.py | 17 ++++++++++++++-- .../test_resample_cases.py | 20 ++++++++++++++++--- xios_examples/shared_testing.py | 2 +- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/.github/workflows/buildTest.yml b/.github/workflows/buildTest.yml index 4fbd899..e7db73c 100644 --- a/.github/workflows/buildTest.yml +++ b/.github/workflows/buildTest.yml @@ -12,8 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - # version: [XIOS/trunk@2252, XIOS2/trunk, XIOS3/trunk] - version: [XIOS/trunk@2252, XIOS2/trunk] + version: [XIOS/trunk@2252, XIOS2/trunk, XIOS3/trunk] steps: # Check out repository branch - uses: actions/checkout@v4 diff --git a/xios_examples/read_axis_resample/test_resample_cases.py b/xios_examples/read_axis_resample/test_resample_cases.py index 87bf604..5026747 100644 --- a/xios_examples/read_axis_resample/test_resample_cases.py +++ b/xios_examples/read_axis_resample/test_resample_cases.py @@ -22,14 +22,27 @@ class TestResampleAxis(xshared._TestCase): # A list of input `.cdl` files where XIOS is known to produce different # output from the expected output data # for future investigation / ToDo -known_failures = ['test_axis_input_edge_simple_square_ten'] +# this is a dict, where the name of the key is the name of the test +# to register as a known_failure (tname) +# and the value is a string explaining the failure +# this handles FAIL conditions but NOT ERROR conditions +known_failures = {'test_axis_input_edge_simple_square_ten': + ('The last value, nearest the upper edge is' + ' not being interpolated using a square poynomial' + ' unlike the first, which is also near the edge' + ' and is being calculated sensibly')} # iterate through `.cdl` files in this test case folder for f in glob.glob('{}/*.cdl'.format(this_dir)): # unique name for the test tname = 'test_{}'.format(os.path.splitext(os.path.basename(f))[0]) # add the test as an attribute (function) to the test class - if tname in known_failures: + if os.environ.get('MVER', '') == 'XIOS3/trunk': + # these tests are hitting exceptions with XIOS3 + # but not XIOS2, so skip for XIOS3 runner + setattr(TestResampleAxis, tname, + unittest.skip(TestResampleAxis.make_a_resample_test(f))) + elif tname in known_failures: # set decorator @unittest.expectedFailure setattr(TestResampleAxis, tname, unittest.expectedFailure(TestResampleAxis.make_a_resample_test(f))) diff --git a/xios_examples/read_domain_resample/test_resample_cases.py b/xios_examples/read_domain_resample/test_resample_cases.py index 52aa494..090ed03 100644 --- a/xios_examples/read_domain_resample/test_resample_cases.py +++ b/xios_examples/read_domain_resample/test_resample_cases.py @@ -21,15 +21,29 @@ class TestResampleDomain(xshared._TestCase): # A list of input `.cdl` files where XIOS is known to produce different # output from the expected output data # for future investigation / ToDo -known_failures = ['test_domain_input_edge_simple_square_ten', - 'test_domain_input_simple_square_ten'] +# this is a dict, where the name of the key is the name of the test +# to register as a known_failure (tname) +# and the value is a string explaining the failure +# this handles FAIL conditions but NOT ERROR conditions +known_failures = {'test_domain_input_edge_simple_square_ten': + ('The bi-linear polynomial poorly reproduces the' + ' input x^2+y^2 function'), + 'test_domain_input_simple_square_ten': + ('The bi-linear polynomial poorly reproduces the' + ' input x^2+y^2 function') + } # iterate through `.cdl` files in this test case folder for f in glob.glob('{}/*.cdl'.format(this_dir)): # unique name for the test tname = 'test_{}'.format(os.path.splitext(os.path.basename(f))[0]) # add the test as an attribute (function) to the test class - if tname in known_failures: + if os.environ.get('MVER', '') == 'XIOS3/trunk': + # these tests are hitting exceptions with XIOS3 + # but not XIOS2, so skip for XIOS3 runner + setattr(TestResampleDomain, tname, + unittest.skip(TestResampleDomain.make_a_resample_test(f))) + elif tname in known_failures: # set decorator @unittest.expectedFailure setattr(TestResampleDomain, tname, unittest.expectedFailure(TestResampleDomain.make_a_resample_test(f))) diff --git a/xios_examples/shared_testing.py b/xios_examples/shared_testing.py index e6f8d9b..2553f6d 100644 --- a/xios_examples/shared_testing.py +++ b/xios_examples/shared_testing.py @@ -30,7 +30,7 @@ def setUpClass(cls): subprocess.run(['make', 'clean'], cwd=cls.test_dir) subprocess.run(['make'], cwd=cls.test_dir) if os.environ.get('MVER', '') == 'XIOS3/trunk': - with open(os.path.join(this_dir, 'iodef.xml'), 'r') as ioin: + with open(os.path.join(cls.test_dir, 'main.xml'), 'r') as ioin: iodef_in = ioin.read() # patch in transport protocol choice for XIOS3 # needed for CI runners