How to update the visibility of an object based on a parameter - modelica

Connections have at least two important variables. The flow variable and not-flow variable (and then stream stuff but lets not talk about those). For clarity I will reference the Fluid connector and its variables m_flow (flow variable) and p (not flow variable).
When your building components it is important to specify if that component is setting the value for the m_flow or p. For example, you do not want to connect two pressure loss components (sets m_flow) together.
The fluid connectors in MSL are defined as port_a (design inlet) and port_b (design outlet). To specify if a port sets m_flow or not, DynamicPipe opts to use the PartialTwoPort component that has an object (black ellipse) in the icon layer that toggles its visibility based on a parameter (port_a_exposesState) which can be modified when PartialTwoPort is extended (i.e., PartialTwoPortFlow).
However, this feature does not work. The parameter will not change its display when the parameter is changed (i.e., the black ellipse on DynamicPipe never goes away).
Below is a simple example demonstrating the concept. When the model "RunMe" is simulated the parameter showBall = false because number <> 1. However, the ball is still visible.
Partial Model setting the object that should appear/disappear:
partial model ballIcon
// input Boolean showBall; // Tried this as well to no avail.
protected
parameter Boolean showBall = true;
annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={
Ellipse(
extent={{-40,40},{40,-40}},
lineColor={0,0,0},
fillPattern=FillPattern.HorizontalCylinder,
fillColor={255,255,0},
visible=showBall)}),
Diagram(coordinateSystem(
preserveAspectRatio=false)));
end ballIcon;
Extending model:
model extendsBallIcon
extends ballIcon(showBall=(number==1));
parameter Real number = 1;
end extendsBallIcon;
Model that should show a ball that appears or disappears based on "number":
model RunMe
extendsBallIcon Ball(number=3)
annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
end RunMe;
Is there something that can be corrected to this approach so the GUI of a component when used (i.e., on the diagram layer) will work? Or do connectors GUI need to capture the flow/not-flow element that is defined by a component to assist in model usage (i.e., change port_a from description design inlet to defined flow variable).
Using Dymola 2017 (tested with the same results on Dymola 2016 as well)
Update:
Knowing the simple case works using DynamicSelect leads me to a real application. The following change appears to cause the icon to not toggle its visiblity.
In extendsBallIcon replacing:
extends ballIcon(showBall=(number==1));
parameter Real number = 1;
with
// Boolean Example
extends ballIcon(showBall=(number==true));
final parameter Boolean number = (modelStructure==Modelica.Fluid.Types.ModelStructure.av_b);
parameter Modelica.Fluid.Types.ModelStructure modelStructure = Modelica.Fluid.Types.ModelStructure.av_b;

Modelica language specification states in section 18.6.6: "Any value (coordinates, color, text, etc) in graphical annotations can be dependent on class variables using the DynamicSelect expression." That is, visible=DynamicSelect(true, showBall) in your example will display the ellipse only if showBall is true.

Related

Can a type be set globally using inner/outer and be replaceable?

Problem Description
I would like to use Non-SI-Units for time in economical modeling (e.g. System Dynamics). While of course I could go for seconds (s) and then use displayUnit there is to my knowledge no nice way to modify displayUnit for time in System Modeler, which I am mainly using.
So, writing a library I would like the user to make a choice of a global type called ModelTime which ideally would be declared as inner and replaceable at some top-level class. Then any component within a model could use the global type to consistently treat any time-related vars.
Minimal Example
The following example shows how I would like to implement this.
package Units declares two Non-SI Unit types( Time_year, Time_month)
package Interfaces contains a partial model class GenericSimulationModel which will be the top-level scope for any model written using the library. It is supposed to provide the type ModelTime as an inner and replaceable class
package Components defines a simple block class that uses ModelTime via an outer definition to define its output y that simple shows time in the globally chosen units of time
model Example ties all of this together to provide an example how any model using the library should work out
Here is the code:
model MinimalExample
package Units
type Time_year = Real(final quantity = "Time", final unit = "yr");
type Time_month = Real(final quantity = "Time", final unit = "mo");
end Units;
package Interfaces
partial model GenericSimulationModel "Top-level model scope providing global vars"
inner replaceable type ModelTime = Years "Set to : Months, Years";
protected
type Years = Units.Time_year;
type Months = Units.Time_month;
end GenericSimulationModel;
end Interfaces;
package Components
block ComponentUsingTime
outer type ModelTime = MinimalExample.Units.Time_year;
output ModelTime y;
equation
y = time;
end ComponentUsingTime;
end Components;
model Example
extends Interfaces.GenericSimulationModel(
redeclare replaceable type ModelTime = Months
);
Components.ComponentUsingTime c;
end Example;
equation
end MinimalExample;
While everything compiles without error in System Modeler and OpenModelica, it unfortunately does not work out: The redeclared type is not used within the component c in the Example model given above.
What can I do to achieve what I want to do?
I have received some feedback on Wolfram Community from someone at Wolfram MathCore (developers of the System Modeler):
The behavior you see for MinimalExample.example and MinimalLibrary.Example are bugs, and from what I can see they should work, I have forwarded them to a developer working on these things.

Connect parameter variables in expandable connector

Two models are connected via an (empty) expandable connector.
One of the two, makes a connection between the expandable connector and a parameter variable.
I didn't expect any issue. On the contrary, I had some issues:
OpenModelica compiles Version 2, but not Version 1
[bus_param_out]: Failed to instantiate equation connect(controlBus.num, numberPar);
Translation Error: Error occurred while flattening model bus_param
Dymola does not compile either Version 1 or Version 2
Connect does not refer to connectors in connect(bus_in.controlBus.num, bus_in.num);
but bus_in.num is a Real and Modelica Specifications says
All components in an expandable connector are seen as connector instances even if they are not declared as such [i.e. it is possible to connect to e.g. a Real variable].
What am I doing wrong? Am I missing something?
My final goal is to link a parameter variable to an expandable connector (e.g. inform different vehicle components about the number of battery cells, let's say) without the need of an additional redundant variable. Is this possible?
The test code is the following:
bus_param.mo
model bus_param
bus_param_in bus_in;
bus_param_out bus_out;
equation
connect(bus_in.controlBus, bus_out.controlBus);
end bus_param_custom;
bus_param_in.mo
model bus_param_in
Real num;
bus controlBus;
equation
connect(controlBus.num, num);
end bus_param_in;
bus_param_out.mo - Version 1
model bus_param_out
parameter Real numberPar = 3.0;
bus controlBus;
equation
connect(controlBus.num, numberPar);
end bus_param_out;
bus_param_out.mo - Version 2
model bus_param_out
parameter Real numberPar = 3.0;
Real number;
bus controlBus;
equation
number = numberPar;
connect(controlBus.num, numberPar);
end bus_param_out;
bus.mo
expandable connector bus
end bus;
f.wue already showed how to write a parameter to the bus.
This post additionally explains how to read the value without increasing the variability (so it stays a parameter).
To make its usage easier, here is the complete code of a demo package to show how to read and write parameters on busses.
It works with Dymola 2019 FD01 in pedantic mode and OMEdit v1.13.2.
package ParmeterToBus
expandable connector bus
end bus;
model bus_param_out
parameter Real numberPar;
Modelica.Blocks.Sources.Constant helper(k=numberPar);
bus controlBus;
equation
connect(controlBus.number, helper.y);
end bus_param_out;
model bus_param_in
Modelica.Blocks.Interfaces.RealOutput buffer;
bus controlBus;
final parameter Real num(fixed=false); // users should not modify it, hence its final
initial equation
num = buffer;
equation
connect(buffer, controlBus.number);
end bus_param_in;
model example
bus_param_in bus_in;
bus_param_out bus_out(numberPar=7);
equation
connect(bus_in.controlBus, bus_out.controlBus);
end example;
end ParmeterToBus;
Note that the implementation is far from being straightforward.
Some tweaks are necessary along with helper classes to overcome the following restrictions:
Only connectors can be used in connect statements.
So we need
an instance of an constant block to write the value
(helper in the code above)
an instance of an RealOutput connector to read the value
(buffer in the code above)
Models and blocks are not allowed to have the prefix parameter.
Therefore wee need the constant block to write the value, we cannot use a RealOutput connector here.
For parameters usually an initial equation is automatically generated from its binding equation.
To prevent this, we have to set (fixed=false). This allows us to assign the parameter in the initialization phase with the value of a variable of higher variability - in our case the buffer.
You could use
Modelica.Blocks.Interfaces.RealOutput num
to declare a Real that can be used in a connect statement.
EDIT:
As far as i know, connecting a parameter to a connector is not possible. Dymola will yield the error:
Connect does not refer to connectors in connect
The official way would be to use Modelica.Blocks.Sources.Constant, which is equivalent to RealOutput. You can directly use a parameter like this:
model bus_param_out
parameter Real number = 3;
Modelica.Blocks.Sources.Constant num_con(k=number);
bus controlBus;
equation
connect(controlBus.num, num_con.y);
end bus_param_out;
When using expandable connectors and connect these connectors, you have to make sure to set bus.numonly once. Everything else will result in an error.
Try connecting everything with the graphical interface, that will maybe clear things up.
You can use the expandable connector outside of connect like this:
model bus_param_out
Real number_of_bus;
parameter Real number = 3;
Modelica.Blocks.Sources.Constant num_con(k=number);
bus controlBus;
equation
connect(controlBus.num, num_con.y);
number_of_bus = controlBus.num;
end bus_param_out;
But trying to declare parameter Real number_of_bus will result in the following error:
The variability of the definition equation: number_of_bus =
controlBus.num; is higher than the declared variability of the
variables.
because the connector is time-variant and the parameter constant.

Unreal GAS: Influence of the GameplayEffect aggregator on gameplay attribute values

During analyzing the lifetime of a GameplayEffect modifier and execution, I've stumbled across attribute aggregators or GameplayEffect aggregators (both terms are used in source code). These are used to evaluate modified attribute values (they are modified by GameplayEffects).
However, I don't understand how those aggregators influence the actual GameplayAbilitySystem attributes which are attached (as part of an AttributeSet) to the actor:
Does an attribute/GameplayEffect aggregator FAggregator influence the base value or the current value of a gameplay attribute FGameplayAttributeData?
Is the base value of an attribute/GameplayEffect aggregator float FAggregator::BaseValue related to the base value of a gameplay attribute float FGameplayAttributeData::BaseValue?
The vital components of attribute/GameplayEffect aggregators are
so called gameplay modifier evaluation channels EGameplayModEvaluationChannel, which are used sequentially during value evaluation (the result of channel0 is passed as base value to channel1 etc)
storing modifiers (with its magnitude, operation, tags and link to the applying GameplayEffect) in certain channels, which define the actual numerical evaluation
Those are used for doing the evaluation of
a final value
a base value by evaluating a final value in reverse, attempting to determine the base value from the modifiers (deprecated b/c GAS now has struct-based attributes - according to documentation)
a bonus value (final value - base value)
(all of them are just return values of functions and are not member variables of the aggregator)
To notify other classes of an evaluation (or changes to the aggregator), two methods are used
a delegate FOnAggregatorDirty is broadcasted which contains a reference to the aggregator
every GameplayEffect, which is registered in the AbilitySystemComponent, updates the change to its affected attribute(s) (via FActiveGameplayEffectsContainer::UpdateAggregatorModMagnitudes()) by updating the aggregator FAggregator for the attribute (which is determined or set via FindOrCreateAttributeAggregator()) in FAggregator::UpdateAggregatorMod())
I don't see, how one or both of those notification methods update the actual attribute values.
(The official documentation/source code as well as the excellent GAS: Comprehensive Analysis and GAS and you unfortunately don't shed light on GameplayEffect aggregators.)
The attribute/GameplayEffect aggregator influences the current value of a gameplay attribute.
Partly yes. They are related in one direction: the base value of the gameplay attribute is used to set the base value of the attribute/GameplayEffect aggregator, but not the other way around. The aggregator does not change the attribute base value.
Explanation for (1)
I was on the right track by looking at the notification methods. In fact, both in conjunction are updating the gameplay attribute:
FActiveGameplayEffectsContainer::FindOrCreateAttributeAggregator() applies UAbilitySystemComponent::OnAttributeAggregatorDirty() to the OnDirty delegate (that delegate is executed when the aggregator changes as written in the question).
OnAttributeAggregatorDirty() calls FActiveGameplayEffectsContainer::InternalUpdateNumericalAttribute(), which calls
UAbilitySystemComponent::SetNumericAttribute_Internal(), which calls
FGameplayAttribute::SetNumericValueChecked(). That sets the current value of a gameplay attribute.
Explanation for (2)
The base value of the attribute/GameplayEffect aggregator is set only using the gameplay attribute base value FGameplayAttributeData::BaseValue in:
FActiveGameplayEffectsContainer::OnAttributeAggregatorDirty()
FActiveGameplayEffectsContainer::SetAttributeBaseValue()
The base value of the gameplay attribute is set by:
UAttributeSet::InitFromMetaDataTable()
FActiveGameplayEffectsContainer::SetAttributeBaseValue()
In both functions, the attribute base value has no relation to the base value of the aggregator.

User defined unit conversion and displayUnit in Modelica

I have been working with several non-SI medical units on OpenModelica and created a package to contain them. What I wanted to do is to select another user defined unit for display purposes. This is done pretty easily for the types in Modelica library such as
Modelica.SIunits.Pressure P_example(displayUnit="bar");
To be more specific about the problem, I am working with 2 different pressure units: cmH2O and mmHg. My variables in the model are in cmH2O, so are all the calculations. I want to plot only few of the variables in mmHg. I have following declarations for the types:
type Pressure = Real(final quantity="Pressure", final unit="cmH2O");
type Pressure_mmHg = Real(final quantity="Pressure", final unit="mmHg");
As well as to_mmHg and from_mmHg functions, just like original Modelica Library. However, the variable I am trying to plot in mmHg still appears in cmH2O.
Types.Pressure P_lv(displayUnit="mmHg");
The following is working but not so fancy as I don't want to define a new variable unnecessarily.
Types.Pressure_mmHg P_lv_in_mmHg = Types.to_mmHg(P_lv);

Fixed value for a parameter in modelica

I have a parameter z for which I need the value to be 1, always.
model test
Real parameter z = 1;
end test;
When I drag and drop this model and double click on it, the parameters tab opens and I can change the value. How can i prevent that from happening?
Make the parameter final or protected. Final means you cannot modify it (and you can set the final modifier in a modification, like M m(final z=2) when instantiating a component). OpenModelica will also evaluate final parameters by default in order to produce a more efficient simulation (making them almost the same as constants).
Protected also means it cannot be modified (and in many tools will not be part of the result-file either).