Coverage for pySDC/helpers/testing.py: 100%

30 statements  

« prev     ^ index     » next       coverage.py v7.6.9, created at 2024-12-20 14:51 +0000

1#!/usr/bin/env python3 

2# -*- coding: utf-8 -*- 

3""" 

4Created on Fri Feb 9 14:41:43 2024 

5 

6Helpers module for testing utilities 

7""" 

8import os 

9import json 

10import warnings 

11import numpy as np 

12 

13 

14class DataChecker: 

15 """ 

16 Object allowing to quickly generate and check generated data from scripts. 

17 

18 Here is an example of use for one given script: 

19 

20 >>> from pySDC.helpers.testing import DataChecker 

21 >>> 

22 >>> data = DataChecker(__file__) 

23 >>> # ... some computations ... 

24 >>> data.storeAndCheck('solution', solution) 

25 >>> # ... some other computations ... 

26 >>> data.storeAndCheck('errors', errors) 

27 >>> # ... ploting some figures 

28 >>> data.writeToJSON() # end of script 

29 

30 The `storeAndCheck` method use a unique key as first argument, and the 

31 data as second argument, into list format. 

32 Calling this method will store the data into a cache variable, and compare 

33 with reference data stored in `_dataRef.json` (if it exists, see below ...). 

34 Finally, the `writeToJSON` method saves the cache variable into a json 

35 file `_data.json`. 

36 

37 When there is no `_dataRef.json` in the script directory, 

38 executing the script output some warning telling that there is no 

39 reference data to compare with. 

40 To remove those warnings (and properly test data), just rename the 

41 `_data.json` into `_dataRef.json`. 

42 Then re-running the script will then compare the newly generated data with 

43 the reference data stored into `_dataRef.json`, and raise an error if there 

44 is some differences. 

45 

46 Important 

47 --------- 

48 

49 - using the `__file__` built-in variable is necessary to save data in the 

50 script directory, independently of the working directory. 

51 - several script in the same directory can use the DataChecker, which 

52 implies that the key provided to `storeAndCheck` must be unique across 

53 all directory scripts. If not, the same key from previous directory will 

54 simply be overwritten in the cached variable and the `_data.ref` file. 

55 """ 

56 

57 def __init__(self, filePath): 

58 path = '/' + os.path.join(*filePath.split('/')[:-1]) 

59 self._data = {} # cache for data 

60 self._dataRef = None # cache for reference data 

61 self._dataFile = os.path.join(path, '_data.json') 

62 self._dataRefFile = os.path.join(path, '_dataRef.json') 

63 

64 def storeAndCheck(self, key, data, rtol=1e-5, atol=1e-8): 

65 """ 

66 Store data into cache, and check with eventual reference data 

67 

68 Parameters 

69 ---------- 

70 key : str 

71 Unique key (project wide) for the data. 

72 data : list or array-like 

73 The data that has to be stored. 

74 rtol : float 

75 Relative tolerance 

76 atol : float 

77 Absolute tolerance 

78 """ 

79 self._data[key] = list(data) 

80 if self._dataRef is None: 

81 try: 

82 with open(self._dataRefFile, "r") as f: 

83 self._dataRef = json.load(f) 

84 except FileNotFoundError: 

85 warnings.warn(f"no reference data to check key:{key}") 

86 return # pragma: no cover 

87 

88 assert key in self._dataRef, f"key:{key} not in reference data" 

89 

90 data = self._data[key] 

91 ref = self._dataRef[key] 

92 

93 assert len(data) == len(ref), f"data with len:{len(data)}) cannot be compared to ref with len:{len(ref)})" 

94 assert np.allclose( 

95 data, ref, atol=atol, rtol=rtol, equal_nan=True 

96 ), f"{key}, difference between data:{data} and ref:{ref}" 

97 

98 def writeToJSON(self): 

99 """Write cached data into a json file""" 

100 if os.path.isfile(self._dataFile): 

101 with open(self._dataFile, "r") as f: 

102 self._data.update(json.load(f)) 

103 with open(self._dataFile, "w") as f: 

104 json.dump(self._data, f)