SemanticAdaptationCanonicalGenerator.xtend 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537
  1. /*
  2. * generated by Xtext 2.10.0
  3. */
  4. package be.uantwerpen.ansymo.semanticadaptation.cg.canonical
  5. import be.uantwerpen.ansymo.semanticadaptation.cg.canonical.graph.DirectedGraph
  6. import be.uantwerpen.ansymo.semanticadaptation.cg.canonical.graph.FMUGraph
  7. import be.uantwerpen.ansymo.semanticadaptation.cg.canonical.graph.TopologicalSort
  8. import be.uantwerpen.ansymo.semanticadaptation.log.Log
  9. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Adaptation
  10. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Assignment
  11. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.AtomicUnity
  12. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.BoolLiteral
  13. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.BuiltinFunction
  14. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Close
  15. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.CompositeOutputFunction
  16. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Connection
  17. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.CustomControlRule
  18. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.DataRule
  19. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Declaration
  20. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.DeclaredParameter
  21. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.DivideUnity
  22. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.DoStep
  23. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.DoStepFun
  24. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Expression
  25. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.FMU
  26. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.InnerFMU
  27. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.InnerFMUDeclaration
  28. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.InnerFMUDeclarationFull
  29. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.IntLiteral
  30. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.IsSet
  31. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.MooreOrMealy
  32. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.MultiplyUnity
  33. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Port
  34. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.ReactiveOrDelayed
  35. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.RealLiteral
  36. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SemanticAdaptationFactory
  37. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SingleParamDeclaration
  38. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SingleVarDeclaration
  39. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Statement
  40. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.StringLiteral
  41. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Unity
  42. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Variable
  43. import java.io.ByteArrayOutputStream
  44. import java.util.HashMap
  45. import java.util.LinkedList
  46. import java.util.List
  47. import java.util.Map
  48. import org.eclipse.emf.common.util.EList
  49. import org.eclipse.emf.common.util.URI
  50. import org.eclipse.emf.ecore.EObject
  51. import org.eclipse.xtext.EcoreUtil2
  52. import org.eclipse.xtext.generator.IFileSystemAccess2
  53. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.CurrentTime
  54. /**
  55. * Generates code from your model files on save.
  56. *
  57. * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation
  58. */
  59. class SemanticAdaptationCanonicalGenerator {
  60. String CANONICAL_SUFIX = "_canonical"
  61. def Adaptation doGenerate(Adaptation adaptation, IFileSystemAccess2 fsa, URI mainFile) {
  62. Log.push("Generating canonical semantic adaptation for file...")
  63. Log.println(prettyprint_model(adaptation, "File Read"))
  64. // Create file name for the canonical sa file
  65. var fileNameWithoutExt = mainFile.trimFileExtension().lastSegment()
  66. Log.println("Checking if file is already a canonical version...")
  67. if (fileNameWithoutExt.indexOf(CANONICAL_SUFIX) == -1){
  68. Log.println("It is not.")
  69. var canonicalFileName = fileNameWithoutExt + CANONICAL_SUFIX + ".sa"
  70. Log.println("canonicalFileName = " + canonicalFileName)
  71. canonicalize(adaptation)
  72. Log.println(prettyprint_model(adaptation, "Generated File"))
  73. fsa.generateFile(canonicalFileName, adaptation.serialize_model)
  74. Log.println("File " + canonicalFileName + " written.")
  75. } else {
  76. Log.println("It is already a canonical version.")
  77. Log.println("Nothing to do.")
  78. }
  79. Log.pop("Generating canonical semantic adaptation for file... DONE")
  80. return adaptation
  81. }
  82. def prettyprint_model(Adaptation sa, String title){
  83. var outputByteArray = new ByteArrayOutputStream()
  84. sa.eResource.save(outputByteArray,null)
  85. return "______________________________" + title + "______________________________\n" +
  86. sa.serialize_model +
  87. "\n__________________________________________________________________________"
  88. }
  89. def serialize_model(Adaptation sa){
  90. var outputByteArray = new ByteArrayOutputStream()
  91. sa.eResource.save(outputByteArray,null)
  92. return outputByteArray.toString()
  93. }
  94. def inferUnits(Adaptation sa){
  95. // Unit inference
  96. var unitlessElements = genericDeclarationInferenceAlgorithm(sa ,
  97. [// getField
  98. element | {
  99. var DUMMY_UNIT = "Dips"
  100. if (element instanceof SingleParamDeclaration) {
  101. return DUMMY_UNIT
  102. } else if (element instanceof Port){
  103. return element.unity
  104. } else if (element instanceof SingleVarDeclaration){
  105. return DUMMY_UNIT
  106. } else {
  107. throw new Exception("Unexpected element type: " + element)
  108. }
  109. }
  110. ],
  111. [// setField
  112. element, value | {
  113. if (element instanceof SingleParamDeclaration) {
  114. } else if (element instanceof Port){
  115. element.unity = EcoreUtil2.copy(value as Unity)
  116. } else if (element instanceof SingleVarDeclaration){
  117. } else {
  118. throw new Exception("Unexpected element type: " + element)
  119. }
  120. }
  121. ],
  122. [// inferField
  123. element | {
  124. var DUMMY_UNIT = "Dips"
  125. if (element instanceof SingleParamDeclaration) {
  126. return DUMMY_UNIT
  127. } else if (element instanceof Port){
  128. return getPortUnit(element)
  129. } else if (element instanceof SingleVarDeclaration){
  130. return DUMMY_UNIT
  131. } else {
  132. throw new Exception("Unexpected element type: " + element)
  133. }
  134. }
  135. ]
  136. )
  137. if (unitlessElements > 0){
  138. Log.println("Could not infer all element units. There are " + unitlessElements + " unitless elements.")
  139. }
  140. }
  141. def inferTypes(Adaptation sa){
  142. // Type inference
  143. var untypedElements = genericDeclarationInferenceAlgorithm(sa ,
  144. [// getField
  145. element | {
  146. if (element instanceof SingleParamDeclaration) {
  147. return element.type
  148. } else if (element instanceof Port){
  149. return element.type
  150. } else if (element instanceof SingleVarDeclaration){
  151. return element.type
  152. } else {
  153. throw new Exception("Unexpected element type: " + element)
  154. }
  155. }
  156. ],
  157. [// setField
  158. element, value | {
  159. if (element instanceof SingleParamDeclaration) {
  160. element.type = value as String
  161. } else if (element instanceof Port){
  162. element.type = value as String
  163. } else if (element instanceof SingleVarDeclaration){
  164. element.type = value as String
  165. } else {
  166. throw new Exception("Unexpected element type: " + element)
  167. }
  168. }
  169. ],
  170. [// inferField
  171. element | {
  172. if (element instanceof SingleParamDeclaration) {
  173. return extractTypeFromExpression(element.expr, element.name)
  174. } else if (element instanceof Port){
  175. return getPortType(element)
  176. } else if (element instanceof SingleVarDeclaration){
  177. return extractTypeFromExpression(element.expr, element.name)
  178. } else {
  179. throw new Exception("Unexpected element type: " + element)
  180. }
  181. }
  182. ]
  183. )
  184. if (untypedElements > 0){
  185. Log.println("Error: Could not infer all types. There are " + untypedElements + " untyped elements.")
  186. Log.println(prettyprint_model(sa, "Current File"))
  187. throw new Exception("Could not infer all types. There are " + untypedElements + " untyped elements.")
  188. }
  189. }
  190. def canonicalize(Adaptation sa){
  191. Log.push("Canonicalize")
  192. inferUnits(sa)
  193. inferTypes(sa)
  194. addInPorts(sa)
  195. val inputPort2parameterDeclaration = addInParams(sa)
  196. val externalInputPort2InVarDeclaration = addInVars(sa, inputPort2parameterDeclaration)
  197. addInRules_External2Stored_Assignments(sa, externalInputPort2InVarDeclaration)
  198. val internalPort2ExternalPortBindings = findAllExternalPort2InputPort_Bindings(sa)
  199. addInRules_External2Internal_Assignments(sa, internalPort2ExternalPortBindings)
  200. removeBindings(internalPort2ExternalPortBindings, sa)
  201. if (sa.outports.size==0){
  202. addOutPorts(sa)
  203. }
  204. val outputPort2parameterDeclaration = addOutParams(sa)
  205. val internalOutputPort2OutVarDeclaration = addOutVars(sa, outputPort2parameterDeclaration)
  206. val internalOutputPort2ExternalPortBindings = findAllInternalPort2ExternalOutputPort_Bindings(sa)
  207. //val internalOutputPort2OutVarDeclaration = transitiveStep(internalOutputPort2ExternalPortBindings, internalOutputPort2OutVarDeclaration)
  208. addOutRules_Internal2Stored_Assignments(sa, internalOutputPort2OutVarDeclaration)
  209. addOutRules_Internal2External_Assignments(sa, internalOutputPort2ExternalPortBindings)
  210. removeBindings(internalOutputPort2ExternalPortBindings, sa)
  211. if (sa.control === null){
  212. sa.control = SemanticAdaptationFactory.eINSTANCE.createControlRuleBlock()
  213. sa.control.rule = SemanticAdaptationFactory.eINSTANCE.createCustomControlRule()
  214. createCoSimStepInstructions(sa)
  215. }
  216. createInternalBindingAssignments(sa)
  217. Log.push("Replace port refs in input rules")
  218. for (rule : sa.in.rules){
  219. check(rule.outputfunction instanceof CompositeOutputFunction, "Only CompositeOutputFunction are supported in DataRules.")
  220. replacePortRefsByVarDecl((rule.outputfunction as CompositeOutputFunction).statements, externalInputPort2InVarDeclaration)
  221. }
  222. Log.pop("Replace port refs in input rules")
  223. Log.push("Replace port refs in control rule")
  224. if (sa.control.rule instanceof CustomControlRule){
  225. replacePortRefsByVarDecl((sa.control.rule as CustomControlRule).controlRulestatements,internalOutputPort2OutVarDeclaration)
  226. }
  227. Log.pop("Replace port refs in control rule")
  228. Log.push("Replace port refs in output rule")
  229. for (rule : sa.out.rules){
  230. check(rule.outputfunction instanceof CompositeOutputFunction, "Only CompositeOutputFunction are supported in DataRules.")
  231. replacePortRefsByVarDecl((rule.outputfunction as CompositeOutputFunction).statements, internalOutputPort2OutVarDeclaration)
  232. }
  233. Log.pop("Replace port refs in output rule")
  234. Log.pop("Canonicalize")
  235. }
  236. def replacePortRefsByVarDecl(EList<Statement> statements, HashMap<Port, SingleVarDeclaration> port2VarDecl) {
  237. Log.push("replacePortRefsByVarDecl")
  238. for(statement : statements){
  239. val vars = statement.eAllContents.filter[v | v instanceof Variable]
  240. var Variable v
  241. while (vars.hasNext) {
  242. v = vars.next as Variable
  243. if (port2VarDecl.containsKey(v.ref)){
  244. val port = v.ref as Port
  245. v.owner = null
  246. val varDecl = port2VarDecl.get(v.ref)
  247. v.ref = varDecl
  248. Log.println("Replaced ref to " + port.qualifiedName + " by " + varDecl.name)
  249. } else {
  250. Log.println("Var ref not substituted: " + v.ref)
  251. }
  252. }
  253. }
  254. Log.pop("replacePortRefsByVarDecl")
  255. }
  256. def createInternalBindingAssignments(Adaptation sa) {
  257. Log.push("createInternalBindingAssignments")
  258. val scenario = (sa.inner as InnerFMUDeclarationFull)
  259. for (connection : scenario.connection){
  260. val trgFMU = connection.tgt.port.eContainer as InnerFMU
  261. val ctrlRule = sa.control.rule as CustomControlRule
  262. val doStepIndex = findDoStepStatementIndex(ctrlRule, trgFMU)
  263. if (doStepIndex < 0){
  264. throw new IllegalArgumentException("DoStep instruction for FMU " + trgFMU.name + " not found in control rule block.")
  265. }
  266. if (! existsAssignmentToPort_BeforeIndex(connection.tgt.port, doStepIndex, ctrlRule)){
  267. Log.println("Creating assignment to port " + connection.tgt.port.qualifiedName + " at position " + doStepIndex)
  268. addPortAssignment(ctrlRule.controlRulestatements, connection.tgt.port, connection.src.port, doStepIndex, true)
  269. } else {
  270. Log.println("There is already an assignment to port " + connection.tgt.port.qualifiedName + " before position " + doStepIndex)
  271. }
  272. }
  273. Log.pop("createInternalBindingAssignments")
  274. }
  275. def existsAssignmentToPort_BeforeIndex(Port port, int index, CustomControlRule rule) {
  276. val assignmentsToPort = rule.controlRulestatements.indexed
  277. .filter[s | s.value instanceof Assignment &&
  278. (s.value as Assignment).lvalue.ref == port
  279. ]
  280. check(assignmentsToPort.size <= 1, "Multiple assignments to the same port are not supported yet. Use a loop with a single call.")
  281. return assignmentsToPort.size == 1
  282. }
  283. def findDoStepStatementIndex(CustomControlRule rule, InnerFMU fmu) {
  284. Log.push("findDoStepStatementIndex")
  285. var result = -1
  286. val doStepProcedures = rule.controlRulestatements.indexed.filter[s | s.value instanceof DoStep && (s.value as DoStep).fmu == fmu]
  287. 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.")
  288. if (doStepProcedures.size == 1){
  289. Log.println("Found a doStep procedure for fmu " + fmu.name + " at position " + doStepProcedures.head.key)
  290. result = doStepProcedures.head.key
  291. }
  292. // Warning: this does not support instructions such as:
  293. // var someVar = 10, h = doStep(f), etc...
  294. // Only single declarations are supported, such as:
  295. // var h = doStep(f)
  296. // FIXME: This needs to look into hirarchical statements (like for loops).
  297. val doStepAssignments = rule.controlRulestatements.indexed
  298. .filter[s | s.value instanceof Declaration &&
  299. (s.value as Declaration).declarations.size == 1 &&
  300. (s.value as Declaration).declarations.head instanceof SingleVarDeclaration &&
  301. (s.value as Declaration).declarations.head.expr instanceof DoStepFun &&
  302. ((s.value as Declaration).declarations.head.expr as DoStepFun).fmu == fmu
  303. ]
  304. 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.")
  305. if (doStepAssignments.size == 1){
  306. check(result==-1, "Multiple calls to the doStep function for the same FMU are not supported yet. Use a loop with a single call.")
  307. Log.println("Found a doStep function for fmu " + fmu.name + " at position " + doStepAssignments.head.key)
  308. result = doStepAssignments.head.key
  309. }
  310. Log.pop("findDoStepStatementIndex")
  311. return result
  312. }
  313. def createCoSimStepInstructions(Adaptation sa) {
  314. check((sa.inner as InnerFMUDeclarationFull).fmus.size > 0, "At least one internal FMU is expected...")
  315. if (onlyOneInternalFMU(sa)){
  316. createCosimStepForOneFMU(sa)
  317. } else {
  318. createCosimStepForMultipleFMUs(sa)
  319. }
  320. }
  321. def createCosimStepForOneFMU(Adaptation sa) {
  322. Log.push("createCosimStepForOneFMU")
  323. val fmu = (sa.inner as InnerFMUDeclarationFull).fmus.head
  324. val controlRule = sa.control.rule as CustomControlRule
  325. val returnedStepVar = controlRule.appendDoStep(fmu)
  326. val stepVarSingleton = new LinkedList()
  327. stepVarSingleton.add(returnedStepVar)
  328. controlRule.appendReturnCosimStep(stepVarSingleton)
  329. Log.pop("createCosimStepForOneFMU")
  330. }
  331. def appendReturnCosimStep(CustomControlRule rule, LinkedList<SingleVarDeclaration> stepVariables) {
  332. Log.push("appendReturnCosimStep")
  333. if (stepVariables.size == 0){
  334. throw new Exception("Does not make sense. At least one inner FMU is expected.")
  335. }
  336. var Expression returnExpression = null
  337. if (stepVariables.size == 1){
  338. val varRef = SemanticAdaptationFactory.eINSTANCE.createVariable()
  339. varRef.ref = stepVariables.first
  340. returnExpression = varRef
  341. Log.println("Single inner fmu: return " + stepVariables.first.name)
  342. } else {
  343. Log.println("Creating min(...) expression with the following arguments:")
  344. val minExpression = SemanticAdaptationFactory.eINSTANCE.createMin()
  345. for(varDecl : stepVariables){
  346. val varRef = SemanticAdaptationFactory.eINSTANCE.createVariable()
  347. varRef.ref = varDecl
  348. minExpression.args.add(varRef)
  349. Log.println(varDecl.name)
  350. }
  351. returnExpression = minExpression
  352. }
  353. rule.returnstatement = SemanticAdaptationFactory.eINSTANCE.createReturnStatement()
  354. rule.returnstatement.expr = returnExpression
  355. Log.pop("appendReturnCosimStep")
  356. }
  357. def appendDoStep(CustomControlRule rule, InnerFMU fmu) {
  358. Log.push("appendDoStep")
  359. val t = SemanticAdaptationFactory.eINSTANCE.createCurrentTime()
  360. val H = SemanticAdaptationFactory.eINSTANCE.createStepSize()
  361. val doStep = SemanticAdaptationFactory.eINSTANCE.createDoStepFun()
  362. doStep.t = t
  363. doStep.h = H
  364. doStep.fmu = fmu
  365. val step_var = SemanticAdaptationFactory.eINSTANCE.createSingleVarDeclaration()
  366. step_var.name = "H_" + fmu.name
  367. step_var.expr = doStep
  368. step_var.type = "Real"
  369. val step_decl = SemanticAdaptationFactory.eINSTANCE.createDeclaration()
  370. step_decl.declarations.add(step_var)
  371. rule.controlRulestatements.add(step_decl)
  372. Log.println("Added var " + step_var.name + " := doStep(t, H, " + fmu.name + ")")
  373. Log.pop("appendDoStep")
  374. return step_var
  375. }
  376. def createCosimStepForMultipleFMUs(Adaptation sa) {
  377. Log.push("createCosimStepForMultipleFMUs")
  378. val innerDeclaration = (sa.inner as InnerFMUDeclarationFull)
  379. val controlRule = sa.control.rule as CustomControlRule
  380. val stepVarSingleton = new LinkedList()
  381. for (fmu : innerDeclaration.topologicalSort()){
  382. val returnedStepVar = controlRule.appendDoStep(fmu)
  383. stepVarSingleton.add(returnedStepVar)
  384. }
  385. controlRule.appendReturnCosimStep(stepVarSingleton)
  386. Log.pop("createCosimStepForMultipleFMUs")
  387. }
  388. def topologicalSort(InnerFMUDeclarationFull scenario){
  389. Log.push("topologicalSort")
  390. val DirectedGraph<InnerFMU> inner_fmu_graph = createFMUGraph(scenario)
  391. val result = TopologicalSort.sort(inner_fmu_graph)
  392. Log.println("Sorting: " + result)
  393. Log.pop("topologicalSort")
  394. return result
  395. }
  396. def createFMUGraph(InnerFMUDeclarationFull scenario) {
  397. Log.push("createFMUGraph")
  398. val graph = new FMUGraph()
  399. for (fmu : scenario.fmus){
  400. graph.addNode(fmu)
  401. }
  402. for (connection : scenario.connection){
  403. check(connection.src.port.eContainer instanceof InnerFMU &&
  404. connection.tgt.port.eContainer instanceof InnerFMU, "Weird connection found: " + connection)
  405. if (reactiveMealyFMU(connection.tgt.port.eContainer as InnerFMU)){
  406. graph.addEdge(connection.src.port.eContainer as InnerFMU, connection.tgt.port.eContainer as InnerFMU)
  407. } else {
  408. Log.println("FMU " + (connection.tgt.port.eContainer as InnerFMU).name + " is not reactive mealy, so it has no algebraic dependencies.")
  409. }
  410. }
  411. Log.println(graph.toString())
  412. Log.pop("createFMUGraph")
  413. return graph
  414. }
  415. def reactiveMealyFMU(InnerFMU fmu) {
  416. return fmu.reactiveness == ReactiveOrDelayed.REACTIVE && fmu.machine == MooreOrMealy.MEALY
  417. }
  418. def check(Boolean condition, String msg){
  419. if (! condition){
  420. throw new Exception("Assertion error: " + msg)
  421. }
  422. }
  423. def onlyOneInternalFMU(Adaptation sa) {
  424. if(sa.inner instanceof InnerFMUDeclarationFull){
  425. return (sa.inner as InnerFMUDeclarationFull).fmus.size == 1
  426. } else {
  427. throw new Exception('This kind of internal scenario is not supported yet.')
  428. }
  429. }
  430. def transitiveStep(HashMap<Port, Port> internalOutputPort2ExternalPortBindings, HashMap<Port, SingleVarDeclaration> externalOutputPort2OutVarDeclaration) {
  431. Log.push("transitiveStep")
  432. val internalOutputPort2OutVarDeclaration = new HashMap<Port, SingleVarDeclaration>()
  433. for(internalOutputPort : internalOutputPort2ExternalPortBindings.keySet){
  434. val externalOutputPort = internalOutputPort2ExternalPortBindings.get(internalOutputPort)
  435. if (externalOutputPort2OutVarDeclaration.containsKey(externalOutputPort)){
  436. val outVar = externalOutputPort2OutVarDeclaration.get(externalOutputPort)
  437. Log.println("Found binding: " + internalOutputPort.qualifiedName + "->" + externalOutputPort.qualifiedName + " to be stored in " + outVar.name)
  438. internalOutputPort2OutVarDeclaration.put(internalOutputPort, outVar)
  439. }
  440. }
  441. Log.pop("transitiveStep")
  442. return internalOutputPort2OutVarDeclaration
  443. }
  444. def String qualifiedName(Port port){
  445. if (port.eContainer instanceof FMU){
  446. return (port.eContainer as FMU).name + "." + port.name
  447. }
  448. return port.name
  449. }
  450. def removeBindings(HashMap<Port, Port> internalPort2ExternalPortBindings, Adaptation sa) {
  451. Log.push("removeBindings")
  452. for (internalPort : internalPort2ExternalPortBindings.keySet){
  453. val externalPort = internalPort2ExternalPortBindings.get(internalPort)
  454. Log.println("Removing binding " + externalPort.qualifiedName + "->" + internalPort.qualifiedName)
  455. externalPort.targetdependency = null
  456. Log.println("Removing binding " + externalPort.qualifiedName + "<-" + internalPort.qualifiedName)
  457. externalPort.sourcedependency = null
  458. }
  459. Log.pop("removeBindings")
  460. }
  461. def findAllExternalPort2InputPort_Bindings(Adaptation sa) {
  462. Log.push("findAllExternalPort2InputPort_Bindings")
  463. val internalPort2ExternalPortBindings = new HashMap<Port, Port>()
  464. for (port : getAllInnerFMUInputPortDeclarations(sa)){
  465. Log.println("Checking if port " + port.qualifiedName + " is bound to an external port.")
  466. val externalPort = findExternalPortByTargetDependency(sa.inports, port)
  467. if (externalPort !== null){
  468. Log.println("Port " + port.qualifiedName + " is bound to an external port: " + externalPort.qualifiedName)
  469. internalPort2ExternalPortBindings.put(port, externalPort)
  470. } else {
  471. Log.println("Port " + port.qualifiedName + " is not bound to an external port.")
  472. }
  473. }
  474. Log.pop("findAllExternalPort2InputPort_Bindings")
  475. return internalPort2ExternalPortBindings
  476. }
  477. def findAllInternalPort2ExternalOutputPort_Bindings(Adaptation sa) {
  478. Log.push("findAllInternalPort2ExternalOutputPort_Bindings")
  479. val internalPort2ExternalPortBindings = new HashMap<Port, Port>()
  480. for (port : getAllInnerFMUOutputPortDeclarations(sa)){
  481. Log.println("Checking if port " + port.qualifiedName + " is bound to an external port.")
  482. val externalPort = findExternalPortBySourceDependency(sa.outports, port)
  483. if (externalPort !== null){
  484. Log.println("Port " + externalPort.qualifiedName + " is bound to an internal port: " + port.qualifiedName
  485. )
  486. internalPort2ExternalPortBindings.put(port, externalPort)
  487. } else {
  488. Log.println("Port " + port.qualifiedName + " is not bound to an external port.")
  489. }
  490. }
  491. Log.pop("findAllInternalPort2ExternalOutputPort_Bindings")
  492. return internalPort2ExternalPortBindings
  493. }
  494. def createExternalPortNameFromInternalPort(String parentFMUName, String internalPortName) {
  495. //return parentFMUName + "__" + internalPortName // Violates transparency
  496. return internalPortName
  497. }
  498. def addInRules_External2Internal_Assignments(Adaptation sa, HashMap<Port, Port> internalPort2ExternalPort) {
  499. Log.push("addInRules_External2Internal_Assignments")
  500. val dataRule = getOrPrependTrueRule(sa.in.rules)
  501. for(internalPort : internalPort2ExternalPort.keySet){
  502. val externalPort = internalPort2ExternalPort.get(internalPort)
  503. check((dataRule.outputfunction instanceof CompositeOutputFunction), "Only CompositeOutputFunction is supported for now.")
  504. val outFunction = dataRule.outputfunction as CompositeOutputFunction
  505. addPortAssignment(outFunction.statements, internalPort, externalPort, 0, true)
  506. }
  507. Log.pop("addInRules_External2Internal_Assignments")
  508. }
  509. def addOutRules_Internal2External_Assignments(Adaptation sa, HashMap<Port, Port> internalPort2ExternalPort){
  510. Log.push("addOutRules_Internal2External_Assignments")
  511. val dataRule = getOrPrependTrueRule(sa.out.rules)
  512. for(internalPort : internalPort2ExternalPort.keySet){
  513. val externalPort = internalPort2ExternalPort.get(internalPort)
  514. check((dataRule.outputfunction instanceof CompositeOutputFunction), "Only CompositeOutputFunction is supported for now.")
  515. val outFunction = dataRule.outputfunction as CompositeOutputFunction
  516. addPortAssignment(outFunction.statements, externalPort, internalPort, 0, true)
  517. }
  518. Log.pop("addOutRules_Internal2External_Assignments")
  519. }
  520. def addPortAssignment(List<Statement> statements, Port toPort, Port fromPort, int position, boolean convertUnits) {
  521. Log.push("addPortAssignment")
  522. val assignment = SemanticAdaptationFactory.eINSTANCE.createAssignment()
  523. assignment.lvalue = SemanticAdaptationFactory.eINSTANCE.createVariable()
  524. assignment.lvalue.owner = toPort.eContainer as FMU
  525. assignment.lvalue.ref = toPort
  526. val varRef = SemanticAdaptationFactory.eINSTANCE.createVariable()
  527. varRef.owner = fromPort.eContainer as FMU
  528. varRef.ref = fromPort
  529. if (convertUnits && compatibleUnits(toPort.unity, fromPort.unity) && !unitsEqual(toPort.unity, fromPort.unity)){
  530. Log.println("Converting units " + fromPort.unity + " to " + toPort.unity)
  531. assignment.expr = getConversionExpression(toPort.unity, fromPort.unity, varRef)
  532. } else {
  533. assignment.expr = varRef
  534. Log.println("Assignment " + toPort.qualifiedName + " := " + fromPort.qualifiedName + " created.")
  535. }
  536. statements.add(position, assignment)
  537. Log.pop("addPortAssignment")
  538. }
  539. def getConversionExpression(Unity toUnits, Unity fromUnit, Variable varFrom) {
  540. check(toUnits instanceof AtomicUnity && fromUnit instanceof AtomicUnity, "Conversion between units is only supported for AtomicUnits.")
  541. var toAtomic = toUnits as AtomicUnity
  542. var fromAtomic = fromUnit as AtomicUnity
  543. check(fromAtomic.name == "cm" && toAtomic.name == "m", "Conversion only possible between cm and m... Not very usefull :)")
  544. var division = SemanticAdaptationFactory.eINSTANCE.createDiv()
  545. division.left = varFrom
  546. var hundred = SemanticAdaptationFactory.eINSTANCE.createRealLiteral()
  547. hundred.value=100f
  548. division.right = hundred
  549. return division
  550. }
  551. def dispatch boolean unitsEqual(DivideUnity u1, DivideUnity u2) {
  552. return unitsEqual(u1.left, u2.left) && unitsEqual(u1.right, u2.right)
  553. }
  554. def dispatch boolean unitsEqual(Void u1, Void u2) {
  555. return true
  556. }
  557. def dispatch boolean unitsEqual(MultiplyUnity u1, MultiplyUnity u2) {
  558. return unitsEqual(u1.left, u2.left) && unitsEqual(u1.right, u2.right)
  559. }
  560. def dispatch boolean unitsEqual(AtomicUnity u1, AtomicUnity u2) {
  561. return u1.name == u2.name && u1.power == u2.power
  562. }
  563. def compatibleUnits(Unity u1, Unity u2) {
  564. if ((u1 === null && u2===null) ||
  565. (u1 !== null && u2!==null)
  566. ){
  567. // TODO What makes two units compatible?
  568. return true
  569. } else {
  570. return false
  571. }
  572. }
  573. def addInRules_External2Stored_Assignments(Adaptation sa, HashMap<Port, SingleVarDeclaration> inputPort2InVarDeclaration) {
  574. Log.push("addInRules_External2Stored_Assignments")
  575. if (sa.in === null){
  576. sa.in = SemanticAdaptationFactory.eINSTANCE.createInRulesBlock()
  577. }
  578. addRules_Port2Stored_Assignments(sa.in.rules, inputPort2InVarDeclaration)
  579. Log.pop("addInRules_External2Stored_Assignments")
  580. }
  581. def addOutRules_Internal2Stored_Assignments(Adaptation sa, HashMap<Port, SingleVarDeclaration> internalOutputPort2OutVarDeclaration) {
  582. Log.push("addOutRules_Internal2Stored_Assignments")
  583. if (sa.out === null){
  584. sa.out = SemanticAdaptationFactory.eINSTANCE.createOutRulesBlock()
  585. }
  586. addRules_Port2Stored_Assignments(sa.out.rules, internalOutputPort2OutVarDeclaration)
  587. Log.pop("addOutRules_Internal2Stored_Assignments")
  588. }
  589. def addRules_Port2Stored_Assignments(List<DataRule> rules, HashMap<Port, SingleVarDeclaration> port2VarDeclaration) {
  590. Log.push("addRules_External2Stored_Assignments")
  591. val dataRule = getOrPrependTrueRule(rules)
  592. if (dataRule.statetransitionfunction.expression !== null){
  593. throw new Exception("Expressions in rules are not supported yet.")
  594. // This and the one below are asily solved with a syntactic sugar substitution.
  595. }
  596. if (dataRule.statetransitionfunction.assignment !== null){
  597. throw new Exception("Assignment in rules are not supported yet.")
  598. }
  599. for(port : port2VarDeclaration.keySet){
  600. val storedVarDecl = port2VarDeclaration.get(port)
  601. addAssignmentToStoredVar(dataRule.statetransitionfunction.statements, port, storedVarDecl)
  602. }
  603. Log.pop("addRules_External2Stored_Assignments")
  604. }
  605. def addAssignmentToStoredVar(List<Statement> statements, Port internalPort, SingleVarDeclaration storedVarDecl) {
  606. Log.push("addAssignmentToStoredVar")
  607. val assignment = SemanticAdaptationFactory.eINSTANCE.createAssignment()
  608. assignment.lvalue = SemanticAdaptationFactory.eINSTANCE.createVariable()
  609. assignment.lvalue.ref = storedVarDecl
  610. assignment.expr = SemanticAdaptationFactory.eINSTANCE.createVariable()
  611. (assignment.expr as Variable).owner = internalPort.eContainer as FMU
  612. (assignment.expr as Variable).ref = internalPort
  613. statements.add(0, assignment)
  614. Log.println("Assignment " + storedVarDecl.name + " := " + internalPort.qualifiedName + " created.")
  615. Log.pop("addAssignmentToStoredVar")
  616. }
  617. def getOrPrependTrueRule(List<DataRule> rules) {
  618. var DataRule rule = null
  619. if (rules.size == 0 || !isTrueRule(rules.head)){
  620. Log.println("No existing rule found with true condition. Creating one.")
  621. val trueRule = SemanticAdaptationFactory.eINSTANCE.createDataRule()
  622. trueRule.condition = SemanticAdaptationFactory.eINSTANCE.createRuleCondition()
  623. val trueExpr = SemanticAdaptationFactory.eINSTANCE.createBoolLiteral()
  624. trueExpr.value = "true"
  625. trueRule.condition.condition = trueExpr
  626. trueRule.statetransitionfunction = SemanticAdaptationFactory.eINSTANCE.createStateTransitionFunction()
  627. trueRule.outputfunction = SemanticAdaptationFactory.eINSTANCE.createCompositeOutputFunction()
  628. rules.add(0, trueRule)
  629. rule = trueRule
  630. } else {
  631. Log.println("Existing rule with true condition found.")
  632. rule = rules.head
  633. }
  634. return rule
  635. }
  636. def isTrueRule(DataRule rule){
  637. if (rule.condition.condition instanceof BoolLiteral){
  638. return (rule.condition.condition as BoolLiteral).value == "true"
  639. }
  640. return false
  641. }
  642. def addInVars(Adaptation sa, Map<Port, SingleParamDeclaration> inputPort2parameterDeclaration){
  643. Log.push("addInVars")
  644. if (sa.in === null){
  645. sa.in = SemanticAdaptationFactory.eINSTANCE.createInRulesBlock()
  646. }
  647. val inputPort2InVarDeclaration = addStorageVars(sa.in.globalInVars, inputPort2parameterDeclaration)
  648. Log.pop("addInVars")
  649. return inputPort2InVarDeclaration
  650. }
  651. def addOutVars(Adaptation sa, Map<Port, SingleParamDeclaration> outputPort2parameterDeclaration){
  652. Log.push("addOutVars")
  653. if (sa.out === null){
  654. sa.out = SemanticAdaptationFactory.eINSTANCE.createOutRulesBlock()
  655. }
  656. val outputPort2InVarDeclaration = addStorageVars(sa.out.globalOutVars, outputPort2parameterDeclaration)
  657. Log.pop("addOutVars")
  658. return outputPort2InVarDeclaration
  659. }
  660. def addStorageVars(List<Declaration> varDeclarations, Map<Port, SingleParamDeclaration> port2parameterDeclaration){
  661. Log.push("addStorageVars")
  662. var port2VarDeclaration = new HashMap<Port, SingleVarDeclaration>()
  663. for(port : port2parameterDeclaration.keySet){
  664. Log.println("Processing port " + port.qualifiedName)
  665. val paramDecl = port2parameterDeclaration.get(port)
  666. val varDeclarationName = getStorageVarDeclarationName(port)
  667. if (!varDeclarationExists(varDeclarationName, varDeclarations) ){
  668. Log.println("Creating new variable declaration " + varDeclarationName)
  669. val varDeclaration = addNewVarDeclaration(port, paramDecl, varDeclarations)
  670. port2VarDeclaration.put(port, varDeclaration)
  671. } else {
  672. Log.println("Input variable declaration " + varDeclarationName + " already exists.")
  673. }
  674. }
  675. Log.pop("addStorageVars")
  676. return port2VarDeclaration
  677. }
  678. def addNewVarDeclaration(Port externalInputPort, SingleParamDeclaration paramDecl, List<Declaration> varDeclarations) {
  679. /*
  680. if (sa.in === null){
  681. sa.in = SemanticAdaptationFactory.eINSTANCE.createInRulesBlock()
  682. }
  683. */
  684. if (varDeclarations.size == 0){
  685. varDeclarations.add(SemanticAdaptationFactory.eINSTANCE.createDeclaration())
  686. }
  687. val newSingleVarDecl = SemanticAdaptationFactory.eINSTANCE.createSingleVarDeclaration()
  688. newSingleVarDecl.name = getStorageVarDeclarationName(externalInputPort)
  689. newSingleVarDecl.type = externalInputPort.type
  690. val initValue = SemanticAdaptationFactory.eINSTANCE.createVariable()
  691. initValue.ref = paramDecl
  692. newSingleVarDecl.expr = initValue
  693. varDeclarations.head.declarations.add(newSingleVarDecl)
  694. Log.println("New variable declaration created: " + newSingleVarDecl.name + " := " + paramDecl.name)
  695. return newSingleVarDecl
  696. }
  697. def varDeclarationExists(String invarName, List<Declaration> varDeclarations) {
  698. for (declarations : varDeclarations){ // sa.in.globalInVars
  699. for (decl : declarations.declarations){
  700. if (decl.name == invarName){
  701. return true
  702. }
  703. }
  704. }
  705. return false
  706. }
  707. def getStorageVarDeclarationName(Port externalInputPort) {
  708. return "stored__" + externalInputPort.name;
  709. }
  710. def genericDeclarationInferenceAlgorithm(Adaptation sa,
  711. (EObject)=>Object getField,
  712. (EObject, Object)=>void setField,
  713. (EObject)=>Object inferField
  714. ){
  715. Log.push("Running generic inference algorithm...")
  716. /*
  717. * Dumbest (and simplest) algorithm for this is a fixed point computation:
  718. * 1. Look for every var/port declaration
  719. * 2. If that var has a XXX already, nothing else to be done.
  720. * 3. If that var has no XXX declared, then
  721. * 3.1 If var/port has an initial value or connection, then
  722. * 3.1.1 If the initial_value/connection has a XXX declared, then var gets that XXX.
  723. * 3.1.2 Otherwise, nothing else to be done.
  724. * 3.2 If var/port has no initial value or connection then this either is a missing feature, or an error.
  725. * 3.3 If something has changed, go to 1. Otherwise, end.
  726. *
  727. * An extra set of instructions is there to push the element field information using connections and bindings.
  728. */
  729. var fixedPoint = false
  730. var unfieldedElementsCounter = 0
  731. while (! fixedPoint){
  732. fixedPoint = true
  733. unfieldedElementsCounter = 0
  734. Log.println("Inferring parameter fields...")
  735. for (paramDeclarations : sa.params) {
  736. for (paramDeclaration : paramDeclarations.declarations) {
  737. Log.println("Computing field for param " + paramDeclaration.name)
  738. if(getField.apply(paramDeclaration) !== null){
  739. Log.println("Already has been inferred: " + getField.apply(paramDeclaration))
  740. } else {
  741. Log.println("Has not been inferred yet.")
  742. if (tryInferAndAssignField(paramDeclaration, getField, setField, inferField)){
  743. fixedPoint = false
  744. } else {
  745. unfieldedElementsCounter++
  746. }
  747. }
  748. }
  749. }
  750. if(sa.inner !== null){
  751. if(sa.inner instanceof InnerFMUDeclarationFull){
  752. var innerFMUFull = sa.inner as InnerFMUDeclarationFull
  753. for(fmu : innerFMUFull.fmus){
  754. Log.println("Inferring port fields of FMU " + fmu.name)
  755. for (port : EcoreUtil2.getAllContentsOfType(fmu, Port)) {
  756. if(getField.apply(port) !== null){
  757. Log.println("Already has a field: " + getField.apply(port))
  758. } else {
  759. if (tryInferAndAssignField(port, getField, setField, inferField)){
  760. fixedPoint = false
  761. } else {
  762. unfieldedElementsCounter++
  763. }
  764. }
  765. }
  766. }
  767. if (innerFMUFull.connection.size > 0){
  768. Log.println("Inferring port fields using internal scenario bindings.")
  769. for (binding : innerFMUFull.connection){
  770. if (getField.apply(binding.src.port) !== null && getField.apply(binding.tgt.port) !== null){
  771. Log.println("Both ports have fields already.")
  772. } else {
  773. var inferredFieldAttempt = inferPortFieldViaConnection(binding, getField, setField, inferField)
  774. if (inferredFieldAttempt !== null){
  775. if (getField.apply(binding.src.port) === null){
  776. setField.apply(binding.src.port, inferredFieldAttempt)
  777. } else if (getField.apply(binding.tgt.port) === null){
  778. setField.apply(binding.tgt.port, inferredFieldAttempt)
  779. }
  780. fixedPoint = false
  781. unfieldedElementsCounter--
  782. Log.println("Got new field: " + inferredFieldAttempt)
  783. } else {
  784. Log.println("Cannot infer field from binding now.")
  785. }
  786. }
  787. }
  788. }
  789. } else {
  790. throw new Exception("Field inference only supported for InnerFMUDeclarationFull.")
  791. }
  792. }
  793. Log.println("Inferring external port fields...")
  794. var externalPorts = new LinkedList(sa.inports)
  795. externalPorts.addAll(sa.outports)
  796. for (port : externalPorts) {
  797. if (getField.apply(port) !== null){
  798. Log.println("Already has a field: " + getField.apply(port))
  799. if (pushPortField(port, getField, setField, inferField)){
  800. fixedPoint = false
  801. unfieldedElementsCounter--
  802. }
  803. } else {
  804. if (tryInferAndAssignField(port, getField, setField, inferField)){
  805. fixedPoint = false
  806. } else {
  807. unfieldedElementsCounter++
  808. }
  809. }
  810. }
  811. Log.println("Inferring all other declaration fields...")
  812. for (varDeclaration : EcoreUtil2.getAllContentsOfType(sa, SingleVarDeclaration)) {
  813. Log.println("Computing field for declaration " + varDeclaration.name)
  814. if(getField.apply(varDeclaration) !== null){
  815. Log.println("Already has a field: " + getField.apply(varDeclaration))
  816. } else {
  817. if (tryInferAndAssignField(varDeclaration, getField, setField, inferField)){
  818. fixedPoint = false
  819. } else {
  820. unfieldedElementsCounter++
  821. }
  822. }
  823. }
  824. Log.println("Ended iteration with unfielded elements remaining: " + unfieldedElementsCounter)
  825. } // while (! fixedPoint)
  826. Log.pop("Running generic inference algorithm... DONE")
  827. return unfieldedElementsCounter
  828. }
  829. def tryInferAndAssignField(EObject element,
  830. (EObject)=>Object getField,
  831. (EObject, Object)=>void setField,
  832. (EObject)=>Object inferField) {
  833. var inferredFieldAttempt = inferField.apply(element)
  834. if (inferredFieldAttempt !== null){
  835. setField.apply(element, inferredFieldAttempt)
  836. Log.println("Got new field: " + inferredFieldAttempt)
  837. return true
  838. } else {
  839. Log.println("Cannot infer field now.")
  840. return false
  841. }
  842. }
  843. def extractTypeFromExpression(Expression expression, String declarationName){
  844. if (expression instanceof IntLiteral){
  845. return "Integer"
  846. } else if (expression instanceof RealLiteral){
  847. return "Real"
  848. } else if (expression instanceof BoolLiteral){
  849. return "Bool"
  850. } else if (expression instanceof StringLiteral){
  851. return "String"
  852. } else if (expression instanceof Variable){
  853. var varRef = expression
  854. if (varRef.ref instanceof Port){
  855. var decl = varRef.ref as Port
  856. if (decl.type !== null){
  857. return decl.type
  858. }
  859. } else if(varRef.ref instanceof SingleParamDeclaration){
  860. var decl = varRef.ref as SingleParamDeclaration
  861. if (decl.type !== null){
  862. return decl.type
  863. }
  864. } else if(varRef.ref instanceof SingleVarDeclaration){
  865. var decl = varRef.ref as SingleVarDeclaration
  866. if (decl.type !== null){
  867. return decl.type
  868. }
  869. } else if(varRef.ref instanceof DeclaredParameter){
  870. throw new Exception("Type cannot be inferred for references to DeclaredParameter (for now). Please specify the explicit type of declaration " + declarationName)
  871. } else {
  872. throw new Exception("Unexpected kind of Variable expression found.")
  873. }
  874. } else if(expression instanceof BuiltinFunction){
  875. if (expression instanceof IsSet || expression instanceof Close){
  876. return "Bool"
  877. } else {
  878. return "Real"
  879. }
  880. } else if (expression instanceof CurrentTime) {
  881. return "Real"
  882. }
  883. else {
  884. 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.")
  885. }
  886. return null
  887. }
  888. def inferPortFieldViaConnection(Connection binding,
  889. (EObject)=>Object getField,
  890. (EObject, Object)=>void setField,
  891. (EObject)=>Object inferField
  892. ){
  893. var Object resultField = null
  894. if (getField.apply(binding.src.port) !== null && getField.apply(binding.tgt.port) !== null){
  895. throw new Exception("Wrong way of using this function. It assumes type is not inferred yet.")
  896. } else if (getField.apply(binding.src.port) !== null){
  897. resultField = getField.apply(binding.src.port)
  898. Log.println("Target port "+ binding.tgt.port.qualifiedName +" got new type: " + resultField)
  899. } else if (getField.apply(binding.tgt.port) !== null){
  900. resultField = getField.apply(binding.tgt.port)
  901. Log.println("Target port "+ binding.src.port.qualifiedName +" got new type: " + resultField)
  902. }
  903. return resultField
  904. }
  905. def pushPortField(Port port,
  906. (EObject)=>Object getField,
  907. (EObject, Object)=>void setField,
  908. (EObject)=>Object inferField){
  909. var fieldInferred = false
  910. Log.println("Pushing field of port " + port.qualifiedName + " to its bindings.")
  911. if(getField.apply(port) === null){
  912. Log.println("Has no field to be pushed.")
  913. throw new Exception("Wrong way of using this function. It assumes field is already inferred.")
  914. } else {
  915. Log.println("Pushing field: " + getField.apply(port))
  916. if(port.sourcedependency !== null){
  917. Log.println("Has a source dependency: " + port.sourcedependency.port.qualifiedName)
  918. if(getField.apply(port.sourcedependency.port) === null){
  919. setField.apply(port.sourcedependency.port, getField.apply(port))
  920. Log.println("Port " + port.sourcedependency.port.qualifiedName + " got new type: " + getField.apply(port.sourcedependency.port))
  921. fieldInferred = true
  922. } else {
  923. Log.println("Source port already has field.")
  924. }
  925. } else {
  926. Log.println("Has no source dependency.")
  927. }
  928. if (port.targetdependency !== null) {
  929. Log.println("Has a target dependency: " + port.targetdependency.port.qualifiedName)
  930. if(getField.apply(port.targetdependency.port) === null){
  931. Log.println("Dependency has no field yet.")
  932. setField.apply(port.targetdependency.port, getField.apply(port))
  933. Log.println("Port " + port.targetdependency.port.qualifiedName + " got new type: " + getField.apply(port.targetdependency.port))
  934. fieldInferred = true
  935. } else {
  936. Log.println("Target port already has field.")
  937. }
  938. } else {
  939. Log.println("Has no target dependency.")
  940. }
  941. }
  942. return fieldInferred
  943. }
  944. def getPortUnit(Port port){
  945. var unitInferred = false
  946. Log.println("Computing unit for port " + port.qualifiedName)
  947. var Unity returnUnit = null
  948. if(port.unity !== null){
  949. throw new Exception("Wrong way of using this function. It assumes unit is not inferred yet.")
  950. } else {
  951. Log.println("Has no unit.")
  952. Log.println("Attempting to infer unit from bindings.")
  953. if(port.sourcedependency !== null){
  954. Log.println("Has a source dependency: " + port.sourcedependency.port.qualifiedName)
  955. if(port.sourcedependency.port.unity === null){
  956. Log.println("Dependency has no unit yet.")
  957. } else {
  958. returnUnit = port.sourcedependency.port.unity
  959. Log.println("Got new unit: " + returnUnit)
  960. unitInferred = true
  961. }
  962. } else {
  963. Log.println("Has no source dependency.")
  964. }
  965. if (port.targetdependency !== null && !unitInferred) {
  966. Log.println("Has a target dependency: " + port.targetdependency.port.qualifiedName)
  967. if(port.targetdependency.port.unity === null){
  968. Log.println("Dependency has no unit yet.")
  969. } else {
  970. returnUnit = port.targetdependency.port.unity
  971. Log.println("Got new unit: " + returnUnit)
  972. unitInferred = true
  973. }
  974. } else {
  975. Log.println("Has no target dependency, or unit has already been inferred from source dependency.")
  976. }
  977. }
  978. return returnUnit
  979. }
  980. def getPortType(Port port){
  981. var typeInferred = false
  982. Log.println("Computing type for port " + port.qualifiedName)
  983. var String returnType = null
  984. if(port.type !== null){
  985. throw new Exception("Wrong way of using this function. It assumes type is not inferred yet.")
  986. } else {
  987. Log.println("Has no type.")
  988. Log.println("Attempting to infer type from units.")
  989. if (port.unity !== null){
  990. returnType = "Real"
  991. Log.println("Got new type: " + returnType)
  992. typeInferred = true
  993. } else {
  994. Log.println("Attempting to infer type from bindings.")
  995. if(port.sourcedependency !== null){
  996. Log.println("Has a source dependency: " + port.sourcedependency.port.qualifiedName)
  997. if(port.sourcedependency.port.type === null){
  998. Log.println("Dependency has no type yet.")
  999. } else {
  1000. returnType = port.sourcedependency.port.type
  1001. Log.println("Got new type: " + returnType)
  1002. typeInferred = true
  1003. }
  1004. } else {
  1005. Log.println("Has no source dependency.")
  1006. }
  1007. if (port.targetdependency !== null && !typeInferred) {
  1008. Log.println("Has a target dependency: " + port.targetdependency.port.qualifiedName)
  1009. if(port.targetdependency.port.type === null){
  1010. //println("Port object: " + port.targetdependency.port)
  1011. Log.println("Dependency has no type yet.")
  1012. } else {
  1013. returnType = port.targetdependency.port.type
  1014. Log.println("Got new type: " + returnType)
  1015. typeInferred = true
  1016. }
  1017. } else {
  1018. Log.println("Has no target dependency, or type has already been inferred from source dependency.")
  1019. }
  1020. }
  1021. }
  1022. return returnType
  1023. }
  1024. def addInPorts(Adaptation sa) {
  1025. Log.push("Adding input ports...")
  1026. for (port : getAllInnerFMUInputPortDeclarations(sa)){
  1027. var parentFMU = port.eContainer as InnerFMU
  1028. Log.println("Checking if port " + port.qualifiedName + " has incoming connections"
  1029. )
  1030. if (! hasConnection(port, sa, true)){
  1031. Log.println("Port " + port.qualifiedName + " has no incoming connections.")
  1032. val externalPortName = createExternalPortNameFromInternalPort(parentFMU.name, port.name)
  1033. if (findExternalPortByName(sa, externalPortName) === null){
  1034. var newExternalPort = createExternalInputPortDeclarationFromInnerPort(port, parentFMU, sa)
  1035. Log.println("External port " + newExternalPort.qualifiedName + " created.")
  1036. newExternalPort.bindExternalInputPortTo(parentFMU, port)
  1037. Log.println("External port " + newExternalPort.qualifiedName + " bound to port " + port.qualifiedName)
  1038. } else {
  1039. Log.println("Error: External port " + externalPortName + " already declared.")
  1040. throw new Exception("Error: External port " + externalPortName + " already declared. Please rename it, or connect it to an internal fmu port, to avoid clashes.")
  1041. }
  1042. } else {
  1043. Log.println("Port " + port.qualifiedName + " has an incoming connection.")
  1044. }
  1045. }
  1046. Log.pop("Adding input ports... DONE")
  1047. }
  1048. def bindExternalInputPortTo(Port externalInputPort, InnerFMU internalPortParent, Port internalPort) {
  1049. externalInputPort.targetdependency = SemanticAdaptationFactory.eINSTANCE.createSpecifiedPort()
  1050. externalInputPort.targetdependency.owner = internalPortParent
  1051. externalInputPort.targetdependency.port = internalPort
  1052. }
  1053. def bindExternalOutputPortTo(Port externalOutputPort, InnerFMU internalPortParent, Port internalPort) {
  1054. externalOutputPort.sourcedependency = SemanticAdaptationFactory.eINSTANCE.createSpecifiedPort()
  1055. externalOutputPort.sourcedependency.owner = internalPortParent
  1056. externalOutputPort.sourcedependency.port = internalPort
  1057. }
  1058. def createExternalInputPortDeclarationFromInnerPort(Port port, FMU parent, Adaptation sa) {
  1059. var externalInputPort = createExternalPortDeclarationFromInnerPort(port, parent)
  1060. sa.inports.add(externalInputPort)
  1061. return externalInputPort
  1062. }
  1063. def createExternalOutputPortDeclarationFromInnerPort(Port port, FMU parent, Adaptation sa) {
  1064. var externalOutputPort = createExternalPortDeclarationFromInnerPort(port, parent)
  1065. sa.outports.add(externalOutputPort)
  1066. return externalOutputPort
  1067. }
  1068. def createExternalPortDeclarationFromInnerPort(Port port, FMU parent) {
  1069. var externalInputPort = SemanticAdaptationFactory.eINSTANCE.createPort()
  1070. externalInputPort.name = createExternalPortNameFromInternalPort(parent.name, port.name)
  1071. externalInputPort.type = port.type
  1072. externalInputPort.unity = EcoreUtil2.copy(port.unity)
  1073. return externalInputPort
  1074. }
  1075. def findExternalPortByName(Adaptation adaptation, String name) {
  1076. for (externalInputPort : adaptation.inports){
  1077. if (externalInputPort.name == name){
  1078. return externalInputPort
  1079. }
  1080. }
  1081. return null
  1082. }
  1083. def findExternalPortByTargetDependency(List<Port> ports, Port targetDependency) {
  1084. for (externalInputPort : ports){
  1085. if (externalInputPort.targetdependency !== null && externalInputPort.targetdependency.port == targetDependency){
  1086. return externalInputPort
  1087. }
  1088. }
  1089. return null
  1090. }
  1091. def findExternalPortBySourceDependency(List<Port> ports, Port sourceDependency) {
  1092. for (externalInputPort : ports){
  1093. if (externalInputPort.sourcedependency !== null && externalInputPort.sourcedependency.port == sourceDependency){
  1094. return externalInputPort
  1095. }
  1096. }
  1097. return null
  1098. }
  1099. def hasConnection(Port port, Adaptation adaptation, Boolean checkForIncomming) {
  1100. var result = false
  1101. if ( (checkForIncomming && port.sourcedependency !== null) ||
  1102. (! checkForIncomming && port.targetdependency !== null)
  1103. ){
  1104. result = true
  1105. } else {
  1106. if (port.eContainer instanceof InnerFMU){
  1107. var innerScenarioDeclaration = EcoreUtil2.getContainerOfType(port, InnerFMUDeclaration)
  1108. if (innerScenarioDeclaration instanceof InnerFMUDeclarationFull){
  1109. var innerScenarioWithCoupling = innerScenarioDeclaration as InnerFMUDeclarationFull
  1110. if (innerScenarioWithCoupling.connection.size > 0){
  1111. for (connection : innerScenarioWithCoupling.connection ){
  1112. if ( (checkForIncomming && connection.tgt.port == port)){
  1113. Log.println("Port " + port.qualifiedName + " has an incoming connection from internal port " + connection.src.port.qualifiedName)
  1114. result = true
  1115. } else if (!checkForIncomming && connection.src.port == port) {
  1116. Log.println("Port " + port.qualifiedName + " has an outgoing connection to internal port " + connection.tgt.port.qualifiedName)
  1117. result = true
  1118. }
  1119. }
  1120. }
  1121. }
  1122. for (externalInputPort : adaptation.inports.filter[p | (checkForIncomming && p.targetdependency !== null) || (!checkForIncomming && p.sourcedependency !== null) ]){
  1123. if (checkForIncomming && externalInputPort.targetdependency.port == port){
  1124. Log.println("Port " + port.qualifiedName + " has an incoming connection from external port " + externalInputPort.qualifiedName)
  1125. result = true
  1126. } else if ( !checkForIncomming && externalInputPort.sourcedependency.port == port){
  1127. Log.println("Port " + port.qualifiedName + " has an outgoing connection to external port " + externalInputPort.qualifiedName)
  1128. result = true
  1129. }
  1130. }
  1131. }
  1132. }
  1133. return result
  1134. }
  1135. def getAllInnerFMUInputPortDeclarations(Adaptation sa){
  1136. return mapAllInnerFMUs(sa, [fmu | fmu.inports]);
  1137. }
  1138. def getAllInnerFMUOutputPortDeclarations(Adaptation sa){
  1139. return mapAllInnerFMUs(sa, [fmu | fmu.outports]);
  1140. }
  1141. def <T> List<T> mapAllInnerFMUs(Adaptation sa, (InnerFMU)=>List<T> map){
  1142. var result = new LinkedList()
  1143. if(sa.inner !== null){
  1144. if(sa.inner instanceof InnerFMUDeclarationFull){
  1145. var innerFMUFull = sa.inner as InnerFMUDeclarationFull
  1146. for(fmu : innerFMUFull.fmus){
  1147. result.addAll(map.apply(fmu))
  1148. }
  1149. } else {
  1150. throw new Exception("Only support for InnerFMUDeclarationFull.")
  1151. }
  1152. }
  1153. return result;
  1154. }
  1155. def addInParams(Adaptation sa) {
  1156. Log.push("Adding input parameters...")
  1157. val result = addParamForPortDeclarations(sa, sa.inports)
  1158. Log.pop("Adding input parameters... DONE")
  1159. return result
  1160. }
  1161. def addOutParams(Adaptation sa) {
  1162. Log.push("Adding output parameters...")
  1163. val result = addParamForPortDeclarations(sa, getAllInnerFMUOutputPortDeclarations(sa))
  1164. Log.pop("Adding output parameters... DONE")
  1165. return result
  1166. }
  1167. def addParamForPortDeclarations(Adaptation sa, List<Port> ports){
  1168. Log.push("addParamForPortDeclarations")
  1169. val PARAM_PREFIX = "INIT_"
  1170. var port2parameterDeclaration = new HashMap<Port, SingleParamDeclaration>(ports.size)
  1171. for (externalPortDecl : ports) {
  1172. Log.println("Generating parameter for port " + externalPortDecl.qualifiedName)
  1173. var paramname = PARAM_PREFIX + externalPortDecl.name.toUpperCase()
  1174. if (paramAlreadyDeclared(paramname, sa)){
  1175. Log.println("Parameter " + paramname + " already declared for port " + externalPortDecl.qualifiedName)
  1176. } else {
  1177. Log.println("Declaring new parameter " + paramname + " for port " + externalPortDecl.qualifiedName)
  1178. var paramDeclaration = addNewParamDeclaration(paramname, externalPortDecl, sa)
  1179. port2parameterDeclaration.put(externalPortDecl, paramDeclaration)
  1180. }
  1181. }
  1182. Log.pop("addParamForPortDeclarations")
  1183. return port2parameterDeclaration
  1184. }
  1185. def addNewParamDeclaration(String name, Port fromPort, Adaptation sa) {
  1186. var factory = SemanticAdaptationFactory.eINSTANCE
  1187. var paramDeclaration = factory.createSingleParamDeclaration()
  1188. paramDeclaration.name = name
  1189. paramDeclaration.type = fromPort.type
  1190. paramDeclaration.expr = getDefaultTypeExpression(paramDeclaration.type)
  1191. if (sa.params.size == 0){
  1192. sa.params.add(factory.createParamDeclarations())
  1193. }
  1194. sa.params.head.declarations.add(paramDeclaration)
  1195. return paramDeclaration
  1196. }
  1197. def getDefaultTypeExpression(String type) {
  1198. switch (type) {
  1199. case "Integer": {
  1200. val result = SemanticAdaptationFactory.eINSTANCE.createIntLiteral
  1201. result.value = 0
  1202. return result
  1203. }
  1204. case "Real": {
  1205. val result = SemanticAdaptationFactory.eINSTANCE.createRealLiteral
  1206. result.value = 0.0f
  1207. return result
  1208. }
  1209. case "Bool": {
  1210. val result = SemanticAdaptationFactory.eINSTANCE.createBoolLiteral
  1211. result.value = "false"
  1212. return result
  1213. }
  1214. case "String": {
  1215. val result = SemanticAdaptationFactory.eINSTANCE.createStringLiteral
  1216. result.value = " "
  1217. return result
  1218. }
  1219. default: {
  1220. throw new Exception("Unexpected type.")
  1221. }
  1222. }
  1223. }
  1224. def paramAlreadyDeclared(String name, Adaptation sa) {
  1225. for(paramDeclarations : sa.params){
  1226. for(paramDeclaration : paramDeclarations.declarations){
  1227. if(paramDeclaration.name == name){
  1228. return true
  1229. }
  1230. }
  1231. }
  1232. return false
  1233. }
  1234. def addOutPorts(Adaptation sa) {
  1235. Log.push("Adding output ports...")
  1236. for (port : getAllInnerFMUOutputPortDeclarations(sa)){
  1237. var parentFMU = port.eContainer as InnerFMU
  1238. Log.println("Checking if port " + port.qualifiedName + " has outgoing connections")
  1239. if (! hasConnection(port, sa, false)){
  1240. Log.println("Port " + port.qualifiedName + " has no outgoing connections.")
  1241. val externalPortName = createExternalPortNameFromInternalPort(parentFMU.name, port.name)
  1242. if (findExternalPortByName(sa, externalPortName) === null){
  1243. var newExternalPort = createExternalOutputPortDeclarationFromInnerPort(port, parentFMU, sa)
  1244. Log.println("External port " + newExternalPort.qualifiedName + " created.")
  1245. newExternalPort.bindExternalOutputPortTo(parentFMU, port)
  1246. Log.println("External port " + newExternalPort.qualifiedName + " bound to port " + port.qualifiedName)
  1247. } else {
  1248. Log.println("Error: External port " + externalPortName + " already declared.")
  1249. throw new Exception("Error: External port " + externalPortName + " already declared. Please rename it, or connect it to an internal fmu port, to avoid clashes.")
  1250. }
  1251. } else {
  1252. Log.println("Port " + port.qualifiedName + " has an incoming connection.")
  1253. }
  1254. }
  1255. Log.pop("Adding output ports... DONE")
  1256. }
  1257. }