Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
O
OptiOrch
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Zizhe Wang
OptiOrch
Commits
3d88a29d
Commit
3d88a29d
authored
May 27, 2024
by
Zizhe Wang
Browse files
Options
Downloads
Patches
Plain Diff
add component to transfer feature models
parent
ff5bc4c4
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
src/feature_model.py
+46
-0
46 additions, 0 deletions
src/feature_model.py
src/modelica.g4
+501
-0
501 additions, 0 deletions
src/modelica.g4
src/parse_modelica.py
+81
-0
81 additions, 0 deletions
src/parse_modelica.py
with
628 additions
and
0 deletions
src/feature_model.py
0 → 100644
+
46
−
0
View file @
3d88a29d
from
anytree
import
Node
,
RenderTree
import
json
from
parse_modelica
import
parse_model
# Class to represent and manipulate the feature model tree
class
FeatureModel
:
def
__init__
(
self
,
root_name
):
self
.
root
=
Node
(
root_name
)
# Initialize the root node of the tree
# Method to add a component and its parameters to the tree
def
add_component
(
self
,
component_type
,
component_name
,
parameters
):
# Create a node for the component
component_node
=
Node
(
f
"
{
component_type
}
(
{
component_name
}
)
"
,
parent
=
self
.
root
)
# Create nodes for each parameter and its value
for
param_name
,
param_value
in
parameters
.
items
():
Node
(
f
"
{
param_name
}
=
{
param_value
}
"
,
parent
=
component_node
)
# Method to display the tree structure in the console
def
display
(
self
):
for
pre
,
fill
,
node
in
RenderTree
(
self
.
root
):
print
(
"
%s%s
"
%
(
pre
,
node
.
name
))
# Method to convert the tree to a dictionary for JSON serialization
def
to_dict
(
self
,
node
=
None
):
if
node
is
None
:
node
=
self
.
root
result
=
{
"
name
"
:
node
.
name
,
"
children
"
:
[
self
.
to_dict
(
child
)
for
child
in
node
.
children
]}
return
result
# Method to save the tree to a JSON file
def
save_to_json
(
self
,
file_path
):
with
open
(
file_path
,
'
w
'
)
as
file
:
json
.
dump
(
self
.
to_dict
(),
file
,
indent
=
4
)
if
__name__
==
"
__main__
"
:
# Parse the Modelica file and extract components
components
=
parse_model
(
'
SimpleHeatingSystem.mo
'
)
# Create a feature model and add the extracted components
feature_model
=
FeatureModel
(
"
SimpleHeatingSystem
"
)
for
component_type
,
component_name
,
parameters
in
components
:
feature_model
.
add_component
(
component_type
,
component_name
,
parameters
)
# Display and save the feature tree
feature_model
.
display
()
feature_model
.
save_to_json
(
'
feature_model.json
'
)
\ No newline at end of file
This diff is collapsed.
Click to expand it.
src/modelica.g4
0 → 100644
+
501
−
0
View file @
3d88a29d
/*
[The "BSD licence"]
Copyright (c) 2012 Tom Everett
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// $antlr-format alignTrailingComments true, columnLimit 150, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments false, useTab false
// $antlr-format allowShortRulesOnASingleLine false, allowShortBlocksOnASingleLine true, alignSemicolons hanging, alignColons hanging
grammar modelica;
stored_definition
: ('within' (name)? ';')* (('final')? class_definition ';')* EOF
;
class_definition
: ('encapsulated')? class_prefixes class_specifier
;
class_specifier
: long_class_specifier
| short_class_specifier
| der_class_specifier
;
class_prefixes
: ('partial')? (
'class'
| 'model'
| ('operator')? 'record'
| 'block'
| ('expandable')? 'connector'
| 'type'
| 'package'
| (('pure' | 'impure'))? ('operator')? 'function'
| 'operator'
)
;
long_class_specifier
: IDENT string_comment composition 'end' IDENT
| 'extends' IDENT (class_modification)? string_comment composition 'end' IDENT
;
short_class_specifier
: IDENT '=' base_prefix name (array_subscripts)? (class_modification)? comment
| IDENT '=' 'enumeration' '(' ((enum_list)? | ':') ')' comment
;
der_class_specifier
: IDENT '=' 'der' '(' name ',' IDENT (',' IDENT)* ')' comment
;
base_prefix
: type_prefix
;
enum_list
: enumeration_literal (',' enumeration_literal)*
;
enumeration_literal
: IDENT comment
;
composition
: element_list (
'public' element_list
| 'protected' element_list
| equation_section
| algorithm_section
)* ('external' (language_specification)? (external_function_call)? (annotation)? ';')? (
annotation ';'
)?
;
language_specification
: STRING
;
external_function_call
: (component_reference '=')? IDENT '(' (expression_list)? ')'
;
element_list
: (element ';')*
;
element
: import_clause
| extends_clause
| ('redeclare')? ('final')? ('inner')? ('outer')? (
(class_definition | component_clause)
| 'replaceable' (class_definition | component_clause) (constraining_clause comment)?
)
;
import_clause
: 'import' (IDENT '=' name | name '.*' | name '.{' import_list '}' | name) comment
;
import_list
: IDENT (',' IDENT)*
;
extends_clause
: 'extends' name (class_modification)? (annotation)?
;
constraining_clause
: 'constrainedby' name (class_modification)?
;
component_clause
: type_prefix type_specifier (array_subscripts)? component_list
;
type_prefix
: ('flow' | 'stream')? ('discrete' | 'parameter' | 'constant')? ('input' | 'output')?
;
type_specifier
: name
;
component_list
: component_declaration (',' component_declaration)*
;
component_declaration
: declaration (condition_attribute)? comment
;
condition_attribute
: 'if' expression
;
declaration
: IDENT (array_subscripts)? (modification)?
;
modification
: class_modification ('=' expression)?
| '=' expression
| ':=' expression
;
class_modification
: '(' (argument_list)? ')'
;
argument_list
: argument (',' argument)*
;
argument
: element_modification_or_replaceable
| element_redeclaration
;
element_modification_or_replaceable
: ('each')? ('final')? (element_modification | element_replaceable)
;
element_modification
: name (modification)? string_comment
;
element_redeclaration
: 'redeclare' ('each')? ('final')? (
(short_class_definition | component_clause1)
| element_replaceable
)
;
element_replaceable
: 'replaceable' (short_class_definition | component_clause1) (constraining_clause)?
;
component_clause1
: type_prefix type_specifier component_declaration1
;
component_declaration1
: declaration comment
;
short_class_definition
: class_prefixes short_class_specifier
;
equation_section
: ('initial')? 'equation' (equation ';')*
;
algorithm_section
: ('initial')? 'algorithm' (statement ';')*
;
equation
: (
simple_expression '=' expression
| if_equation
| for_equation
| connect_clause
| when_equation
| name function_call_args
) comment
;
statement
: (
component_reference (':=' expression | function_call_args)
| '(' output_expression_list ')' ':=' component_reference function_call_args
| 'break'
| 'return'
| if_statement
| for_statement
| while_statement
| when_statement
) comment
;
if_equation
: 'if' expression 'then' (equation ';')* ('elseif' expression 'then' (equation ';')*)* (
'else' (equation ';')*
)? 'end' 'if'
;
if_statement
: 'if' expression 'then' (statement ';')* ('elseif' expression 'then' (statement ';')*)* (
'else' (statement ';')*
)? 'end' 'if'
;
for_equation
: 'for' for_indices 'loop' (equation ';')* 'end' 'for'
;
for_statement
: 'for' for_indices 'loop' (statement ';')* 'end' 'for'
;
for_indices
: for_index (',' for_index)*
;
for_index
: IDENT ('in' expression)?
;
while_statement
: 'while' expression 'loop' (statement ';')* 'end' 'while'
;
when_equation
: 'when' expression 'then' (equation ';')* ('elsewhen' expression 'then' (equation ';')*)* 'end' 'when'
;
when_statement
: 'when' expression 'then' (statement ';')* ('elsewhen' expression 'then' (statement ';')*)* 'end' 'when'
;
connect_clause
: 'connect' '(' component_reference ',' component_reference ')'
;
expression
: simple_expression
| 'if' expression 'then' expression ('elseif' expression 'then' expression)* 'else' expression
;
simple_expression
: logical_expression (':' logical_expression (':' logical_expression)?)?
;
logical_expression
: logical_term ('or' logical_term)*
;
logical_term
: logical_factor ('and' logical_factor)*
;
logical_factor
: ('not')? relation
;
relation
: arithmetic_expression (rel_op arithmetic_expression)?
;
rel_op
: '<'
| '<='
| '>'
| '>='
| '=='
| '<>'
;
arithmetic_expression
: (add_op)? term (add_op term)*
;
add_op
: '+'
| '-'
| '.+'
| '.-'
;
term
: factor (mul_op factor)*
;
mul_op
: '*'
| '/'
| '.*'
| './'
;
factor
: primary (('^' | '.^') primary)?
;
primary
: UNSIGNED_NUMBER
| STRING
| 'false'
| 'true'
| (name | 'der' | 'initial') function_call_args
| component_reference
| '(' output_expression_list ')'
| '[' expression_list (';' expression_list)* ']'
| '{' function_arguments '}'
| 'end'
;
name
: ('.')? IDENT ('.' IDENT)*
;
component_reference
: ('.')? IDENT (array_subscripts)? ('.' IDENT (array_subscripts)?)*
;
function_call_args
: '(' (function_arguments)? ')'
;
function_arguments
: function_argument (',' function_arguments | 'for' for_indices)?
| named_arguments
;
named_arguments
: named_argument (',' named_arguments)?
;
named_argument
: IDENT '=' function_argument
;
function_argument
: 'function' name '(' (named_arguments)? ')'
| expression
;
output_expression_list
: (expression)? (',' (expression)?)*
;
expression_list
: expression (',' expression)*
;
array_subscripts
: '[' subscript_ (',' subscript_)* ']'
;
subscript_
: ':'
| expression
;
comment
: string_comment (annotation)?
;
string_comment
: (STRING ('+' STRING)*)?
;
annotation
: 'annotation' class_modification
;
IDENT
: NONDIGIT (DIGIT | NONDIGIT)*
| Q_IDENT
;
fragment Q_IDENT
: '\'' (Q_CHAR | S_ESCAPE) (Q_CHAR | S_ESCAPE)* '\''
;
fragment S_CHAR
: ~ ["\\]
;
fragment NONDIGIT
: '_'
| 'a' .. 'z'
| 'A' .. 'Z'
;
STRING
: '"' (S_CHAR | S_ESCAPE)* '"'
;
fragment Q_CHAR
: NONDIGIT
| DIGIT
| '!'
| '#'
| '$'
| '%'
| '&'
| '('
| ')'
| '*'
| '+'
| ','
| '-'
| '.'
| '/'
| ':'
| ';'
| '<'
| '>'
| '='
| '?'
| '@'
| '['
| ']'
| '^'
| '{'
| '}'
| '|'
| '~'
;
fragment S_ESCAPE
: '\\' ('’' | '\'' | '"' | '?' | '\\' | 'a' | 'b' | 'f' | 'n' | 'r' | 't' | 'v')
;
fragment DIGIT
: '0' .. '9'
;
fragment UNSIGNED_INTEGER
: DIGIT (DIGIT)*
;
UNSIGNED_NUMBER
: UNSIGNED_INTEGER ('.' (UNSIGNED_INTEGER)?)? (('e' | 'E') ('+' | '-')? UNSIGNED_INTEGER)?
;
WS
: [ \r\n\t]+ -> channel (HIDDEN)
;
COMMENT
: '/*' .*? '*/' -> channel (HIDDEN)
;
LINE_COMMENT
: '//' ~[\r\n]* -> channel (HIDDEN)
;
\ No newline at end of file
This diff is collapsed.
Click to expand it.
src/parse_modelica.py
0 → 100644
+
81
−
0
View file @
3d88a29d
# This parses a Modelica model to extract its components (variables and parameters) and their parameters.
# It uses the ANTLR-generated lexer and parser to build a parse tree and then walks the tree to extract relevant information.
import
sys
import
os
from
antlr4
import
*
# Import lexer, parser, and listener generated by ANTLR for Modelica grammar.
from
modelicaLexer
import
modelicaLexer
from
modelicaParser
import
modelicaParser
from
modelicaListener
import
modelicaListener
# Listener class to extract components and their parameters from the parse tree
class
ModelicaFeatureExtractor
(
modelicaListener
):
def
__init__
(
self
):
self
.
components
=
[]
# List to store extracted components
# Method called when entering a component clause in the parse tree
def
enterComponent_clause
(
self
,
ctx
:
modelicaParser
.
Component_clauseContext
):
# Extract the component type and name
type_prefix
=
ctx
.
type_prefix
().
getText
()
if
ctx
.
type_prefix
()
else
""
component_type
=
type_prefix
+
"
"
+
ctx
.
type_specifier
().
getText
()
print
(
f
"
Component type:
{
component_type
}
"
)
# Iterate over each component declaration in the component list
for
component
in
ctx
.
component_list
().
component_declaration
():
component_name
=
component
.
declaration
().
IDENT
().
getText
()
# print(f"Component name: {component_name}") ## uncomment for debugging
parameters
=
{}
# Dictionary to store parameters and their values
# Check if there are any modifications (initial values or other modifications)
if
component
.
declaration
().
modification
()
is
not
None
:
modification
=
component
.
declaration
().
modification
()
param_value
=
self
.
get_modification_value
(
modification
)
if
param_value
is
not
None
:
parameters
[
component_name
]
=
param_value
# Store the parameter value
# print(f"Param: {component_name} = {param_value}") uncomment for debugging
# Add the component to the list
self
.
components
.
append
((
component_type
,
component_name
,
parameters
))
# Helper method to extract the value from a modification context
def
get_modification_value
(
self
,
modification_ctx
):
if
modification_ctx
is
None
:
return
None
if
modification_ctx
.
expression
():
# Direct value assignment
return
modification_ctx
.
expression
().
getText
()
elif
modification_ctx
.
class_modification
():
class_mod
=
modification_ctx
.
class_modification
()
# Class modification
if
class_mod
.
argument_list
()
is
not
None
:
values
=
[]
for
argument
in
class_mod
.
argument_list
().
argument
():
if
hasattr
(
argument
,
'
element_modification
'
):
element_mod
=
argument
.
element_modification
()
param_name
=
element_mod
.
name
().
getText
()
param_value
=
self
.
get_modification_value
(
element_mod
.
modification
())
values
.
append
(
f
"
{
param_name
}
=
{
param_value
}
"
)
return
"
({})
"
.
format
(
"
,
"
.
join
(
values
))
return
None
# Function to parse a Modelica file and extract components
def
parse_model
(
file_name
):
input_stream
=
FileStream
(
file_name
,
encoding
=
'
utf-8
'
)
# Read the file
lexer
=
modelicaLexer
(
input_stream
)
# Tokenize the input
stream
=
CommonTokenStream
(
lexer
)
# Create a token stream
parser
=
modelicaParser
(
stream
)
# Create a parser
tree
=
parser
.
stored_definition
()
# Parse the input into a parse tree
extractor
=
ModelicaFeatureExtractor
()
# Create a listener
walker
=
ParseTreeWalker
()
# Create a parse tree walker
walker
.
walk
(
extractor
,
tree
)
# Walk the parse tree with the listener
return
extractor
.
components
# Return the extracted components
if
__name__
==
"
__main__
"
:
file_name
=
'
SimpleHeatingSystem.mo
'
components
=
parse_model
(
file_name
)
# Parse the file and extract components
for
component
in
components
:
print
(
component
)
# Print the extracted components
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment