diff --git a/OMCompiler/Compiler/BackEnd/BackendDAECreate.mo b/OMCompiler/Compiler/BackEnd/BackendDAECreate.mo index 9e17d85bf34..5b52d46f5e5 100644 --- a/OMCompiler/Compiler/BackEnd/BackendDAECreate.mo +++ b/OMCompiler/Compiler/BackEnd/BackendDAECreate.mo @@ -1590,12 +1590,7 @@ algorithm else algorithm /* Consider toplevel inputs as known unless they are protected. Ticket #5591 */ - /* Consider all inputs known with flag --nonStdExposeLocalIOs > 0 unless they are protected */ - if Flags.getConfigInt(Flags.EXPOSE_LOCAL_IOS) == 0 then - false := DAEUtil.topLevelInput(inComponentRef, inVarDirection, inConnectorType, protection); - else - false := DAEUtil.varDirectionEqual(inVarDirection, DAE.INPUT()) and not DAEUtil.boolVarVisibility(protection); - end if; + false := DAEUtil.topLevelInput(inComponentRef, inVarDirection, inConnectorType, protection); then match (inVarKind, inType) case (DAE.VARIABLE(), DAE.T_BOOL()) then BackendDAE.DISCRETE(); @@ -1623,11 +1618,7 @@ algorithm case DAE.CONST() then BackendDAE.CONST(); case DAE.VARIABLE() equation - if Flags.getConfigInt(Flags.EXPOSE_LOCAL_IOS) == 0 then - true = DAEUtil.topLevelInput(componentRef, varDirection, connectorType, visibility); - else - true = DAEUtil.varDirectionEqual(varDirection, DAE.INPUT()) and not DAEUtil.boolVarVisibility(visibility); - end if; + true = DAEUtil.topLevelInput(componentRef, varDirection, connectorType, visibility); then BackendDAE.VARIABLE(); // adrpo: topLevelInput might fail! diff --git a/OMCompiler/Compiler/BackEnd/BackendVariable.mo b/OMCompiler/Compiler/BackEnd/BackendVariable.mo index 376a2c68ee8..c64f0c97eaf 100644 --- a/OMCompiler/Compiler/BackEnd/BackendVariable.mo +++ b/OMCompiler/Compiler/BackEnd/BackendVariable.mo @@ -2027,7 +2027,7 @@ end getVarKindForVar; public function isVarOnTopLevelAndOutput "has the DAE.VarDirection = OUTPUT Don't check for top level here as this is done by NFConvertDAE.makeDAEVar. - Otherwise the list of model variables may contradict with model structure, e.g. with --nonStdExposeLocalIOs." + Otherwise the list of model variables may contradict with model structure." input BackendDAE.Var inVar; //output Boolean outBoolean = DAEUtil.topLevelOutput(inVar.varName, inVar.varDirection, inVar.connectorType); output Boolean outBoolean = isOutputVar(inVar); @@ -2035,7 +2035,7 @@ end isVarOnTopLevelAndOutput; public function isVarOnTopLevelAndInput "has the DAE.VarDirection = INPUT Don't check for top level here as this is done by NFConvertDAE.makeDAEVar. - Otherwise the list of model variables may contradict with model structure, e.g. with --nonStdExposeLocalIOs." + Otherwise the list of model variables may contradict with model structure." input BackendDAE.Var inVar; //output Boolean outBoolean = DAEUtil.topLevelInput(inVar.varName, inVar.varDirection, inVar.connectorType); output Boolean outBoolean = isInput(inVar); diff --git a/OMCompiler/Compiler/NFFrontEnd/NFConnectEquations.mo b/OMCompiler/Compiler/NFFrontEnd/NFConnectEquations.mo index 50022988055..af579223055 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFConnectEquations.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFConnectEquations.mo @@ -212,7 +212,7 @@ algorithm if Connector.variability(c1) > Variability.PARAMETER then equations := list(makeEqualityEquation(c1.name, c1.source, c2.name, c2.source) for c2 in listRest(elements)); - // collect inputs and outputs that are inside in connections if --nonStdExposeLocalIOs > 0 + // collect inputs and outputs that are inside in connections if --exposeLocalIOs > 0 // strip array indices so that the variables will be found later if Flags.getConfigInt(Flags.EXPOSE_LOCAL_IOS) > 0 then for c in elements loop diff --git a/OMCompiler/Compiler/NFFrontEnd/NFFlatModel.mo b/OMCompiler/Compiler/NFFrontEnd/NFFlatModel.mo index 2c1c850eb47..a57b37e356b 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFFlatModel.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFFlatModel.mo @@ -1045,16 +1045,13 @@ public function removeNonTopLevelDirections input output FlatModel flatModel; - protected - Integer expose_local_ios; algorithm // Keep the declared directions if --useLocalDirection=true has been set. if Flags.getConfigBool(Flags.USE_LOCAL_DIRECTION) then return; end if; - expose_local_ios := Flags.getConfigInt(Flags.EXPOSE_LOCAL_IOS); - flatModel.variables := list(Variable.removeNonTopLevelDirection(v, expose_local_ios) for v in flatModel.variables); + flatModel.variables := list(Variable.removeNonTopLevelDirection(v) for v in flatModel.variables); end removeNonTopLevelDirections; annotation(__OpenModelica_Interface="frontend"); diff --git a/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo b/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo index 9ec2a72fe6d..9a79dbac52e 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo @@ -79,7 +79,7 @@ import Face = NFConnector.Face; import System; import ComplexType = NFComplexType; import NFInstNode.CachedData; -import NFPrefixes.{Direction, Variability, Visibility, Purity, Parallelism}; +import NFPrefixes.{ConnectorType, Direction, Variability, Visibility, Purity, Parallelism}; import Variable = NFVariable; import ElementSource; import Ceval = NFCeval; @@ -2183,13 +2183,15 @@ function resolveConnections input FlattenSettings settings; protected Connections conns; - list conn_eql, ec_eql; + list conn_eql, ec_eql, tlio_eql; + list tlio_vars; ConnectionSets.Sets csets; array> csets_array; CardinalityTable.Table ctable; Connections.BrokenEdges broken = {}; UnorderedMap vars; UnorderedSet connectedLocalIOs; + Integer exposeLocalIOs; algorithm vars := UnorderedMap.new(ComponentRef.hash, ComponentRef.isEqual, listLength(flatModel.variables)); @@ -2240,9 +2242,12 @@ algorithm // add the equations to the flat model flatModel.equations := listAppend(conn_eql, flatModel.equations); - // remove input and output prefixes from local IOs that are determined through connect equations - if Flags.getConfigInt(Flags.EXPOSE_LOCAL_IOS) > 0 then - flatModel.variables := list(stripInputOutputForConnected(v, connectedLocalIOs) for v in flatModel.variables); + // add top-level IOs for unconnected local IOs + exposeLocalIOs := Flags.getConfigInt(Flags.EXPOSE_LOCAL_IOS); + if exposeLocalIOs > 0 then + (tlio_vars, tlio_eql) := generateTopLevelIOs(vars, connectedLocalIOs, exposeLocalIOs); + flatModel.variables := List.append_reverse(flatModel.variables, tlio_vars); + flatModel.equations := List.append_reverse(flatModel.equations, tlio_eql); end if; // Evaluate any connection operators if they're used. @@ -2253,18 +2258,51 @@ algorithm execStat(getInstanceName()); end resolveConnections; -function stripInputOutputForConnected - "remove input and output prefixes if variable appears in connectedIOs" - input output Variable v; - input UnorderedSet connectedIOs; +function generateTopLevelIOs + "generate top-level inputs and outputs for public unconnected local input and output connectors" + input UnorderedMap variables; + input UnorderedSet connectedLocalIOs; + input Integer exposeLocalIOs; + output list tlio_vars; + output list tlio_eql; protected - Attributes attributes = v.attributes; -algorithm - if UnorderedSet.contains(v.name, connectedIOs) then - attributes.direction := Direction.NONE; - v.attributes := attributes; - end if; -end stripInputOutputForConnected; + Attributes attributes; + Variable tlio_var; + ComponentRef cref; + String name; + InstNode tlio_node; + Integer level; +algorithm + tlio_vars := {}; + tlio_eql := {}; + for variable in UnorderedMap.valueList(variables) loop + level := ComponentRef.depth(variable.name) - 1; + attributes := variable.attributes; + if 0 < level and level <= exposeLocalIOs and + variable.visibility == Visibility.PUBLIC and + attributes.connectorType <> ConnectorType.NON_CONNECTOR and + (attributes.direction == Direction.INPUT or attributes.direction == Direction.OUTPUT) and + not UnorderedSet.contains(variable.name, connectedLocalIOs) + then + tlio_var := variable; // same attributes like start, unit + tlio_var.name := ComponentRef.combineSubscripts(tlio_var.name); + tlio_var.binding := UNBOUND(); // value is defined with tlio_eql + // find new name in global scope, using underscore instead of dot + cref := tlio_var.name; + name := stringDelimitList(ComponentRef.toString_impl(cref, {}), "_"); + while UnorderedMap.contains(tlio_var.name, variables) loop + tlio_node := InstNode.NAME_NODE(name); + tlio_var.name := match cref case ComponentRef.CREF() then + ComponentRef.CREF(tlio_node, cref.subscripts, cref.ty, cref.origin, ComponentRef.EMPTY()); + end match; + name := name + "_" "append underscore until name is unique"; + end while; + tlio_vars := tlio_var :: tlio_vars; + tlio_eql := Equation.makeCrefEquality(variable.name, tlio_var.name, + InstNode.EMPTY_NODE(), ElementSource.createElementSource(variable.info)) :: tlio_eql; + end if; + end for; +end generateTopLevelIOs; function evaluateConnectionOperators input output FlatModel flatModel; diff --git a/OMCompiler/Compiler/NFFrontEnd/NFVariable.mo b/OMCompiler/Compiler/NFFrontEnd/NFVariable.mo index ac7a43dfec2..e76392d56cc 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFVariable.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFVariable.mo @@ -417,11 +417,8 @@ public function removeNonTopLevelDirection "Removes input/output prefixes from a variable that's not a top-level component, a component in a top-level connector, or a component in a - top-level input component. exposeLocalIOs can be used to keep the direction - for variables at lower levels as well, where 0 means top-level, 1 the level - below that, and so on." + top-level input component." input output Variable var; - input Integer exposeLocalIOs; protected ComponentRef rest_name; InstNode node; @@ -431,13 +428,6 @@ public return; end if; - if exposeLocalIOs > 0 and - var.attributes.connectorType <> ConnectorType.NON_CONNECTOR and - var.visibility == Visibility.PUBLIC and - ComponentRef.depth(var.name) < exposeLocalIOs then - return; - end if; - rest_name := ComponentRef.rest(var.name); while not ComponentRef.isEmpty(rest_name) loop node := ComponentRef.node(rest_name); diff --git a/OMCompiler/Compiler/Util/Flags.mo b/OMCompiler/Compiler/Util/Flags.mo index 7366219d1bb..d77ca9bb0eb 100644 --- a/OMCompiler/Compiler/Util/Flags.mo +++ b/OMCompiler/Compiler/Util/Flags.mo @@ -1444,11 +1444,11 @@ constant ConfigFlag FRONTEND_INLINE = CONFIG_FLAG(151, "frontendInline", NONE(), EXTERNAL(), BOOL_FLAG(false), NONE(), Gettext.gettext("Enables inlining of functions in the frontend.")); -constant ConfigFlag EXPOSE_LOCAL_IOS = CONFIG_FLAG(152, "nonStdExposeLocalIOs", +constant ConfigFlag EXPOSE_LOCAL_IOS = CONFIG_FLAG(152, "exposeLocalIOs", NONE(), EXTERNAL(), INT_FLAG(0), NONE(), - Gettext.gettext("Keeps input/output prefixes for unconnected input/output connectors at requested levels, provided they are public, " + + Gettext.gettext("Introduces top-level inputs/outputs for unconnected input/output connectors at requested levels, provided they are public, " + "0 meaning top-level (standard Modelica), 1 inputs/outputs of top-level components, >1 going deeper. " + - "This flag is particularly useful for FMI export. It extends the Modelica standard when exposing local inputs.")); + "This flag is particularly useful for FMI export.")); function getFlags "Loads the flags with getGlobalRoot. Assumes flags have been loaded." diff --git a/testsuite/openmodelica/cppruntime/fmu/modelExchange/2.0/exposeLocalIOs.mos b/testsuite/openmodelica/cppruntime/fmu/modelExchange/2.0/exposeLocalIOs.mos index e4fd2d2c955..a04a4a9b8a8 100644 --- a/testsuite/openmodelica/cppruntime/fmu/modelExchange/2.0/exposeLocalIOs.mos +++ b/testsuite/openmodelica/cppruntime/fmu/modelExchange/2.0/exposeLocalIOs.mos @@ -4,7 +4,7 @@ // teardown_command: rm -f *LocalIOs.System* modelDescription.tmp.xml setCommandLineOptions("--simCodeTarget=Cpp"); -setCommandLineOptions("--nonStdExposeLocalIOs=10"); getErrorString(); +setCommandLineOptions("--exposeLocalIOs=1"); getErrorString(); loadString(" package LocalIOs @@ -45,14 +45,20 @@ algorithm y := 0.5*u; end f; +model Medium + RealInput p \"unconnected IO at level 2\"; +end Medium; + model Component PhysicalConnector c; input Real modifiedInput annotation(Dialog(enable=true)); output Real simpleOutput = signaling.y; RealOutput measurement; + Medium m; protected Signaling signaling(u1 = 1); equation + m.p = 1; signaling.u2 = 2; signaling.u = 3:4; c.f = f(c.p) + modifiedInput + signaling.y; @@ -63,7 +69,7 @@ block Signaling RealInput u1; RealInput u2; RealInput[2] u; - RealOutput y; + RealOutput y \"unconnected IO at level 0\"; equation y = u1 + u2 + sum(u); end Signaling; @@ -72,7 +78,10 @@ model System Source source(use_u_in = true); Component component(modifiedInput = 1); Signaling signaling; + Real component_measurement = 0 \"name already in use\"; + RealOutput y; equation + y = time; connect(source.c, component.c); connect(source.yf, signaling.u1); connect(source.y, signaling.u); @@ -120,15 +129,15 @@ readFile("modelDescription.tmp.xml"); // // // -// +// // // // -// +// description=\"unconnected IO at level 2\" +// initial=\"exact\"> +// // // // // // +// description=\"name already in use\" +// initial=\"exact\"> // // // // @@ -155,107 +164,168 @@ readFile("modelDescription.tmp.xml"); // // // -// +// // // // // // // // // // // // +// +// +// +// +// +// +// +// +// +// +// +// // // -// +// // // // -// +// // // // -// +// +// +// +// +// // // // -// +// // // // -// +// // // // -// +// // +// +// +// +// +// +// +// +// // // -// +// // // // -// +// // // // -// +// +// +// +// +// // // // -// +// // // // -// +// +// +// +// +// // // // -// -// -// +// +// +// +// // // -// -// -// -// +// +// +// +// +// // // //