/* * generated by Xtext 2.10.0 */ package be.uantwerpen.ansymo.semanticadaptation.cg.canonical import be.uantwerpen.ansymo.semanticadaptation.cg.canonical.graph.DirectedGraph import be.uantwerpen.ansymo.semanticadaptation.cg.canonical.graph.FMUGraph import be.uantwerpen.ansymo.semanticadaptation.cg.canonical.graph.TopologicalSort import be.uantwerpen.ansymo.semanticadaptation.log.Log import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Adaptation import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Assignment import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.AtomicUnity import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.BoolLiteral import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.BuiltinFunction import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Close import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.CompositeOutputFunction import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Connection import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.CustomControlRule import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.DataRule import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Declaration import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.DeclaredParameter import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.DivideUnity import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.DoStep import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.DoStepFun import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Expression import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.FMU import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.InnerFMU import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.InnerFMUDeclaration import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.InnerFMUDeclarationFull import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.IntLiteral import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.IsSet import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.MooreOrMealy import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.MultiplyUnity import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Port import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.ReactiveOrDelayed import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.RealLiteral import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SemanticAdaptationFactory import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SingleParamDeclaration import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SingleVarDeclaration import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Statement import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.StringLiteral import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Unity import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Variable import java.io.ByteArrayOutputStream import java.util.HashMap import java.util.LinkedList import java.util.List import java.util.Map import org.eclipse.emf.common.util.EList import org.eclipse.emf.common.util.URI import org.eclipse.emf.ecore.EObject import org.eclipse.xtext.EcoreUtil2 import org.eclipse.xtext.generator.IFileSystemAccess2 /** * Generates code from your model files on save. * * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation */ class SemanticAdaptationCanonicalGenerator { String CANONICAL_SUFIX = "_canonical" def Adaptation doGenerate(Adaptation adaptation, IFileSystemAccess2 fsa, URI mainFile) { Log.push("Generating canonical semantic adaptation for file...") Log.println(prettyprint_model(adaptation, "File Read")) // Create file name for the canonical sa file var fileNameWithoutExt = mainFile.trimFileExtension().lastSegment() Log.println("Checking if file is already a canonical version...") if (fileNameWithoutExt.indexOf(CANONICAL_SUFIX) == -1){ Log.println("It is not.") var canonicalFileName = fileNameWithoutExt + CANONICAL_SUFIX + ".sa" Log.println("canonicalFileName = " + canonicalFileName) canonicalize(adaptation) Log.println(prettyprint_model(adaptation, "Generated File")) fsa.generateFile(canonicalFileName, adaptation.serialize_model) Log.println("File " + canonicalFileName + " written.") } else { Log.println("It is already a canonical version.") Log.println("Nothing to do.") } Log.pop("Generating canonical semantic adaptation for file... DONE") return adaptation } def prettyprint_model(Adaptation sa, String title){ var outputByteArray = new ByteArrayOutputStream() sa.eResource.save(outputByteArray,null) return "______________________________" + title + "______________________________\n" + sa.serialize_model + "\n__________________________________________________________________________" } def serialize_model(Adaptation sa){ var outputByteArray = new ByteArrayOutputStream() sa.eResource.save(outputByteArray,null) return outputByteArray.toString() } def inferUnits(Adaptation sa){ // Unit inference var unitlessElements = genericDeclarationInferenceAlgorithm(sa , [// getField element | { var DUMMY_UNIT = "Dips" if (element instanceof SingleParamDeclaration) { return DUMMY_UNIT } else if (element instanceof Port){ return element.unity } else if (element instanceof SingleVarDeclaration){ return DUMMY_UNIT } else { throw new Exception("Unexpected element type: " + element) } } ], [// setField element, value | { if (element instanceof SingleParamDeclaration) { } else if (element instanceof Port){ element.unity = EcoreUtil2.copy(value as Unity) } else if (element instanceof SingleVarDeclaration){ } else { throw new Exception("Unexpected element type: " + element) } } ], [// inferField element | { var DUMMY_UNIT = "Dips" if (element instanceof SingleParamDeclaration) { return DUMMY_UNIT } else if (element instanceof Port){ return getPortUnit(element) } else if (element instanceof SingleVarDeclaration){ return DUMMY_UNIT } else { throw new Exception("Unexpected element type: " + element) } } ] ) if (unitlessElements > 0){ Log.println("Could not infer all element units. There are " + unitlessElements + " unitless elements.") } } def inferTypes(Adaptation sa){ // Type inference var untypedElements = genericDeclarationInferenceAlgorithm(sa , [// getField element | { if (element instanceof SingleParamDeclaration) { return element.type } else if (element instanceof Port){ return element.type } else if (element instanceof SingleVarDeclaration){ return element.type } else { throw new Exception("Unexpected element type: " + element) } } ], [// setField element, value | { if (element instanceof SingleParamDeclaration) { element.type = value as String } else if (element instanceof Port){ element.type = value as String } else if (element instanceof SingleVarDeclaration){ element.type = value as String } else { throw new Exception("Unexpected element type: " + element) } } ], [// inferField element | { if (element instanceof SingleParamDeclaration) { return extractTypeFromExpression(element.expr, element.name) } else if (element instanceof Port){ return getPortType(element) } else if (element instanceof SingleVarDeclaration){ return extractTypeFromExpression(element.expr, element.name) } else { throw new Exception("Unexpected element type: " + element) } } ] ) if (untypedElements > 0){ Log.println("Error: Could not infer all types. There are " + untypedElements + " untyped elements.") Log.println(prettyprint_model(sa, "Current File")) throw new Exception("Could not infer all types. There are " + untypedElements + " untyped elements.") } } def canonicalize(Adaptation sa){ Log.push("Canonicalize") inferUnits(sa) inferTypes(sa) addInPorts(sa) val inputPort2parameterDeclaration = addInParams(sa) val externalInputPort2InVarDeclaration = addInVars(sa, inputPort2parameterDeclaration) addInRules_External2Stored_Assignments(sa, externalInputPort2InVarDeclaration) val internalPort2ExternalPortBindings = findAllExternalPort2InputPort_Bindings(sa) addInRules_External2Internal_Assignments(sa, internalPort2ExternalPortBindings) removeBindings(internalPort2ExternalPortBindings, sa) if (sa.outports.size==0){ addOutPorts(sa) } val outputPort2parameterDeclaration = addOutParams(sa) val internalOutputPort2OutVarDeclaration = addOutVars(sa, outputPort2parameterDeclaration) val internalOutputPort2ExternalPortBindings = findAllInternalPort2ExternalOutputPort_Bindings(sa) //val internalOutputPort2OutVarDeclaration = transitiveStep(internalOutputPort2ExternalPortBindings, internalOutputPort2OutVarDeclaration) addOutRules_Internal2Stored_Assignments(sa, internalOutputPort2OutVarDeclaration) addOutRules_Internal2External_Assignments(sa, internalOutputPort2ExternalPortBindings) removeBindings(internalOutputPort2ExternalPortBindings, sa) if (sa.control === null){ sa.control = SemanticAdaptationFactory.eINSTANCE.createControlRuleBlock() sa.control.rule = SemanticAdaptationFactory.eINSTANCE.createCustomControlRule() createCoSimStepInstructions(sa) } createInternalBindingAssignments(sa) Log.push("Replace port refs in input rules") for (rule : sa.in.rules){ check(rule.outputfunction instanceof CompositeOutputFunction, "Only CompositeOutputFunction are supported in DataRules.") replacePortRefsByVarDecl((rule.outputfunction as CompositeOutputFunction).statements, externalInputPort2InVarDeclaration) } Log.pop("Replace port refs in input rules") Log.push("Replace port refs in control rule") if (sa.control.rule instanceof CustomControlRule){ replacePortRefsByVarDecl((sa.control.rule as CustomControlRule).controlRulestatements,internalOutputPort2OutVarDeclaration) } Log.pop("Replace port refs in control rule") Log.push("Replace port refs in output rule") for (rule : sa.out.rules){ check(rule.outputfunction instanceof CompositeOutputFunction, "Only CompositeOutputFunction are supported in DataRules.") replacePortRefsByVarDecl((rule.outputfunction as CompositeOutputFunction).statements, internalOutputPort2OutVarDeclaration) } Log.pop("Replace port refs in output rule") Log.pop("Canonicalize") } def replacePortRefsByVarDecl(EList statements, HashMap port2VarDecl) { Log.push("replacePortRefsByVarDecl") for(statement : statements){ val vars = statement.eAllContents.filter[v | v instanceof Variable] var Variable v while (vars.hasNext) { v = vars.next as Variable if (port2VarDecl.containsKey(v.ref)){ val port = v.ref as Port v.owner = null val varDecl = port2VarDecl.get(v.ref) v.ref = varDecl Log.println("Replaced ref to " + port.qualifiedName + " by " + varDecl.name) } else { Log.println("Var ref not substituted: " + v.ref) } } } Log.pop("replacePortRefsByVarDecl") } def createInternalBindingAssignments(Adaptation sa) { Log.push("createInternalBindingAssignments") val scenario = (sa.inner as InnerFMUDeclarationFull) for (connection : scenario.connection){ val trgFMU = connection.tgt.port.eContainer as InnerFMU val ctrlRule = sa.control.rule as CustomControlRule val doStepIndex = findDoStepStatementIndex(ctrlRule, trgFMU) if (! existsAssignmentToPort_BeforeIndex(connection.tgt.port, doStepIndex, ctrlRule)){ Log.println("Creating assignment to port " + connection.tgt.port.qualifiedName + " at position " + doStepIndex) addPortAssignment(ctrlRule.controlRulestatements, connection.tgt.port, connection.src.port, doStepIndex, true) } else { Log.println("There is already an assignment to port " + connection.tgt.port.qualifiedName + " before position " + doStepIndex) } } Log.pop("createInternalBindingAssignments") } def existsAssignmentToPort_BeforeIndex(Port port, int index, CustomControlRule rule) { val assignmentsToPort = rule.controlRulestatements.indexed .filter[s | s.value instanceof Assignment && (s.value as Assignment).lvalue.ref == port ] check(assignmentsToPort.size <= 1, "Multiple assignments to the same port are not supported yet. Use a loop with a single call.") return assignmentsToPort.size == 1 } def findDoStepStatementIndex(CustomControlRule rule, InnerFMU fmu) { Log.push("findDoStepStatementIndex") var result = -1 val doStepProcedures = rule.controlRulestatements.indexed.filter[s | s.value instanceof DoStep && (s.value as DoStep).fmu == fmu] check(doStepProcedures.size <= 1, "Multiple calls to the doStep function for the same FMU are not supported yet. Use a loop with a single call.") if (doStepProcedures.size == 1){ Log.println("Found a doStep procedure for fmu " + fmu.name + " at position " + doStepProcedures.head.key) result = doStepProcedures.head.key } // Warning: this does not support instructions such as: // var someVar = 10, h = doStep(f), etc... // Only single declarations are supported, such as: // var h = doStep(f) val doStepAssignments = rule.controlRulestatements.indexed .filter[s | s.value instanceof Declaration && (s.value as Declaration).declarations.size == 1 && (s.value as Declaration).declarations.head instanceof SingleVarDeclaration && ((s.value as Declaration).declarations.head as SingleVarDeclaration).expr instanceof DoStepFun && (((s.value as Declaration).declarations.head as SingleVarDeclaration).expr as DoStepFun).fmu == fmu ] check(doStepAssignments.size <= 1, "Multiple calls to the doStep function for the same FMU are not supported yet. Use a loop with a single call.") if (doStepAssignments.size == 1){ check(result==-1, "Multiple calls to the doStep function for the same FMU are not supported yet. Use a loop with a single call.") Log.println("Found a doStep function for fmu " + fmu.name + " at position " + doStepAssignments.head.key) result = doStepAssignments.head.key } Log.pop("findDoStepStatementIndex") return result } def createCoSimStepInstructions(Adaptation sa) { check((sa.inner as InnerFMUDeclarationFull).fmus.size > 0, "At least one internal FMU is expected...") if (onlyOneInternalFMU(sa)){ createCosimStepForOneFMU(sa) } else { createCosimStepForMultipleFMUs(sa) } } def createCosimStepForOneFMU(Adaptation sa) { Log.push("createCosimStepForOneFMU") val fmu = (sa.inner as InnerFMUDeclarationFull).fmus.head val controlRule = sa.control.rule as CustomControlRule val returnedStepVar = controlRule.appendDoStep(fmu) val stepVarSingleton = new LinkedList() stepVarSingleton.add(returnedStepVar) controlRule.appendReturnCosimStep(stepVarSingleton) Log.pop("createCosimStepForOneFMU") } def appendReturnCosimStep(CustomControlRule rule, LinkedList stepVariables) { Log.push("appendReturnCosimStep") if (stepVariables.size == 0){ throw new Exception("Does not make sense. At least one inner FMU is expected.") } val minExpression = SemanticAdaptationFactory.eINSTANCE.createMin() Log.println("Creating min(...) expression with the following arguments:") for(varDecl : stepVariables){ val varRef = SemanticAdaptationFactory.eINSTANCE.createVariable() varRef.ref = varDecl minExpression.args.add(varRef) Log.println(varDecl.name) } rule.returnstatement = SemanticAdaptationFactory.eINSTANCE.createReturnStatement() rule.returnstatement.expr = minExpression Log.pop("appendReturnCosimStep") } def appendDoStep(CustomControlRule rule, InnerFMU fmu) { Log.push("appendDoStep") val t = SemanticAdaptationFactory.eINSTANCE.createCurrentTime() val H = SemanticAdaptationFactory.eINSTANCE.createStepSize() val doStep = SemanticAdaptationFactory.eINSTANCE.createDoStepFun() doStep.t = t doStep.h = H doStep.fmu = fmu val step_var = SemanticAdaptationFactory.eINSTANCE.createSingleVarDeclaration() step_var.name = "H_" + fmu.name step_var.expr = doStep val step_decl = SemanticAdaptationFactory.eINSTANCE.createDeclaration() step_decl.declarations.add(step_var) rule.controlRulestatements.add(step_decl) Log.println("Added var " + step_var.name + " := doStep(t, H, " + fmu.name + ")") Log.pop("appendDoStep") return step_var } def createCosimStepForMultipleFMUs(Adaptation sa) { Log.push("createCosimStepForMultipleFMUs") val innerDeclaration = (sa.inner as InnerFMUDeclarationFull) val controlRule = sa.control.rule as CustomControlRule val stepVarSingleton = new LinkedList() for (fmu : innerDeclaration.topologicalSort()){ val returnedStepVar = controlRule.appendDoStep(fmu) stepVarSingleton.add(returnedStepVar) } controlRule.appendReturnCosimStep(stepVarSingleton) Log.pop("createCosimStepForMultipleFMUs") } def topologicalSort(InnerFMUDeclarationFull scenario){ Log.push("topologicalSort") val DirectedGraph inner_fmu_graph = createFMUGraph(scenario) val result = TopologicalSort.sort(inner_fmu_graph) Log.println("Sorting: " + result) Log.pop("topologicalSort") return result } def createFMUGraph(InnerFMUDeclarationFull scenario) { Log.push("createFMUGraph") val graph = new FMUGraph() for (fmu : scenario.fmus){ graph.addNode(fmu) } for (connection : scenario.connection){ check(connection.src.port.eContainer instanceof InnerFMU && connection.tgt.port.eContainer instanceof InnerFMU, "Weird connection found: " + connection) if (reactiveMealyFMU(connection.tgt.port.eContainer as InnerFMU)){ graph.addEdge(connection.src.port.eContainer as InnerFMU, connection.tgt.port.eContainer as InnerFMU) } else { Log.println("FMU " + (connection.tgt.port.eContainer as InnerFMU).name + " is not reactive mealy, so it has no algebraic dependencies.") } } Log.println(graph.toString()) Log.pop("createFMUGraph") return graph } def reactiveMealyFMU(InnerFMU fmu) { return fmu.reactiveness == ReactiveOrDelayed.REACTIVE && fmu.machine == MooreOrMealy.MEALY } def check(Boolean condition, String msg){ if (! condition){ throw new Exception("Assertion error: " + msg) } } def onlyOneInternalFMU(Adaptation sa) { if(sa.inner instanceof InnerFMUDeclarationFull){ return (sa.inner as InnerFMUDeclarationFull).fmus.size == 1 } else { throw new Exception('This kind of internal scenario is not supported yet.') } } def transitiveStep(HashMap internalOutputPort2ExternalPortBindings, HashMap externalOutputPort2OutVarDeclaration) { Log.push("transitiveStep") val internalOutputPort2OutVarDeclaration = new HashMap() for(internalOutputPort : internalOutputPort2ExternalPortBindings.keySet){ val externalOutputPort = internalOutputPort2ExternalPortBindings.get(internalOutputPort) if (externalOutputPort2OutVarDeclaration.containsKey(externalOutputPort)){ val outVar = externalOutputPort2OutVarDeclaration.get(externalOutputPort) Log.println("Found binding: " + internalOutputPort.qualifiedName + "->" + externalOutputPort.qualifiedName + " to be stored in " + outVar.name) internalOutputPort2OutVarDeclaration.put(internalOutputPort, outVar) } } Log.pop("transitiveStep") return internalOutputPort2OutVarDeclaration } def String qualifiedName(Port port){ if (port.eContainer instanceof FMU){ return (port.eContainer as FMU).name + "." + port.name } return port.name } def removeBindings(HashMap internalPort2ExternalPortBindings, Adaptation sa) { Log.push("removeBindings") for (internalPort : internalPort2ExternalPortBindings.keySet){ val externalPort = internalPort2ExternalPortBindings.get(internalPort) Log.println("Removing binding " + externalPort.qualifiedName + "->" + internalPort.qualifiedName) externalPort.targetdependency = null Log.println("Removing binding " + externalPort.qualifiedName + "<-" + internalPort.qualifiedName) externalPort.sourcedependency = null } Log.pop("removeBindings") } def findAllExternalPort2InputPort_Bindings(Adaptation sa) { Log.push("findAllExternalPort2InputPort_Bindings") val internalPort2ExternalPortBindings = new HashMap() for (port : getAllInnerFMUInputPortDeclarations(sa)){ var parentFMU = port.eContainer as InnerFMU Log.println("Checking if port " + port.qualifiedName + " is bound to an external port.") val externalPort = findExternalPortByTargetDependency(sa.inports, port) if (externalPort !== null){ Log.println("Port " + port.qualifiedName + " is bound to an external port: " + externalPort.qualifiedName) internalPort2ExternalPortBindings.put(port, externalPort) } else { Log.println("Port " + port.qualifiedName + " is not bound to an external port.") } } Log.pop("findAllExternalPort2InputPort_Bindings") return internalPort2ExternalPortBindings } def findAllInternalPort2ExternalOutputPort_Bindings(Adaptation sa) { Log.push("findAllInternalPort2ExternalOutputPort_Bindings") val internalPort2ExternalPortBindings = new HashMap() for (port : getAllInnerFMUOutputPortDeclarations(sa)){ Log.println("Checking if port " + port.qualifiedName + " is bound to an external port.") val externalPort = findExternalPortBySourceDependency(sa.outports, port) if (externalPort !== null){ Log.println("Port " + externalPort.qualifiedName + " is bound to an internal port: " + port.qualifiedName ) internalPort2ExternalPortBindings.put(port, externalPort) } else { Log.println("Port " + port.qualifiedName + " is not bound to an external port.") } } Log.pop("findAllInternalPort2ExternalOutputPort_Bindings") return internalPort2ExternalPortBindings } def createExternalPortNameFromInternalPort(String parentFMUName, String internalPortName) { //return parentFMUName + "__" + internalPortName // Violates transparency return internalPortName } def addInRules_External2Internal_Assignments(Adaptation sa, HashMap internalPort2ExternalPort) { Log.push("addInRules_External2Internal_Assignments") val dataRule = getOrPrependTrueRule(sa.in.rules) for(internalPort : internalPort2ExternalPort.keySet){ val externalPort = internalPort2ExternalPort.get(internalPort) check((dataRule.outputfunction instanceof CompositeOutputFunction), "Only CompositeOutputFunction is supported for now.") val outFunction = dataRule.outputfunction as CompositeOutputFunction addPortAssignment(outFunction.statements, internalPort, externalPort, 0, true) } Log.pop("addInRules_External2Internal_Assignments") } def addOutRules_Internal2External_Assignments(Adaptation sa, HashMap internalPort2ExternalPort){ Log.push("addOutRules_Internal2External_Assignments") val dataRule = getOrPrependTrueRule(sa.out.rules) for(internalPort : internalPort2ExternalPort.keySet){ val externalPort = internalPort2ExternalPort.get(internalPort) check((dataRule.outputfunction instanceof CompositeOutputFunction), "Only CompositeOutputFunction is supported for now.") val outFunction = dataRule.outputfunction as CompositeOutputFunction addPortAssignment(outFunction.statements, externalPort, internalPort, 0, true) } Log.pop("addOutRules_Internal2External_Assignments") } def addPortAssignment(List statements, Port toPort, Port fromPort, int position, boolean convertUnits) { Log.push("addPortAssignment") val assignment = SemanticAdaptationFactory.eINSTANCE.createAssignment() assignment.lvalue = SemanticAdaptationFactory.eINSTANCE.createVariable() (assignment.lvalue as Variable).owner = toPort.eContainer as FMU (assignment.lvalue as Variable).ref = toPort val varRef = SemanticAdaptationFactory.eINSTANCE.createVariable() varRef.owner = fromPort.eContainer as FMU varRef.ref = fromPort if (convertUnits && compatibleUnits(toPort.unity, fromPort.unity) && !unitsEqual(toPort.unity, fromPort.unity)){ Log.println("Converting units " + fromPort.unity + " to " + toPort.unity) assignment.expr = getConversionExpression(toPort.unity, fromPort.unity, varRef) } else { assignment.expr = varRef Log.println("Assignment " + toPort.qualifiedName + " := " + fromPort.qualifiedName + " created.") } statements.add(position, assignment) Log.pop("addPortAssignment") } def getConversionExpression(Unity toUnits, Unity fromUnit, Variable varFrom) { check(toUnits instanceof AtomicUnity && fromUnit instanceof AtomicUnity, "Conversion between units is only supported for AtomicUnits.") var toAtomic = toUnits as AtomicUnity var fromAtomic = fromUnit as AtomicUnity check(fromAtomic.name == "cm" && toAtomic.name == "m", "Conversion only possible between cm and m... Not very usefull :)") var division = SemanticAdaptationFactory.eINSTANCE.createDiv() division.left = varFrom var hundred = SemanticAdaptationFactory.eINSTANCE.createRealLiteral() hundred.value=100f division.right = hundred return division } def dispatch boolean unitsEqual(DivideUnity u1, DivideUnity u2) { return unitsEqual(u1.left, u2.left) && unitsEqual(u1.right, u2.right) } def dispatch boolean unitsEqual(Void u1, Void u2) { return true } def dispatch boolean unitsEqual(MultiplyUnity u1, MultiplyUnity u2) { return unitsEqual(u1.left, u2.left) && unitsEqual(u1.right, u2.right) } def dispatch boolean unitsEqual(AtomicUnity u1, AtomicUnity u2) { return u1.name == u2.name && u1.power == u2.power } def compatibleUnits(Unity u1, Unity u2) { if ((u1 === null && u2===null) || (u1 !== null && u2!==null) ){ // TODO What makes two units compatible? return true } else { return false } } def addInRules_External2Stored_Assignments(Adaptation sa, HashMap inputPort2InVarDeclaration) { Log.push("addInRules_External2Stored_Assignments") if (sa.in === null){ sa.in = SemanticAdaptationFactory.eINSTANCE.createInRulesBlock() } addRules_Port2Stored_Assignments(sa.in.rules, inputPort2InVarDeclaration) Log.pop("addInRules_External2Stored_Assignments") } def addOutRules_Internal2Stored_Assignments(Adaptation sa, HashMap internalOutputPort2OutVarDeclaration) { Log.push("addOutRules_Internal2Stored_Assignments") if (sa.out === null){ sa.out = SemanticAdaptationFactory.eINSTANCE.createOutRulesBlock() } addRules_Port2Stored_Assignments(sa.out.rules, internalOutputPort2OutVarDeclaration) Log.pop("addOutRules_Internal2Stored_Assignments") } def addRules_Port2Stored_Assignments(List rules, HashMap port2VarDeclaration) { Log.push("addRules_External2Stored_Assignments") val dataRule = getOrPrependTrueRule(rules) if (dataRule.statetransitionfunction.expression !== null){ throw new Exception("Expressions in rules are not supported yet.") // This and the one below are asily solved with a syntactic sugar substitution. } if (dataRule.statetransitionfunction.assignment !== null){ throw new Exception("Assignment in rules are not supported yet.") } for(port : port2VarDeclaration.keySet){ val storedVarDecl = port2VarDeclaration.get(port) addAssignmentToStoredVar(dataRule.statetransitionfunction.statements, port, storedVarDecl) } Log.pop("addRules_External2Stored_Assignments") } def addAssignmentToStoredVar(List statements, Port internalPort, SingleVarDeclaration storedVarDecl) { Log.push("addAssignmentToStoredVar") val assignment = SemanticAdaptationFactory.eINSTANCE.createAssignment() assignment.lvalue = SemanticAdaptationFactory.eINSTANCE.createVariable() assignment.lvalue.ref = storedVarDecl assignment.expr = SemanticAdaptationFactory.eINSTANCE.createVariable() (assignment.expr as Variable).owner = internalPort.eContainer as FMU (assignment.expr as Variable).ref = internalPort statements.add(0, assignment) Log.println("Assignment " + storedVarDecl.name + " := " + internalPort.qualifiedName + " created.") Log.pop("addAssignmentToStoredVar") } def getOrPrependTrueRule(List rules) { var DataRule rule = null if (rules.size == 0 || !isTrueRule(rules.head)){ Log.println("No existing rule found with true condition. Creating one.") val trueRule = SemanticAdaptationFactory.eINSTANCE.createDataRule() trueRule.condition = SemanticAdaptationFactory.eINSTANCE.createRuleCondition() val trueExpr = SemanticAdaptationFactory.eINSTANCE.createBoolLiteral() trueExpr.value = "true" trueRule.condition.condition = trueExpr trueRule.statetransitionfunction = SemanticAdaptationFactory.eINSTANCE.createStateTransitionFunction() trueRule.outputfunction = SemanticAdaptationFactory.eINSTANCE.createCompositeOutputFunction() rules.add(0, trueRule) rule = trueRule } else { Log.println("Existing rule with true condition found.") rule = rules.head } return rule } def isTrueRule(DataRule rule){ if (rule.condition.condition instanceof BoolLiteral){ return (rule.condition.condition as BoolLiteral).value == "true" } return false } def addInVars(Adaptation sa, Map inputPort2parameterDeclaration){ Log.push("addInVars") if (sa.in === null){ sa.in = SemanticAdaptationFactory.eINSTANCE.createInRulesBlock() } val inputPort2InVarDeclaration = addStorageVars(sa.in.globalInVars, inputPort2parameterDeclaration) Log.pop("addInVars") return inputPort2InVarDeclaration } def addOutVars(Adaptation sa, Map outputPort2parameterDeclaration){ Log.push("addOutVars") if (sa.out === null){ sa.out = SemanticAdaptationFactory.eINSTANCE.createOutRulesBlock() } val outputPort2InVarDeclaration = addStorageVars(sa.out.globalOutVars, outputPort2parameterDeclaration) Log.pop("addOutVars") return outputPort2InVarDeclaration } def addStorageVars(List varDeclarations, Map port2parameterDeclaration){ Log.push("addStorageVars") var port2VarDeclaration = new HashMap() for(port : port2parameterDeclaration.keySet){ Log.println("Processing port " + port.qualifiedName) val paramDecl = port2parameterDeclaration.get(port) val varDeclarationName = getStorageVarDeclarationName(port) if (!varDeclarationExists(varDeclarationName, varDeclarations) ){ Log.println("Creating new variable declaration " + varDeclarationName) val varDeclaration = addNewVarDeclaration(port, paramDecl, varDeclarations) port2VarDeclaration.put(port, varDeclaration) } else { Log.println("Input variable declaration " + varDeclarationName + " already exists.") } } Log.pop("addStorageVars") return port2VarDeclaration } def addNewVarDeclaration(Port externalInputPort, SingleParamDeclaration paramDecl, List varDeclarations) { /* if (sa.in === null){ sa.in = SemanticAdaptationFactory.eINSTANCE.createInRulesBlock() } */ if (varDeclarations.size == 0){ varDeclarations.add(SemanticAdaptationFactory.eINSTANCE.createDeclaration()) } val newSingleVarDecl = SemanticAdaptationFactory.eINSTANCE.createSingleVarDeclaration() newSingleVarDecl.name = getStorageVarDeclarationName(externalInputPort) newSingleVarDecl.type = externalInputPort.type val initValue = SemanticAdaptationFactory.eINSTANCE.createVariable() initValue.ref = paramDecl newSingleVarDecl.expr = initValue varDeclarations.head.declarations.add(newSingleVarDecl) Log.println("New variable declaration created: " + newSingleVarDecl.name + " := " + paramDecl.name) return newSingleVarDecl } def varDeclarationExists(String invarName, List varDeclarations) { for (declarations : varDeclarations){ // sa.in.globalInVars for (decl : declarations.declarations){ if (decl.name == invarName){ return true } } } return false } def getStorageVarDeclarationName(Port externalInputPort) { return "stored__" + externalInputPort.name; } def genericDeclarationInferenceAlgorithm(Adaptation sa, (EObject)=>Object getField, (EObject, Object)=>void setField, (EObject)=>Object inferField ){ Log.push("Running generic inference algorithm...") /* * Dumbest (and simplest) algorithm for this is a fixed point computation: * 1. Look for every var/port declaration * 2. If that var has a XXX already, nothing else to be done. * 3. If that var has no XXX declared, then * 3.1 If var/port has an initial value or connection, then * 3.1.1 If the initial_value/connection has a XXX declared, then var gets that XXX. * 3.1.2 Otherwise, nothing else to be done. * 3.2 If var/port has no initial value or connection then this either is a missing feature, or an error. * 3.3 If something has changed, go to 1. Otherwise, end. * * An extra set of instructions is there to push the element field information using connections and bindings. */ var fixedPoint = false var unfieldedElementsCounter = 0 while (! fixedPoint){ fixedPoint = true unfieldedElementsCounter = 0 Log.println("Inferring parameter fields...") for (paramDeclarations : sa.params) { for (paramDeclaration : paramDeclarations.declarations) { Log.println("Computing field for param " + paramDeclaration.name) if(getField.apply(paramDeclaration) !== null){ Log.println("Already has been inferred: " + getField.apply(paramDeclaration)) } else { Log.println("Has not been inferred yet.") if (tryInferAndAssignField(paramDeclaration, getField, setField, inferField)){ fixedPoint = false } else { unfieldedElementsCounter++ } } } } if(sa.inner !== null){ if(sa.inner instanceof InnerFMUDeclarationFull){ var innerFMUFull = sa.inner as InnerFMUDeclarationFull for(fmu : innerFMUFull.fmus){ Log.println("Inferring port fields of FMU " + fmu.name) for (port : EcoreUtil2.getAllContentsOfType(fmu, Port)) { if(getField.apply(port) !== null){ Log.println("Already has a field: " + getField.apply(port)) } else { if (tryInferAndAssignField(port, getField, setField, inferField)){ fixedPoint = false } else { unfieldedElementsCounter++ } } } } if (innerFMUFull.connection.size > 0){ Log.println("Inferring port fields using internal scenario bindings.") for (binding : innerFMUFull.connection){ if (getField.apply(binding.src.port) !== null && getField.apply(binding.tgt.port) !== null){ Log.println("Both ports have fields already.") } else { var inferredFieldAttempt = inferPortFieldViaConnection(binding, getField, setField, inferField) if (inferredFieldAttempt !== null){ if (getField.apply(binding.src.port) === null){ setField.apply(binding.src.port, inferredFieldAttempt) } else if (getField.apply(binding.tgt.port) === null){ setField.apply(binding.tgt.port, inferredFieldAttempt) } fixedPoint = false unfieldedElementsCounter-- Log.println("Got new field: " + inferredFieldAttempt) } else { Log.println("Cannot infer field from binding now.") } } } } } else { throw new Exception("Field inference only supported for InnerFMUDeclarationFull.") } } Log.println("Inferring external port fields...") var externalPorts = new LinkedList(sa.inports) externalPorts.addAll(sa.outports) for (port : externalPorts) { if (getField.apply(port) !== null){ Log.println("Already has a field: " + getField.apply(port)) if (pushPortField(port, getField, setField, inferField)){ fixedPoint = false unfieldedElementsCounter-- } } else { if (tryInferAndAssignField(port, getField, setField, inferField)){ fixedPoint = false } else { unfieldedElementsCounter++ } } } Log.println("Inferring all other declaration fields...") for (varDeclaration : EcoreUtil2.getAllContentsOfType(sa, SingleVarDeclaration)) { Log.println("Computing field for declaration " + varDeclaration.name) if(getField.apply(varDeclaration) !== null){ Log.println("Already has a field: " + getField.apply(varDeclaration)) } else { if (tryInferAndAssignField(varDeclaration, getField, setField, inferField)){ fixedPoint = false } else { unfieldedElementsCounter++ } } } Log.println("Ended iteration with unfielded elements remaining: " + unfieldedElementsCounter) } // while (! fixedPoint) Log.pop("Running generic inference algorithm... DONE") return unfieldedElementsCounter } def tryInferAndAssignField(EObject element, (EObject)=>Object getField, (EObject, Object)=>void setField, (EObject)=>Object inferField) { var inferredFieldAttempt = inferField.apply(element) if (inferredFieldAttempt !== null){ setField.apply(element, inferredFieldAttempt) Log.println("Got new field: " + inferredFieldAttempt) return true } else { Log.println("Cannot infer field now.") return false } } def extractTypeFromExpression(Expression expression, String declarationName){ if (expression instanceof IntLiteral){ return "Integer" } else if (expression instanceof RealLiteral){ return "Real" } else if (expression instanceof BoolLiteral){ return "Bool" } else if (expression instanceof StringLiteral){ return "String" } else if (expression instanceof Variable){ var varRef = expression as Variable if (varRef.ref instanceof Port){ var decl = varRef.ref as Port if (decl.type !== null){ return decl.type } } else if(varRef.ref instanceof SingleParamDeclaration){ var decl = varRef.ref as SingleParamDeclaration if (decl.type !== null){ return decl.type } } else if(varRef.ref instanceof SingleVarDeclaration){ var decl = varRef.ref as SingleVarDeclaration if (decl.type !== null){ return decl.type } } else if(varRef.ref instanceof DeclaredParameter){ throw new Exception("Type cannot be inferred for references to DeclaredParameter (for now). Please specify the explicit type of declaration " + declarationName) } else { throw new Exception("Unexpected kind of Variable expression found.") } } else if(expression instanceof BuiltinFunction){ if (expression instanceof IsSet || expression instanceof Close){ return "Bool" } else { return "Real" } } else { throw new Exception("Initial value for declaration " + declarationName + " must be literal or var ref for now. Got instead " + expression + ". If you want complex expressions, give it an explicit type.") } return null } def inferPortFieldViaConnection(Connection binding, (EObject)=>Object getField, (EObject, Object)=>void setField, (EObject)=>Object inferField ){ var Object resultField = null if (getField.apply(binding.src.port) !== null && getField.apply(binding.tgt.port) !== null){ throw new Exception("Wrong way of using this function. It assumes type is not inferred yet.") } else if (getField.apply(binding.src.port) !== null){ resultField = getField.apply(binding.src.port) Log.println("Target port "+ binding.tgt.port.qualifiedName +" got new type: " + resultField) } else if (getField.apply(binding.tgt.port) !== null){ resultField = getField.apply(binding.tgt.port) Log.println("Target port "+ binding.src.port.qualifiedName +" got new type: " + resultField) } return resultField } def pushPortField(Port port, (EObject)=>Object getField, (EObject, Object)=>void setField, (EObject)=>Object inferField){ var fieldInferred = false Log.println("Pushing field of port " + port.qualifiedName + " to its bindings.") if(getField.apply(port) === null){ Log.println("Has no field to be pushed.") throw new Exception("Wrong way of using this function. It assumes field is already inferred.") } else { Log.println("Pushing field: " + getField.apply(port)) if(port.sourcedependency !== null){ Log.println("Has a source dependency: " + port.sourcedependency.port.qualifiedName) if(getField.apply(port.sourcedependency.port) === null){ setField.apply(port.sourcedependency.port, getField.apply(port)) Log.println("Port " + port.sourcedependency.port.qualifiedName + " got new type: " + getField.apply(port.sourcedependency.port)) fieldInferred = true } else { Log.println("Source port already has field.") } } else { Log.println("Has no source dependency.") } if (port.targetdependency !== null) { Log.println("Has a target dependency: " + port.targetdependency.port.qualifiedName) if(getField.apply(port.targetdependency.port) === null){ Log.println("Dependency has no field yet.") setField.apply(port.targetdependency.port, getField.apply(port)) Log.println("Port " + port.targetdependency.port.qualifiedName + " got new type: " + getField.apply(port.targetdependency.port)) fieldInferred = true } else { Log.println("Target port already has field.") } } else { Log.println("Has no target dependency.") } } return fieldInferred } def getPortUnit(Port port){ var unitInferred = false Log.println("Computing unit for port " + port.qualifiedName) var Unity returnUnit = null if(port.unity !== null){ throw new Exception("Wrong way of using this function. It assumes unit is not inferred yet.") } else { Log.println("Has no unit.") Log.println("Attempting to infer unit from bindings.") if(port.sourcedependency !== null){ Log.println("Has a source dependency: " + port.sourcedependency.port.qualifiedName) if(port.sourcedependency.port.unity === null){ Log.println("Dependency has no unit yet.") } else { returnUnit = port.sourcedependency.port.unity Log.println("Got new unit: " + returnUnit) unitInferred = true } } else { Log.println("Has no source dependency.") } if (port.targetdependency !== null && !unitInferred) { Log.println("Has a target dependency: " + port.targetdependency.port.qualifiedName) if(port.targetdependency.port.unity === null){ Log.println("Dependency has no unit yet.") } else { returnUnit = port.targetdependency.port.unity Log.println("Got new unit: " + returnUnit) unitInferred = true } } else { Log.println("Has no target dependency, or unit has already been inferred from source dependency.") } } return returnUnit } def getPortType(Port port){ var typeInferred = false Log.println("Computing type for port " + port.qualifiedName) var String returnType = null if(port.type !== null){ throw new Exception("Wrong way of using this function. It assumes type is not inferred yet.") } else { Log.println("Has no type.") Log.println("Attempting to infer type from units.") if (port.unity !== null){ returnType = "Real" Log.println("Got new type: " + returnType) typeInferred = true } else { Log.println("Attempting to infer type from bindings.") if(port.sourcedependency !== null){ Log.println("Has a source dependency: " + port.sourcedependency.port.qualifiedName) if(port.sourcedependency.port.type === null){ Log.println("Dependency has no type yet.") } else { returnType = port.sourcedependency.port.type Log.println("Got new type: " + returnType) typeInferred = true } } else { Log.println("Has no source dependency.") } if (port.targetdependency !== null && !typeInferred) { Log.println("Has a target dependency: " + port.targetdependency.port.qualifiedName) if(port.targetdependency.port.type === null){ //println("Port object: " + port.targetdependency.port) Log.println("Dependency has no type yet.") } else { returnType = port.targetdependency.port.type Log.println("Got new type: " + returnType) typeInferred = true } } else { Log.println("Has no target dependency, or type has already been inferred from source dependency.") } } } return returnType } def addInPorts(Adaptation sa) { Log.push("Adding input ports...") for (port : getAllInnerFMUInputPortDeclarations(sa)){ var parentFMU = port.eContainer as InnerFMU Log.println("Checking if port " + port.qualifiedName + " has incoming connections" ) if (! hasConnection(port, sa, true)){ Log.println("Port " + port.qualifiedName + " has no incoming connections.") val externalPortName = createExternalPortNameFromInternalPort(parentFMU.name, port.name) if (findExternalPortByName(sa, externalPortName) === null){ var newExternalPort = createExternalInputPortDeclarationFromInnerPort(port, parentFMU, sa) Log.println("External port " + newExternalPort.qualifiedName + " created.") newExternalPort.bindExternalInputPortTo(parentFMU, port) Log.println("External port " + newExternalPort.qualifiedName + " bound to port " + port.qualifiedName) } else { Log.println("Error: External port " + externalPortName + " already declared.") throw new Exception("Error: External port " + externalPortName + " already declared. Please rename it to avoid clashes.") } } else { Log.println("Port " + port.qualifiedName + " has an incoming connection.") } } Log.pop("Adding input ports... DONE") } def bindExternalInputPortTo(Port externalInputPort, InnerFMU internalPortParent, Port internalPort) { externalInputPort.targetdependency = SemanticAdaptationFactory.eINSTANCE.createSpecifiedPort() externalInputPort.targetdependency.owner = internalPortParent externalInputPort.targetdependency.port = internalPort } def bindExternalOutputPortTo(Port externalOutputPort, InnerFMU internalPortParent, Port internalPort) { externalOutputPort.sourcedependency = SemanticAdaptationFactory.eINSTANCE.createSpecifiedPort() externalOutputPort.sourcedependency.owner = internalPortParent externalOutputPort.sourcedependency.port = internalPort } def createExternalInputPortDeclarationFromInnerPort(Port port, FMU parent, Adaptation sa) { var externalInputPort = createExternalPortDeclarationFromInnerPort(port, parent) sa.inports.add(externalInputPort) return externalInputPort } def createExternalOutputPortDeclarationFromInnerPort(Port port, FMU parent, Adaptation sa) { var externalOutputPort = createExternalPortDeclarationFromInnerPort(port, parent) sa.outports.add(externalOutputPort) return externalOutputPort } def createExternalPortDeclarationFromInnerPort(Port port, FMU parent) { var externalInputPort = SemanticAdaptationFactory.eINSTANCE.createPort() externalInputPort.name = createExternalPortNameFromInternalPort(parent.name, port.name) externalInputPort.type = port.type externalInputPort.unity = EcoreUtil2.copy(port.unity) return externalInputPort } def findExternalPortByName(Adaptation adaptation, String name) { for (externalInputPort : adaptation.inports){ if (externalInputPort.name == name){ return externalInputPort } } return null } def findExternalPortByTargetDependency(List ports, Port targetDependency) { for (externalInputPort : ports){ if (externalInputPort.targetdependency !== null && externalInputPort.targetdependency.port == targetDependency){ return externalInputPort } } return null } def findExternalPortBySourceDependency(List ports, Port sourceDependency) { for (externalInputPort : ports){ if (externalInputPort.sourcedependency !== null && externalInputPort.sourcedependency.port == sourceDependency){ return externalInputPort } } return null } def hasConnection(Port port, Adaptation adaptation, Boolean checkForIncomming) { var result = false if ( (checkForIncomming && port.sourcedependency !== null) || (! checkForIncomming && port.targetdependency !== null) ){ result = true } else { if (port.eContainer instanceof InnerFMU){ var innerScenarioDeclaration = EcoreUtil2.getContainerOfType(port, InnerFMUDeclaration) if (innerScenarioDeclaration instanceof InnerFMUDeclarationFull){ var innerScenarioWithCoupling = innerScenarioDeclaration as InnerFMUDeclarationFull if (innerScenarioWithCoupling.connection.size > 0){ for (connection : innerScenarioWithCoupling.connection ){ if ( (checkForIncomming && connection.tgt.port == port)){ Log.println("Port " + port.qualifiedName + " has an incoming connection from internal port " + connection.src.port.qualifiedName) result = true } else if (!checkForIncomming && connection.src.port == port) { Log.println("Port " + port.qualifiedName + " has an outgoing connection to internal port " + connection.tgt.port.qualifiedName) result = true } } } } for (externalInputPort : adaptation.inports.filter[p | (checkForIncomming && p.targetdependency !== null) || (!checkForIncomming && p.sourcedependency !== null) ]){ if (checkForIncomming && externalInputPort.targetdependency.port == port){ Log.println("Port " + port.qualifiedName + " has an incoming connection from external port " + externalInputPort.qualifiedName) result = true } else if ( !checkForIncomming && externalInputPort.sourcedependency.port == port){ Log.println("Port " + port.qualifiedName + " has an outgoing connection to external port " + externalInputPort.qualifiedName) result = true } } } } return result } def getAllInnerFMUInputPortDeclarations(Adaptation sa){ return mapAllInnerFMUs(sa, [fmu | fmu.inports]); } def getAllInnerFMUOutputPortDeclarations(Adaptation sa){ return mapAllInnerFMUs(sa, [fmu | fmu.outports]); } def List mapAllInnerFMUs(Adaptation sa, (InnerFMU)=>List map){ var result = new LinkedList() if(sa.inner !== null){ if(sa.inner instanceof InnerFMUDeclarationFull){ var innerFMUFull = sa.inner as InnerFMUDeclarationFull for(fmu : innerFMUFull.fmus){ result.addAll(map.apply(fmu)) } } else { throw new Exception("Only support for InnerFMUDeclarationFull.") } } return result; } def addInParams(Adaptation sa) { Log.push("Adding input parameters...") val result = addParamForPortDeclarations(sa, sa.inports) Log.pop("Adding input parameters... DONE") return result } def addOutParams(Adaptation sa) { Log.push("Adding output parameters...") val result = addParamForPortDeclarations(sa, getAllInnerFMUOutputPortDeclarations(sa)) Log.pop("Adding output parameters... DONE") return result } def addParamForPortDeclarations(Adaptation sa, List ports){ Log.push("addParamForPortDeclarations") val PARAM_PREFIX = "INIT_" var port2parameterDeclaration = new HashMap(ports.size) for (externalPortDecl : ports) { Log.println("Generating parameter for port " + externalPortDecl.qualifiedName) var paramname = PARAM_PREFIX + externalPortDecl.name.toUpperCase() if (paramAlreadyDeclared(paramname, sa)){ Log.println("Parameter " + paramname + " already declared for port " + externalPortDecl.qualifiedName) } else { Log.println("Declaring new parameter " + paramname + " for port " + externalPortDecl.qualifiedName) var paramDeclaration = addNewParamDeclaration(paramname, externalPortDecl, sa) port2parameterDeclaration.put(externalPortDecl, paramDeclaration) } } Log.pop("addParamForPortDeclarations") return port2parameterDeclaration } def addNewParamDeclaration(String name, Port fromPort, Adaptation sa) { var factory = SemanticAdaptationFactory.eINSTANCE var paramDeclaration = factory.createSingleParamDeclaration() paramDeclaration.name = name paramDeclaration.type = fromPort.type paramDeclaration.expr = getDefaultTypeExpression(paramDeclaration.type) if (sa.params.size == 0){ sa.params.add(factory.createParamDeclarations()) } sa.params.head.declarations.add(paramDeclaration) return paramDeclaration } def getDefaultTypeExpression(String type) { switch (type) { case "Integer": { val result = SemanticAdaptationFactory.eINSTANCE.createIntLiteral result.value = 0 return result } case "Real": { val result = SemanticAdaptationFactory.eINSTANCE.createRealLiteral result.value = 0.0f return result } case "Bool": { val result = SemanticAdaptationFactory.eINSTANCE.createBoolLiteral result.value = "false" return result } case "String": { val result = SemanticAdaptationFactory.eINSTANCE.createStringLiteral result.value = " " return result } default: { throw new Exception("Unexpected type.") } } } def paramAlreadyDeclared(String name, Adaptation sa) { for(paramDeclarations : sa.params){ for(paramDeclaration : paramDeclarations.declarations){ if(paramDeclaration.name == name){ return true } } } return false } def addOutPorts(Adaptation sa) { Log.push("Adding output ports...") for (port : getAllInnerFMUOutputPortDeclarations(sa)){ var parentFMU = port.eContainer as InnerFMU Log.println("Checking if port " + port.qualifiedName + " has outgoing connections") if (! hasConnection(port, sa, false)){ Log.println("Port " + port.qualifiedName + " has no outgoing connections.") val externalPortName = createExternalPortNameFromInternalPort(parentFMU.name, port.name) if (findExternalPortByName(sa, externalPortName) === null){ var newExternalPort = createExternalOutputPortDeclarationFromInnerPort(port, parentFMU, sa) Log.println("External port " + newExternalPort.qualifiedName + " created.") newExternalPort.bindExternalOutputPortTo(parentFMU, port) Log.println("External port " + newExternalPort.qualifiedName + " bound to port " + port.qualifiedName) } else { Log.println("Error: External port " + externalPortName + " already declared.") throw new Exception("Error: External port " + externalPortName + " already declared. Please rename it to avoid clashes.") } } else { Log.println("Port " + port.qualifiedName + " has an incoming connection.") } } Log.pop("Adding output ports... DONE") } }