11# -*- coding: utf-8 -*-
22"""
3- Implements the .mo file parsing and generates wrapped.fmu. The supported
4- tools are OpenModelica, Dymola, and OCT. In order to parse with a supported tool,
5- it must be installed on the system.
6- Choose as tool for compilation using variable "tool".
3+ Implements the .mo file parsing and generates teh test case wrapped.fmu.
4+ The supported tools are OpenModelica, Dymola, and OCT.
5+ In order to parse with a supported tool, it must be installed on the system.
6+ The primary function to use here is export_fmu() and its arguments for
7+ tool and solver options.
78
8- The steps are:
9+ The general steps are:
9101) Compile Modelica code into fmu
10112) Use signal exchange block id parameters to find block instance paths and
1112read any associated signals for KPIs, units, min/max, and descriptions.
3233else :
3334 modelicapath = os .path .abspath ('.' )
3435
36+ def compile_fmu_OM (model_path , file_name , algorithm = 'cvode' , tolerance = 1e-6 ):
37+ '''Use OpenModelica via OMPython to compile FMU.
38+
39+ Parameters
40+ ----------
41+ model_path : str
42+ Path to modelica model
43+ file_name : list
44+ Path(s) to modelica file and required libraries not on MODELICAPATH.
45+ algorithm : str, optional
46+ Specify the solver algorithm. Only 'cvode' available for OpenModelica.
47+ Default is 'cvode'.
48+ tolerance : numeric, optional
49+ Specify the solver tolerance.
50+ Default is 1e-6.
51+
52+ Returns
53+ -------
54+ fmu_path : str
55+ Generated FMU path.
56+
57+ '''
58+
59+ from OMPython import OMCSessionZMQ
60+ omc = OMCSessionZMQ ()
61+ # Load libraries from MODELICAPATH
62+ libs = []
63+ for d in os .environ ['MODELICAPATH' ].split (':' ):
64+ if ('Buildings' in d ):
65+ path = d + '/package.mo'
66+ elif ('IDEAS' in d ):
67+ path = d + '/package.mo'
68+ elif ('IBPSA' in d ):
69+ path = d + '/package.mo'
70+ else :
71+ continue
72+ libs .append (path )
73+ for f in file_name :
74+ res = omc .sendExpression ('loadFile("{0}")' .format (f ))
75+ print ('Loaded file: {0}, {1}' .format (f , res ))
76+ # Load Modelica library
77+ res = omc .sendExpression ('loadModel(Modelica)' )
78+ print ('Loaded library: Modelica, {0}' .format (res ))
79+ # Load packages from libraries
80+ for lib in libs :
81+ res = omc .sendExpression ('loadFile("{0}")' .format (lib ))
82+ print ('Loaded library: {0}, {1}' .format (lib , res ))
83+ # Set Compilation Flags as annotations
84+ res = omc .sendExpression ('setCommandLineOptions("--matchingAlgorithm=PFPlusExt \
85+ --indexReductionMethod=dynamicStateSelection -d=initialization")' )
86+
87+ # Set simulation flags via fmiFlags
88+ res = omc .sendExpression ('setCommandLineOptions("--fmiFlags=s:{0},lv:LOG_STDOUT \
89+ LOG_ASSERT LOG_STATS,tolerance:{1}")' .format (algorithm ,tolerance ))
90+
91+ # Compile FMU
92+ fmu_path = omc .sendExpression ('buildModelFMU({0}, fmuType="cs")' .format (model_path ))
93+
94+ return fmu_path
95+
3596def compile_fmu_dymola (model_path , algorithm = 'Cvode' , tolerance = 1e-6 ):
36- '''Execute dymola process to compile FMU.
97+ '''Use Dymola to compile FMU.
3798
99+ Parameters
100+ ----------
38101 model_path : str
39102 Path to modelica model
40103 algorithm : str, optional
41104 Specify the solver algorithm. Options are 'Cvode', 'Dassl', 'Radau', 'Lsodar'.
42105 Default is 'Cvode'.
43106 tolerance : numeric, optional
44- Specify the solver tolerance.
107+ Specify the solver tolerance.
45108 Default is 1e-6.
46-
109+
47110 Returns
48111 -------
49112 fmu_path : str
50- generated FMU path.
113+ Generated FMU path.
51114
52115 '''
53116
@@ -176,8 +239,8 @@ def parse_instances(model_path, file_name, tool='openmodelica', algorithm='cvode
176239 tool : str, optional
177240 FMU compilation tool. "OCT" or "dymola" or "openmodelica" supported.
178241 Default is "openmodelica".
179- algorithm : str, optional
180- Specify the solver algorithm. Check _solver_check function for options
242+ algorithm : str, optional
243+ Specify the solver algorithm. Check _solver_check function for options.
181244 Default is 'cvode'.
182245 tolerance : numeric, optional
183246 Specify the solver tolerance.
@@ -198,7 +261,7 @@ def parse_instances(model_path, file_name, tool='openmodelica', algorithm='cvode
198261 # Compile fmu
199262 if tool == 'OCT' :
200263 from pymodelica import compile_fmu
201- fmu_path = compile_fmu (model_path , file_name , modelicapath = modelicapath , jvm_args = "-Xmx8g" , target = 'cs' ,
264+ fmu_path = compile_fmu (model_path , file_name , modelicapath = modelicapath , jvm_args = "-Xmx8g" , target = 'cs' ,
202265 compiler_options = {'cs_rel_tol' : tolerance ,'cs_solver' : algorithm })
203266 elif tool == 'openmodelica' :
204267 fmu_path = compile_fmu_OM (model_path , file_name )
@@ -313,7 +376,7 @@ def parse_instances(model_path, file_name, tool='openmodelica', algorithm='cvode
313376 signals [signal_type ].append (_make_var_name (instance ,style = 'output' ))
314377 else :
315378 signals [signal_type ] = [_make_var_name (instance ,style = 'output' )]
316-
379+
317380 return instances , signals
318381
319382def write_wrapper (model_path , file_name , instances , tool = 'openmodelica' , algorithm = 'cvode' , tolerance = 1e-6 ):
@@ -336,7 +399,7 @@ def write_wrapper(model_path, file_name, instances, tool='openmodelica', algorit
336399 Specify the solver algorithm. Check _solver_check function for options.
337400 Default is 'cvode'.
338401 tolerance : numeric, optional
339- Specify the solver tolerance.
402+ Specify the solver tolerance.
340403 Default is 1e-6.
341404
342405 Returns
@@ -404,7 +467,7 @@ def write_wrapper(model_path, file_name, instances, tool='openmodelica', algorit
404467 # Export as fmu
405468 if tool == 'OCT' :
406469 from pymodelica import compile_fmu
407- fmu_path = compile_fmu ('wrapped' , [wrapped_path ]+ file_name , modelicapath = modelicapath , jvm_args = "-Xmx8g" , target = 'cs' ,
470+ fmu_path = compile_fmu ('wrapped' , [wrapped_path ]+ file_name , modelicapath = modelicapath , jvm_args = "-Xmx8g" , target = 'cs' ,
408471 compiler_options = {'cs_rel_tol' : tolerance ,'cs_solver' : algorithm })
409472 elif tool == 'openmodelica' :
410473 fmu_path = compile_fmu_OM ('wrapped' , [wrapped_path ]+ file_name )
@@ -420,7 +483,7 @@ def write_wrapper(model_path, file_name, instances, tool='openmodelica', algorit
420483 # Compile fmu
421484 if tool == 'OCT' :
422485 from pymodelica import compile_fmu
423- fmu_path = compile_fmu (model_path , file_name , modelicapath = modelicapath , jvm_args = "-Xmx8g" , target = 'cs' ,
486+ fmu_path = compile_fmu (model_path , file_name , modelicapath = modelicapath , jvm_args = "-Xmx8g" , target = 'cs' ,
424487 compiler_options = {'cs_rel_tol' : tolerance ,'cs_solver' : algorithm })
425488 elif tool == 'openmodelica' :
426489 fmu_path = compile_fmu_OM (model_path , file_name )
@@ -449,7 +512,7 @@ def export_fmu(model_path, file_name, tool='openmodelica', algorithm='cvode', to
449512 Specify the solver algorithm. Check _solver_check function for options.
450513 Default is 'cvode'.
451514 tolerance : numeric, optional
452- Specify the solver tolerance.
515+ Specify the solver tolerance.
453516 Default is 1e-6.
454517
455518 Returns
@@ -463,7 +526,7 @@ def export_fmu(model_path, file_name, tool='openmodelica', algorithm='cvode', to
463526
464527 # Take folder snapshot for cleanup
465528 folder_content = set (os .listdir ())
466- # Check if solver option is valid
529+ # Check if solver option is valid
467530 _solver_check (algorithm ,tool )
468531 # Get signal exchange instances and kpi signals
469532 instances , signals = parse_instances (model_path , file_name , tool , algorithm = algorithm , tolerance = tolerance )
@@ -476,7 +539,7 @@ def export_fmu(model_path, file_name, tool='openmodelica', algorithm='cvode', to
476539 # Generate test case data
477540 man = Data_Manager ()
478541 man .save_data_and_jsons (fmu_path = fmu_path )
479-
542+
480543 # Clean up
481544 folder_content_remove = set (os .listdir ())
482545 keep = {"wrapped.fmu" , "wrapped.mo" ,"kpis.json" }
@@ -532,92 +595,33 @@ def _make_var_name(block, style, description='', attribute=''):
532595
533596 return var_name
534597
535- def _solver_check (algorithm ,tool ):
536- '''Checks if solver option is correct for the chosen tool.
598+ def _solver_check (algorithm , tool ):
599+ '''Checks if solver option is valid for the chosen tool.
600+
601+ Parameters
602+ ----------
537603 algorithm : str
538604 Specify the solver algorithm.
539- Default is "cvode"
540605 tool : str, optional
541606 FMU compilation tool. "OCT" or "dymola" or "openmodelica" supported.
542- Default is "openmodelica".
543607
544608 '''
609+
545610 # Check solver option is valid
546611 if tool == 'dymola' :
547612 valid_algorithms = ['Cvode' , 'Dassl' , 'Radau' , 'Lsodar' ]
548613 if (algorithm not in valid_algorithms ):
549- raise ValueError ('Invalid algorithm "{0}" for tool Dymola. Choose from {1}.' .format (algorithm , valid_algorithms ))
550-
551- elif tool == 'openmodelica' :
614+ raise ValueError ('Invalid algorithm "{0}" for tool {1}. Choose from {2}.' .format (algorithm , tool , valid_algorithms ))
615+ elif tool == 'openmodelica' :
552616 valid_algorithms = ['cvode' ]
553617 if (algorithm not in valid_algorithms ):
554- raise ValueError ('Invalid algorithm "{0}" for tool OpenModelica. Choose from {1}.' .format (algorithm , valid_algorithms ))
555-
618+ raise ValueError ('Invalid algorithm "{0}" for tool {1}. Choose from {2}.' .format (algorithm , tool , valid_algorithms ))
556619 elif tool == 'OCT' :
557620 valid_algorithms = ['CVode' , 'Radau5ODE' , 'RungeKutta34' , 'ExplicitEuler' ]
558621 if (algorithm not in valid_algorithms ):
559- raise ValueError ('Invalid algorithm "{0}" for tool OCT. Choose from {1}.' .format (algorithm , valid_algorithms ))
560-
622+ raise ValueError ('Invalid algorithm "{0}" for tool {1}. Choose from {2}.' .format (algorithm , tool , valid_algorithms ))
561623 else :
562624 raise ValueError ('Tool {0} unknown.' .format (tool ))
563-
564-
565- def compile_fmu_OM (model_path , file_name , algorithm = 'cvode' , tolerance = 1e-6 ):
566- '''Utilize OMPython to compile OpenModelica FMU.
567-
568- model_path : str
569- Path to modelica model
570- file_name : list
571- Path(s) to modelica file and required libraries not on MODELICAPATH.
572- algorithm : str, optional
573- Specify the solver algorithm. Only 'cvode' available for OpenModelica.
574- Default is 'cvode'.
575- tolerance : numeric, optional
576- Specify the solver tolerance.
577- Default is 1e-6.
578-
579- Returns
580- -------
581- fmu_path : str
582- generated FMU path.
583-
584- '''
585- from OMPython import OMCSessionZMQ
586- omc = OMCSessionZMQ ()
587- # Load libraries from MODELICAPATH
588- libs = []
589- for d in os .environ ['MODELICAPATH' ].split (':' ):
590- if ('Buildings' in d ):
591- path = d + '/package.mo'
592- elif ('IDEAS' in d ):
593- path = d + '/package.mo'
594- elif ('IBPSA' in d ):
595- path = d + '/package.mo'
596- else :
597- continue
598- libs .append (path )
599- for f in file_name :
600- res = omc .sendExpression ('loadFile("{0}")' .format (f ))
601- print ('Loaded file: {0}, {1}' .format (f , res ))
602- # Load Modelica library
603- res = omc .sendExpression ('loadModel(Modelica)' )
604- print ('Loaded library: Modelica, {0}' .format (res ))
605- # Load packages from libraries
606- for lib in libs :
607- res = omc .sendExpression ('loadFile("{0}")' .format (lib ))
608- print ('Loaded library: {0}, {1}' .format (lib , res ))
609- # Set Compilation Flags as annotations
610- res = omc .sendExpression ('setCommandLineOptions("--matchingAlgorithm=PFPlusExt \
611- --indexReductionMethod=dynamicStateSelection -d=initialization")' )
612-
613- # Set simulation flags via fmiFlags
614- res = omc .sendExpression ('setCommandLineOptions("--fmiFlags=s:{0},lv:LOG_STDOUT \
615- LOG_ASSERT LOG_STATS,tolerance:{1}")' .format (algorithm ,tolerance ))
616-
617- # Compile FMU
618- fmu_path = omc .sendExpression ('buildModelFMU({0}, fmuType="cs")' .format (model_path ))
619-
620- return fmu_path
621625
622626if __name__ == '__main__' :
623627 # Define model
0 commit comments