ncrystal-python 3.9.81__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.
- NCrystal/__init__.py +85 -0
- NCrystal/__main__.py +98 -0
- NCrystal/_chooks.py +854 -0
- NCrystal/_cli_cif2ncmat.py +269 -0
- NCrystal/_cli_endf2ncmat.py +503 -0
- NCrystal/_cli_hfg2ncmat.py +144 -0
- NCrystal/_cli_mcstasunion.py +74 -0
- NCrystal/_cli_ncmat2cpp.py +31 -0
- NCrystal/_cli_ncmat2hkl.py +180 -0
- NCrystal/_cli_nctool.py +1018 -0
- NCrystal/_cli_vdos2ncmat.py +463 -0
- NCrystal/_cli_verifyatompos.py +257 -0
- NCrystal/_cliimpl.py +307 -0
- NCrystal/_cliwrap_config.py +36 -0
- NCrystal/_common.py +499 -0
- NCrystal/_coreimpl.py +114 -0
- NCrystal/_hfgdata.py +546 -0
- NCrystal/_hklobjects.py +136 -0
- NCrystal/_is_std.py +0 -0
- NCrystal/_locatelib.py +210 -0
- NCrystal/_miscimpl.py +354 -0
- NCrystal/_mmc.py +757 -0
- NCrystal/_msg.py +60 -0
- NCrystal/_ncmat2cpp_impl.py +445 -0
- NCrystal/_ncmatimpl.py +2131 -0
- NCrystal/_numpy.py +76 -0
- NCrystal/_testimpl.py +579 -0
- NCrystal/api.py +56 -0
- NCrystal/atomdata.py +177 -0
- NCrystal/cfgstr.py +77 -0
- NCrystal/cifutils.py +1795 -0
- NCrystal/cli.py +96 -0
- NCrystal/constants.py +134 -0
- NCrystal/core.py +1910 -0
- NCrystal/datasrc.py +226 -0
- NCrystal/exceptions.py +66 -0
- NCrystal/hfg2ncmat.py +270 -0
- NCrystal/mcstasutils.py +438 -0
- NCrystal/misc.py +317 -0
- NCrystal/mmc.py +35 -0
- NCrystal/ncmat.py +778 -0
- NCrystal/ncmat2cpp.py +80 -0
- NCrystal/obsolete.py +67 -0
- NCrystal/plot.py +484 -0
- NCrystal/plugins.py +49 -0
- NCrystal/test.py +76 -0
- NCrystal/vdos.py +1034 -0
- ncrystal_python-3.9.81.dist-info/LICENSE +206 -0
- ncrystal_python-3.9.81.dist-info/METADATA +515 -0
- ncrystal_python-3.9.81.dist-info/RECORD +53 -0
- ncrystal_python-3.9.81.dist-info/WHEEL +5 -0
- ncrystal_python-3.9.81.dist-info/entry_points.txt +10 -0
- ncrystal_python-3.9.81.dist-info/top_level.txt +1 -0
NCrystal/_numpy.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
|
|
2
|
+
################################################################################
|
|
3
|
+
## ##
|
|
4
|
+
## This file is part of NCrystal (see https://mctools.github.io/ncrystal/) ##
|
|
5
|
+
## ##
|
|
6
|
+
## Copyright 2015-2024 NCrystal developers ##
|
|
7
|
+
## ##
|
|
8
|
+
## Licensed under the Apache License, Version 2.0 (the "License"); ##
|
|
9
|
+
## you may not use this file except in compliance with the License. ##
|
|
10
|
+
## You may obtain a copy of the License at ##
|
|
11
|
+
## ##
|
|
12
|
+
## http://www.apache.org/licenses/LICENSE-2.0 ##
|
|
13
|
+
## ##
|
|
14
|
+
## Unless required by applicable law or agreed to in writing, software ##
|
|
15
|
+
## distributed under the License is distributed on an "AS IS" BASIS, ##
|
|
16
|
+
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ##
|
|
17
|
+
## See the License for the specific language governing permissions and ##
|
|
18
|
+
## limitations under the License. ##
|
|
19
|
+
## ##
|
|
20
|
+
################################################################################
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
"""Internal module providing ctypes-based hooks into the compiled NCrystal
|
|
24
|
+
shared library"""
|
|
25
|
+
|
|
26
|
+
__all__ = ['_np',
|
|
27
|
+
'_ensure_numpy',
|
|
28
|
+
'_np_linspace',
|
|
29
|
+
'_np_geomspace',
|
|
30
|
+
'_np_logspace',
|
|
31
|
+
'_np_trapezoid']
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
import numpy as _np
|
|
35
|
+
except ImportError:
|
|
36
|
+
_np = None
|
|
37
|
+
|
|
38
|
+
def _ensure_numpy():
|
|
39
|
+
if not _np:
|
|
40
|
+
from .exceptions import NCException
|
|
41
|
+
raise NCException("Numpy not available - array "
|
|
42
|
+
"based functionality is unavailable")
|
|
43
|
+
return _np
|
|
44
|
+
|
|
45
|
+
def _np_linspace(start,stop,num=50):
|
|
46
|
+
"""linspace with reproducible endpoint value"""
|
|
47
|
+
_ensure_numpy()
|
|
48
|
+
assert num >= 2
|
|
49
|
+
ll = _np.linspace(start,stop,num)
|
|
50
|
+
ll[0] = start
|
|
51
|
+
ll[-1] = stop
|
|
52
|
+
return ll
|
|
53
|
+
|
|
54
|
+
def _np_geomspace(start,stop,num=50):
|
|
55
|
+
"""geomspace with reproducible endpoint value"""
|
|
56
|
+
_ensure_numpy()
|
|
57
|
+
assert num >= 2
|
|
58
|
+
ll = _np.geomspace(start,stop,num)
|
|
59
|
+
ll[0] = start
|
|
60
|
+
ll[-1] = stop
|
|
61
|
+
return ll
|
|
62
|
+
|
|
63
|
+
def _np_logspace(start,stop,num=50):
|
|
64
|
+
"""logspace with reproducible endpoint value"""
|
|
65
|
+
_ensure_numpy()
|
|
66
|
+
assert num >= 2
|
|
67
|
+
ll = _np.logspace(start,stop,num)
|
|
68
|
+
ll[0] = 10.0**start
|
|
69
|
+
ll[-1] = 10.0**stop
|
|
70
|
+
return ll
|
|
71
|
+
|
|
72
|
+
def _np_trapezoid( *args, **kwargs ):
|
|
73
|
+
_ensure_numpy()
|
|
74
|
+
if hasattr(_np,'trapezoid'):
|
|
75
|
+
return _np.trapezoid( *args, **kwargs )
|
|
76
|
+
return _np.trapz( *args, **kwargs )
|
NCrystal/_testimpl.py
ADDED
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
|
|
2
|
+
################################################################################
|
|
3
|
+
## ##
|
|
4
|
+
## This file is part of NCrystal (see https://mctools.github.io/ncrystal/) ##
|
|
5
|
+
## ##
|
|
6
|
+
## Copyright 2015-2024 NCrystal developers ##
|
|
7
|
+
## ##
|
|
8
|
+
## Licensed under the Apache License, Version 2.0 (the "License"); ##
|
|
9
|
+
## you may not use this file except in compliance with the License. ##
|
|
10
|
+
## You may obtain a copy of the License at ##
|
|
11
|
+
## ##
|
|
12
|
+
## http://www.apache.org/licenses/LICENSE-2.0 ##
|
|
13
|
+
## ##
|
|
14
|
+
## Unless required by applicable law or agreed to in writing, software ##
|
|
15
|
+
## distributed under the License is distributed on an "AS IS" BASIS, ##
|
|
16
|
+
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ##
|
|
17
|
+
## See the License for the specific language governing permissions and ##
|
|
18
|
+
## limitations under the License. ##
|
|
19
|
+
## ##
|
|
20
|
+
################################################################################
|
|
21
|
+
|
|
22
|
+
"""Implementation of the built-in unit tests."""
|
|
23
|
+
|
|
24
|
+
__all__ = ['test','test_cmdline','test_cmake','test_extra','test_all']
|
|
25
|
+
from ._common import print as _nc_print
|
|
26
|
+
import contextlib as _contextlib
|
|
27
|
+
|
|
28
|
+
def test( verbose = False ):
|
|
29
|
+
"""Quick test that NCrystal works as expected in the current installation."""
|
|
30
|
+
_actualtest( verbose = verbose )
|
|
31
|
+
if verbose!='quiet':
|
|
32
|
+
_nc_print("Tests completed succesfully")
|
|
33
|
+
|
|
34
|
+
def test_cmdline( verbose = False ):
|
|
35
|
+
"""Quick test that NCrystal command-line scripts are present and working in
|
|
36
|
+
the current installation."""
|
|
37
|
+
_actual_test_cmdline( verbose = verbose )
|
|
38
|
+
if verbose!='quiet':
|
|
39
|
+
_nc_print("Tests completed succesfully")
|
|
40
|
+
|
|
41
|
+
def test_cmake( verbose = False ):
|
|
42
|
+
"""Quick test that the NCrystal installation supports down-stream CMake/C++
|
|
43
|
+
projects (possibly after using ncrystal-config to get CMAKE_PREFIX_PATH and
|
|
44
|
+
(DY)LD_LIBRARY_PATHS setup).
|
|
45
|
+
"""
|
|
46
|
+
_actual_test_cmake( verbose = verbose, ignore_if_absent = False )
|
|
47
|
+
if verbose!='quiet':
|
|
48
|
+
_nc_print("Tests completed succesfully")
|
|
49
|
+
|
|
50
|
+
def test_extra( verbose = False ):
|
|
51
|
+
"""Run both test() and test_cmdline(). If CMake is present, also run test_cmake()."""
|
|
52
|
+
_actualtest( verbose = verbose )
|
|
53
|
+
_actual_test_cmdline( verbose = verbose )
|
|
54
|
+
_actual_test_cmake( verbose = verbose, ignore_if_absent = True )
|
|
55
|
+
if verbose!='quiet':
|
|
56
|
+
_nc_print("Tests completed succesfully")
|
|
57
|
+
|
|
58
|
+
def test_all( verbose = False ):
|
|
59
|
+
"""Run both test(), test_cmdline(), and test_cmake()."""
|
|
60
|
+
_actualtest( verbose = verbose )
|
|
61
|
+
_actual_test_cmdline( verbose = verbose )
|
|
62
|
+
_actual_test_cmake( verbose = verbose, ignore_if_absent = False )
|
|
63
|
+
if verbose!='quiet':
|
|
64
|
+
_nc_print("Tests completed succesfully")
|
|
65
|
+
|
|
66
|
+
def _get_prfct( verbose ):
|
|
67
|
+
if verbose and verbose != 'quiet':
|
|
68
|
+
return lambda *a, **kw : _nc_print('::NCrystalTest::',*a,**kw)
|
|
69
|
+
else:
|
|
70
|
+
return lambda *a, **kw : None
|
|
71
|
+
|
|
72
|
+
def _actualtest( verbose ):
|
|
73
|
+
prfct = _get_prfct( verbose )
|
|
74
|
+
prfct('starting standard Python-API testing')
|
|
75
|
+
try:
|
|
76
|
+
import numpy as _np
|
|
77
|
+
except ImportError:
|
|
78
|
+
_np = None
|
|
79
|
+
from . import core as NC
|
|
80
|
+
from .constants import wl2ekin
|
|
81
|
+
from .plugins import hasFactory
|
|
82
|
+
|
|
83
|
+
def require(b):
|
|
84
|
+
if not b:
|
|
85
|
+
raise RuntimeError('check failed')
|
|
86
|
+
def flteq(a,b,rtol=1.0e-6,atol=1.0e-6):
|
|
87
|
+
return abs(a-b) <= 0.5 * rtol * (abs(a) + abs(b)) + atol
|
|
88
|
+
def require_flteq(a,b):
|
|
89
|
+
if not flteq(a,b):
|
|
90
|
+
raise RuntimeError('check failed (%.16g != %.16g, diff %g)'%(a,b,a-b))
|
|
91
|
+
return True
|
|
92
|
+
require(hasFactory('stdncmat'))
|
|
93
|
+
from . import _common as nc_common
|
|
94
|
+
require( nc_common.prettyFmtValue(0.25) == '1/4' )
|
|
95
|
+
require( nc_common.prettyFmtValue(0.25 + 1e-12) != '1/4' )
|
|
96
|
+
require( nc_common.prettyFmtValue(0.25 + 1e-15) == '1/4' )
|
|
97
|
+
|
|
98
|
+
_cfgstr='stdlib::Al_sg225.ncmat;dcutoff=1.4'
|
|
99
|
+
prfct(f'Trying to createInfo("{_cfgstr}")')
|
|
100
|
+
al = NC.createInfo(_cfgstr)
|
|
101
|
+
prfct('Verifying loaded Info object')
|
|
102
|
+
require(al.hasTemperature() and require_flteq(al.getTemperature(),293.15))
|
|
103
|
+
require_flteq(al.getXSectFree(),1.39667)
|
|
104
|
+
require_flteq(al.getXSectAbsorption(),0.231)
|
|
105
|
+
require_flteq(al.getDensity(),2.69864547673)
|
|
106
|
+
require_flteq(al.getNumberDensity(),0.06023238256131625)
|
|
107
|
+
require(al.hasDebyeTemperature())
|
|
108
|
+
|
|
109
|
+
require(al.hasStructureInfo())
|
|
110
|
+
si=al.getStructureInfo()
|
|
111
|
+
require( si['spacegroup'] == 225 )
|
|
112
|
+
require_flteq(si['a'],4.04958)
|
|
113
|
+
require_flteq(si['b'],4.04958)
|
|
114
|
+
require_flteq(si['c'],4.04958)
|
|
115
|
+
require( si['alpha'] == 90.0 )
|
|
116
|
+
require( si['beta'] == 90.0 )
|
|
117
|
+
require( si['gamma'] == 90.0 )
|
|
118
|
+
require( si['n_atoms'] == 4 )
|
|
119
|
+
require_flteq(si['volume'],66.4094599932)
|
|
120
|
+
require( al.hasHKLInfo() )
|
|
121
|
+
require( al.nHKL() == 3 )
|
|
122
|
+
require_flteq(al.hklDLower(),1.4)
|
|
123
|
+
require( al.hklDUpper() > 1e36 )
|
|
124
|
+
expected_hkl = { 0 : (1, 1, 1, 8, 2.3380261031049243, 1.7731590373262052),
|
|
125
|
+
1 : (2, 0, 0, 6, 2.02479, 1.7317882793764163),
|
|
126
|
+
2 : (2, 2, 0, 12, 1.4317427394787092, 1.5757351418107877) }
|
|
127
|
+
for idx,hkl in enumerate(al.hklList()):
|
|
128
|
+
h,k,l_,mult,dsp,fsq = hkl
|
|
129
|
+
require(idx<len(expected_hkl))
|
|
130
|
+
e = expected_hkl[idx]
|
|
131
|
+
require( list(e)[0:4] == [h,k,l_,mult] )
|
|
132
|
+
require_flteq(dsp, e[4])
|
|
133
|
+
require_flteq(fsq, e[5])
|
|
134
|
+
|
|
135
|
+
_cfgstr2='stdlib::Al_sg225.ncmat;dcutoff=1.4;incoh_elas=0;inelas=0'
|
|
136
|
+
prfct(f'Trying to createScatter("{_cfgstr2}")')
|
|
137
|
+
#We do all createScatter... here with independent RNG, for reproducibility
|
|
138
|
+
#and to avoid consuming random numbers from other streams.
|
|
139
|
+
alpc = NC.createScatterIndependentRNG(_cfgstr2)
|
|
140
|
+
prfct('Verifying loaded Scatter object')
|
|
141
|
+
require( alpc.name == 'PCBragg' )
|
|
142
|
+
require( isinstance(alpc.name,str) )
|
|
143
|
+
require( alpc.refCount() in (1,2) )
|
|
144
|
+
require( type(alpc.refCount()) == int ) # noqa E721
|
|
145
|
+
require( alpc.isNonOriented() )
|
|
146
|
+
#_nc_print(alpc.xsect(wl=4.0))
|
|
147
|
+
require_flteq(1.632435821586171,alpc.crossSectionIsotropic(wl2ekin(4.0)) )
|
|
148
|
+
require_flteq(1.632435821586171,alpc.crossSection(wl2ekin(4.0),(1,0,0)))
|
|
149
|
+
require( alpc.crossSectionIsotropic(wl2ekin(5.0)) == 0.0 )
|
|
150
|
+
|
|
151
|
+
require( alpc.rngSupportsStateManipulation() )
|
|
152
|
+
require(alpc.getRNGState()=='a79fd777407ba03b3d9d242b2b2a2e58b067bd44')
|
|
153
|
+
|
|
154
|
+
alpc.setRNGState('deadbeefdeadbeefdeadbeefdeadbeefb067bd44')
|
|
155
|
+
require(alpc.getRNGState()=='deadbeefdeadbeefdeadbeefdeadbeefb067bd44')
|
|
156
|
+
alpc_clone = alpc.clone()
|
|
157
|
+
require(alpc.getRNGState()=='deadbeefdeadbeefdeadbeefdeadbeefb067bd44')
|
|
158
|
+
require(alpc_clone.getRNGState()=='e0fd16d42a2aced7706cffa08536d869b067bd44')
|
|
159
|
+
alpc_clone2 = alpc_clone.clone(for_current_thread=True)
|
|
160
|
+
require(alpc_clone2.getRNGState()=='cc762bb1160a0be514300da860f6d160b067bd44')
|
|
161
|
+
alpc_clone3 = alpc_clone.clone(rng_stream_index = 12345 )
|
|
162
|
+
require(alpc_clone3.getRNGState()=='3a20660a10fd581bd7cddef8fc3f32a2b067bd44')
|
|
163
|
+
|
|
164
|
+
#Pick Nickel at 1.2 angstrom, to also both vdos + incoherent-elastic + coherent-elastic:
|
|
165
|
+
_cfgstr3='stdlib::Ni_sg225.ncmat;dcutoff=0.6;vdoslux=2'
|
|
166
|
+
_seed=2543577
|
|
167
|
+
prfct(f'Trying to createScatterIndependentRNG("{_cfgstr3}",{_seed})')
|
|
168
|
+
nipc = NC.createScatterIndependentRNG(_cfgstr3,_seed)
|
|
169
|
+
prfct('Verifying loaded Scatter object')
|
|
170
|
+
nipc_testwl = 1.2
|
|
171
|
+
#_nc_print(nipc.xsect(wl=nipc_testwl),nipc.xsect(wl=5.0))
|
|
172
|
+
require_flteq(16.76474410391571,nipc.xsect(wl=nipc_testwl))
|
|
173
|
+
require_flteq(16.76474410391571,nipc.xsect(wl=nipc_testwl,direction=(1,0,0)))
|
|
174
|
+
require_flteq(5.958467463288343,nipc.xsect(wl=5.0))
|
|
175
|
+
|
|
176
|
+
require( nipc.name == 'ProcComposition' )
|
|
177
|
+
|
|
178
|
+
expected = [ ( 0.056808478892590906, 0.5361444826572666 ),
|
|
179
|
+
( 0.056808478892590906, 0.5361444826572666 ),
|
|
180
|
+
( 0.056808478892590906, 0.36219866365374176 ),
|
|
181
|
+
( 0.056808478892590906, 0.8391056916029316 ),
|
|
182
|
+
( 0.03200142524676351, -0.37261037212010517 ),
|
|
183
|
+
( 0.056808478892590906, -0.10165685368899147 ),
|
|
184
|
+
( 0.056808478892590906, -0.15963879335683306 ),
|
|
185
|
+
( 0.056808478892590906, 0.8260541809964751 ),
|
|
186
|
+
( 0.0779984939788784, -0.5293576625127443 ),
|
|
187
|
+
( 0.05348552589207497, -0.09540771817962344 ),
|
|
188
|
+
( 0.056808478892590906, 0.8260541809964751 ),
|
|
189
|
+
( 0.041255667101120046, -0.21139471030502716 ),
|
|
190
|
+
( 0.056808478892590906, -0.10165685368899147 ),
|
|
191
|
+
( 0.056808478892590906, -0.10165685368899147 ),
|
|
192
|
+
( 0.056808478892590906, 0.5361444826572666 ),
|
|
193
|
+
( 0.056808478892590906, -0.3915665520281999 ),
|
|
194
|
+
( 0.056808478892590906, 0.36219866365374176 ),
|
|
195
|
+
( 0.05750889239879721, -0.5221309343148964 ),
|
|
196
|
+
( 0.056808478892590906, 0.36219866365374176 ),
|
|
197
|
+
( 0.08122761653652728, -0.9893394211150188 ),
|
|
198
|
+
( 0.056808478892590906, -0.5655123710317247 ),
|
|
199
|
+
( 0.05809677932650489, -0.9514020394895405 ),
|
|
200
|
+
( 0.056808478892590906, 0.3042167239859003 ),
|
|
201
|
+
( 0.056808478892590906, 0.7378808571510718 ),
|
|
202
|
+
( 0.056808478892590906, -0.10165685368899147 ),
|
|
203
|
+
( 0.08045215149882884, -0.8062011016624717 ),
|
|
204
|
+
( 0.056808478892590906, -0.5655123710317247 ),
|
|
205
|
+
( 0.06930589080120417, 0.079019907465779 ),
|
|
206
|
+
( 0.04019429812207957, -0.9619814414415885 ),
|
|
207
|
+
( 0.08983559328581395, -0.5822087429342399 ) ]
|
|
208
|
+
|
|
209
|
+
if _np is None:
|
|
210
|
+
ekin,mu=[],[]
|
|
211
|
+
for i in range(30):
|
|
212
|
+
_ekin,_mu=nipc.sampleScatterIsotropic(wl2ekin(nipc_testwl))
|
|
213
|
+
mu += [_mu]
|
|
214
|
+
ekin += [_ekin]
|
|
215
|
+
else:
|
|
216
|
+
ekin,mu = nipc.sampleScatterIsotropic(wl2ekin(nipc_testwl),repeat=30)
|
|
217
|
+
|
|
218
|
+
for i in range(len(ekin)):
|
|
219
|
+
#print ( f' ( {ekin[i]}, {mu[i]} ),');continue
|
|
220
|
+
require_flteq(ekin[i],expected[i][0])
|
|
221
|
+
require_flteq(mu[i],expected[i][1])
|
|
222
|
+
|
|
223
|
+
expected = [ ( 0.056808478892590906, (0.07228896531453344, -0.5190173207165885, 0.8517014302500192) ),
|
|
224
|
+
( 0.056808478892590906, (-0.9249112255344181, -0.32220112076758217, -0.20180600252850442) ),
|
|
225
|
+
( 0.056808478892590906, (-0.15963879335683306, -0.8486615569734178, 0.5042707778277745) ),
|
|
226
|
+
( 0.04922198429225973, (-0.9779858857774598, 0.14099376149839138, 0.1538322672218415) ),
|
|
227
|
+
( 0.056808478892590906, (0.07228896531453344, 0.7905105193171594, -0.6081672667471253) ),
|
|
228
|
+
( 0.056808478892590906, (-0.10165685368899147, -0.8869759070713323, -0.4504882066969593) ),
|
|
229
|
+
( 0.056808478892590906, (0.07228896531453344, -0.39741541395284924, -0.914787021249449) ),
|
|
230
|
+
( 0.056808478892590906, (-0.10165685368899147, -0.9768880366798581, -0.1880309758785167) ),
|
|
231
|
+
( 0.02561081364848724, (-0.8847741369311427, -0.465745536939693, 0.015994418980024606) ),
|
|
232
|
+
( 0.056808478892590906, (0.8260541809964751, 0.539797243436807, 0.16202909009269678) ),
|
|
233
|
+
( 0.07443151255169597, (-0.6036845347910699, -0.06282202590029042, -0.7947442201839992) ),
|
|
234
|
+
( 0.056808478892590906, (0.8260541809964751, 0.10854661864786977, 0.5530389874487663) ),
|
|
235
|
+
( 0.056808478892590906, (0.5361444826572666, 0.7795115518549294, 0.3238994199452849) ),
|
|
236
|
+
( 0.056808478892590906, (0.07228896531453344, 0.746175597107444, 0.6618128767069312) ),
|
|
237
|
+
( 0.056808478892590906, (-0.10165685368899147, -0.4247181868490453, 0.8996001033001911) ),
|
|
238
|
+
( 0.056808478892590906, (0.5361444826572666, 0.5555760611065321, -0.6355189486093415) ),
|
|
239
|
+
( 0.05736877062456004, (-0.17262993734116835, -0.6849866797325108, 0.7078079918470932) ),
|
|
240
|
+
( 0.056808478892590906, (0.3042167239859003, -0.8706122815482211, -0.3866347631352975) ),
|
|
241
|
+
( 0.056808478892590906, (-0.7384733804796917, 0.6322144258925643, -0.23443972789660028) ),
|
|
242
|
+
( 0.056808478892590906, (-0.15963879335683306, 0.21525619037302965, -0.9634211063505222) ),
|
|
243
|
+
( 0.056808478892590906, (0.41359447569500096, 0.4927058865194684, 0.7656242675514158) ),
|
|
244
|
+
( 0.056808478892590906, (0.25796367721315083, 0.48520231047621615, 0.8354839670198411) ),
|
|
245
|
+
( 0.056808478892590906, (0.5785005938702705, 0.8104481067271115, -0.09225469740985966) ),
|
|
246
|
+
( 0.04320250494907263, (-0.03036895176557113, -0.49547892839001373, 0.8680889115120317) ),
|
|
247
|
+
( 0.054287027970592844, (-0.360243154961136, -0.9063878964988544, 0.22064870356299168) ),
|
|
248
|
+
( 0.056808478892590906, (0.36219866365374176, -0.8822186430862216, 0.3008361577978114) ),
|
|
249
|
+
( 0.056808478892590906, (0.7680722413286334, 0.5975216576265994, -0.23028873347945303) ),
|
|
250
|
+
( 0.056808478892590906, (0.32922859149927786, -0.9426419619170849, 0.0550878042084668) ),
|
|
251
|
+
( 0.056808478892590906, (-0.10165685368899147, -0.2489220191768986, -0.9631737706493833) ),
|
|
252
|
+
( 0.0670453578395921, (-0.8979763975977056, 0.34669277926553477, 0.2710027788835134) ) ]
|
|
253
|
+
|
|
254
|
+
for i in range(30):
|
|
255
|
+
out_ekin,outdir = nipc.sampleScatter(wl2ekin(nipc_testwl),(1.0,0.0,0.0))
|
|
256
|
+
#print ( f' ( {out_ekin}, {outdir} ),');continue
|
|
257
|
+
require_flteq(out_ekin,expected[i][0])
|
|
258
|
+
require_flteq(outdir[0],expected[i][1][0])
|
|
259
|
+
require_flteq(outdir[1],expected[i][1][1])
|
|
260
|
+
require_flteq(outdir[2],expected[i][1][2])
|
|
261
|
+
|
|
262
|
+
_cfgstr4="""stdlib::Ge_sg227.ncmat;dcutoff=0.5;mos=40.0arcsec
|
|
263
|
+
;dir1=@crys_hkl:5,1,1@lab:0,0,1
|
|
264
|
+
;dir2=@crys_hkl:0,-1,1@lab:0,1,0""".replace(' ','').replace('\n','')
|
|
265
|
+
_seed4 = 3453455
|
|
266
|
+
prfct(f'Trying to createScatterIndependentRNG("{_cfgstr4}",{_seed4})')
|
|
267
|
+
gesc = NC.createScatterIndependentRNG(_cfgstr4,_seed4)
|
|
268
|
+
prfct('Verifying loaded Scatter object')
|
|
269
|
+
require_flteq(591.0263476502018,gesc.crossSection(wl2ekin(1.540),( 0., 1., 1. )))
|
|
270
|
+
require_flteq(1.667600586136298,gesc.crossSection(wl2ekin(1.540),( 1., 1., 0. )))
|
|
271
|
+
prfct('standard Python-API testing done')
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
class CallInspector:
|
|
275
|
+
|
|
276
|
+
@property
|
|
277
|
+
def name( self ):
|
|
278
|
+
return self.__name
|
|
279
|
+
|
|
280
|
+
@property
|
|
281
|
+
def the_real_inspected_object( self ):
|
|
282
|
+
return self.__realobj
|
|
283
|
+
|
|
284
|
+
def __init__( self, name, *, realobj = None, subfcts = None, fmtcall = None ):
|
|
285
|
+
self.__name = name
|
|
286
|
+
self.__realobj = realobj
|
|
287
|
+
self.__subfcts = {}
|
|
288
|
+
self.__fmtcall = fmtcall or _fmtcall
|
|
289
|
+
for sf in (subfcts or []):
|
|
290
|
+
if isinstance(sf,str):
|
|
291
|
+
self.__subfcts[sf] = None
|
|
292
|
+
else:
|
|
293
|
+
assert len(sf)==2 and isinstance(sf,tuple)
|
|
294
|
+
self.__subfcts[sf[0]] = sf[1]
|
|
295
|
+
|
|
296
|
+
def __call__( self, *a, **kwargs ):
|
|
297
|
+
return self.__getattrimpl('__call__')(*a,**kwargs)
|
|
298
|
+
|
|
299
|
+
def __getattr__( self, attrname ):
|
|
300
|
+
return self.__getattrimpl(attrname)
|
|
301
|
+
|
|
302
|
+
def __getattrimpl( self, attrname ):
|
|
303
|
+
if attrname not in self.__subfcts:
|
|
304
|
+
raise RuntimeError(f'Not allowed to access attribute {attrname} of {self.__name} objects.')
|
|
305
|
+
sf_kwargs = self.__subfcts[attrname] or {}
|
|
306
|
+
thefmtcall = sf_kwargs.get('fmtcall') or self.__fmtcall
|
|
307
|
+
def wrapper( *args, **kwargs ):
|
|
308
|
+
_n = f'{self.__name}.{attrname}' if attrname!='__call__' else self.__name
|
|
309
|
+
_nc_print("CALLING %s"%thefmtcall(_n,args,kwargs))
|
|
310
|
+
res = getattr(self.__realobj,attrname)(*args,**kwargs) if self.__realobj else None
|
|
311
|
+
return CallInspector( name = 'ResultOf[%s(..)]'%_n,
|
|
312
|
+
realobj = res, **sf_kwargs ) if sf_kwargs else None
|
|
313
|
+
return wrapper
|
|
314
|
+
|
|
315
|
+
_fmtvalue_default_ndigits = 3
|
|
316
|
+
def _fmtvalue( x, *, ndigits = _fmtvalue_default_ndigits ):
|
|
317
|
+
import numbers
|
|
318
|
+
if isinstance(x,numbers.Real) and not isinstance(x,numbers.Integral):
|
|
319
|
+
fmtstring = f'%.{ndigits}g'
|
|
320
|
+
s=fmtstring%x#only 3 to avoid too many spurious test issues due to FPE irrep.
|
|
321
|
+
return s+'.0' if ( s.isdigit() or s[0]=='-' and s[1:].isdigit() ) else s
|
|
322
|
+
return repr(x)
|
|
323
|
+
|
|
324
|
+
def _fmtcall(fctname,args=tuple(),kwargs={}):
|
|
325
|
+
import numbers
|
|
326
|
+
def _fmt(a):
|
|
327
|
+
if isinstance(a,numbers.Real):
|
|
328
|
+
return _fmtvalue(a)
|
|
329
|
+
def pruneaddr(s):
|
|
330
|
+
while ' object at 0x' in s:
|
|
331
|
+
_ = s.split(' object at 0x',1)
|
|
332
|
+
while _[1] and _[1][0].isalnum():
|
|
333
|
+
_[1] = _[1][1:]
|
|
334
|
+
s = ' object at SNIPADDR'.join(_)
|
|
335
|
+
return s
|
|
336
|
+
return 'Object[%s]'%a.name if isinstance(a,CallInspector) else pruneaddr(repr(a))
|
|
337
|
+
ll = [ _fmt(a) for a in args ]
|
|
338
|
+
ll += [ '%s=%s'%(k,_fmt(v)) for k,v in sorted(kwargs.items()) ]
|
|
339
|
+
a=','.join(ll)
|
|
340
|
+
return f'{fctname}({a})'
|
|
341
|
+
|
|
342
|
+
def _create_pyplot_inspector( pass_calls_to_real_plt ):
|
|
343
|
+
import copy
|
|
344
|
+
if pass_calls_to_real_plt:
|
|
345
|
+
import matplotlib.pyplot as realplt
|
|
346
|
+
else:
|
|
347
|
+
realplt = None
|
|
348
|
+
def shorten( x ):
|
|
349
|
+
if hasattr(x,'shape') and len(x.shape)==2:
|
|
350
|
+
return 'Array(shape=%s,content=%s)'%(x.shape,shorten(x.flatten()))
|
|
351
|
+
if isinstance(x,str) or not hasattr(x,'__len__'):
|
|
352
|
+
return x
|
|
353
|
+
#Fewer digits to guard against annoying test errors:
|
|
354
|
+
maxxval = max(x)
|
|
355
|
+
def _fmtthislistval(val):
|
|
356
|
+
if val==0.0:
|
|
357
|
+
return '0.0'
|
|
358
|
+
if abs(val)<abs(maxxval)*1e-13:
|
|
359
|
+
return 'TINYVAL'
|
|
360
|
+
#return _fmtvalue( val, ndigits = max(1,(_fmtvalue_default_ndigits-2)) )
|
|
361
|
+
elif abs(val)<abs(maxxval)*1e-8:
|
|
362
|
+
return 'SMALLVAL'
|
|
363
|
+
#return _fmtvalue( val, ndigits = max(1,(_fmtvalue_default_ndigits-1)) )
|
|
364
|
+
else:
|
|
365
|
+
return _fmtvalue( val )
|
|
366
|
+
if len(x) <= 10:
|
|
367
|
+
return list(_fmtthislistval(e) for e in x)
|
|
368
|
+
else:
|
|
369
|
+
return list(_fmtthislistval(e) for e in x[0:3])+['...']+list(_fmtthislistval(e) for e in x[-3:])
|
|
370
|
+
def _create_shortening_fmtcall( nargs_to_shorten, kwargs_to_shorten = None ):
|
|
371
|
+
def fmtcall_pltplot( name, args, kwargs ):
|
|
372
|
+
plot_args, plot_kwargs = args, kwargs
|
|
373
|
+
if nargs_to_shorten>0:
|
|
374
|
+
plot_args = [ shorten(e) for e in args[0:nargs_to_shorten] ] + list(args[nargs_to_shorten:])
|
|
375
|
+
if any( e in kwargs for e in (kwargs_to_shorten or [])):
|
|
376
|
+
plot_kwargs = copy.deepcopy(kwargs)
|
|
377
|
+
for xy in ('x','y'):
|
|
378
|
+
if xy in plot_kwargs:
|
|
379
|
+
plot_kwargs[xy] = shorten(plot_kwargs[xy])
|
|
380
|
+
return _fmtcall(name, plot_args,plot_kwargs)
|
|
381
|
+
return fmtcall_pltplot
|
|
382
|
+
|
|
383
|
+
return CallInspector( name = 'plt',
|
|
384
|
+
realobj = realplt,
|
|
385
|
+
subfcts = [ 'title','xlabel','ylabel','semilogx','semilogy',
|
|
386
|
+
'legend','grid','show','figure',
|
|
387
|
+
'savefig','ylim','xlim','colorbar',
|
|
388
|
+
'tight_layout','close',
|
|
389
|
+
( 'plot', dict( fmtcall=_create_shortening_fmtcall(2,('x','y')) ) ),
|
|
390
|
+
( 'pcolormesh',dict( subfcts=['set_clim'],
|
|
391
|
+
fmtcall=_create_shortening_fmtcall(3) ) ),
|
|
392
|
+
] )
|
|
393
|
+
|
|
394
|
+
def _create_pdfpages_inspector( real_pdfpages ):
|
|
395
|
+
return CallInspector( name = 'PdfPages',
|
|
396
|
+
realobj = real_pdfpages,
|
|
397
|
+
subfcts = [ ('__call__',dict(subfcts=['savefig','close'])) ] )
|
|
398
|
+
|
|
399
|
+
def _run_cmd( cmd, env = None ):
|
|
400
|
+
import sys
|
|
401
|
+
import subprocess
|
|
402
|
+
sys.stdout.flush()
|
|
403
|
+
sys.stderr.flush()
|
|
404
|
+
if env and sys.platform == 'darwin':
|
|
405
|
+
#osx's system protection #$%#^ is so damn annoying:
|
|
406
|
+
for name in ['DYLD_LIBRARY_PATH','LD_LIBRARY_PATH']:
|
|
407
|
+
v = env.get(name)
|
|
408
|
+
if v is not None:
|
|
409
|
+
from shlex import quote
|
|
410
|
+
#NB: "export A=B" is posix, not bash, so hopefully OK on all OSX
|
|
411
|
+
#shells:
|
|
412
|
+
cmd = 'export %s=%s && %s'%(name,quote(v),cmd)
|
|
413
|
+
try:
|
|
414
|
+
p = subprocess.Popen( cmd, shell=True, env=env,
|
|
415
|
+
stdout=subprocess.PIPE,
|
|
416
|
+
stderr=subprocess.PIPE )
|
|
417
|
+
output = p.communicate()[0]
|
|
418
|
+
ok = p.returncode==0
|
|
419
|
+
except OSError:
|
|
420
|
+
ok = False
|
|
421
|
+
sys.stdout.flush()
|
|
422
|
+
sys.stderr.flush()
|
|
423
|
+
return ok, output
|
|
424
|
+
|
|
425
|
+
def _test_cmdline_script_availablity( prfct ):
|
|
426
|
+
import subprocess
|
|
427
|
+
import shutil
|
|
428
|
+
from .cli import cli_tool_list, cli_tool_lookup
|
|
429
|
+
for t in cli_tool_list():
|
|
430
|
+
c = cli_tool_lookup(t)['shellcmd']
|
|
431
|
+
prfct(f"Testing availability of command: {c}")
|
|
432
|
+
if not shutil.which(c):
|
|
433
|
+
raise RuntimeError(f'Command {c} not found!')
|
|
434
|
+
ev = subprocess.run( [c,'--help'], capture_output = True )
|
|
435
|
+
if ev.returncode != 0:
|
|
436
|
+
raise RuntimeError(f'Command "{c} --help" did not run succesfully!')
|
|
437
|
+
|
|
438
|
+
def _actual_test_cmdline( verbose ):
|
|
439
|
+
from .cli import cli_tool_lookup
|
|
440
|
+
import shlex
|
|
441
|
+
prfct = _get_prfct( verbose )
|
|
442
|
+
prfct('starting testing of cmd-line utilities')
|
|
443
|
+
_test_cmdline_script_availablity( prfct )
|
|
444
|
+
cmds = ['ncrystal-config --help',
|
|
445
|
+
'ncrystal-config -s',
|
|
446
|
+
'nctool --version',
|
|
447
|
+
'nctool --help',
|
|
448
|
+
'nctool --test',
|
|
449
|
+
'ncrystal_endf2ncmat --help',
|
|
450
|
+
'ncrystal_hfg2ncmat --help',
|
|
451
|
+
'ncrystal_ncmat2cpp --help',
|
|
452
|
+
'ncrystal_ncmat2hkl --help',
|
|
453
|
+
'ncrystal_cif2ncmat --help',
|
|
454
|
+
'ncrystal_vdos2ncmat --help',
|
|
455
|
+
'ncrystal_verifyatompos --help',
|
|
456
|
+
'ncrystal-config --show cmakedir']
|
|
457
|
+
for cmd in cmds:
|
|
458
|
+
cmd = shlex.split(cmd)
|
|
459
|
+
cmd[0] = cli_tool_lookup( cmd[0] )['shellcmd']
|
|
460
|
+
cmd = shlex.join(cmd)
|
|
461
|
+
prfct('Trying to run:',cmd)
|
|
462
|
+
ok, output = _run_cmd(cmd)
|
|
463
|
+
if not ok:
|
|
464
|
+
raise RuntimeError('Command failed: %s'%cmd)
|
|
465
|
+
prfct('testing of cmd-line utilities done')
|
|
466
|
+
|
|
467
|
+
@_contextlib.contextmanager
|
|
468
|
+
def _work_in_tmpdir():
|
|
469
|
+
"""Context manager for working in a temporary directory (automatically created+cleaned) and then switching back"""
|
|
470
|
+
import os
|
|
471
|
+
import tempfile
|
|
472
|
+
the_cwd = os.getcwd()
|
|
473
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
474
|
+
try:
|
|
475
|
+
os.chdir(tmpdir)
|
|
476
|
+
yield
|
|
477
|
+
finally:
|
|
478
|
+
os.chdir(the_cwd)#Important to leave tmpdir *before* deletion, to
|
|
479
|
+
#avoid PermissionError on Windows.
|
|
480
|
+
|
|
481
|
+
def _actual_test_cmake( verbose = False, ignore_if_absent = False ):
|
|
482
|
+
prfct = _get_prfct( verbose )
|
|
483
|
+
prfct('starting testing of compiled downstream cmake-based projects')
|
|
484
|
+
import shutil
|
|
485
|
+
cmakecmd = shutil.which('cmake')
|
|
486
|
+
if not cmakecmd:
|
|
487
|
+
if ignore_if_absent:
|
|
488
|
+
prfct('Skipping CMake test since "cmake" command not found.')
|
|
489
|
+
return
|
|
490
|
+
raise RuntimeError('cmake command not found')
|
|
491
|
+
|
|
492
|
+
prfct('Using cmake command: %s'%cmakecmd)
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
def _singleline2str( x ):
|
|
496
|
+
return ((x.decode() if hasattr(x,'decode') else x) or '').strip()
|
|
497
|
+
|
|
498
|
+
_cmd = 'ncrystal-config --show cmakedir'
|
|
499
|
+
ok, ncrystal_cmakedir = _run_cmd(_cmd)
|
|
500
|
+
if not ok:
|
|
501
|
+
raise RuntimeError('Command failed: %s'%_cmd)
|
|
502
|
+
ncrystal_cmakedir = _singleline2str(ncrystal_cmakedir)
|
|
503
|
+
prfct('ncrystal-config gives cmakedir: %s'%ncrystal_cmakedir)
|
|
504
|
+
_cmd = 'ncrystal-config --show libdir'
|
|
505
|
+
ok, ncrystal_libdir = _run_cmd(_cmd)
|
|
506
|
+
if not ok:
|
|
507
|
+
raise RuntimeError('Command failed: %s'%_cmd)
|
|
508
|
+
ncrystal_libdir = _singleline2str(ncrystal_libdir)
|
|
509
|
+
prfct('ncrystal-config gives libdir: %s'%ncrystal_libdir)
|
|
510
|
+
|
|
511
|
+
def prepend_to_path( envdict, pathvar, entry ):
|
|
512
|
+
from shlex import quote
|
|
513
|
+
entry = quote(((entry.decode() if hasattr(entry,'decode') else entry) or '').strip())
|
|
514
|
+
if not entry:
|
|
515
|
+
return
|
|
516
|
+
ll = [ entry ]
|
|
517
|
+
orig = envdict.get(pathvar,'')
|
|
518
|
+
if orig:
|
|
519
|
+
ll.append( orig )
|
|
520
|
+
envdict[pathvar] = ':'.join(ll)
|
|
521
|
+
|
|
522
|
+
import os
|
|
523
|
+
cmake_env = os.environ.copy()
|
|
524
|
+
runtime_env = os.environ.copy()
|
|
525
|
+
prfct('Testing with cmakedir added to CMAKE_PREFIX_PATH and libdir added to (DY)LD_LIBRARY_PATH')
|
|
526
|
+
prepend_to_path( cmake_env, 'CMAKE_PREFIX_PATH', ncrystal_cmakedir )
|
|
527
|
+
prepend_to_path( runtime_env, 'LD_LIBRARY_PATH', ncrystal_libdir )
|
|
528
|
+
prepend_to_path( runtime_env, 'DYLD_LIBRARY_PATH', ncrystal_libdir )
|
|
529
|
+
def runcmake(args,apply_CMAKE_ARGS=True):
|
|
530
|
+
cmake_args = cmake_env.get('CMAKE_ARGS','') if apply_CMAKE_ARGS else ''
|
|
531
|
+
cmd=f'{cmakecmd} {cmake_args} {args}'
|
|
532
|
+
ok, output = _run_cmd(cmd, env=cmake_env)
|
|
533
|
+
prfct(f'Launching: {cmd}')
|
|
534
|
+
if not ok:
|
|
535
|
+
raise RuntimeError(f'Test command failed: {cmd}')
|
|
536
|
+
|
|
537
|
+
downstream_cmake = """
|
|
538
|
+
cmake_minimum_required(VERSION 3.10...3.24)
|
|
539
|
+
project(MyExampleProject LANGUAGES CXX)
|
|
540
|
+
find_package(NCrystal REQUIRED)
|
|
541
|
+
file(WRITE "${PROJECT_BINARY_DIR}/cppsrc.cpp" "
|
|
542
|
+
#include \\"NCrystal/NCrystal.hh\\"
|
|
543
|
+
#include <iostream>
|
|
544
|
+
int main() {
|
|
545
|
+
auto pc = NCrystal::createScatter( \\"Al_sg225.ncmat;dcutoff=0.5;temp=25C\\" );
|
|
546
|
+
auto wl = NCrystal::NeutronWavelength{1.8};
|
|
547
|
+
auto xsect = pc.crossSectionIsotropic( wl );
|
|
548
|
+
std::cout << \\"Powder Al x-sect at \\" << wl << \\" is \\" << xsect << std::endl;
|
|
549
|
+
return 0;
|
|
550
|
+
}
|
|
551
|
+
")
|
|
552
|
+
add_executable(exampleapp "${PROJECT_BINARY_DIR}/cppsrc.cpp")
|
|
553
|
+
target_link_libraries( exampleapp NCrystal::NCrystal )
|
|
554
|
+
install( TARGETS exampleapp DESTINATION bin )
|
|
555
|
+
"""
|
|
556
|
+
|
|
557
|
+
import pathlib
|
|
558
|
+
with _work_in_tmpdir():
|
|
559
|
+
td = pathlib.Path('.').absolute()
|
|
560
|
+
( td / 'src' ).mkdir()
|
|
561
|
+
( td / 'src' / 'CMakeLists.txt' ).write_text(downstream_cmake)
|
|
562
|
+
( td / 'bld' ).mkdir()
|
|
563
|
+
os.chdir( td / 'bld' )
|
|
564
|
+
runcmake('../src -DCMAKE_INSTALL_PREFIX=../install')
|
|
565
|
+
runcmake('--build . --target install --config Release',apply_CMAKE_ARGS=False)
|
|
566
|
+
os.chdir( td )
|
|
567
|
+
app = ( td / 'install' / 'bin' / 'exampleapp' )
|
|
568
|
+
if not app.exists():
|
|
569
|
+
raise RuntimeError('Could not produce example app in downstream cmake project')
|
|
570
|
+
prfct(f'Launching: {app}')
|
|
571
|
+
ok, output = _run_cmd(str(app),env=runtime_env)
|
|
572
|
+
if not ok:
|
|
573
|
+
raise RuntimeError('Could not launch example app compiled in downstream cmake project')
|
|
574
|
+
#envrun = os.environ.copy()
|
|
575
|
+
expected_output='Powder Al x-sect at 1.8Aa is 1.44816barn'
|
|
576
|
+
if not output.decode().strip()==expected_output:
|
|
577
|
+
raise RuntimeError('Example app compiled in downstream cmake project produces unexpected output')
|
|
578
|
+
prfct('App produced expected output')
|
|
579
|
+
prfct('testing of compiled downstream cmake-based projects done')
|