Assuming I have a very complicated thermal-fluid model built with Dymola. During the initialization process, how would dymola choose the iteration variables for the nonlinear solver? Is there a standard for this issue in dymola? I wanna make this clear, cause sometimes if the start values of the iteration variables are too far away from the right solution, there would be a divergence issue during the initialization process. I think if I could know the choice of iteration variables, I could make sure their values are appropriate instead of checking all the start values.
I think this information is not available to the public. At least I could not find anything in the user manuals. Therefore, you have only limited options.
What you can do is:
List your current iteration variables
Try to influence the selection
Get information on performed iterations
List iteration variables
You can list your current iteration variables by activating the flag
Advanced.LogNonLinearIterationVariables = true;
The iteration variables will be listed in the Translation tab as info message Variables appearing in the nonlinear systems of equations:
Influence selected variables
You can influence (but not control) the variables selected for iteration by setting start values. Take this code for example:
model MyNonLinear
Real x;
Real y;
Real z(start=-1);
equation
0 = y - z;
x = (y + z)^2;
x = (y + z) + time;
end MyNonLinear;
If you translate it with the above flag active, Dymola will give this information in the translation tab of the message window:
Iteration variables:
y
When you additionally set a start value for x, (e.g. start=1) x becomes the iteration variable in this case.
Information on performed iterations
To get more information on the performed iterations, activate the Nonlinear solver diagnostics flags in the Debug tab of the Simulation Setup:
Dymola will then display additional information in the simulation log. Note that some of these flags can generate a log of output.
This is possible via a very lightly documented feature. See the 2019 FD01 release highlights for some limited info: https://www.3ds.com/fileadmin/PRODUCTS/CATIA/DYMOLA/PDF/Dymola-2019FD01-highlights.pdf
Specifically:
Related
I'd like to find the set of variables selected by the tearing algorithm in Dymola. so that I could know which variables link different parts of the system together. But I am not sure how to show these variables in Dymola. I checked the help document of Dymola but didn't find anything related to how to show these variables.
You should be able to see it in dsmodel.mof, which is created after setting Advanced.OutputModelicaCode = true; or activating it in the UI using "Simulation Setup -> Translation -> Generate listing of translated Modelica code in dsmodel.mof".
Dymola will generate the relevant code in the // Torn part. Searching for this in dsmodel.mof is a good option as the file can get pretty big.
The exact code will depend on the type of problem. Two examples:
(1) A rather simple electrical like this
will be solved symbolically, with the resulting code:
...
// Linear system of equations
// Tag: simulation.linear[1]
// Symbolic solution
/* Original equation
resistor1.v = constantVoltage.V-resistor.v-capacitor.v;
*/
resistor1.p.i := -(capacitor.v-constantVoltage.V+resistor.R_actual*
inductor.i)/(resistor.R_actual+resistor1.R_actual);
// Torn part
resistor.p.i := inductor.i+resistor1.p.i;
resistor.v := resistor.R_actual*resistor.p.i;
resistor1.v := resistor1.R_actual*resistor1.p.i;
// End of linear system of equations
...
In this case the tearing variable is resistor1.p.i, with the equation to compute it stated directly there.
(2) Translating Modelica.Thermal.FluidHeatFlow.Examples.TwoMass will give you a non-nonlinear case, i.e. when an iteration is needed to solve the system of equations. You should find something like:
...
// Start values for iteration variables of non-linear system of 1 equations:
// pipe2.V_flow(start = 0)
algorithm // Torn part
pipe2.flowPort_a.m_flow := pipe2.V_flow*pipe2.medium.rho;
pipe1.flowPort_a.m_flow := -(pipe2.flowPort_a.m_flow+ambient1.flowPort.m_flow);
...
The tearing variable is pipe2.V_flow in this case, with the start value for the iteration.
In Dymola 2021X, we could use Equation Incidence Browser to see which variables are used in the nonlinear equations, I guess these variables could be treated as tearing variables. And this works for commercial libraries, too. But it is a pity that Dymola 2021X doesn't allow showing details of nonlinear equations.
I am currently working on a spacecraft body with actuator, and given the equation below:
J·w_dot = -w^x·J·w + u (1)
where w^x is actually a notation of 3x3 matrix
[ 0 -w3 w2
w3 0 -w1
-w2 w1 0]
By rearranging (1), I got w_dot = (-w^x·J·w + u)/J. And here I face the problem, I need to update value constantly for w_dot but I have no idea how. I have tried the Memory block but it only update every 0.2 seconds which is not appropriate for the system.
This is my current setting:
I was thinking the integrator block could be the one to be updated every single cycle as initial condition could be set.
Yes, your solution seems about right; the integrator block will cause the system to be continuous-time, rather than discrete-time. This will output results as accurately as Simulink can accomplish.
You can set initial values for the integrator by double-clicking on the integrator block, setting the "Initial condition source" to "external", then connecting another input or constant block, output, or whatever else you want providing the initial value.
By the way, is J is the inertia tensor? In that case, you can't simply "divide" by it; you should multiply by its inverse (setting "Matrix" as the "Multiplication" option in the Divide block's options)
I'm having doubts at how to use ode45 since I know it uses an internal variable step size. For instance, in my particular case I have a model of ODE's and I use a sampling time of 5 minutes. Hence, inside my main simulation loop I have the following line to obtain the output of my model by solving it using ode45:
[T,X] = ode45(#(t,x) model(t,x,u,data),[t t+scenario.Ts],x0);
Where u are inputs of the model, data is a structure with parameters, x0 are the initial conditions at the current time step and [t t+scenario.Ts] is the initial and final time. My doubt is that between t and t+scenario.Ts the ode45-solver uses variable time steps and thus the way I introduce my input actions u may be affected. Hence, I understand that a value of a particular input u is kept constant through the internal time steps between [t t+scenario.Ts]. Then, if I have for instance a flux, i.e. water into a tank, the time step has a direct effect to this u.
Let me explain this a little more with an example. If over [t t+scenario.Ts] I know that u(1) = 10. Then the real input I should use is u(1)=10/(# of time steps between [t0 tend]). However, since the internal step is variable which input do I have to use?
I hope you understand my problem and can help me out.
You should formulate the inputs such that it is independent of the time- discretization. This shouldn't be a problem if your equations are formulated in continuous time. If the control variable is not constant, then you should be make it explicitly dependent of t and write a function u(t).
If my answer is not sufficient to help you out, please add more details about your application, especially the dynamical model that you are simulating. Then we can help you further.
I'm trying to model the respective processes of an internal combustion engine. My current modelling approach is to have different sub functions which model the different processes.
Within each sub function is a Level 2 S-Function which solves the ODEs to give the in cylinder state (pressure, temperature, etc).
The problem that I'm having is that each sub function is enabled depending on the current crank angle which is computed from the current timestep in Simulink. The first process works fine as I manually set the initial values, but then I can't pass the latest in-cylinder state (the output from the first sub function) to the second sub function to use as the initial conditions (it insists on using the initial values I set at the beginning of the simulation).
Is there any way round this? Currently I'm going along a path of global data stores, but haven't had any joy so far.
There are a lot of different ways to solve this problem.
I'll show some of them as examples.
You can create additive output with Unit dalay block like this:
So you can get value of your crank angle from previous timestep and USE IT in formula for solving you equations.
Also you can use some code like this:
if (t == 0)
% equations with your initial values
sred = 0;
else
% equations with other values
y = uOld + myCoeef;
end
Another idea: sometimes I use persistent variables in Matlab function to save values of some variable from previous step. But I think it makes calculation slower.
One more idea - if you have Stateflow you can create chart with two states: first for initial moment with your coefficient and second to solve new equations.
If I understood you in wrong way you can show your code and we'll offer some new ideas!
P.S. Example of my using of S-Function:
My S-Function needs 2 values: Q is calculated in simulink at every step, ro is initial I took from big matrix I loaded from workspace in table and took necessary value depending of time.
So there is no any initial values in S-Function - all needed values I transmit into it from simulink!
I have an ODE for calculating how acidicity changes. Everything is working just fine, only I would like to change a constant whenever acidicity reaches a critical point. It is supposed to be some kind of irreversible effect I wish to simulate.
My constants are coming from a structure file (c) I load once in the ODE function.
[Time,Results] = ode15s(#(x, c) f1(x, c),[0 c.length],x0,options);
The main problem I have here is not telling Matlab to change the constant but remember if it happened already during the simulation once. so Matlab should take the irreversibly changed constant rather than the one I supply at the beginning.
I would like to write a flag that is saved while the ODE is running and an if condition, "if flag exists, change constant". How to do that?
UPDATE I:
PROBLEM SOLVED
Here a first own solution, it is not polished and requires a structure file approach. Which means, the constants which should suddenly changed upon an event, must be struct files which are handed in the ODE function into the function that should be evaluated (look above for the ODE syntax). The function accepts the inputs like this:
function [OUTPUT] = f1(t, x, c)
% So here, the constants all start with c. followed by the variable name. (because they are structs instead of globals)
%% write a flag when that event happens
if c.someODEevent <= 999 && exist ('flag.txt') == 0
dlmwrite ('flag.txt',1);
end
%% next iteration will either write the flag again or not. more importantly, if it exists, the constant will change because of this.
if exist ('flag.txt') == 2
c.changingconstant = c.changingconstant/2;
end
end
Please look into Horchlers kind answer where you have to take care that such a step may introduce inaccuracies and you have to be careful to check if your code does what it is supposed to do.
To do this accurately, you should use event detection within the ODE solver. I can't give you a specific answer because you've only provided the ode15s call it in your question, but you'll need to write an events function and then specify it via odeset. Something like this:
function acidity_main
% load c data
...
x0 = ...
options = odeset('Events',#events); % add any other options too
% integrate until critical value and stop
[Time1,Results1] = ode15s(#(x,c)f1(x,c),[0 c.length],x0,options);
x0 = Results(end,:); % set new initial conditions
% pass new parameters -it's not clear how you're passing parameters
% if desired, change options to turn off events for faster integration
[Time2,Results2] = ode15s(#(x,c)f1(x,c),[0 c.length],x0,options);
% append outputs, last of 1 is same as first of 2
Time = [Time1;Time2(2:end)];
Results = [Results1;Results2(2:end,:)];
...
function y=f1(x,c)
% your integration function
...
function [value,isterminal,direction] = events(x,c)
value = ... % crossing condition, evaluates to zero at event condition
isterminal = 1; % stop integration when event detected
direction = ... % see documentation
You'll want to use the events to integrate right to the point where the "acidicity reaches a critical point" and stop the integration. Then call ode15s again with the new value and continue the integration. This may seem crude, but it how this sort of thing can be done accurately.
You can see an example of basic event detection here. Type ballode in your command window to see the code for this. You can see a slightly more complex version of this demo in my answer here. Here's an example of using events to accurately change an ODE at specified times (rather than your case of specified state values).
Note: I find it strange that you're passing what you call "constants", c, as the second argument to ode15s. This function has strict input argument requirements: the first is the independent variable (often time), and the second is the array of state variables (same as your initial condition vector). Also if f1 only takes two arguments, #(x,c)f1(x,c) is superfluous – it's sufficient to pass in #f1.