pyemaps 2.0.0__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 (112) hide show
  1. pyemaps/COPYING +798 -0
  2. pyemaps/CifFile/CifFile_module.py +3117 -0
  3. pyemaps/CifFile/StarFile.py +2496 -0
  4. pyemaps/CifFile/TypeContentsParser.py +82 -0
  5. pyemaps/CifFile/YappsStarParser_1_0.py +289 -0
  6. pyemaps/CifFile/YappsStarParser_1_1.py +288 -0
  7. pyemaps/CifFile/YappsStarParser_2_0.py +369 -0
  8. pyemaps/CifFile/YappsStarParser_STAR2.py +382 -0
  9. pyemaps/CifFile/__init__.py +7 -0
  10. pyemaps/CifFile/drel/__init__.py +1 -0
  11. pyemaps/CifFile/drel/drel_ast_yacc.py +582 -0
  12. pyemaps/CifFile/drel/drel_lex.py +228 -0
  13. pyemaps/CifFile/drel/drel_runtime.py +126 -0
  14. pyemaps/CifFile/drel/parsetab.py +185 -0
  15. pyemaps/CifFile/drel/py_from_ast.py +628 -0
  16. pyemaps/CifFile/parsetab.py +185 -0
  17. pyemaps/CifFile/yapps3_compiled_rt.py +390 -0
  18. pyemaps/README.md +201 -0
  19. pyemaps/__config__.py +91 -0
  20. pyemaps/__init__.py +233 -0
  21. pyemaps/__main__.py +219 -0
  22. pyemaps/__version__.py +1 -0
  23. pyemaps/cdata/Aluminium.xtl +4 -0
  24. pyemaps/cdata/AluminiumOxide.xtl +5 -0
  25. pyemaps/cdata/Aluminium_FCC.xtl +4 -0
  26. pyemaps/cdata/BariumTitanate_180k.xtl +6 -0
  27. pyemaps/cdata/BariumTitanate_270k.xtl +7 -0
  28. pyemaps/cdata/BariumTitanate_Tetra.xtl +7 -0
  29. pyemaps/cdata/BiMnO3.xtl +27 -0
  30. pyemaps/cdata/Boron_Tetra.xtl +8 -0
  31. pyemaps/cdata/CadmiumSelenide_Hex.xtl +5 -0
  32. pyemaps/cdata/CadmiumSulfide_Cubic.xtl +5 -0
  33. pyemaps/cdata/CadmiumSulfide_Hex.xtl +5 -0
  34. pyemaps/cdata/Chromium_BCC.xtl +4 -0
  35. pyemaps/cdata/CoSb3_Skutterudite.xtl +5 -0
  36. pyemaps/cdata/CopperOxide.xtl +5 -0
  37. pyemaps/cdata/Copper_FCC.xtl +4 -0
  38. pyemaps/cdata/Cu2O_Cuprite.xtl +5 -0
  39. pyemaps/cdata/Diamond.xtl +4 -0
  40. pyemaps/cdata/ErbiumPyrogermanate.xtl +9 -0
  41. pyemaps/cdata/FePd_Tetra.xtl +5 -0
  42. pyemaps/cdata/FeS2_Pyrite.xtl +15 -0
  43. pyemaps/cdata/GalliumAntimonide.xtl +5 -0
  44. pyemaps/cdata/GalliumArsenide.xtl +5 -0
  45. pyemaps/cdata/GalliumNitride.xtl +5 -0
  46. pyemaps/cdata/Germanium.xtl +4 -0
  47. pyemaps/cdata/Gold_FCC.xtl +4 -0
  48. pyemaps/cdata/IndiumArsenide.xtl +5 -0
  49. pyemaps/cdata/LaMnO3.xtl +7 -0
  50. pyemaps/cdata/LeadZirconateTitanate.xtl +8 -0
  51. pyemaps/cdata/Li2MnO3.xtl +13 -0
  52. pyemaps/cdata/NaFeO2.xtl +6 -0
  53. pyemaps/cdata/Nb3Sn.xtl +5 -0
  54. pyemaps/cdata/Pentacene.xtl +39 -0
  55. pyemaps/cdata/Silicon.xtl +4 -0
  56. pyemaps/cdata/StrontiumTitanate.xtl +6 -0
  57. pyemaps/cdata/TelluriumDioxide.xtl +5 -0
  58. pyemaps/cdata/TinDioxide_RT.xtl +5 -0
  59. pyemaps/cdata/TitaniumDioxide_Anatase.xtl +5 -0
  60. pyemaps/cdata/TitaniumDioxide_Rutile.xtl +5 -0
  61. pyemaps/cdata/TungstenDiselenide.xtl +5 -0
  62. pyemaps/cdata/VanadiumDioxide_RT.xtl +6 -0
  63. pyemaps/cdata/ZincOxide.xtl +5 -0
  64. pyemaps/cdata/Zinc_HCP.xtl +4 -0
  65. pyemaps/cdata/ZirconiumNitride.xtl +5 -0
  66. pyemaps/cdata/limno2.xtl +6 -0
  67. pyemaps/crystals.py +1415 -0
  68. pyemaps/ddiffs.py +147 -0
  69. pyemaps/diffract/__init__.py +70 -0
  70. pyemaps/diffract/bloch_dec.py +779 -0
  71. pyemaps/diffract/csf_dec.py +242 -0
  72. pyemaps/diffract/dif_dec.py +519 -0
  73. pyemaps/diffract/dpgen_dec.py +175 -0
  74. pyemaps/diffract/mxtal_dec.py +201 -0
  75. pyemaps/diffract/powder_dec.py +137 -0
  76. pyemaps/diffract/stereo_dec.py +111 -0
  77. pyemaps/display.py +791 -0
  78. pyemaps/emcontrols.py +1017 -0
  79. pyemaps/errors.py +266 -0
  80. pyemaps/fileutils.py +1001 -0
  81. pyemaps/kdiffs.py +1221 -0
  82. pyemaps/license.txt +42 -0
  83. pyemaps/samples/adf.py +137 -0
  84. pyemaps/samples/al.img +0 -0
  85. pyemaps/samples/al_dpgen.py +57 -0
  86. pyemaps/samples/al_ediom.py +94 -0
  87. pyemaps/samples/convert_image.py +88 -0
  88. pyemaps/samples/dm_diff.py +225 -0
  89. pyemaps/samples/mask.im3 +0 -0
  90. pyemaps/samples/powder.py +51 -0
  91. pyemaps/samples/raw.img +0 -0
  92. pyemaps/samples/si_bloch.py +120 -0
  93. pyemaps/samples/si_constructor.py +51 -0
  94. pyemaps/samples/si_csf.py +59 -0
  95. pyemaps/samples/si_dif.py +134 -0
  96. pyemaps/samples/si_lacbed.py +59 -0
  97. pyemaps/samples/si_pyemaps.py +80 -0
  98. pyemaps/samples/si_scm.py +156 -0
  99. pyemaps/samples/si_stereo.py +116 -0
  100. pyemaps/scattering/__init__.py +26 -0
  101. pyemaps/scattering/sct_dec.py +31 -0
  102. pyemaps/spg/__init__.py +25 -0
  103. pyemaps/spg/spg_dec.py +60 -0
  104. pyemaps/stackimg.py +1031 -0
  105. pyemaps/xtal.py +222 -0
  106. pyemaps-2.0.0.dist-info/METADATA +231 -0
  107. pyemaps-2.0.0.dist-info/RECORD +112 -0
  108. pyemaps-2.0.0.dist-info/WHEEL +5 -0
  109. pyemaps-2.0.0.dist-info/entry_points.txt +2 -0
  110. pyemaps-2.0.0.dist-info/licenses/COPYING +798 -0
  111. pyemaps-2.0.0.dist-info/licenses/license.txt +42 -0
  112. pyemaps-2.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,628 @@
1
+ # To maximize python3/python2 compatibility
2
+ from __future__ import print_function
3
+ from __future__ import unicode_literals
4
+ from __future__ import division
5
+ from __future__ import absolute_import
6
+
7
+ # The unicode type does not exist in Python3 as the str type
8
+ # encompasses unicode. PyCIFRW tests for 'unicode' would fail
9
+ # Suggestions for a better approach welcome.
10
+
11
+ if isinstance(u"abc",str): #Python3
12
+ unicode = str
13
+
14
+ import re
15
+ from CifFile import CifError
16
+ pycifrw_func_table = { #how to use PyCIFRW CifFile objects
17
+ "data_access": "ciffile[%s]", # argument is dataname to be accessed
18
+ "optional_data_access":"emapsCifFile.get(%s,None)",
19
+ "element_no": "%s[%s]", # accessing a particular element of the result of data_access
20
+ "count_data": "len(%s)", # number of elements for result of data_access
21
+ "cat_names":"emapsCifFile.dictionary.names_in_cat(%s)", #names in category %s
22
+ "has_name":"emapsCifFile.has_key_or_alias(%s)",
23
+ "semantic_packet":"emapsCifFile.GetKeyedSemanticPacket(%s,%s)" #get a packet for key, value
24
+ }
25
+
26
+ def make_python_function(in_ast,func_name,targetname, special_ids=[{}],
27
+ func_table = pycifrw_func_table, cif_dic=None,cat_meth=False,
28
+ func_def = False, have_sn=True,loopable={},debug=None,depends=False):
29
+ """Convert in_ast to python code"""
30
+ if debug is not None:
31
+ print("incoming AST:")
32
+ print(repr(in_ast))
33
+ func_text,withtable,dependencies,cur_row = start_traverse(in_ast,func_table,target_id=targetname,cat_meth=cat_meth,loopable=loopable,debug=debug,func=func_def,cif_dic=cif_dic)
34
+ if debug is not None:
35
+ print('Start========')
36
+ print(func_text)
37
+ print('End==========')
38
+ if func_def and not depends:
39
+ return func_text
40
+ elif func_def:
41
+ return func_text, None
42
+ # now indent the string
43
+ noindent = func_text.splitlines()
44
+ # get the minimum indent and remove empty lines
45
+ no_spaces = [re.match(r' *',a).end() for a in noindent if a] #drop empty lines
46
+ min_spaces = min(no_spaces)+4 # because we add 4 ourselves to everything
47
+ if len(withtable) > 0 or cur_row: # a loop method
48
+ d_vars = [a[1][0] for a in withtable.items()]
49
+ if cur_row:
50
+ d_vars = d_vars + ['__current_row']
51
+ dummy_vars = ",".join(d_vars)
52
+ actual_names = [k for k in withtable.keys()]
53
+ actual_names = [func_table["data_access"]% ("'"+a+"'") for a in actual_names]
54
+ # intercept optional values and replace with [] if None
55
+ optional_names = ["__option_w%d"%n for n,k in enumerate(withtable.keys()) if withtable[k][2]]
56
+ if cur_row:
57
+ actual_names+=['__row_id']
58
+ final_names = actual_names[:]
59
+ one_pack_names = [func_table["element_no"] % (a,"packet_no") for a in actual_names]
60
+ for n,k in enumerate(withtable.keys()):
61
+ if withtable[k][2]:
62
+ final_names[n]="__option_w%d"%n #pre-evaluated
63
+ one_pack_names[n] = "__option_w%d"%n
64
+ map_names = ",".join(final_names)
65
+ one_packet_each = ",".join(one_pack_names)
66
+ preamble = "def %s(ciffile,packet_no=-1):\n" % (func_name)
67
+ preamble +=" try:\n"
68
+ preamble +=" from itertools import repeat,imap\n" #note that imap might fail
69
+ preamble +=" except ImportError: #python3\n"
70
+ preamble +=" imap = map\n"
71
+ preamble +=" def drel_func(%s):\n" % dummy_vars
72
+ # for debugging
73
+ print_instruction = "'Function passed variables "+("{!r} "*len(d_vars))+"'.format("+dummy_vars+",)"
74
+ preamble +=" print(%s)\n" % print_instruction
75
+ # preamble +=" print('Globals inside looped drel_func:' + repr(globals())\n")
76
+ # the actual function gets inserted here
77
+ # Handle the optional names
78
+ end_body = "\n"
79
+ for n,one_opt in enumerate(withtable.keys()):
80
+ if withtable[one_opt][2]:
81
+ end_body += " try:\n"
82
+ end_body += " %s%d = %s\n" % ("__option_w",n,func_table["optional_data_access"]%("'"+one_opt+"'"))
83
+ end_body += " except KeyError:\n"
84
+ end_body += " %s%d = None\n" % ("__option_w",n)
85
+ end_body+= " if packet_no < 0: #map\n"
86
+ for one_opt in optional_names:
87
+ end_body += " if %s is None: %s = repeat(None)\n" % (one_opt,one_opt)
88
+
89
+ if cur_row and len(actual_names) > 1: #i.e. have real names from category
90
+ end_body +=" __row_id = range(%s)\n" % (func_table['count_data'] % ("'"+actual_names[0]+"'"))
91
+ elif cur_row and len(actual_names)==1: #so no actual names available
92
+
93
+ end_body += " cat_names = %s\n" % (func_table["cat_names"] % ("'"+getcatname(targetname)[0]+"'"))
94
+ end_body += " have_name = [a for a in cat_names if %s]\n" % (func_table["has_name"] % "a")
95
+ end_body += " if len(have_name)>0:\n"
96
+ end_body += " full_length = %s \n" % (func_table["count_data"] % (func_table["data_access"] % "have_name[0]"))
97
+ end_body += " __row_id = range(full_length)\n"
98
+ end_body += " else:\n"
99
+ end_body += " return []\n"
100
+
101
+ end_body+= " return list(imap(drel_func,%s))\n" % (map_names+",")
102
+ end_body+= " else:\n"
103
+ end_body+= " return drel_func(%s)\n" % one_packet_each
104
+
105
+ else:
106
+ preamble = "def %s(ciffile):\n" % func_name
107
+ #preamble +=" global StarList#from emapsCifFile.drel import drel_runtime\n"
108
+ end_body = ""
109
+
110
+ if cat_meth:
111
+ preamble += " "*8 + "__dreltarget = {}\n" # initialise
112
+ num_header = """
113
+ import math,cmath
114
+ try:
115
+ import numpy
116
+ except:
117
+ print("Can't import numerical python, this method may not work")
118
+ """
119
+ preamble += num_header
120
+ indented = map(lambda a:" "*8 + a +"\n",noindent) #indent dREL body
121
+ postamble = ""
122
+ postamble += " "*8 + "return __dreltarget"
123
+ final = preamble + "".join(indented) + postamble + end_body
124
+ if not depends:
125
+ return final
126
+ else: return final, dependencies
127
+
128
+ def start_traverse(in_node,api_table,target_id=None,loopable={},cat_meth=False,debug=None, func=False,
129
+ cif_dic=None):
130
+ special_info = {"special_id":[{}],"target_id":target_id,"withtable":{},"sub_subject":"",
131
+ "depends":set(),"loopable_cats":loopable,"packet_vars":{},
132
+ "need_current_row":False,"rhs":None,"inif":False}
133
+ # create a virtual enclosing 'with' statement
134
+ if target_id is not None and not cat_meth and not func:
135
+ cat,name = getcatname(target_id)
136
+ special_info["special_id"][-1].update({"_"+cat:[cat,"",False]})
137
+ if cat in special_info["loopable_cats"].keys(): #
138
+ special_info["special_id"][-1]["_"+cat][1] = "looped_cat"
139
+ mathop_table = {"+":None, "-":None, "<":"<", "*":None, "/":None,
140
+ "&":"&", "|":"|",
141
+ ">":">", "<=":"<=", ">=":">=", "!=":"!=",
142
+ "or":" or ", "and":" and ",
143
+ "==":"==", "in":" in ", "not in":" not in ",
144
+ "^":None,"**":"**"}
145
+
146
+ aug_assign_table = {"++=":"drel_runtime.aug_append",
147
+ "+=":"drel_runtime.aug_add",
148
+ "-=":"drel_runtime.aug_sub",
149
+ "--=":"drel_runtime.aug_remove"}
150
+
151
+ def traverse_ast(in_node,debug=debug):
152
+ if isinstance(in_node,(unicode,str)):
153
+ return in_node
154
+ if isinstance(in_node[0],list):
155
+ raise SyntaxError('First element of AST Node must be string: ' + repr(in_node))
156
+ node_type = in_node[0]
157
+ if debug == node_type:
158
+ print(node_type + ": " + repr(in_node))
159
+ if node_type == "ARGLIST":
160
+ pass
161
+ elif node_type == "BINARY":
162
+ return("%d" % int(in_node[1],base=2))
163
+ elif node_type == "FALSE":
164
+ return("False")
165
+ elif node_type == "REAL":
166
+ return(in_node[1])
167
+ elif node_type == "HEX":
168
+ return("%d" % int(in_node[1],base=16))
169
+ elif node_type == "INT":
170
+ return(in_node[1])
171
+ elif node_type == "IMAGINARY":
172
+ return(in_node[1])
173
+ elif node_type == "OCTAL":
174
+ return("%d" % int(in_node[1],base=8))
175
+
176
+ elif node_type == "ATOM":
177
+ if isinstance(in_node[1],(unicode,str)):
178
+ # pick up built-in literals
179
+ if in_node[1].lower() == 'twopi':
180
+ return "(2.0 * math.pi)"
181
+ if in_node[1].lower() == 'pi':
182
+ return "math.pi"
183
+ else:
184
+ return in_node[1]
185
+ else:
186
+ return traverse_ast(in_node[1])
187
+ elif node_type == "ITEM_TAG":
188
+ return in_node[1]
189
+ elif node_type == "LITERAL":
190
+ return in_node[1]
191
+ elif node_type == "LIST":
192
+ if len(in_node)==1: #empty list
193
+ return "StarList([])"
194
+ if special_info["rhs"] == True:
195
+ outstring = "StarList(["
196
+ else:
197
+ outstring = ""
198
+ for list_elem in in_node[1:]:
199
+ outstring = outstring + traverse_ast(list_elem) + ","
200
+ if special_info["rhs"] == True:
201
+ return outstring[:-1] + "])"
202
+ else:
203
+ return outstring[:-1]
204
+ elif node_type == "TABLE":
205
+ if len(in_node)==1:
206
+ return "StarTable({})"
207
+ else:
208
+ outstring = "{"
209
+ for table_elem in in_node[1:]:
210
+ outstring = outstring + traverse_ast(table_elem[0])+":"+traverse_ast(table_elem[1]) +","
211
+ return outstring[:-1] + "}"
212
+ elif node_type == "SUBSCRIPTION": # variable, single expression
213
+ newid = 0
214
+ if in_node[1][0] == "ATOM" and in_node[1][1][0] == "ITEM_TAG": #keyed lookup
215
+ print("Found category used as item tag: subscribing")
216
+ newid = [in_node[1][1][1][1:],False,False] #drop underscore and remember
217
+ else:
218
+ primary = traverse_ast(in_node[1])
219
+ # check to see if this is a special variable
220
+ for idtable in special_info["special_id"]:
221
+ newid = idtable.get(primary,0)
222
+ if newid: break
223
+ if primary in special_info["loopable_cats"].keys(): #loop category used
224
+ newid = [primary,False,False]
225
+ break
226
+ if newid:
227
+ #FIXME: the dataname may not be the <cat>.<obj> construction (eg pdCIF)
228
+ key_items = ["_"+newid[0]+"."+s for s in special_info["loopable_cats"][newid[0]][0]] #key name
229
+ special_info["depends"].update([k.lower() for k in key_items])
230
+ get_loop = api_table["semantic_packet"] % (traverse_ast(in_node[2]),"'"+newid[0]+"'")
231
+ special_info["sub_subject"] = newid[0] #in case of attribute reference following
232
+ print("Set sub_subject to %s" % special_info["sub_subject"])
233
+ return get_loop
234
+ else:
235
+ outstring = primary + "["
236
+ outstring = outstring + traverse_ast(in_node[2]) + "]"
237
+ return outstring
238
+
239
+ elif node_type == "ATTRIBUTE": # id/tag , att
240
+ outstring = ""
241
+ newid = 0
242
+ # check for special ids
243
+ primary = traverse_ast(in_node[1]) # this will set sub_subject if necessary
244
+ for idtable in special_info["special_id"]:
245
+ newid = idtable.get(primary,0)
246
+ if newid: break
247
+ if newid:
248
+ #catch our output name
249
+ true_name = cif_dic.get_name_by_cat_obj(newid[0].lower(),in_node[2].lower()).lower()
250
+ if true_name == special_info.get("target_id","").lower():
251
+ outstring = "__dreltarget"
252
+ special_info["have_drel_target"] = True
253
+ # if we are looping, we add a loop prefix. If we are withing an
254
+ # unlooped category, we put the full name back.
255
+ elif newid[2] or (not newid[2] and not newid[1]): # looping or simple with
256
+ outstring = api_table["data_access"] % ('"' +true_name +'"')
257
+ special_info["depends"].add(true_name)
258
+ if newid[1]: # a loop statement requires an index
259
+ outstring += "[" + newid[1]+ "]"
260
+ else: # a with statement; capture the name and create a dummy variable
261
+ if true_name not in special_info["withtable"]: #new
262
+ position = len(special_info["withtable"])
263
+ new_var = "__w%d" % position
264
+ isoptional = special_info["inif"]
265
+ special_info["withtable"][true_name] = (new_var,position,isoptional)
266
+ outstring += special_info["withtable"][true_name][0]
267
+ special_info["depends"].add(true_name)
268
+ elif in_node[1][0] == "ATOM" and primary[0] == "_": # a cat/obj name
269
+ fullname = cif_dic.get_name_by_cat_obj(primary,in_node[2]).lower()
270
+ # a simple cat.obj dataname from the dictionary
271
+ if special_info.get("target_id","").lower() == fullname:
272
+ outstring = "__dreltarget"
273
+ special_info["have_drel_target"] = True
274
+ else:
275
+ special_info["depends"].add(fullname)
276
+ outstring = api_table["data_access"] % ("'" + fullname + "'")
277
+ else: # default to Python attribute access
278
+ # check for packet variables
279
+ if primary in special_info["packet_vars"]:
280
+ real_cat = special_info["packet_vars"][primary]
281
+ fullname = cif_dic.get_name_by_cat_obj(real_cat,in_node[2])
282
+ special_info['depends'].add(fullname)
283
+ elif special_info["sub_subject"]:
284
+ fullname = cif_dic.get_name_by_cat_obj(special_info["sub_subject"],in_node[2])
285
+ special_info['depends'].add(fullname)
286
+ else: # not anything special
287
+ fullname = in_node[2]
288
+ outstring = "getattr(" + primary + ",'" + fullname + "')"
289
+ # sub_subject no longer relevant after attribute resolution
290
+ special_info['sub_subject'] = ""
291
+ return outstring
292
+
293
+ elif node_type == "FUNC_CALL":
294
+ if in_node[1] == "Current_Row": #not a function but a keyword really
295
+ outstring = "__current_row"
296
+ special_info["need_current_row"]=True
297
+ else:
298
+ func_name,every_arg_prefix,postfix = get_function_name(in_node[1])
299
+ outstring = func_name + "( "
300
+ if func_name == "list" and len(in_node[2])>1: #special case
301
+ outstring = outstring + "["
302
+ for argument in in_node[2]:
303
+ outstring = outstring + every_arg_prefix + traverse_ast(argument) + ","
304
+ if postfix == None: # signal for dictionary defined
305
+ outstring = outstring + "ciffile)"
306
+ else:
307
+ outstring = outstring[:-1]
308
+ if func_name == "list" and len(in_node[2])>1:
309
+ outstring = outstring + "]"
310
+ outstring = outstring + ")" + postfix
311
+ return outstring
312
+
313
+ elif node_type == "SLICE": # primary [[start,finish,step],[...]
314
+ outstring = traverse_ast(in_node[1]) + "["
315
+ slice_list = in_node[2]
316
+ for one_slice in slice_list:
317
+ if one_slice[0] == "EXPR": #not a slice as such
318
+ outstring += traverse_ast(one_slice)
319
+ elif len(one_slice) == 0:
320
+ outstring += ":"
321
+ elif len(one_slice) >0: # at least start
322
+ outstring += traverse_ast(one_slice[0]) + ":"
323
+ if len(one_slice) >1: #start,finish only
324
+ outstring += traverse_ast(one_slice[1])
325
+ if len(one_slice) == 3: #step as well
326
+ outstring += ":" + traverse_ast(one_slice[2])
327
+ outstring += ","
328
+ outstring = outstring[:-1] + "]"
329
+ return outstring
330
+
331
+ elif node_type == "MATHOP":
332
+ op = mathop_table[in_node[1]]
333
+ first_arg = traverse_ast(in_node[2])
334
+ second_arg = traverse_ast(in_node[3])
335
+ if op is not None: #simple operation
336
+ outstring = first_arg + op + second_arg
337
+ else:
338
+ outstring = fix_mathops(in_node[1],first_arg,second_arg)
339
+ return outstring
340
+ elif node_type == "SIGN":
341
+ outstring = "drel_runtime.drel_dot(" + in_node[1] + "1," + traverse_ast(in_node[2])+")"
342
+ return outstring
343
+ elif node_type == "UNARY":
344
+ outstring = in_node[1] + " " + traverse_ast(in_node[2])
345
+ return outstring
346
+
347
+ elif node_type == "IF_EXPR": #IF_EXPR test true_suite [ELSE IF_EXPR] false_suite
348
+ outstring = "if "
349
+ outstring = outstring + traverse_ast(in_node[1])
350
+ outstring = outstring + ":"
351
+ old_inif = special_info["inif"]
352
+ special_info["inif"] = True
353
+ true_bit = traverse_ast(in_node[2])
354
+ outstring = outstring + add_indent("\n"+true_bit) #indent
355
+ elseif = in_node[3]
356
+ if len(elseif)!=0:
357
+ for one_cond in elseif: #each entry is condition, suite
358
+ outstring += "\nelif " + traverse_ast(one_cond[0]) + ":"
359
+ outstring += add_indent("\n" + traverse_ast(one_cond[1]))
360
+ if len(in_node)>4:
361
+ outstring = outstring + "\nelse:"
362
+ false_bit = traverse_ast(in_node[4])
363
+ outstring = outstring + add_indent("\n"+false_bit) #indent
364
+ special_info["inif"] = old_inif
365
+ return outstring
366
+
367
+ # dREL for statements include the final value, whereas a python range will include
368
+ # everything up to the final number
369
+ elif node_type == "DO": #DO ID = start, finish, incr, suite
370
+ outstring = "for " + in_node[1] + " in range(" + traverse_ast(in_node[2]) + ","
371
+ finish = traverse_ast(in_node[3])
372
+ increment = traverse_ast(in_node[4])
373
+ outstring = outstring + finish + "+1" + "," + increment
374
+ outstring = outstring + "):"
375
+ suite = add_indent("\n"+traverse_ast(in_node[5]))
376
+ return outstring + suite
377
+ elif node_type == "FOR": # FOR target_list expression_list suite
378
+ outstring = "for "
379
+ for express in in_node[1]:
380
+ outstring = outstring + traverse_ast(express) + ","
381
+ outstring = outstring[:-1] + " in "
382
+ special_info["rhs"] = True
383
+ for target in in_node[2]:
384
+ outstring += "copy("+traverse_ast(target) + "),"
385
+ special_info["rhs"] = None
386
+ outstring = outstring[:-1] + ":" + add_indent("\n" + traverse_ast(in_node[3]))
387
+ return outstring
388
+ elif node_type == "REPEAT": #REPEAT suite
389
+ outstring = "while True:" + add_indent("\n" + traverse_ast(in_node[1]))
390
+ return outstring
391
+ elif node_type == "WITH": #new_id old_id suite
392
+ # each entry in special_id is [alias:[cat_name,loop variable, is_loop]]
393
+ alias_id = in_node[1]
394
+ cat_id = in_node[2]
395
+ is_already_there = [a for a in special_info['special_id'][-1].keys() if \
396
+ special_info['special_id'][-1][a][0] == cat_id]
397
+ if len(is_already_there)>0:
398
+ del special_info['special_id'][-1][is_already_there[0]]
399
+ print("Found explicit loop category alias: %s for %s" % (alias_id,cat_id) )
400
+ special_info['special_id'][-1].update({alias_id:[cat_id,"",False]})
401
+ if in_node[2] in special_info['loopable_cats'].keys(): #flag this
402
+ special_info['special_id'][-1][alias_id][1] = "looped_cat"
403
+ outstring = traverse_ast(in_node[3])
404
+ return outstring
405
+
406
+ elif node_type == "LOOP": #ALIAS CAT LOOPVAR COMP COMPVAR SUITE
407
+ alias_id = in_node[1]
408
+ cat_id = in_node[2]
409
+ var_info = [cat_id,"",False]
410
+ if cat_id not in special_info['loopable_cats'].keys():
411
+ message = "%s is not a loopable category (must be one of:\n%s)" % (cat_id,special_info['loopable_cats'].keys())
412
+ print(message)
413
+ raise CifError(message)
414
+ #loop over some index
415
+ loop_num = len(special_info['special_id'][-1])+1
416
+ if in_node[3] == "": # provide our own
417
+ loop_index = "__pi%d" % loop_num
418
+ else:
419
+ loop_index = in_node[3]
420
+ var_info[1] = loop_index
421
+ var_info[2] = True
422
+ special_info['special_id'][-1].update({alias_id:var_info})
423
+ # now emit some text: first to find the length of the category
424
+ # loopable cats contains a list of names defined for the category
425
+ # this might not be robust as we ignore alternative resolutions of the (cat,name) pair
426
+ catnames = set([a[1][0] for a in cif_dic.cat_obj_lookup_table.items() if a[0][0]==cat_id.lower()])
427
+ outstring = "__pyallitems = " + repr(catnames)
428
+ outstring += "\nprint('names in cat = %s' % repr(__pyallitems))"
429
+ outstring += "\n" + "__pycitems = [a for a in __pyallitems if %s]" % (api_table["has_name"] % "a")
430
+ outstring += "\nprint('names in cat -> %s' % repr(__pycitems))\n"
431
+ cat_key = cif_dic[cat_id]['_category_key.name'][0] #take official key
432
+ # If there is nothing in the category, provoke category creation by evaluating the key
433
+ outstring += "if len(__pycitems)==0:\n"
434
+ outstring += " __pydummy = %s\n" % (api_table["data_access"] % repr(cat_key))
435
+ outstring += " __pycitems = [a for a in __pyallitems if %s]\n" % (api_table["has_name"] % "a")
436
+ outstring += " print('After category creation, names in cat ->' + repr(__pycitems))\n"
437
+ special_info["depends"].add(cat_key) #add key as a dependency
438
+ if var_info[2] == True:
439
+ access_string = api_table["count_data"] % (api_table["data_access"] % "__pycitems[0]")
440
+ outstring += "\n" + "__loop_range%d = range(%s)" % (loop_num,access_string)
441
+ else:
442
+ outstring += "\n" + "__loop_range%d = [0]" % loop_num
443
+ #outstring +="\n" + "for __noloop in [0]:"
444
+ # deal with this comparison test
445
+ if in_node[4] != "":
446
+ outstring += "\n" + "__loop_range%d = [a for a in __loop_range%d if a %s %s]" % (loop_num,loop_num,in_node[4],in_node[5])
447
+ # now output the looping command
448
+ outstring += "\n" + "for %s in __loop_range%d:" % (loop_index,loop_num)
449
+ # now the actual body of the loop
450
+ loop_body = traverse_ast(in_node[6])
451
+ outstring = outstring + add_indent("\n"+loop_body)
452
+ return outstring
453
+
454
+ elif node_type == "FUNCTION": #FUNCTION ID ARGLIST SUITE
455
+ func_name = in_node[1]
456
+ outstring = "def %s (" % func_name
457
+ for one_arg in in_node[2]:
458
+ outstring += one_arg[0] + ","
459
+ outstring = outstring + "ciffile):"
460
+ # imports
461
+ #import_lines = "import numpy\nfrom emapsCifFile.drel import drel_runtime\n"
462
+ import_lines = ""
463
+ outstring = outstring + add_indent("\n" + import_lines + traverse_ast(in_node[3])+"\nreturn %s" % func_name)
464
+ return outstring
465
+
466
+
467
+ elif node_type == "STATEMENTS":
468
+ outstring = ""
469
+ for one_statement in in_node[1]:
470
+ # try:
471
+ next_bit = traverse_ast(one_statement)
472
+ if not isinstance(next_bit,(unicode,str)):
473
+ print("Unable to traverse AST for %s" % one_statement[0])
474
+ else:
475
+ outstring = outstring + next_bit + "\n"
476
+ # except SyntaxError as message:
477
+ # print("Failed, so far have \n " + outstring)
478
+ # outstring += "raise SyntaxError, %s" % message
479
+ # except:
480
+ # print("Failed, so far have \n " + outstring)
481
+ # outstring += "raise SyntaxError, %s" % `one_statement`
482
+ return outstring
483
+ elif node_type == "ASSIGN": #Target_list ,assigner, expression list
484
+ outstring = ""
485
+ lhs_values = []
486
+ special_info["rhs"] = False
487
+ for target_value in in_node[1]:
488
+ one_value = traverse_ast(target_value)
489
+ outstring = outstring + one_value +","
490
+ lhs_values.append(one_value)
491
+ lhs = outstring[:-1]
492
+ rhs = ""
493
+ special_info["rhs"] = True
494
+ for order,expression in enumerate(in_node[3]):
495
+ rhs += traverse_ast(expression)+","
496
+ if special_info["sub_subject"] != "": #a full packet
497
+ special_info["packet_vars"].update({lhs_values[order]:special_info["sub_subject"]})
498
+ special_info["sub_subject"] = ""
499
+ # we cannot expand a numpy array, hence the workaround here
500
+ #if in_node[2] == "++=":
501
+ # outstring = "_temp1 = %s;%s = %s(_temp1,%s)" % (lhs,lhs,aug_assign_table["++="],rhs[:-1])
502
+ if in_node[2] != "=":
503
+ outstring = "%s = %s(%s,%s)" % (lhs, aug_assign_table[in_node[2]],lhs,rhs[:-1])
504
+ else:
505
+ outstring = "%s = %s" % (lhs,rhs[:-1])
506
+ special_info["rhs"] = None
507
+ return outstring
508
+ elif node_type == "FANCY_ASSIGN": # [1] is cat name, [2] is list of objects
509
+ catname = in_node[1]
510
+ outstring = ""
511
+ special_info["rhs"] = True
512
+ for obj,value in in_node[2]:
513
+ real_id = cif_dic.get_name_by_cat_obj(catname, obj)
514
+ newvalue = traverse_ast(value)
515
+ outstring = outstring + "__dreltarget.update({'%s':__dreltarget.get('%s',[])+[%s]})\n" % (real_id,real_id,newvalue)
516
+ special_info["rhs"] = None
517
+ return outstring
518
+
519
+ elif node_type == "LIST":
520
+ outstring = "["
521
+ for one_element in in_node[1]:
522
+ outstring = outstring + traverse_ast(one_element) + ","
523
+ return outstring + "]"
524
+ elif node_type == "EXPR":
525
+ return traverse_ast(in_node[1])
526
+ # Expr list occurs only when a non-assignment statement appears as expr_stmt
527
+ elif node_type == "EXPRLIST":
528
+ outstring = ""
529
+ for one_expr in in_node[1]:
530
+ outstring += traverse_ast(one_expr) + "\n"
531
+ return outstring
532
+ elif node_type == "GROUP":
533
+ outstring = "("
534
+ for expression in in_node[1]:
535
+ outstring = outstring + traverse_ast(expression) + ","
536
+ return outstring[:-1] + ")"
537
+ elif node_type == "PRINT":
538
+ return 'print( ' + traverse_ast(in_node[1]) + ")"
539
+ elif node_type == "BREAK":
540
+ return 'break '
541
+ elif node_type == "NEXT":
542
+ return 'continue '
543
+
544
+ else:
545
+ return "Not found: %s" % repr(in_node)
546
+ result = traverse_ast(in_node)
547
+ # remove target id from dependencies
548
+ if special_info["target_id"] is not None:
549
+ special_info["depends"].discard(special_info["target_id"].lower())
550
+ if not special_info.get("have_drel_target",False):
551
+ print('WARNING: no assignment to __dreltarget in %s (this is OK for category methods)' % repr(target_id))
552
+ print(result)
553
+ return result,special_info["withtable"],special_info["depends"],special_info["need_current_row"]
554
+
555
+ def get_function_name(in_name):
556
+ """Return the Python name of the dREL function, an argument prefix,
557
+ and anything to be appended to the end"""
558
+ builtins = {"table":"dict",
559
+ "list":"list",
560
+ "array":"numpy.array",
561
+ "len":"len",
562
+ "abs":"abs",
563
+ "magn":"abs",
564
+ "atoi":"int",
565
+ "float":"float",
566
+ "str":"str",
567
+ "array":"numpy.array",
568
+ "norm":"numpy.linalg.norm",
569
+ "sqrt":"math.sqrt",
570
+ "exp":"math.exp",
571
+ "complex":"complex",
572
+ "max":"max",
573
+ "min":"min",
574
+ "strip":"drel_runtime.drel_strip",
575
+ "int":"drel_runtime.drel_int",
576
+ "eigen":"drel_runtime.drel_eigen",
577
+ "hash":"hash" #dREL extension
578
+ }
579
+ test_name = in_name.lower()
580
+ target_name = builtins.get(test_name,None)
581
+ if target_name is not None:
582
+ return target_name,"",""
583
+ if test_name in ['sind','cosd','tand']:
584
+ return "math."+test_name[:-1],"math.radians(",")"
585
+ if test_name in ['acosd','asind','atand','atan2d']:
586
+ return "math.degrees(math."+test_name[:-1],"",")"
587
+ if test_name == "mod":
588
+ return "divmod","","[1]"
589
+ if test_name == "upper":
590
+ return "","",".upper()"
591
+ if test_name == "transpose":
592
+ return "","",".T"
593
+ if test_name == 'expimag':
594
+ return "cmath.exp","1j*(",")"
595
+ if test_name in ['real','imag']:
596
+ return "","","." + test_name
597
+ if test_name == 'matrix':
598
+ return "numpy.matrix","",".astype('float64')"
599
+ if test_name == 'sort':
600
+ return "","",".sort()"
601
+ return in_name,"",None #dictionary defined
602
+
603
+ def fix_mathops(op,first_arg,second_arg):
604
+ """Return a string that will carry out the requested operation"""
605
+ if op == "^":
606
+ return "numpy.cross(%s,%s)" % (first_arg,second_arg)
607
+ elif op == "*": #could be matrix multiplication
608
+ return "drel_runtime.drel_dot(%s,%s)" % (first_arg,second_arg)
609
+ elif op == "+":
610
+ return "drel_runtime.drel_add(%s,%s)" % (first_arg, second_arg)
611
+ elif op == "-":
612
+ return "numpy.subtract(%s,%s)" % (first_arg, second_arg)
613
+ # beware integer division on this one...
614
+ elif op == "/":
615
+ return "numpy.true_divide(%s,%s)" % (first_arg, second_arg)
616
+
617
+ def add_indent(text,n=4):
618
+ """Indent text by n spaces"""
619
+ return re.sub("\n","\n"+4*" ",text)
620
+
621
+ def getcatname(dataname):
622
+ """Return cat,name pair from dataname"""
623
+ try:
624
+ cat,name = dataname.split(".")
625
+ except ValueError: #no period in name
626
+ return cat,None
627
+ return cat[1:],name
628
+