| /***************************************************************************** |
| * Copyright (c) 2019 CEA LIST. |
| * |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * CEA LIST - Initial API and implementation |
| * |
| *****************************************************************************/ |
| package org.eclipse.papyrus.ease; |
| |
| |
| |
| |
| import java.util.ArrayList; |
| import java.util.Date; |
| import java.util.GregorianCalendar; |
| import java.util.List; |
| import java.util.UUID; |
| |
| import javax.xml.datatype.DatatypeConfigurationException; |
| import javax.xml.datatype.DatatypeFactory; |
| import javax.xml.datatype.XMLGregorianCalendar; |
| |
| import org.eclipse.papyrus.moka.fmi.fmiprofile.CS_FMU; |
| import org.eclipse.papyrus.moka.fmi.fmiprofile.FlowDirection; |
| import org.eclipse.papyrus.moka.fmi.fmiprofile.Port; |
| import org.eclipse.papyrus.moka.fmi.fmiprofile.ScalarVariable; |
| import org.eclipse.papyrus.moka.fmi.modeldescription.BooleanType; |
| import org.eclipse.papyrus.moka.fmi.modeldescription.CausalityType; |
| import org.eclipse.papyrus.moka.fmi.modeldescription.CoSimulationType; |
| import org.eclipse.papyrus.moka.fmi.modeldescription.Fmi2ScalarVariable; |
| import org.eclipse.papyrus.moka.fmi.modeldescription.Fmi2VariableDependency; |
| import org.eclipse.papyrus.moka.fmi.modeldescription.FmiFactory; |
| import org.eclipse.papyrus.moka.fmi.modeldescription.FmiModelDescriptionType; |
| import org.eclipse.papyrus.moka.fmi.modeldescription.InitialType; |
| import org.eclipse.papyrus.moka.fmi.modeldescription.IntegerType; |
| import org.eclipse.papyrus.moka.fmi.modeldescription.ModelStructureType; |
| import org.eclipse.papyrus.moka.fmi.modeldescription.ModelVariablesType; |
| import org.eclipse.papyrus.moka.fmi.modeldescription.RealType; |
| import org.eclipse.papyrus.moka.fmi.modeldescription.StringType; |
| import org.eclipse.papyrus.moka.fmi.modeldescription.UnknownType1; |
| import org.eclipse.papyrus.moka.fmi.profile.util.FMIProfileUtil; |
| import org.eclipse.papyrus.moka.utils.UMLPrimitiveTypesUtils; |
| import org.eclipse.uml2.uml.Class; |
| import org.eclipse.uml2.uml.Property; |
| |
| |
| |
| public class ModelDescriptionGenerator { |
| |
| |
| |
| public static void setDefaultValuesForMokaFMU(Class umlClass) { |
| |
| CS_FMU csFMU = FMIProfileUtil.getCSFMU(umlClass); |
| |
| |
| |
| csFMU.setCanHandleVariableCommunicationStepSize(true); |
| |
| csFMU.setCanInterpolateInputs(false); |
| |
| csFMU.setCanRunAsynchronuously(false); |
| |
| csFMU.setMaxOutputDerivativeOrder(0); |
| |
| csFMU.setNeedsExecutionTool(false); |
| |
| csFMU.setFmiVersion("2.0"); |
| |
| csFMU.setGenerationTool("Moka Exporter"); |
| |
| |
| |
| } |
| |
| |
| |
| public static FmiModelDescriptionType getModelDescription(Class umlClass, String modelIdentifier) { |
| |
| CS_FMU csFMU = FMIProfileUtil.getCSFMU(umlClass); |
| |
| |
| |
| List<Integer> knownValueRefs = new ArrayList<>(); |
| |
| if (csFMU != null) { |
| |
| FmiModelDescriptionType result = FmiFactory.eINSTANCE.createFmiModelDescriptionType(); |
| |
| result.setGenerationTool("Moka FMU exporter"); |
| |
| result.setFmiVersion("2.0"); |
| |
| |
| |
| GregorianCalendar date = new GregorianCalendar(); |
| |
| date.setTime(new Date()); |
| |
| XMLGregorianCalendar xmlDate; |
| |
| try { |
| |
| xmlDate = DatatypeFactory.newInstance().newXMLGregorianCalendar(date); |
| |
| result.setGenerationDateAndTime(xmlDate); |
| |
| } catch (DatatypeConfigurationException e) { |
| |
| e.printStackTrace(); |
| |
| } |
| |
| |
| |
| result.setModelName(umlClass.getLabel()); |
| |
| result.setGuid(UUID.randomUUID().toString()); |
| |
| |
| |
| CoSimulationType cosim = FmiFactory.eINSTANCE.createCoSimulationType(); |
| |
| result.getCoSimulation().add(cosim); |
| |
| // cosim.setCanGetAndSetFMUstate(false); |
| // |
| // cosim.setCanHandleVariableCommunicationStepSize(true); |
| // |
| // cosim.setCanBeInstantiatedOnlyOncePerProcess(true); |
| // |
| // cosim.setCanInterpolateInputs(false); |
| // |
| // cosim.setCanNotUseMemoryManagementFunctions(true); |
| // |
| // cosim.setCanSerializeFMUstate(false); |
| // |
| // cosim.setCanRunAsynchronuously(false); |
| // |
| // cosim.setNeedsExecutionTool(false); |
| // |
| // cosim.setProvidesDirectionalDerivative(false); |
| // |
| // cosim.setMaxOutputDerivativeOrder(0); |
| |
| |
| |
| if (modelIdentifier == null) { |
| |
| modelIdentifier = umlClass.getName(); |
| |
| } |
| |
| cosim.setModelIdentifier(modelIdentifier); |
| |
| |
| |
| List<ScalarVariable> umlVariables = FMIProfileUtil.collectScalarVariables(umlClass); |
| |
| List<Port> outputUMLVariables = new ArrayList<Port>(); |
| |
| if (!umlVariables.isEmpty()) { |
| |
| ModelVariablesType modelVariables = FmiFactory.eINSTANCE.createModelVariablesType(); |
| |
| result.setModelVariables(modelVariables); |
| |
| for (ScalarVariable umlVariable : umlVariables) { |
| |
| modelVariables.getScalarVariable().add(createFMIScalarVariable(umlVariable, knownValueRefs)); |
| |
| if (umlVariable instanceof Port && ((Port) umlVariable).getDirection().equals(FlowDirection.OUT)) { |
| |
| outputUMLVariables.add((Port) umlVariable); |
| |
| } |
| |
| } |
| |
| |
| |
| } |
| |
| |
| |
| if (!outputUMLVariables.isEmpty()) { |
| |
| |
| |
| ModelStructureType modelStructure = FmiFactory.eINSTANCE.createModelStructureType(); |
| |
| result.setModelStructure(modelStructure); |
| |
| Fmi2VariableDependency outputs = FmiFactory.eINSTANCE.createFmi2VariableDependency(); |
| |
| modelStructure.setOutputs(outputs); |
| |
| for (Port outputPort : outputUMLVariables) { |
| |
| outputs.getUnknown().add(createUnknown(outputPort, umlVariables)); |
| |
| } |
| |
| |
| |
| } |
| |
| |
| |
| return result; |
| |
| } else { |
| |
| return null; |
| |
| } |
| |
| |
| |
| } |
| |
| |
| |
| private static UnknownType1 createUnknown(Port outputPort, List<ScalarVariable> umlVariables) { |
| |
| UnknownType1 result = FmiFactory.eINSTANCE.createUnknownType1(); |
| |
| result.setIndex(umlVariables.indexOf(outputPort) + 1); |
| |
| return result; |
| |
| } |
| |
| |
| |
| private static Fmi2ScalarVariable createFMIScalarVariable(ScalarVariable umlVariable, List<Integer> knownValueRefs) { |
| |
| Fmi2ScalarVariable result = FmiFactory.eINSTANCE.createFmi2ScalarVariable(); |
| |
| // //Property baseProperty = umlVariable.getBase_Property(); |
| // |
| // if (baseProperty == null && umlVariable instanceof Port) { |
| // |
| // baseProperty = ((Port) umlVariable).getBase_Port(); |
| // |
| // } |
| // |
| // result.setName(baseProperty.getName()); |
| // |
| // |
| // result.setValueReference(getValueReference(umlVariable, knownValueRefs)); |
| // |
| // |
| // |
| // if (!baseProperty.getOwnedComments().isEmpty()) { |
| // |
| // String description = ""; |
| // |
| // for (Comment comment : baseProperty.getOwnedComments()) { |
| // |
| // if (comment.getBody() != null) { |
| // |
| // description += comment.getBody() + "\n"; |
| // |
| // } |
| // |
| // } |
| // |
| // result.setDescription(description); |
| // |
| // } |
| // |
| // |
| // |
| // result.setVariability(VariabilityType.DISCRETE); |
| // |
| // |
| // |
| // CausalityType causality = computeCausality(umlVariable); |
| // |
| // result.setCausality(causality); |
| // |
| // updateTypeAndInitial(result, baseProperty, causality); |
| |
| |
| |
| return result; |
| |
| } |
| |
| |
| |
| // private static long getValueReference(ScalarVariable umlVariable, List<Integer> knownValueRefs) { |
| // int valueReference; |
| // if (umlVariable.eIsSet(FMIProfilePackage.eINSTANCE.getScalarVariable_ValueReference())) { |
| // valueReference = umlVariable.getValueReference(); |
| // |
| // }else { |
| // valueReference = knownValueRefs.isEmpty()? 0: Collections.max(knownValueRefs) +1; |
| // } |
| // while(knownValueRefs.contains(valueReference)) { |
| // valueReference++; |
| // } |
| // |
| // knownValueRefs.add(valueReference); |
| // |
| // return valueReference; |
| // } |
| |
| |
| |
| private static void updateTypeAndInitial(Fmi2ScalarVariable result, Property baseProperty, |
| |
| CausalityType causality) { |
| |
| if (baseProperty.getType().equals(UMLPrimitiveTypesUtils.getReal(baseProperty))) { |
| |
| RealType fmiReal = FmiFactory.eINSTANCE.createRealType(); |
| |
| result.setReal(fmiReal); |
| |
| if (causality == CausalityType.INPUT) { |
| |
| result.setInitial(InitialType.APPROX); |
| |
| } else { |
| |
| result.setInitial(InitialType.EXACT); |
| |
| } |
| |
| String defaultValue = baseProperty.getDefault(); |
| |
| if (defaultValue != null) { |
| |
| fmiReal.setStart(Double.parseDouble(defaultValue)); |
| |
| } |
| |
| |
| |
| } else if (baseProperty.getType().equals(UMLPrimitiveTypesUtils.getInteger(baseProperty))) { |
| |
| IntegerType fmiInteger = FmiFactory.eINSTANCE.createIntegerType(); |
| |
| result.setInteger(fmiInteger); |
| |
| if (causality == CausalityType.INPUT) { |
| |
| result.setInitial(InitialType.APPROX); |
| |
| } else { |
| |
| result.setInitial(InitialType.EXACT); |
| |
| } |
| |
| String defaultValue = baseProperty.getDefault(); |
| |
| if (defaultValue != null) { |
| |
| fmiInteger.setStart(Integer.decode(defaultValue)); |
| |
| } |
| |
| |
| |
| } else if (baseProperty.getType().equals(UMLPrimitiveTypesUtils.getBoolean(baseProperty))) { |
| |
| BooleanType fmiBoolean = FmiFactory.eINSTANCE.createBooleanType(); |
| |
| result.setBoolean(fmiBoolean); |
| |
| if (causality == CausalityType.INPUT) { |
| |
| result.setInitial(InitialType.APPROX); |
| |
| } else { |
| |
| result.setInitial(InitialType.EXACT); |
| |
| } |
| |
| String defaultValue = baseProperty.getDefault(); |
| |
| if (defaultValue != null) { |
| |
| fmiBoolean.setStart(Boolean.getBoolean(defaultValue)); |
| |
| } |
| |
| |
| |
| } else { |
| |
| StringType fmiString = FmiFactory.eINSTANCE.createStringType(); |
| |
| result.setString(fmiString); |
| |
| if (causality == CausalityType.INPUT) { |
| |
| result.setInitial(InitialType.APPROX); |
| |
| } else { |
| |
| result.setInitial(InitialType.EXACT); |
| |
| } |
| |
| String defaultValue = baseProperty.getDefault(); |
| |
| if (defaultValue != null) { |
| |
| fmiString.setStart(defaultValue); |
| |
| } |
| |
| } |
| |
| |
| |
| } |
| |
| |
| |
| // public static CausalityType computeCausality(ScalarVariable umlVariable) { |
| // |
| // if (umlVariable instanceof Local) { |
| // |
| // return CausalityType.LOCAL; |
| // |
| // } else if (umlVariable instanceof CalculatedParameter) { |
| // |
| // return CausalityType.CALCULATED_PARAMETER; |
| // |
| // } else if (umlVariable instanceof Port) { |
| // |
| // FlowDirection direction = ((Port) umlVariable).getDirection(); |
| // |
| // if (direction.equals(FlowDirection.IN)) { |
| // |
| // return CausalityType.INPUT; |
| // |
| // } else { |
| // |
| // return CausalityType.OUTPUT; |
| // |
| // } |
| // |
| // } else if (umlVariable instanceof Parameter) { |
| // |
| // return CausalityType.PARAMETER; |
| // |
| // } else if (umlVariable instanceof Independent) { |
| // |
| // return CausalityType.INDEPENDENT; |
| // |
| // } |
| // |
| // |
| // |
| // return null; |
| // |
| // } |
| |
| } |
| |