-
Notifications
You must be signed in to change notification settings - Fork 0
/
block_diagram_xml.py
226 lines (176 loc) · 7.98 KB
/
block_diagram_xml.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
import xml.etree.ElementTree as ET
from xml.dom import minidom
import pdb
import xml_utils
from xml_utils import prettify
import copy
from IPython.core.debugger import Pdb
## element_params = {'dc_motor':['g','p','dt'], \
## 'torsional_spring_damper':['k','c'], \
## 'rigid_mass':['M','L','R','I'], \
## 'beam':['mu','L','EI','t','N'], \
## }
## sorted_elements = sorted(element_params.iterkeys())
#print('sorted_elements = %s' % sorted_elements)
class bd_XML_element(xml_utils.xml_writer):
def __init__(self, name=None, blocktype=None, params={}, \
pullist=['input','input2']):
"""pullist refers to a list of parameters that will be pulled
from params before converting the xml representation to an
actual elememt. For the DT-TMM blocks, input was pulled to
process later. I am not sure if there are any params to pull
for block diagram objects.
pulling input and input2 from params messes with
block_diagram_gui.py, but not having self.input and
self.input2 defined seems to mess up parse_bd_xml_system. I
am going to try and make both happy by copying rather than
popping from params.
"""
if not bool(name) and bool(blocktype) and bool(params):
print('all inputs must be non-empty:')
print('name: %s' % name)
print('blocktype: %s' % blocktype)
print('params: %s' % params)
raise(ValueError, "problems with non-empty inputs")
self.name = name
self.blocktype = blocktype
self.params = params
self.pullist = pullist
#assert len(pullist) == 0, "pullist is not actually implemented yet"
self.xml_attrs = ['name','blocktype'] + pullist#?how to handle params?
self.xml_tag_name = 'block'
for key in pullist:
if self.params.has_key(key):
val = self.params[key]
setattr(self, key, val)
def set_params_as_attrs(self):
for key, val in self.params.iteritems():
val = xml_utils.full_clean(val)
val = xml_utils.try_string_to_number(val)
setattr(self, key, val)
def create_xml(self, root):
my_elem = xml_utils.xml_writer.create_xml(self, root)
params_xml = ET.SubElement(my_elem, 'params')
for attr, val in self.params.iteritems():
cur_xml = ET.SubElement(params_xml, attr)
try:
cur_xml.text = val.encode()
except:
cur_xml.text = str(val)
def cleanup_params(self):
clean_params = copy.copy(self.params)
for attr in self.pullist:
if clean_params.has_key(attr):
val = clean_params.pop(attr)
setattr(self, attr, val)
#attempt converting params to float
clean2 = {}
for key, val in clean_params.iteritems():
try:
val_out = float(val)
except:
val_out = val
if val_out == 'None':
val_out = None
clean2[key] = val_out
self.clean_params = clean2
def get_num_outputs(self):
num_outputs = -1
if self.params.has_key('sensors'):
sensors = self.params['sensors']
if type(sensors) in [str, unicode]:
if type(sensors) == unicode:
sensors = sensors.encode()
sensors = xml_utils.full_clean(sensors)
assert type(sensors) in [list, tuple], "Problem with the type of sensors: " + str(type(sensors))
num_outputs = len(sensors)
return num_outputs
elif self.params.has_key('output_angles'):
out_angles = self.params['output_angles']
if type(out_angles) == str:
out_angles = xml_utils.full_clean(out_angles)
num_outputs = len(out_angles)
return num_outputs
#I don't know what to do if that didn't work
return 1
class block_diagram_system_parser(xml_utils.xml_parser):
def get_blocks(self):
self.block_xml_list = xml_utils.find_child_if_it_exists(self.root, \
'blocks')
def parse(self):
"""Parse the block diagram system"""
assert self.root.tag == 'block_diagram_system', \
"This does not appear to be a valid block_diagram_system_parser xml file"
self.get_blocks()
block_parsers = []
for block_xml in self.block_xml_list:
cur_parser = block_parser(filename=None)
cur_parser.set_root(block_xml)
cur_parser.parse()
block_parsers.append(cur_parser)
self.block_parsers = block_parsers
return self.block_parsers
def convert(self):
block_list = []
for block_parser in self.block_parsers:
cur_inst = block_parser.convert()
block_list.append(cur_inst)
self.block_list = block_list
return block_list
class block_parser(xml_utils.xml_parser):
def validate_and_get_body(self):
"""I don't know if I would ever really try to pass in an xml
file that contains a single block, but this is what I did for
individual figures and full GUI state xml files in
data_vis_gui"""
if self.root.tag == 'block':
body = self.root
return body
elif self.root.tag == 'blocks':
children = self.root.getchildren()
#a figure file should have one child that is either a
#bode_figure or a time_domain_figure
assert len(children) == 1, "problem with the children in my xml file"
body = children[0]
return body
else:
raise(ValueError, "Not sure how to proceed for a figure with tag %s" % self.root.tag)
def parse(self):
"""convert the XML associated with self to a list something
ready to be converted to a bd_XML_element instance"""
body = self.validate_and_get_body()
self.name = xml_utils.get_child_value(body, 'name')
self.blocktype = xml_utils.get_child_value(body, 'blocktype')
self.params = xml_utils.get_params(body)
def convert(self):
"""convert the list of parse dictionaries in
:py:attr:`self.parsed_dicts to :py:class:`plot_description`
instances and then also create and return a :py:class:`figure`
instance"""
bd_instance = bd_XML_element(name=self.name, \
blocktype=self.blocktype, \
params=self.params)
return bd_instance
## class sensor_XML_element(object):
## def __init__(self, name=None, sensor_type=None, signal=None, \
## elem1=None, elem2=None):
## """name is the name of the sensor; sensor_type is either abs or diff;
## signal should be one of x, xdot, xddot, theta, thetadot,
## thetaddot, V or M; elem1 is the only element used for sensor_type
## abs; if sensor_type is diff, the sensor signal will be calculated
## from elem1-elem2"""
## if not bool(name) and bool(sensor_type) and bool(signal) \
## and bool(elem1):
## print('only elem2 is optional; all other inputs must be non-empty:')
## print('name: %s' % name)
## print('sensor_type: %s' % sensor_type)
## print('signal: %s' % signal)
## print('elem1: %s' % elem1)
## raise ValueError, "problems with non-empty inputs"
## if sensor_type == 'diff' and not bool(elem2):
## raise ValueError, "if sensor sensor_type is diff, elem2 must not be empty"
## self.name = name
## self.sensor_type = sensor_type
## self.signal = signal
## self.elem1 = elem1
## self.elem2 = elem2