Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parser improvements #22

Merged
merged 39 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2a980d9
add MLStyle
jClugstor Mar 12, 2024
12a773c
parse changes
jClugstor Mar 15, 2024
59a5780
AST for arithmetic expressions working
jClugstor Mar 19, 2024
6113c0b
logical expressions and ranges
jClugstor Mar 19, 2024
52c3d34
add if expressions
jClugstor Mar 20, 2024
14c4772
add spc to parameter equation
jClugstor Mar 21, 2024
907d02f
get ready for arrays and records
jClugstor Mar 27, 2024
3fd4e60
array subscripts, component clauses added to AST
jClugstor Apr 1, 2024
6de51af
Component reference, parameter equations, when equations
jClugstor Apr 2, 2024
6d8aaf6
When equations and for equations working
jClugstor Apr 4, 2024
eccf379
compositions starting to parse
jClugstor Apr 5, 2024
64bdd9d
create evaluator file
jClugstor Apr 25, 2024
59e01a6
equations now work in compositions
jClugstor Apr 25, 2024
8dfed31
change how equations get evaluated
jClugstor May 2, 2024
482c6c2
change parsing for type prefix and add component clause evaluator
jClugstor May 3, 2024
6cd4dfe
package and model evaluation
jClugstor May 6, 2024
9705d91
function call parsing
jClugstor May 7, 2024
35e0dda
Merge branch 'SciML:main' into parser_improvements
jClugstor Jun 4, 2024
2143add
derivative parse fix
jClugstor Jun 4, 2024
6820254
fix model evaluation, change expr eval
jClugstor Jun 25, 2024
d60daba
add compat, fix things to allow tests
jClugstor Jun 25, 2024
13dd939
fix tests, update
jClugstor Jun 25, 2024
d8de1ae
fix tests
jClugstor Jun 25, 2024
ccc13c6
redundant BMWhen
jClugstor Jun 26, 2024
40f21e5
redundant BMNEQ
jClugstor Jun 26, 2024
1366697
redundant function
jClugstor Jun 26, 2024
2f34e43
formatting
jClugstor Jun 26, 2024
a658b00
test format
jClugstor Jun 26, 2024
fd47fd3
format
jClugstor Jun 27, 2024
f81de66
testset changes
jClugstor Jun 28, 2024
3290d4b
format
jClugstor Jun 28, 2024
b663aec
test comment
jClugstor Jun 28, 2024
b85b7c2
test groups
jClugstor Jun 28, 2024
2af1732
add comment and run ci
jClugstor Jun 29, 2024
091a3fe
format
jClugstor Jul 9, 2024
a2d3ab5
fix ci?
jClugstor Jul 9, 2024
e6ff110
actually fix CI
jClugstor Jul 9, 2024
7075c5c
format
jClugstor Jul 13, 2024
eadf96e
add comment
jClugstor Jul 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/Tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,16 @@ concurrency:
jobs:
tests:
name: "Tests"
strategy:
fail-fast: false
matrix:
group:
- Core
- Quality
version:
- '1'
uses: "SciML/.github/.github/workflows/tests.yml@v1"
with:
group: "${{ matrix.group }}"
secrets: "inherit"

8 changes: 5 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
name = "BaseModelica"
uuid = "a17d5099-185d-4ff5-b5d3-51aa4569e56d"
authors = ["jClugstor <jadonclugston@gmail.com> and contributors"]
version = "1.0.0"
version = "1.1.0"

[deps]
MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078"
ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78"
ParserCombinator = "fae87a5f-d1ad-5cf0-8f61-c941e1580b46"

[compat]
Aqua = "0.8"
ModelingToolkit = "8.75, 9"
MLStyle = "0.4.17"
ModelingToolkit = "9"
ParserCombinator = "2"
SafeTestsets = "0.1"
Test = "1.10"
julia = "1.10"
ParserCombinator = "2"

[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@
[![ColPrac: Contributor's Guide on Collaborative Practices for Community Packages](https://img.shields.io/badge/ColPrac-Contributor%27s%20Guide-blueviolet)](https://github.com/SciML/ColPrac)
[![SciML Code Style](https://img.shields.io/static/v1?label=code%20style&message=SciML&color=9558b2&labelColor=389826)](https://github.com/SciML/SciMLStyle)


A parser for the [Base Modelica](https://github.com/modelica/ModelicaSpecification/tree/MCP/0031/RationaleMCP/0031) format. Contains utilities to parse Base Modelica model files in to Julia objects, and to convert Base Modelica models to [ModelingToolkit](https://docs.sciml.ai/ModelingToolkit/stable/) models.

So far only very simple Base Modelica models are supported. Only models with real parameters, real variables, and equations consisting of simple arithmetic equations and first order derivatives are supported. Support for the rest of the BaseModelica specification is planned to be added in the future.
So far only very simple Base Modelica models are supported. Only models with real parameters, real variables, and equations consisting of simple arithmetic equations and first order derivatives are supported. Support for the rest of the BaseModelica specification is planned to be added in the future.

## Installation

Expand All @@ -25,6 +24,7 @@ Pkg.add("BaseModelica");
```

# Example

A Base Modelica model is in the file `ExampleFirstOrder.mo`. Inside of the file is a Base Modelica model specifying a simple first order linear differential equation:

```
Expand Down
55 changes: 3 additions & 52 deletions src/BaseModelica.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,11 @@ module BaseModelica

using ModelingToolkit
using ParserCombinator

"""
Holds the name of the package, the models in the package, and eventually BaseModelica records.
"""
struct BaseModelicaPackage
name::Any
model::Any
end

"""
Represents a BaseModelica model.
"""
struct BaseModelicaModel
name::Any
description::Any
parameters::Any
variables::Any
equations::Any
initialequations::Any
end

struct BaseModelicaParameter
type::Any
name::Any
value::Any
description::Any
end

struct BaseModelicaVariable
type::Any
name::Any
input_or_output::Any
description::Any
end

struct BaseModelicaEquation
lhs::Any
rhs::Any
description::Any
end

struct BaseModelicaInitialEquation
lhs::Any
rhs::Any
description::Any
end

# needed to parse derivatives in equations correctly
@variables t
der = Differential(t)
using MLStyle

#Includes
include("parser.jl")
include("conversion.jl")
include("evaluator.jl")
"""
parse_basemodelica(filename::String)::ODESystem

Expand All @@ -69,7 +20,7 @@ parse_basemodelica("testfiles/NewtonCoolingBase.mo")
"""
function parse_basemodelica(filename::String)
package = parse_file(filename)
baseModelica_to_ModelingToolkit(package.model)
baseModelica_to_ModelingToolkit(package)
end

export parse_basemodelica
Expand Down
49 changes: 0 additions & 49 deletions src/conversion.jl

This file was deleted.

154 changes: 154 additions & 0 deletions src/evaluator.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# function to convert "AST" to ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as D

@data BaseModelicaRuntimeTypes begin
RTRecord()
RTClass()
RTFunction()
#built in classes
RTReal()
RTInteger()
RTBoolean()
RTString()
end

function eval_AST(expr::BaseModelicaExpr)
let f = eval_AST
@match expr begin
BaseModelicaNumber(val) => val
BaseModelicaFactor(base, exp) => (f(base))^f(exp)
BaseModelicaSum(left, right) => (f(left)) + (f(right))
BaseModelicaMinus(left, right) => f(left) - f(right)
BaseModelicaProd(left, right) => f(left) * f(right)
BaseModelicaDivide(left, right) => f(left) / f(right)
BaseModelicaNot(relation) => !(f(relation))
BaseModelicaAnd(left, right) => f(left) && f(right)
BaseModelicaOr(left, right) => f(left) || f(right)
BaseModelicaLEQ(left, right) => f(left) <= f(right)
BaseModelicaGEQ(left, right) => f(left) >= f(right)
BaseModelicaLessThan(left, right) => f(left) < f(right)
BaseModelicaGreaterThan(left, right) => f(left) > f(right)
BaseModelicaEQ(left, right) => f(left) == f(right)
BaseModelicaNEQ(left, right) => f(left) != f(right)
_ => nothing
end
end
end

include("maps.jl")

function eval_AST(eq::BaseModelicaInitialEquation)
inner_eq = eq.equation.equation
Dict(eval_AST(inner_eq.lhs) => eval_AST(inner_eq.rhs))
end

function eval_AST(eq::BaseModelicaAnyEquation)
equation = eval_AST(eq.equation)
description = eq.description
return equation
end

function eval_AST(eq::BaseModelicaSimpleEquation)
lhs = eval_AST(eq.lhs)
rhs = eval_AST(eq.rhs)
lhs ~ rhs
end

function eval_AST(component::BaseModelicaComponentClause)
#this mutates a dict
#place holder to get simple equations working
#also needs to account for "modifications"
#also doesn't handle constants yet
list = component.component_list
type_prefix = component.type_prefix.dpc
declaration = list[1].declaration
name = Symbol(declaration.ident[1].name)
if type_prefix == "parameter"
variable_map[name] = only(@parameters($name))
parameter_val_map[variable_map[name]] = declaration.modification[1].expr[1].val
return variable_map[name]
elseif isnothing(type_prefix)
variable_map[name] = only(@variables($name(t)))
end
end

function eval_AST(model::BaseModelicaModel)
class_specifier = model.long_class_specifier
model_name = class_specifier.name
description = class_specifier.description

composition = class_specifier.composition

components = composition.components
equations = composition.equations
initial_equations = composition.initial_equations

#vars = [eval_AST(comp) for comp in components if comp.type_prefix.dpc != "parameter"]
#pars = [eval_AST(comp) for comp in components if comp.type_prefix.dpc == "parameter"]

# this loop populates the variable_map
vars = Num[]
pars = Num[]
for comp in components
name = Symbol(comp.component_list[1].declaration.ident[1].name)

eval_AST(comp)

if comp.type_prefix.dpc == "parameter" || comp.type_prefix.dpc == "constant"
push!(pars, variable_map[name])
else
push!(vars, variable_map[name])
end
end

eqs = [eval_AST(eq) for eq in equations]

#vars_and_pars = merge(Dict(vars .=> vars), Dict(pars .=> pars))
#println(vars_and_pars)
#eqs = [substitute(x,vars_and_pars) for x in eqs]

init_eqs = [eval_AST(eq) for eq in initial_equations]
init_eqs_dict = Dict()

# quick and dumb kind of
for dictionary in init_eqs
for (key, value) in dictionary
init_eqs_dict[key] = value
end
end
for (key, value) in init_eqs_dict
init_eqs_dict[key] = substitute(value, parameter_val_map)
end

#vars,pars,eqs, init_eqs_dict

defaults = merge(init_eqs_dict, parameter_val_map)
@named model = ODESystem(eqs, t, vars, pars; defaults)
structural_simplify(model)
end

function eval_AST(package::BaseModelicaPackage)
model = package.model
eval_AST(model)
end

function eval_AST(function_args::BaseModelicaFunctionArgs)
args = function_args.args
eval_AST.([args...])
end

function eval_AST(function_call::BaseModelicaFunctionCall)
function_name = Symbol(function_call.func_name)
args = eval_AST(function_call.args)
function_map[function_name](args)
end

function eval_AST(comp_reference::BaseModelicaComponentReference)
#will need to eventually account for array references and dot references...
#for now only does direct references to variables
return variable_map[Symbol(comp_reference.ref_list[1].name)]
end

function baseModelica_to_ModelingToolkit(package::BaseModelicaPackage)
eval_AST(package)
end
14 changes: 14 additions & 0 deletions src/maps.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# holds functions predefined or defined in the Base Modelica Package
function_map = Dict(
:der => x -> D(x...),
:abs => x -> Base.abs(x...),
:sin => x -> Base.sin(x...)
)

# holds variables, populated by evaluating component_clause
variable_map = Dict()

# holds parameter values, default values
parameter_val_map = Dict()

initial_value_map = Dict()
Loading
Loading