Add CIF to CIF transformation to generate an interface of a model
Context
A model, say a plant model, can have an input variable that models a value from the environment. Something then needs to provide the value of that variable, namely the environment. If you for instance generate PLC code, then the PLC can provide the input value. If you simulate the model, you can import the plant model in the simulation model, and add an SVG input mapping with updates to assign the input variable based on clicks on the SVG image.
But, there are also cases where you want to model the environment in a CIF model. You for instance want to model the behavior of the input variable yourself, using an algebraic variable, a continuous variable, etc. This is an approach we use regularly. It has been around for years.
So, let's say we have a simulation model, where we make an input variable of another model (like a plant model) concrete. Then typically you also want to use part of the state of that other model (the plant model) in the simulation model. You may for instance want to use the state of certain actuators for SVG output mappings, and so on. You get a situation where you want to define part of the plant model and make it concrete, but you also want to access the concrete part of the plant model.
So, how to make the concrete part of the plant available in the simulation model? You can't import the plant model, because then you have both the abstract input variable and the concrete algebraic/continuous/... variable.
What you can do, and this is what we've done until now, is to copy the relevant skeleton/interface of the plant to the simulation model. For instance, you copy an automaton from the plant to the simulation model, replace the automaton by a group, its locations by input variables, etc. Then you can use that state information in the simulation model. And you can merge the plant and simulation models, which both have input variables that the other makes concrete. So far, so good.
Problem
Problems arise when the models become more complex. You have to copy large parts of the plant to the simulation model and abstract it to the skeleton/interface. And when you change the plant, you have to replace or update the skeletons/interfaces. This is tedious work, and become inconsistent.
So, the question is: how to make this easier.
Solution of RWS
RWS has made a Python script to do this job: turn a plant into an interface that can be imported in the simulation model. It is quite ad-hoc. If for instance the word 'plant' occurs on a line, it is turned into a group. But, what if 'plant' occurs in a string, a comment, etc. It is not very robust.
Solution in CIF (proposed addition to CIF to be contributed for this issue)
The solution would be to implement this instead as a proper CIF to CIF transformation:
- Events, constants and type definitions are preserved.
- Automata become groups.
- Locations, discrete variables, algebraic variables and continuous variables become input variables.
- Edges, marker predicates, initialization predicates, and equations are removed.
- Input variables are removed.
- Component definition/instantiation is preserved. (This allows simulation models to have definitions with definitions from the plant model as parameters.)
- Etc. (Still need to check all concepts in CIF, and see whether they need to be preserved, removed, or replaced.)
This then provides a robust alternative to RWS's Python script.
Alternatives
@koenveldik and I looked at alternatives. We considered:
- Doing it with the merger. But, this doesn't work. For one, the merge eliminates component definition/instantiation. Also, you need part of the plant in the simulation model and can't do imports, and merging is too late as you need the interface in the simulation model to refer to these variables or it won't be a valid model.
- Doing imports differently. Something with layers, and putting the right things in the right layers. But, already in simple examples with a single layer it doesn't work. You can't import a model with an input variable into the model where you make it concrete, and you need it there to refer to the other concrete state.
So, imports and merging, as we have them now, don't solve it. We did consider language changes:
- Allow
import interface "plant.cif";
in the simulation model, and doing the CIF to CIF transformation under the hood. Could later be considered, but let's do the CIF to CIF transformation first, and see how it works out. - Allow merging an imported input variables with something concrete from the model that imports it. So, do a little bit of the CIF merger in the type checker:
- We do this already for groups in the type checker. But, groups have only a name and no other properties (except children). So, that is easy to merge in type checker at AST level.
- To merge an input variable and say an algebraic variable, we need to check that the types are the same, for which we need to type check them first.
- We can't have multiple objects with the same name in the same scope, in symbol tables in the type checker.
- We could add the algebraic variable to the symbol table, and the input variable as an 'extra to be checked and merged thing'.
- Then we use the algebraic variable as usual in type checking. But, the extra step would be to also check it against the the input variable. If they can be merged, then fine. If not, then the type checker gives an error.
- We could consider this later, but given all the complexities, both in type checking and on the conceptual level for users to understand this, I propose not to do this now.
With a lack of real good alternatives, I think we should for now go for the CIF to CIF transformation.