/
test_Simulation.py
180 lines (146 loc) · 5.86 KB
/
test_Simulation.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
import unittest
import jsbsim
import multiprocessing
import time
from simulation import Simulation
class TestSimulation(unittest.TestCase):
sim: Simulation = None
def setUp(self):
if self.sim:
self.sim.close()
self.sim = Simulation()
def tearDown(self):
self.sim = None
def test_init_jsbsim(self):
self.assertIsInstance(self.sim.sim, jsbsim.FGFDMExec,
msg=f'Expected Simulation.sim to hold an '
'instance of JSBSim.')
def test_load_model(self):
# make fresh sim instance with "X15" plane
model_name = 'X15'
self.sim = None
self.sim = Simulation(aircraft_model_name=model_name)
actual_name = self.sim.get_model_name()
self.assertEqual(model_name, actual_name,
msg=f'Unexpected aircraft model name after loading.')
def test_load_bad_aircraft_name(self):
bad_name = 'qwertyuiop'
with self.assertRaises(RuntimeError):
self.sim = None
self.sim = Simulation(aircraft_model_name=bad_name)
def test_get_property(self):
self.setUp()
# we expect certain values specified in the IC config XML file
expected_values = {
'ic/u-fps': 328.0,
'ic/v-fps': 0.0,
'ic/w-fps': 0.0,
'velocities/u-fps': 328.0,
'velocities/v-fps': 0.0,
'velocities/w-fps': 0.0,
}
for prop, expected in expected_values.items():
actual = self.sim[prop]
self.assertAlmostEqual(expected, actual)
def test_get_bad_property(self):
self.setUp()
bad_prop = 'bad'
with self.assertRaises(KeyError):
_ = self.sim[bad_prop]
def test_set_property(self):
self.setUp()
set_values = {
'ic/u-fps': 200.0,
'ic/v-fps': 5.0,
'ic/w-fps': 5,
'position/h-sl-meters': 1000,
'fcs/aileron-cmd-norm': 0.2,
'fcs/elevator-cmd-norm': 0.2,
'fcs/rudder-cmd-norm': 0.2,
'fcs/throttle-cmd-norm': 0.2,
}
for prop, value in set_values.items():
self.sim[prop] = value
for prop, expected in set_values.items():
actual = self.sim[prop]
self.assertAlmostEqual(expected, actual)
def test_initialise_conditions_basic_config(self):
aircraft = '737'
# manually reset JSBSim instance with new initial conditions
if self.sim:
self.sim.close()
self.sim = Simulation(sim_dt=0.5, aircraft_model_name=aircraft, init_conditions=None)
self.assertEqual(self.sim.get_model_name(), aircraft,
msg='JSBSim did not load expected aircraft model: ' +
self.sim.get_model_name())
# check that properties are as we expected them to be
expected_values = {
'ic/u-fps': 328.0,
'ic/v-fps': 0.0,
'ic/w-fps': 0.0,
'velocities/u-fps': 328.0,
'velocities/v-fps': 0.0,
'velocities/w-fps': 0.0,
'simulation/dt': 0.5
}
for prop, expected in expected_values.items():
actual = self.sim[prop]
self.assertAlmostEqual(expected, actual)
def test_initialise_conditions_custom_config(self):
""" Test JSBSimInstance initialisation with custom initial conditions. """
aircraft = 'f15'
init_conditions = {
'ic/u-fps': 1000.0,
'ic/v-fps': 0.0,
'ic/w-fps': 1.0,
'ic/h-sl-ft': 5000,
'ic/phi-deg': 12,
'ic/theta-deg': -5,
'ic/psi-true-deg': 45,
}
# map JSBSim initial condition properties to sim properties
init_to_sim_conditions = {
'ic/u-fps': 'velocities/u-fps',
'ic/v-fps': 'velocities/v-fps',
'ic/w-fps': 'velocities/w-fps',
'ic/h-sl-ft': 'position/h-sl-ft',
'ic/phi-deg': 'attitude/phi-deg',
'ic/theta-deg': 'attitude/theta-deg',
'ic/psi-true-deg': 'attitude/psi-deg',
}
dt = 0.1
# manually reset JSBSim instance
if self.sim:
self.sim.close()
self.sim = Simulation(dt, aircraft, init_conditions)
# check JSBSim initial condition and simulation properties
for init_prop, expected in init_conditions.items():
sim_prop = init_to_sim_conditions[init_prop]
init_actual = self.sim[init_prop]
sim_actual = self.sim[sim_prop]
self.assertAlmostEqual(expected, init_actual,
msg=f'wrong value for property {init_prop}')
self.assertAlmostEqual(expected, sim_actual,
msg=f'wrong value for property {sim_prop}')
self.assertAlmostEqual(dt, self.sim['simulation/dt'])
def test_multiprocess_simulations(self):
""" JSBSim segfaults when multiple instances are run on one process.
Lets confirm that we can launch multiple processes each with 1 instance.
"""
processes = 4
with multiprocessing.Pool(processes) as pool:
# N.B. basic_task is a top level function that inits JSBSim
future_results = [pool.apply_async(basic_task) for _ in range(processes)]
results = [f.get() for f in future_results]
expected = [0] * processes # each process should return 0
self.assertListEqual(results, expected,
msg="multiprocess execution of JSBSim did not work")
def basic_task():
""" A simple task involving initing a JSBSimInstance to test multiprocessing. """
time.sleep(0.05)
fdm = Simulation(aircraft_model_name='c172x')
fdm.run()
time.sleep(0.05)
return 0
if __name__ == '__main__':
unittest.main()