DM_attribute_handling.py
1 ## @package python.demo.DM_attribute_handling
2 #
3 # managing attributes using addinfo layouts and views
4 # (script works in python 2 and 3)
5 #
6 from __future__ import print_function # print function syntax as in python 3
7 import sys
8 
9 from opals import pyDM
10 
11 typeNames = {
12  pyDM.ColumnType.bool_: "bit(boolean)",
13  pyDM.ColumnType.int8: "int8",
14  pyDM.ColumnType.uint8: "uint8",
15  pyDM.ColumnType.int16: "int16",
16  pyDM.ColumnType.uint16: "uint16",
17  pyDM.ColumnType.int32: "int32",
18  pyDM.ColumnType.uint32: "uint32",
19  pyDM.ColumnType.int64: "int64",
20  pyDM.ColumnType.float_: "float",
21  pyDM.ColumnType.double_: "double",
22  pyDM.ColumnType.string: "string",
23  pyDM.ColumnType.cstr: "cstr"
24  }
25 
26 
27 def output_layout(layout):
28  for i in range(layout.columns()):
29  print("\t" + layout.name(i) + " (type = " + typeNames[layout.type(i)] + ")")
30 
31 
32 def DM_attribute_handling(filename):
33  # create a point without attributes
34  pt1 = pyDM.Point()
35  assert pt1.hasInfo() == False # point has no attributes (addinfo object)
36 
37  # =================================================================================================================
38  # now create layouts for the addinfo object
39  f = pyDM.AddInfoLayoutFactory()
40  f.addColumn(pyDM.ColumnSemantic.Amplitude) # pre-defined attribute "Amplitude"
41  f.addColumn(pyDM.ColumnSemantic.EchoWidth) # pre-defined attribute "EchoWidth"
42  f.addColumn(pyDM.ColumnType.uint32, "_testAttr") # user-defined attribute "_testAttr" (type unsigned int)
43  layout1 = f.getLayout()
44 
45  f.addColumn(pyDM.ColumnType.uint32, "_testAttr") # user-defined attribute "_testAttr" (type unsigned int)
46  layout2 = f.getLayout()
47 
48  print("Layout 1:")
49  output_layout(layout1)
50 
51  print("Layout 2:")
52  output_layout(layout2)
53 
54  # create a point with 3 attribut columns
55  pt2 = pyDM.Point(layout1)
56  assert pt2.hasInfo() == True # point has an attributes
57  assert pt2.info().columns() == 3 # point has 3 attribute columns
58 
59  # cloning a point DOES NOT clone the attribute (AddInfo) object!
60  pt3 = pt2.clone()
61  assert pt2.info().isNull(0) == True and pt3.info().isNull(0) == True # attribute 0 (Amplitude) is not set yet
62  assert pt2.getAddInfo() == pt3.getAddInfo() # attribute object is the same for pt2 and pt3
63 
64  pt2.info().set(0, 10.23) # setting attribute value
65  amp = pt3.info().get(0)
66  assert pt2.info().get(0) == pt3.info().get(
67  0) # since both point use the same AddInfo object the attribute has to be same
68 
69  # to create a separate attribute object for each point, it is necessary clone it explicitly
70  pt4 = pt2.clone()
71  pt4.setAddInfo(pt2.info().clone()) # clone the attribute object
72  assert pt2.getAddInfo() != pt4.getAddInfo() # p2 and p4 have different attribute objects
73 
74  pt2.info().set(0, 5.92) # change attribute 0 of p2
75  assert abs(pt2.info().get(0) - 5.92) < 1e-5 and abs(pt4.info().get(0) - 10.23) < 1e-5
76 
77  # =================================================================================================================
78  # using views only the attributes of interest are visible
79  # since we want to access "_testAttr" only, we can apply a view (layout2)
80  assert pt2.info().isView() == False
81  pt2.setAddInfoView(layout2, True)
82 
83  assert pt2.info().isView() == True
84  assert layout2.columns() == 1 and pt2.info().columns() == 1
85 
86  pt2.info().set(0, 15) # set _testAttr to 15
87 
88  # since pt2 and pt3 point to the same attribute object the view is also applied to pt3
89  assert pt3.info().columns() == 1 and pt3.info().get(0) == 15
90 
91  # the view can be removed as well
92  pt2.restoreAddInfoFullLayout()
93  assert pt2.info().isView() == False and pt2.info().columns() == 3
94 
95  value = pt3.info().get(2) # in the real layout "_testAttr" is at index 2
96  assert value == 15
97 
98  # it is also possible to create a cloned view object, which still points to the same data object, but a new
99  # attribute object is created. this allows to create multiple views on the same attribute data object
100  pt3.cloneAddInfoView(layout2, True)
101 
102  assert pt2.getAddInfo() != pt3.getAddInfo()
103  pt3.info().set(0, 35)
104  value = pt2.info().get(2)
105  assert pt2.info().get(2) == 35 and pt3.info().get(0) == 35
106 
107  # =================================================================================================================
108  # simplified way to access attributes within an ODM by
109  # list of given attribute names
110  attributs = ["Amplitude", "EchoWidth", "_testAttr"]
111 
112  # open the odm / pyDM.Datamanager.load parameters: filename(string), readOnly(bool) threadSafety(bool)
113  dm = pyDM.Datamanager.load(filename, True, False)
114 
115  # if the dm wasn't opened successfully exit function
116  if not dm:
117  print("Unable to open ODM '" + filename + "'")
118  return
119 
120  print("Create layout based on ODM '" + filename + "'")
121  for attr in attributs:
122  type, inDM = f.addColumn(dm, attr, True, pyDM.ColumnType.uint32)
123  if inDM:
124  print("\t" + attr + " exists in ODM (type = " + typeNames[type] + ")")
125  else:
126  print("\t" + attr + " does NOT exist in ODM (type = " + typeNames[type] + ")")
127  layout3 = f.getLayout()
128 
129  print("layout3 :")
130  output_layout(layout3)
131 
132 
133 if len(sys.argv) == 1:
134  print("ODM parameter missing")
135  sys.exit(-1)
136 
137 DM_attribute_handling(sys.argv[1])