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 bfe4b78a..089ee463 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 @@ -592,7 +592,7 @@ class Fmi3ModelDescription : ModelDescription { val typeDefinition: ClockTypeDefinition? = getTypeDefinitionFromDeclaredType(declaredType ?: "") as ClockTypeDefinition? - val interval = node.attributes.getNamedItem("interval")?.nodeValue + val interval = node.attributes.getNamedItem("intervalVariability")?.nodeValue return ClockVariable( node.attributes.getNamedItem("name").nodeValue, @@ -610,15 +610,15 @@ class Fmi3ModelDescription : ModelDescription { node.attributes.getNamedItem("clocks")?.nodeValue?.split(" ")?.map { value -> value.toUInt() }, Fmi3TypeEnum.ClockType, declaredType, - node.attributes.getNamedItem("canBeDeactivated").nodeValue?.toBoolean() - ?: typeDefinition?.canBeDeactivated, + when(node.attributes.getNamedItem("canBeDeactivated")?.nodeValue?.toBoolean() + ?: typeDefinition?.canBeDeactivated){true->true;false,null->false}, node.attributes.getNamedItem("priority")?.nodeValue?.toUInt() ?: typeDefinition?.priority, if (interval == null) typeDefinition!!.interval else valueOf(interval), node.attributes.getNamedItem("intervalDecimal")?.nodeValue?.toFloat() ?: typeDefinition?.intervalDecimal, node.attributes.getNamedItem("shiftDecimal")?.nodeValue?.toFloat() ?: typeDefinition?.shiftDecimal ?: (0).toFloat(), - node.attributes.getNamedItem("supportsFraction").nodeValue?.toBoolean() + node.attributes.getNamedItem("supportsFraction")?.nodeValue?.toBoolean() ?: typeDefinition?.supportsFraction ?: false, node.attributes.getNamedItem("resolution")?.nodeValue?.toULong() ?: typeDefinition?.resolution, node.attributes.getNamedItem("intervalCounter")?.nodeValue?.toULong() diff --git a/frameworks/builder/src/main/java/org/intocps/maestro/framework/fmi2/api/FmiBuilder.java b/frameworks/builder/src/main/java/org/intocps/maestro/framework/fmi2/api/FmiBuilder.java index 9735875d..c666f586 100644 --- a/frameworks/builder/src/main/java/org/intocps/maestro/framework/fmi2/api/FmiBuilder.java +++ b/frameworks/builder/src/main/java/org/intocps/maestro/framework/fmi2/api/FmiBuilder.java @@ -5,6 +5,7 @@ import org.intocps.maestro.ast.node.PType; import javax.xml.xpath.XPathExpressionException; +import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.List; import java.util.Map; @@ -256,6 +257,8 @@ interface Scope extends Scoping { ArrayVariable store(String name, CV[] value); + ArrayVariable createArray(String name,Class type, IntVariable...sizes ) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException; + /** * Store the given value and get a tag for it. Copy * @@ -443,7 +446,7 @@ interface Value { } - interface NamedValue extends Value { + interface NamedValue extends Value,ProvidesTypedReferenceExp { } @@ -453,6 +456,12 @@ interface IntVariable extends Variable, ProvidesTy void increment(); } + interface UIntVariable extends Variable, ProvidesTypedReferenceExp, NumericTypedReferenceExp{ + void decrement(); + + void increment(); + }; + interface ProvidesTypedReferenceExp { PType getType(); @@ -842,7 +851,7 @@ Map.Entry, DoubleVariable> step(DoubleVariable curre DoubleVariable communicationStepSize); } - interface Variable { + interface Variable extends ProvidesTypedReferenceExp { String getName(); void setValue(V value); @@ -877,6 +886,9 @@ interface DoubleExpressionValue extends NumericExpressionValue { interface IntExpressionValue extends NumericExpressionValue { } + interface UIntExpressionValue extends IntExpressionValue { + } + interface StringExpressionValue extends FmiBuilder.ExpressionValue { } 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 ebcd344f..b6f16cc9 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 @@ -6,6 +6,7 @@ import org.intocps.maestro.framework.fmi2.api.FmiBuilder; import org.intocps.maestro.framework.fmi2.api.mabl.variables.*; +import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.util.Collection; import java.util.Set; @@ -185,6 +186,12 @@ public ArrayVariableFmi2Api store(String name, V value[]) { return activeScope.store(name, value); } + @Override + public ArrayVariableFmi2Api createArray(String name, Class type, + FmiBuilder.IntVariable... sizes) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + return activeScope.createArray(name,type,sizes); + } + @Override public FmiBuilder.Variable store(FmiBuilder.Value tag) { return activeScope.store(tag); 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 29b0186a..c0dcec9d 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 @@ -1,11 +1,13 @@ package org.intocps.maestro.framework.fmi2.api.mabl.scoping; 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.fmi3.Fmi3ModelDescription; import org.intocps.maestro.framework.fmi2.api.FmiBuilder; import org.intocps.maestro.framework.fmi2.api.mabl.variables.*; +import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.util.Collection; import java.util.Set; @@ -84,6 +86,9 @@ public interface IMablScope extends FmiBuilder.Scope { @Override ArrayVariableFmi2Api store(String name, V value[]); + @Override + ArrayVariableFmi2Api createArray(String name,Class type, FmiBuilder.IntVariable... sizes ) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException; + @Override FmiBuilder.Variable store(FmiBuilder.Value tag); @@ -93,6 +98,7 @@ public interface IMablScope extends FmiBuilder.Scope { ArrayVariableFmi2Api storeInArray(String name, VariableFmi2Api[] variables); + FmuVariableFmi2Api createFMU(String name, Fmi2ModelDescription modelDescription, URI path) throws Exception; @Override 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 294fb168..28f56b3d 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 @@ -2,6 +2,7 @@ import org.intocps.maestro.ast.ABasicBlockStm; import org.intocps.maestro.ast.AParallelBlockStm; +import org.intocps.maestro.ast.AVariableDeclaration; import org.intocps.maestro.ast.MableAstFactory; import org.intocps.maestro.ast.node.*; import org.intocps.maestro.fmi.Fmi2ModelDescription; @@ -13,6 +14,7 @@ import org.intocps.maestro.framework.fmi2.api.mabl.values.*; import org.intocps.maestro.framework.fmi2.api.mabl.variables.*; +import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.util.*; import java.util.function.Supplier; @@ -228,6 +230,12 @@ public ArrayVariableFmi2Api store(String name, V[] value) { return store(() -> builder.getNameGenerator().getName(name), value); } + @Override + public ArrayVariableFmi2Api createArray(String name, Class type, + FmiBuilder.IntVariable... sizes) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + return newArray(() -> builder.getNameGenerator().getName(name), type, sizes); + } + public DoubleVariableFmi2Api store(Supplier nameProvider, double value) { String name = nameProvider.get(); @@ -265,6 +273,44 @@ public StringVariableFmi2Api store(Supplier nameProvider, String value) newAIdentifierExp(name)); } + private ArrayVariableFmi2Api newArray(Supplier nameProvider, Class type, + FmiBuilder.IntVariable... sizes) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + + PType type_ = null; + + if (FmiBuilder.IntVariable.class.isAssignableFrom(type)) { + type_ = new AIntNumericPrimitiveType(); + } else if (FmiBuilder.UIntVariable.class.isAssignableFrom(type)) { + type_ = new AUIntNumericPrimitiveType(); + } else if (FmiBuilder.BoolVariable.class.isAssignableFrom(type)) { + type_ = new ABooleanPrimitiveType(); + } else if (FmiBuilder.DoubleVariable.class.isAssignableFrom(type)) { + type_ = new ARealNumericPrimitiveType(); + } else if (FmiBuilder.StringVariable.class.isAssignableFrom(type)) { + type_ = new ABooleanPrimitiveType(); + } else { + throw new IllegalArgumentException("Type not supported: " + type.getName()); + } + + + String name = nameProvider.get(); + + List size_ = Arrays.stream(sizes).map(FmiBuilder.ProvidesTypedReferenceExp::getExp).map(PExp::clone).collect(Collectors.toList()); + + + AVariableDeclaration variableDeclaration = new AVariableDeclaration(); + variableDeclaration.setName(newAIdentifier(name)); + variableDeclaration.setType(type_); + variableDeclaration.setSize(size_); + + PStm arrayVariableStm = newALocalVariableStm(variableDeclaration); + add(arrayVariableStm); + + //the array is dynamic so we cannot do anything about the items + return new ArrayVariableFmi2Api<>(arrayVariableStm, type_.clone(), builder.getDynamicScope(), + builder.getDynamicScope(), newAIdentifierStateDesignator(name), newAIdentifierExp(name), Collections.emptyList()); + } + /** * @param identifyingName the name of the MaBL array * @param mdArray non-jagged multidimensional Java array. @@ -310,7 +356,7 @@ private ArrayVariableFmi2Api storeMDArray(String identifyingName, V[] mdA * @return an ArrayVariable representing the multidimensional array */ private ArrayVariableFmi2Api instantiateMDArrayRecursively(V[] array, PStm declaringStm, PStateDesignatorBase stateDesignator, - PExpBase indexExp) { + PExpBase indexExp) { if (array.getClass().getComponentType().isArray()) { List arrays = new ArrayList<>(); diff --git a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/ArrayVariableFmi2Api.java b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/ArrayVariableFmi2Api.java index 070c39f2..8ecba53c 100644 --- a/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/ArrayVariableFmi2Api.java +++ b/frameworks/fmi2api/src/main/java/org/intocps/maestro/framework/fmi2/api/mabl/variables/ArrayVariableFmi2Api.java @@ -31,6 +31,7 @@ public List> items() { @Override public void setValue(FmiBuilder.IntExpressionValue index, FmiBuilder.ExpressionValue value) { - AAssigmentStm stm = newAAssignmentStm(newAArayStateDesignator(this.getDesignator(), index.getExp()), value.getExp()); + AAssigmentStm stm = newAAssignmentStm(newAArayStateDesignator(this.getDesignator().clone(), index.getExp().clone()), value.getExp()); + this.dynamicScope.add(stm); } } 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 2127401e..df0df89b 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 @@ -44,7 +44,7 @@ public class InstanceVariableFmi3Api extends VariableFmi2Api>> tentativeBuffer = new HashMap<>(); + // private final Map>> tentativeBuffer = new HashMap<>(); // private final Map> tentativeBufferIndexMap = new HashMap<>(); private final String environmentName; @@ -59,7 +59,7 @@ public class InstanceVariableFmi3Api extends VariableFmi2Api>> derivativePortsToShare; private List variablesToLog; - Predicate obtainAsShared= p->p.isLinked() || (variablesToLog !=null && variablesToLog.contains(p.getName())); + Predicate obtainAsShared = p -> p.isLinked() || (variablesToLog != null && variablesToLog.contains(p.getName())); public InstanceVariableFmi3Api(PStm declaration, FmuVariableFmi3Api parent, String name, ModelDescriptionContext3 modelDescriptionContext, MablApiBuilder builder, IMablScope declaringScope, PStateDesignator designator, PExp referenceExp) { @@ -343,6 +343,36 @@ public void enterInitializationMode(FmiBuilder.Scope scope, FmiBuilder.Boo handleError(scope, method); } + public void enterEventMode() { + this.enterEventMode(this.dynamicScope); + } + + public void enterEventMode(FmiBuilder.Scope scope) { + //enterEventMode + fmiCall(scope, "enterEventMode"); + + } + + public void enterStepMode() { + this.enterStepMode(this.dynamicScope); + } + + public void enterStepMode(FmiBuilder.Scope scope) { + //enterEventMode + fmiCall(scope, "enterStepMode"); + } + + public void getEventIndicators(FmiBuilder.Scope scope, FmiBuilder.ArrayVariable> eventIndicators, + FmiBuilder.IntVariable nEventIndicators) { + + fmiCall(scope, "getEventIndicators", new ARefExp(eventIndicators.getExp().clone()), nEventIndicators.getExp().clone()); + + } + + public void getNumberOfEventIndicators(FmiBuilder.Scope scope, FmiBuilder.IntVariable nEventIndicators) { + fmiCall(scope, "getNumberOfEventIndicators", new ARefExp(nEventIndicators.getExp().clone())); + } + private void handleError(FmiBuilder.Scope scope, String method) { handleError(scope, method, MablApiBuilder.Fmi3Status.FMI_ERROR, MablApiBuilder.Fmi3Status.FMI_FATAL); } @@ -373,15 +403,48 @@ public void setupExperiment(FmiBuilder.Scope scope, double startTime, Doub @Override public void exitInitializationMode(FmiBuilder.Scope scope) { + fmiCall(scope,"exitInitializationMode"); + } - final String method = "exitInitializationMode"; + public void getClock(ArrayVariableFmi2Api vrs, FmiBuilder.IntVariable nvr, + ArrayVariableFmi2Api triggeredClocks) { + this.getClock(builder.getDynamicScope(), vrs, nvr, triggeredClocks); + } - AAssigmentStm stm = - newAAssignmentStm(((IMablScope) scope).getFmiStatusVariable().getDesignator().clone(), call(this.getReferenceExp().clone(), method)); - scope.add(stm); + public void getClock(FmiBuilder.Scope scope, ArrayVariableFmi2Api vrs, FmiBuilder.IntVariable nvr, + ArrayVariableFmi2Api triggeredClocks) { + fmiCall(scope,"getClock", vrs.getReferenceExp().clone(), nvr.getExp().clone(), + new ARefExp(triggeredClocks.getExp().clone())); + } + + public void setClock(ArrayVariableFmi2Api vrs, FmiBuilder.IntVariable nvr, + ArrayVariableFmi2Api triggeredClocks) { + this.setClock(builder.getDynamicScope(), vrs, nvr, triggeredClocks); + } + + + public void setClock(FmiBuilder.Scope scope, ArrayVariableFmi2Api vrs, FmiBuilder.IntVariable nvr, + ArrayVariableFmi2Api triggeredClocks) { + + fmiCall(scope,"setClock", vrs.getReferenceExp().clone(), nvr.getExp().clone(), + triggeredClocks.getExp().clone()); + + } + + public void updateDiscreteStates(FmiBuilder.Scope scope, BooleanVariableFmi2Api discreteStatesNeedUpdate, + BooleanVariableFmi2Api terminateSimulation, + BooleanVariableFmi2Api nominalsOfContinuousStatesChanged, BooleanVariableFmi2Api valuesOfContinuousStatesChanged, + BooleanVariableFmi2Api nextEventTimeDefined, DoubleVariableFmi2Api nextEventTime) { + + fmiCall(scope,"updateDiscreteStates", + new ARefExp(discreteStatesNeedUpdate.getReferenceExp().clone()), + new ARefExp(terminateSimulation.getReferenceExp().clone()), + new ARefExp(nominalsOfContinuousStatesChanged.getReferenceExp().clone()), + new ARefExp(valuesOfContinuousStatesChanged.getReferenceExp().clone()), + new ARefExp(nextEventTimeDefined.getReferenceExp().clone()), + new ARefExp(nextEventTime.getReferenceExp().clone())); - handleError(scope, method); } // @Override @@ -449,10 +512,10 @@ public Map.Entry, StepResult> step(FmiBuilder.Scop PExp noSetFMUStatePriorToCurrentPoint) { if (stepResult == null) { - stepResult = new StepResult(createReusableBooleanVariable(false, this.getDeclaredScope(), "eventHandlingNeeded"), - createReusableBooleanVariable(false, this.getDeclaredScope(), "terminateSimulation"), - createReusableBooleanVariable(false, this.getDeclaredScope(), "earlyReturn"), - createReusableDoubleVariable(0d, this.getDeclaredScope(), "lastSuccessfulTime")); + stepResult = new StepResult(createReusableBooleanVariable(false, this.getDeclaredScope(), this.name + "EventHandlingNeeded"), + createReusableBooleanVariable(false, this.getDeclaredScope(), this.name + "TerminateSimulation"), + createReusableBooleanVariable(false, this.getDeclaredScope(), this.name + "EarlyReturn"), + createReusableDoubleVariable(0d, this.getDeclaredScope(), this.name + "LastSuccessfulTime")); } @@ -1155,14 +1218,24 @@ public void terminate() { @Override public void terminate(FmiBuilder.Scope scope) { - final String method = "terminate"; + fmiCall(scope, "terminate"); + } + public void reset() { + this.reset(builder.getDynamicScope()); + } + + public void reset(FmiBuilder.Scope scope) { + fmiCall(scope, "reset"); + } + + private void fmiCall(FmiBuilder.Scope scope, String methodName, PExp... args) { AAssigmentStm stm = - newAAssignmentStm(((IMablScope) scope).getFmiStatusVariable().getDesignator().clone(), call(this.getReferenceExp().clone(), method)); + newAAssignmentStm(((IMablScope) scope).getFmiStatusVariable().getDesignator().clone(), call(this.getReferenceExp().clone(), methodName, args)); scope.add(stm); - handleError(scope, method); + handleError(scope, methodName); } // TODO: these are work in progress @@ -1191,20 +1264,18 @@ public void share( PType type = ((PortFmi3Api) map.getValue().get(0).getKey()).getType(); - Map, FmiBuilder.Variable> 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 -> { + .forEach(port -> { //this is the sorted set of assignments, these can be replaced by a memcopy later Fmi3TypeEnum fmiType = port.getSourceObject().getVariable().getTypeIdentifier(); - - ArrayVariableFmi2Api buffer =buffers.getBuffer(Buffers.BufferTypes.Share,type, fmiType); + ArrayVariableFmi2Api buffer = buffers.getBuffer(Buffers.BufferTypes.Share, type, fmiType); if (port.getSharedAsVariable() == null) { - ArrayVariableFmi2Api newBuf = this.buffers.growBuffer(Buffers.BufferTypes.Share, buffer, 1,fmiType); + ArrayVariableFmi2Api newBuf = this.buffers.growBuffer(Buffers.BufferTypes.Share, buffer, 1, fmiType); VariableFmi2Api newShared = newBuf.items().get(newBuf.items().size() - 1); port.setSharedAsVariable(newShared); diff --git a/maestro/src/main/java/org/intocps/maestro/Mabl.java b/maestro/src/main/java/org/intocps/maestro/Mabl.java index 920d51f3..bb0b8502 100644 --- a/maestro/src/main/java/org/intocps/maestro/Mabl.java +++ b/maestro/src/main/java/org/intocps/maestro/Mabl.java @@ -112,8 +112,12 @@ public static ARootDocument getRuntimeModule(String module) throws IOException { if (resourceAsStream == null) { return null; } - ARootDocument parse = MablParserUtil.parse(CharStreams.fromStream(resourceAsStream)); + try { + ARootDocument parse = MablParserUtil.parse(CharStreams.fromStream(resourceAsStream)); return parse; + }catch(IllegalStateException e){ + throw new IllegalStateException(e.getMessage()+" in module "+module,e); + } } public static List getModuleDocuments(List modules) throws IOException { diff --git a/maestro/src/test/java/org/intocps/maestro/BuilderFmi3Test.java b/maestro/src/test/java/org/intocps/maestro/BuilderFmi3Test.java index 95561bc3..c2ec422d 100644 --- a/maestro/src/test/java/org/intocps/maestro/BuilderFmi3Test.java +++ b/maestro/src/test/java/org/intocps/maestro/BuilderFmi3Test.java @@ -125,13 +125,7 @@ public void wt() throws Exception { controller.exitInitializationMode(); tank.exitInitializationMode(); - /* - IMablScope scope1 = dynamicScope.getActiveScope(); - for (int i = 0; i < 4; i++) { - dynamicScope.enterIf(null); - AMablFmi2ComponentAPI tank2 = tankFMU.create("tank"); - } - scope1.activate();*/ + ComponentVariableFmi2Api tank2 = tankFMU.instantiate("tank"); diff --git a/maestro/src/test/java/org/intocps/maestro/fmi3/BuilderFmi3Test.java b/maestro/src/test/java/org/intocps/maestro/fmi3/BuilderFmi3Test.java index 58b7435d..5cbe0154 100644 --- a/maestro/src/test/java/org/intocps/maestro/fmi3/BuilderFmi3Test.java +++ b/maestro/src/test/java/org/intocps/maestro/fmi3/BuilderFmi3Test.java @@ -1,23 +1,44 @@ package org.intocps.maestro.fmi3; +import org.antlr.v4.runtime.CharStreams; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; import org.intocps.fmi.FmuInvocationException; import org.intocps.fmi.jnifmuapi.fmi3.Fmu3; +import org.intocps.maestro.Mabl; import org.intocps.maestro.ast.display.PrettyPrinter; -import org.intocps.maestro.ast.node.ASimulationSpecificationCompilationUnit; +import org.intocps.maestro.ast.node.*; +import org.intocps.maestro.core.Framework; +import org.intocps.maestro.core.messages.ErrorReporter; +import org.intocps.maestro.core.messages.IErrorReporter; import org.intocps.maestro.fmi.fmi3.Fmi3Causality; import org.intocps.maestro.fmi.fmi3.Fmi3ModelDescription; +import org.intocps.maestro.fmi.fmi3.Fmi3TypeEnum; +import org.intocps.maestro.framework.fmi2.api.FmiBuilder; import org.intocps.maestro.framework.fmi2.api.mabl.MablApiBuilder; import org.intocps.maestro.framework.fmi2.api.mabl.PortFmi3Api; -import org.intocps.maestro.framework.fmi2.api.mabl.variables.ArrayVariableFmi2Api; -import org.intocps.maestro.framework.fmi2.api.mabl.variables.FmuVariableFmi3Api; -import org.intocps.maestro.framework.fmi2.api.mabl.variables.InstanceVariableFmi3Api; +import org.intocps.maestro.framework.fmi2.api.mabl.scoping.DynamicActiveBuilderScope; +import org.intocps.maestro.framework.fmi2.api.mabl.scoping.IfMaBlScope; +import org.intocps.maestro.framework.fmi2.api.mabl.values.BooleanExpressionValue; +import org.intocps.maestro.framework.fmi2.api.mabl.values.IntExpressionValue; +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.parser.MablParserUtil; +import org.intocps.maestro.typechecker.TypeChecker; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.File; import java.io.IOException; +import java.io.PrintWriter; import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; public class BuilderFmi3Test { @@ -27,11 +48,11 @@ public static void before() throws IOException { } - public static InstanceVariableFmi3Api createInstance(MablApiBuilder builder,String name, URI uri) throws Exception { + public static InstanceVariableFmi3Api createInstance(MablApiBuilder builder, String name, URI uri) throws Exception { Fmi3ModelDescription md = new Fmi3ModelDescription(new Fmu3(new File(uri)).getModelDescription()); - FmuVariableFmi3Api fmu = builder.getDynamicScope().createFMU(name+"Fmu", md, uri); + FmuVariableFmi3Api fmu = builder.getDynamicScope().createFMU(name + "Fmu", md, uri); boolean visible = true; boolean loggingOn = true; @@ -48,8 +69,10 @@ public static InstanceVariableFmi3Api createInstance(MablApiBuilder builder,Stri public void test() throws Exception { MablApiBuilder builder = new MablApiBuilder(); - InstanceVariableFmi3Api fd = createInstance(builder,"fd",new File("target/Fmi3ModuleReferenceFmusTest/cache/Feedthrough.fmu").getAbsoluteFile().toURI()); - InstanceVariableFmi3Api sg = createInstance(builder,"sg",new File("src/test/resources/fmi3/reference/siggen-feedthrough/SignalGenerator.fmu").getAbsoluteFile().toURI()); + InstanceVariableFmi3Api fd = createInstance(builder, "fd", + new File("target/Fmi3ModuleReferenceFmusTest/cache/Feedthrough.fmu").getAbsoluteFile().toURI()); + InstanceVariableFmi3Api sg = createInstance(builder, "sg", + new File("src/test/resources/fmi3/reference/siggen-feedthrough/SignalGenerator.fmu").getAbsoluteFile().toURI()); // fd.enterInitializationMode(false, 0.0, 0.0, true, 10.0); @@ -84,4 +107,243 @@ public void test() throws Exception { System.out.println(PrettyPrinter.printLineNumbers(program)); } + @Test + public void testClocks() throws Exception { + MablApiBuilder builder = new MablApiBuilder(); + DynamicActiveBuilderScope scope = builder.getDynamicScope(); + + InstanceVariableFmi3Api instance = createInstance(builder, "clocks", + new File("target/Fmi3ModuleReferenceFmusTest/cache/Clocks.fmu").getAbsoluteFile().toURI()); + + +// fd.enterInitializationMode(false, 0.0, 0.0, true, 10.0); +// sg.enterInitializationMode(false, 0.0, 0.0, true, 10.0); + + List sgOutputs = instance.getPorts().stream().filter(p -> p.scalarVariable.getVariable().getCausality() == Fmi3Causality.Output) + .collect(Collectors.toList()); + + List clocks = instance.getPorts().stream().filter(p -> p.getSourceObject().getVariable().getTypeIdentifier() == Fmi3TypeEnum.ClockType) + .collect(Collectors.toList()); + + sgOutputs.stream().map(PortFmi3Api::getName).forEach(System.out::println); + + instance.enterEventMode(); + + FmiBuilder.IntVariable nEventIndicators = builder.getDynamicScope().store(0); + instance.getNumberOfEventIndicators(builder.getDynamicScope(), nEventIndicators); + + + ArrayVariableFmi2Api eventIndicators = builder.getDynamicScope() + .createArray("eventIndicators", UIntVariableFmi2Api.class, nEventIndicators); + +// FmiBuilder.ArrayVariable eventIndicators=builder.getDynamicScope().store(builder.n).storeInArray(); + instance.getEventIndicators(scope, eventIndicators, nEventIndicators); + + + List outClocks = clocks.stream().filter(p -> p.scalarVariable.getVariable().getCausality() == Fmi3Causality.Output) + .collect(Collectors.toList()); + FmiBuilder.IntVariable nvr = scope.store("clock_get_nvr", outClocks.size()); + ArrayVariableFmi2Api vrs = scope.createArray("clock_get_vrs", UIntVariableFmi2Api.class, nvr); + for (int i = 0; i < outClocks.size(); i++) { + vrs.setValue(new IntExpressionValue(i), new IntExpressionValue((int) outClocks.get(i).scalarVariable.getVariable().getValueReferenceAsLong())); + } + ArrayVariableFmi2Api triggeredClocks = scope.createArray("clock_get_vrs", BooleanVariableFmi2Api.class, nvr); + instance.getClock(vrs, nvr, triggeredClocks); + + + List inClocks = clocks.stream().filter(p -> p.scalarVariable.getVariable().getCausality() == Fmi3Causality.Input) + .collect(Collectors.toList()); + FmiBuilder.IntVariable clock_set_nvr = scope.store("clock_in_nvr", inClocks.size()); + ArrayVariableFmi2Api clock_set_vrs = scope.createArray("clock_in_vrs", UIntVariableFmi2Api.class, nvr); + ArrayVariableFmi2Api clock_set_Clocks = scope.createArray("clock_in_vrs", BooleanVariableFmi2Api.class, nvr); + for (int i = 0; i < inClocks.size(); i++) { + clock_set_vrs.setValue(new IntExpressionValue(i), + new IntExpressionValue((int) inClocks.get(i).scalarVariable.getVariable().getValueReferenceAsLong())); + clock_set_Clocks.setValue(new IntExpressionValue(i), new BooleanExpressionValue(true)); + } + + instance.setClock(clock_set_vrs, clock_set_nvr, clock_set_Clocks); + + + FmiBuilder.DoubleVariable currentCommunicationPoint = scope.store("time", 0d); + FmiBuilder.DoubleVariable stepSize = scope.store("step", 0.1d); + Map.Entry, InstanceVariableFmi3Api.StepResult> stepRes = instance.step(scope, currentCommunicationPoint, + stepSize, new ABoolLiteralExp(false)); + +// stepRes.getValue().getLastSuccessfulTime() + +// instance.g +// for (PortFmi3Api o : sgOutputs) { +// sg.get(o); +// } + +// System.out.println("Linked ports"); +// sg.getPorts().stream().filter(PortFmi3Api::isLinked).forEach(System.out::println); +// System.out.println("---Linked ports"); +// sg.getPort("Int8_output").linkTo(fd.getPort("Int8_input")); +// sg.getPort("UInt8_output").linkTo(fd.getPort("UInt8_input")); +// System.out.println("Linked ports"); +// sg.getPorts().stream().filter(PortFmi3Api::isLinked).forEach(System.out::println); +// System.out.println("---Linked ports"); +// sg.getAndShare(); +// fd.setLinked(); + +// fd.exitInitializationMode(); + + ASimulationSpecificationCompilationUnit program = builder.build(); + +// String test = PrettyPrinter.print(program); + + System.out.println(PrettyPrinter.printLineNumbers(program)); + } + + @Test + public void testSimulateClocks() throws Exception { + MablApiBuilder builder = new MablApiBuilder(); + DynamicActiveBuilderScope scope = builder.getDynamicScope(); + + InstanceVariableFmi3Api instance = createInstance(builder, "clocks", + new File("target/Fmi3ModuleReferenceFmusTest/cache/Clocks.fmu").getAbsoluteFile().toURI()); + + +// fd.enterInitializationMode(false, 0.0, 0.0, true, 10.0); +// sg.enterInitializationMode(false, 0.0, 0.0, true, 10.0); + + List sgOutputs = instance.getPorts().stream().filter(p -> p.scalarVariable.getVariable().getCausality() == Fmi3Causality.Output) + .collect(Collectors.toList()); + + List clocks = instance.getPorts().stream().filter(p -> p.getSourceObject().getVariable().getTypeIdentifier() == Fmi3TypeEnum.ClockType) + .collect(Collectors.toList()); + + sgOutputs.stream().map(PortFmi3Api::getName).forEach(System.out::println); + + instance.enterEventMode(); + + FmiBuilder.IntVariable nEventIndicators = builder.getDynamicScope().store(0); + instance.getNumberOfEventIndicators(builder.getDynamicScope(), nEventIndicators); + + + ArrayVariableFmi2Api eventIndicators = builder.getDynamicScope() + .createArray("eventIndicators", UIntVariableFmi2Api.class, nEventIndicators); + +// FmiBuilder.ArrayVariable eventIndicators=builder.getDynamicScope().store(builder.n).storeInArray(); + instance.getEventIndicators(scope, eventIndicators, nEventIndicators); + + + List outClocks = clocks.stream().filter(p -> p.scalarVariable.getVariable().getCausality() == Fmi3Causality.Output) + .collect(Collectors.toList()); + FmiBuilder.IntVariable nvr = scope.store("clock_get_nvr", outClocks.size()); + ArrayVariableFmi2Api vrs = scope.createArray("clock_get_vrs", UIntVariableFmi2Api.class, nvr); + for (int i = 0; i < outClocks.size(); i++) { + vrs.setValue(new IntExpressionValue(i), new IntExpressionValue((int) outClocks.get(i).scalarVariable.getVariable().getValueReferenceAsLong())); + } + ArrayVariableFmi2Api triggeredClocks = scope.createArray("clock_get_vrs", BooleanVariableFmi2Api.class, nvr); + instance.getClock(vrs, nvr, triggeredClocks); + + + List inClocks = clocks.stream().filter(p -> p.scalarVariable.getVariable().getCausality() == Fmi3Causality.Input) + .collect(Collectors.toList()); + FmiBuilder.IntVariable clock_set_nvr = scope.store("clock_in_nvr", inClocks.size()); + ArrayVariableFmi2Api clock_set_vrs = scope.createArray("clock_in_vrs", UIntVariableFmi2Api.class, nvr); + ArrayVariableFmi2Api clock_set_Clocks = scope.createArray("clock_in_vrs", BooleanVariableFmi2Api.class, nvr); + for (int i = 0; i < inClocks.size(); i++) { + clock_set_vrs.setValue(new IntExpressionValue(i), + new IntExpressionValue((int) inClocks.get(i).scalarVariable.getVariable().getValueReferenceAsLong())); + clock_set_Clocks.setValue(new IntExpressionValue(i), new BooleanExpressionValue(true)); + } + + instance.setClock(clock_set_vrs, clock_set_nvr, clock_set_Clocks); + + + FmiBuilder.DoubleVariable currentCommunicationPoint = scope.store("time", 0d); + FmiBuilder.DoubleVariable stepSize = scope.store("step", 0.1d); + Map.Entry, InstanceVariableFmi3Api.StepResult> stepRes = instance.step(scope, currentCommunicationPoint, + stepSize, new ABoolLiteralExp(false)); + + IfMaBlScope eventHandlingScope = scope.enterIf( + stepRes.getValue().getEventHandlingNeeded().toPredicate()); + + instance.enterEventMode(); + + +//handle events + BooleanVariableFmi2Api discreteStatesNeedUpdate = scope.store("discreteStatesNeedUpdate",false); + BooleanVariableFmi2Api terminateSimulation = scope.store("terminateSimulation",false); + BooleanVariableFmi2Api nominalsOfContinuousStatesChanged = scope.store("nominalsOfContinuousStatesChanged",false); + BooleanVariableFmi2Api valuesOfContinuousStatesChanged = scope.store("valuesOfContinuousStatesChanged",false); + BooleanVariableFmi2Api nextEventTimeDefined = scope.store("nextEventTimeDefined",false); + DoubleVariableFmi2Api nextEventTime = scope.store("nextEventTime",0d); + instance.updateDiscreteStates(scope, discreteStatesNeedUpdate, terminateSimulation, nominalsOfContinuousStatesChanged, valuesOfContinuousStatesChanged, + nextEventTimeDefined, nextEventTime); + + instance.enterStepMode(); + + +// stepRes.getValue().getLastSuccessfulTime() + +// instance.g +// for (PortFmi3Api o : sgOutputs) { +// sg.get(o); +// } + +// System.out.println("Linked ports"); +// sg.getPorts().stream().filter(PortFmi3Api::isLinked).forEach(System.out::println); +// System.out.println("---Linked ports"); +// sg.getPort("Int8_output").linkTo(fd.getPort("Int8_input")); +// sg.getPort("UInt8_output").linkTo(fd.getPort("UInt8_input")); +// System.out.println("Linked ports"); +// sg.getPorts().stream().filter(PortFmi3Api::isLinked).forEach(System.out::println); +// System.out.println("---Linked ports"); +// sg.getAndShare(); +// fd.setLinked(); + +// fd.exitInitializationMode(); + + ASimulationSpecificationCompilationUnit program = builder.build(); + +// String test = PrettyPrinter.print(program); + + System.out.println(PrettyPrinter.printLineNumbers(program)); + + File workingDirectory=getWorkingDirectory(null,this.getClass()); + File specFile = new File(workingDirectory, "spec.mabl"); + FileUtils.write(specFile,PrettyPrinter.print(program),StandardCharsets.UTF_8); + + IErrorReporter reporter = new ErrorReporter(); + Mabl mabl = new Mabl(workingDirectory, workingDirectory); + mabl.setReporter(reporter); +// mabl.setVerbose(getMablVerbose()); +mabl.parse(Collections.singletonList(specFile)); + mabl.expand(); + var tcRes = mabl.typeCheck(); + mabl.verify(Framework.FMI2); + + + if (mabl.getReporter().getErrorCount() > 0) { + mabl.getReporter().printErrors(new PrintWriter(System.err, true)); + Assertions.fail(); + } + if (mabl.getReporter().getWarningCount() > 0) { + mabl.getReporter().printWarnings(new PrintWriter(System.out, true)); + } + + mabl.dump(workingDirectory); + Map types = tcRes.getValue(); + + new MableInterpreter(new DefaultExternalValueFactory(workingDirectory, name -> TypeChecker.findModule(types, name), + IOUtils.toInputStream(mabl.getRuntimeDataAsJsonString(), StandardCharsets.UTF_8))).execute(MablParserUtil.parse(CharStreams.fromString(PrettyPrinter.print(program)))); + } + static File getWorkingDirectory(File base, Class cls) throws IOException { + String s = Paths.get("target", cls.getSimpleName()).toString() + File.separatorChar + (base==null?"":base.getAbsolutePath().substring( + base.getAbsolutePath().replace(File.separatorChar, '/').indexOf("src/test/resources/") + ("src" + "/test" + "/resources/").length())); + + File workingDir = new File(s.replace('/', File.separatorChar)); + if (workingDir.exists()) { + FileUtils.deleteDirectory(workingDir); + } + if (!workingDir.exists()) { + workingDir.mkdirs(); + } + return workingDir; + } } 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 bab809ea..339599ae 100644 --- a/typechecker/src/main/resources/org/intocps/maestro/typechecker/FMI3.mabl +++ b/typechecker/src/main/resources/org/intocps/maestro/typechecker/FMI3.mabl @@ -172,7 +172,7 @@ module FMI3Instance /* Clock related functions */ /* tag::getClock[] */ - int getClock(uint valueReferences[], int nValueReferences, bool values[]); + int getClock(uint valueReferences[], int nValueReferences, out bool values[]); /* end::getClock[] */ /* tag::setClock[] */ @@ -219,9 +219,9 @@ module FMI3Instance /* end::EvaluateDiscreteStates[] */ /* tag::UpdateDiscreteStates[] */ - int updateDiscreteStates(out bool[] discreteStatesNeedUpdate, out bool[] terminateSimulation, - out bool[] nominalsOfContinuousStatesChanged, out bool[] valuesOfContinuousStatesChanged, out bool[] nextEventTimeDefined, - out real[] nextEventTime); + int updateDiscreteStates(out bool discreteStatesNeedUpdate, out bool terminateSimulation, + out bool nominalsOfContinuousStatesChanged, out bool valuesOfContinuousStatesChanged, out bool nextEventTimeDefined, + out real nextEventTime); /* end::UpdateDiscreteStates[] */ /*************************************************** @@ -252,7 +252,7 @@ module FMI3Instance /* end::getDerivatives[] */ /* tag::getEventIndicators[] */ - int getEventIndicators(real eventIndicators[], int nEventIndicators); + int getEventIndicators(out uint[] eventIndicators, int nEventIndicators); /* end::getEventIndicators[] */ /* tag::getContinuousStates[] */ @@ -264,7 +264,7 @@ module FMI3Instance /* end::getNominalsOfContinuousStates[] */ /* tag::getNumberOfEventIndicators[] */ - int getNumberOfEventIndicators(int[] nEventIndicators); + int getNumberOfEventIndicators(out int nEventIndicators); /* end::getNumberOfEventIndicators[] */ /* tag::getNumberOfContinuousStates[] */