sofar 1.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. docs/Makefile +20 -0
  2. docs/api_reference.rst +20 -0
  3. docs/conf.py +167 -0
  4. docs/contributing.rst +1 -0
  5. docs/history.rst +1 -0
  6. docs/index.rst +4 -0
  7. docs/make.bat +36 -0
  8. docs/readme.rst +1 -0
  9. docs/resources/conventions.py +162 -0
  10. docs/resources/working_with_sofa_HRIR_lateral.png +0 -0
  11. docs/resources/working_with_sofa_source_horizontal.png +0 -0
  12. docs/resources/working_with_sofa_source_lateral.png +0 -0
  13. docs/sofar.rst +82 -0
  14. sofar/__init__.py +28 -0
  15. sofar/io.py +427 -0
  16. sofar/sofa.py +1835 -0
  17. sofar/sofa_conventions/VERSION +1 -0
  18. sofar/sofa_conventions/conventions/AnnotatedEmitterAudio_0.2.csv +46 -0
  19. sofar/sofa_conventions/conventions/AnnotatedEmitterAudio_0.2.json +353 -0
  20. sofar/sofa_conventions/conventions/AnnotatedReceiverAudio_0.2.csv +46 -0
  21. sofar/sofa_conventions/conventions/AnnotatedReceiverAudio_0.2.json +353 -0
  22. sofar/sofa_conventions/conventions/FreeFieldDirectivityTF_1.1.csv +59 -0
  23. sofar/sofa_conventions/conventions/FreeFieldDirectivityTF_1.1.json +444 -0
  24. sofar/sofa_conventions/conventions/FreeFieldHRIR_1.0.csv +43 -0
  25. sofar/sofa_conventions/conventions/FreeFieldHRIR_1.0.json +333 -0
  26. sofar/sofa_conventions/conventions/FreeFieldHRTF_1.0.csv +44 -0
  27. sofar/sofa_conventions/conventions/FreeFieldHRTF_1.0.json +340 -0
  28. sofar/sofa_conventions/conventions/GeneralFIR-E_2.0.csv +37 -0
  29. sofar/sofa_conventions/conventions/GeneralFIR-E_2.0.json +270 -0
  30. sofar/sofa_conventions/conventions/GeneralFIR_1.0.csv +40 -0
  31. sofar/sofa_conventions/conventions/GeneralFIR_1.0.json +295 -0
  32. sofar/sofa_conventions/conventions/GeneralSOS_1.0.csv +40 -0
  33. sofar/sofa_conventions/conventions/GeneralSOS_1.0.json +306 -0
  34. sofar/sofa_conventions/conventions/GeneralTF-E_1.0.csv +38 -0
  35. sofar/sofa_conventions/conventions/GeneralTF-E_1.0.json +277 -0
  36. sofar/sofa_conventions/conventions/GeneralTF_1.0.csv +38 -0
  37. sofar/sofa_conventions/conventions/GeneralTF_1.0.json +277 -0
  38. sofar/sofa_conventions/conventions/GeneralTF_2.0.csv +38 -0
  39. sofar/sofa_conventions/conventions/GeneralTF_2.0.json +277 -0
  40. sofar/sofa_conventions/conventions/SimpleFreeFieldHRIR_1.0.csv +47 -0
  41. sofar/sofa_conventions/conventions/SimpleFreeFieldHRIR_1.0.json +369 -0
  42. sofar/sofa_conventions/conventions/SimpleFreeFieldHRSOS_1.0.csv +43 -0
  43. sofar/sofa_conventions/conventions/SimpleFreeFieldHRSOS_1.0.json +349 -0
  44. sofar/sofa_conventions/conventions/SimpleFreeFieldHRTF_1.0.csv +44 -0
  45. sofar/sofa_conventions/conventions/SimpleFreeFieldHRTF_1.0.json +340 -0
  46. sofar/sofa_conventions/conventions/SimpleFreeFieldSOS_1.0.csv +43 -0
  47. sofar/sofa_conventions/conventions/SimpleFreeFieldSOS_1.0.json +349 -0
  48. sofar/sofa_conventions/conventions/SimpleHeadphoneIR_1.0.csv +51 -0
  49. sofar/sofa_conventions/conventions/SimpleHeadphoneIR_1.0.json +396 -0
  50. sofar/sofa_conventions/conventions/SingleRoomMIMOSRIR_1.0.csv +78 -0
  51. sofar/sofa_conventions/conventions/SingleRoomMIMOSRIR_1.0.json +601 -0
  52. sofar/sofa_conventions/conventions/SingleRoomSRIR_1.0.csv +78 -0
  53. sofar/sofa_conventions/conventions/SingleRoomSRIR_1.0.json +601 -0
  54. sofar/sofa_conventions/conventions/deprecated/AnnotatedEmitterAudio_0.1.csv +46 -0
  55. sofar/sofa_conventions/conventions/deprecated/AnnotatedEmitterAudio_0.1.json +351 -0
  56. sofar/sofa_conventions/conventions/deprecated/AnnotatedReceiverAudio_0.1.csv +46 -0
  57. sofar/sofa_conventions/conventions/deprecated/AnnotatedReceiverAudio_0.1.json +351 -0
  58. sofar/sofa_conventions/conventions/deprecated/FreeFieldDirectivityTF_1.0.csv +58 -0
  59. sofar/sofa_conventions/conventions/deprecated/FreeFieldDirectivityTF_1.0.json +437 -0
  60. sofar/sofa_conventions/conventions/deprecated/GeneralFIRE_1.0.csv +37 -0
  61. sofar/sofa_conventions/conventions/deprecated/GeneralFIRE_1.0.json +270 -0
  62. sofar/sofa_conventions/conventions/deprecated/MultiSpeakerBRIR_0.3.csv +48 -0
  63. sofar/sofa_conventions/conventions/deprecated/MultiSpeakerBRIR_0.3.json +376 -0
  64. sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldHRIR_0.4.csv +43 -0
  65. sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldHRIR_0.4.json +333 -0
  66. sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldTF_0.4.csv +44 -0
  67. sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldTF_0.4.json +340 -0
  68. sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldTF_1.0.csv +44 -0
  69. sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldTF_1.0.json +340 -0
  70. sofar/sofa_conventions/conventions/deprecated/SimpleHeadphoneIR_0.1.csv +51 -0
  71. sofar/sofa_conventions/conventions/deprecated/SimpleHeadphoneIR_0.1.json +396 -0
  72. sofar/sofa_conventions/conventions/deprecated/SimpleHeadphoneIR_0.2.csv +51 -0
  73. sofar/sofa_conventions/conventions/deprecated/SimpleHeadphoneIR_0.2.json +396 -0
  74. sofar/sofa_conventions/conventions/deprecated/SingleRoomDRIR_0.2.csv +47 -0
  75. sofar/sofa_conventions/conventions/deprecated/SingleRoomDRIR_0.2.json +360 -0
  76. sofar/sofa_conventions/conventions/deprecated/SingleRoomDRIR_0.3.csv +47 -0
  77. sofar/sofa_conventions/conventions/deprecated/SingleRoomDRIR_0.3.json +360 -0
  78. sofar/sofa_conventions/conventions/deprecated/SingleTrackedAudio_0.1.csv +47 -0
  79. sofar/sofa_conventions/conventions/deprecated/SingleTrackedAudio_0.1.json +366 -0
  80. sofar/sofa_conventions/conventions/deprecated/SingleTrackedAudio_0.2.csv +51 -0
  81. sofar/sofa_conventions/conventions/deprecated/SingleTrackedAudio_0.2.json +397 -0
  82. sofar/sofa_conventions/rules/deprecations.json +13 -0
  83. sofar/sofa_conventions/rules/rules.json +819 -0
  84. sofar/sofa_conventions/rules/unit_aliases.json +11 -0
  85. sofar/sofa_conventions/rules/upgrade.json +226 -0
  86. sofar/sofa_conventions/write_upgrade_rules.py +139 -0
  87. sofar/sofa_conventions/write_verification_data.py +313 -0
  88. sofar/sofa_conventions/write_verification_rules.py +356 -0
  89. sofar/sofastream.py +301 -0
  90. sofar/update_conventions.py +449 -0
  91. sofar/utils.py +316 -0
  92. sofar-1.2.1.dist-info/LICENSE +22 -0
  93. sofar-1.2.1.dist-info/METADATA +136 -0
  94. sofar-1.2.1.dist-info/RECORD +105 -0
  95. sofar-1.2.1.dist-info/WHEEL +5 -0
  96. sofar-1.2.1.dist-info/top_level.txt +3 -0
  97. tests/__init__.py +0 -0
  98. tests/conftest.py +27 -0
  99. tests/test_deprecations.py +19 -0
  100. tests/test_io.py +349 -0
  101. tests/test_sofa.py +353 -0
  102. tests/test_sofa_upgrade_conventions.py +111 -0
  103. tests/test_sofa_verify.py +480 -0
  104. tests/test_sofastream.py +127 -0
  105. tests/test_utils.py +250 -0
@@ -0,0 +1,11 @@
1
+ {
2
+ "metre": "metre",
3
+ "metres": "metre",
4
+ "meter": "metre",
5
+ "meters": "metre",
6
+ "cubic": "cubic",
7
+ "degree": "degree",
8
+ "degrees": "degree",
9
+ "second": "second",
10
+ "seconds": "second"
11
+ }
@@ -0,0 +1,226 @@
1
+ {
2
+ "AnnotatedEmitterAudio": {
3
+ "from_to": [
4
+ [
5
+ [
6
+ "0.1"
7
+ ],
8
+ [
9
+ "AnnotatedEmitterAudio_0.2"
10
+ ],
11
+ "1"
12
+ ]
13
+ ],
14
+ "1": {
15
+ "move": {},
16
+ "remove": [],
17
+ "message": "The data in the variable 'Response' might have to be updated."
18
+ }
19
+ },
20
+ "AnnotatedReceiverAudio": {
21
+ "from_to": [
22
+ [
23
+ [
24
+ "0.1"
25
+ ],
26
+ [
27
+ "AnnotatedReceiverAudio_0.2"
28
+ ],
29
+ "1"
30
+ ]
31
+ ],
32
+ "1": {
33
+ "move": {},
34
+ "remove": [],
35
+ "message": "The data in the variable 'Response' might have to be updated."
36
+ }
37
+ },
38
+ "FreeFieldDirectivityTF": {
39
+ "from_to": [
40
+ [
41
+ [
42
+ "1.0"
43
+ ],
44
+ [
45
+ "FreeFieldDirectivityTF_1.1"
46
+ ],
47
+ "1"
48
+ ]
49
+ ],
50
+ "1": {
51
+ "move": {
52
+ "EmitterPosition": {
53
+ "target": "EmitterPosition",
54
+ "moveaxis": null,
55
+ "deprecated_dimensions": [
56
+ "IC",
57
+ "MC"
58
+ ]
59
+ },
60
+ "EmitterDescription": {
61
+ "target": "EmitterDescriptions",
62
+ "moveaxis": null,
63
+ "deprecated_dimensions": [
64
+ "IS"
65
+ ]
66
+ }
67
+ },
68
+ "remove": [],
69
+ "message": "Consider to add the optional data 'GLOBAL_EmitterDescription'introduced in convention version 1.1.\nWARNING: Adding 'GLOBAL_EmitterDescription' is required if 'EmitterDescriptions' is contained in the SOFA object."
70
+ }
71
+ },
72
+ "SimpleFreeFieldHRIR": {
73
+ "from_to": [
74
+ [
75
+ [
76
+ "0.4"
77
+ ],
78
+ [
79
+ "SimpleFreeFieldHRIR_1.0"
80
+ ],
81
+ "1"
82
+ ]
83
+ ],
84
+ "1": {
85
+ "move": {},
86
+ "remove": [],
87
+ "message": "Consider to add the optional data 'SourceUp', 'SourceView', 'SourceView:Type', and 'SourceView:Units' with default values that were introduced in convention version 1.0"
88
+ }
89
+ },
90
+ "SimpleFreeFieldTF": {
91
+ "from_to": [
92
+ [
93
+ [
94
+ "0.4",
95
+ "1.0"
96
+ ],
97
+ [
98
+ "SimpleFreeFieldHRTF_1.0"
99
+ ],
100
+ "1"
101
+ ]
102
+ ],
103
+ "1": {
104
+ "move": {},
105
+ "remove": [],
106
+ "message": null
107
+ }
108
+ },
109
+ "SimpleHeadphoneIR": {
110
+ "from_to": [
111
+ [
112
+ [
113
+ "0.1",
114
+ "0.2"
115
+ ],
116
+ [
117
+ "SimpleHeadphoneIR_1.0"
118
+ ],
119
+ "1"
120
+ ]
121
+ ],
122
+ "1": {
123
+ "move": {
124
+ "ReceiverDescription": {
125
+ "target": "ReceiverDescriptions",
126
+ "moveaxis": null,
127
+ "deprecated_dimensions": null
128
+ },
129
+ "EmitterDescription": {
130
+ "target": "EmitterDescriptions",
131
+ "moveaxis": null,
132
+ "deprecated_dimensions": null
133
+ }
134
+ },
135
+ "remove": [],
136
+ "message": null
137
+ }
138
+ },
139
+ "SingleRoomDRIR": {
140
+ "from_to": [
141
+ [
142
+ [
143
+ "0.2",
144
+ "0.3"
145
+ ],
146
+ [
147
+ "SingleRoomSRIR_1.0"
148
+ ],
149
+ "1"
150
+ ]
151
+ ],
152
+ "1": {
153
+ "move": {},
154
+ "remove": [],
155
+ "message": "Consider providing optional data that was introduced in SingleRoomSRIR version 1.0"
156
+ }
157
+ },
158
+ "MultiSpeakerBRIR": {
159
+ "from_to": [
160
+ [
161
+ [
162
+ "0.3"
163
+ ],
164
+ [
165
+ "SingleRoomMIMOSRIR_1.0"
166
+ ],
167
+ "1"
168
+ ]
169
+ ],
170
+ "1": {
171
+ "move": {
172
+ "Data.IR": {
173
+ "target": "Data.IR",
174
+ "moveaxis": [
175
+ 3,
176
+ 2
177
+ ],
178
+ "deprecated_dimensions": null
179
+ },
180
+ "Data.Delay": {
181
+ "target": "Data.Delay",
182
+ "moveaxis": null,
183
+ "deprecated_dimensions": [
184
+ "IRE"
185
+ ]
186
+ }
187
+ },
188
+ "remove": [],
189
+ "message": "Consider providing optional data that was introduced in SingleRoomSRIR version 1.0"
190
+ }
191
+ },
192
+ "GeneralFIRE": {
193
+ "from_to": [
194
+ [
195
+ [
196
+ "1.0"
197
+ ],
198
+ [
199
+ "GeneralFIR-E_2.0"
200
+ ],
201
+ "1"
202
+ ]
203
+ ],
204
+ "1": {
205
+ "move": {
206
+ "Data.IR": {
207
+ "target": "Data.IR",
208
+ "moveaxis": [
209
+ 3,
210
+ 2
211
+ ],
212
+ "deprecated_dimensions": null
213
+ },
214
+ "EmitterPosition": {
215
+ "target": "EmitterPosition",
216
+ "moveaxis": null,
217
+ "deprecated_dimensions": [
218
+ "ECI"
219
+ ]
220
+ }
221
+ },
222
+ "remove": [],
223
+ "message": "Consider providing optional data that was introduced in SingleRoomSRIR version 1.0"
224
+ }
225
+ }
226
+ }
@@ -0,0 +1,139 @@
1
+ """
2
+ Write rules for upgrading outdated SOFA files.
3
+
4
+ Writes the following json files:
5
+ upgrade.json
6
+
7
+ For a more detailed information about the json files refer to _readme.txt
8
+ """
9
+ # %%
10
+ import json
11
+ import os
12
+
13
+ upgrade = {
14
+ "AnnotatedEmitterAudio": {
15
+ "from_to": [[["0.1"], ["AnnotatedEmitterAudio_0.2"], "1"]],
16
+ "1": {
17
+ "move": {},
18
+ "remove": [],
19
+ "message": ("The data in the variable 'Response' "
20
+ "might have to be updated."),
21
+ },
22
+ },
23
+ "AnnotatedReceiverAudio": {
24
+ "from_to": [[["0.1"], ["AnnotatedReceiverAudio_0.2"], "1"]],
25
+ "1": {
26
+ "move": {},
27
+ "remove": [],
28
+ "message": ("The data in the variable 'Response' "
29
+ "might have to be updated."),
30
+ },
31
+ },
32
+ "FreeFieldDirectivityTF": {
33
+ "from_to": [[["1.0"], ["FreeFieldDirectivityTF_1.1"], "1"]],
34
+ "1": {
35
+ "move": {
36
+ "EmitterPosition": {
37
+ "target": "EmitterPosition",
38
+ "moveaxis": None,
39
+ "deprecated_dimensions": ["IC", "MC"]},
40
+ "EmitterDescription": {
41
+ "target": "EmitterDescriptions",
42
+ "moveaxis": None,
43
+ "deprecated_dimensions": ["IS"]},
44
+ },
45
+ "remove": [],
46
+ "message": ("Consider to add the optional data "
47
+ "'GLOBAL_EmitterDescription'"
48
+ "introduced in convention version 1.1.\n"
49
+ "WARNING: Adding 'GLOBAL_EmitterDescription' is "
50
+ "required if 'EmitterDescriptions' is contained in "
51
+ "the SOFA object."),
52
+ },
53
+ },
54
+ "SimpleFreeFieldHRIR": {
55
+ "from_to": [[["0.4"], ["SimpleFreeFieldHRIR_1.0"], "1"]],
56
+ "1": {
57
+ "move": {},
58
+ "remove": [],
59
+ "message": ("Consider to add the optional data 'SourceUp', "
60
+ "'SourceView', 'SourceView:Type', and "
61
+ "'SourceView:Units' with default values that were "
62
+ "introduced in convention version 1.0"),
63
+ },
64
+ },
65
+ "SimpleFreeFieldTF": {
66
+ "from_to": [[["0.4", "1.0"], ["SimpleFreeFieldHRTF_1.0"], "1"]],
67
+ "1": {
68
+ "move": {},
69
+ "remove": [],
70
+ "message": None,
71
+ },
72
+ },
73
+ "SimpleHeadphoneIR": {
74
+ "from_to": [[["0.1", "0.2"], ["SimpleHeadphoneIR_1.0"], "1"]],
75
+ "1": {
76
+ "move": {
77
+ "ReceiverDescription": {
78
+ "target": "ReceiverDescriptions",
79
+ "moveaxis": None,
80
+ "deprecated_dimensions": None},
81
+ "EmitterDescription": {
82
+ "target": "EmitterDescriptions",
83
+ "moveaxis": None,
84
+ "deprecated_dimensions": None},
85
+ },
86
+ "remove": [],
87
+ "message": None,
88
+ },
89
+ },
90
+ "SingleRoomDRIR": {
91
+ "from_to": [[["0.2", "0.3"], ["SingleRoomSRIR_1.0"], "1"]],
92
+ "1": {
93
+ "move": {},
94
+ "remove": [],
95
+ "message": ("Consider providing optional data that was introduced "
96
+ "in SingleRoomSRIR version 1.0"),
97
+ },
98
+ },
99
+ "MultiSpeakerBRIR": {
100
+ "from_to": [[["0.3"], ["SingleRoomMIMOSRIR_1.0"], "1"]],
101
+ "1": {
102
+ "move": {
103
+ "Data.IR": {
104
+ "target": "Data.IR",
105
+ "moveaxis": [3, 2],
106
+ "deprecated_dimensions": None},
107
+ "Data.Delay": {
108
+ "target": "Data.Delay",
109
+ "moveaxis": None,
110
+ "deprecated_dimensions": ["IRE"]},
111
+ },
112
+ "remove": [],
113
+ "message": ("Consider providing optional data that was introduced "
114
+ "in SingleRoomSRIR version 1.0"),
115
+ },
116
+ },
117
+ "GeneralFIRE": {
118
+ "from_to": [[["1.0"], ["GeneralFIR-E_2.0"], "1"]],
119
+ "1": {
120
+ "move": {
121
+ "Data.IR": {
122
+ "target": "Data.IR",
123
+ "moveaxis": [3, 2],
124
+ "deprecated_dimensions": None},
125
+ "EmitterPosition": {
126
+ "target": "EmitterPosition",
127
+ "moveaxis": None,
128
+ "deprecated_dimensions": ["ECI"]},
129
+ },
130
+ "remove": [],
131
+ "message": ("Consider providing optional data that was introduced "
132
+ "in SingleRoomSRIR version 1.0"),
133
+ },
134
+ },
135
+ }
136
+
137
+ json_file = os.path.join(os.path.dirname(__file__), "rules", "upgrade.json")
138
+ with open(json_file, 'w') as file:
139
+ json.dump(upgrade, file, indent=4)
@@ -0,0 +1,313 @@
1
+ # %%
2
+ """Write verification data to SOFA files."""
3
+ import sofar as sf
4
+ from sofar.utils import _complete_sofa
5
+ import os
6
+ import numpy as np
7
+
8
+ rules, unit_aliases, deprecations, _ = sf.Sofa._verification_rules()
9
+
10
+
11
+ # -----------------------------------------------------------------------------
12
+ # Rules that restrict SOFA attributes to certain values
13
+ print("Write data to test SOFA attributes with restricted values")
14
+ print("---------------------------------------------------------")
15
+
16
+ # key: name of variable or attribute for testing the rule
17
+ for key in rules:
18
+ # check if rule exists
19
+ if "value" not in rules[key] or rules[key]["value"] is None:
20
+ continue
21
+
22
+ # get blank SOFA file
23
+ key_sf = key.replace(".", "_").replace(":", "_")
24
+ filename = f"{key_sf}=invalid-value.sofa"
25
+ print(filename)
26
+ sofa = _complete_sofa()
27
+
28
+ # write invalid value
29
+ sofa.protected = False
30
+ setattr(sofa, key_sf, "invalid-value")
31
+ sofa.protected = True
32
+
33
+ # write invalid SOFA file
34
+ sf.io._write_sofa(
35
+ os.path.join("data", "restricted_values", filename),
36
+ sofa, compression=4, verify=False)
37
+
38
+ del key, key_sf, sofa, filename
39
+
40
+
41
+ # -----------------------------------------------------------------------------
42
+ # Rules that require conditional Attributes or Variables to be existing
43
+ print("\nWrite data to test general dependencies")
44
+ print("---------------------------------------")
45
+
46
+ # key: name of variable or attribute for testing the rule
47
+ for key in rules:
48
+
49
+ # check if rule applies
50
+ if "general" not in rules[key]:
51
+ continue
52
+
53
+ key_sf = key.replace(".", "_").replace(":", "_")
54
+
55
+ for sub in rules[key]["general"]:
56
+
57
+ # get blank SOFA file
58
+ sub_sf = sub.replace(".", "_").replace(":", "_")
59
+ filename = f"{key_sf}.{sub_sf}=missing.sofa"
60
+ print(filename)
61
+ sofa = _complete_sofa()
62
+
63
+ # delete conditional dependency
64
+ sofa.delete(sub_sf)
65
+
66
+ # write invalid SOFA file
67
+ sf.io._write_sofa(os.path.join(
68
+ "data", "general_dependencies", filename),
69
+ sofa, compression=4, verify=False)
70
+
71
+ del key, key_sf, sub, sub_sf, sofa, filename
72
+
73
+
74
+ # -----------------------------------------------------------------------------
75
+ # Specific rules except for GLOBAL:DataType and GLOBAL:SOFAConventions.
76
+ # Specific rules require certain variables or attributes to exist depending
77
+ # on a parent variable or attribute and sometimes also restrict the value for
78
+ # the child.
79
+ print("\nWrite data to test specific dependencies")
80
+ print("----------------------------------------")
81
+
82
+ keys = [k for k in rules.keys() if "specific" in rules[k] and k not in
83
+ ["GLOBAL:DataType", "GLOBAL:SOFAConventions"]]
84
+
85
+ # key: name of variable or attribute for testing specific dependency
86
+ for key in keys:
87
+ key_sf = key.replace(".", "_").replace(":", "_")
88
+
89
+ # key_value: value of the variable or attribute that triggers the
90
+ # specific dependency
91
+ for value_key in rules[key]["specific"]:
92
+
93
+ # sub: name of variable or attribute for which a specific
94
+ # dependency is checked
95
+ for sub in rules[key]["specific"][value_key]:
96
+
97
+ if sub.startswith("_"):
98
+ continue
99
+
100
+ sub_sf = sub.replace(".", "_").replace(":", "_")
101
+ sofa = _complete_sofa()
102
+
103
+ # set key to correct value
104
+ sofa.protected = False
105
+ setattr(sofa, key_sf, value_key)
106
+ sofa.protected = False
107
+
108
+ # test a wrong value sor sub
109
+ value_sub = rules[key]["specific"][value_key][sub]
110
+ if value_sub is not None:
111
+ setattr(sofa, sub_sf, "invalid-value")
112
+ filename = f"{key_sf}={value_key}.{sub_sf}=invalid-value.sofa"
113
+ print(filename)
114
+ sf.io._write_sofa(os.path.join(
115
+ "data", "specific_dependencies", filename),
116
+ sofa, compression=4, verify=False)
117
+
118
+ # test deleting sub
119
+ sofa.protected = False
120
+ delattr(sofa, sub_sf)
121
+ sofa.protected = True
122
+ filename = f"{key_sf}={value_key}.{sub_sf}=missing.sofa"
123
+ print(filename)
124
+ sf.io._write_sofa(os.path.join(
125
+ "data", "specific_dependencies", filename),
126
+ sofa, compression=4, verify=False)
127
+
128
+ del keys, key, key_sf, value_key, sub, sub_sf, sofa, value_sub, filename
129
+
130
+
131
+ # -----------------------------------------------------------------------------
132
+ # specific rules for GLOBAL:DataType
133
+ for data_type in rules["GLOBAL:DataType"]["specific"]:
134
+
135
+ if data_type in ["FIR", "FIR-E", "FIRE", "TF", "TF-E"]:
136
+ convention = "General" + data_type
137
+ elif data_type == "SOS":
138
+ convention = "SimpleFreeFieldHRSOS"
139
+ elif data_type == "FIRE":
140
+ convention = "MultiSpeakerBRIR"
141
+ elif data_type == "Audio":
142
+ convention = "AnnotatedEmitterAudio"
143
+
144
+ for key in rules["GLOBAL:DataType"]["specific"][data_type]:
145
+ if key.startswith("_"):
146
+ continue
147
+
148
+ key_sf = key.replace(".", "_").replace(":", "_")
149
+ sofa = sf.Sofa(convention)
150
+ if sofa.GLOBAL_SOFAConventionsVersion.startswith('0.'):
151
+ sofa.verify(mode="read")
152
+
153
+ # test a wrong value
154
+ value = rules["GLOBAL:DataType"]["specific"][data_type][key]
155
+ if value is not None:
156
+ setattr(sofa, key_sf, "invalid-value")
157
+ filename = \
158
+ f"GLOBAL_DataType={data_type}.{key_sf}=invalid-value.sofa"
159
+ print(filename)
160
+ sf.io._write_sofa(os.path.join(
161
+ "data", "specific_dependencies", filename),
162
+ sofa, compression=4, verify=False)
163
+
164
+ # test deleting the attribute
165
+ sofa.protected = False
166
+ delattr(sofa, key_sf)
167
+ sofa.protected = True
168
+ filename = f"GLOBAL_DataType={data_type}.{key_sf}=missing.sofa"
169
+ print(filename)
170
+ sf.io._write_sofa(os.path.join(
171
+ "data", "specific_dependencies", filename),
172
+ sofa, compression=4, verify=False)
173
+
174
+ del data_type, convention, key, key_sf, sofa, value, filename
175
+
176
+
177
+ # -----------------------------------------------------------------------------
178
+ # specific rules for GLOBAL:SOFAConventions
179
+ for convention in rules["GLOBAL:SOFAConventions"]["specific"]:
180
+ for key in rules["GLOBAL:SOFAConventions"]["specific"][convention]:
181
+ if key.startswith("_"):
182
+ continue
183
+
184
+ key_sf = key.replace(".", "_").replace(":", "_")
185
+ sofa = sf.Sofa(convention)
186
+ if sofa.GLOBAL_SOFAConventionsVersion.startswith('0.'):
187
+ sofa.verify(mode="read")
188
+
189
+ # test a wrong value
190
+ value = rules["GLOBAL:SOFAConventions"]["specific"][convention][key]
191
+ if value is not None:
192
+ sofa.protected = False
193
+ setattr(sofa, key_sf, "invalid-value")
194
+ sofa.protected = True
195
+
196
+ filename = (f"GLOBAL_SOFAConventions={convention}."
197
+ f"{key_sf}=invalid-value.sofa")
198
+ print(filename)
199
+
200
+ sf.io._write_sofa(os.path.join(
201
+ "data", "specific_dependencies", filename),
202
+ sofa, compression=4, verify=False)
203
+
204
+ # test deleting the attribute
205
+ sofa.protected = False
206
+ delattr(sofa, key_sf)
207
+ sofa.protected = True
208
+
209
+ filename = f"GLOBAL_SOFAConventions={convention}.{key_sf}=missing.sofa"
210
+ print(filename)
211
+
212
+ sf.io._write_sofa(os.path.join(
213
+ "data", "specific_dependencies", filename),
214
+ sofa, compression=4, verify=False)
215
+
216
+ del convention, key, key_sf, sofa, filename
217
+
218
+
219
+ # -----------------------------------------------------------------------------
220
+ # restrictions on dimensions
221
+ print("\nWrite data to test restrictions on dimensions")
222
+ print("---------------------------------------------")
223
+
224
+ # test dimensions for spherical harmonics coordinates
225
+ sofa = sf.Sofa("GeneralFIR-E")
226
+ sofa.ReceiverPosition_Type = "spherical harmonics"
227
+ sofa.ReceiverPosition_Units = "degree, degree, metre"
228
+ sofa.Data_IR = np.zeros((1, 2, 1, 1))
229
+ sofa.Data_Delay = np.zeros((1, 2, 1))
230
+
231
+ filename = "ReceiverPosition_Type=spherical harmonics.R=2.sofa"
232
+ print(filename)
233
+
234
+ sofa.verify(issue_handling="ignore")
235
+ sf.io._write_sofa(os.path.join(
236
+ "data", "restricted_dimensions", filename),
237
+ sofa, compression=4, verify=False)
238
+
239
+ sofa = sf.Sofa("GeneralFIR-E")
240
+ sofa.EmitterPosition_Type = "spherical harmonics"
241
+ sofa.EmitterPosition_Units = "degree, degree, metre"
242
+ sofa.Data_IR = np.zeros((1, 1, 1, 2))
243
+ sofa.Data_Delay = np.zeros((1, 1, 2))
244
+
245
+ filename = "EmitterPosition_Type=spherical harmonics.E=2.sofa"
246
+ print(filename)
247
+
248
+ sofa.verify(issue_handling="ignore")
249
+ sf.io._write_sofa(os.path.join(
250
+ "data", "restricted_dimensions", filename),
251
+ sofa, compression=4, verify=False)
252
+
253
+ # test dimensions for SOS data type
254
+ sofa = sf.Sofa("SimpleFreeFieldHRSOS")
255
+ sofa.Data_SOS = np.zeros((1, 2, 1))
256
+
257
+ filename = "GLOBAL_DataType_Type=SOS.N=1.sofa"
258
+ print(filename)
259
+
260
+ sofa.verify(issue_handling="ignore")
261
+ sf.io._write_sofa(os.path.join(
262
+ "data", "restricted_dimensions", filename),
263
+ sofa, compression=4, verify=False)
264
+
265
+ # test dimensions for SimpleFreeFieldHRIR
266
+ for convention in ["SimpleFreeFieldHRIR",
267
+ "SimpleFreeFieldHRTF",
268
+ "SimpleFreeFieldHRSOS"]:
269
+ sofa = sf.Sofa(convention)
270
+ sofa.EmitterPosition = [[1, 0, 0], [0, 1, 0]]
271
+
272
+ filename = f"GLOBAL_SOFAConventions={convention}.E=2.sofa"
273
+ print(filename)
274
+
275
+ sofa.verify(issue_handling="ignore")
276
+ sf.io._write_sofa(os.path.join(
277
+ "data", "restricted_dimensions", filename),
278
+ sofa, compression=4, verify=False)
279
+
280
+ del sofa, filename, convention
281
+
282
+
283
+ # -----------------------------------------------------------------------------
284
+ # deprecations
285
+ print("\nWrite data to test deprecations")
286
+ print("-------------------------------")
287
+
288
+ conventions = sf.utils._get_conventions("name")
289
+
290
+ for deprecated, substitute in deprecations["GLOBAL:SOFAConventions"].items():
291
+ """
292
+ Test if deprecations raise warnings in read mode and errors in write mode.
293
+ """
294
+
295
+ # check if deprecated and substitute convention exist in sofar
296
+ if deprecated in conventions:
297
+
298
+ if deprecated == "SingleTrackedAudio":
299
+ # This convention was never used and does not define the dimension
300
+ # 'R'. Thus test files can not be written in this case
301
+ continue
302
+
303
+ sofa = sf.Sofa(deprecated, verify=False)
304
+
305
+ filename = f"GLOBAL_SOFAConventions={deprecated}.{substitute}.sofa"
306
+ print(filename)
307
+
308
+ sofa.verify(issue_handling="ignore")
309
+ sf.io._write_sofa(os.path.join(
310
+ "data", "deprecations", filename),
311
+ sofa, compression=4, verify=False)
312
+
313
+ del conventions, deprecated, substitute, sofa, filename