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.
Files changed (53) hide show
  1. NCrystal/__init__.py +85 -0
  2. NCrystal/__main__.py +98 -0
  3. NCrystal/_chooks.py +854 -0
  4. NCrystal/_cli_cif2ncmat.py +269 -0
  5. NCrystal/_cli_endf2ncmat.py +503 -0
  6. NCrystal/_cli_hfg2ncmat.py +144 -0
  7. NCrystal/_cli_mcstasunion.py +74 -0
  8. NCrystal/_cli_ncmat2cpp.py +31 -0
  9. NCrystal/_cli_ncmat2hkl.py +180 -0
  10. NCrystal/_cli_nctool.py +1018 -0
  11. NCrystal/_cli_vdos2ncmat.py +463 -0
  12. NCrystal/_cli_verifyatompos.py +257 -0
  13. NCrystal/_cliimpl.py +307 -0
  14. NCrystal/_cliwrap_config.py +36 -0
  15. NCrystal/_common.py +499 -0
  16. NCrystal/_coreimpl.py +114 -0
  17. NCrystal/_hfgdata.py +546 -0
  18. NCrystal/_hklobjects.py +136 -0
  19. NCrystal/_is_std.py +0 -0
  20. NCrystal/_locatelib.py +210 -0
  21. NCrystal/_miscimpl.py +354 -0
  22. NCrystal/_mmc.py +757 -0
  23. NCrystal/_msg.py +60 -0
  24. NCrystal/_ncmat2cpp_impl.py +445 -0
  25. NCrystal/_ncmatimpl.py +2131 -0
  26. NCrystal/_numpy.py +76 -0
  27. NCrystal/_testimpl.py +579 -0
  28. NCrystal/api.py +56 -0
  29. NCrystal/atomdata.py +177 -0
  30. NCrystal/cfgstr.py +77 -0
  31. NCrystal/cifutils.py +1795 -0
  32. NCrystal/cli.py +96 -0
  33. NCrystal/constants.py +134 -0
  34. NCrystal/core.py +1910 -0
  35. NCrystal/datasrc.py +226 -0
  36. NCrystal/exceptions.py +66 -0
  37. NCrystal/hfg2ncmat.py +270 -0
  38. NCrystal/mcstasutils.py +438 -0
  39. NCrystal/misc.py +317 -0
  40. NCrystal/mmc.py +35 -0
  41. NCrystal/ncmat.py +778 -0
  42. NCrystal/ncmat2cpp.py +80 -0
  43. NCrystal/obsolete.py +67 -0
  44. NCrystal/plot.py +484 -0
  45. NCrystal/plugins.py +49 -0
  46. NCrystal/test.py +76 -0
  47. NCrystal/vdos.py +1034 -0
  48. ncrystal_python-3.9.81.dist-info/LICENSE +206 -0
  49. ncrystal_python-3.9.81.dist-info/METADATA +515 -0
  50. ncrystal_python-3.9.81.dist-info/RECORD +53 -0
  51. ncrystal_python-3.9.81.dist-info/WHEEL +5 -0
  52. ncrystal_python-3.9.81.dist-info/entry_points.txt +10 -0
  53. ncrystal_python-3.9.81.dist-info/top_level.txt +1 -0
NCrystal/_msg.py ADDED
@@ -0,0 +1,60 @@
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
+
24
+ Internal implementation details for NCrystal output handling (see also
25
+ functions in _common.py).
26
+
27
+ """
28
+
29
+ def _default_pymsghandler( msg, msgtype ):
30
+ from ._common import print
31
+ if msgtype == 0:
32
+ #Info
33
+ print(f"NCrystal: {msg}")
34
+ elif msgtype == 1:
35
+ #Warning:
36
+ #TODO: Consider default action here:
37
+ if False:
38
+ from ._common import warn
39
+ warn(msg)
40
+ else:
41
+ print(f"NCrystal WARNING: {msg}")
42
+ else:
43
+ #Raw output:
44
+ assert msgtype == 2
45
+ print(msg,end='')
46
+
47
+ #TODO: Overlaps somewhat with the (py-only) set_ncrystal_print_fct from _common.py:
48
+
49
+ #NB: This next function could become part of a public API, allowing e.g. a GUI
50
+ #to redirect all NCrystal output to appropriate text boxes, etc.:
51
+ _was_set = [False]
52
+ def _setMsgHandler( handler ):
53
+ from ._chooks import _get_raw_cfcts
54
+ _rawfct = _get_raw_cfcts()
55
+ _rawfct['setmsghandler'](handler)
56
+ _was_set[0] = True
57
+
58
+ def _setDefaultPyMsgHandlerIfNotSet():
59
+ if not _was_set[0]:
60
+ _setMsgHandler(_default_pymsghandler)
@@ -0,0 +1,445 @@
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
+ #NB: Important that this script can work WITHOUT any imports (std modules
23
+ #allowed, but other NCrystal modules are not), since the file is used as a
24
+ #script from the NCrystal CMake code to embed the data library.
25
+
26
+ _default_regfctname = ( 'NCrystal::registerInMemoryStaticFileData'
27
+ '(const std::string&,const char*)' )
28
+
29
+ def _find_data_list( keys, run_standalone = False ):
30
+ if not keys:
31
+ return True, []
32
+ if ( isinstance(keys,list)
33
+ and isinstance(keys[0],dict)
34
+ and set(keys[0].keys())==set(['name',
35
+ 'read_text_function',
36
+ 'read_bytes_function']) ):
37
+ #keys is already a datalist:
38
+ return True, keys
39
+
40
+ datalist = []
41
+ bns=set()
42
+ for f in keys:
43
+ data = _find_data(f,run_standalone)
44
+ if not data:
45
+ return False, 'File not found: %s'%f
46
+ assert data['name'] is not None
47
+ if data['name'] in bns:
48
+ return False, 'Name not unique in list: %s'%f
49
+ datalist.append(data)
50
+ bns.add(data['name'])
51
+ datalist.sort(key = lambda d : d['name'])
52
+ return True, datalist
53
+
54
+ def _find_data( key, run_standalone ):
55
+ #Returns None if data is not found, otherwise a dictionary with name and
56
+ #read functions.
57
+ if run_standalone:
58
+ #Not allowed to do any imports apart from python stdlib imports. So we
59
+ #rely exclusively on finding files on disk.
60
+ import pathlib
61
+ f = pathlib.Path(key)
62
+ if not f.exists():
63
+ return None
64
+ return dict( name = pathlib.Path(f).name,
65
+ read_text_function = f.read_text,
66
+ read_bytes_function = f.read_bytes )
67
+ from .misc import AnyTextData
68
+ from .core import createTextData,TextData
69
+ if isinstance(key,AnyTextData):
70
+ td = key
71
+ is_textdata = False
72
+ elif isinstance(key,TextData):
73
+ td = key
74
+ is_textdata = True
75
+ elif '\n' not in key:
76
+ td = createTextData(key)
77
+ is_textdata = True
78
+ else:
79
+ td = AnyTextData(key)
80
+ is_textdata = False
81
+ name = td.dataSourceName if is_textdata else td.name
82
+
83
+ if name is None:
84
+ from .exceptions import NCBadInput
85
+ raise NCBadInput( 'Can not accept unnamed text data when'
86
+ ' converting to C++ code, since a string'
87
+ ' key will be needed in the code.' )
88
+ def td_read_text():
89
+ return td.rawData if is_textdata else td.content
90
+ def td_read_bytes():
91
+ return td_read_text().encode('utf-8')
92
+ return dict( name = name,
93
+ read_text_function = td_read_text,
94
+ read_bytes_function = td_read_bytes )
95
+
96
+ def parseArgs( progname, arglist, *, return_parser = False ):
97
+
98
+ #Hidden option used by CMake:
99
+ run_as_standalone_script = False
100
+ while arglist and '--runasstandalonescript' in arglist:
101
+ run_as_standalone_script = True
102
+ arglist.remove('--runasstandalonescript')
103
+
104
+ if not run_as_standalone_script:
105
+ from ._cliimpl import create_ArgumentParser
106
+ else:
107
+ def create_ArgumentParser( *a, **kw ):
108
+ import argparse
109
+ return argparse.ArgumentParser(*a,**kw)
110
+
111
+
112
+ #NOTE: Keep this description in sync with the doc-string in the Python API
113
+ #function in ncmat2cpp.py:
114
+ descr="""
115
+
116
+ Script which can be used to embed the content of .ncmat files (or actually any
117
+ ASCII/UTF8 excoded text files) directly into a C++ library. It does so by
118
+ reading the .ncmat files and creating C++ code which keeps the contents of the
119
+ files in static strings, and registers those strings with NCrystal, using the
120
+ original filename as key. Naturally, those file must be compiled along with the
121
+ rest of the C++ library, and the enclosing function must be invoked.
122
+
123
+ """
124
+ parser = create_ArgumentParser(prog = progname,
125
+ description=descr)
126
+ parser.add_argument( 'FILE', type=str, nargs='+',
127
+ help=( "One or more NCMAT (or other text) files. They"
128
+ " will be registered with a key equal to their"
129
+ " filename (without preceding directory name),"
130
+ " which must therefore be unique in the list") )
131
+ parser.add_argument('--compact','-c', action='store_true',
132
+ help=("Set this option to strip all comments and"
133
+ " excess whitespace from the file data before"
134
+ " embedding as C++ code."))
135
+ parser.add_argument('--validate','-v', action='store_true',
136
+ help="""If specified input files will be validated by confirming that they can be
137
+ loaded with NCrystal. For this to work, the NCrystal python module must be
138
+ available.""")
139
+ parser.add_argument("--name",'-n',default='registerNCMATData',type=str,
140
+ help="""Name of C++ function to create which must be called in order to register the
141
+ data with NCrystal. If desired, it can contain namespace(s), e.g. a value of
142
+ "MyNameSpace::myFunction" will create a function "void myFunction()" in the
143
+ namespace "MyNameSpace.""")
144
+ parser.add_argument("--regfctname",default=_default_regfctname,type=str,
145
+ help="""Name of C++ function used to register string objects with NCrystal.""")
146
+ parser.add_argument("--include",nargs='+',type=str,action='append',
147
+ help="""One or more extra include statements for the top of the file. The file
148
+ NCrystal/core/NCDefs.hh will always be included by default (prevent this by
149
+ adding a special entry 'no-ncrystal-includes' to the list).""")
150
+ parser.add_argument("--width",'-w',type=int,default=80,
151
+ help=("Wrap C++ code at this column width. Ignored"
152
+ " for text files <~60KB unless running with"
153
+ " --compact."))
154
+ parser.add_argument('--outfile','-o',type=str,default='stdout',
155
+ help="Name of output file (default: stdout)")
156
+
157
+ if return_parser:
158
+ return parser
159
+
160
+ args=parser.parse_args( arglist )
161
+ args.run_as_standalone_script = run_as_standalone_script
162
+
163
+ if not args.name or ' ' in args.name:
164
+ parser.error('Invalid C++ function name provided to --name')
165
+
166
+ ok, datalist_or_errmsg = _find_data_list( args.FILE,
167
+ run_as_standalone_script )
168
+ if not ok:
169
+ parser.error(datalist_or_errmsg)
170
+ args.files = datalist_or_errmsg
171
+ args.FILE=None
172
+
173
+ wmin=30
174
+ wmax=999999
175
+ if args.width>wmax:
176
+ args.width=wmax
177
+ if args.width < wmin:
178
+ parser.error('Out of range value of --width (must be at least %i)'%wmin)
179
+
180
+ #flatten args.include, so we get single list with 3 elements from:
181
+ # --inc 'foobla.hh' --inc '<vector>' Bla/Bla.hh
182
+ args.include = [item for sublist in (args.include or []) for item in sublist]
183
+
184
+ if args.run_as_standalone_script and args.validate:
185
+ parser.error('Do not use --validate with hidden'
186
+ ' --runasstandalonescript option')
187
+
188
+ return args
189
+
190
+ _sys_print = print
191
+ def files2cppcode(infiles,
192
+ *,outfile,
193
+ cppfunctionname='registerData',
194
+ compact=False,
195
+ width=140,
196
+ validate=False,
197
+ extra_includes=None,
198
+ regfctname=None,
199
+ quiet = False,
200
+ run_standalone = False
201
+ ):
202
+ #NOTE: This function is called both from the CLI script (this file) and the
203
+ #Python API function in ncmat2cpp.py
204
+
205
+ #We would like to support AnyTextData, but since we must try to not do any
206
+ #imports when this is used from CLI (to use it in the NCrystal CMake cfg
207
+ #step to embed the standard lib), we should be a bit more careful:
208
+ orig_print_fct = _sys_print
209
+ if quiet:
210
+ def print(*a,**kw):
211
+ pass
212
+ elif run_standalone:
213
+ print = _sys_print
214
+ else:
215
+ from ._cliimpl import print
216
+ orig_print_fct = print
217
+
218
+ if regfctname is None:
219
+ regfctname = _default_regfctname
220
+ if regfctname.startswith('NCrystal::'):
221
+ regfctname = 'NCRYSTAL_NAMESPACE::' + regfctname[len('NCrystal::'):]
222
+
223
+ out=['// Code automatically generated by NCrystal/ncmat2cpp','']
224
+ if extra_includes is None:
225
+ extra_includes = []
226
+ if 'no-ncrystal-includes' in extra_includes:
227
+ extra_includes = [ e for e in extra_includes
228
+ if e!='no-ncrystal-includes' ]
229
+ else:
230
+ extra_includes.insert(0,'NCrystal/core/NCDefs.hh')
231
+
232
+ for inc in extra_includes:
233
+ if inc.startswith('#include'):
234
+ out.append(inc)
235
+ elif inc.startswith('<'):
236
+ out.append('#include %s'%inc)
237
+ else:
238
+ out.append('#include "%s"'%inc)
239
+ out.append('')
240
+
241
+ large_files = False
242
+
243
+ def fwddeclare(out,fctname,args_str=''):
244
+ if '(' not in fctname:
245
+ fctname+='()'
246
+ _ = fctname.split('(',1)[0].split('::')
247
+ namespaces,justname = _[0:-1],_[-1]
248
+ if namespaces and namespaces[0]=='NCrystal':
249
+ namespaces[0]='NCRYSTAL_NAMESPACE'
250
+ argssignature='('+fctname.split('(',1)[1]
251
+ tmp=''
252
+ for ns in namespaces:
253
+ tmp += 'namespace %s { '%ns
254
+ tmp += 'void %s%s;'%(justname,argssignature)
255
+ tmp += ' }'*len(namespaces)
256
+ out+=[tmp]
257
+ out+=['']
258
+
259
+ fwddeclare(out,regfctname)
260
+ if '::' in cppfunctionname:
261
+ fwddeclare(out,cppfunctionname)
262
+
263
+ out += [ 'void %s()'%cppfunctionname, '{' ]
264
+ prefix=' '
265
+ seen = set()
266
+
267
+ ok, datalist_or_errmsg = _find_data_list( infiles )
268
+ if not ok:
269
+ if run_standalone:
270
+ raise RuntimeError(datalist_or_errmsg)
271
+ else:
272
+ from .exceptions import NCBadInput
273
+ raise NCBadInput(datalist_or_errmsg)
274
+ else:
275
+ datalist = datalist_or_errmsg
276
+
277
+ for data in datalist:
278
+ #for p in [pathlib.Path(f) for f in infiles]:
279
+ fn= data['name']
280
+ print(f"ncmat2cpp : Processing {fn}")
281
+ assert fn not in seen, "ERROR: Multiple files in input named: %s"%fn
282
+ seen.add(fn)
283
+
284
+ def fmtline(line):
285
+ if compact:
286
+ ncmatcfg=None
287
+ if 'NCRYSTALMATCFG[' in line:
288
+ #special case: preserve NCRYSTALMATCFG
289
+ _=line.split('NCRYSTALMATCFG[',1)[1]
290
+ errmsg = None
291
+ if 'NCRYSTALMATCFG' in _:
292
+ errmsg = "multiple NCRYSTALMATCFG entries in a single line"
293
+ elif ']' not in _:
294
+ errmsg = "NCRYSTALMATCFG[ entry without closing ] bracket"
295
+ if errmsg:
296
+ if run_standalone:
297
+ raise RuntimeError(errmsg)
298
+ else:
299
+ from .exceptions import NCBadInput
300
+ raise NCBadInput(errmsg)
301
+ ncmatcfg=_.split(']',1)[0].strip()
302
+ ncmatcfg.encode('utf8')#Just a check
303
+ line=' '.join(line.split('#',1)[0].split())
304
+ line.encode('ascii')#Just a check
305
+ if ncmatcfg:
306
+ line += '#NCRYSTALMATCFG[%s]'%ncmatcfg
307
+ if not line:
308
+ return ''
309
+ else:
310
+ line.encode('utf8')#Just a check
311
+ return line.replace('"',r'\"')+r'\n'
312
+
313
+ def as_c_str(strdata):
314
+ try:
315
+ strdata.encode('ascii')
316
+ return '"%s"'%strdata
317
+ except UnicodeEncodeError:
318
+ pass
319
+ try:
320
+ strdata.encode('utf8')
321
+ return 'u8"%s"'%strdata
322
+ except UnicodeEncodeError:
323
+ raise SystemExit('Invalid encoding encountered in'
324
+ ' input (must be ASCII or UTF8)')
325
+
326
+
327
+ raw_text_data = data['read_text_function']()
328
+
329
+ if validate:
330
+ assert not run_standalone,"standalone mode prevents --validate"
331
+ print("Trying to validate: %s"%fn)
332
+ from .misc import MaterialSource
333
+ MaterialSource( raw_text_data ).load( doInfo = True,
334
+ doScatter = False,
335
+ doAbsorption = False )
336
+ print(' -> OK')
337
+
338
+ lines = list(raw_text_data.splitlines())
339
+ assert lines,"file was empty: %s"%fn
340
+
341
+ #string literals have a limit of 65K in the standard. For such large
342
+ #files we must embed contents in const std::array<std::uint8_t, 12>
343
+ #arrays.
344
+ is_large = ( sum(len(as_c_str(fmtline(line))) for line in lines) > 60000 )
345
+
346
+ if is_large:
347
+ large_files=True
348
+
349
+ out+= [prefix+"{"]
350
+ out+= [prefix+" // File %s%s%s"%(fn,
351
+ (' (compact form without comments)' if compact else ''),
352
+ (' (too large for string literals)' if is_large else ''))]
353
+
354
+ if is_large:
355
+ #NB: This could be used for non-text-data as well!
356
+ raw_data_bytes = data['read_bytes_function']()
357
+ out += [ prefix+' static const std::array<std::uint8_t,%i> rawdata {'%(len(raw_data_bytes)+1)]
358
+ n = len(raw_data_bytes)
359
+ n_on_current_line = 0
360
+ delim,currentline='',''
361
+ _prefstr = prefix+' '
362
+ ndatawidth = width-len(_prefstr)
363
+ for c in raw_data_bytes:
364
+ ++n_on_current_line
365
+ currentline += delim + str(c)
366
+ delim = ','
367
+ if len(currentline)>=ndatawidth:
368
+ out += [_prefstr + currentline+',']
369
+ delim=''
370
+ currentline = ''
371
+ eol=',0};'
372
+ if currentline:
373
+ out += [_prefstr + currentline+eol]
374
+ else:
375
+ out[-1] = out[-1][:-1]+eol
376
+ out += [' const char * textdata = (const char*)(&rawdata[0]);']
377
+ else:
378
+ #count_all_entries = [0]
379
+ def linepattern(strdata):
380
+ return ' %s'%as_c_str(strdata)
381
+ #fix_nentries_iout = len(out)
382
+ out += [ prefix+' const char * textdata =']
383
+ if not compact:
384
+ for line in lines:
385
+ out+= [prefix+linepattern(fmtline(line))]
386
+ else:
387
+ alldata=''
388
+ for line in lines:
389
+ alldata += fmtline(line)
390
+ while alldata:
391
+ n = max(10,width-(len(linepattern(''))))
392
+ if alldata[n-1:n+1]==r'\n':
393
+ n+=1#dont break up '\n' entries
394
+ out += [ prefix+linepattern(alldata[0:n])]
395
+ alldata = alldata[n:]
396
+ out[-1]+=';'
397
+ out+= [prefix+" ::%s(\"%s\",textdata);"%(regfctname.split('(')[0],fn)]
398
+ out+= [prefix+"}"]
399
+ out+= ['}','']
400
+
401
+ if large_files:
402
+ out.insert(1,'#include <cstdint>')
403
+ out.insert(1,'#include <array>')
404
+
405
+ out = '\n'.join(out)
406
+ if outfile is None:
407
+ pass
408
+ elif outfile == 'stdout':
409
+ for line in out.splitlines():
410
+ orig_print_fct(line)
411
+ else:
412
+ import pathlib
413
+ of=pathlib.Path(outfile)
414
+ if run_standalone:
415
+ of.write_text(out,encoding='utf8')
416
+ else:
417
+ from ._common import write_text
418
+ write_text(of,out)
419
+ print('Wrote: %s'%of)
420
+ return out
421
+
422
+ #Sphinx doc function. Signature always the following:
423
+ def create_argparser_for_sphinx( progname ):
424
+ return parseArgs([progname],return_parser=True)
425
+
426
+ def main( progname, arglist ):
427
+ args = parseArgs( progname, arglist )
428
+ return files2cppcode( args.files,
429
+ outfile = args.outfile,
430
+ cppfunctionname = args.name,
431
+ compact = args.compact,
432
+ width = args.width,
433
+ extra_includes = args.include,
434
+ validate = args.validate,
435
+ regfctname = args.regfctname,
436
+ quiet = False,
437
+ run_standalone = args.run_as_standalone_script )
438
+
439
+ if __name__ == '__main__':
440
+ #Running from CMake code to embed the standard data library.
441
+ import sys
442
+ import os
443
+ progname = os.path.basename(sys.argv[0])
444
+ arglist = sys.argv[1:] + ['--runasstandalonescript']
445
+ main( progname, arglist )