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