Mantid
Loading...
Searching...
No Matches
generate_mdevent_declarations.py
Go to the documentation of this file.
1# Mantid Repository : https://github.com/mantidproject/mantid
2#
3# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4# NScD Oak Ridge National Laboratory, European Spallation Source,
5# Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6# SPDX - License - Identifier: GPL - 3.0 +
7""" Simple script that generates references to all
8needed MDEvent<X>/MDLeanEvent<X> instantiations. """
9import os
10import datetime
11import re
12
13# List of every possible MDEvent or MDLeanEvent types.
14mdevent_types = ["MDLeanEvent", "MDEvent"]
15
16header = """/* Code below Auto-generated by '%s'
17 * on %s
18 *
19 * DO NOT EDIT!
20 */
21""" % (
22 os.path.basename(__file__),
23 datetime.datetime.now(),
24)
25
26footer = """
27/* CODE ABOWE WAS AUTO-GENERATED BY %s - DO NOT EDIT! */
28""" % (
29 os.path.basename(__file__)
30)
31
32
33def build_macro(padding, min_dimension=1, max_dimensions=4, const=""):
34 """Return the macro code CALL_MDEVENT_FUNCTION
35 Parameter:
36 min_dimension :: to avoid compiler warnings, limit to dimensions higher than this
37 mad_dimension :: by default, maximal numner of dimesnions to be generated
38 const :: set to "const " to make a const equivalent
39 """
40 # for the calling function macro
41 macro_top = """
42/** Macro that makes it possible to call a templated method for
43 * a MDEventWorkspace using a IMDEventWorkspace_sptr as the input.
44 *
45 * @param funcname :: name of the function that will be called.
46 * @param workspace :: IMDEventWorkspace_sptr input workspace.
47*/
48
49#define %sCALL_MDEVENT_FUNCTION%s(funcname, workspace) \\
50{ \\
51"""
52
53 macro = """%s%sMDEventWorkspace<%s, %d>::sptr %s = std::dynamic_pointer_cast<%sMDEventWorkspace<%s, %d> >(workspace); \\
54if (%s) funcname<%s, %d>(%s); \\
55 """
56
57 suffix = ""
58 prefix = ""
59 if min_dimension > 1:
60 suffix = "%d" % min_dimension
61 if const != "":
62 prefix = "CONST_"
63 s = macro_top % (prefix, suffix)
64
65 for mdevent_type in mdevent_types:
66 for nd in xrange(1, max_dimensions + 1):
67 if nd >= min_dimension:
68 eventType = "%s<%d>" % (mdevent_type, nd)
69 varname = "MDEW_%s_%d" % (mdevent_type.upper(), nd)
70 if const != "":
71 varname = "CONST_" + varname
72 s += macro % (padding, const, eventType, nd, varname, const, eventType, nd, varname, eventType, nd, varname)
73 s += "} \n \n \n"
74
75 return s.split("\n")
76
77
78def get_padding(line):
79 """Return a string with the spaces padding the start of the given line."""
80 out = ""
81 for c in line:
82 if c == " ":
83 out += " "
84 else:
85 break
86 return out
87
88
89def find_line_number(lines, pattern, startat=0):
90 """Look line-by-line in lines[] for a line that starts with pattern. Return
91 the line number in source where the line was found, and the padding (in spaces) before it"""
92 searcher = re.compile(pattern)
93 for n in xrange(startat, len(lines)):
94 found = searcher.search(lines[n])
95 if found:
96 # How much padding?
97 padding = get_padding(lines[n])
98 return (n, padding)
99
100 return (None, None)
101
102
103def find_num_dim(lines):
104 """Look up through header file and the string which identifies how many dimensions have to be instantiated"""
105 searcher = re.compile(r"(?<=MAX_MD_DIMENSIONS_NUM)(\s*\=\s*)\d+")
106 for i in xrange(len(lines)):
107 found = searcher.search(lines[i])
108 if found:
109 rez = found.group()
110 return re.search(r"\d", rez).group()
111
112 raise IOError("can not find the string which defines the number of dimensions to process")
113
114
115def parse_file(file_name, start_marker, end_marker):
116 """Read the file and separate it into three parts with the part between input markers to be generated and two others left unchanged.
117
118 @param -- file_name -- full file name to open
119 @param -- start_marker -- the marker which indicate first line of autogenerated file
120 @param -- end_marger -- the margker which indicate last line of autogenerated file
121
122 @return padding -- the number of spaces to insert in front of autogenerated lines
123 @return lines_before -- list of lines before autogenerated one (including start_marker)
124 @return lines_after -- list of lines after autogenerated one (including end_marker)
125 """
126 # First, open the header and read all the lines
127 f = open(file_name, "r")
128 s = f.read()
129
130 lines = s.split("\n")
131 (n1, padding) = find_line_number(lines, start_marker, startat=0)
132 (n2, padding_ignored) = find_line_number(lines, end_marker, startat=n1)
133
134 print("Lines for autogenerated code: ", n1, n2)
135 if n1 is None or n2 is None:
136 raise Exception("Could not find the marker in the " + file_name + " file.")
137
138 lines_before = lines[: n1 + 1]
139 lines_after = lines[n2:]
140 f.close()
141
142 return (padding, lines_before, lines_after)
143
144
146 print("Generating MDEventFactory")
147
148 # Classes that have a .cpp file (and will get an Include line)
149 classes_cpp = ["MDBoxBase", "MDBox", "MDEventWorkspace", "MDGridBox", "MDBin", "MDBoxIterator"]
150
151 padding, lines, lines_after = parse_file(
152 "../inc/MantidDataObjects/MDEventFactory.h", "//### BEGIN AUTO-GENERATED CODE", "//### END AUTO-GENERATED CODE"
153 )
154
155 nDim = int(find_num_dim(lines))
156 print(" numDimensions to be generated: ", nDim)
157 # List of the dimensions to instantiate
158 dimensions = range(1, nDim + 1)
159
160 header_lines = map(lambda x: padding + x, header.split("\n"))
161 footer_lines = map(lambda x: padding + x, footer.split("\n"))
162
163 lines += header_lines
164
165 macro_lines = build_macro(padding, 1, nDim) + build_macro(padding, 3, nDim) + build_macro(padding, 1, nDim, "const ")
166
167 lines += macro_lines
168
169 lines.append("\n")
170 classes = ["MDBox", "MDBoxBase", "MDGridBox", "MDEventWorkspace", "MDBin"]
171 for c in classes:
172 lines.append("\n%s// ------------- Typedefs for %s ------------------\n" % (padding, c))
173 mdevent_type = "MDLeanEvent"
174 for nd in dimensions:
175 lines.append("%s/// Typedef for a %s with %d dimension%s " % (padding, c, nd, ["", "s"][nd > 1]))
176 lines.append("%s typedef %s<%s<%d>, %d> %s%dLean;" % (padding, c, mdevent_type, nd, nd, c, nd))
177 mdevent_type = "MDEvent"
178 for nd in dimensions:
179 lines.append("%s/// Typedef for a %s with %d dimension%s " % (padding, c, nd, ["", "s"][nd > 1]))
180 lines.append("%stypedef %s<%s<%d>, %d> %s%d;" % (padding, c, mdevent_type, nd, nd, c, nd))
181
182 lines.append("\n")
183
184 lines += footer_lines + lines_after
185
186 f = open("../inc/MantidDataObjects/MDEventFactory.h", "w")
187 for line in lines:
188 f.write(line + "\n")
189 f.close()
190
191 padding, lines, lines_after = parse_file("./MDEventFactory.cpp", "//### BEGIN AUTO-GENERATED CODE", "//### END AUTO-GENERATED CODE")
192
193 header_lines = map(lambda x: padding + x, header.split("\n"))
194 footer_lines = map(lambda x: padding + x, footer.split("\n"))
195
196 lines += header_lines
197
198
199 for c in mdevent_types:
200 lines.append("%s// Instantiations for %s" % (padding, c))
201 for nd in dimensions:
202 lines.append("%s template class DLLExport %s<%d>;" % (padding, c, nd))
203
204 # Classes with MDLeanEvent<x>,x
205 for c in classes_cpp:
206 lines.append("%s// Instantiations for %s" % (padding, c))
207 for mdevent_type in mdevent_types:
208 for nd in dimensions:
209 lines.append("%s template class DLLExport %s<%s<%d>, %d>;" % (padding, c, mdevent_type, nd, nd))
210 lines.append("\n ")
211
212 lines += footer_lines + lines_after
213 f = open("./MDEventFactory.cpp", "w")
214 for line in lines:
215 f.write(line + "\n")
216 f.close()
217
218 # Post message about updating the id strings in the python layer to
219 # understand the new structure
220 print("")
221 print("The available IDs on the templated MDEventWorkspace classes may have changed.")
222 print("Please update the casting IDs in PythonInterface/mantid/api/IMDEventWorkspace accordingly")
223
224
225if __name__ == "__main__":
226 generate()
def find_line_number(lines, pattern, startat=0)
def parse_file(file_name, start_marker, end_marker)
def build_macro(padding, min_dimension=1, max_dimensions=4, const="")