From ab5942a25a88b38463822406ccd9b5aba90f1dd3 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Fri, 4 Mar 2022 20:04:15 +0100 Subject: [PATCH 1/8] Nicer print of @showModel --- src/ModelCollections.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ModelCollections.jl b/src/ModelCollections.jl index bfd19e0..46ece10 100644 --- a/src/ModelCollections.jl +++ b/src/ModelCollections.jl @@ -83,7 +83,9 @@ function showModel(m::OrderedDict, level=0) end println(" "^level, "]") elseif k != :_class - println(" "^level, k, " = ", stringifyDefinition(v), ",") + #println(" "^level, k, " = ", stringifyDefinition(v), ",") + print(" "^level, k, " = ") + showModel(v,level) end end println(" "^(level-1), "),") From 50ae82a4cdd0a2b24743e0510a3793ac05ebed9e Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Fri, 4 Mar 2022 20:04:45 +0100 Subject: [PATCH 2/8] Remove empty hierarchies in mappedParameters --- src/ModiaLang.jl | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ModiaLang.jl b/src/ModiaLang.jl index 79c4b73..16b8129 100644 --- a/src/ModiaLang.jl +++ b/src/ModiaLang.jl @@ -291,14 +291,16 @@ prependDict(dict, prefix) = OrderedDict([prepend(k, prefix) => prepend(v, prefix function mergeModelStructures(parent::ModelStructure, child::ModelStructure, prefix) - merge!(parent.parameters, child.parameters) - parent.mappedParameters[prefix] = child.mappedParameters + if length(child.mappedParameters) > 0 + merge!(parent.parameters, child.parameters) + parent.mappedParameters[prefix] = child.mappedParameters - merge!(parent.init, child.init) - parent.mappedParameters[prefix] = child.mappedParameters + merge!(parent.init, child.init) + parent.mappedParameters[prefix] = child.mappedParameters - merge!(parent.start, child.start) - parent.mappedParameters[prefix] = child.mappedParameters + merge!(parent.start, child.start) + parent.mappedParameters[prefix] = child.mappedParameters + end merge!(parent.variables, child.variables) merge!(parent.flows, child.flows) From 2c0159fdca4b15e5588f57fa2a3d127339586d37 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Fri, 4 Mar 2022 20:06:19 +0100 Subject: [PATCH 3/8] Hide result only if hideResult=true --- src/ModelCollections.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ModelCollections.jl b/src/ModelCollections.jl index 46ece10..f566a10 100644 --- a/src/ModelCollections.jl +++ b/src/ModelCollections.jl @@ -548,7 +548,7 @@ function flattenModelTuple!(model, modelStructure, modelName, to; unitless = fal if :_outer in keys(v) && v[:_outer] push!(modelStructure.equations, :($k = $(prepend(k, :up)))) end - if :hideResult in keys(v) + if :hideResult in keys(v) && v[:hideResult] == true push!(modelStructure.hideResults, subMod) end elseif isCollection(v) # || typeof(v) == Symbol # instantiate From 5457cd3ce3ae25fc3f87bfeafe80e5823085ff2d Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 6 Mar 2022 08:28:02 +0100 Subject: [PATCH 4/8] New function Modia.unitAsString(unitOfQuantity); see Unitful issue 412 (https://github.com/PainterQubits/Unitful.jl/issues/412). --- src/Modia.jl | 31 +++++++++++++++++++++++++++++++ src/ModiaLang.jl | 5 +---- test/TestUnitAsString.jl | 17 +++++++++++++++++ test/include_all.jl | 1 + 4 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 test/TestUnitAsString.jl diff --git a/src/Modia.jl b/src/Modia.jl index 70ad4ea..7e6e62f 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -111,6 +111,37 @@ The function is defined as: `stripUnit(v) = ustrip.(upreferred.(v))`. """ stripUnit(v) = ustrip.(upreferred.(v)) + +""" + str = unitAsString( unitOfQuantity::Unitful.FreeUnits ) + +Return a string representation of the unit of a quantity that can be used in a unit string macro +(see also Unitful [issue 412](https://github.com/PainterQubits/Unitful.jl/issues/412)). + +# Example +``` +v1 = 2.0u"m/s" +v1_unit = unitAsString( unit(v1) ) # = "m*s^-1" +v2_withoutUnit = 2.0 +code = :( \$v2_withoutUnit@u_str(\$v1_unit) ) # = 2.0u"m*s^-1" +v2 = eval(code) +@show v1 +@show v1_unit +@show v2 +``` + +# Notes +Transforms unit to string representation that is parseable again +(see also Unitful [issue 412](https://github.com/PainterQubits/Unitful.jl/issues/412)). +This implementation is a hack and only works in common cases. +Implementation is performed in the following way: + +1. Transform to string and display exponents on units not as Unicode superscripts (= default on macOS). +2. Replace " " by "*", since Unitful removes "*" when converting to string. +""" +unitAsString(unitOfQuantity::Unitful.FreeUnits) = replace(repr(unitOfQuantity,context = Pair(:fancy_exponent,false)), " " => "*") + + include("EquationAndStateInfo.jl") include("StateSelection.jl") diff --git a/src/ModiaLang.jl b/src/ModiaLang.jl index 16b8129..1e48db3 100644 --- a/src/ModiaLang.jl +++ b/src/ModiaLang.jl @@ -552,10 +552,7 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod @assert all([un[i] == un[1] for i in 2:length(un)]) "The unit of all elements of state vector must be equal: $var::$(value)" un = un[1] end - # Transform unit to string representation that is parseable again (see also https://github.com/PainterQubits/Unitful.jl/issues/412): - # - Display exponents on units not as superscripts (= default on macOS) - # - Replace " " by "*", since Unitful removes "*" when converting to string - return replace(repr(un,context = Pair(:fancy_exponent,false)), " " => "*") + return unitAsString(un) end function var_startInitFixed(v_original) diff --git a/test/TestUnitAsString.jl b/test/TestUnitAsString.jl new file mode 100644 index 0000000..5e5fd1b --- /dev/null +++ b/test/TestUnitAsString.jl @@ -0,0 +1,17 @@ +module TestUnitAsString + +using Modia +using Test + +v1 = 2.0u"m/s" +unit_v1 = unit(v1) +v1_unit = Modia.unitAsString( unit_v1 ) # = "m*s^-1" +v2_withoutUnit = 2.0 +code = :( $v2_withoutUnit*@u_str($v1_unit) ) # = 2.0u"m*s^-1" +v2 = eval(code) +@show v1 +@show v1_unit +@show v2 + +@test v1==v2 +end \ No newline at end of file diff --git a/test/include_all.jl b/test/include_all.jl index 429ef40..e004bc6 100644 --- a/test/include_all.jl +++ b/test/include_all.jl @@ -2,6 +2,7 @@ import Modia import Modia.Test Test.@testset "Test basic functionality" begin + include("TestUnitAsString.jl") include("TestVariables.jl") include("TestFirstOrder.jl") include("TestFirstOrder2.jl") From e877c5fb7a45e1993b7b39180568378072100689 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 6 Mar 2022 14:43:19 +0100 Subject: [PATCH 5/8] Rotational.jl: Change some Int to Float64 values, because errors occured in some situations. --- models/Rotational.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/Rotational.jl b/models/Rotational.jl index d1596de..214ff4d 100644 --- a/models/Rotational.jl +++ b/models/Rotational.jl @@ -61,7 +61,7 @@ PartialCompliant = Model( # Linear 1D rotational spring Spring = PartialCompliant | Model( c = 1.0u"N*m/rad", # (min = 0, info = "Spring constant") - phi_rel0 = 0u"rad", # (info = "Unstretched spring angle") + phi_rel0 = 0.0u"rad", # (info = "Unstretched spring angle") equations = :[ tau = c * (phi_rel - phi_rel0) ] ) @@ -70,7 +70,7 @@ Spring = PartialCompliant | Model( SpringDamper = PartialCompliant | Model( c = 1.0*u"N*m/rad", # (min = 0, info = "Spring constant") d = 0.0u"N*m*s/rad", # (info = "Damping constant") - phi_rel0 = 0u"rad", # (info = "Unstretched spring angle") + phi_rel0 = 0.0u"rad", # (info = "Unstretched spring angle") equations = :[ tau = c * (phi_rel - phi_rel0) + d * der(phi_rel) ] ) From c5355c214707a8407dd7e754ed5ea75e7e3a3d14 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 6 Mar 2022 14:46:18 +0100 Subject: [PATCH 6/8] New option @instantiateModel(..., saveCodeOnFile="", ...) to store the generated code on file. --- src/ModiaLang.jl | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/ModiaLang.jl b/src/ModiaLang.jl index 1e48db3..777eef6 100644 --- a/src/ModiaLang.jl +++ b/src/ModiaLang.jl @@ -433,7 +433,7 @@ end function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelModule, buildDict, FloatType, TimeType, init, start, inputs, outputs, vEliminated, vProperty, unknownsWithEliminated, mappedParameters, hideResults; - unitless=false, logStateSelection=false, logCode=false, logExecution=false, logCalculations=false, logTiming=false, evaluateParameters=false) + unitless=false, logStateSelection=false, logCode=false, logExecution=false, logCalculations=false, logTiming=false, evaluateParameters=false, saveCodeOnFile="") (unknowns, equations, G, Avar, Bequ, assign, blt, parameters) = modStructure Goriginal = deepcopy(G) function getSolvedEquationAST(e, v) @@ -703,6 +703,13 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod # generatedFunction = @RuntimeGeneratedFunction(modelModule, code) #getDerivatives = Core.eval(modelModule, code) + if saveCodeOnFile != "" + println(" Save generated code on file ", joinpath(pwd(), saveCodeOnFile)) + open(saveCodeOnFile, "w") do io + print(io, replace(sprint(show,code), r"( *#= .*=#\n)|(#= .*=#)" => "")) + end + end + if logTiming println("eval code") @time @timeit to "eval(code)" Core.eval(modelModule, code) @@ -845,7 +852,7 @@ end """ modelInstance = @instantiateModel(model; FloatType = Float64, aliasReduction=true, unitless=false, - evaluateParameters=false, log=false, logModel=false, logDetails=false, logStateSelection=false, + evaluateParameters=false, saveCodeOnFile="", log=false, logModel=false, logDetails=false, logStateSelection=false, logCode=false,logExecution=logExecution, logCalculations=logCalculations, logTiming=false) Instantiates a model, i.e. performs structural and symbolic transformations and generates a function for calculation of derivatives suitable for simulation. @@ -855,6 +862,7 @@ Instantiates a model, i.e. performs structural and symbolic transformations and * `aliasReduction`: Perform alias elimination and remove singularities * `unitless`: Remove units (useful while debugging models and needed for MonteCarloMeasurements) * `evaluateParameters`: Use evaluated parameters in the generated code. +* `saveCodeOnFile`: If non-empty string, save generated code in file with name `saveCodeOnFile`. * `log`: Log the different phases of translation * `logModel`: Log the variables and equations of the model * `logDetails`: Log internal data during the different phases of translation @@ -879,7 +887,7 @@ See documentation of macro [`@instantiateModel`] """ function instantiateModel(model; modelName="", modelModule=nothing, source=nothing, FloatType = Float64, aliasReduction=true, unitless=false, log=false, logModel=false, logDetails=false, logStateSelection=false, logCode=false, - logExecution=logExecution, logCalculations=logCalculations, logTiming=false, evaluateParameters=false) + logExecution=logExecution, logCalculations=logCalculations, logTiming=false, evaluateParameters=false, saveCodeOnFile="") #try # model = JSONModel.cloneModel(model, expressionsAsStrings=false) println("\nInstantiating model $modelName\n in module: $modelModule\n in file: $source") @@ -1057,7 +1065,7 @@ function instantiateModel(model; modelName="", modelModule=nothing, source=nothi if ! experimentalTranslation inst = stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelModule, buildDict, FloatType, TimeType, modelStructure.init, modelStructure.start, modelStructure.inputs, modelStructure.outputs, vEliminated, vProperty, unknownsWithEliminated, modelStructure.mappedParameters, modelStructure.hideResults; - unitless, logStateSelection, logCode, logExecution, logCalculations, logTiming, evaluateParameters) + unitless, logStateSelection, logCode, logExecution, logCalculations, logTiming, evaluateParameters, saveCodeOnFile) else interface[:equations] = modStructure[:equations] return interface From ed70050ea9ee4e7a711281e42c3031afb3f0ab68 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 6 Mar 2022 22:12:25 +0100 Subject: [PATCH 7/8] Various improvements --- Manifest.toml | 162 ++++++++++++++++++++------------------- Project.toml | 41 +++++----- docs/src/index.md | 42 ++++++++++ examples/ServoSystem.jl | 16 ++-- src/CodeGeneration.jl | 38 ++++++--- src/JSONModel.jl | 34 +++++++- src/Modia.jl | 27 ++++++- src/ModiaLang.jl | 15 ++-- src/Symbolic.jl | 140 +++++++++++++++++++++++++++++++++ test/TestUnitAsString.jl | 112 +++++++++++++++++++++++++-- test/include_all.jl | 2 +- 11 files changed, 497 insertions(+), 132 deletions(-) create mode 100644 src/Symbolic.jl diff --git a/Manifest.toml b/Manifest.toml index f4ce02d..8d14d26 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -44,9 +44,9 @@ uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" [[deps.BitTwiddlingConvenienceFunctions]] deps = ["Static"] -git-tree-sha1 = "5e98d6a6aa92e5758c4d58501b7bf23732699fa3" +git-tree-sha1 = "28bbdbf0354959db89358d1d79d421ff31ef0b5e" uuid = "62783981-4cbd-42fc-bca8-16325de8dc4b" -version = "0.1.2" +version = "0.1.3" [[deps.BoundaryValueDiffEq]] deps = ["BandedMatrices", "DiffEqBase", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "NLsolve", "Reexport", "SparseArrays"] @@ -60,10 +60,10 @@ uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" version = "0.4.1" [[deps.CPUSummary]] -deps = ["Hwloc", "IfElse", "Static"] -git-tree-sha1 = "849799453de85b55e78550fc7b0c8f442eb497ab" +deps = ["Hwloc", "IfElse", "Preferences", "Static"] +git-tree-sha1 = "2283583c451e880ec11c7fd693613434fb5ffa74" uuid = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" -version = "0.1.8" +version = "0.1.12" [[deps.Calculus]] deps = ["LinearAlgebra"] @@ -85,9 +85,9 @@ version = "0.1.2" [[deps.CloseOpenIntervals]] deps = ["ArrayInterface", "Static"] -git-tree-sha1 = "03dc838350fbd448fca0b99285ed4d60fc229b72" +git-tree-sha1 = "f576084239e6bdf801007c80e27e2cc2cd963fe0" uuid = "fb6a15b2-703c-40df-9091-08a04967cfa9" -version = "0.1.5" +version = "0.1.6" [[deps.CommonSolve]] git-tree-sha1 = "68a0743f578349ada8bc911a5cbd5a2ef6ed6d1f" @@ -123,9 +123,9 @@ version = "4.1.1" [[deps.DEDataArrays]] deps = ["ArrayInterface", "DocStringExtensions", "LinearAlgebra", "RecursiveArrayTools", "SciMLBase", "StaticArrays"] -git-tree-sha1 = "31186e61936fbbccb41d809ad4338c9f7addf7ae" +git-tree-sha1 = "5e5f8f363c8c9a2415ef9185c4e0ff6966c87d52" uuid = "754358af-613d-5f8d-9788-280bf1605d4c" -version = "0.2.0" +version = "0.2.2" [[deps.DataAPI]] git-tree-sha1 = "cc70b17275652eb47bc9e5f81635981f13cea5c8" @@ -155,9 +155,9 @@ uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" [[deps.DelayDiffEq]] deps = ["ArrayInterface", "DataStructures", "DiffEqBase", "LinearAlgebra", "Logging", "NonlinearSolve", "OrdinaryDiffEq", "Printf", "RecursiveArrayTools", "Reexport", "UnPack"] -git-tree-sha1 = "ceb3463f2913eec2f0af5f0d8e1386fb546fdd32" +git-tree-sha1 = "9b50344853bd81a1a22bfe290781d538f4790244" uuid = "bcd4f6db-9728-5f36-b5f7-82caef46ccdb" -version = "5.34.0" +version = "5.35.0" [[deps.DelimitedFiles]] deps = ["Mmap"] @@ -171,21 +171,21 @@ version = "0.4.0" [[deps.DiffEqBase]] deps = ["ArrayInterface", "ChainRulesCore", "DEDataArrays", "DataStructures", "Distributions", "DocStringExtensions", "FastBroadcast", "ForwardDiff", "FunctionWrappers", "IterativeSolvers", "LabelledArrays", "LinearAlgebra", "Logging", "MuladdMacro", "NonlinearSolve", "Parameters", "PreallocationTools", "Printf", "RecursiveArrayTools", "RecursiveFactorization", "Reexport", "Requires", "SciMLBase", "Setfield", "SparseArrays", "StaticArrays", "Statistics", "SuiteSparse", "ZygoteRules"] -git-tree-sha1 = "433291c9e63dcfc1a0e42c6aeb6bb5d3e5ab1789" +git-tree-sha1 = "0dee26eff5f7a4ab0381f43281c9734354ddc93d" uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" -version = "6.81.4" +version = "6.82.0" [[deps.DiffEqCallbacks]] deps = ["DataStructures", "DiffEqBase", "ForwardDiff", "LinearAlgebra", "NLsolve", "OrdinaryDiffEq", "Parameters", "RecipesBase", "RecursiveArrayTools", "SciMLBase", "StaticArrays"] -git-tree-sha1 = "e57ecaf9f7875714c164ccca3c802711589127cf" +git-tree-sha1 = "c4b99e3a199e293e7290eea94ba89364d47ee557" uuid = "459566f4-90b8-5000-8ac3-15dfb0a30def" -version = "2.20.1" +version = "2.22.0" [[deps.DiffEqJump]] deps = ["ArrayInterface", "Compat", "DataStructures", "DiffEqBase", "FunctionWrappers", "Graphs", "LinearAlgebra", "PoissonRandom", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "StaticArrays", "TreeViews", "UnPack"] -git-tree-sha1 = "e30f058eb600407e3fd4ea082e2527e3a3671238" +git-tree-sha1 = "eec5fd03c26dadc6b20f84d815309d060358e95b" uuid = "c894b116-72e5-5b58-be3c-e6d8d4ac2b12" -version = "8.2.1" +version = "8.3.0" [[deps.DiffEqNoiseProcess]] deps = ["DiffEqBase", "Distributions", "LinearAlgebra", "Optim", "PoissonRandom", "QuadGK", "Random", "Random123", "RandomNumbers", "RecipesBase", "RecursiveArrayTools", "Requires", "ResettableStacks", "SciMLBase", "StaticArrays", "Statistics"] @@ -239,15 +239,15 @@ uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" [[deps.DualNumbers]] deps = ["Calculus", "NaNMath", "SpecialFunctions"] -git-tree-sha1 = "84f04fe68a3176a583b864e492578b9466d87f1e" +git-tree-sha1 = "90b158083179a6ccbce2c7eb1446d5bf9d7ae571" uuid = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74" -version = "0.6.6" +version = "0.6.7" [[deps.ExponentialUtilities]] -deps = ["ArrayInterface", "LinearAlgebra", "Printf", "Requires", "SparseArrays"] -git-tree-sha1 = "3e1289d9a6a54791c1ee60da0850f4fd71188da6" +deps = ["ArrayInterface", "LinearAlgebra", "Printf", "Requires", "SparseArrays", "libblastrampoline_jll"] +git-tree-sha1 = "b026981973ccbe38682fbb4ccb0732fd6b1e1207" uuid = "d4d017d3-3776-5f7e-afef-a10c40355c18" -version = "1.11.0" +version = "1.13.0" [[deps.ExprTools]] git-tree-sha1 = "56559bbef6ca5ea0c0818fa5c90320398a6fbf8d" @@ -256,9 +256,9 @@ version = "0.1.8" [[deps.FastBroadcast]] deps = ["LinearAlgebra", "Polyester", "Static"] -git-tree-sha1 = "0f8ef5dcb040dbb9edd98b1763ac10882ee1ff03" +git-tree-sha1 = "f39bcc05eb0dcbd2c0195762df7a5737041289b9" uuid = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -version = "0.1.12" +version = "0.1.14" [[deps.FastClosures]] git-tree-sha1 = "acebe244d53ee1b461970f8910c235b259e772ef" @@ -273,9 +273,9 @@ version = "0.12.8" [[deps.FiniteDiff]] deps = ["ArrayInterface", "LinearAlgebra", "Requires", "SparseArrays", "StaticArrays"] -git-tree-sha1 = "ec299fdc8f49ae450807b0cb1d161c6b76fd2b60" +git-tree-sha1 = "56956d1e4c1221000b7781104c58c34019792951" uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" -version = "2.10.1" +version = "2.11.0" [[deps.Formatting]] deps = ["Printf"] @@ -306,9 +306,9 @@ version = "1.6.0" [[deps.HostCPUFeatures]] deps = ["BitTwiddlingConvenienceFunctions", "IfElse", "Libdl", "Static"] -git-tree-sha1 = "3965a3216446a6b020f0d48f1ba94ef9ec01720d" +git-tree-sha1 = "18be5268cf415b5e27f34980ed25a7d34261aa83" uuid = "3e5b6fbb-0976-4d2c-9146-d79de83f2fb0" -version = "0.1.6" +version = "0.1.7" [[deps.Hwloc]] deps = ["Hwloc_jll"] @@ -389,9 +389,9 @@ version = "0.3.0" [[deps.Krylov]] deps = ["LinearAlgebra", "Printf", "SparseArrays"] -git-tree-sha1 = "6333cc5b848295895f3b23eb763d020fc8e05867" +git-tree-sha1 = "a024280a69c49f51ba29d2deb66f07508f0b9b49" uuid = "ba0b0d4f-ebba-5204-a429-3ac8c609bfb7" -version = "0.7.12" +version = "0.7.13" [[deps.KrylovKit]] deps = ["LinearAlgebra", "Printf"] @@ -401,15 +401,21 @@ version = "0.5.3" [[deps.LabelledArrays]] deps = ["ArrayInterface", "ChainRulesCore", "LinearAlgebra", "MacroTools", "StaticArrays"] -git-tree-sha1 = "3e6a4c07ea78db18f885e474c7de466ce257de85" +git-tree-sha1 = "fbd884a02f8bf98fd90c53c1c9d2b21f9f30f42a" uuid = "2ee39098-c373-598a-b85f-a56591580800" -version = "1.7.3" +version = "1.8.0" [[deps.LayoutPointers]] deps = ["ArrayInterface", "LinearAlgebra", "ManualMemory", "SIMDTypes", "Static"] -git-tree-sha1 = "6dd77ee76188b0365f7d882d674b95796076fa2c" +git-tree-sha1 = "b651f573812d6c36c22c944dd66ef3ab2283dfa1" uuid = "10f19ff3-798f-405d-979b-55457f8fc047" -version = "0.1.5" +version = "0.1.6" + +[[deps.LevyArea]] +deps = ["LinearAlgebra", "Random", "SpecialFunctions"] +git-tree-sha1 = "56513a09b8e0ae6485f34401ea9e2f31357958ec" +uuid = "2d8b4e74-eb68-11e8-0fb9-d5eb67b50637" +version = "1.0.0" [[deps.LibCURL]] deps = ["LibCURL_jll", "MozillaCACerts_jll"] @@ -442,9 +448,9 @@ uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" [[deps.LinearSolve]] deps = ["ArrayInterface", "DocStringExtensions", "IterativeSolvers", "KLU", "Krylov", "KrylovKit", "LinearAlgebra", "RecursiveFactorization", "Reexport", "Requires", "SciMLBase", "Setfield", "SparseArrays", "SuiteSparse", "UnPack"] -git-tree-sha1 = "f27bb8e4eabdb93ed3703c55025b111e045ffe81" +git-tree-sha1 = "a25bc80647e44d0e1e1694b47000603497700b18" uuid = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" -version = "1.12.0" +version = "1.13.0" [[deps.LogExpFunctions]] deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] @@ -457,9 +463,9 @@ uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" [[deps.LoopVectorization]] deps = ["ArrayInterface", "CPUSummary", "ChainRulesCore", "CloseOpenIntervals", "DocStringExtensions", "ForwardDiff", "HostCPUFeatures", "IfElse", "LayoutPointers", "LinearAlgebra", "OffsetArrays", "PolyesterWeave", "SIMDDualNumbers", "SLEEFPirates", "SpecialFunctions", "Static", "ThreadingUtilities", "UnPack", "VectorizationBase"] -git-tree-sha1 = "534aa24fae56f5f0956134d8789ab30d6fe2f615" +git-tree-sha1 = "077c7c9d746cbe30ac5f001ea4c1277f64cc5dad" uuid = "bdcacae8-1622-11e9-2a5c-532679323890" -version = "0.12.102" +version = "0.12.103" [[deps.MacroTools]] deps = ["Markdown", "Random"] @@ -482,9 +488,9 @@ uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" [[deps.Measurements]] deps = ["Calculus", "LinearAlgebra", "Printf", "RecipesBase", "Requires"] -git-tree-sha1 = "58390f5617544fb09d27244749484fee0cae6712" +git-tree-sha1 = "88cd033eb781c698e75ae0b680e5cef1553f0856" uuid = "eff96d63-e80a-5855-80a2-b1b0885c5ab7" -version = "2.7.0" +version = "2.7.1" [[deps.Missings]] deps = ["DataAPI"] @@ -497,9 +503,9 @@ uuid = "a63ad114-7e13-5084-954f-fe012c677804" [[deps.ModiaBase]] deps = ["DataFrames", "DiffRules", "Measurements", "MonteCarloMeasurements", "OrderedCollections", "StaticArrays", "Unitful"] -git-tree-sha1 = "4562d56ff6b2fe5b78ef0995e478e8b734e24f2a" +git-tree-sha1 = "57f347bcda8e96732d3f0c2e3a162383fedbeeff" uuid = "ec7bf1ca-419d-4510-bbab-199861c55244" -version = "0.10.0" +version = "0.11.0" [[deps.ModiaResult]] deps = ["DataFrames", "Measurements", "MonteCarloMeasurements", "OrderedCollections", "Pkg", "Tables", "Unitful"] @@ -509,9 +515,9 @@ version = "0.4.1" [[deps.MonteCarloMeasurements]] deps = ["Distributed", "Distributions", "LinearAlgebra", "MacroTools", "Random", "RecipesBase", "Requires", "SLEEFPirates", "StaticArrays", "Statistics", "StatsBase", "Test"] -git-tree-sha1 = "bce0a32d6c64165388eec2573b68000ed06f39c1" +git-tree-sha1 = "03619e255664666b352a5e5f6b45e8b00d439870" uuid = "0987c9cc-fe09-11e8-30f0-b96dd679fdca" -version = "1.0.7" +version = "1.0.8" [[deps.MozillaCACerts_jll]] uuid = "14a3606d-f60d-562e-9121-12d972cd8159" @@ -543,9 +549,9 @@ uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" [[deps.NonlinearSolve]] deps = ["ArrayInterface", "FiniteDiff", "ForwardDiff", "IterativeSolvers", "LinearAlgebra", "RecursiveArrayTools", "RecursiveFactorization", "Reexport", "SciMLBase", "Setfield", "StaticArrays", "UnPack"] -git-tree-sha1 = "b61c51cd5b9d8b197dfcbbf2077a0a4e1505278d" +git-tree-sha1 = "4e5ee038e5655c8aaa9ac179743c5227d1f0f0f3" uuid = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" -version = "0.3.14" +version = "0.3.15" [[deps.OffsetArrays]] deps = ["Adapt"] @@ -579,10 +585,10 @@ uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" version = "1.4.1" [[deps.OrdinaryDiffEq]] -deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DocStringExtensions", "ExponentialUtilities", "FastClosures", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "LinearSolve", "Logging", "LoopVectorization", "MacroTools", "MuladdMacro", "NLsolve", "NonlinearSolve", "Polyester", "PreallocationTools", "RecursiveArrayTools", "Reexport", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] -git-tree-sha1 = "df82fa0f9f90f669cc3cf9e3f0400e431e0704ac" +deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DocStringExtensions", "ExponentialUtilities", "FastClosures", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "LinearSolve", "Logging", "LoopVectorization", "MacroTools", "MuladdMacro", "NLsolve", "NonlinearSolve", "Polyester", "PreallocationTools", "RecursiveArrayTools", "Reexport", "SciMLBase", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] +git-tree-sha1 = "d8f30cac5f1d2bf3b9c0012c2f078d850c804ef1" uuid = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -version = "6.6.6" +version = "6.7.0" [[deps.PDMats]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] @@ -598,9 +604,9 @@ version = "0.12.3" [[deps.Parsers]] deps = ["Dates"] -git-tree-sha1 = "13468f237353112a01b2d6b32f3d0f80219944aa" +git-tree-sha1 = "85b5da0fa43588c75bb1ff986493443f821c70b7" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.2.2" +version = "2.2.3" [[deps.Pkg]] deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] @@ -614,15 +620,15 @@ version = "0.4.0" [[deps.Polyester]] deps = ["ArrayInterface", "BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "ManualMemory", "PolyesterWeave", "Requires", "Static", "StrideArraysCore", "ThreadingUtilities"] -git-tree-sha1 = "2232d3865bc9a098e664f69cbe340b960d48217f" +git-tree-sha1 = "ad769d3f29cffb33380ab28318a10c1ccb19c827" uuid = "f517fe37-dbe3-4b94-8317-1923a5111588" -version = "0.6.6" +version = "0.6.7" [[deps.PolyesterWeave]] deps = ["BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "Static", "ThreadingUtilities"] -git-tree-sha1 = "dc11fa882240c43a875b48e21e6423704927d12f" +git-tree-sha1 = "7e597df97e46ffb1c8adbaddfa56908a7a20194b" uuid = "1d0040c9-8b98-4ee7-8388-3f51789ca0ad" -version = "0.1.4" +version = "0.1.5" [[deps.PooledArrays]] deps = ["DataAPI", "Future"] @@ -638,9 +644,9 @@ version = "0.2.4" [[deps.PreallocationTools]] deps = ["Adapt", "ArrayInterface", "ForwardDiff", "LabelledArrays"] -git-tree-sha1 = "e4cb8d4a2edf9b3804c1fb2c2de57d634ff3f36e" +git-tree-sha1 = "6c138c8510111fa47b5d2ed8ada482d97e279bee" uuid = "d236fae5-4411-538c-8e31-a6e3d9e00b46" -version = "0.2.3" +version = "0.2.4" [[deps.Preferences]] deps = ["TOML"] @@ -673,10 +679,10 @@ deps = ["SHA", "Serialization"] uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [[deps.Random123]] -deps = ["Libdl", "Random", "RandomNumbers"] -git-tree-sha1 = "0e8b146557ad1c6deb1367655e052276690e71a3" +deps = ["Random", "RandomNumbers"] +git-tree-sha1 = "afeacaecf4ed1649555a19cb2cad3c141bbc9474" uuid = "74087812-796a-5b5d-8853-05524746bad3" -version = "1.4.2" +version = "1.5.0" [[deps.RandomNumbers]] deps = ["Random", "Requires"] @@ -691,9 +697,9 @@ version = "1.2.1" [[deps.RecursiveArrayTools]] deps = ["Adapt", "ArrayInterface", "ChainRulesCore", "DocStringExtensions", "FillArrays", "LinearAlgebra", "RecipesBase", "Requires", "StaticArrays", "Statistics", "ZygoteRules"] -git-tree-sha1 = "736699f42935a2b19b37a6c790e2355ca52a12ee" +git-tree-sha1 = "b66df9b4f668b340a6b6b8a7e667a68f586c5561" uuid = "731186ca-8d62-57ce-b412-fbd966d074cd" -version = "2.24.2" +version = "2.25.0" [[deps.RecursiveFactorization]] deps = ["LinearAlgebra", "LoopVectorization", "Polyester", "StrideArraysCore", "TriangularSolve"] @@ -746,15 +752,15 @@ version = "0.1.0" [[deps.SLEEFPirates]] deps = ["IfElse", "Static", "VectorizationBase"] -git-tree-sha1 = "61a96d8b89083a53fb2b745f3b59a05359651bbe" +git-tree-sha1 = "d4c366b135fc2e1af7a000473e08edc5afd94819" uuid = "476501e8-09a2-5ece-8869-fb82de89a1fa" -version = "0.6.30" +version = "0.6.31" [[deps.SciMLBase]] deps = ["ArrayInterface", "CommonSolve", "ConstructionBase", "Distributed", "DocStringExtensions", "IteratorInterfaceExtensions", "LinearAlgebra", "Logging", "RecipesBase", "RecursiveArrayTools", "StaticArrays", "Statistics", "Tables", "TreeViews"] -git-tree-sha1 = "8ff1bf96965b3878ca5d235752ff1daf519e7a26" +git-tree-sha1 = "c086056df381502621dc6b5f1d1a0a1c2d0185e7" uuid = "0bca4576-84f4-4d90-8ffe-ffa030f20462" -version = "1.26.3" +version = "1.28.0" [[deps.Serialization]] uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" @@ -841,16 +847,16 @@ uuid = "9672c7b4-1e72-59bd-8a11-6ac3964bc41f" version = "1.6.6" [[deps.StochasticDiffEq]] -deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DiffEqJump", "DiffEqNoiseProcess", "DocStringExtensions", "FillArrays", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "Logging", "MuladdMacro", "NLsolve", "OrdinaryDiffEq", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] -git-tree-sha1 = "5f88440e7470baad99f559eed674a46d2b6b96f7" +deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DiffEqJump", "DiffEqNoiseProcess", "DocStringExtensions", "FillArrays", "FiniteDiff", "ForwardDiff", "LevyArea", "LinearAlgebra", "Logging", "MuladdMacro", "NLsolve", "OrdinaryDiffEq", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] +git-tree-sha1 = "24d8b3ab7e91b351ccbed5e54499a1864a64a6c6" uuid = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0" -version = "6.44.0" +version = "6.45.0" [[deps.StrideArraysCore]] deps = ["ArrayInterface", "CloseOpenIntervals", "IfElse", "LayoutPointers", "ManualMemory", "Requires", "SIMDTypes", "Static", "ThreadingUtilities"] -git-tree-sha1 = "e0a02838565c4600ecd1d8874db8cfe263aaa6c7" +git-tree-sha1 = "49d616ef230fec080d02ada0ca5639e652cca06b" uuid = "7792a7ef-975c-4747-a70f-980b88e8d1da" -version = "0.2.12" +version = "0.2.13" [[deps.SuiteSparse]] deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] @@ -883,10 +889,10 @@ uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" version = "1.0.1" [[deps.Tables]] -deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"] -git-tree-sha1 = "bb1064c9a84c52e277f1096cf41434b675cd368b" +deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits", "Test"] +git-tree-sha1 = "5ce79ce186cc678bbb5c5681ca3379d1ddae11a1" uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" -version = "1.6.1" +version = "1.7.0" [[deps.Tar]] deps = ["ArgTools", "SHA"] @@ -916,9 +922,9 @@ version = "0.3.0" [[deps.TriangularSolve]] deps = ["CloseOpenIntervals", "IfElse", "LayoutPointers", "LinearAlgebra", "LoopVectorization", "Polyester", "Static", "VectorizationBase"] -git-tree-sha1 = "5cbc1a4551fcf8afe8f80bb4f1f13e3271ee2656" +git-tree-sha1 = "b8d08f55b02625770c09615d96927b3a8396925e" uuid = "d5829a12-d9aa-46ab-831f-fb7c9ab06edf" -version = "0.1.10" +version = "0.1.11" [[deps.UUIDs]] deps = ["Random", "SHA"] @@ -940,9 +946,9 @@ version = "1.11.0" [[deps.VectorizationBase]] deps = ["ArrayInterface", "CPUSummary", "HostCPUFeatures", "Hwloc", "IfElse", "LayoutPointers", "Libdl", "LinearAlgebra", "SIMDTypes", "Static"] -git-tree-sha1 = "e9a35d501b24c127af57ca5228bcfb806eda7507" +git-tree-sha1 = "1901efb08ce6c4526ddf7fdfa9181dc3593fe6a2" uuid = "3d5dd08c-fd9d-11e8-17fa-ed2836048c2f" -version = "0.21.24" +version = "0.21.25" [[deps.VertexSafeGraphs]] deps = ["Graphs"] diff --git a/Project.toml b/Project.toml index f1d49ed..8dca31a 100644 --- a/Project.toml +++ b/Project.toml @@ -1,8 +1,27 @@ +authors = ["Hilding Elmqvist ", "Martin Otter "] name = "Modia" uuid = "cb905087-75eb-5f27-8515-1ce0ec8e839e" -authors = ["Hilding Elmqvist ", "Martin Otter "] version = "0.8.2" +[compat] +DataFrames = "1" +DifferentialEquations = "7" +FiniteDiff = "2" +ForwardDiff = "0.10" +JSON = "0.21" +Measurements = "2" +ModiaBase = "0.11" +ModiaResult = "0.4.1" +MonteCarloMeasurements = "1" +OrderedCollections = "1" +RecursiveFactorization = "0.2" +Reexport = "1" +StaticArrays = "1" +Sundials = "4.4" +TimerOutputs = "0.5" +Unitful = "1" +julia = "1.7" + [deps] DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" @@ -25,21 +44,5 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" -[compat] -DataFrames = "1" -DifferentialEquations = "7" -FiniteDiff = "2" -ForwardDiff = "0.10" -JSON = "0.21" -Measurements = "2" -ModiaBase = "0.10" -ModiaResult = "0.4.1" -MonteCarloMeasurements = "1" -OrderedCollections = "1" -RecursiveFactorization = "0.2" -Reexport = "1" -StaticArrays = "1" -Sundials = "4.4" -TimerOutputs = "0.5" -Unitful = "1" -julia = "1.7" +[extras] +CPUSummary = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" diff --git a/docs/src/index.md b/docs/src/index.md index 4d23bc4..7c72713 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -38,8 +38,50 @@ functionalities of these packages. ### Version 0.8.2 +- New exported functions + - modelToJSON(model; expressionsAsStrings=true) + - JSONToModel(json) + - writeModel(filename, model; log=true) + - readModel(filename; log=true) + writeModel saves the model in JSON format on file and readModel reads the model from a JSON file. + +- `Modia/examples/ServoSystem.jl` enhanced, so that the hierarchical model with units is + first stored in JSON format on file, then the model is read from file, a parameter is modified, + and then the model is passed to @instantiateModel(..). + +- `@instantiateModel(...)`: + - `@instantiateModel(..., logCode=true, ...)` provides now correct unit type casts for scalars. + - `@instantiateModel(..., saveCodeOnFile=fileName, ...)` stores the generated code on file `fileName`. + - Automatically use `@instantiatedModel(..., unitless=true, ..)`, if `FloatType = MonteCarloMeasurements.XXX`, + because there are easily cases where this fails, if units are present. + +- `@showModel model`: Nicer pretty print if model is hierarchical. + +- New function `Modia.unitAsString(unitOfQuantity)`, + see Unitful issue 412 (https://github.com/PainterQubits/Unitful.jl/issues/412). + +- Remove empty hierarchies in model parameters (seen with `simulate!(..., logParameters=true)`). + - Memory allocation reduced if states or tearing variables are SVectors. +- Improved casting and checking of types in the generated code + (see new test model Modia/test/TestUnitAsString.jl). + +- Moved ModiaBase.Symbolic.makeDerVar from ModiaBase to Modia (because makeDerVar needs FloatType for + generating type-stable code and FloatType is available in Modia but not in ModiaBase). + +- Github actions workflow added for automatic tests on Linux/Windows/MacOS, for pull requests on main. + +**Bug fixes** + +- Fixed issue with unit on macOS (exponents had been displayed as Unicode superscripts when converting + the unit to a string, leading to errors in the further processing). + +- Hide result only if `Var(hideResult=true)` (previously, hideResult=false was treated as true). + +- `Modia/models/Rotational.jl`: Change some Int to Float64 values, because errors occured in some situations. + + ### Version 0.8.1 - Missing file Modia/test/TestLinearEquations.jl added. diff --git a/examples/ServoSystem.jl b/examples/ServoSystem.jl index 1b4ba75..5197a33 100644 --- a/examples/ServoSystem.jl +++ b/examples/ServoSystem.jl @@ -98,27 +98,31 @@ Servo = Model( TestServo = Model( - ks = 0.8, + ks = 0.4, Ts = 0.08u"s", ramp = Ramp | Map(duration=1.18u"s", height=2.95), servo = Servo | Map(ks=:(up.ks), Ts=:(up.Ts)), - load = Inertia | Map(J=170u"kg*m^2"), - equations =:[load.flange_b.tau = 0u"N*m"], + load = Inertia | Map(J=170.0u"kg*m^2"), + equations =:[load.flange_b.tau = 0.0u"N*m"], connect = :[ (ramp.y , servo.refSpeed) (servo.flange_b, load.flange_a) ] ) +file = joinpath(pwd(), "TestServo.json") +writeModel(file, TestServo) +TestServo = readModel(file) | Map(ks = 0.8) + plotVariables = [("ramp.y", "load.w") "servo.speedError.y"; "servo.gear.spring.phi_rel" "servo.motor.currentSensor.i"] -testServo1 = @instantiateModel(TestServo) +testServo1 = @instantiateModel(TestServo, saveCodeOnFile="TestServo.jl") println("Simulate") @time simulate!(testServo1, Tsit5(), stopTime=2.0, tolerance=1e-6, requiredFinalStates = [7.320842067204029, 9.346410309487013, 355.30389168655955, 2.792544498835712, 429.42665751348284, 311.7812493890421, 4.089776248793499, 2.969353608933471]) plot(testServo1, plotVariables, figure=1) - +#= println("\nServo with uncertainties") using Modia.Measurements TestServoWithUncertainties = TestServo | Map( @@ -139,6 +143,6 @@ TestServoWithMonteCarlo = TestServo | Map( testServo3 = @instantiateModel(TestServoWithMonteCarlo, FloatType = Modia.MonteCarloMeasurements.StaticParticles{Float64,nparticles}, unitless=true) @time simulate!(testServo3, Tsit5(), stopTime=2.0, tolerance=1e-6) plot(testServo3, plotVariables, figure=3) - +=# end diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 40da0f1..d9fdd8b 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -17,7 +17,15 @@ fieldnames(typeof(integrator)) = (:sol, :u, :du, :k, :t, :dt, :f, :p, :uprev, :u """ baseType(T) -Return the base type of a type T. +Return the base type of a type T, according to the following definition. + +```julia +baseType(::Type{T}) where {T} = T +baseType(::Type{Unitful.Quantity{T,D,U}}) where {T,D,U} = T +baseType(::Type{Measurements.Measurement{T}}) where {T} = T +baseType(::Type{MonteCarloMeasurements.Particles{T,N}}) where {T,N} = T +baseType(::Type{MonteCarloMeasurements.StaticParticles{T,N}}) where {T,N} = T +``` # Examples ``` @@ -25,13 +33,20 @@ baseType(Float32) # Float32 baseType(Measurement{Float64}) # Float64 ``` """ -baseType(::Type{T}) where {T} = T -baseType(::Type{Measurements.Measurement{T}}) where {T<:AbstractFloat} = T -baseType(::Type{MonteCarloMeasurements.Particles{T,N}}) where {T<:AbstractFloat,N} = T -baseType(::Type{MonteCarloMeasurements.StaticParticles{T,N}}) where {T<:AbstractFloat,N} = T +baseType(::Type{T}) where {T} = T +baseType(::Type{Unitful.Quantity{T,D,U}}) where {T,D,U} = T +baseType(::Type{Measurements.Measurement{T}}) where {T} = T +baseType(::Type{MonteCarloMeasurements.Particles{T,N}}) where {T,N} = T +baseType(::Type{MonteCarloMeasurements.StaticParticles{T,N}}) where {T,N} = T + +isQuantity( ::Type{T}) where {T} = T <: Unitful.Quantity || T <: MonteCarloMeasurements.AbstractParticles && baseType(T) <: Unitful.Quantity +isMeasurements( ::Type{T}) where {T} = T <: Measurements.Measurement || T <: Unitful.Quantity && baseType(T) <: Measurements.Measurement +isMonteCarloMeasurements(::Type{T}) where {T} = T <: MonteCarloMeasurements.AbstractParticles -Base.floatmax(::Type{MonteCarloMeasurements.Particles{T,N}}) where {T<:AbstractFloat,N} = Base.floatmax(T) -Base.floatmax(::Type{MonteCarloMeasurements.StaticParticles{T,N}}) where {T<:AbstractFloat,N} = Base.floatmax(T) +Base.floatmax(::Type{Unitful.Quantity{T,D,U}}) where {T,D,U} = Base.floatmax(T) +Base.floatmax(::Type{Measurements.Measurement{T}}) where {T} = Base.floatmax(T) +Base.floatmax(::Type{MonteCarloMeasurements.Particles{T,N}}) where {T,N} = Base.floatmax(T) +Base.floatmax(::Type{MonteCarloMeasurements.StaticParticles{T,N}}) where {T,N} = Base.floatmax(T) """ @@ -1528,7 +1543,7 @@ Symbol `functionName` as function name. By `eval(code)` or - `hasUnits::Bool`: = true, if variables have units. Note, the units of the state vector are defined in equationinfo. """ -function generate_getDerivatives!(AST::Vector{Expr}, equationInfo::Modia.EquationInfo, +function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equationInfo::Modia.EquationInfo, parameters, variables, previousVars, preVars, holdVars, functionName::Symbol; pre::Vector{Symbol} = Symbol[], hasUnits=false) @@ -1643,9 +1658,12 @@ function generate_getDerivatives!(AST::Vector{Expr}, equationInfo::Modia.Equatio end # Generate code of the function + # temporarily removed: _m.time = $TimeType(Modia.getValue(_time)) code = quote - function $functionName(_x, _m::Modia.SimulationModel{_FloatType,_TimeType}, _time)::Nothing where {_FloatType,_TimeType} - _m.time = _TimeType(Modia.getValue(_time)) + function $functionName(_x, _m::Modia.SimulationModel{$FloatType,$TimeType}, _time::$TimeType)::Nothing + _FloatType = $FloatType + _TimeType = $TimeType + _m.time = _time _m.nGetDerivatives += 1 instantiatedModel = _m _p = _m.evaluatedParameters diff --git a/src/JSONModel.jl b/src/JSONModel.jl index 17efe32..d483718 100644 --- a/src/JSONModel.jl +++ b/src/JSONModel.jl @@ -8,7 +8,7 @@ Encoding and decoding Modia models as JSON. """ module JSONModel -export modelToJSON, JSONToModel, cloneModel +export modelToJSON, JSONToModel, cloneModel, writeModel, readModel import JSON using Modia @@ -31,7 +31,7 @@ function encodeModel(model, expressionsAsStrings=true) Base.remove_linenums!(model) model = removeBlock(model) if typeof(model) <: Quantity - return Dict(:_value => ustrip.(model), :_unit=>string(unit(model))) + return Dict(:_value => ustrip.(model), :_unit=>Modia.unitAsString(unit(model))) elseif expressionsAsStrings && typeof(model) == Expr return Dict(:_Expr=>string(model)) elseif typeof(model) == Expr @@ -80,10 +80,10 @@ Encodes a model suitable to convert to a JSON string. function decodeModel(jModel) if typeof(jModel) <: AbstractDict && length(keys(jModel)) == 2 && "_value" in keys(jModel) && "_unit" in keys(jModel) unit = jModel["_unit"] - unit = replace(unit, ' ' => '*') # Workaround for https://github.com/PainterQubits/Unitful.jl/issues/391 + #unit = replace(unit, ' ' => '*') # Workaround for https://github.com/PainterQubits/Unitful.jl/issues/391 # Remove, since already correctly done in encodeModel(...) return jModel["_value"]*uparse(unit) elseif typeof(jModel) <: AbstractDict && length(keys(jModel)) == 1 && "_Expr" in keys(jModel) - return Meta.parse(jModel["_Expr"]) + return Base.remove_linenums!( Meta.parse(jModel["_Expr"]) ) # without remove_linenums!, there are errors later with if-expressions. elseif typeof(jModel) <: AbstractDict && length(keys(jModel)) == 1 && "_Symbol" in keys(jModel) return Symbol(jModel["_Symbol"]) elseif typeof(jModel) <: AbstractDict && length(keys(jModel)) == 2 && "head" in keys(jModel) && "args" in keys(jModel) @@ -122,6 +122,32 @@ function JSONToModel(json) end +""" + writeModel(filename::String, model; log=true) + +Write model in JSON format on file `filename`. +""" +function writeModel(filename::String, model::AbstractDict; log=true) + if log + println(" Write model in JSON format on file \"$filename\"") + end + write(filename, modelToJSON(model)) +end + + +""" + model = readModel(filename::AbstractString; log=true) + +Read a model that is stored in JSON format on file `filename` and return it. +""" +function readModel(filename::String; log=true) + if log + println(" Read model from JSON file \"$filename\"") + end + JSONToModel( read(filename,String) ) +end + + """ modelClone = cloneModel(model; expressionsAsStrings=true) diff --git a/src/Modia.jl b/src/Modia.jl index 7e6e62f..7842298 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.8.2" -const Date = "2022-03-04" +const Date = "2022-03-08" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") @@ -56,8 +56,7 @@ export get_xNames export registerExtraSimulateKeywordArguments export get_extraSimulateKeywordArgumentsDict - - +export modelToJSON, JSONToModel, writeModel, readModel import Sundials const CVODE_BDF = Sundials.CVODE_BDF @@ -141,6 +140,25 @@ Implementation is performed in the following way: """ unitAsString(unitOfQuantity::Unitful.FreeUnits) = replace(repr(unitOfQuantity,context = Pair(:fancy_exponent,false)), " " => "*") +""" + quantityType = quantity(numberType, numberUnit::Unitful.FreeUnits) + +Return the quantity type given the numberType and the numberUnit. + +# Example +```julia +mutable struct Data{FloatType <: AbstractFloat} + velocity::quantity(FloatType, u"m/s") +end + +v = Data{Float64}(2.0u"mm/s") +@show v # v = +``` +""" +quantity(numberType, numberUnit::Unitful.FreeUnits) = Quantity{numberType, dimension(numberUnit), typeof(numberUnit)} + +quantityTypes(::Type{Unitful.Quantity{T,D,U}}) where {T,D,U} = (T,D,U) + include("EquationAndStateInfo.jl") include("StateSelection.jl") @@ -155,6 +173,7 @@ include("SimulateAndPlot.jl") include("ReverseDiffInterface.jl") include("PathPlanning.jl") include("JSONModel.jl") +using .JSONModel # include("IncidencePlot.jl") # using .IncidencePlot @@ -162,7 +181,7 @@ include("JSONModel.jl") const drawIncidence = false - +include("Symbolic.jl") include("ModiaLang.jl") end \ No newline at end of file diff --git a/src/ModiaLang.jl b/src/ModiaLang.jl index 777eef6..08e2e28 100644 --- a/src/ModiaLang.jl +++ b/src/ModiaLang.jl @@ -457,7 +457,7 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod # solution = :(try $solution; catch e; println("Failure executing: ", $sol); printstyled(stderr,"ERROR: ", bold=true, color=:red); # printstyled(stderr,sprint(showerror,e), color=:light_red); println(stderr); end) end - solution = makeDerVar(solution, parameters, inputs, evaluateParameters) + solution = makeDerVar(solution, parameters, inputs, FloatType, evaluateParameters) if logCalculations var = string(unknowns[v]) solutionString = string(solution) @@ -475,7 +475,7 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod return nothing end if isexpr(lhs, :tuple) && all(a == 0 for a in lhs.args) || lhs == :(0) - eq_rhs = makeDerVar(:($rhs), parameters, inputs, evaluateParameters) + eq_rhs = makeDerVar(:($rhs), parameters, inputs, FloatType, evaluateParameters) if unitless eqs = eq_rhs else @@ -486,8 +486,8 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod # eq_lhs = makeDerVar(:($lhs), parameters, inputs, evaluateParameters) # eqs = :( ($eq_rhs .-= $eq_lhs) ) else - eq_rhs = makeDerVar(:($rhs), parameters, inputs, evaluateParameters) - eq_lhs = makeDerVar(:($lhs), parameters, inputs, evaluateParameters) + eq_rhs = makeDerVar(:($rhs), parameters, inputs, FloatType, evaluateParameters) + eq_lhs = makeDerVar(:($lhs), parameters, inputs, FloatType, evaluateParameters) if unitless eqs = :( $eq_rhs .- $eq_lhs ) else @@ -687,7 +687,7 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod if useNewCodeGeneration @timeit to "generate_getDerivativesNew!" code = generate_getDerivativesNew!(AST, newFunctions, modelModule, equationInfo, [:(_p)], vcat(:time, [Symbol(u) for u in unknowns]), previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) else - @timeit to "generate_getDerivatives!" code = generate_getDerivatives!(AST, equationInfo, [:(_p)], extraResults, previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) + @timeit to "generate_getDerivatives!" code = generate_getDerivatives!(FloatType, TimeType, AST, equationInfo, [:(_p)], extraResults, previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) end else # code = generate_getDerivatives!(AST, equationInfo, Symbol.(keys(parameters)), extraResults, :getDerivatives, hasUnits = !unitless) @@ -888,6 +888,11 @@ See documentation of macro [`@instantiateModel`] function instantiateModel(model; modelName="", modelModule=nothing, source=nothing, FloatType = Float64, aliasReduction=true, unitless=false, log=false, logModel=false, logDetails=false, logStateSelection=false, logCode=false, logExecution=logExecution, logCalculations=logCalculations, logTiming=false, evaluateParameters=false, saveCodeOnFile="") + if isMonteCarloMeasurements(FloatType) && !unitless + unitless=true + printstyled(" @instantiateModel(...,unitless=true, ..) set automatically, because\n FloatType=MonteCarloMeasurements often fails if units are involved.\n", color=:red) + end + #try # model = JSONModel.cloneModel(model, expressionsAsStrings=false) println("\nInstantiating model $modelName\n in module: $modelModule\n in file: $source") diff --git a/src/Symbolic.jl b/src/Symbolic.jl new file mode 100644 index 0000000..742e806 --- /dev/null +++ b/src/Symbolic.jl @@ -0,0 +1,140 @@ +# Moved from ModiaBase/src/Symbolic.jl, because dependent on FloatType that is only available in ModiaLang + +prependPar(ex, prefix, parameters=[], inputs=[]) = ex + +function prependPar(ex::Symbol, prefix, parameters=[], inputs=[]) + if prefix == nothing; ex elseif ex in [:time, :instantiatedModel, :_leq_mode, :_x]; ex else Expr(:ref, prefix, QuoteNode(ex)) end +end + +function prependPar(ex::Expr, prefix, parameters=[], inputs=[]) + if isexpr(ex, :.) + Expr(:ref, prependPar(ex.args[1], prefix, parameters, inputs), QuoteNode(ex.args[2].value)) + else + Expr(ex.head, [prependPar(arg, prefix, parameters, inputs) for arg in ex.args]...) + end +end + + + +function addCastAndTypeCheckBasicValueType(ex, value, FloatType) + # typeof(FloatType) is neither Measurements nor MonteCarloMeasurements + T = baseType(FloatType) + if isQuantity(typeof(value)) + ustr = unitAsString(unit(value)) + :( Modia.quantity($T, @u_str($ustr))($ex)::Modia.quantity($T, @u_str($ustr)) ) + else + :( $T($ex)::$T ) + end +end + + +""" + e = addCastAndTypeCheck(ex,value,FloatType) + +If `eltype(value) <: Number` add either + +1. RequiredType(ex)::RequiredType or +2. typeof(value)(ex)::typeof(value) + +If it is manageable, variant (1) is used and the type cast is made with respect to _FloatType. +This is done for scalars that are no Measurements and no MonteCarloMeasurements. +Otherwise, variant (2) is used. + +As a result, the generated code is type stable and does not work with Any types +(although the values are stored in an Any dictionary). +So the code will be more efficient and memory allocated at run-time will be reduced. +Furthermore, if value is a scalar that has a unit, the conversion includes also the conversion +to the unit used during code generation. + +Note, this function should only be used on parameter values. +""" +function addCastAndTypeCheck(ex,value,FloatType) + if eltype(value) <: Number + # Numeric scalar or array + valueType = typeof(value) + + if valueType <: Number + # Numeric scalar + T = baseType(FloatType) + if FloatType <: Measurements.Measurement + if isMeasurements(valueType) + if isQuantity(valueType) + ustr = unitAsString(unit(value)) + :( Modia.quantity(Modia.Measurements.Measurement{$T}, @u_str($ustr))($ex)::Modia.quantity(Modia.Measurements.Measurement{$T}, @u_str($ustr)) ) + else + :( Modia.Measurements.Measurement{$T}($ex)::Modia.Measurements.Measurement{$T} ) + end + else + addCastAndTypeCheckBasicValueType(ex,value,T) + end + + elseif FloatType <: MonteCarloMeasurements.AbstractParticles + if isMonteCarloMeasurements(valueType) + if isQuantity(valueType) + error("Error in Modia (MonteCarloMeasurements with Quantities appears - which is not supported.)") + else + :( ($ex)::$valueType ) + end + else + addCastAndTypeCheckBasicValueType(ex,value,T) + end + + else + # FloatType is neither Measurements nor MonteCarloMeasurements + addCastAndTypeCheckBasicValueType(ex,value,T) + end + else + # Numeric array + :( ($ex)::$valueType ) + end + else + # No numeric scalar or array + ex + end +end + +""" + e = makeDerVar(ex, parameters, inputs, FloatType, evaluateParameters=false) + +Recursively converts der(x) to Symbol(:(der(x))) in expression `ex` + +* `ex`: Expression or array of expressions +* `return `e`: ex with der(x) converted +""" +function makeDerVar(ex, parameters, inputs, FloatType, evaluateParameters=false) + if typeof(ex) in [Symbol, Expr] + if ex in keys(parameters) + addCastAndTypeCheck( prependPar(ex, :(_p), parameters, inputs), parameters[ex], FloatType ) + elseif ex in keys(inputs) + prependPar(ex, :(_p), parameters, inputs) + else + ex + end + else + ex + end +end + +function makeDerVar(ex::Expr, parameters, inputs, FloatType, evaluateParameters=false) + if ex.head == :call && ex.args[1] == :der + Symbol(ex) + elseif isexpr(ex, :.) && ex in keys(parameters) + if evaluateParameters + parameters[ex] + else + addCastAndTypeCheck( prependPar(ex, :(_p), parameters, inputs), parameters[ex], FloatType ) + end + elseif isexpr(ex, :.) && ex in keys(inputs) + if evaluateParameters + inputs[ex] + else + prependPar(ex, :(_p), parameters, inputs) + end + elseif ex.head == :. + Symbol(ex) + elseif ex.head == :call # Don't change dot-notation for function calls + Expr(ex.head, ex.args[1], [makeDerVar(arg, parameters, inputs, FloatType, evaluateParameters) for arg in ex.args[2:end]]...) + else + Expr(ex.head, [makeDerVar(arg, parameters, inputs, FloatType, evaluateParameters) for arg in ex.args]...) + end +end \ No newline at end of file diff --git a/test/TestUnitAsString.jl b/test/TestUnitAsString.jl index 5e5fd1b..a083f68 100644 --- a/test/TestUnitAsString.jl +++ b/test/TestUnitAsString.jl @@ -1,7 +1,10 @@ module TestUnitAsString -using Modia -using Test +using Modia +using Test +using Modia.Measurements +import Modia.MonteCarloMeasurements +import Modia.MonteCarloMeasurements.StaticParticles v1 = 2.0u"m/s" unit_v1 = unit(v1) @@ -9,9 +12,108 @@ v1_unit = Modia.unitAsString( unit_v1 ) # = "m*s^-1" v2_withoutUnit = 2.0 code = :( $v2_withoutUnit*@u_str($v1_unit) ) # = 2.0u"m*s^-1" v2 = eval(code) -@show v1 -@show v1_unit -@show v2 +#@show v1 +#@show v1_unit +#@show v2 @test v1==v2 + + +mutable struct Data{FloatType <: AbstractFloat} + velocity::Modia.quantity(FloatType, u"m/s") +end + +data = Data{Float64}(2.0u"mm/s") +v3 = data.velocity +#@show v3 # v3 = 0.002 m s^-1 + +@test Modia.unitAsString( unit(v3) ) == "m*s^-1" + + +v = 2.0 +@test typeof(v) <: AbstractFloat +@test Modia.baseType(typeof(v)) == Float64 +@test Modia.isQuantity( typeof(v)) == false +@test Modia.isMeasurements( typeof(v)) == false +@test Modia.isMonteCarloMeasurements(typeof(v)) == false +Base.floatmax(typeof(v)) + +v = 2.0u"m/s" +@test typeof(v) <: Unitful.Quantity +@test Modia.baseType(typeof(v)) == Float64 +@test Modia.isQuantity( typeof(v)) == true +@test Modia.isMeasurements( typeof(v)) == false +@test Modia.isMonteCarloMeasurements(typeof(v)) == false +Base.floatmax(typeof(v)) + + +### Measurements +v = 2.0 ± 0.1 +@test typeof(v) <: Measurements.Measurement +@test Modia.baseType(typeof(v)) == Float64 +@test Modia.isQuantity( typeof(v)) == false +@test Modia.isMeasurements( typeof(v)) == true +@test Modia.isMonteCarloMeasurements(typeof(v)) == false +Base.floatmax(typeof(v)) + +v = (2.0 ± 0.1)u"m/s" +@test typeof(v) <: Unitful.Quantity +@test Modia.baseType(typeof(v)) <: Measurements.Measurement +@test Modia.baseType(Modia.baseType(typeof(v))) == Float64 +@test Modia.isQuantity( typeof(v)) == true +@test Modia.isMeasurements( typeof(v)) == true +@test Modia.isMonteCarloMeasurements(typeof(v)) == false +Base.floatmax(typeof(v)) + + +### MonteCarloMeasurements +const nparticles = 100 +normal(mue,sigma) = StaticParticles(nparticles,MonteCarloMeasurements.Distributions.Normal(mue,sigma)) + +v = normal(2.0, 0.1) +@test typeof(v) <: Modia.MonteCarloMeasurements.AbstractParticles +@test Modia.baseType(typeof(v)) == Float64 +@test Modia.isQuantity( typeof(v)) == false +@test Modia.isMeasurements( typeof(v)) == false +@test Modia.isMonteCarloMeasurements(typeof(v)) == true +Base.floatmax(typeof(v)) + +v = normal(2.0, 0.1)u"m/s" +@test typeof(v) <: Modia.MonteCarloMeasurements.AbstractParticles +@test Modia.baseType(typeof(v)) <: Unitful.Quantity +@test Modia.baseType(Modia.baseType(typeof(v))) == Float64 +@test Modia.isQuantity( typeof(v)) == true +@test Modia.isMeasurements( typeof(v)) == false +@test Modia.isMonteCarloMeasurements(typeof(v)) == true +Base.floatmax(typeof(v)) + + +logCode = false + +FirstOrder1 = Model( + T = 0.2u"s", + k = 2.0, + x = Var(init=0.3), + equations = :[T * der(x) + x = k] +) +FirstOrder2 = FirstOrder1 | Map(k = 2.0u"m/s", x = Var(init = 0.3u"m/s")) +FirstOrder3 = FirstOrder1 | Map(k = 2.0 ± 0.1, x = Var(init = 0.3 ± 0.1)) +FirstOrder4 = FirstOrder1 | Map(k = (2.0 ± 0.1)u"m/s" , x = Var(init = (0.3 ± 0.1)u"m/s")) +FirstOrder5 = FirstOrder1 | Map(k = normal(2.0, 0.1/3), x = Var(init = normal(0.3, 0.1/3))) +FirstOrder6 = FirstOrder1 | Map(k = normal(2.0, 0.1/3)u"m/s", x = Var(init = normal(0.3, 0.1/3)u"m/s")) + +firstOrder1 = @instantiateModel(FirstOrder1, logCode=logCode) +firstOrder2 = @instantiateModel(FirstOrder2, logCode=logCode) +firstOrder3 = @instantiateModel(FirstOrder3, logCode=logCode, FloatType=Measurements.Measurement{Float64}) +firstOrder4 = @instantiateModel(FirstOrder4, logCode=logCode, FloatType=Measurements.Measurement{Float64}) +firstOrder5 = @instantiateModel(FirstOrder5, logCode=logCode, FloatType=StaticParticles{Float64,nparticles}) +firstOrder6 = @instantiateModel(FirstOrder6, logCode=logCode, FloatType=StaticParticles{Float64,nparticles}) + +simulate!(firstOrder1) +simulate!(firstOrder2) +simulate!(firstOrder3) +simulate!(firstOrder4) +simulate!(firstOrder5) +simulate!(firstOrder6) + end \ No newline at end of file diff --git a/test/include_all.jl b/test/include_all.jl index e004bc6..f21a7f4 100644 --- a/test/include_all.jl +++ b/test/include_all.jl @@ -2,7 +2,6 @@ import Modia import Modia.Test Test.@testset "Test basic functionality" begin - include("TestUnitAsString.jl") include("TestVariables.jl") include("TestFirstOrder.jl") include("TestFirstOrder2.jl") @@ -16,6 +15,7 @@ end Test.@testset "Test units, uncertainties" begin + include("TestUnitAsString.jl") include("TestUnits.jl") include("TestUncertainties.jl") include("TestUnitsAndUncertainties.jl") From f6745f8e42ee92d15c1e9bee222467755363f987 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 6 Mar 2022 22:13:15 +0100 Subject: [PATCH 8/8] Minor improvement of release notes. --- docs/src/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/index.md b/docs/src/index.md index 7c72713..81db840 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -67,7 +67,7 @@ functionalities of these packages. - Improved casting and checking of types in the generated code (see new test model Modia/test/TestUnitAsString.jl). -- Moved ModiaBase.Symbolic.makeDerVar from ModiaBase to Modia (because makeDerVar needs FloatType for +- Moved ModiaBase.Symbolic.makeDerVar from ModiaBase to new file `Modia/src/Symbolic.jl` (because makeDerVar needs FloatType for generating type-stable code and FloatType is available in Modia but not in ModiaBase). - Github actions workflow added for automatic tests on Linux/Windows/MacOS, for pull requests on main.