Skip to content

Commit

Permalink
Simplify --exposeLocalIOs and conform to Modelica standard (OpenModel…
Browse files Browse the repository at this point in the history
…ica#10599) (OpenModelica#12303)

Add top-level variables for unconnected local IOs.
Only NFFlatten.mo and NFConnectEquations.mo are extended. Untouch backend as well as NFFlatModel.mo and NFVariable.mo.
  • Loading branch information
rfranke committed Apr 25, 2024
1 parent 89eb367 commit c0911cd
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 92 deletions.
13 changes: 2 additions & 11 deletions OMCompiler/Compiler/BackEnd/BackendDAECreate.mo
Expand Up @@ -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();
Expand Down Expand Up @@ -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!
Expand Down
4 changes: 2 additions & 2 deletions OMCompiler/Compiler/BackEnd/BackendVariable.mo
Expand Up @@ -2027,15 +2027,15 @@ 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);
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);
Expand Down
2 changes: 1 addition & 1 deletion OMCompiler/Compiler/NFFrontEnd/NFConnectEquations.mo
Expand Up @@ -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
Expand Down
5 changes: 1 addition & 4 deletions OMCompiler/Compiler/NFFrontEnd/NFFlatModel.mo
Expand Up @@ -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");
Expand Down
70 changes: 54 additions & 16 deletions OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo
Expand Up @@ -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;
Expand Down Expand Up @@ -2183,13 +2183,15 @@ function resolveConnections
input FlattenSettings settings;
protected
Connections conns;
list<Equation> conn_eql, ec_eql;
list<Equation> conn_eql, ec_eql, tlio_eql;
list<Variable> tlio_vars;
ConnectionSets.Sets csets;
array<list<Connector>> csets_array;
CardinalityTable.Table ctable;
Connections.BrokenEdges broken = {};
UnorderedMap<ComponentRef, Variable> vars;
UnorderedSet<ComponentRef> connectedLocalIOs;
Integer exposeLocalIOs;
algorithm
vars := UnorderedMap.new<Variable>(ComponentRef.hash, ComponentRef.isEqual,
listLength(flatModel.variables));
Expand Down Expand Up @@ -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.
Expand All @@ -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<ComponentRef> connectedIOs;
function generateTopLevelIOs
"generate top-level inputs and outputs for public unconnected local input and output connectors"
input UnorderedMap<ComponentRef, Variable> variables;
input UnorderedSet<ComponentRef> connectedLocalIOs;
input Integer exposeLocalIOs;
output list<Variable> tlio_vars;
output list<Equation> 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;
Expand Down
12 changes: 1 addition & 11 deletions OMCompiler/Compiler/NFFrontEnd/NFVariable.mo
Expand Up @@ -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;
Expand All @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions OMCompiler/Compiler/Util/Flags.mo
Expand Up @@ -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."
Expand Down

0 comments on commit c0911cd

Please sign in to comment.