source: branches/dev-5819/Python/src/tests_jmodelica/test_fmi_2.py @ 13800

Last change on this file since 13800 was 13800, checked in by randersson, 6 weeks ago

#5819 Merged trunk into branch

File size: 44.0 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# Copyright (C) 2010 Modelon AB
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, version 3 of the License.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18"""
19Module containing the tests for the FMI interface.
20"""
21
22import nose
23import os
24import numpy as N
25import sys as S
26import scipy.sparse.csc
27from collections import OrderedDict
28
29from tests_jmodelica import testattr, get_files_path
30from pymodelica.compiler import compile_fmu
31from pyfmi.fmi import FMUModel, FMUException, FMUModelME1, FMUModelCS1, load_fmu, FMUModelCS2, FMUModelME2, PyEventInfo
32import pyfmi.fmi_algorithm_drivers as ad
33from pyfmi.common.core import get_platform_dir
34from pyjmi.log import parse_jmi_log, gather_solves
35from pyfmi.common.io import ResultHandler
36import pyfmi.fmi_util as fmi_util
37import pyfmi.fmi as fmi
38
39path_to_fmus = os.path.join(get_files_path(), 'FMUs')
40path_to_fmus_me1 = os.path.join(path_to_fmus,"ME1.0")
41path_to_fmus_cs1 = os.path.join(path_to_fmus,"CS1.0")
42path_to_mofiles = os.path.join(get_files_path(), 'Modelica')
43
44path_to_fmus_me2 = os.path.join(path_to_fmus,"ME2.0")
45path_to_fmus_cs2 = os.path.join(path_to_fmus,"CS2.0")
46ME2 = 'bouncingBall2_me.fmu'
47CS2 = 'bouncingBall2_cs.fmu'
48ME1 = 'bouncingBall.fmu'
49CS1 = 'bouncingBall.fmu'
50
51class Test_FMUModelBase2:
52    @classmethod
53    def setUpClass(cls):
54        """
55        Sets up the test class.
56        """
57        cls.negAliasFmu = compile_fmu("NegatedAlias",os.path.join(path_to_mofiles,"NegatedAlias.mo"), version=2.0)
58        cls.enumeration4 = compile_fmu("Enumerations.Enumeration4",os.path.join(path_to_mofiles,"Enumerations.mo"), version=2.0)
59        cls.nonlinear8 = compile_fmu("NonLinear.NonLinear8",os.path.join(path_to_mofiles,"NonLinear.mo"), version=2.0)
60        cls.brentEnforce = compile_fmu("TestBrent.Bounds", os.path.join(path_to_mofiles,"TestBrent.mo"), version=2.0)
61   
62    @testattr(stddist_full = True)
63    def test_enforce_bounds_brent(self):
64       
65        model = load_fmu(self.brentEnforce)
66
67        model.set("_enforce_bounds", True)
68        nose.tools.assert_raises(FMUException, model.initialize)
69       
70        model = load_fmu(self.brentEnforce)
71       
72        model.set("_enforce_bounds", False)
73        model.initialize()
74       
75    @testattr(stddist_full = True)
76    def test_brent_failure_message(self):
77       
78        model = load_fmu(Test_FMUModelBase2.nonlinear8)
79       
80        try:
81            model.initialize()
82        except FMUException:
83            pass
84       
85        err_msg = ""
86        for line in model.get_log():
87            if "BrentBracketFailed" in line:
88                err_msg = line
89                break
90       
91        #Check that certain key attributes are in the error message
92        assert "variable" in err_msg
93        assert "min" in err_msg
94        assert "max" in err_msg
95
96    @testattr(stddist_full = True)
97    def test_set_enumeration(self):
98        enumeration_model = load_fmu(Test_FMUModelBase2.enumeration4)
99       
100        assert enumeration_model.get("tsize")[0] == 2
101       
102        enumeration_model.set("tsize", "small")
103        assert enumeration_model.get("tsize")[0] == 1
104       
105        enumeration_model.set("tsize", "large")
106        assert enumeration_model.get("tsize")[0] == 3
107       
108        enumeration_model.set("tsize", 2)
109        assert enumeration_model.get("tsize")[0] == 2
110       
111        nose.tools.assert_raises(FMUException, enumeration_model.set, "tsize", "hej")
112   
113    @testattr(stddist_full = True)
114    def test_version(self):
115        negated_alias  = load_fmu(Test_FMUModelBase2.negAliasFmu)
116       
117        assert negated_alias.get_version() == "2.0"
118
119    @testattr(stddist_full = True)
120    def test_set_get_negated_real(self):
121        negated_alias  = load_fmu(Test_FMUModelBase2.negAliasFmu)
122        x,y = negated_alias.get("x"), negated_alias.get("y")
123        nose.tools.assert_almost_equal(x,1.0)
124        nose.tools.assert_almost_equal(y,-1.0)
125
126        negated_alias.set("y",2)
127
128        x,y = negated_alias.get("x"), negated_alias.get("y")
129        nose.tools.assert_almost_equal(x,-2.0)
130        nose.tools.assert_almost_equal(y,2.0)
131
132        negated_alias.set("x",3)
133
134        x,y = negated_alias.get("x"), negated_alias.get("y")
135        nose.tools.assert_almost_equal(x,3.0)
136        nose.tools.assert_almost_equal(y,-3.0)
137
138    @testattr(stddist_full = True)
139    def test_set_get_negated_integer(self):
140        negated_alias  = load_fmu(Test_FMUModelBase2.negAliasFmu)
141        x,y = negated_alias.get("ix"), negated_alias.get("iy")
142        nose.tools.assert_almost_equal(x,1.0)
143        nose.tools.assert_almost_equal(y,-1.0)
144
145        negated_alias.set("iy",2)
146
147        x,y = negated_alias.get("ix"), negated_alias.get("iy")
148        nose.tools.assert_almost_equal(x,-2.0)
149        nose.tools.assert_almost_equal(y,2.0)
150
151        negated_alias.set("ix",3)
152
153        x,y = negated_alias.get("ix"), negated_alias.get("iy")
154        nose.tools.assert_almost_equal(x,3.0)
155        nose.tools.assert_almost_equal(y,-3.0)
156
157    @testattr(stddist_full = True)
158    def test_set_additional_logger(self):
159        messages = []
160        def my_custom_logger(module, log_level, message):
161            messages.append(message)
162        log_level = 4
163        model = load_fmu(Test_FMUModelBase2.negAliasFmu, log_level=log_level)
164        model.set("_log_level", log_level)
165        model.set_additional_logger(my_custom_logger)
166        model.simulate()
167        assert(len(messages) > 0)
168
169class Test_FMUModelCS2:
170    """
171    This class tests pyfmi.fmi.FMUModelCS2
172    """
173    @classmethod
174    def setUpClass(cls):
175        """
176        Sets up the test class.
177        """
178        cls.coupled_name = compile_fmu("Modelica.Mechanics.Rotational.Examples.CoupledClutches", target="cs", version="2.0", compiler_options={'eliminate_alias_constants':False})
179        cls.bouncing_name = compile_fmu("BouncingBall",os.path.join(path_to_mofiles,"BouncingBall.mo"), target="cs", version="2.0", compiler_options={'eliminate_alias_constants':False})
180        cls.terminate = compile_fmu("Terminate",os.path.join(path_to_mofiles,"Terminate.mo"),target="cs", version="2.0")
181        cls.assert_fail = compile_fmu("AssertFail",os.path.join(path_to_mofiles,"Terminate.mo"),target="cs", version="2.0")
182        cls.initialize_solver = compile_fmu("Inputs.DiscChange",os.path.join(path_to_mofiles,"InputTests.mo"),target="cs", version="2.0")
183   
184    @testattr(stddist_full = True)
185    def test_reinitialize_solver(self):
186        model = load_fmu(Test_FMUModelCS2.initialize_solver)
187       
188        model.initialize()
189
190        model.set("u", 0.0)
191        flag = model.do_step(0.0, 0.1)
192        assert flag == 0
193        model.set("u", 20)
194        flag = model.do_step(0.1, 0.1)
195        assert flag == 0
196       
197    @testattr(stddist_full = True)
198    def test_assert_fail(self):
199        model = load_fmu(Test_FMUModelCS2.assert_fail)
200       
201        nose.tools.assert_raises(Exception, model.simulate)
202   
203    @testattr(stddist_full = True)
204    def test_terminate_3(self):
205        model = load_fmu(Test_FMUModelCS2.terminate)
206       
207        model.initialize()
208        status = model.do_step(0,1)
209       
210        assert status == fmi.FMI_DISCARD
211        assert abs(model.get_real_status(fmi.FMI2_LAST_SUCCESSFUL_TIME) - 0.5) < 1e-3
212       
213    @testattr(stddist_full = True)
214    def test_terminate_2(self):
215        model = load_fmu(Test_FMUModelCS2.terminate)
216       
217        res = model.simulate()
218       
219        assert res.status == fmi.FMI_DISCARD
220        assert abs(res["time"][-1] - 0.5) < 1e-3
221
222    @testattr(stddist_full = True)
223    def test_part_log(self):
224        model = load_fmu(self.coupled_name, log_level=6)
225       
226        model.set("_log_level", 6)
227       
228        model.simulate()
229       
230        num_lines = model.get_number_of_lines_log()
231        assert num_lines > 50 #Assert big log
232       
233        log = model.get_log(start_lines=10)
234        assert len(log) == 10
235        log = model.get_log(end_lines=10)
236        assert len(log) == 10
237        log = model.get_log()
238        assert len(log) == num_lines
239        log = model.get_log(start_lines=10, end_lines=10)
240        assert len(log) == 20
241        log = model.get_log(start_lines=num_lines-10, end_lines=num_lines-10)
242        assert len(log) == num_lines
243   
244    @testattr(windows_full = True)
245    def test_init(self):
246        """
247        Test the method __init__ in FMUModelCS2
248        """
249        bounce = load_fmu(self.bouncing_name)
250
251        assert bounce.get_identifier() == 'BouncingBall'
252        nose.tools.assert_raises(FMUException, FMUModelCS2, fmu=ME2, path=path_to_fmus_me2)
253        nose.tools.assert_raises(FMUException, FMUModelCS2, fmu=CS1, path=path_to_fmus_cs1)
254        nose.tools.assert_raises(FMUException, FMUModelCS2, fmu=ME1, path=path_to_fmus_me1)
255
256    @testattr(stddist_full = True)
257    def test_instantiate_slave(self):
258        """
259        Test the method instantiate_slave in FMUModelCS2
260        """
261        bounce = load_fmu(self.bouncing_name)
262       
263        bounce.setup_experiment()
264        bounce.initialize()
265
266        bounce.reset() #Test multiple instantiation
267        for i in range(0,10):
268            name_of_slave = 'slave' + str(i)
269            bounce.instantiate(name = name_of_slave)
270
271    @testattr(stddist_full = True)
272    def test_initialize(self):
273        """
274        Test the method initialize in FMUModelCS2
275        """
276        bounce = load_fmu(self.bouncing_name)
277
278        for i in range(10):
279            bounce.setup_experiment(tolerance= 10**-i)
280            bounce.initialize()  #Initialize multiple times with different relTol
281            bounce.reset()
282           
283        bounce.setup_experiment()
284        bounce.initialize()    #Initialize with default options
285        bounce.reset()
286
287        bounce.setup_experiment(start_time=4.5)
288        bounce.initialize()
289        nose.tools.assert_almost_equal(bounce.time, 4.5)
290   
291    @testattr(stddist_full = True)
292    def test_simulation_past_tstop(self):
293       
294        coupled = load_fmu(self.coupled_name)
295       
296        #Try to simulate past the defined stop
297        coupled.setup_experiment(stop_time_defined=True, stop_time=1.0)
298        coupled.initialize()
299       
300        step_size=0.1
301        total_time=0
302        for i in range(10):
303            coupled.do_step(total_time, step_size)
304            total_time += step_size
305        status = coupled.do_step(total_time, step_size)
306        assert status != 0
307
308    @testattr(stddist_full = True)
309    def test_reset_slave(self):
310        """
311        Test the method reset_slave in FMUModelCS2
312        """
313        bounce = load_fmu(self.bouncing_name)
314       
315        bounce.setup_experiment()
316        bounce.initialize()
317
318        bounce.reset()
319       
320        bounce.setup_experiment()
321        bounce.initialize()
322   
323    @testattr(stddist_full = True)
324    def test_reset_free_slave(self):
325        bounce = load_fmu(self.bouncing_name)
326        res = bounce.simulate()
327       
328        bounce.reset()
329        bounce.terminate()
330        bounce.free_instance()
331       
332    @testattr(stddist_full = True)
333    def test_terminate(self):
334        """
335        Test the method terminate in FMUModelCS2
336        """
337        coupled = load_fmu(self.coupled_name)
338       
339        coupled.setup_experiment()
340        coupled.initialize()
341        coupled.terminate()
342
343    @testattr(stddist_full = True)
344    def test_the_time(self):
345        """
346        Test the time in FMUModelCS2
347        """
348        bounce = load_fmu(self.bouncing_name)
349       
350        bounce.setup_experiment()
351        bounce.initialize()
352
353        assert bounce.time == 0.0
354        bounce._set_time(4.5)
355        assert bounce._get_time() == 4.5
356        bounce.time = 3
357        assert bounce.time == 3.0
358
359        bounce.reset()
360        bounce.setup_experiment(start_time=2.5)
361        bounce.initialize()
362        assert bounce.time == 2.5
363
364    @testattr(stddist_full = True)
365    def test_version(self):
366        bounce = load_fmu(self.bouncing_name)
367        assert bounce.get_version() == "2.0"
368       
369        coupled = load_fmu(self.coupled_name)
370        assert coupled.get_version() == "2.0"
371
372    @testattr(stddist_full = True)
373    def test_do_step(self):
374        """
375        Test the method do_step in FMUModelCS2
376        """
377        bounce = load_fmu(self.bouncing_name)
378       
379        bounce.setup_experiment()
380        bounce.initialize()
381       
382        coupled = load_fmu(self.coupled_name)
383       
384        coupled.setup_experiment()
385        coupled.initialize()
386
387        new_step_size = 1e-1
388        for i in range(1,30):
389            current_time = bounce.time
390            status = bounce.do_step(current_time, new_step_size, True)
391            assert status == 0
392            nose.tools.assert_almost_equal(bounce.time , current_time + new_step_size)
393
394        for i in range(10):
395            current_time = coupled.time
396            status = coupled.do_step(current_time, new_step_size, True)
397            assert status == 0
398            nose.tools.assert_almost_equal(coupled.time , current_time + new_step_size)
399
400    @testattr(stddist_full = True)
401    def test_set_input_derivatives(self):
402        """
403        Test the method set_input_derivatives in FMUModelCS2
404        """
405        #Do the setUp
406        coupled = load_fmu(self.coupled_name)
407
408        nose.tools.assert_raises(FMUException, coupled.set_input_derivatives, 'J1.phi', 1.0, 0) #this is nou an input-variable
409        nose.tools.assert_raises(FMUException, coupled.set_input_derivatives, 'J1.phi', 1.0, 1)
410        nose.tools.assert_raises(FMUException, coupled.set_input_derivatives, 578, 1.0, 1)
411
412    @testattr(stddist_full = True)
413    def test_get_output_derivatives(self):
414        """
415        Test the method get_output_derivatives in FMUModelCS2
416        """
417        coupled = load_fmu(self.coupled_name)
418       
419        coupled.setup_experiment()
420        coupled.initialize()
421
422        coupled.do_step(0.0, 0.02)
423        nose.tools.assert_raises(FMUException, coupled.get_output_derivatives, 'J1.phi', 1)
424        nose.tools.assert_raises(FMUException, coupled.get_output_derivatives, 'J1.phi', -1)
425        nose.tools.assert_raises(FMUException, coupled.get_output_derivatives, 578, 0)
426
427    @testattr(stddist_full = True)
428    def test_simulate(self):
429        """
430        Test the main features of the method simulate() in FMUmodelCS2
431        """
432        #Set up for simulation
433        bounce = load_fmu(self.bouncing_name)
434        coupled = load_fmu(self.coupled_name)
435
436        #Try simulate the bouncing ball
437        res = bounce.simulate()
438        sim_time = res['time']
439        nose.tools.assert_almost_equal(sim_time[0], 0.0)
440        nose.tools.assert_almost_equal(sim_time[-1], 1.0)
441        bounce.reset()
442
443        for i in range(5):
444            res = bounce.simulate(start_time=0.1, final_time=1.0, options={'ncp':500})
445            sim_time = res['time']
446            nose.tools.assert_almost_equal(sim_time[0], 0.1)
447            nose.tools.assert_almost_equal(sim_time[-1],1.0)
448            assert sim_time.all() >= sim_time[0] - 1e-4   #Check that the time is increasing
449            assert sim_time.all() <= sim_time[-1] + 1e-4  #Give it some marginal
450            height = res['h']
451            assert height.all() >= -1e-4 #The height of the ball should be non-negative
452            nose.tools.assert_almost_equal(res.final('h'), 6.0228998448008104, 4)
453            if i>0: #check that the results stays the same
454                diff = height_old - height
455                nose.tools.assert_almost_equal(diff[-1],0.0)
456            height_old = height
457            bounce.reset()
458
459        #Try to simulate the coupled-clutches
460        res_coupled = coupled.simulate()
461        sim_time_coupled = res_coupled['time']
462        nose.tools.assert_almost_equal(sim_time_coupled[0], 0.0)
463        nose.tools.assert_almost_equal(sim_time_coupled[-1], 1.5)
464        coupled.reset()
465
466
467        for i in range(10):
468            coupled = load_fmu(self.coupled_name)
469            res_coupled = coupled.simulate(start_time=0.0, final_time=2.0)
470            sim_time_coupled = res_coupled['time']
471            nose.tools.assert_almost_equal(sim_time_coupled[0], 0.0)
472            nose.tools.assert_almost_equal(sim_time_coupled[-1],2.0)
473            assert sim_time_coupled.all() >= sim_time_coupled[0] - 1e-4   #Check that the time is increasing
474            assert sim_time_coupled.all() <= sim_time_coupled[-1] + 1e-4  #Give it some marginal
475
476            #val_J1 = res_coupled['J1.w']
477            #val_J2 = res_coupled['J2.w']
478            #val_J3 = res_coupled['J3.w']
479            #val_J4 = res_coupled['J4.w']
480
481            val=[res_coupled.final('J1.w'), res_coupled.final('J2.w'), res_coupled.final('J3.w'), res_coupled.final('J4.w')]
482            if i>0: #check that the results stays the same
483                for j in range(len(val)):
484                    nose.tools.assert_almost_equal(val[j], val_old[j])
485            val_old = val
486            coupled.reset()
487       
488        """
489        #Compare to something we know is correct
490        cs1_model = load_fmu('Modelica_Mechanics_Rotational_Examples_CoupledClutches_CS.fmu',path_to_fmus_cs1)
491        res1 = cs1_model.simulate(final_time=10, options={'result_file_name':'result1'})
492        self._coupledCS2 = load_fmu(CoupledCS2, path_to_fmus_cs2)
493        res2 = self._coupledCS2.simulate(final_time=10, options={'result_file_name':'result2'})
494        diff1 = res1.final("J1.w") - res2.final("J1.w")
495        diff2 = res1.final("J2.w") - res2.final("J2.w")
496        diff3 = res1.final("J3.w") - res2.final("J3.w")
497        diff4 = res1.final("J4.w") - res2.final("J4.w")
498        nose.tools.assert_almost_equal(abs(diff1), 0.000, 1)
499        nose.tools.assert_almost_equal(abs(diff2), 0.000, 1)
500        nose.tools.assert_almost_equal(abs(diff3), 0.000, 1)
501        nose.tools.assert_almost_equal(abs(diff4), 0.000, 1)
502        """
503       
504    @testattr(windows_full = True)
505    def test_simulate_extern(self):
506        """
507        Test the method simulate in FMUModelCS2 on FMU SDK bouncing ball
508        """
509        bounce  = load_fmu(fmu=CS2, path=path_to_fmus_cs2)
510
511        #Try simulate the bouncing ball
512        res = bounce.simulate()
513        sim_time = res['time']
514        nose.tools.assert_almost_equal(sim_time[0], 0.0)
515        nose.tools.assert_almost_equal(sim_time[-1], 1.0)
516        bounce.reset()
517
518        for i in range(5):
519            res = bounce.simulate(start_time=0.1, final_time=1.0, options={'ncp':500})
520            sim_time = res['time']
521            nose.tools.assert_almost_equal(sim_time[0], 0.1)
522            nose.tools.assert_almost_equal(sim_time[-1],1.0)
523            assert sim_time.all() >= sim_time[0] - 1e-4   #Check that the time is increasing
524            assert sim_time.all() <= sim_time[-1] + 1e-4  #Give it some marginal
525            height = res['h']
526            assert height.all() >= -1e-4 #The height of the ball should be non-negative
527            nose.tools.assert_almost_equal(res.final('h'), 0.40479334288121899, 4)
528            if i>0: #check that the results stays the same
529                diff = height_old - height
530                nose.tools.assert_almost_equal(diff[-1],0.0)
531            height_old = height
532            bounce.reset()
533
534    @testattr(stddist_full = True)
535    def test_simulate_options(self):
536        """
537        Test the method simultaion_options in FMUModelCS2
538        """
539        #Do the setUp
540        coupled = load_fmu(self.coupled_name)
541
542        #Test the result file
543        res = coupled.simulate(options={"result_handling":"file"})
544        assert res.result_file == coupled.get_identifier()+'_result.txt'
545        assert os.path.exists(res.result_file)
546
547        coupled.reset()
548        opts = {'result_file_name':'Modelica_Mechanics_Rotational_Examples_CoupledClutches_result_test.txt'}
549        res = coupled.simulate(options=opts)
550        assert res.result_file == 'Modelica_Mechanics_Rotational_Examples_CoupledClutches_result_test.txt'
551        assert os.path.exists(res.result_file)
552
553        #Test the option in the simulate method
554        coupled.reset()
555        opts={}
556        opts['ncp'] = 250
557        opts['initialize'] = False
558       
559        coupled.setup_experiment()
560        coupled.initialize()
561        res = coupled.simulate(options=opts)
562        assert len(res['time']) == 251
563
564
565class Test_FMUModelME2:
566    """
567    This class tests pyfmi.fmi.FMUModelME2
568    """
569    @classmethod
570    def setUpClass(cls):
571        """
572        Sets up the test class.
573        """
574        cls.coupled_name = compile_fmu("Modelica.Mechanics.Rotational.Examples.CoupledClutches", target="me", version="2.0", compiler_options={'eliminate_alias_constants':False})
575        cls.bouncing_name = compile_fmu("BouncingBall",os.path.join(path_to_mofiles,"BouncingBall.mo"), target="me", version="2.0", compiler_options={'eliminate_alias_constants':False})
576        cls.enum_name = compile_fmu("Enumerations.Enumeration2", os.path.join(path_to_mofiles,"Enumerations.mo"), target="me", version="2.0")   
577        cls.string1 = compile_fmu("StringModel1",os.path.join(path_to_mofiles,"TestString.mo"), target="me", version="2.0")
578        cls.linear2 = compile_fmu("LinearTest.Linear2", os.path.join(path_to_mofiles,"Linear.mo"), target="me", version="2.0")
579    def _get_discrete_inputs_results(self, model_name):
580        """
581            Used by test_model_bool_input_pre_operator_without_edge
582            and
583            test_model_bool_input_pre_operator_with_edge
584        """
585        rtol = 1e-6
586        atol = rtol
587        ncp = 500
588        libpaths = [os.path.join(get_files_path(), 'Modelica', 'DiscreteInputTestModels.mo')]
589        n = compile_fmu(model_name,
590                        libpaths,
591                        jvm_args='-Xmx6g')
592
593        m = load_fmu(n)
594
595        start = 0.400
596        stop = 0.405
597
598        m.initialize(start_time=start, tolerance=rtol)
599        m.event_update()
600        m.enter_continuous_time_mode()
601
602        opts = m.simulate_options()
603
604        opts["initialize"] = False
605        opts["CVode_options"]["rtol"] = rtol
606        opts["CVode_options"]["atol"] = atol
607        opts['ncp'] = ncp
608
609        ts = []
610        inp = [True]
611        results = []
612        m.set("Bool_A", True)
613
614        for h in N.linspace(start, stop, 21)[:-1]:
615            ts.append(h)
616            inp.append(not inp[-1])
617           
618            m.enter_event_mode()
619            m.set("Bool_B", inp[-1])
620            m.event_update()
621            m.enter_continuous_time_mode()
622            res_jm = m.simulate(h, h+0.00025, options=opts)
623           
624            results.extend(res_jm["Real_B"])
625       
626        return results
627
628
629    def _discrete_inputs_get_reference_data(self, path_to_reference_data):
630        """
631            Used by test_model_bool_input_pre_operator_without_edge
632            and
633            test_model_bool_input_pre_operator_with_edge
634        """
635        ref_values = []
636        with open(path_to_reference_data, 'r') as f:
637            ref_values = f.readlines()
638
639        # remove all newlines and convert elements to float since they are strings
640        ref_values = [s.strip() for s in ref_values]
641        ref_values = [float(x) for x in ref_values]
642        return ref_values
643   
644    @testattr(stddist_full = True)
645    def test_model_bool_input_pre_operator_without_edge(self):
646        """Test boolean inputs used in a pre operator and without using edge"""
647        model_name = 'DiscreteInputTestModels.boolInputInPreOperatorWithoutEdge'
648        results_no_edge = self._get_discrete_inputs_results(model_name)
649
650        path_to_reference_data = os.path.join(get_files_path(), 'Modelica', 'DiscreteInputTestValues.txt')
651        ref_values = self._discrete_inputs_get_reference_data(path_to_reference_data)
652
653        assert N.amax(N.array(ref_values) - results_no_edge) == 0.0
654
655    @testattr(stddist_full = True)
656    def test_model_bool_input_pre_operator_with_edge(self):
657        """Test boolean inputs used in a pre operator and using edge"""
658        model_name = 'DiscreteInputTestModels.boolInputInPreOperatorWithEdge'
659        results_with_edge = self._get_discrete_inputs_results(model_name)
660
661        path_to_reference_data = os.path.join(get_files_path(), 'Modelica', 'DiscreteInputTestValues.txt')
662        ref_values = self._discrete_inputs_get_reference_data(path_to_reference_data)
663
664        assert N.amax(N.array(ref_values) - results_with_edge) == 0.0
665
666    @testattr(stddist_full = True)
667    def test_relative_tolerance(self):
668        model = load_fmu(self.linear2)
669       
670        opts = model.simulate_options()
671        opts["CVode_options"]["rtol"] = 1e-8
672       
673        res = model.simulate(options=opts)
674       
675        assert res.options["CVode_options"]["atol"] == 1e-10
676
677    @testattr(stddist_full = True)
678    def test_get_string(self):
679        model = load_fmu(self.string1)
680       
681        for i in range(100): #Test so that memory issues are detected
682            assert model.get("str")[0] == "hej"
683   
684    @testattr(stddist_full = True)
685    def test_estimate_directional_derivatives_A(self):
686       
687        model = load_fmu(self.coupled_name)
688        model.initialize()
689        model.event_update()
690        model.enter_continuous_time_mode()
691       
692        A = model._get_A(use_structure_info=True)
693        B = model._get_A(use_structure_info=True, output_matrix=A)
694        assert A is B #Test that the returned matrix is actually the same as the input
695        N.allclose(A.toarray(),B.toarray())
696        A = model._get_A(use_structure_info=False)
697        B = model._get_A(use_structure_info=False, output_matrix=A)
698        assert A is B
699        N.allclose(A,B)
700        C = model._get_A(use_structure_info=True, output_matrix=A)
701        assert A is not C
702        N.allclose(C.toarray(), A)
703        D = model._get_A(use_structure_info=False, output_matrix=C)
704        assert D is not C
705        N.allclose(D, C.toarray())
706
707    @testattr(stddist_full = True)
708    def test_display_values(self):
709        model = load_fmu(self.coupled_name)
710       
711        import scipy
712       
713        val = model.get_variable_display_value("J1.phi")
714        val_ref = scipy.rad2deg(model.get("J1.phi"))
715       
716        nose.tools.assert_almost_equal(val, val_ref)
717       
718        model.simulate()
719       
720        val = model.get_variable_display_value("J1.phi")
721        val_ref = scipy.rad2deg(model.get("J1.phi"))
722       
723        nose.tools.assert_almost_equal(val, val_ref)
724   
725    @testattr(stddist_full = True)
726    def test_get_enum(self):
727        model = load_fmu(self.enum_name)
728       
729        assert model.get("one") == 1
730       
731        model.set("one", 2)
732        assert model.get("one") == 2
733
734    @testattr(stddist_full = True)
735    def test_version(self):
736        bounce = load_fmu(self.bouncing_name)
737        assert bounce.get_version() == "2.0"
738       
739        coupled = load_fmu(self.coupled_name)
740        assert coupled.get_version() == "2.0"
741       
742    @testattr(stddist_full = True)
743    def test_variable_initial(self):
744        coupled = load_fmu(self.coupled_name)
745       
746        assert coupled.get_variable_initial("sin1.y") == fmi.FMI2_INITIAL_CALCULATED
747        vars = coupled.get_model_variables()
748        assert vars["sin1.y"].initial == fmi.FMI2_INITIAL_CALCULATED
749   
750    @testattr(windows_full = True)
751    def test_init(self):
752        """
753        Test the method __init__ in FMUModelME2
754        """
755        bounce = load_fmu(self.bouncing_name)
756
757        assert bounce.get_identifier() == 'BouncingBall'
758        nose.tools.assert_raises(FMUException, FMUModelME2, fmu=CS2, path=path_to_fmus_cs2)
759        nose.tools.assert_raises(FMUException, FMUModelME2, fmu=CS1, path=path_to_fmus_cs1)
760        nose.tools.assert_raises(FMUException, FMUModelME2, fmu=ME1, path=path_to_fmus_me1)
761
762    @testattr(stddist_full = True)
763    def test_instantiate_model(self):
764        """
765        Test the method instantiate_model in FMUModelME2
766        """
767        for i in range(5):
768            bounce = load_fmu(self.bouncing_name)
769
770    @testattr(stddist_full = True)
771    def test_initialize(self):
772        """
773        Test the method initialize in FMUModelME2
774        """
775        bounce = load_fmu(self.bouncing_name)
776       
777        bounce.setup_experiment()
778        bounce.initialize()
779        nose.tools.assert_almost_equal(bounce.time, 0.0)
780
781        bounce.reset()
782        bounce.setup_experiment(tolerance=1e-7)
783        bounce.initialize()
784
785    @testattr(stddist_full = True)
786    def test_reset(self):
787        """
788        Test the method reset in FMUModelME2
789        """
790        bounce = load_fmu(self.bouncing_name)
791
792        bounce.setup_experiment()
793        bounce.initialize()
794
795        bounce.reset()
796
797        assert bounce.time is None
798
799    @testattr(stddist_full = True)
800    def test_terminate(self):
801        """
802        Test the method terminate in FMUModelME2
803        """
804        coupled = load_fmu(self.coupled_name)
805       
806        coupled.setup_experiment()
807        coupled.initialize()
808        coupled.terminate()
809
810    @testattr(stddist_full = True)
811    def test_time(self):
812        """
813        Test the method get/set_time in FMUModelME2
814        """
815        bounce = load_fmu(self.bouncing_name)
816
817        bounce.reset() #Currently results in a seg fault
818        assert bounce.time is None
819       
820        bounce.setup_experiment()
821        bounce.initialize()
822       
823        nose.tools.assert_almost_equal(bounce._get_time(), 0.0)
824        bounce._set_time(2.71)
825        nose.tools.assert_almost_equal(bounce.time , 2.71)
826        bounce._set_time(1.00)
827        nose.tools.assert_almost_equal(bounce._get_time() , 1.00)
828
829        nose.tools.assert_raises(TypeError, bounce._set_time, '2.0')
830        nose.tools.assert_raises(TypeError, bounce._set_time, N.array([1.0, 1.0]))
831
832    @testattr(stddist_full = True)
833    def test_get_event_info(self):
834        """
835        Test the method get_event_info in FMUModelME2
836        """
837        bounce = load_fmu(self.bouncing_name)
838       
839        bounce.setup_experiment()
840        bounce.initialize()
841       
842        event = bounce.get_event_info()
843        assert isinstance(event, PyEventInfo)
844
845        assert event.newDiscreteStatesNeeded           == False
846        assert event.nominalsOfContinuousStatesChanged == False
847        assert event.valuesOfContinuousStatesChanged   == True
848        assert event.terminateSimulation               == False
849        assert event.nextEventTimeDefined              == False
850        assert event.nextEventTime                     == 0.0
851
852    @testattr(stddist_full = True)
853    def test_get_event_indicators(self):
854        """
855        Test the method get_event_indicators in FMUModelME2
856        """
857        bounce = load_fmu(self.bouncing_name)
858        coupled = load_fmu(self.coupled_name)
859       
860        bounce.setup_experiment()
861        bounce.initialize()
862       
863        coupled.setup_experiment()
864        coupled.initialize()
865
866        assert len(bounce.get_event_indicators()) == 1
867        assert len(coupled.get_event_indicators()) == 33
868
869        event_ind = bounce.get_event_indicators()
870        nose.tools.assert_almost_equal(event_ind[0],10.000000)
871        bounce.continuous_states = N.array([5.]*2)
872        event_ind = bounce.get_event_indicators()
873        nose.tools.assert_almost_equal(event_ind[0],5.000000)
874
875    @testattr(stddist_full = True)
876    def test_get_tolerances(self):
877        """
878        Test the method get_tolerances in FMUModelME2
879        """
880        bounce = load_fmu(self.bouncing_name)
881       
882        bounce.setup_experiment()
883        bounce.initialize()
884
885        [rtol,atol] = bounce.get_tolerances()
886
887        assert rtol == 0.0001
888        nose.tools.assert_almost_equal(atol[0],0.0000010)
889        nose.tools.assert_almost_equal(atol[1],0.0000010)
890
891    @testattr(stddist_full = True)
892    def test_continuous_states(self):
893        """
894        Test the method get/set_continuous_states in FMUModelME2
895        """
896        bounce = load_fmu(self.bouncing_name)
897        coupled = load_fmu(self.coupled_name)
898       
899        bounce.setup_experiment()
900        bounce.initialize()
901       
902        coupled.setup_experiment()
903        coupled.initialize()
904
905        nx = bounce.get_ode_sizes()[0]
906        states = bounce._get_continuous_states()
907        assert nx == len(states)
908
909        nose.tools.assert_almost_equal(states[0],10.000000)
910        nose.tools.assert_almost_equal(states[1],0.000000)
911
912        bounce.continuous_states = N.array([2.,-3.])
913        states = bounce.continuous_states
914
915        nose.tools.assert_almost_equal(states[0],2.000000)
916        nose.tools.assert_almost_equal(states[1],-3.000000)
917
918        n_states=bounce._get_nominal_continuous_states()
919        assert nx == len(n_states)
920        nose.tools.assert_almost_equal(n_states[0], 1.000000)
921        nose.tools.assert_almost_equal(n_states[1], 1.000000)
922
923
924        nx = coupled.get_ode_sizes()[0]
925        states = coupled._get_continuous_states()
926        assert nx == len(states)
927        coupled._set_continuous_states(N.array([5.]*nx))
928        states = coupled.continuous_states
929        nose.tools.assert_almost_equal(states[-1], 5.000000)
930
931        n_states=coupled._get_nominal_continuous_states()
932        nose.tools.assert_almost_equal(n_states[0], 0.0001)
933        n_states=coupled.nominal_continuous_states
934        nose.tools.assert_almost_equal(n_states[0], 0.0001)
935       
936    @testattr(stddist_full = True)
937    def test_get_derivatives(self):
938        """
939        Test the method get_derivatives in FMUModelME2
940        """
941        bounce = load_fmu(self.bouncing_name)
942        coupled = load_fmu(self.coupled_name)
943       
944        bounce.setup_experiment()
945        bounce.initialize()
946       
947        coupled.setup_experiment()
948        coupled.initialize()
949
950        nx = bounce.get_ode_sizes()[0]
951        der=bounce.get_derivatives()
952        assert nx == len(der)
953
954        nose.tools.assert_almost_equal(der[0], 0.000000)
955        nose.tools.assert_almost_equal(der[1], -9.820000)
956
957        bounce.continuous_states = N.array([5.0, 2.0])
958        der=bounce.get_derivatives()
959        nose.tools.assert_almost_equal(der[0], 2.000000)
960
961        der_list = coupled.get_derivatives_list()
962        der_ref  = N.array([s.value_reference for s in list(der_list.values())])
963        der = coupled.get_derivatives()
964        diff = N.sort(N.array([coupled.get_real(i) for i in der_ref]))-N.sort(der)
965        nose.tools.assert_almost_equal(N.sum(diff), 0.)
966       
967    @testattr(stddist_full = True)
968    def test_simulate_with_debug_option(self):
969        coupled = load_fmu(self.coupled_name)
970
971        opts=coupled.simulate_options()
972        opts["logging"] = True
973       
974        #Verify that a simulation is successful
975        res=coupled.simulate(options=opts)
976       
977        from pyfmi.debug import CVodeDebugInformation
978        debug = CVodeDebugInformation(coupled.get_identifier()+"_debug.txt")
979
980    @testattr(stddist_full = True)
981    def test_simulate_options(self):
982        """
983        Test the method simulate_options in FMUModelME2
984        """
985        coupled = load_fmu(self.coupled_name)
986
987        opts=coupled.simulate_options()
988        assert opts['initialize']
989        assert opts['with_jacobian'] == "Default"
990
991        #Test the result file
992        res=coupled.simulate(options={"result_handling":"file"})
993        assert res.result_file == coupled.get_identifier()+'_result.txt'
994        assert os.path.exists(res.result_file)
995
996        coupled.reset()
997        opts = {'result_file_name':'Modelica_Mechanics_Rotational_Examples_CoupledClutches_result_test.txt'}
998        res=coupled.simulate(options=opts)
999        assert res.result_file == 'Modelica_Mechanics_Rotational_Examples_CoupledClutches_result_test.txt'
1000        assert os.path.exists(res.result_file)
1001
1002        #Test the option in the simulate method
1003        coupled.reset()
1004        opts={}
1005        opts['ncp'] = 250
1006        opts['initialize'] = False
1007       
1008        coupled.setup_experiment()
1009        coupled.initialize()
1010        coupled.event_update()
1011        coupled.enter_continuous_time_mode()
1012        res=coupled.simulate(options=opts)
1013        assert len(res['time']) > 250
1014   
1015    @testattr(stddist_full = True)
1016    def test_simulate(self):
1017        """
1018        Test the method simulate in FMUModelME2
1019        """
1020        bounce  = load_fmu(self.bouncing_name)
1021        coupled = load_fmu(self.coupled_name)
1022
1023        #Try simulate the bouncing ball
1024        res=bounce.simulate()
1025        sim_time = res['time']
1026        nose.tools.assert_almost_equal(sim_time[0], 0.0)
1027        nose.tools.assert_almost_equal(sim_time[-1], 1.0)
1028        bounce.reset()
1029
1030        opts = bounce.simulate_options()
1031        opts["CVode_options"]["rtol"] = 1e-6
1032        opts["CVode_options"]["atol"] = 1e-6
1033        opts["ncp"] = 500
1034
1035        for i in range(5):
1036            res=bounce.simulate(start_time=0.1, final_time=1.0, options=opts)
1037            sim_time = res['time']
1038            nose.tools.assert_almost_equal(sim_time[0], 0.1)
1039            nose.tools.assert_almost_equal(sim_time[-1],1.0)
1040            assert sim_time.all() >= sim_time[0] - 1e-4   #Check that the time is increasing
1041            assert sim_time.all() <= sim_time[-1] + 1e-4  #Give it some marginal
1042            height = res['h']
1043            assert height.all() >= -1e-4 #The height of the ball should be non-negative
1044            nose.tools.assert_almost_equal(res.final('h'), 6.0228998448008104, 4)
1045            if i>0: #check that the results stays the same
1046                diff = height_old - height
1047                nose.tools.assert_almost_equal(diff[-1],0.0)
1048            height_old = height
1049            bounce.reset()
1050
1051        #Try to simulate the coupled-clutches
1052        res_coupled=coupled.simulate()
1053        sim_time_coupled = res_coupled['time']
1054        nose.tools.assert_almost_equal(sim_time_coupled[0], 0.0)
1055        nose.tools.assert_almost_equal(sim_time_coupled[-1], 1.5)
1056        coupled.reset()
1057
1058
1059        for i in range(10):
1060            res_coupled = coupled.simulate(start_time=0.0, final_time=2.0)
1061            sim_time_coupled = res_coupled['time']
1062            nose.tools.assert_almost_equal(sim_time_coupled[0], 0.0)
1063            nose.tools.assert_almost_equal(sim_time_coupled[-1],2.0)
1064            assert sim_time_coupled.all() >= sim_time_coupled[0] - 1e-4   #Check that the time is increasing
1065            assert sim_time_coupled.all() <= sim_time_coupled[-1] + 1e-4  #Give it some marginal
1066
1067            #val_J1 = res_coupled['J1.w']
1068            #val_J2 = res_coupled['J2.w']
1069            #val_J3 = res_coupled['J3.w']
1070            #val_J4 = res_coupled['J4.w']
1071
1072            val=[res_coupled.final('J1.w'), res_coupled.final('J2.w'), res_coupled.final('J3.w'), res_coupled.final('J4.w')]
1073            if i>0: #check that the results stays the same
1074                for j in range(len(val)):
1075                    nose.tools.assert_almost_equal(val[j], val_old[j])
1076            val_old = val
1077            coupled.reset()
1078       
1079        """
1080        #Compare to something we know is correct
1081        me1_model = load_fmu('Modelica_Mechanics_Rotational_Examples_CoupledClutches_ME.fmu',path_to_fmus_me1)
1082        res1 = me1_model.simulate(final_time=2., options={'result_file_name':'result1'})
1083        coupled = load_fmu(CoupledME2, path_to_fmus_me2)
1084        res2 = coupled.simulate(final_time=2., options={'result_file_name':'result2'})
1085        diff1 = res1.final("J1.w") - res2.final("J1.w")
1086        diff2 = res1.final("J2.w") - res2.final("J2.w")
1087        diff3 = res1.final("J3.w") - res2.final("J3.w")
1088        diff4 = res1.final("J4.w") - res2.final("J4.w")
1089        nose.tools.assert_almost_equal(abs(diff1), 0.0000, 2)
1090        nose.tools.assert_almost_equal(abs(diff2), 0.0000, 2)
1091        nose.tools.assert_almost_equal(abs(diff3), 0.0000, 2)
1092        nose.tools.assert_almost_equal(abs(diff4), 0.0000, 2)
1093        """
1094       
1095    @testattr(windows_full = True)
1096    def test_simulate_extern(self):
1097        """
1098        Test the method simulate in FMUModelME2 on FMU SDK bouncing ball
1099        """
1100        bounce  = load_fmu(fmu=ME2, path=path_to_fmus_me2)
1101
1102        #Try simulate the bouncing ball
1103        res = bounce.simulate()
1104        sim_time = res['time']
1105        nose.tools.assert_almost_equal(sim_time[0], 0.0)
1106        nose.tools.assert_almost_equal(sim_time[-1], 1.0)
1107        bounce.reset()
1108
1109        opts = bounce.simulate_options()
1110        opts["CVode_options"]["rtol"] = 1e-6
1111        opts["CVode_options"]["atol"] = 1e-6
1112        opts["ncp"] = 500
1113
1114        for i in range(5):
1115            res=bounce.simulate(start_time=0.1, final_time=1.0, options=opts)
1116            sim_time = res['time']
1117            nose.tools.assert_almost_equal(sim_time[0], 0.1)
1118            nose.tools.assert_almost_equal(sim_time[-1],1.0)
1119            assert sim_time.all() >= sim_time[0] - 1e-4   #Check that the time is increasing
1120            assert sim_time.all() <= sim_time[-1] + 1e-4  #Give it some marginal
1121            height = res['h']
1122            assert height.all() >= -1e-4 #The height of the ball should be non-negative
1123            nose.tools.assert_almost_equal(res.final('h'), 0.40400192742719998, 4)
1124            if i>0: #check that the results stays the same
1125                diff = height_old - height
1126                nose.tools.assert_almost_equal(diff[-1],0.0)
1127            height_old = height
1128            bounce.reset()
1129
1130class Test_load_fmu2:
1131    """
1132    This test the functionality of load_fmu method.
1133    """
1134    @testattr(windows_full = True)
1135    def test_raise_exception(self):
1136        """
1137        This method tests the error-handling of load_fmu
1138        """
1139        nose.tools.assert_raises(FMUException, load_fmu, 'not_an_fmu.txt', path_to_fmus)                      #loading non-fmu file
1140        nose.tools.assert_raises(FMUException, load_fmu, 'not_existing_file.fmu', path_to_fmus_me2)           #loading non-existing file
1141        #nose.tools.assert_raises(FMUException, load_fmu, 'not_a_.fmu', path_to_fmus)                          #loading a non-real fmu
1142        nose.tools.assert_raises(FMUException, load_fmu, fmu=ME2, path=path_to_fmus_me2, kind='invalid_kind') #loading fmu with wrong argument
1143        nose.tools.assert_raises(FMUException, load_fmu, fmu=ME1, path=path_to_fmus_me1, kind='CS')           #loading ME1-model as a CS-model
1144        nose.tools.assert_raises(FMUException, load_fmu, fmu=CS1, path=path_to_fmus_cs1, kind='ME')           #loading CS1-model as ME-model
1145        nose.tools.assert_raises(FMUException, load_fmu, fmu=ME2, path=path_to_fmus_me2, kind='CS')           #loading ME2-model as a CS-model
1146        nose.tools.assert_raises(FMUException, load_fmu, fmu=CS2, path=path_to_fmus_cs2, kind='ME')           #loading CS2-model as ME-model
1147
1148    @testattr(windows_full = True)
1149    def test_correct_loading(self):
1150        """
1151        This method tests the correct loading of FMUs
1152        """
1153        model = load_fmu(fmu=ME2, path=path_to_fmus_me2, kind='auto') #loading ME2-model correct
1154        assert isinstance(model, FMUModelME2)
1155        model = load_fmu(fmu=ME2, path=path_to_fmus_me2, kind='me')   #loading ME2-model correct
1156        assert isinstance(model, FMUModelME2)
1157        model = load_fmu(fmu=CS2, path=path_to_fmus_cs2, kind='auto') #loading CS2-model correct
1158        assert isinstance(model, FMUModelCS2)
1159        model = load_fmu(fmu=CS2, path=path_to_fmus_cs2, kind='cs')   #loading CS2-model correct
1160        assert isinstance(model, FMUModelCS2)
1161
1162
Note: See TracBrowser for help on using the repository browser.