From 30db2ac1c7c2deb7ed7b7a8ed03e3aaf3f6a5e07 Mon Sep 17 00:00:00 2001 From: Nestor Date: Thu, 31 Aug 2023 10:04:27 +0200 Subject: [PATCH 1/3] Initial commit. First few lines of mabl added. Compiles cleanly Signed-off-by: Nestor --- .../fmi2/api/mabl/variables/VariableCreatorFmi3Api.java | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/VariableCreatorFmi3Api.java diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/VariableCreatorFmi3Api.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/VariableCreatorFmi3Api.java new file mode 100644 index 00000000..ac49a5d9 --- /dev/null +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/VariableCreatorFmi3Api.java @@ -0,0 +1,2 @@ +package org.intocps.maestro.framework.fmi2.api.mabl.variables;public class VariableCreatorFmi3Api { +} From 2ea6d6a2c620b9efcc258b50b005349ae3b55a20 Mon Sep 17 00:00:00 2001 From: Nestor Date: Thu, 31 Aug 2023 10:12:36 +0200 Subject: [PATCH 2/3] First lines of mabl. Compiles Signed-off-by: Nestor --- .../fmi2/api/mabl/MablApiBuilder.java | 6 +- .../api/mabl/ModelDescriptionContext.java | 4 +- .../api/mabl/ModelDescriptionContext3.java | 27 +++ .../fmi2/api/mabl/scoping/ScopeFmi2Api.java | 2 +- .../variables/ComponentVariableFmi2Api.java | 3 - .../mabl/variables/FmuVariableFmi3Api.java | 43 ++--- .../variables/InstanceVariableFmi3Api.java | 5 + .../variables/VariableCreatorFmi3Api.java | 159 +++++++++++++++++- .../org/intocps/maestro/BuilderFmi3Test.java | 4 +- .../java/org/intocps/maestro/BuilderTest.java | 1 - .../fmi3/basic/basic1/fmi3_basic.mabl | 1 - .../org/intocps/maestro/typechecker/FMI3.mabl | 3 - 12 files changed, 226 insertions(+), 32 deletions(-) create mode 100644 frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/ModelDescriptionContext3.java create mode 100644 frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/InstanceVariableFmi3Api.java diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/MablApiBuilder.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/MablApiBuilder.java index c893fcc1..d4c83d2e 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/MablApiBuilder.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/MablApiBuilder.java @@ -508,9 +508,13 @@ public void defaultInPStm(PStm node) throws AnalysisException { config.setName(newAIdentifier("FMI2")); //config.setConfig(StringEscapeUtils.escapeJava(simulationEnvironment.)); // unit.setFrameworkConfigs(Arrays.asList(config)); - unit.setImports(Stream.concat(Stream.of(newAIdentifier("FMI2")), importedModules.stream().map(MableAstFactory::newAIdentifier)) + + // TODO: added "import FMI3" after "import FMI2". Should probably figure out a smarter way to do this + unit.setImports(Stream.concat(Stream.of(newAIdentifier("FMI2")), + Stream.concat(Stream.of(newAIdentifier("FMI3")), importedModules.stream().map(MableAstFactory::newAIdentifier))) .collect(Collectors.toList())); + return unit; } diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/ModelDescriptionContext.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/ModelDescriptionContext.java index 03f0c440..b926d197 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/ModelDescriptionContext.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/ModelDescriptionContext.java @@ -1,6 +1,7 @@ package org.intocps.maestro.framework.fmi2.api.mabl; import org.intocps.maestro.fmi.Fmi2ModelDescription; +import org.intocps.maestro.fmi.org.intocps.maestro.fmi.fmi3.Fmi3ModelDescription; import javax.xml.xpath.XPathExpressionException; import java.lang.reflect.InvocationTargetException; @@ -20,8 +21,9 @@ public ModelDescriptionContext( this.valRefToSv.put(sv.valueReference, sv); }); } - public Fmi2ModelDescription getModelDescription() { return modelDescription; } } + + diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/ModelDescriptionContext3.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/ModelDescriptionContext3.java new file mode 100644 index 00000000..bfa39b0d --- /dev/null +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/ModelDescriptionContext3.java @@ -0,0 +1,27 @@ +package org.intocps.maestro.framework.fmi2.api.mabl; + +import kotlin.UInt; +import org.intocps.maestro.fmi.org.intocps.maestro.fmi.fmi3.Fmi3ModelDescription; + +import javax.xml.xpath.XPathExpressionException; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; + +public class ModelDescriptionContext3 { + + private final Fmi3ModelDescription modelDescription; + public Map nameToSv = new HashMap<>(); + public Map valRefToSv = new HashMap<>(); + public ModelDescriptionContext3( + Fmi3ModelDescription modelDescription) throws IllegalAccessException, XPathExpressionException, InvocationTargetException { + this.modelDescription = modelDescription; + modelDescription.getScalarVariables().forEach((sv) -> { + this.nameToSv.put(sv.getVariable().getName(), sv); + this.valRefToSv.put((long) 1, sv); //TODO: sv.getVariable().getValueReference() + }); + } + public Fmi3ModelDescription getModelDescription() { + return modelDescription; + } +} diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/ScopeFmi2Api.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/ScopeFmi2Api.java index 407b7924..3630fc7e 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/ScopeFmi2Api.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/ScopeFmi2Api.java @@ -498,7 +498,7 @@ public FmuVariableFmi2Api createFMU(String name, String loaderName, String... ar @Override public FmuVariableFmi3Api createFMU(String name, Fmi3ModelDescription modelDescription, URI path) throws Exception { - return null; + return VariableCreatorFmi3Api.createFMU(builder, builder.getNameGenerator(), builder.getDynamicScope(), name, modelDescription, path, this); } @Override diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/ComponentVariableFmi2Api.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/ComponentVariableFmi2Api.java index 87acf0fe..2531b162 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/ComponentVariableFmi2Api.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/ComponentVariableFmi2Api.java @@ -1242,14 +1242,11 @@ private ArrayVariableFmi2Api growBuffer(ArrayVariableFmi2Api buf @Override public Fmi2Builder.StateVariable getState() throws XPathExpressionException { - return getState(builder.getDynamicScope()); - } @Override public Fmi2Builder.StateVariable getState(Fmi2Builder.Scope scope) throws XPathExpressionException { - if (!this.modelDescriptionContext.getModelDescription().getCanGetAndSetFmustate()) { throw new RuntimeException("Unable to get state on fmu: " + this.getOwner() + " with instance name: " + this.getName()); } diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/FmuVariableFmi3Api.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/FmuVariableFmi3Api.java index d056455e..f5ad360b 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/FmuVariableFmi3Api.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/FmuVariableFmi3Api.java @@ -1,10 +1,12 @@ package org.intocps.maestro.framework.fmi2.api.mabl.variables; +import org.intocps.fmi.jnifmuapi.fmi3.Fmi3Instance; import org.intocps.maestro.ast.MableAstFactory; import org.intocps.maestro.ast.node.*; import org.intocps.maestro.framework.fmi2.api.Fmi2Builder; import org.intocps.maestro.framework.fmi2.api.mabl.MablApiBuilder; import org.intocps.maestro.framework.fmi2.api.mabl.ModelDescriptionContext; +import org.intocps.maestro.framework.fmi2.api.mabl.ModelDescriptionContext3; import org.intocps.maestro.framework.fmi2.api.mabl.PredicateFmi2Api; import org.intocps.maestro.framework.fmi2.api.mabl.scoping.IMablScope; import org.intocps.maestro.framework.fmi2.api.mabl.scoping.ScopeFmi2Api; @@ -15,29 +17,32 @@ import static org.intocps.maestro.ast.MableBuilder.newVariable; public class FmuVariableFmi3Api extends VariableFmi2Api> implements Fmi2Builder.Fmu3Variable { - public FmuVariableFmi3Api(PStm declaration, PType type, IMablScope declaredScope, Fmi2Builder.DynamicActiveScope dynamicScope, - PStateDesignator designator, PExp referenceExp) { +// public FmuVariableFmi3Api(PStm declaration, PType type, IMablScope declaredScope, Fmi2Builder.DynamicActiveScope dynamicScope, +// PStateDesignator designator, PExp referenceExp) { +// super(declaration, type, declaredScope, dynamicScope, designator, referenceExp); +// } + + + private final ModelDescriptionContext3 modelDescriptionContext; + private final MablApiBuilder builder; + private String fmuIdentifier; +// + public FmuVariableFmi3Api(String fmuIdentifier, MablApiBuilder builder, ModelDescriptionContext3 modelDescriptionContext, PStm declaration, + PType type, IMablScope declaredScope, Fmi2Builder.DynamicActiveScope dynamicScope, PStateDesignator designator, PExp referenceExp) { + this(builder, modelDescriptionContext, declaration, type, declaredScope, dynamicScope, designator, referenceExp); + this.fmuIdentifier = fmuIdentifier; + } + + + public FmuVariableFmi3Api(MablApiBuilder builder, ModelDescriptionContext3 modelDescriptionContext, PStm declaration, PType type, + IMablScope declaredScope, Fmi2Builder.DynamicActiveScope dynamicScope, PStateDesignator designator, PExp referenceExp) { super(declaration, type, declaredScope, dynamicScope, designator, referenceExp); + this.builder = builder; + this.modelDescriptionContext = modelDescriptionContext; } - // private final ModelDescriptionContext modelDescriptionContext; -// private final MablApiBuilder builder; -// private String fmuIdentifier; -// -// public FmuVariableFmi2Api(String fmuIdentifier, MablApiBuilder builder, ModelDescriptionContext modelDescriptionContext, PStm declaration, -// PType type, IMablScope declaredScope, Fmi2Builder.DynamicActiveScope dynamicScope, PStateDesignator designator, PExp referenceExp) { -// this(builder, modelDescriptionContext, declaration, type, declaredScope, dynamicScope, designator, referenceExp); -// this.fmuIdentifier = fmuIdentifier; -// } -// -// public FmuVariableFmi2Api(MablApiBuilder builder, ModelDescriptionContext modelDescriptionContext, PStm declaration, PType type, -// IMablScope declaredScope, Fmi2Builder.DynamicActiveScope dynamicScope, PStateDesignator designator, PExp referenceExp) { -// super(declaration, type, declaredScope, dynamicScope, designator, referenceExp); -// this.builder = builder; -// this.modelDescriptionContext = modelDescriptionContext; -// } // -// public ModelDescriptionContext getModelDescriptionContext() { +// public ModelDescriptionContext3 getModelDescriptionContext() { // return modelDescriptionContext; // } // diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/InstanceVariableFmi3Api.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/InstanceVariableFmi3Api.java new file mode 100644 index 00000000..9f2d45c6 --- /dev/null +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/InstanceVariableFmi3Api.java @@ -0,0 +1,5 @@ +package org.intocps.maestro.framework.fmi2.api.mabl.variables; + +public class InstanceVariableFmi3Api { + +} diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/VariableCreatorFmi3Api.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/VariableCreatorFmi3Api.java index ac49a5d9..b6db8eaa 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/VariableCreatorFmi3Api.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/VariableCreatorFmi3Api.java @@ -1,2 +1,159 @@ -package org.intocps.maestro.framework.fmi2.api.mabl.variables;public class VariableCreatorFmi3Api { +package org.intocps.maestro.framework.fmi2.api.mabl.variables; + +import org.intocps.fmi.IFmu; +import org.intocps.maestro.ast.MableAstFactory; +import org.intocps.maestro.ast.MableBuilder; +import org.intocps.maestro.ast.node.AErrorStm; +import org.intocps.maestro.ast.node.ALoadExp; +import org.intocps.maestro.ast.node.PStm; +import org.intocps.maestro.ast.node.PType; +import org.intocps.maestro.fmi.Fmi2ModelDescription; +import org.intocps.maestro.fmi.org.intocps.maestro.fmi.fmi3.Fmi3ModelDescription; +import org.intocps.maestro.framework.fmi2.FmuFactory; +import org.intocps.maestro.framework.fmi2.api.Fmi2Builder; +import org.intocps.maestro.framework.fmi2.api.mabl.*; +import org.intocps.maestro.framework.fmi2.api.mabl.scoping.DynamicActiveBuilderScope; +import org.intocps.maestro.framework.fmi2.api.mabl.scoping.IMablScope; +import org.intocps.maestro.framework.fmi2.api.mabl.scoping.ScopeFmi2Api; +import org.intocps.maestro.framework.fmi2.api.mabl.scoping.TryMaBlScope; + +import javax.xml.xpath.XPathExpressionException; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.function.Supplier; + +import static org.intocps.maestro.ast.MableAstFactory.*; +import static org.intocps.maestro.ast.MableBuilder.newVariable; + + +public class VariableCreatorFmi3Api { + + private final IMablScope scope; + private final MablApiBuilder builder; + + public VariableCreatorFmi3Api(IMablScope scope, MablApiBuilder builder) { + this.scope = scope; + this.builder = builder; + } + + + public static PType fmitypetomabltype(Fmi2ModelDescription.Types type) { + switch (type) { + case Boolean: + return newABoleanPrimitiveType(); + case Real: + return newARealNumericPrimitiveType(); + case Integer: + return newAIntNumericPrimitiveType(); + case String: + return newAStringPrimitiveType(); + default: + throw new UnsupportedOperationException("Converting fmi type: " + type + " to mabl type is not supported."); + } + } + +// public static VariableFmi2Api createVariableForPort(TagNameGenerator nameGenerator, PortFmi2Api port, IMablScope scope, +// Fmi2Builder.DynamicActiveScope dynamicScope) { +// var name = nameGenerator.getName(port.toLexName()); +// var type = MableAstFactory.newAArrayType(fmitypetomabltype(port.scalarVariable.type.type)); +// var size = 1; +// PStm stm = MableBuilder.newVariable(name, type, size); +// scope.add(stm); +// VariableFmi2Api variable = new VariableFmi2Api(stm, type, scope, dynamicScope, +// newAArayStateDesignator(newAIdentifierStateDesignator(newAIdentifier(name)), newAIntLiteralExp(0)), +// newAArrayIndexExp(newAIdentifierExp(name), Arrays.asList(newAIntLiteralExp(0)))); +// return variable; +// } + + public static FmuVariableFmi3Api createFMU(MablApiBuilder builder, TagNameGenerator nameGenerator, DynamicActiveBuilderScope dynamicScope, + String name, URI uriPath, IMablScope scope) throws Exception { + String path = uriPath.toString(); + if (uriPath.getScheme() != null && uriPath.getScheme().equals("file")) { + path = uriPath.getPath(); + } + + IFmu fmu = FmuFactory.create(null, URI.create(path)); + //check schema. The constructor checks the schema + Fmi3ModelDescription modelDescription = new Fmi3ModelDescription(fmu.getModelDescription()); + + return createFMU(builder, nameGenerator, dynamicScope, name, modelDescription, uriPath, scope); + } + + public static FmuVariableFmi3Api createFMU(MablApiBuilder builder, TagNameGenerator nameGenerator, DynamicActiveBuilderScope dynamicScope, + String name, String loaderName, String[] args, IMablScope scope) throws Exception { + + if (loaderName.equals("FMI3")) { + return createFMU(builder, nameGenerator, dynamicScope, name, URI.create(args[0]), scope); + } else if (loaderName.equals("JFMI3")) { + return createFMU(builder, nameGenerator, dynamicScope, name, args[0], scope); + } + return null; + } + + + public static FmuVariableFmi3Api createFMU(MablApiBuilder builder, TagNameGenerator nameGenerator, DynamicActiveBuilderScope dynamicScope, + String name, String className, IMablScope scope) throws Exception { + + ALoadExp loadExp = newALoadExp(Arrays.asList(newAStringLiteralExp("JFMI3"), newAStringLiteralExp(className))); + + IFmu fmu = (IFmu) VariableCreatorFmi2Api.class.getClassLoader().loadClass(className).getConstructor().newInstance(); + final ModelDescriptionContext3 ctxt = new ModelDescriptionContext3(new Fmi3ModelDescription(fmu.getModelDescription())); + return createFmu(builder, nameGenerator, dynamicScope, name, scope, loadExp, () -> ctxt, + "FMU load failed on fmu: '%s' for classpath: '" + className + "'"); + } + + public static FmuVariableFmi3Api createFMU(MablApiBuilder builder, TagNameGenerator nameGenerator, DynamicActiveBuilderScope dynamicScope, + String name, Fmi3ModelDescription modelDescription, URI uriPath, + IMablScope scope) throws IllegalAccessException, XPathExpressionException, InvocationTargetException { + String path = uriPath.toString(); + if (uriPath.getScheme() != null && uriPath.getScheme().equals("file")) { + path = uriPath.getPath(); + } + + ALoadExp loadExp = newALoadExp( + Arrays.asList(newAStringLiteralExp("FMI3"), newAStringLiteralExp(modelDescription.getInstantiationToken()), newAStringLiteralExp(path))); + + final ModelDescriptionContext3 ctxt = new ModelDescriptionContext3(modelDescription); + + return createFmu(builder, nameGenerator, dynamicScope, name, scope, loadExp, () -> ctxt, + "FMU load failed on fmu: '%s' for uri: '" + uriPath + "'"); + } + + + private static FmuVariableFmi3Api createFmu(MablApiBuilder builder, TagNameGenerator nameGenerator, DynamicActiveBuilderScope dynamicScope, + String name, IMablScope scope, ALoadExp loadExp, Supplier modelDescriptionSupplier, + String loadErrorMsgWithNameStringArgument) { + String uniqueName = nameGenerator.getName(name); + + PStm var = newVariable(uniqueName, newANameType("FMI3"), newNullExp()); + var assign = newAAssignmentStm(newAIdentifierStateDesignator(uniqueName), loadExp); + + var enclosingTryScope = scope.findParentScope(TryMaBlScope.class); + if (enclosingTryScope == null) { + throw new IllegalArgumentException("Call to load FMU is only allowed within a try scope"); + } + + enclosingTryScope.parent().addBefore(enclosingTryScope.getDeclaration(), var); + scope.add(assign); + + FmuVariableFmi3Api fmuVar = new FmuVariableFmi3Api(name, builder, modelDescriptionSupplier.get(), var, MableAstFactory.newANameType("FMI3"), + enclosingTryScope.parent(), dynamicScope, newAIdentifierStateDesignator(newAIdentifier(uniqueName)), newAIdentifierExp(uniqueName)); + + enclosingTryScope.getFinallyBody().addAfterOrTop(null, newIf(newNotEqual(fmuVar.getReferenceExp().clone(), newNullExp()), + newABlockStm(newExpressionStm(newUnloadExp(List.of(fmuVar.getReferenceExp().clone()))), + newAAssignmentStm(fmuVar.getDesignator().clone(), newNullExp())), null)); + + if (builder.getSettings().fmiErrorHandlingEnabled) { + ScopeFmi2Api thenScope = scope.enterIf(new PredicateFmi2Api(newEqual(fmuVar.getReferenceExp().clone(), newNullExp()))).enterThen(); + + builder.getLogger().error(thenScope, loadErrorMsgWithNameStringArgument, name); + + thenScope.add(new AErrorStm(newAStringLiteralExp(String.format(loadErrorMsgWithNameStringArgument, name)))); + + thenScope.leave(); + } + return fmuVar; + } } diff --git a/maestro/src/test/java/org/intocps/maestro/BuilderFmi3Test.java b/maestro/src/test/java/org/intocps/maestro/BuilderFmi3Test.java index 56233715..71814e92 100644 --- a/maestro/src/test/java/org/intocps/maestro/BuilderFmi3Test.java +++ b/maestro/src/test/java/org/intocps/maestro/BuilderFmi3Test.java @@ -20,6 +20,7 @@ import org.intocps.maestro.framework.fmi2.api.mabl.scoping.DynamicActiveBuilderScope; import org.intocps.maestro.framework.fmi2.api.mabl.variables.ComponentVariableFmi2Api; import org.intocps.maestro.framework.fmi2.api.mabl.variables.FmuVariableFmi2Api; +import org.intocps.maestro.framework.fmi2.api.mabl.variables.FmuVariableFmi3Api; import org.intocps.maestro.framework.fmi2.api.mabl.variables.VariableFmi2Api; import org.intocps.maestro.interpreter.DefaultExternalValueFactory; import org.intocps.maestro.interpreter.MableInterpreter; @@ -82,7 +83,8 @@ public void wt() throws Exception { Fmi3ModelDescription md3Ball = new Fmi3ModelDescription(ball.getModelDescription()); - builder.getDynamicScope().createFMU("ball", md3Ball, ballUri); + FmuVariableFmi3Api ballFmu = builder.getDynamicScope().createFMU("ball", md3Ball, ballUri); + // Create the two FMUs FmuVariableFmi2Api controllerFMU = builder.getDynamicScope() diff --git a/maestro/src/test/java/org/intocps/maestro/BuilderTest.java b/maestro/src/test/java/org/intocps/maestro/BuilderTest.java index 1685e145..38dfb37e 100644 --- a/maestro/src/test/java/org/intocps/maestro/BuilderTest.java +++ b/maestro/src/test/java/org/intocps/maestro/BuilderTest.java @@ -202,7 +202,6 @@ public void call(ExtFunc func, Object... args) { @Override public void destroy() { - } } } \ No newline at end of file diff --git a/maestro/src/test/resources/fmi3/basic/basic1/fmi3_basic.mabl b/maestro/src/test/resources/fmi3/basic/basic1/fmi3_basic.mabl index 5c4f408d..cd1738d6 100644 --- a/maestro/src/test/resources/fmi3/basic/basic1/fmi3_basic.mabl +++ b/maestro/src/test/resources/fmi3/basic/basic1/fmi3_basic.mabl @@ -9,7 +9,6 @@ import FMI3; { error; } - string instanceName="fmi3functiontest"; bool visible=true; diff --git a/typechecker/src/main/resources/org/intocps/maestro/typechecker/FMI3.mabl b/typechecker/src/main/resources/org/intocps/maestro/typechecker/FMI3.mabl index 6b66e082..657f40d0 100644 --- a/typechecker/src/main/resources/org/intocps/maestro/typechecker/FMI3.mabl +++ b/typechecker/src/main/resources/org/intocps/maestro/typechecker/FMI3.mabl @@ -14,9 +14,6 @@ import FMI2; } - - - module FMU3State{} module FMI3Instance import FMU3State;{ From 9fe0c2cbf8e0d5851454ad2f789785f9edd8dbbd Mon Sep 17 00:00:00 2001 From: Nestor Date: Thu, 7 Sep 2023 12:38:33 +0200 Subject: [PATCH 3/3] InstanceVariableFmi3Api, instantiateCoSimulation in mabl, compiles succesfully --- .../intocps/maestro/ast/MableAstFactory.java | 1 + .../maestro/fmi/fmi3/Fmi3ModelDescription.kt | 1 + .../intocps/maestro/fmi/fmi3/Fmi3Variables.kt | 4 +- .../api/mabl/ModelDescriptionContext3.java | 2 +- .../framework/fmi2/api/mabl/PortFmi3Api.java | 148 ++ .../scoping/DynamicActiveBuilderScope.java | 6 + .../fmi2/api/mabl/scoping/IMablScope.java | 3 + .../fmi2/api/mabl/scoping/ScopeFmi2Api.java | 16 +- .../variables/ComponentVariableFmi2Api.java | 1 + .../mabl/variables/FmuVariableFmi3Api.java | 174 +- .../variables/InstanceVariableFmi3Api.java | 1404 ++++++++++++++++- .../variables/StateMablVariableFmi2Api.java | 3 + .../variables/StateMablVariableFmi3Api.java | 75 + .../org/intocps/maestro/BuilderFmi3Test.java | 8 +- 14 files changed, 1752 insertions(+), 94 deletions(-) create mode 100644 frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/PortFmi3Api.java create mode 100644 frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/StateMablVariableFmi3Api.java diff --git a/ast/src/main/java/org/intocps/maestro/ast/MableAstFactory.java b/ast/src/main/java/org/intocps/maestro/ast/MableAstFactory.java index a00cdf72..ee3df3ad 100644 --- a/ast/src/main/java/org/intocps/maestro/ast/MableAstFactory.java +++ b/ast/src/main/java/org/intocps/maestro/ast/MableAstFactory.java @@ -376,6 +376,7 @@ public static AIntLiteralExp newAIntLiteralExp(Integer value) { return exp; } + public static AStringLiteralExp newAStringLiteralExp(String value) { AStringLiteralExp exp = new AStringLiteralExp(); exp.setValue(value); diff --git a/fmi/src/main/kotlin/org/intocps/maestro/fmi/fmi3/Fmi3ModelDescription.kt b/fmi/src/main/kotlin/org/intocps/maestro/fmi/fmi3/Fmi3ModelDescription.kt index 9b0d42ab..72fe09ea 100644 --- a/fmi/src/main/kotlin/org/intocps/maestro/fmi/fmi3/Fmi3ModelDescription.kt +++ b/fmi/src/main/kotlin/org/intocps/maestro/fmi/fmi3/Fmi3ModelDescription.kt @@ -12,6 +12,7 @@ import java.lang.reflect.InvocationTargetException import javax.xml.transform.stream.StreamSource import javax.xml.xpath.XPathExpressionException + class Fmi3ModelDescription : ModelDescription { private var variables: Collection? = null private var typeDefinitions: Collection? = null diff --git a/fmi/src/main/kotlin/org/intocps/maestro/fmi/fmi3/Fmi3Variables.kt b/fmi/src/main/kotlin/org/intocps/maestro/fmi/fmi3/Fmi3Variables.kt index a5d1c88e..f0b77465 100644 --- a/fmi/src/main/kotlin/org/intocps/maestro/fmi/fmi3/Fmi3Variables.kt +++ b/fmi/src/main/kotlin/org/intocps/maestro/fmi/fmi3/Fmi3Variables.kt @@ -14,7 +14,9 @@ abstract class Fmi3Variable protected constructor( val previous: UInt? = null, val clocks: List? = null, val typeIdentifier: Fmi3TypeEnum // This is for easier type identification and is not part of the official spec -) +) { + fun getValueReferenceAsLong():Long { return valueReference.toLong() } +} data class Dimension(val valueReference: UInt?, val start: List?) diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/ModelDescriptionContext3.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/ModelDescriptionContext3.java index bfa39b0d..3c9e7512 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/ModelDescriptionContext3.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/ModelDescriptionContext3.java @@ -18,7 +18,7 @@ public ModelDescriptionContext3( this.modelDescription = modelDescription; modelDescription.getScalarVariables().forEach((sv) -> { this.nameToSv.put(sv.getVariable().getName(), sv); - this.valRefToSv.put((long) 1, sv); //TODO: sv.getVariable().getValueReference() + this.valRefToSv.put((long) sv.getVariable().getValueReferenceAsLong(), sv); }); } public Fmi3ModelDescription getModelDescription() { diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/PortFmi3Api.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/PortFmi3Api.java new file mode 100644 index 00000000..b92a0124 --- /dev/null +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/PortFmi3Api.java @@ -0,0 +1,148 @@ +package org.intocps.maestro.framework.fmi2.api.mabl; + +import org.intocps.maestro.ast.node.PType; +import org.intocps.maestro.fmi.Fmi2ModelDescription; +import org.intocps.maestro.fmi.org.intocps.maestro.fmi.fmi3.Fmi3Causality; +import org.intocps.maestro.fmi.org.intocps.maestro.fmi.fmi3.Fmi3ModelDescription; +import org.intocps.maestro.framework.fmi2.api.Fmi2Builder; +import org.intocps.maestro.framework.fmi2.api.mabl.variables.ComponentVariableFmi2Api; +import org.intocps.maestro.framework.fmi2.api.mabl.variables.InstanceVariableFmi3Api; +import org.intocps.maestro.framework.fmi2.api.mabl.variables.VariableFmi2Api; + +import java.util.ArrayList; +import java.util.List; + +import static org.intocps.maestro.ast.MableAstFactory.*; + +public class PortFmi3Api implements Fmi2Builder.Port { + + public final InstanceVariableFmi3Api aMablFmi3InstanceAPI; + public final Fmi3ModelDescription.Fmi3ScalarVariable scalarVariable; + private final List targetPorts = new ArrayList<>(); + private VariableFmi2Api sharedAsVariable; + private PortFmi3Api sourcePort; + + + // TODO model description fmi3 + public PortFmi3Api(InstanceVariableFmi3Api aMablFmi3InstanceAPI, Fmi3ModelDescription.Fmi3ScalarVariable scalarVariable) { + + this.aMablFmi3InstanceAPI = aMablFmi3InstanceAPI; + this.scalarVariable = scalarVariable; + } + + @Override + public String toString() { + return "Port( '" + aMablFmi3InstanceAPI.getName() + "." + scalarVariable.getVariable().getName() + "' , '" + scalarVariable.getVariable().getTypeIdentifier().name() + "')"; + } + + public VariableFmi2Api getSharedAsVariable() { + return sharedAsVariable; + } + + public void setSharedAsVariable(VariableFmi2Api sharedAsVariable) { + this.sharedAsVariable = sharedAsVariable; + } + + public PType getType() { + switch (scalarVariable.getVariable().getTypeIdentifier()) { +// case Boolean: +// return newBoleanType(); +// case Real: +// return newRealType(); +// case Integer: +// return newIntType(); +// case String: +// return newStringType(); +// case Enumeration: + default: + return null; + } + } + + @Override + public String getName() { + return this.scalarVariable.getVariable().getName(); + } + + @Override + public Long getPortReferenceValue() { + return this.scalarVariable.getVariable().getValueReferenceAsLong(); + } + + + @Override + public void linkTo(Fmi2Builder.Port... receivers) throws PortLinkException { + + if (receivers == null || receivers.length == 0) { + return; + } + + if (this.scalarVariable.getVariable().getCausality() != Fmi3Causality.Output) { + throw new PortLinkException("Can only link output ports. This port is: " + this.scalarVariable.getVariable().getCausality(), this); + } + + for (Fmi2Builder.Port receiver : receivers) { + PortFmi3Api receiverPort = (PortFmi3Api) receiver; + + if (receiverPort.scalarVariable.getVariable().getCausality() != Fmi3Causality.Input) { + throw new PortLinkException("Receivers must be input ports. This receiver is: " + receiverPort.scalarVariable.getVariable().getCausality(), + receiverPort); + } + + // HEJ: TBD - This check fails with "already linked" in expansion since both rbmq fmus connect to single actuation + if (receiverPort.getSourcePort() != null) { + throw new PortLinkException("Cannot port already linked please break link first", receiver); + } + receiverPort.sourcePort = this; + if (!this.targetPorts.contains(receiverPort)) { + this.targetPorts.add(receiverPort); + } + } + } + + public PortFmi3Api getSourcePort() { + return this.sourcePort; + } + + @Override + public void breakLink() { + if (sourcePort != null) { + //delete this from the source port + sourcePort.targetPorts.remove(this); + } + sourcePort = null; + } + + @Override + public boolean isLinked() { + return isLinkedAsInputConsumer() || isLinkedAsOutputProvider(); + } + + @Override + public boolean isLinkedAsOutputProvider() { + return targetPorts.isEmpty(); + } + + @Override + public boolean isLinkedAsInputConsumer() { + return this.sourcePort != null; + } + + public String toLexName() { + return this.aMablFmi3InstanceAPI.getOwner().getName() + "_" + this.aMablFmi3InstanceAPI.getName() + "_" + this.getName(); + } + + public String getMultiModelScalarVariableName() { + return this.aMablFmi3InstanceAPI.getOwner().getFmuIdentifier() + "." + this.aMablFmi3InstanceAPI.getEnvironmentName() + "." + + this.getName(); + } + + public String getMultiModelScalarVariableNameWithoutFmu() { + return this.aMablFmi3InstanceAPI.getEnvironmentName() + "." + this.getName(); + } + + public List getTargetPorts() { + return this.targetPorts; + } +} + diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/DynamicActiveBuilderScope.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/DynamicActiveBuilderScope.java index 86f7adbb..c0821a3e 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/DynamicActiveBuilderScope.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/DynamicActiveBuilderScope.java @@ -252,6 +252,12 @@ public void registerComponentVariableFmi2Api(ComponentVariableFmi2Api componentV } + + @Override + public void registerInstanceVariableFmi3Api(InstanceVariableFmi3Api instanceVariableFmi3Api) { + // TODO stuff goes here. + } + @Override public S findParentScope(Class type) { return this.activeScope.findParentScope(type); diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/IMablScope.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/IMablScope.java index f3f010ed..85bcc8d4 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/IMablScope.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/IMablScope.java @@ -115,5 +115,8 @@ public interface IMablScope extends Fmi2Builder.Scope { */ void registerComponentVariableFmi2Api(ComponentVariableFmi2Api componentVariableFmi2Api); + void registerInstanceVariableFmi3Api(InstanceVariableFmi3Api instanceVariableFmi3Api); + + S findParentScope(Class type); } diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/ScopeFmi2Api.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/ScopeFmi2Api.java index 3630fc7e..721c4847 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/ScopeFmi2Api.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/scoping/ScopeFmi2Api.java @@ -373,6 +373,11 @@ protected ArrayVariableFmi2Api store(Supplier nameProvider, V[] v if (length > 1 && value[0] != null) { initializer = newAArrayInitializer(Arrays.stream(value).map(v -> newAIntLiteralExp((Integer) v)).collect(Collectors.toList())); } + } else if (value instanceof Long[]) { + type = new AUIntNumericPrimitiveType(); + if (length > 1 && value[0] != null) { + initializer = newAArrayInitializer(Arrays.stream(value).map(v -> newAUIntLiteralExp((Long) v)).collect(Collectors.toList())); + } } else if (value instanceof Boolean[]) { type = new ABooleanPrimitiveType(); if (length > 1 && value[0] != null) { @@ -472,7 +477,6 @@ private Fmi2Builder.Variable storePrivate(String name, Fmi2Builder. if (v.get() != null) { initial = newAIntLiteralExp((Integer) v.get()); } - } else if (v.getType() instanceof ABooleanPrimitiveType) { if (v.get() != null) { initial = newABoolLiteralExp((Boolean) v.get()); @@ -506,6 +510,14 @@ public FmuVariableFmi3Api createFMU3(String name, String loaderName, String... a return null; } + + // TODO stuff goes here. + @Override + public void registerInstanceVariableFmi3Api(InstanceVariableFmi3Api instanceVariableFmi3Api) { + + } + + @Override public void markTransferPoint(String... names) { @@ -601,6 +613,8 @@ public void registerComponentVariableFmi2Api(ComponentVariableFmi2Api componentV this.fmi2ComponentVariables.add(componentVariableFmi2Api); } + + @Override public S findParentScope(Class type) { Fmi2Builder.ScopeElement p = this; diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/ComponentVariableFmi2Api.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/ComponentVariableFmi2Api.java index 2531b162..77c99921 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/ComponentVariableFmi2Api.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/ComponentVariableFmi2Api.java @@ -1247,6 +1247,7 @@ public Fmi2Builder.StateVariable getState() throws XPathExpressionExceptio @Override public Fmi2Builder.StateVariable getState(Fmi2Builder.Scope scope) throws XPathExpressionException { + if (!this.modelDescriptionContext.getModelDescription().getCanGetAndSetFmustate()) { throw new RuntimeException("Unable to get state on fmu: " + this.getOwner() + " with instance name: " + this.getName()); } diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/FmuVariableFmi3Api.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/FmuVariableFmi3Api.java index f5ad360b..0b18e53f 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/FmuVariableFmi3Api.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/FmuVariableFmi3Api.java @@ -12,6 +12,10 @@ import org.intocps.maestro.framework.fmi2.api.mabl.scoping.ScopeFmi2Api; import org.intocps.maestro.framework.fmi2.api.mabl.scoping.TryMaBlScope; +import java.util.Arrays; +import java.util.HashMap; +import java.util.stream.Collectors; + import static org.intocps.maestro.ast.MableAstFactory.*; import static org.intocps.maestro.ast.MableBuilder.call; import static org.intocps.maestro.ast.MableBuilder.newVariable; @@ -41,91 +45,89 @@ public FmuVariableFmi3Api(MablApiBuilder builder, ModelDescriptionContext3 model this.modelDescriptionContext = modelDescriptionContext; } -// -// public ModelDescriptionContext3 getModelDescriptionContext() { -// return modelDescriptionContext; -// } -// -// @Override -// public ComponentVariableFmi2Api instantiate(String name, String environmentName) { -// IMablScope scope = builder.getDynamicScope().getActiveScope(); -// return instantiate(name, scope.findParentScope(TryMaBlScope.class), scope, environmentName); -// } -// -// @Override -// public ComponentVariableFmi2Api instantiate(String name) { -// IMablScope scope = builder.getDynamicScope().getActiveScope(); -// return instantiate(name, scope.findParentScope(TryMaBlScope.class), scope); -// } -// -// -// @Override -// public ComponentVariableFmi2Api instantiate(String namePrefix, Fmi2Builder.TryScope enclosingTryScope, Fmi2Builder.Scope scope, -// String environmentName) { -// return instantiate(namePrefix, enclosingTryScope, scope, environmentName, true); -// } -// -// @Override -// public ComponentVariableFmi2Api instantiate(String namePrefix, Fmi2Builder.TryScope enclosingTryScope, Fmi2Builder.Scope scope, -// String environmentName, boolean loggingOn) { -// -// String name = builder.getNameGenerator().getName(namePrefix); -// //TODO: Extract bool visible and bool loggingOn from configuration -// var var = newVariable(name, newANameType("FMI2Component"), newNullExp()); -// -// PStm instantiateAssign = newAAssignmentStm(newAIdentifierStateDesignator(name), -// call(getReferenceExp().clone(), "instantiate", newAStringLiteralExp(name), newABoolLiteralExp(true), newABoolLiteralExp(loggingOn))); -// -// -// if (enclosingTryScope == null) { -// throw new IllegalArgumentException("Call to instantiate is not allowed with a null enclosing try scope"); -// } -// -// -// TryMaBlScope mTryScope = (TryMaBlScope) enclosingTryScope; -// mTryScope.parent().addBefore(mTryScope.getDeclaration(), var); -// -// ComponentVariableFmi2Api compVar; -// if (environmentName == null) { -// compVar = new ComponentVariableFmi2Api(var, this, name, this.modelDescriptionContext, builder, mTryScope.parent(), -// newAIdentifierStateDesignator(newAIdentifier(name)), newAIdentifierExp(name)); -// } else { -// -// AInstanceMappingStm mapping = newAInstanceMappingStm(newAIdentifier(name), environmentName); -// compVar = new ComponentVariableFmi2Api(var, this, name, this.modelDescriptionContext, builder, mTryScope.parent(), -// newAIdentifierStateDesignator(newAIdentifier(name)), newAIdentifierExp(name), environmentName); -// scope.add(mapping); -// } -// -// scope.add(instantiateAssign); -// -// mTryScope.getFinallyBody().addAfterOrTop(null, newIf(newNotEqual(compVar.getReferenceExp().clone(), newNullExp()), -// newABlockStm(MableAstFactory.newExpressionStm(call(getReferenceExp().clone(), "freeInstance", compVar.getReferenceExp().clone())), -// newAAssignmentStm(compVar.getDesignatorClone(), newNullExp())), null)); -// -// scope.activate(); -// -// if (builder.getSettings().fmiErrorHandlingEnabled) { -// ScopeFmi2Api thenScope = -// (ScopeFmi2Api) scope.enterIf(new PredicateFmi2Api(newEqual(compVar.getReferenceExp().clone(), newNullExp()))).enterThen(); -// -// builder.getLogger().error(thenScope, "Instantiate failed on fmu: '%s' for instance: '%s'", this.getFmuIdentifier(), namePrefix); -// thenScope.add(new AErrorStm( -// newAStringLiteralExp(String.format("Instantiate failed on fmu: '%s' for instance: '%s'", this.getFmuIdentifier(), namePrefix)))); -// thenScope.leave(); -// } -// -// ((IMablScope) scope).registerComponentVariableFmi2Api(compVar); -// -// return compVar; -// } -// + public ModelDescriptionContext3 getModelDescriptionContext() { + return modelDescriptionContext; + } + // @Override -// public ComponentVariableFmi2Api instantiate(String namePrefix, Fmi2Builder.TryScope enclosingTryScope, Fmi2Builder.Scope scope) { -// return instantiate(namePrefix, enclosingTryScope, scope, null); -// } -// -// public String getFmuIdentifier() { -// return fmuIdentifier; -// } + public InstanceVariableFmi3Api instantiate(String name, String environmentName, ArrayVariableFmi2Api variables) { + IMablScope scope = builder.getDynamicScope().getActiveScope(); + return instantiate(name, scope.findParentScope(TryMaBlScope.class), scope, environmentName, variables); + } + + public InstanceVariableFmi3Api instantiate(String name, ArrayVariableFmi2Api variables) { + IMablScope scope = builder.getDynamicScope().getActiveScope(); + return instantiate(name, scope.findParentScope(TryMaBlScope.class), scope, variables); + } + + + public InstanceVariableFmi3Api instantiate(String namePrefix, Fmi2Builder.TryScope enclosingTryScope, Fmi2Builder.Scope scope, + String environmentName, ArrayVariableFmi2Api variables) { + return instantiate(namePrefix, enclosingTryScope, scope, environmentName, true, variables ); + } + public InstanceVariableFmi3Api instantiate(String namePrefix, Fmi2Builder.TryScope enclosingTryScope, Fmi2Builder.Scope scope, + String environmentName, boolean loggingOn, ArrayVariableFmi2Api variables) { + + String name = builder.getNameGenerator().getName(namePrefix); + //TODO: Extract bool visible and bool loggingOn from configuration + var var = newVariable(name, newANameType("FMI3Instance"), newNullExp()); + + + + + + PStm instantiateAssign = newAAssignmentStm(newAIdentifierStateDesignator(name), + call(getReferenceExp().clone(), "instantiateCoSimulation", newAStringLiteralExp(name), newABoolLiteralExp(true), + newABoolLiteralExp(loggingOn), newABoolLiteralExp(true), newABoolLiteralExp(true), + variables.getReferenceExp().clone())); + + if (enclosingTryScope == null) { + throw new IllegalArgumentException("Call to instantiate is not allowed with a null enclosing try scope"); + } + + + TryMaBlScope mTryScope = (TryMaBlScope) enclosingTryScope; + mTryScope.parent().addBefore(mTryScope.getDeclaration(), var); + + InstanceVariableFmi3Api compVar; + if (environmentName == null) { + compVar = new InstanceVariableFmi3Api(var, this, name, this.modelDescriptionContext, builder, mTryScope.parent(), + newAIdentifierStateDesignator(newAIdentifier(name)), newAIdentifierExp(name)); + } else { + + AInstanceMappingStm mapping = newAInstanceMappingStm(newAIdentifier(name), environmentName); + compVar = new InstanceVariableFmi3Api(var, this, name, this.modelDescriptionContext, builder, mTryScope.parent(), + newAIdentifierStateDesignator(newAIdentifier(name)), newAIdentifierExp(name), environmentName); + scope.add(mapping); + } + + scope.add(instantiateAssign); + + mTryScope.getFinallyBody().addAfterOrTop(null, newIf(newNotEqual(compVar.getReferenceExp().clone(), newNullExp()), + newABlockStm(MableAstFactory.newExpressionStm(call(getReferenceExp().clone(), "freeInstance", compVar.getReferenceExp().clone())), + newAAssignmentStm(compVar.getDesignatorClone(), newNullExp())), null)); + + scope.activate(); + + if (builder.getSettings().fmiErrorHandlingEnabled) { + ScopeFmi2Api thenScope = + (ScopeFmi2Api) scope.enterIf(new PredicateFmi2Api(newEqual(compVar.getReferenceExp().clone(), newNullExp()))).enterThen(); + + builder.getLogger().error(thenScope, "Instantiate failed on fmu: '%s' for instance: '%s'", this.getFmuIdentifier(), namePrefix); + thenScope.add(new AErrorStm( + newAStringLiteralExp(String.format("Instantiate failed on fmu: '%s' for instance: '%s'", this.getFmuIdentifier(), namePrefix)))); + thenScope.leave(); + } + + ((IMablScope) scope).registerInstanceVariableFmi3Api(compVar); + + return compVar; + } + public InstanceVariableFmi3Api instantiate(String namePrefix, Fmi2Builder.TryScope enclosingTryScope, Fmi2Builder.Scope scope, ArrayVariableFmi2Api variables) { + return instantiate(namePrefix, enclosingTryScope, scope, null, variables); + } + + public String getFmuIdentifier() { + return fmuIdentifier; + } } \ No newline at end of file diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/InstanceVariableFmi3Api.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/InstanceVariableFmi3Api.java index 9f2d45c6..ea1a2e20 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/InstanceVariableFmi3Api.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/InstanceVariableFmi3Api.java @@ -1,5 +1,1407 @@ package org.intocps.maestro.framework.fmi2.api.mabl.variables; -public class InstanceVariableFmi3Api { +import org.intocps.maestro.ast.AVariableDeclaration; +import org.intocps.maestro.ast.LexIdentifier; +import org.intocps.maestro.ast.MableAstFactory; +import org.intocps.maestro.ast.analysis.AnalysisException; +import org.intocps.maestro.ast.analysis.DepthFirstAnalysisAdaptor; +import org.intocps.maestro.ast.node.*; +import org.intocps.maestro.fmi.Fmi2ModelDescription; +import org.intocps.maestro.fmi.org.intocps.maestro.fmi.fmi3.Fmi3Causality; +import org.intocps.maestro.fmi.org.intocps.maestro.fmi.fmi3.Fmi3ModelDescription; +import org.intocps.maestro.fmi.org.intocps.maestro.fmi.fmi3.Fmi3TypeEnum; +import org.intocps.maestro.framework.fmi2.RelationVariable; +import org.intocps.maestro.framework.fmi2.api.Fmi2Builder; +import org.intocps.maestro.framework.fmi2.api.mabl.*; +import org.intocps.maestro.framework.fmi2.api.mabl.scoping.IMablScope; +import org.intocps.maestro.framework.fmi2.api.mabl.scoping.ScopeFmi2Api; +import org.intocps.maestro.framework.fmi2.api.mabl.values.PortValueExpresssionMapImpl; +import org.intocps.maestro.framework.fmi2.api.mabl.values.PortValueMapImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.xml.xpath.XPathExpressionException; +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static java.util.stream.Collectors.toSet; +import static org.intocps.maestro.ast.MableAstFactory.*; +import static org.intocps.maestro.ast.MableBuilder.call; +import static org.intocps.maestro.ast.MableBuilder.newVariable; + + +@SuppressWarnings("rawtypes") +public class InstanceVariableFmi3Api extends VariableFmi2Api> implements Fmi2Builder.Fmi2ComponentVariable { + final static Logger logger = LoggerFactory.getLogger(InstanceVariableFmi3Api.class); + private final static int FMI_OK = 0; + private final static int FMI_WARNING = 1; + private final static int FMI_DISCARD = 2; + private final static int FMI_ERROR = 3; + private final static int FMI_FATAL = 4; + private final static int FMI_PENDING = 5; + private final static int FMI_STATUS_LAST_SUCCESSFUL = 2; + private static final String LOGLEVELS_POSTFIX = "_log_levels"; + private final static String CATEGORY_STATUS = "category_status"; + final List outputPorts; + final List inputPorts; + final List ports; + private final FmuVariableFmi3Api owner; + private final String name; + private final MablApiBuilder builder; + private final Map> ioBuffer = new HashMap<>(); + private final Map> sharedBuffer = new HashMap<>(); + private final Map>> tentativeBuffer = new HashMap<>(); + private final Map> tentativeBufferIndexMap = new HashMap<>(); + private final String environmentName; + Predicate isLinked = p -> ((PortFmi3Api) p).getSourcePort() != null; + ModelDescriptionContext3 modelDescriptionContext; + private ArrayVariableFmi2Api derSharedBuffer; + private DoubleVariableFmi2Api currentTimeVar = null; + private BooleanVariableFmi2Api currentTimeStepFullStepVar = null; + private ArrayVariableFmi2Api valueRefBuffer; + private Map>> derivativePortsToShare; + private List variabesToLog; + + public InstanceVariableFmi3Api(PStm declaration, FmuVariableFmi3Api parent, String name, ModelDescriptionContext3 modelDescriptionContext, + MablApiBuilder builder, IMablScope declaringScope, PStateDesignator designator, PExp referenceExp) { + this(declaration, parent, name, modelDescriptionContext, builder, declaringScope, designator, referenceExp, name); + } + + public InstanceVariableFmi3Api(PStm declaration, FmuVariableFmi3Api parent, String name, ModelDescriptionContext3 modelDescriptionContext, + MablApiBuilder builder, IMablScope declaringScope, PStateDesignator designator, PExp referenceExp, String environmentName) { + super(declaration, newANameType("FMI3Instance"), declaringScope, builder.getDynamicScope(), designator, referenceExp); + this.owner = parent; + this.name = name; + + this.modelDescriptionContext = modelDescriptionContext; + this.builder = builder; + + ports = modelDescriptionContext.nameToSv.values().stream().map(sv -> new PortFmi3Api(this, sv)) + .sorted(Comparator.comparing(PortFmi3Api::getPortReferenceValue)).collect(Collectors.toUnmodifiableList()); + + outputPorts = ports.stream().filter(p -> p.scalarVariable.getVariable().getCausality() == Fmi3Causality.Output) + .sorted(Comparator.comparing(PortFmi3Api::getPortReferenceValue)).collect(Collectors.toUnmodifiableList()); + + inputPorts = + ports.stream().filter(p -> p.scalarVariable.getVariable().getCausality() == Fmi3Causality.Input) + .sorted(Comparator.comparing(PortFmi3Api::getPortReferenceValue)).collect(Collectors.toUnmodifiableList()); + + this.environmentName = environmentName; + } + + // TODO fmi3 model description. + public Fmi3ModelDescription getModelDescription() { + return modelDescriptionContext.getModelDescription(); + } + + public List getVariablesToLog() { + return this.getPorts(this.variabesToLog.toArray(new String[0])); + } + + public void setVariablesToLog(List variablesToLog) { + this.variabesToLog = variablesToLog.stream().map(x -> x.scalarVariable.getName()).collect(Collectors.toList()); + } + + @Override + public void share(Fmi2Builder.Port port, Fmi2Builder.Variable value) { + Map> map = new HashMap<>(); + map.put(port, value); + share(map); + } + + private DoubleVariableFmi2Api getCurrentTimeVar() { + if (currentTimeVar == null) { + String name = builder.getNameGenerator().getName(this.name, "current", "time"); + PStm var = newVariable(name, newRealType(), newARealLiteralExp(0d)); + this.getDeclaredScope().addAfter(this.getDeclaringStm(), var); + currentTimeVar = new DoubleVariableFmi2Api(var, this.getDeclaredScope(), dynamicScope, newAIdentifierStateDesignator(name), + newAIdentifierExp(name)); + } + return currentTimeVar; + } + + private BooleanVariableFmi2Api getCurrentTimeFullStepVar() { + if (currentTimeStepFullStepVar == null) { + String name = builder.getNameGenerator().getName(this.name, "current", "time", "full", "step"); + PStm var = newVariable(name, newBoleanType(), newABoolLiteralExp(true)); + this.getDeclaredScope().addAfter(this.getDeclaringStm(), var); + + currentTimeStepFullStepVar = new BooleanVariableFmi2Api(var, this.getDeclaredScope(), dynamicScope, newAIdentifierStateDesignator(name), + newAIdentifierExp(name)); + } + return currentTimeStepFullStepVar; + } + + private ArrayVariableFmi2Api getValueReferenceBuffer() { + if (this.valueRefBuffer == null) { + this.valueRefBuffer = createBuffer(newUIntType(), "VRef", modelDescriptionContext.valRefToSv.size(), getDeclaredScope()); + } + return this.valueRefBuffer; + } + + private ArrayVariableFmi2Api getBuffer(Map> buffer, PType type, String prefix, int size, + IMablScope scope) { + Optional first = buffer.keySet().stream().filter(x -> x.toString().equals(type.toString())).findFirst(); + if (first.isEmpty()) { + ArrayVariableFmi2Api value = createBuffer(type, prefix, size, scope); + buffer.put(type, value); + return value; + + } else { + return buffer.get(first.get()); + } + } + + private ArrayVariableFmi2Api getIOBuffer(PType type) { + return getBuffer(this.ioBuffer, type, "IO", modelDescriptionContext.valRefToSv.size(), getDeclaredScope()); + } + + private ArrayVariableFmi2Api getSharedDerBuffer() { + if (this.derSharedBuffer == null) { + try { + this.derSharedBuffer = createDerValBuffer("DerShare", List.of(1, getModelDescription().getMaxOutputDerivativeOrder())); + } catch (XPathExpressionException e) { + throw new RuntimeException("Exception occurred when accessing modeldescription: " + e); + } + } + return this.derSharedBuffer; + } + + + private ArrayVariableFmi2Api getSharedBuffer(PType type) { + return this.getBuffer(this.sharedBuffer, type, "Share", 0, getDeclaredScope()); + } + + private ArrayVariableFmi2Api createMDArrayRecursively(List arraySizes, PStm declaringStm, PStateDesignatorBase stateDesignator, + PExpBase indexExp) { + + if (arraySizes.size() > 1) { + List arrays = new ArrayList<>(); + for (int i = 0; i < arraySizes.get(0); i++) { + arrays.add(createMDArrayRecursively(arraySizes.subList(1, arraySizes.size()), declaringStm, + newAArayStateDesignator(stateDesignator, newAIntLiteralExp(i)), newAArrayIndexExp(indexExp, List.of(newAIntLiteralExp(i))))); + } + return new ArrayVariableFmi2Api(declaringStm, arrays.get(0).getType(), getDeclaredScope(), builder.getDynamicScope(), stateDesignator, + indexExp.clone(), arrays); + } + + List> variables = new ArrayList<>(); + for (int i = 0; i < arraySizes.get(0); i++) { + variables.add(new VariableFmi2Api<>(declaringStm, type, getDeclaredScope(), builder.getDynamicScope(), + newAArayStateDesignator(stateDesignator.clone(), newAIntLiteralExp(i)), + newAArrayIndexExp(indexExp.clone(), List.of(newAIntLiteralExp(i))))); + } + return new ArrayVariableFmi2Api<>(declaringStm, variables.get(0).getType(), getDeclaredScope(), builder.getDynamicScope(), + ((AArrayStateDesignator) variables.get(0).getDesignatorClone()).getTarget(), indexExp.clone(), variables); + } + + private ArrayVariableFmi2Api createDerValBuffer(String identifyingName, List lengths) { + String bufferName = builder.getNameGenerator().getName(this.name, identifyingName); + + PStm arrayVariableStm = newALocalVariableStm( + newAVariableDeclarationMultiDimensionalArray(newAIdentifier(bufferName), newARealNumericPrimitiveType(), lengths)); + + getDeclaredScope().addAfter(getDeclaringStm(), arrayVariableStm); + + return createMDArrayRecursively(lengths, arrayVariableStm, newAIdentifierStateDesignator(newAIdentifier(bufferName)), + newAIdentifierExp(bufferName)); + } + + private ArrayVariableFmi2Api createBuffer(PType type, String prefix, int length, IMablScope scope) { + + //lets find a good place to store the buffer. + String ioBufName = builder.getNameGenerator().getName(this.name, type + "", prefix); + + PStm var = newALocalVariableStm(newAVariableDeclaration(newAIdentifier(ioBufName), type, length, null)); + + getDeclaredScope().addAfter(getDeclaringStm(), var); + + List> items = IntStream.range(0, length).mapToObj( + i -> new VariableFmi2Api<>(var, type, scope, builder.getDynamicScope(), + newAArayStateDesignator(newAIdentifierStateDesignator(newAIdentifier(ioBufName)), newAIntLiteralExp(i)), + newAArrayIndexExp(newAIdentifierExp(ioBufName), Collections.singletonList(newAIntLiteralExp(i))))) + .collect(Collectors.toList()); + + return new ArrayVariableFmi2Api<>(var, type, scope, builder.getDynamicScope(), newAIdentifierStateDesignator(newAIdentifier(ioBufName)), + newAIdentifierExp(ioBufName), items); + + } + + @Override + public void setDebugLogging(List categories, boolean enableLogging) { + AArrayInitializer loglevelsArrayInitializer = null; + String arrayName = name + LOGLEVELS_POSTFIX; + IMablScope scope = builder.getDynamicScope().getActiveScope(); + if (!categories.isEmpty()) { + loglevelsArrayInitializer = + newAArrayInitializer(categories.stream().map(MableAstFactory::newAStringLiteralExp).collect(Collectors.toList())); + } + ALocalVariableStm arrayContent = MableAstFactory.newALocalVariableStm( + MableAstFactory.newAVariableDeclaration(MableAstFactory.newAIdentifier(arrayName), + MableAstFactory.newAArrayType(MableAstFactory.newAStringPrimitiveType()), categories.size(), loglevelsArrayInitializer)); + + LexIdentifier statusIdentifier = newAIdentifier(getEnvironmentName() + "_" + CATEGORY_STATUS); + + ALocalVariableStm callStm = newALocalVariableStm(newAVariableDeclaration(statusIdentifier, newAIntNumericPrimitiveType(), newAExpInitializer( + newACallExp(newAIdentifierExp(name), newAIdentifier("setDebugLogging"), + Arrays.asList(newABoolLiteralExp(enableLogging), MableAstFactory.newAIntLiteralExp(categories.size()), + MableAstFactory.newAIdentifierExp(arrayName)))))); + + scope.add(arrayContent, callStm); + + if (builder.getSettings().fmiErrorHandlingEnabled) { + FmiStatusErrorHandlingBuilder.generate(builder, "setDebugLogging", this, (IMablScope) scope, MablApiBuilder.FmiStatus.FMI_ERROR, + MablApiBuilder.FmiStatus.FMI_FATAL); + } + } + + @Override + public void setupExperiment(Fmi2Builder.DoubleVariable startTime, Fmi2Builder.DoubleVariable endTime, + Fmi2Builder.BoolVariable endTimeDefined, Double tolerance) { + this.setupExperiment(((DoubleVariableFmi2Api) startTime).getReferenceExp().clone(), + ((DoubleVariableFmi2Api) endTime).getReferenceExp().clone(), ((BooleanVariableFmi2Api) endTimeDefined).getReferenceExp().clone(), + tolerance); + } + + @Override + public void setupExperiment(double startTime, Double endTime, Double tolerance) { + this.setupExperiment(newARealLiteralExp(startTime), newARealLiteralExp(endTime), newABoolLiteralExp(true), tolerance); + } + + private void setupExperiment(PExp startTime, PExp endTime, PExp endTimeDefined, Double tolerance) { + IMablScope scope = builder.getDynamicScope().getActiveScope(); + this.setupExperiment(scope, startTime, endTime, endTimeDefined, tolerance); + } + + private void setupExperiment(Fmi2Builder.Scope scope, PExp startTime, PExp endTime, PExp endTimeDefined, Double tolerance) { + AAssigmentStm stm = newAAssignmentStm(((IMablScope) scope).getFmiStatusVariable().getDesignator().clone(), + call(this.getReferenceExp().clone(), createFunctionName(FmiFunctionType.SETUPEXPERIMENT), new ArrayList<>( + Arrays.asList(newABoolLiteralExp(tolerance != null), newARealLiteralExp(tolerance != null ? tolerance : 0d), + startTime.clone(), endTimeDefined, endTime != null ? endTime.clone() : newARealLiteralExp(0d))))); + scope.add(stm); + if (builder.getSettings().fmiErrorHandlingEnabled) { + FmiStatusErrorHandlingBuilder.generate(builder, "setupExperiment", this, (IMablScope) scope, MablApiBuilder.FmiStatus.FMI_ERROR, + MablApiBuilder.FmiStatus.FMI_FATAL); + } + } + + @Override + public void enterInitializationMode() { + this.enterInitializationMode(builder.getDynamicScope()); + + } + + @Override + public void exitInitializationMode() { + this.exitInitializationMode(builder.getDynamicScope()); + } + + @Override + public void setupExperiment(Fmi2Builder.Scope scope, Fmi2Builder.DoubleVariable startTime, Fmi2Builder.DoubleVariable endTime, + Fmi2Builder.BoolVariable endTimeDefined, Double tolerance) { + this.setupExperiment(scope, ((DoubleVariableFmi2Api) startTime).getReferenceExp().clone(), + ((DoubleVariableFmi2Api) endTime).getReferenceExp().clone(), endTimeDefined.getExp().clone(), tolerance); + } + + @Override + public void setupExperiment(Fmi2Builder.Scope scope, double startTime, Double endTime, Double tolerance) { + this.setupExperiment(scope, newARealLiteralExp(startTime), newARealLiteralExp(endTime), newABoolLiteralExp(true), tolerance); + } + + @Override + public void enterInitializationMode(Fmi2Builder.Scope scope) { + PStm stm = stateTransitionFunction(FmiFunctionType.ENTERINITIALIZATIONMODE); + scope.add(stm); + if (builder.getSettings().fmiErrorHandlingEnabled) { + FmiStatusErrorHandlingBuilder.generate(builder, "enterInitializationMode", this, (IMablScope) scope, MablApiBuilder.FmiStatus.FMI_ERROR, + MablApiBuilder.FmiStatus.FMI_FATAL); + } + } + + @Override + public void exitInitializationMode(Fmi2Builder.Scope scope) { + PStm stm = stateTransitionFunction(FmiFunctionType.EXITINITIALIZATIONMODE); + scope.add(stm); + if (builder.getSettings().fmiErrorHandlingEnabled) { + FmiStatusErrorHandlingBuilder.generate(builder, "exitInitializationMode", this, (IMablScope) scope, MablApiBuilder.FmiStatus.FMI_ERROR, + MablApiBuilder.FmiStatus.FMI_FATAL); + } + } + + @Override + public Map.Entry, Fmi2Builder.DoubleVariable> step(Fmi2Builder.Scope scope, + Fmi2Builder.DoubleVariable currentCommunicationPoint, Fmi2Builder.DoubleVariable communicationStepSize, + Fmi2Builder.BoolVariable noSetFMUStatePriorToCurrentPoint) { + return step(scope, currentCommunicationPoint, communicationStepSize, ((VariableFmi2Api) noSetFMUStatePriorToCurrentPoint).getReferenceExp()); + } + + @Override + public Map.Entry, Fmi2Builder.DoubleVariable> step(Fmi2Builder.Scope scope, + Fmi2Builder.DoubleVariable currentCommunicationPoint, Fmi2Builder.DoubleVariable communicationStepSize) { + return step(scope, currentCommunicationPoint, communicationStepSize, newABoolLiteralExp(false)); + } + + @Override + public Map.Entry, Fmi2Builder.DoubleVariable> step( + Fmi2Builder.DoubleVariable currentCommunicationPoint, Fmi2Builder.DoubleVariable communicationStepSize, + Fmi2Builder.BoolVariable noSetFMUStatePriorToCurrentPoint) { + return step(dynamicScope, currentCommunicationPoint, communicationStepSize, noSetFMUStatePriorToCurrentPoint); + } + + @Override + public Map.Entry, Fmi2Builder.DoubleVariable> step( + Fmi2Builder.DoubleVariable currentCommunicationPoint, Fmi2Builder.DoubleVariable communicationStepSize) { + return step(dynamicScope, currentCommunicationPoint, communicationStepSize, newABoolLiteralExp(false)); + } + + private Map.Entry, Fmi2Builder.DoubleVariable> step(Fmi2Builder.Scope scope, + Fmi2Builder.DoubleVariable currentCommunicationPoint, Fmi2Builder.DoubleVariable communicationStepSize, + PExp noSetFMUStatePriorToCurrentPoint) { + + scope.add(newAAssignmentStm(((IMablScope) scope).getFmiStatusVariable().getDesignator().clone(), + newACallExp(this.getReferenceExp().clone(), newAIdentifier("doStep"), + Arrays.asList(((VariableFmi2Api) currentCommunicationPoint).getReferenceExp().clone(), + ((VariableFmi2Api) communicationStepSize).getReferenceExp().clone(), noSetFMUStatePriorToCurrentPoint.clone())))); + + if (builder.getSettings().fmiErrorHandlingEnabled) { + FmiStatusErrorHandlingBuilder.generate(builder, "doStep", this, (IMablScope) scope, MablApiBuilder.FmiStatus.FMI_ERROR, + MablApiBuilder.FmiStatus.FMI_FATAL); + } + + + scope.add(newIf(newNotEqual(((IMablScope) scope).getFmiStatusVariable().getReferenceExp().clone(), + builder.getFmiStatusConstant(MablApiBuilder.FmiStatus.FMI_OK).getReferenceExp().clone()), newABlockStm( + newIf(newEqual(((IMablScope) scope).getFmiStatusVariable().getReferenceExp().clone(), + builder.getFmiStatusConstant(MablApiBuilder.FmiStatus.FMI_DISCARD).getReferenceExp().clone()), newABlockStm( + newAAssignmentStm(((IMablScope) scope).getFmiStatusVariable().getDesignator().clone(), + newACallExp(this.getReferenceExp().clone(), newAIdentifier("getRealStatus"), + Arrays.asList(newAIntLiteralExp(FMI_STATUS_LAST_SUCCESSFUL), + newARefExp(getCurrentTimeVar().getReferenceExp().clone())))), + newAAssignmentStm(getCurrentTimeFullStepVar().getDesignator().clone(), newABoolLiteralExp(false))), null)), newABlockStm( + newAAssignmentStm(this.getCurrentTimeVar().getDesignator().clone(), + newPlusExp(((VariableFmi2Api) currentCommunicationPoint).getReferenceExp().clone(), + ((VariableFmi2Api) communicationStepSize).getReferenceExp().clone())), + newAAssignmentStm(getCurrentTimeFullStepVar().getDesignator().clone(), newABoolLiteralExp(true))))); + + return Map.entry(getCurrentTimeFullStepVar(), getCurrentTimeVar()); + } + + private PStm stateTransitionFunction(FmiFunctionType type) { + switch (type) { + case ENTERINITIALIZATIONMODE: + break; + case EXITINITIALIZATIONMODE: + break; + case TERMINATE: + break; + default: + throw new RuntimeException("Attempting to call state transition function with non-state transition function type: " + type); + } + + AAssigmentStm stm = newAAssignmentStm(((IMablScope) this.dynamicScope).getFmiStatusVariable().getDesignator().clone(), + call(this.getReferenceExp().clone(), createFunctionName(type))); + return stm; + } + + @Override + public List getPorts() { + return ports; + } + + @Override + public List getPorts(String... names) { + List accept = Arrays.asList(names); + return ports.stream().filter(p -> accept.contains(p.getName())).collect(Collectors.toList()); + } + + @Override + public List getPorts(int... valueReferences) { + List accept = Arrays.stream(valueReferences).boxed().collect(Collectors.toList()); + return ports.stream().filter(p -> accept.contains(p.getPortReferenceValue().intValue())).collect(Collectors.toList()); + } + + @Override + public PortFmi3Api getPort(String name) { + return (PortFmi3Api) this.getPorts(name).get(0); + } + + @Override + public PortFmi3Api getPort(int valueReference) { + return (PortFmi3Api) this.getPorts(valueReference).get(0); + } + + //TODO: Move tentative buffer and global share buffer logic to its own module so that it is not coupled with the component logic? + public Map> getTentative(IMablScope scope, String... names) { + // Get filtered port values + Fmi2Builder.Port[] filteredPorts = this.ports.stream() + .filter(p -> Arrays.asList(names).contains(p.getName()) && (p.scalarVariable.getVariable().getCausality() == Fmi3Causality.Output)) + .toArray(Fmi2Builder.Port[]::new); + Map> portToValueMap = get(scope, filteredPorts); + if (portToValueMap.isEmpty()) { + return Map.of(); + } + + // Get tentative buffer index map for the scope + tentativeBufferIndexMap.computeIfAbsent(scope, (s) -> new HashMap<>()); + Map portToVariableIndexMap = tentativeBufferIndexMap.get(scope); + + // Return a port value map where the value is an index in a tentative buffer for the given scope instead of the global IO buffer + return portToValueMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> { + PType type = entry.getKey().getType(); + PortFmi3Api port = entry.getKey(); + VariableFmi2Api variable = entry.getValue(); + VariableFmi2Api varToReturn; + + // Get the tentative buffer for the given scope + tentativeBuffer.computeIfAbsent(scope, (s) -> new HashMap<>()); + ArrayVariableFmi2Api buffer = + this.getBuffer(tentativeBuffer.getOrDefault(scope, new HashMap<>()), type, "TentativeBuffer", 0, scope); + + // Expand the buffer if the port has not been indexed + if (!portToVariableIndexMap.containsKey(port)) { + portToVariableIndexMap.put(port, portToVariableIndexMap.entrySet().size()); + ArrayVariableFmi2Api newBuf = growBuffer(buffer, 1); + tentativeBuffer.get(scope).entrySet().removeIf(x -> x.getKey().toString().equals(type.toString())); + tentativeBuffer.get(scope).put(type, newBuf); + varToReturn = (VariableFmi2Api) newBuf.items().get(newBuf.items().size() - 1); + } else { + varToReturn = (VariableFmi2Api) buffer.items().get(portToVariableIndexMap.get(port)); + } + + // Create the assignment from the IO buffer to the tentative buffer in MaBL + scope.add(MableAstFactory.newAAssignmentStm(varToReturn.getDesignator(), variable.getExp())); + return varToReturn; + })); + } + + @Override + public Map> get(Fmi2Builder.Port... ports) { + return get(builder.getDynamicScope().getActiveScope(), ports); + } + + @Override + public Map> get(Fmi2Builder.Scope scope, Fmi2Builder.Port... ports) { + + List selectedPorts; + if (ports == null || ports.length == 0) { + return Map.of(); + } else { + selectedPorts = Arrays.stream(ports).map(PortFmi3Api.class::cast).collect(Collectors.toList()); + } + + Map> results = new HashMap<>(); + + Map> typeToSortedPorts = new HashMap<>(); + ArrayVariableFmi2Api vrefBuf = getValueReferenceBuffer(); + + selectedPorts.stream().map(p -> p.scalarVariable.getVariable().getTypeIdentifier()).distinct() + .map(t -> selectedPorts.stream().filter(p -> p.scalarVariable.getVariable().getTypeIdentifier().equals(t)) + .sorted(Comparator.comparing(Fmi2Builder.Port::getPortReferenceValue)).collect(Collectors.toList())) + .forEach(l -> typeToSortedPorts.put(l.get(0).scalarVariable.getVariable().getTypeIdentifier(), l)); + + for (Map.Entry> e : typeToSortedPorts.entrySet()) { + for (int i = 0; i < e.getValue().size(); i++) { + PortFmi3Api p = e.getValue().get(i); + PStateDesignator designator = vrefBuf.items().get(i).getDesignator().clone(); + scope.add(newAAssignmentStm(designator, newAIntLiteralExp(p.getPortReferenceValue().intValue()))); + } + + + PType type; + switch (e.getKey()) { +// case Boolean: +// type = new ABooleanPrimitiveType(); +// break; +// case Real: +// type = new ARealNumericPrimitiveType(); +// break; +// case Integer: +// type = new AIntNumericPrimitiveType(); +// break; +// case String: +// type = new AStringPrimitiveType(); +// break; +// case Enumeration: +// throw new RuntimeException("Cannot assign enumeration port type."); +// default: +// throw new RuntimeException("Cannot match port types."); + default: + type = new AIntNumericPrimitiveType(); // TODO For now for testing + } + + ArrayVariableFmi2Api valBuf = getIOBuffer(type); + + AAssigmentStm stm = newAAssignmentStm(((IMablScope) scope).getFmiStatusVariable().getDesignator().clone(), + call(this.getReferenceExp().clone(), createFunctionName(FmiFunctionType.GET, e.getValue().get(0)), + vrefBuf.getReferenceExp().clone(), newAUIntLiteralExp((long) e.getValue().size()), valBuf.getReferenceExp().clone())); + scope.add(stm); + + if (builder.getSettings().fmiErrorHandlingEnabled) { + FmiStatusErrorHandlingBuilder.generate(builder, createFunctionName(FmiFunctionType.GET, e.getValue().get(0)), this, + (IMablScope) scope, MablApiBuilder.FmiStatus.FMI_ERROR, MablApiBuilder.FmiStatus.FMI_FATAL); + } + + if (builder.getSettings().setGetDerivatives && type.equals(new ARealNumericPrimitiveType())) { + derivativePortsToShare = getDerivatives(e.getValue(), scope); + } + + for (int i = 0; i < e.getValue().size(); i++) { + results.put(e.getValue().get(i), (VariableFmi2Api) valBuf.items().get(i)); + } + } + return results; + } + + /** + * @param ports The ports for which derivatives should be retrieved + * @param scope The builder scope. + * @return Derivative ports with a list of derivative values up to max derivative order + */ + public Map>> getDerivatives(List ports, Fmi2Builder.Scope scope) { + Map>> derivativePortsToReturn = new HashMap<>(); + +// // If any target ports exists that can interpolate the port is also linked and derivatives should be retrieved. +// // TODO: interpolation for FMI3? +// List portsLinkedToTargetsThatInterpolates = ports.stream().filter(p1 -> p1.getTargetPorts().stream().anyMatch(p2 -> { +// try { +// return p2.aMablFmi3InstanceAPI.getModelDescription().getCanInterpolateInputs(); +// } catch (XPathExpressionException e) { +// throw new RuntimeException("Exception occurred when accessing modeldescription: ", e); +// } +// })).collect(Collectors.toList()); +// +// try { +// int maxOutputDerOrder = modelDescriptionContext.getModelDescription().getMaxOutputDerivativeOrder(); +// if (portsLinkedToTargetsThatInterpolates.size() > 0 && maxOutputDerOrder > 0) { +// +// // Find derivative ports +// List derivativePorts = new ArrayList<>(); +// modelDescriptionContext.getModelDescription().getDerivativeToDerivativeSourceMap().entrySet().stream() +// .filter(entry -> portsLinkedToTargetsThatInterpolates.stream() +// .anyMatch(p -> p.getPortReferenceValue().equals(entry.getKey().getVariable().getValueReference()))).forEach(e -> +// // Find the PortFmi3Api representation of the scalarvariable derivative port. +// getPorts().stream().filter(p -> p.getPortReferenceValue().equals(e.getValue().getVariable().getValueReference())).findAny() +// .ifPresent(derivativePorts::add)); +// +// if (derivativePorts.size() > 0) { +// // Array size: number of ports for which to get derivatives multiplied the max derivative order. +// int arraySize = derivativePorts.size() * maxOutputDerOrder; +// +// ArrayVariableFmi2Api derValOutBuf = createBuffer(newRealType(), "DVal_OUT", arraySize, getDeclaredScope()); +// ArrayVariableFmi2Api derOrderOutBuf = createBuffer(newIntType(), "DOrder_OUT", arraySize, getDeclaredScope()); +// ArrayVariableFmi2Api derRefOutBuf = createBuffer(newUIntType(), "DRef_OUT", arraySize, getDeclaredScope()); +// +// // Loop arrays and assign derivative value reference and derivative order. +// // E.g for two ports with and a max derivative order of two: derRefOutBuf = [derPortRef1, derPortRef1, derPortRef2,derPortRef2], +// // derOrderOutBuf = [1,2,1,2] +// PortFmi3Api derivativePort = null; +// for (int arrayIndex = 0, portIndex = 0, order = 1; arrayIndex < arraySize; arrayIndex++) { +// // Switch to the next port when we have traversed a length of 'maxOutputDerOrder' in the arrays and reset order. +// if (arrayIndex % maxOutputDerOrder == 0) { +// order = 1; +// derivativePort = derivativePorts.get(portIndex); +// derivativePortsToReturn.put(derivativePort, derValOutBuf.items().subList(arrayIndex, arrayIndex + maxOutputDerOrder)); +// portIndex++; +// } +// +// PStateDesignator dRefDesignator = derRefOutBuf.items().get(arrayIndex).getDesignator().clone(); +// scope.add(newAAssignmentStm(dRefDesignator, newAIntLiteralExp(derivativePort.getPortReferenceValue().intValue()))); +// +// PStateDesignator derOrderDesignator = derOrderOutBuf.items().get(arrayIndex).getDesignator().clone(); +// scope.add(newAAssignmentStm(derOrderDesignator, newAIntLiteralExp(order))); +// order++; +// } +// +// // Create assignment statement which assigns derivatives to derValOutBuf by calling getRealOutputDerivatives with +// // derRefOutBuf, arraySize and derOrderOutBuf. +// PStm AStm = newAAssignmentStm(builder.getGlobalFmiStatus().getDesignator().clone(), +// call(this.getReferenceExp().clone(), createFunctionName(FmiFunctionType.GETREALOUTPUTDERIVATIVES), +// derRefOutBuf.getReferenceExp().clone(), newAUIntLiteralExp((long) arraySize), +// derOrderOutBuf.getReferenceExp().clone(), derValOutBuf.getReferenceExp().clone())); +// scope.add(AStm); +// +// // If enabled handle potential errors from calling getRealOutputDerivatives +// if (builder.getSettings().fmiErrorHandlingEnabled) { +// FmiStatusErrorHandlingBuilder.generate(builder, createFunctionName(FmiFunctionType.GETREALOUTPUTDERIVATIVES), this, +// (IMablScope) scope, MablApiBuilder.FmiStatus.FMI_ERROR, MablApiBuilder.FmiStatus.FMI_FATAL); +// } +// } +// } +// // TODO InvocationTargetException | IllegalAccessException ? +// } catch (XPathExpressionException e) { +// throw new RuntimeException("Exception occurred when retrieving derivatives: ", e); +// } + + return derivativePortsToReturn; + } + + @Override + public Map> get() { + return get(builder.getDynamicScope(), outputPorts.toArray(Fmi2Builder.Port[]::new)); + } + + @Override + public Map> get(int... valueReferences) { + List accept = Arrays.stream(valueReferences).boxed().collect(Collectors.toList()); + return get(builder.getDynamicScope(), + outputPorts.stream().filter(p -> accept.contains(p.getPortReferenceValue().intValue())).toArray(Fmi2Builder.Port[]::new)); + } + + @Override + public Map> get(String... names) { + List accept = Arrays.asList(names); + Fmi2Builder.Port[] ports = this.ports.stream().filter(p -> accept.contains(p.getName())).toArray(Fmi2Builder.Port[]::new); + return get(builder.getDynamicScope(), ports); + } + + /** + * Stores the final value in rootScope + * Uses the rootScope for valueReferences + */ + @Override + public Map> getAndShare(String... names) { + + Map> values = get(names); + share(values); + return values; + } + + @Override + public Map> getAndShare(Fmi2Builder.Port... ports) { + Map> values = get(ports); + share(values); + return values; + } + + @Override + public Map> getAndShare() { + Map> values = get(); + share(values); + return values; + } + + @Override + public VariableFmi2Api getShared(String name) { + return this.getPort(name).getSharedAsVariable(); + } + + @Override + public VariableFmi2Api getShared(Fmi2Builder.Port port) { + return ((PortFmi3Api) port).getSharedAsVariable(); + } + + @Override + public VariableFmi2Api getSingle(Fmi2Builder.Port port) { + return (VariableFmi2Api) this.get(port).entrySet().iterator().next().getValue(); + } + + private String createFunctionName(FmiFunctionType fun) { + switch (fun) { + case ENTERINITIALIZATIONMODE: + return "enterInitializationMode"; + case EXITINITIALIZATIONMODE: + return "exitInitializationMode"; + case SETUPEXPERIMENT: + return "setupExperiment"; + case GETREALOUTPUTDERIVATIVES: + return "getRealOutputDerivatives"; + case SETREALINPUTDERIVATIVES: + return "setRealInputDerivatives"; + case TERMINATE: + return "terminate"; + default: + throw new RuntimeException("Attempting to call function that is type dependant without specifying type: " + fun); + } + + } + + private String createFunctionName(FmiFunctionType fun, PortFmi3Api p) { + return createFunctionName(fun, p.scalarVariable.getVariable().getTypeIdentifier()); + } + + private String createFunctionName(FmiFunctionType f, Fmi3TypeEnum type) { + String functionName = ""; + switch (f) { + case GET: + functionName += "get"; + break; + case SET: + functionName += "set"; + break; + default: + throw new RuntimeException("Attempting to call non type-dependant function with type: " + type); + } + functionName += type.name(); + return functionName; + } + + @Override + public VariableFmi2Api getSingle(String name) { + return this.get(name).entrySet().iterator().next().getValue(); + } + + + + public void set(Fmi2Builder.Port p, Fmi2Builder.ExpressionValue v) { + this.set(new PortValueExpresssionMapImpl(Map.of(p, v))); + ; + } + + public void set(Fmi2Builder.Scope scope, Fmi2Builder.Port p, Fmi2Builder.ExpressionValue v) { + this.set(scope, new PortValueMapImpl(Map.of(p, v))); + } + + public void set(PortExpressionValueMap value) { + this.set(builder.getDynamicScope().getActiveScope(), value); + } + + public void set(Fmi2Builder.Scope scope, PortExpressionValueMap value) { + if (value == null || value.isEmpty()) { + return; + } + + List selectedPorts = value.keySet().stream().map(PortFmi3Api.class::cast).collect(Collectors.toList()); + + set(scope, selectedPorts, port -> { + Fmi2Builder.ExpressionValue value_ = value.get(port); + return Map.entry(value_.getExp(), value_.getType()); + }); + } + + @Override + public void set(Fmi2Builder.Scope scope, PortValueMap value) { + + + if (value == null || value.isEmpty()) { + return; + } + + List selectedPorts = value.keySet().stream().map(PortFmi3Api.class::cast).collect(Collectors.toList()); + + + set(scope, selectedPorts, port -> { + Object val = (value.get(port)).get(); + if (val instanceof Double) { + return Map.entry(newARealLiteralExp((Double) val), newRealType()); + } + if (val instanceof Long) { + return Map.entry(newAUIntLiteralExp((Long) val), newUIntType()); + } + if (val instanceof Integer) { + return Map.entry(newAIntLiteralExp((Integer) val), newIntType()); + } + if (val instanceof Boolean) { + return Map.entry(newABoolLiteralExp((Boolean) val), newBoleanType()); + } + if (val instanceof String) { + return Map.entry(newAStringLiteralExp((String) val), newStringType()); + } + return null; + }); + } + + @Override + public void set(Fmi2Builder.Scope scope, PortVariableMap value) { + + List selectedPorts; + if (value == null || value.isEmpty()) { + return; + } else { + selectedPorts = value.keySet().stream().map(PortFmi3Api.class::cast).collect(Collectors.toList()); + } + + final PortVariableMap valueFinal = value; + set(scope, selectedPorts, + port -> Map.entry(((VariableFmi2Api) valueFinal.get(port)).getReferenceExp().clone(), ((VariableFmi2Api) valueFinal.get(port)).type)); + } + + public void set(Fmi2Builder.Scope scope, List selectedPorts, Function> portToValue) { + + Set selectedPortsAsStrings = selectedPorts.stream() + .map(p -> p.getName() + "-" + p.aMablFmi3InstanceAPI.getName() + "-" + p.aMablFmi3InstanceAPI.getOwner().getName()) + .collect(toSet()); + selectedPortsAsStrings.removeAll( + ports.stream().map(p -> p.getName() + "-" + p.aMablFmi3InstanceAPI.getName() + "-" + p.aMablFmi3InstanceAPI.getOwner().getName()) + .collect(toSet())); + if (selectedPortsAsStrings.size() > 0) { + throw new RuntimeException("Unable to set port(s) that is not declared in the FMU: " + + selectedPortsAsStrings.stream().map(name -> name.split("-")[0]).collect(Collectors.joining(", "))); + } + + List sortedPorts = + selectedPorts.stream().sorted(Comparator.comparing(Fmi2Builder.Port::getPortReferenceValue)).collect(Collectors.toList()); + + // Group by the string value of the port type as grouping by the port type itself doesnt utilise equals + sortedPorts.stream().collect(Collectors.groupingBy(i -> i.getType().toString())).forEach((key, value) -> { + ArrayVariableFmi2Api vrefBuf = getValueReferenceBuffer(); + PType type = value.get(0).getType(); + for (int i = 0; i < value.size(); i++) { + Fmi2Builder.Port p = value.get(i); + PStateDesignator designator = vrefBuf.items().get(i).getDesignator().clone(); + scope.add(newAAssignmentStm(designator, newAIntLiteralExp(p.getPortReferenceValue().intValue()))); + } + + ArrayVariableFmi2Api valBuf = getIOBuffer(type); + for (int i = 0; i < value.size(); i++) { + PortFmi3Api p = value.get(i); + PStateDesignator designator = valBuf.items().get(i).getDesignator(); + + scope.addAll(BuilderUtil.createTypeConvertingAssignment(builder, scope, designator.clone(), portToValue.apply(p).getKey().clone(), + portToValue.apply(p).getValue(), valBuf.type)); + } + + AAssigmentStm stm = newAAssignmentStm(((IMablScope) scope).getFmiStatusVariable().getDesignator().clone(), + call(this.getReferenceExp().clone(), createFunctionName(FmiFunctionType.SET, value.get(0)), vrefBuf.getReferenceExp().clone(), + newAUIntLiteralExp((long) value.size()), valBuf.getReferenceExp().clone())); + scope.add(stm); + + if (builder.getSettings().fmiErrorHandlingEnabled) { + FmiStatusErrorHandlingBuilder.generate(builder, createFunctionName(FmiFunctionType.SET, sortedPorts.get(0)), this, (IMablScope) scope, + MablApiBuilder.FmiStatus.FMI_ERROR, MablApiBuilder.FmiStatus.FMI_FATAL); + } + + // TODO: IntermediateUpdateMode instead of CanInterpolateInputs? + // TODO: commented out for no so it compiles +// try { +// if (builder.getSettings().setGetDerivatives && modelDescriptionContext.getModelDescription().getCanInterpolateInputs() && +// type.equals(new ARealNumericPrimitiveType())) { +// setDerivativesForSharedPorts(value, scope); +// } +// } catch (XPathExpressionException e) { +// throw new RuntimeException("Exception occurred when when setting derivatives.", e); +// } + }); + } +// +// /** +// * @param ports The ports for which derivative should be set from SHARED derivative ports +// * @param scope The builder scope +// */ +// private void setDerivativesForSharedPorts(List ports, Fmi2Builder.Scope scope) { +// // Find all ports for which derivatives should be passed together with the derivatives and their order. +// LinkedHashMap> mapPortsToDerPortsWithOrder = +// ports.stream().filter(port -> port.getSourcePort() != null).map(port -> { +// try { +// Map.Entry innerEntry; +// // Find if port is in map of derivatives +// Optional> derivativePortEntry = +// port.getSourcePort().aMablFmi3InstanceAPI.getModelDescription().getDerivativeToDerivativeSourceMap().entrySet().stream() +// .filter(e -> e.getKey().getVariable().getValueReferenceAsLong().equals(port.getSourcePort().getPortReferenceValue())).findAny(); +// +// +// if (derivativePortEntry.isPresent()) { +// // Find PortFmi3Api value of the scalarvariable derivative port and the components max output derivative. +// innerEntry = Map.entry(port.getSourcePort().aMablFmi3InstanceAPI.getPort((int) +// derivativePortEntry.get().getValue().getVariable().getValueReferenceAsLong()), +// port.getSourcePort().aMablFmi3InstanceAPI.getModelDescription().getMaxOutputDerivativeOrder()); +// return Map.entry(port, innerEntry); +// } +// +// return null; +// } catch (XPathExpressionException | IllegalAccessException | InvocationTargetException e) { +// throw new RuntimeException("Exception occurred when accessing modeldescription: ", e); +// } +// }).filter(Objects::nonNull).collect(LinkedHashMap::new, (map, item) -> map.put(item.getKey(), item.getValue()), // Accumulator +// Map::putAll); +// +// if (mapPortsToDerPortsWithOrder.size() > 0) { +// // Get the total array size as the sum of derivative orders. +// int arraySize = mapPortsToDerPortsWithOrder.values().stream().mapToInt(Map.Entry::getValue).sum(); +// +// // Create input arrays +// ArrayVariableFmi2Api derValInBuf = createBuffer(newRealType(), "DVal_IN", arraySize, getDeclaredScope()); +// ArrayVariableFmi2Api derOrderInBuf = createBuffer(newIntType(), "DOrder_IN", arraySize, getDeclaredScope()); +// ArrayVariableFmi2Api derRefInBuf = createBuffer(newUIntType(), "DRef_IN", arraySize, getDeclaredScope()); +// +// // Loop through arrays and assign the port reference, derivative order and derivative value. +// // E.g: for two derivative ports Out1 (linked to In1) and Out2 (linked to In2) with a max derivative order of 2 and 1: derValInBuf = [der +// // (Out1), der(der(Out1)),der(Out2))], derOrderInBuf = [1,2,1], derRefInBuf = [In1, In1, In2] +// int arrayIndex = 0; +// for (Map.Entry> entry : mapPortsToDerPortsWithOrder.entrySet()) { +// PortFmi3Api port = entry.getKey(); +// int maxOrder = entry.getValue().getValue(); +// for (int order = 1; order <= maxOrder; order++, arrayIndex++) { +// // Assign to array variables +// PStateDesignator derRefDesignator = derRefInBuf.items().get(arrayIndex).getDesignator().clone(); +// scope.add(newAAssignmentStm(derRefDesignator, newAIntLiteralExp(port.getPortReferenceValue().intValue()))); +// +// PStateDesignator derOrderDesignator = derOrderInBuf.items().get(arrayIndex).getDesignator().clone(); +// scope.add(newAAssignmentStm(derOrderDesignator, newAIntLiteralExp(order))); +// +// PStateDesignator derValInDesignator = derValInBuf.items().get(arrayIndex).getDesignator().clone(); +// scope.add(newAAssignmentStm(derValInDesignator, +// ((VariableFmi2Api) ((ArrayVariableFmi2Api) entry.getValue().getKey().getSharedAsVariable()).items() +// .get(order - 1)).getReferenceExp().clone())); +// } +// } +// +// setDerivatives(derValInBuf, derOrderInBuf, derRefInBuf, scope); +// } +// } + + /** + * If two derivative ports 'Out1' (linked to 'In1') and 'Out2' (linked to 'In2') with a max derivative order of 2 and 1 then derValInBuf = + * [der(Out1), der(der(Out1)), der(Out2))], derOrderInBuf = [1,2,1], derRefInBuf = [In1, In1, In2] + * + * @param derValInBuf derivative values + * @param derOrderInBuf derivative value orders + * @param derRefInBuf ports for which to set the derivative + * @param scope the builder scope + */ + public void setDerivatives(ArrayVariableFmi2Api derValInBuf, ArrayVariableFmi2Api derOrderInBuf, ArrayVariableFmi2Api derRefInBuf, + Fmi2Builder.Scope scope) { + int arraySize = derValInBuf.size(); + + // Create set derivatives statement which calls setRealOutputDerivatives with derRefInBuf, arraySize, derOrderInBuf and + // derValInBuf. + PStm ifStm = newAAssignmentStm(builder.getGlobalFmiStatus().getDesignator().clone(), + call(this.getReferenceExp().clone(), createFunctionName(FmiFunctionType.SETREALINPUTDERIVATIVES), + derRefInBuf.getReferenceExp().clone(), newAUIntLiteralExp((long) arraySize), derOrderInBuf.getReferenceExp().clone(), + derValInBuf.getReferenceExp().clone())); + scope.add(ifStm); + + // If enabled handle potential errors from calling setRealInputDerivatives + if (builder.getSettings().fmiErrorHandlingEnabled) { + FmiStatusErrorHandlingBuilder.generate(builder, createFunctionName(FmiFunctionType.SETREALINPUTDERIVATIVES), this, (IMablScope) scope, + MablApiBuilder.FmiStatus.FMI_ERROR, MablApiBuilder.FmiStatus.FMI_FATAL); + } + } + + @Override + public void set(PortValueMap value) { + set(builder.getDynamicScope(), value); + } + + @Override + public void set(Fmi2Builder.Port port, Fmi2Builder.Variable value) { + this.set(new PortVariableMapImpl(Map.of(port, value))); + } + + @Override + public void set(Fmi2Builder.Scope scope, Fmi2Builder.Port port, Fmi2Builder.Variable value) { + this.set(scope, new PortVariableMapImpl(Map.of(port, value))); + } + + @Override + public void set(Fmi2Builder.Port port, Fmi2Builder.Value value) { + PortValueMap map = new PortValueMapImpl(); + map.put(port, value); + set(map); + + } + + + @Override + public void set(PortVariableMap value) { + set(builder.getDynamicScope(), value); + } + + @Override + public void setLinked(Fmi2Builder.Scope scope, Fmi2Builder.Port... filterPorts) { + + List selectedPorts = ports.stream().filter(isLinked).collect(Collectors.toList()); + if (filterPorts != null && filterPorts.length != 0) { + + List filterList = Arrays.asList(filterPorts); + + for (Fmi2Builder.Port p : filterList) { + if (!isLinked.test(p)) { + logger.warn("Filter for setLinked contains unlined port. Its ignored. {}", p); + } + } + + selectedPorts = selectedPorts.stream().filter(filterList::contains).collect(Collectors.toList()); + } + if (selectedPorts.size() == 0) { + logger.warn("No linked input variables for FMU instance: " + this.getName()); + return; + } + + + for (PortFmi3Api port : selectedPorts) { + if (port.getSourcePort() == null) { + throw new RuntimeException( + "Attempting to obtain shared value from a port that is not linked. This port is missing a required " + "link: " + port); + } + + if (port.getSourcePort().getSharedAsVariable() == null) { + throw new RuntimeException( + "Attempting to obtain shared values from a port that is linked but has no value shared. Share a value " + "first. " + port); + + } + } + + set(scope, selectedPorts, + k -> Map.entry(k.getSourcePort().getSharedAsVariable().getReferenceExp().clone(), k.getSourcePort().getSharedAsVariable().type)); + + } + + @Override + public void setLinked() { + this.setLinked(dynamicScope, (Fmi2Builder.Port[]) null); + } + + @Override + public void setLinked(Fmi2Builder.Port... filterPorts) { + + this.setLinked(dynamicScope, filterPorts); + } + + @Override + public void setLinked(String... filterNames) { + List accept = Arrays.asList(filterNames); + this.setLinked(dynamicScope, getPorts().stream().filter(p -> accept.contains(p.getName())).toArray(Fmi2Builder.Port[]::new)); + + } + + @Override + public void setLinked(long... filterValueReferences) { + List accept = Arrays.stream(filterValueReferences).boxed().collect(Collectors.toList()); + this.setLinked(dynamicScope, getPorts().stream().filter(p -> accept.contains(p.getPortReferenceValue())).toArray(Fmi2Builder.Port[]::new)); + + } + + @Override + public void setInt(Map> values) { + + } + + @Override + public void setString(Map> value) { + + } + + @Override + public void terminate() { + this.terminate(builder.getDynamicScope()); + } + + @Override + public void terminate(Fmi2Builder.Scope scope) { + PStm stm = stateTransitionFunction(FmiFunctionType.TERMINATE); + scope.add(stm); + if (builder.getSettings().fmiErrorHandlingEnabled) { + FmiStatusErrorHandlingBuilder.generate(builder, "terminate", this, (IMablScope) scope, MablApiBuilder.FmiStatus.FMI_ERROR, + MablApiBuilder.FmiStatus.FMI_FATAL); + } + } + + // TODO: implement this from the other share function below. This for now to build. + @Override + public void share(Map> values) { + ; + } + +// @Override +// public void share(Map> values) { +// // Group by the string value of the port type as grouping by the port type itself doesnt utilise equals +// values.entrySet().stream().collect(Collectors.groupingBy(map -> ((PortFmi3Api) map.getKey()).getType().toString())).entrySet().stream() +// .forEach(map -> { +// PType type = ((PortFmi3Api) map.getValue().get(0).getKey()).getType(); +// +// Map data = +// map.getValue().stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); +// +// data.keySet().stream().map(PortFmi3Api.class::cast).sorted(Comparator.comparing(PortFmi3Api::getPortReferenceValue)) +// .forEach(port -> { +// //this is the sorted set of assignments, these can be replaced by a memcopy later +// ArrayVariableFmi2Api buffer = getSharedBuffer(type); +// if (port.getSharedAsVariable() == null) { +// ArrayVariableFmi2Api newBuf = growBuffer(buffer, 1); +// this.setSharedBuffer(newBuf, type); +// +// VariableFmi2Api newShared = newBuf.items().get(newBuf.items().size() - 1); +// port.setSharedAsVariable(newShared); +// } +// +// PStateDesignator designator = port.getSharedAsVariable().getDesignator(); +// builder.getDynamicScope().addAll(BuilderUtil.createTypeConvertingAssignment(builder, dynamicScope, designator.clone(), +// ((VariableFmi2Api) data.get(port)).getReferenceExp().clone(), port.getType(), +// ((VariableFmi2Api) ((VariableFmi2Api) data.get(port))).type)); +// +// +// if (type.equals(new ARealNumericPrimitiveType()) && derivativePortsToShare != null) { +// // Find match a derivativePortsToShare where both port reference and derivative port reference matches. +// derivativePortsToShare.keySet().stream().filter(derivativePort -> { +// try { +// return modelDescriptionContext.getModelDescription().getDerivativesMap().entrySet().stream().anyMatch( +// e -> e.getKey().getValueReference().equals(port.getPortReferenceValue()) && +// e.getValue().getValueReference().equals(derivativePort.getPortReferenceValue())); +// } catch (XPathExpressionException | InvocationTargetException | IllegalAccessException e) { +// throw new RuntimeException( +// "Attempting to obtain shared values from a port that is linked but has no value shared. Share a value " + +// "first. " + port); +// } +// }).findFirst().ifPresent((derivativePort) -> { +// // If the derivative port is not yet shared then get shared derivative buffer, grow it by one and set the port as shared +// // with the new array. +// if (derivativePort.getSharedAsVariable() == null) { +// ArrayVariableFmi2Api sharedDerBuf = growSharedDerBuf(1); +// +// ArrayVariableFmi2Api newSharedArray = +// (ArrayVariableFmi2Api) sharedDerBuf.items().get(sharedDerBuf.items().size() - 1); +// derivativePort.setSharedAsVariable(newSharedArray); +// } +// +// // DerivativePorts.get(derivativePort).size should equal derivativePort.getSharedAsVariable().items().size() as they are +// // both determined by the max derivative order. +// List derivatives = ((ArrayVariableFmi2Api) derivativePort.getSharedAsVariable()).items(); +// for (int i = 0; i < derivatives.size(); i++) { +// PExp val = derivativePortsToShare.get(derivativePort).get(i).getReferenceExp().clone(); +// builder.getDynamicScope().add(newAAssignmentStm(derivatives.get(i).getDesignator().clone(), val)); +// } +// }); +// } +// }); +// }); +// } + + /** + * @param increaseByCount the length of which the outer array should grow + * @return a two dimensional non-jagged array for derivatives. + * e.g.: [originalSize+increaseByCount][maxDerivativeOrder] + */ + private ArrayVariableFmi2Api growSharedDerBuf(int increaseByCount) { + + // Get shared buffer creates the buffer with one element. + if (this.derSharedBuffer == null && increaseByCount == 1) { + return getSharedDerBuffer(); + } + + ArrayVariableFmi2Api sharedBuffer = getSharedDerBuffer(); + + int innerArraySize; + try { + innerArraySize = modelDescriptionContext.getModelDescription().getMaxOutputDerivativeOrder(); + } catch (XPathExpressionException e) { + throw new RuntimeException("Exception occurred when accessing model description: ", e); + } + + String bufferName = ((AIdentifierExp) sharedBuffer.getReferenceExp()).getName().getText(); + int outerArraySize = sharedBuffer.size() + increaseByCount; + + PStm outerArrayVariableStm = newALocalVariableStm( + newAVariableDeclarationMultiDimensionalArray(newAIdentifier(bufferName), newARealNumericPrimitiveType(), + Arrays.asList(outerArraySize, innerArraySize))); + + sharedBuffer.getDeclaringStm().parent().replaceChild(sharedBuffer.getDeclaringStm(), outerArrayVariableStm); + + List> items = new ArrayList<>(); + + // Add new element(s) to array. + // E.g: buff[1][1] with increaseByCount of 2 will become: buff[3][1] where 1 equals the max derivative order. + for (int i = 0; i < increaseByCount; i++) { + int outerIndex = sharedBuffer.size() + i; + + List> variables = new ArrayList<>(); + // Create variables + for (int l = 0; l < innerArraySize; l++) { + AArrayStateDesignator designator = newAArayStateDesignator( + newAArayStateDesignator(newAIdentifierStateDesignator(newAIdentifier(bufferName)), newAIntLiteralExp(outerIndex)), + newAIntLiteralExp(l)); + + AArrayIndexExp indexExp = + newAArrayIndexExp(newAIdentifierExp(bufferName), Arrays.asList(newAIntLiteralExp(outerIndex), newAIntLiteralExp(l))); + + variables.add( + new VariableFmi2Api<>(outerArrayVariableStm, type, this.getDeclaredScope(), builder.getDynamicScope(), designator, indexExp)); + } + // Create array with variables + ArrayVariableFmi2Api innerArrayVariable = + new ArrayVariableFmi2Api<>(outerArrayVariableStm, newARealNumericPrimitiveType(), getDeclaredScope(), builder.getDynamicScope(), + newAArayStateDesignator(newAIdentifierStateDesignator(newAIdentifier(bufferName)), newAIntLiteralExp(outerIndex)), + newAArrayIndexExp(newAIdentifierExp(bufferName), Collections.singletonList(newAIntLiteralExp(outerIndex))), variables); + + items.add(innerArrayVariable); + } + // Add new array(s) to existing arrays + items.addAll(0, sharedBuffer.items()); + + return new ArrayVariableFmi2Api<>(outerArrayVariableStm, newAArrayType(newARealNumericPrimitiveType()), getDeclaredScope(), + builder.getDynamicScope(), newAIdentifierStateDesignator(newAIdentifier(bufferName)), newAIdentifierExp(bufferName), items); + + } + + private void setSharedBuffer(ArrayVariableFmi2Api newBuf, PType type) { + this.sharedBuffer.entrySet().removeIf(x -> x.getKey().toString().equals(type.toString())); + this.sharedBuffer.put(type, newBuf); + + } + + private ArrayVariableFmi2Api growBuffer(ArrayVariableFmi2Api buffer, int increaseByCount) { + + String ioBufName = ((AIdentifierExp) buffer.getReferenceExp()).getName().getText(); + + int length = buffer.size() + increaseByCount; + PStm var = newALocalVariableStm(newAVariableDeclaration(newAIdentifier(ioBufName), buffer.type, length, null)); + + buffer.getDeclaringStm().parent().replaceChild(buffer.getDeclaringStm(), var); + // getDeclaredScope().addAfter(getDeclaringStm(), var); + + List> items = IntStream.range(buffer.size(), length).mapToObj( + i -> new VariableFmi2Api<>(var, buffer.type, this.getDeclaredScope(), builder.getDynamicScope(), + newAArayStateDesignator(newAIdentifierStateDesignator(newAIdentifier(ioBufName)), newAIntLiteralExp(i)), + newAArrayIndexExp(newAIdentifierExp(ioBufName), Collections.singletonList(newAIntLiteralExp(i))))) + .collect(Collectors.toList()); + + //we can not replace these as some of them may be used and could potential have reference problems (they should not but just to be sure) + items.addAll(0, buffer.items()); + + return new ArrayVariableFmi2Api<>(var, buffer.type, getDeclaredScope(), builder.getDynamicScope(), + newAIdentifierStateDesignator(newAIdentifier(ioBufName)), newAIdentifierExp(ioBufName), items); + + } + + @Override + public Fmi2Builder.StateVariable getState() throws XPathExpressionException { + return getState(builder.getDynamicScope()); + } + + @Override + public Fmi2Builder.StateVariable getState(Fmi2Builder.Scope scope) throws XPathExpressionException { + if (!this.modelDescriptionContext.getModelDescription().getCanGetAndSetFmustate()) { + throw new RuntimeException("Unable to get state on fmu: " + this.getOwner() + " with instance name: " + this.getName()); + } + + String stateName = builder.getNameGenerator().getName(name, "state"); + PStm stateVar = newVariable(stateName, newANameType("FmiComponentState")); + scope.add(stateVar); + + StateMablVariableFmi3Api state = + new StateMablVariableFmi3Api(stateVar, newANameType("FmiComponentState"), (IMablScope) scope, builder.getDynamicScope(), + newAIdentifierStateDesignator(stateName), newAIdentifierExp(stateName), builder, this); + + AAssigmentStm stm = newAAssignmentStm(((IMablScope) scope).getFmiStatusVariable().getDesignator().clone(), + call(this.getReferenceExp().clone(), "getState", Collections.singletonList(newARefExp(state.getReferenceExp().clone())))); + scope.add(stm); + if (builder.getSettings().fmiErrorHandlingEnabled) { + FmiStatusErrorHandlingBuilder.generate(builder, "getState", this, (IMablScope) scope, MablApiBuilder.FmiStatus.FMI_ERROR, + MablApiBuilder.FmiStatus.FMI_FATAL); + } + + return state; + } + + public FmuVariableFmi3Api getOwner() { + return this.owner; + } + + public List getAllConnectedOutputs() { + return this.ports.stream().filter(x -> x.scalarVariable.getVariable().getCausality() == Fmi3Causality.Output && x.getTargetPorts().size() > 0) + .collect(Collectors.toList()); + } + + @Override + public String getName() { + return this.name; + } + + public String getEnvironmentName() { + return environmentName; + } + + + public enum FmiFunctionType { + GET, + SET, + ENTERINITIALIZATIONMODE, + EXITINITIALIZATIONMODE, + SETUPEXPERIMENT, + GETREALOUTPUTDERIVATIVES, + SETREALINPUTDERIVATIVES, + TERMINATE + } + + /** + * Error and Fatal should lead to freeInstance calls followed by subsequent termination. + */ + static class FmiStatusErrorHandlingBuilder { + static void generate(MablApiBuilder builder, String method, InstanceVariableFmi3Api instance, IMablScope scope, + MablApiBuilder.FmiStatus... statusesToFail) { + if (statusesToFail == null || statusesToFail.length == 0) { + return; + } + + Function checkStatusEq = + s -> newEqual(((IMablScope) scope).getFmiStatusVariable().getReferenceExp().clone(), + builder.getFmiStatusConstant(s).getReferenceExp().clone()); + + PExp exp = checkStatusEq.apply(statusesToFail[0]); + + for (int i = 1; i < statusesToFail.length; i++) { + exp = newOr(exp, checkStatusEq.apply(statusesToFail[i])); + } + + ScopeFmi2Api thenScope = scope.enterIf(new PredicateFmi2Api(exp)).enterThen(); + + // thenScope.add(newAAssignmentStm(builder.getGlobalExecutionContinue().getDesignator().clone(), newABoolLiteralExp(false))); + + for (MablApiBuilder.FmiStatus status : statusesToFail) { + ScopeFmi2Api s = thenScope.enterIf(new PredicateFmi2Api(checkStatusEq.apply(status))).enterThen(); + builder.getLogger() + .error(s, method.substring(0, 1).toUpperCase() + method.substring(1) + " failed on '%s' with status: " + status, instance); + } + + thenScope.add(new AErrorStm(newAStringLiteralExp("Failed to '" + method + "' on '" + instance.getName() + "'"))); + thenScope.leave(); + } + + static Set collectedPreviousLoadedModules(INode node/*, Set externalLoadedModuleIdentifiers*/) { + + if (node == null) { + return new HashSet<>(); + } + + Function getLoadedIdentifier = s -> { + AtomicReference id = new AtomicReference<>(); + try { + s.apply(new DepthFirstAnalysisAdaptor() { + @Override + public void caseALoadExp(ALoadExp node) { + AVariableDeclaration decl = node.getAncestor(AVariableDeclaration.class); + if (decl != null) { + id.set(decl.getName().getText()); + } + ALocalVariableStm ldecl = node.getAncestor(ALocalVariableStm.class); + if (decl != null) { + id.set(ldecl.getDeclaration().getName().getText()); + } + } + }); + } catch (AnalysisException e) { + e.addSuppressed(e); + } + return id.get(); + }; + + Set identifiers = new HashSet<>(); + if (node instanceof SBlockStm) { + + for (PStm n : ((SBlockStm) node).getBody()) { + String id = getLoadedIdentifier.apply(n); + if (id != null) { + identifiers.add(id); + } + } + } + + if (node.parent() != null) { + identifiers.addAll(collectedPreviousLoadedModules(node.parent()/*, externalLoadedModuleIdentifiers*/)); + } + /* + if (identifiers != null) { + identifiers.removeAll(externalLoadedModuleIdentifiers); + }*/ + + return identifiers; + + } + } + } diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/StateMablVariableFmi2Api.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/StateMablVariableFmi2Api.java index c2cfc3b1..1dea8288 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/StateMablVariableFmi2Api.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/StateMablVariableFmi2Api.java @@ -22,11 +22,14 @@ public StateMablVariableFmi2Api(PStm declaration, PType type, IMablScope declare this.builder = builder; } + @Override public void set() throws IllegalStateException { set(builder.getDynamicScope()); } + + @Override public void set(Fmi2Builder.Scope scope) throws IllegalStateException { if (!valid) { diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/StateMablVariableFmi3Api.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/StateMablVariableFmi3Api.java new file mode 100644 index 00000000..826610ad --- /dev/null +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/StateMablVariableFmi3Api.java @@ -0,0 +1,75 @@ +package org.intocps.maestro.framework.fmi2.api.mabl.variables; + +import org.intocps.maestro.ast.node.*; +import org.intocps.maestro.framework.fmi2.api.Fmi2Builder; +import org.intocps.maestro.framework.fmi2.api.mabl.MablApiBuilder; +import org.intocps.maestro.framework.fmi2.api.mabl.scoping.IMablScope; + +import java.util.Collections; + +import static org.intocps.maestro.ast.MableAstFactory.newAAssignmentStm; +import static org.intocps.maestro.ast.MableBuilder.call; + +public class StateMablVariableFmi3Api extends VariableFmi2Api implements Fmi2Builder.StateVariable { + private final InstanceVariableFmi3Api owner; + private final MablApiBuilder builder; + private boolean valid = true; + + public StateMablVariableFmi3Api(PStm declaration, PType type, IMablScope declaredScope, Fmi2Builder.DynamicActiveScope dynamicScope, + PStateDesignator designator, PExp referenceExp, MablApiBuilder builder, InstanceVariableFmi3Api owner) { + super(declaration, type, declaredScope, dynamicScope, designator, referenceExp); + this.owner = owner; + this.builder = builder; + } + + + @Override + public void set() throws IllegalStateException { + set(builder.getDynamicScope()); + } + + @Override + public void set(Fmi2Builder.Scope scope) throws IllegalStateException { + if (!valid) { + throw new IllegalStateException(); + } + AAssigmentStm stm = newAAssignmentStm(((IMablScope) scope).getFmiStatusVariable().getDesignator().clone(), + call(owner.getReferenceExp().clone(), "setState", Collections.singletonList(this.getReferenceExp().clone()))); + scope.add(stm); + if (builder.getSettings().fmiErrorHandlingEnabled) { + InstanceVariableFmi3Api.FmiStatusErrorHandlingBuilder + .generate(builder, "setState", this.owner, (IMablScope) scope, MablApiBuilder.FmiStatus.FMI_ERROR, + MablApiBuilder.FmiStatus.FMI_FATAL); + } + } + + @Override + public void destroy() throws IllegalStateException { + destroy(builder.getDynamicScope()); + } + + @Override + public void destroy(Fmi2Builder.Scope scope) throws IllegalStateException { + if (!valid) { + throw new IllegalStateException(); + } + + AAssigmentStm stm = newAAssignmentStm(((IMablScope) scope).getFmiStatusVariable().getDesignator().clone(), + call(owner.getReferenceExp().clone(), "freeState", Collections.singletonList(this.getReferenceExp().clone()))); + scope.add(stm); + if (builder.getSettings().fmiErrorHandlingEnabled) { + InstanceVariableFmi3Api.FmiStatusErrorHandlingBuilder + .generate(builder, "freeState", this.owner, (IMablScope) scope, MablApiBuilder.FmiStatus.FMI_ERROR, + MablApiBuilder.FmiStatus.FMI_FATAL); + } + + valid = false; + } + + @Override + public void setValue(Fmi2Builder.Scope scope, Object value) { + throw new IllegalStateException(); + } + + +} diff --git a/maestro/src/test/java/org/intocps/maestro/BuilderFmi3Test.java b/maestro/src/test/java/org/intocps/maestro/BuilderFmi3Test.java index 71814e92..e5b0fd37 100644 --- a/maestro/src/test/java/org/intocps/maestro/BuilderFmi3Test.java +++ b/maestro/src/test/java/org/intocps/maestro/BuilderFmi3Test.java @@ -18,10 +18,7 @@ import org.intocps.maestro.framework.fmi2.api.mabl.MablApiBuilder; import org.intocps.maestro.framework.fmi2.api.mabl.PortFmi2Api; import org.intocps.maestro.framework.fmi2.api.mabl.scoping.DynamicActiveBuilderScope; -import org.intocps.maestro.framework.fmi2.api.mabl.variables.ComponentVariableFmi2Api; -import org.intocps.maestro.framework.fmi2.api.mabl.variables.FmuVariableFmi2Api; -import org.intocps.maestro.framework.fmi2.api.mabl.variables.FmuVariableFmi3Api; -import org.intocps.maestro.framework.fmi2.api.mabl.variables.VariableFmi2Api; +import org.intocps.maestro.framework.fmi2.api.mabl.variables.*; import org.intocps.maestro.interpreter.DefaultExternalValueFactory; import org.intocps.maestro.interpreter.MableInterpreter; import org.intocps.maestro.typechecker.TypeChecker; @@ -80,11 +77,14 @@ public void wt() throws Exception { URI ballUri = new File("target/Fmi3ModuleReferenceFmusTest/cache/BouncingBall.fmu").getAbsoluteFile().toURI(); Fmu3 ball = new Fmu3(new File(ballUri)); + ArrayVariableFmi2Api varArray = builder.getDynamicScope().store("varArray", new Long[] {1L}); Fmi3ModelDescription md3Ball = new Fmi3ModelDescription(ball.getModelDescription()); FmuVariableFmi3Api ballFmu = builder.getDynamicScope().createFMU("ball", md3Ball, ballUri); + InstanceVariableFmi3Api ballInstance = ballFmu.instantiate("ballInstance", varArray); + // Create the two FMUs FmuVariableFmi2Api controllerFMU = builder.getDynamicScope()