source: palm/trunk/UTIL/inifor/tests/inifor_test.py

Last change on this file was 4843, checked in by raasch, 3 years ago

local namelist parameter added to switch off the module although the respective module namelist appears in the namelist file, further copyright updates

  • Property svn:executable set to *
File size: 6.7 KB
Line 
1#!/usr/bin/env python
2#------------------------------------------------------------------------------#
3# This file is part of the PALM model system.
4#
5# PALM is free software: you can redistribute it and/or modify it under the
6# terms of the GNU General Public License as published by the Free Software
7# Foundation, either version 3 of the License, or (at your option) any later
8# version.
9#
10# PALM is distributed in the hope that it will be useful, but WITHOUT ANY
11# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along with
15# PALM. If not, see <http://www.gnu.org/licenses/>.
16#
17# Copyright 2017-2021 Leibniz Universitaet Hannover
18# Copyright 2017-2021 Deutscher Wetterdienst Offenbach
19#------------------------------------------------------------------------------#
20#
21# Current revisions:
22# -----------------
23#
24#
25# Former revisions:
26# -----------------
27#
28# Initial revision
29#
30#
31#
32#
33# Authors:
34# --------
35# @author Eckhard Kadasch
36#
37# Description:
38# ------------
39# This script runs the INIFOR integration test. It runs the 'inifor' executable
40# found in the test directory (the directory this script resides in) and
41# compares the produced dynamic driver file with a referene file.
42#------------------------------------------------------------------------------#
43from netCDF4 import Dataset
44from numpy import max as numpy_max
45from os import path
46from subprocess import run
47from sys import argv, exit
48
49EXIT_CODE_OK = 0
50EXIT_CODE_FAIL = 1
51ATTRIBUTES_TO_CHECK = set(['origin_lon', 'origin_lat', 'origin_z'])
52DEBUGGING = 'on'
53REFERENCE_FILENAME = 'reference.nc'
54TEST_FILENAME = 'test.nc'
55   
56
57def main(argv):
58
59    test_dir = directory_of_this_script()
60    case_dir = test_dir + '/cases/20130720_cosmo'
61    path_to_reference_file = case_dir + '/' + REFERENCE_FILENAME
62    path_to_test_file = case_dir + '/' + TEST_FILENAME
63    inifor_binary = test_dir + '/inifor'
64    reference_call = "%s \
65--namelist %s/namelist \
66--path %s \
67--date 2013072012 \
68--elevation 42.0 \
69--averaging-angle 0.02 \
70--output %s" % (inifor_binary, case_dir, case_dir, path_to_test_file)
71    run(['rm', '-f', path_to_test_file], cwd=test_dir)
72    print(reference_call)
73    run(reference_call.split(' '), cwd=test_dir)
74
75    try:
76
77       with Dataset(path_to_reference_file, 'r') as reference_file, \
78            Dataset(path_to_test_file, 'r') as test_file:
79
80            print_debug('Comparing test file: %s' % path_to_test_file)
81            print_debug('with reference file: %s' % path_to_reference_file)
82
83            exit_code = compare_files(reference_file, test_file)
84
85    except OSError as e:
86
87        print_debug('%s: %s' % (e.strerror, e.filename.decode('utf-8')))
88        exit_code = EXIT_CODE_FAIL
89
90    print_test_result(exit_code)
91    return exit_code
92
93
94def compare_files(reference_file, test_file):
95
96    test_result, missing_items = test_file_contains_reference_attributes(test_file)
97    try:
98        assert test_result
99        print_debug('All required global attributes are present.')
100    except AssertionError:
101        print_debug('The following global attributes are missing:')
102        print_debug(missing_items)
103        return EXIT_CODE_FAIL
104
105    try:
106        assert all_attributes_match(reference_file, test_file)
107        print_debug('All attributes match.')
108    except AssertionError:
109        print_debug('Some global attributes do not match.')
110        return EXIT_CODE_FAIL
111
112    test_result, missing_items = test_file_contains_reference_variables(reference_file, test_file)
113    try:
114        assert test_result
115        print_debug('All variables are present.')
116    except AssertionError:
117        print_debug('The following variables are missing:')
118        print_debug(missing_items)
119        return EXIT_CODE_FAIL
120
121    try:
122        assert all_variables_match(reference_file, test_file)
123        print_debug('All variables match.')
124    except AssertionError:
125        print_debug('Some variables do not match.')
126        return EXIT_CODE_FAIL
127
128    return EXIT_CODE_OK
129
130
131def test_file_contains_reference_variables(reference_file, test_file):
132    """
133    Check if any netCDF variable contained in the reference file is missing
134    from the test file. Additional variables in the test file are permitted.
135    """
136    reference_vars = set(reference_file.variables.keys())
137    test_vars = set(test_file.variables.keys())
138
139    return set_contains_reference_items(
140        reference_set=set(reference_file.variables.keys()),
141        test_set=set(test_file.variables.keys())
142    )
143
144
145def all_variables_match(file_a, file_b):
146    vars_a = set(file_a.variables.keys())
147    vars_b = set(file_b.variables.keys())
148    shared_vars = vars_a.intersection(vars_b)
149    true_if_all_match = True
150   
151    for var in shared_vars:
152        try:
153            assert (file_a.variables[var][:] == file_b.variables[var][:]).all()
154            print_debug(%s: data matches' % var)
155        except AssertionError:
156            max_diff = numpy_max(file_a.variables[var][:] - file_b.variables[var][:])
157            print_debug(%s: max error = %f' % (var, max_diff))
158            true_if_all_match = False
159
160    return true_if_all_match
161
162
163def test_file_contains_reference_attributes(test_file):
164    """
165    Check if any required global netCDF attribute (listed in
166    ATTRIBUTES_TO_CHECK) are missing from the test file. Additional attributes
167    are permitted.
168    """
169    return set_contains_reference_items(
170        reference_set=ATTRIBUTES_TO_CHECK,
171        test_set=set(test_file.ncattrs())
172    )
173
174
175def all_attributes_match(reference_file, test_file):
176    for attribute in ATTRIBUTES_TO_CHECK:
177        reference_value = float(reference_file.getncattr(attribute))
178        test_value = float(test_file.getncattr(attribute))
179        try:
180            assert (test_value == reference_value)
181            print_debug(%s: value matches' % attribute)
182        except AssertionError:
183            diff = test_value - reference_value
184            print_debug(%s: error = %f' % (attribute, diff))
185            return False
186
187    return True
188
189
190def set_contains_reference_items(reference_set, test_set):
191    missing_items = reference_set.difference(test_set)
192    if len(missing_items) == 0:
193        return True, missing_items
194    else:
195        return False, missing_items
196
197
198def directory_of_this_script():
199    return path.dirname(path.realpath(__file__))
200
201
202def print_debug(message):
203    if DEBUGGING == 'on':
204        print('inifor_test: %s' % message)
205
206
207def print_test_result(exit_code):
208
209    if exit_code == EXIT_CODE_OK:
210        print_debug('SUCCESS: INIFOR passed all tests.')
211    else:
212        print_debug('FAILURE: INIFOR failed the above test.')
213
214
215if __name__ == '__main__':
216    exit(main(argv))
217
Note: See TracBrowser for help on using the repository browser.