Save start / initial guess values in OpenModelica & implement initial values from file - modelica

There is an option in Dymola "Save start values in the model", which allows one to re-use these parameters in order to tune the simulation.
I was looking for a similar possibility in OpenModelica, but so far I wasn't able to figure it out. Particularly, I am building a model with ThermoSysPro, which is rather sensitive to the change of initial values. My model has several vertical pipes (upstream, downstream), so it fails quite easily.
1. Is it possible to save initial / start / guess values in OpenModelica?
2. What would be the ways of implementing / taking these values in the model? (let's say I have density - ρ, enthalpy - h, temperature - T and so on. Just for simplification purposes for Modelica newbie)
------UPDATE------
In my case, I have two approaches to start / initial values:
(ThermoSysPro - TSP)
Approach 1 - Run the simulation for 1s without changing default start-values given in TSP by introducing desired boundary conditions or close ones that it would run successfully.
Gather the generated initial values and add them as start-values (time-consuming when one has a lot of components).
For components such as “volume” or any other component that is not discretized it is enough to give these values under the “Initialization” section in the component or in the “Text view” window e.g. Q(start = 0.3); P(start = xxx).
But in case of discretized components, such as “pipe” it has to be done via “Text view” by using the operator each e.g. Q(each start = 0.3). However, the operator “each” disappears when one changes any parameter of the component via “Diagram view”, so it has to be given as follows:
• Q(start = {0.3 for i in 1:componentName.Ns+1})
• Q(start = fill(0.3, componentName.Ns+1))
• Q(start = {x1, x2, x3, x4, … xi})
Ns + 1 - for hydraulic nodes / Ns – for thermal nodes
PROBLEM
P.1.1 - Normally, one should write:
Q(start = fill(0.3, Ns+1), fixed = fill(true/false, Ns+1))
But it is the same story as with operator each, after changing any parameter of the component via “Diagram view”, the attribute fixed changes automatically to fixed=false, although an array is needed. I tried creating a Boolean parameter and using array comprehension but I always get the same outcome. Any advice or workaround?
P.1.2 – I cannot see any improvement (speed up / better results / or something else) of simulations, after adapting the generated start-values instead of using default ones. Also, after adapting too many of them, I start getting initialization problems – which should be opposite for my understanding. So, I am not sure how I should be using/declaring start-values properly? Maybe the problem is that I do not explicitly add fixed = true/false?
Approach 2 – calculate start-values based on the boundary conditions by using Modelica functions. So firstly, I calculate start-values of multiple parameters (normally I do for pressure and enthalpy). e.g.
parameter Modelica.SIunits.Enthalpy init_enthalpy[Ns+1] = {Modelica.Media.Water.WaterIF97_base.specificEnthalpy_pT(P[i], T) for i in 1:Ns+1}
and then add it for specific component as:
h(start = init_enthalpy)
PROBLEM:
P2.1 With the ThermoPower library this approach works perfectly, but with ThermoSysPro, I am having difficulties, as there are so many parameters that can be given for initialization. How many parameters generally should be given or how to locate the most important ones that definitely should be given?
P2.2 Is there a difference between declaring start / initial values in the initial equation section and calculating it as a parameter (like above)?
P2.3 By indicating that start-value is either fixed=true / false wouldn’t mean that you are using the so-called "inverse problem"?

I am not aware if the option of automated saving of initial values is available jet, but in general you can set initial values of variables either with an initial equation or you can change the start attribute of a variable. If it is a state you have to set the fixed attribute to true such that it will be considered for initialization.
model test
Real a(start=10, fixed=true);
Real b;
initial equation
b = 20;
equation
der(a) = cos(time);
der(b) = sin(time);
end test;
Nonlinear iteration variables for nonlinear systems and discrete variables also need to have start values.

P1.1 Regarding the missing each operator, that unfortunately is a known bug we are trying to fix. Related ticket:
trac.openmodelica - #5737
I also cross linked this question.
P1.2 Start values don't really speed up the simulation, only (slightly) the initialization. If you don't provide any, the compiler just sets them to zero and starts from there. This could cause multiple problems:
you actually don't simulate the system you thought you would
iterative solvers (newton) for nonlinear systems converge to the wrong solution or not at all during initialization
unexpected division by zero
not resolvable under-constraint initial system
If you provide to many initial values you could cause alias conflicts or over-constrain the system. If you have an equation as a=b and provide start values for both, they have to be equal. Your provided start values will always shadow the ones from the original model and not cause alias conflicts though. If you have conflicts the compiler chooses arbitrarily between the options (some pretty basic heuristic).
Approach 2 Unfortunately i am no engineer so i don't know if that is the right way, but in general this seems fine.
P2.1 The default initial values from libraries are fine most of the time, you only have to set them specifically if you want to do something differently. E.g. a boiler starts with higher temperature or something like that.
If you want to have full information use: Simulation -> Simulation Setup -> Translation Flags The field Additional Translation Flags. Put: -d=backenddaeinfo,stateselection,discreteinfo,iterationVars
I did this for Modelica.Electrical.Analog.Examples.Rectifier and here is the output:
[1] 11:25:25 Symbolic Notification
Model statistics after passing the front-end and creating the data structures used by the back-end:
* Number of equations: 128
* Number of variables: 128
[2] 11:25:25 Translation Notification
List of all iteration variables (DAE kind: initialization)
Iteration variables of torn nonlinear equation system:
IdealDiode6.s:VARIABLE(start = 0.0 unit = "1" protected = true ) "Auxiliary variable for actual position on the ideal diode characteristic" type: Real
IdealDiode3.s:VARIABLE(start = 0.0 unit = "1" protected = true ) "Auxiliary variable for actual position on the ideal diode characteristic" type: Real
Iteration variables of torn nonlinear equation system:
IdealDiode5.s:VARIABLE(start = 0.0 unit = "1" protected = true ) "Auxiliary variable for actual position on the ideal diode characteristic" type: Real
IdealDiode2.s:VARIABLE(start = 0.0 unit = "1" protected = true ) "Auxiliary variable for actual position on the ideal diode characteristic" type: Real
Iteration variables of torn nonlinear equation system:
IdealDiode1.s:VARIABLE(start = 0.0 unit = "1" protected = true ) "Auxiliary variable for actual position on the ideal diode characteristic" type: Real
IdealDiode4.s:VARIABLE(start = 0.0 unit = "1" protected = true ) "Auxiliary variable for actual position on the ideal diode characteristic" type: Real
Iteration variables of torn linear equation system:
SineVoltage1.n.v:VARIABLE(flow=false unit = "V" ) "Potential at the pin" type: Real
[3] 11:25:25 Symbolic Notification
Model statistics after passing the back-end for initialization:
* Number of independent subsystems: 2
* Number of states: 0 ()
* Number of discrete variables: 6 (IdealDiode1.off,IdealDiode2.off,IdealDiode3.off,IdealDiode4.off,IdealDiode5.off,IdealDiode6.off)
* Number of discrete states: 0 ()
* Top-level inputs: 0
[4] 11:25:25 Symbolic Notification
Strong component statistics for initialization (33):
* Single equations (assignments): 29
* Array equations: 0
* Algorithm blocks: 0
* Record equations: 0
* When equations: 0
* If-equations: 0
* Equation systems (linear and non-linear blocks): 0
* Torn equation systems: 4
* Mixed (continuous/discrete) equation systems: 0
[5] 11:25:25 Symbolic Notification
Model statistics after passing the back-end for simulation:
* Number of independent subsystems: 1
* Number of states: 4 (Inductor2.i,Inductor3.i,Capacitor1.v,Capacitor2.v)
* Number of discrete variables: 6 (IdealDiode1.off,IdealDiode2.off,IdealDiode3.off,IdealDiode4.off,IdealDiode5.off,IdealDiode6.off)
* Number of discrete states: 0 ()
* Top-level inputs: 0
[6] 11:25:25 Symbolic Notification
Strong component statistics for simulation (28):
* Single equations (assignments): 24
* Array equations: 0
* Algorithm blocks: 0
* Record equations: 0
* When equations: 0
* If-equations: 0
* Equation systems (linear and non-linear blocks): 0
* Torn equation systems: 4
* Mixed (continuous/discrete) equation systems: 0
[7] 11:25:25 Symbolic Notification
Torn system details for strict tearing set:
* Linear torn systems: 1 {(1,100.0%) 9}
* Non-linear torn systems: 3 {2 7,2 7,2 7}
[8] 11:25:25 Translation Notification
List of all iteration variables (DAE kind: simulation)
Iteration variables of torn nonlinear equation system:
IdealDiode2.s:VARIABLE(start = 0.0 unit = "1" protected = true ) "Auxiliary variable for actual position on the ideal diode characteristic" type: Real
IdealDiode5.s:VARIABLE(start = 0.0 unit = "1" protected = true ) "Auxiliary variable for actual position on the ideal diode characteristic" type: Real
Iteration variables of torn nonlinear equation system:
IdealDiode6.s:VARIABLE(start = 0.0 unit = "1" protected = true ) "Auxiliary variable for actual position on the ideal diode characteristic" type: Real
IdealDiode3.s:VARIABLE(start = 0.0 unit = "1" protected = true ) "Auxiliary variable for actual position on the ideal diode characteristic" type: Real
Iteration variables of torn nonlinear equation system:
IdealDiode1.s:VARIABLE(start = 0.0 unit = "1" protected = true ) "Auxiliary variable for actual position on the ideal diode characteristic" type: Real
IdealDiode4.s:VARIABLE(start = 0.0 unit = "1" protected = true ) "Auxiliary variable for actual position on the ideal diode characteristic" type: Real
Iteration variables of torn linear equation system:
SineVoltage1.n.v:VARIABLE(flow=false unit = "V" ) "Potential at the pin" type: Real
Under [2] you can see the iteration variables that need to have start values. In [3] you can see the discrete variables that either need to have start values or be explicitly defined in the system (e.g. if you use a when condition to switch them they need to have start values. Boolean default: false). In [5] you can see the chosen states, they need start values and need to be fixed (you can also instead provide initial equations for their derivatives e.g. steady state initialization).
P2.2 Start values can be used as initial values for iteration variables (necessary for newton solver). For states they won't always be used unless you set fixed=true, fixed=false is default. Initial equations are always part of the initial system. For calculating a parameter the same rules apply whether you use that parameter as a start value or in an initial equation.
P2.3 Unfortunately i am not quite sure what you mean by inverse problem. As i mentioned you could provide initial equations for the state derivatives instead of the states and that would also work (maybe that's what you are implying here?). fixed=false is default, the option to state this is to revoke fixed=true decisions made on lower levels or in used libraries.
Sorry this is quite verbose, i hope i could help!

Related

Why the initialization setting in the dsin.txt file is different from the Model in Dymola?

I build a simple model in Dymola, I choose to use i_R1 to set the intializaiton condition, as shown in the follwing code and screenshot.
model circuit1
Real i_gen(unit="A") "Current of the generator";
Real i_R1(start=1,fixed=true,unit="A") "Current of R1";
Real i_R2(unit="A") "Current of R2";
Real i_C(unit="A") "Current of the capacitor";
Real i_D(unit="A") "Current of the diode";
Real u_1(unit="V") "Voltage of generator";
Real u_2(unit="V") "Output voltage";
// Voltage generator
constant Real PI = 3.1415926536;
parameter Real U0( unit="V") = 5;
parameter Real frec( unit="Hz") = 100;
parameter Real w( unit="rad/s") = 2*PI*frec;
parameter Real phi( unit="rad") = 0;
// Resistors
parameter Real R1( unit="Ohm") = 100;
parameter Real R2( unit="Ohm") = 100;
// Capacitor
parameter Real C( unit="F") = 1e-6;
// Diode
parameter Real Is( unit="A") = 1e-9;
parameter Real Vt( unit="V") = 0.025;
equation
// Node equations
i_gen = i_R1;
i_R1 = i_D + i_R2 + i_C;
// Constitutive relationships
u_1 = U0 * sin( w * time + phi);
u_1 - u_2 = i_R1 * R1;
i_D = Is * ( exp(u_2 / Vt) - 1);
u_2 = i_R2 * R2;
C * der(u_2) = i_C;
end circuit1;
But after translation, in the dsin.txt, it shows that i_R1 is a free variable, but u_2 is fixed.
My question is:
Why Dymola sets u_2 as fixed instead of i_R1?
The first column in dsin.txt is now primarily used for continue simulation in Dymola, and is otherwise sort of ignored.
If you want to know which values are relevant for starting the simulation, i.e. parameters and variables with fixed=true you should instead look at the 6th column and x&8, that shows that i_R1, U0, freq, phi, R1, R2, C, Is, and Vt will influence a normal simulation.
For continue simulation it is instead x&16 that matters, so u_2 instead of i_R1.
The x above is the value in the 6th column, and &8 represents bitwise and. In Modelica you could do mod(div(x, 8),2)==1 to test the numbers.
Better read Hans Olsson's answer, he knows better, still here is what I wrote:
I didn't implement it, so take everything with a grain of salt:
dsmodel.mof for the posted example, contains the following code:
// Initial Section
u_1 := U0*sin(w*time+phi);
u_2 := u_1-i_R1*R1;
Using the values from the example results in u_1 = 0 and u_2=-100. So it seems the fixed start value for i_R1 is used to compute the initial value u_2 using the above equations.
This should be the reason for the fixed statements in the model and dsin.txt being different in dsin.txt compared to the original Modelica code. Basically information from the model is used to compute the initial value of the state (u_2) from the start value from an auxiliary variable (i_R1). In the executed code, the state is being initialized.
Speculation: u_2 is unknown when creating dsin.txt, so it is set to zero and computed later. This should correspond to the first case described in dsin.txt in
"Initial values are calculated according to the following procedure:"
which is when all states are fixed.
I think it is a bug: even though it is signed as fixed, the voltage u_2 starts at -100V instead of 0V when I simulate it, and i_R1 starts at 1A.
Speculation: Perhaps the sorting algorithms are allowed during translation to set fixed initial values to more meaningful variables, as long as the condition given by the Modelica code (i_R1=1, in your case) is met. If that's the case, it would still count as a bug for me, but it might explain what's going on.

spatialDistribution()-Operator and non-scalar gradients in Modelica

I am using the spatialDistribution() Operator in Dymola and get the follwing message when using Hidden.PrintFailureToDifferentiate = true;
"Can only compute non-scalar gradients of functions specifying derivatives and not for: spatialDistribution"
I call the operator like this :
(time_rev,time_flow) = spatialDistribution(time,time,x/length,v_water>=0,{0.0,1.0}, {time,time});
and use it to calculate the outlet Temperature of my pipe.
Anyone got an idea where the issue lies? I don't really understand the error message.
More complete example:
cp_in = //Calculates specific Heatcap
cp_out = //Calculates specific Heatcap
cp = (cp_in+cp_out)*0.5;
C = (Modelica.Constants.pi*(1/4))*diameter_i^2*fluidInlet.d*cp;
R= // Calculates Heatresistance
//---------Conservation of mass flow and composition
//The usual stuff equal massflow,xi and p at both connectors
//----------Spatial
tau_nom = C*R;
v_water = //Calc Speed of water from Geometric data and inlet rho
der(x) = v_water;
(time_reversed,time_flow) = spatialDistribution(time,time,x/length,v_water>=0, {0.0,1.0}, {time,time});
tau_delay= time - time_flow;
tau_reversed= time - time_reversed; //Not used right now
if inlet.m_flow >= 0 then
T_out = (T_amb + (T_in - heat.T)*exp(-tau_delay/tau_nom));
heat.Q_flow = -inlet.m_flow*cp*(T_in - T_out);
inlet.h = inStream(outlet.h);
else
outlet.h = inStream(inlet.h);
T_in = T_out;
heat.Q_flow = -inlet.m_flow*cp*(T_in - T_out);
end if;
The reason for getting this error message is that Dymola cannot compute a gradient, that is likely used as part of computing a Jacobian for a non-linear system of equations.
If you look at the translation log I would expect that "Number of numerical Jacobians: " is non-zero.
A missing Jacobian for a non-linear system of equations is normally not a major issue.
However, that the non-linear system needs the gradient for spatialDistribution does not seem right, since it indicates that the delayed variables are implicitly given in some odd way.
It could be that the delay of the spatial distribution should solve that and in that case Dymola 2019 FD01 might remove the issue if you set Advanced.BreakDelayLoops=true; (but it is difficult to say without the complete model).
(It seems you have an earlier version, and the flag does not work there.)
I know it is a bit late answer, but it was difficult to investigate without a complete model.

Simulink Execution

I have created the following simulink model with two blocks one with direct addition and the other block with a unit delay. The simulink configuration parameters are fixed step solver with 0.2 fixed step size. Now my doubt is for the blocks without unit delay the output is available at 0th simulation time which is 2 but in case of unit delay the output is 0 at 0th simulation time. Why? simulink model sorry but i am unable to attch the model.
You can think of your Simulink diagrams as of the discrete linear dynamical systems with inputs and outputs. Using the transfer function approach, such systems can be represented via
(1) Y(z)=G(z)X(z),
where Y(z) is the out of the system, X(z) is the input and G(z) is the transfer function (note: I omitted the initial conditions at this stage for the simplicity of explanation). Each individual block of the system can also be treated as the system of the form (1).
Consider your first diagram. The constant block expressed in the input output form (1) is
(2) Y1(z) = G1(z)X(z),
with: G1(z) = 1, i.e.
(3) Y1(z) = X(z).
Each Simulink 'unit delay' block can be treated as a system of the form (1) with the transfer function of the form Gu(z) = z^(-1). Denote the transfer function associated with the 'unit delay' block in the middle of the diagram as G2(z) and the one at the bottom of the diagram as G3(z). In this case, we have G3(z) = G2(z) = Gu(z) = z^(-1). Note that the input to the system associated with G2 is the output of the system (3) and the input to the system associated with G3 is the output of the system associated with G2. Taking into account the considerations above, the systems that correspond to the unit delay blocks associated with G1 and G2 are given by (4) and (5), respectively.
(4) Y2(z) = G2(z)*Y1(z) = z^(-1)*Y1(z) = z^(-1)*G1(z)*X(z) = z^(-1)*X(z)
(5) Y3(z) = G3(z)Y2(z) = z^(-1)*z^(-1)*X(z) = z^(-2)*X(z)
Assuming that the output of the system associated with the entire model is denoted Y(z) and corresponds to the output of the summation block, the transfer function of the entire system can be expressed as
(6) Y(z) = Y1(z) + Y2(z) + Y3(z)
To summarise:
(7a) Y1(z) = X(z)
(7b) Y2(z) = z^(-1)*Y1(z)
(7c) Y3(z) = z^(-1)*Y2(z)
(7d) Y(z) = Y1(z) + Y2(z) + Y3(z)
The system above corresponds to a difference equation of the form
(8a) y1(k) = x(k)
(8b) y2(k) = y1(k-1)
(8c) y2(k) = y2(k-1)
(8d) y(k) = y1(k) + y2(k) + y3(k)
To see this, you can apply Z-transform to the equation (8) above. You can assume that in Simulink, the simulation always starts at k=0 (to obtain the 'physical time' that associated with the output you would need to use t(k) = k*T, where T is the sampling time set in the solver properties). Thus, you would need to provide the values of y1(k) and y2(k) for k=-1 to be able to solve the system for all k>=0.
All Simulink blocks that represent transfer functions (be it discrete or continuous) allow the assignment of initial conditions. For discrete systems, the initial conditions are assumed to be valid for all k<=0 (or t<=0 if you consider physical time). The default initial condition for the blocks that represent transfer functions is 0. Thus, when you simulate the system (8), Simulink assumes that y1(-1)=0, y2(-1)=0. The constant block assigns x(k) = 1 for all k>=0.
Given what is stated above, let us calculate the values of the system (8) at time steps k=0,1,2.
At k=0:
y1(0) = x(0) = 1, y2(0) = y1(-1) = 0, y3(0) = y2(-1) = 0, y(0) = 1
At k=1:
y2(1) = x(1) = 1, y2(1) = y1(0) = 1, y3(1) = y2(0) = 0, y(0) = 2
At k=2:
y2(2) = x(2) = 1, y2(2) = y1(1) = 1, y3(2) = y2(1) = 1, y(0) = 3

Trouble balancing a simple power flow model in modelica

I try to set up a simple model with electrical or thermal power flows between sources and sinks.
I seem to have the same problem as treated in this topic although I used only one pair of flow and potential variables in my connector:
connector PowerPortE
flow SI.Power P;
SI.Voltage v "Dummy potential-variable to balance flow-variable P";
end PowerPortE;
A simple example with a signal responsed power sink looks like this:
model PowerSinkE
SimplePowerSystem.PowerPortE Port;
Modelica.Blocks.Interfaces.RealInput P(unit = "W");
SI.Voltage v(start = 230);
equation
Port.P = P;
Port.v = v;
end PowerSinkE;
model Test
SimplePowerSystem.PowerSinkE Verbraucher ;
Modelica.Blocks.Sources.Sine sine1(freqHz = 50) ;
equation
connect(sine1.y,Verbraucher.P);
end Test;
Checking PowerSinkE goes well, but when trying to simulate, I get the following errors:
Internal error pre-optimization module removeSimpleEquations failed.
Internal error Found Equation without time dependent variables Verbraucher.Port.P = const.k
An independent subset of the model has imbalanced number of equations (1) and variables (2).
variables:
Verbraucher.v
Verbraucher.Port.v
equations:
1 : Verbraucher.Port.v = Verbraucher.v
An independent subset of the model has imbalanced number of equations (4) and variables (3).
variables:
sine1.y
Verbraucher.P
Verbraucher.Port.P
equations:
1 : Verbraucher.Port.P = Verbraucher.P
2 : sine1.y = sine1.offset + (if time < sine1.startTime then 0.0 else sine1.amplitude * sin(6.283185307179586 * sine1.freqHz * (time - sine1.startTime) + sine1.phase))
3 : Verbraucher.Port.P = 0.0
4 : Verbraucher.P = sine1.y
Initially I wanted to leave the variable v completely out of the model (though I had to leave it in the connector to be balanced) but this didn't work out either:
Model is structurally singular, error found sorting equations
1: 0.0 = sine1.offset + (if time < sine1.startTime then 0.0 else sine1.amplitude * sin(6.283185307179586 * sine1.freqHz * (time - sine1.startTime) + sine1.phase));
for variables
Verbraucher.Port.v(1)
The problem seems to be that I need the flow variable power but don't have a corresponding potential variable. I am running out of ideas how to fix this, so thanks for the help.
Why do you try to use a connector in this case? If you don't need the "pyhsical meaning" of flow and potential variables inside the connector, you just can use real inputs and outputs to handle signals.
package SimplePowerSystem
model PowerSinkE
import SI = Modelica.SIunits;
SI.Power P;
Modelica.Blocks.Interfaces.RealInput P_in(unit="W");
equation
P = P_in;
end PowerSinkE;
model Test
SimplePowerSystem.PowerSinkE Verbraucher;
Modelica.Blocks.Sources.Sine sine1(freqHz = 50);
equation
connect(sine1.y, Verbraucher.P_in);
end Test;
end SimplePowerSystem;
My initial thought is that port in the consumer is unconnected. This adds the equation consumer.port.P = 0.0. But what you really need is an equation for the voltage in the port.
You need to use voltage and current on your electrical connector and you need an electrical ground. I suggest you have a look at Modelica by Example for more about both electrical and thermal component modeling.

MATLAB - understanding structure of Event location function

In my textbook I have encountered an example of a function I am supposed to use when specifying an event location for a system of ODEs. The function example is as follows:
function [value, isterminal, dircn] = proj(t,z,flag);
g = 9.81;
if nargin < 3 | isempty(flag)
value = [z(2); 0; z(4); -g];
else
switch flag
case 'events'
value = z(3);
isterminal = 1;
dircn = -1;
otherwise
error('function not programmed for this event');
end
end
There is one part of the logic here which I don't understand. Say that I activate the "events" option and then run ode45. How, then, can ode45 actually read the system of equations (which is specified in the above function as value = [z(2); 0; z(4); -g];)? I have ran ode45 based on the above function, after specifying tspan and inital conditions of course, and it works like a charm. But I don't understand how ode45 can read the system properly when it is only presented in the "if"-part of the script above.
If anyone can explain the logic here, I would greatly appreciate it!
Well I think I can explain some parts. As I wrote above it is strange that the dimension of value changes.
given your statespace and the names of your variables it looks like 2 dimensional motion.
in the case of no flag it seems that state space is:
horizontal position (x)
horizontal speed (vx)
vertical position (y)
vertical speed (vy)
correction
It seems that ode can send 'events' when you specify them. So your function outputs 3rd component of the state space. Look at this site explaining it: http://www.mathworks.de/help/techdoc/math/f1-662913.html
unless you specify it beforehand ode can't send 'events' to the function so this part will not be called.
But your function won't work anyway - as the derivative would need to have same dimension as the statespace (4x1). But has only 1x1.
But I really don't know what you mean by "specifying an event location". Maybe the secret is hidden there.
With some creativity I think you could use the function to extract the 3rd component of the state space.
The answer is in the if command:
if nargin < 3 | isempty(flag)
value = [z(2); 0; z(4); -g];
else
If number of arguments is less than 3 or if variable flag is empty, then set variable value to [z(2); 0; z(4); -g]. Otherwise, if variable flag is 'events', then set variable value to z(3), and when flag is not 'events', report an error. So this function always assigns some return value for variable value or, reports an error using error command.
I can supplement a bit more information about how we proceed after writing the function above. We then define, say:
tspan = [0 6];
z0 = [0, 5*cos(pi/4), 0, 5*sin(pi/4)];
options = odeset('events','on');
[t y] = ode42('proj',tspan,z0,options)
By writing this the output is 5 columns, 1 column for tspan , and 1 column for each of the z-values (z(1), z(2), z(3) and z(4)). When z(3) hits zero, the calculations are terminated since the "event" occurs.
If, on the other hand I do not include the options = odeset('events','on') line, and simply write:
[t y] = ode42('proj',tspan,z0)
The calculations are performed for the entire tspan range.
Yet, I still fail to see how ode42 is capable of calculating all the output vectors when we activate "events" since it then looks logical me that MatLab should only execute the "else"-statement in the "proj"-function. And in this part of the function, the actual system of the differential equations is not included.