1D Heat Diffusion PDE implementation in Modelica(Dymola) - modelica

I was trying to implement a 1D heat diffusion example from the Peter Fritzon's "Object Oriented Modeling and Simulation with Modelica 3.3" based on the Grid Function Finite Difference Approach to 1D Heat Diffusion but I am getting an error:
Translation of Heat_diffusion_Test_1D.HeatDiffusion1D:
The DAE has 50 scalar unknowns and 50 scalar equations.
Cannot find differentiation function:
Heat_diffusion_Test_1D.DifferentialOperators1D.pder(
u,
1)
with respect to time
Failed to differentiate the equation
Heat_diffusion_Test_1D.FieldDomainOperators1D.right(Heat_diffusion_Test_1D.DifferentialOperators1D.pder (
u,
1)) = 0;
in order to reduce the DAE index.
Failed to reduce the DAE index.
Translation aborted.
ERROR: 1 error was found
WARNING: 1 warning was issued
I am a quite new user of the programming language, do you have any idea on how I could fix the issue? Apparently the problem is in the boundary condition of the right boundary.
Thank you in advance!
here is the code:
package Heat_diffusion_Test_1D
import SI = Modelica.SIunits;
model HeatDiffusion1D
import SI = Modelica.SIunits;
parameter SI.Length L=1;
import Heat_diffusion_Test_1D.Fields.*;
import Heat_diffusion_Test_1D.Domains.*;
import Heat_diffusion_Test_1D.FieldDomainOperators1D.*;
import Heat_diffusion_Test_1D.DifferentialOperators1D.*;
constant Real PI=Modelica.Constants.pi;
Domain1D rod(left=0, right=L, n=50);
Field1D u(domain=rod, redeclare type FieldValueType=SI.Temperature, start={20*sin(PI/2*x)+ 300 for x in rod.x});
equation
interior(der(u.val))=interior(4*pder(u,x=2));
left(u.val)=20*sin(PI/12*time)+300;
right(pder(u,x=1)) = 0;
//right(u.val)=320;
annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram(
coordinateSystem(preserveAspectRatio=false)));
end HeatDiffusion1D;
package Fields
record Field1D "Field over a 1D spatial domain"
replaceable type FieldValueType = Real;
parameter Domains.Domain1D domain;
parameter FieldValueType start[domain.n]=zeros(domain.n);
FieldValueType val[domain.n](start=start);
annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram(
coordinateSystem(preserveAspectRatio=false)));
end Field1D;
annotation ();
end Fields;
package Domains
import SI = Modelica.SIunits;
record Domain1D "1D spatial domain"
parameter SI.Length left=0.0;
parameter SI.Length right=1.0;
parameter Integer n=100;
parameter SI.Length dx = (right-left)/(n-1);
parameter SI.Length x[n]=linspace(right,left,n);
annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram(
coordinateSystem(preserveAspectRatio=false)));
end Domain1D;
annotation ();
end Domains;
package FieldDomainOperators1D
"Selection operators of field on 1D domain"
function left "Returns the left value of the field vector v1"
input Real[:] v1;
output Real v2;
algorithm
v2 := v1[1];
end left;
function right "Returns the left value of the field vector v1"
input Real[:] v1;
output Real v2;
algorithm
v2 := v1[end];
end right;
function interior
"returns the interior values of the field as a vector"
input Real v1[:];
output Real v2[size(v1,1)-2];
algorithm
v2:= v1[2:end-1];
end interior;
end FieldDomainOperators1D;
package DifferentialOperators1D
"Finite difference differential operators"
function pder
"returns vector of spatial derivative values of a 1D field"
input Heat_diffusion_Test_1D.Fields.Field1D f;
input Integer x=1 "Diff order - first or second order derivative";
output Real df[size(f.val,1)];
algorithm
df:= if x == 1 then SecondOrder.diff1(f.val, f.domain.dx)
else
SecondOrder.diff2(f.val, f.domain.dx);
end pder;
package SecondOrder
"Second order polynomial derivative approximations"
function diff1 "First derivative"
input Real u[:];
input Real dx;
output Real du[size(u,1)];
algorithm
du := cat( 1, {(-3*u[1] + 4*u[2] - u[3])/2/dx}, (u[3:end] - u[1:end-2])/2/dx, {(3*u[end] -4*u[end-1] + u[end-2])/2/dx});
end diff1;
function diff2
input Real u[:];
input Real dx;
output Real du2[size(u,1)];
algorithm
du2 :=cat( 1, {(2*u[1] - 5*u[2] + 4*u[3]- u[4])/dx/dx}, (u[3:end] - 2*u[2:end-1] + u[1:end-2])/dx/dx, {(2*u[end] -5*u[end-1] + 4*u[end-2] - u[end-3])/dx/dx});
end diff2;
annotation ();
end SecondOrder;
package FirstOrder
"First order polynomial derivative approximations"
function diff1 "First derivative"
input Real u[:];
input Real dx;
output Real du[size(u,1)];
algorithm
// Left, central and right differences
du := cat(1, {(u[2] - u[1])/dx}, (u[3:end]-u[1:end-2])/2/dx, {(u[end] - u[end-1])/dx});
end diff1;
annotation ();
end FirstOrder;
annotation ();
end DifferentialOperators1D;
annotation (uses(Modelica(version="3.2.1")));
end Heat_diffusion_Test_1D;

Your implementation translate and simulate in Dymola 2015 FD01 if you inline all functions in the package FieldDomainOperators1D and DifferentialOperators1D with annotation(Inline=true). The reason is given by Peter Fritzson at page 406:
[...] Note that inline semantics is needed for the pder() function and
the grid function. [...] This makes it possible to put calls to such a
function at places where function calls are usually not allowed. [...]

Related

Having errors with userdefined functions

Doing homework and there's a question that's giving me trouble. The questions is:
a)create a function M-file called nmoles that requires two vector inputs—
the mass and molecular weight—and returns the corresponding number
of moles. Because you are providing vector input, it will be necessary
to use the meshgrid function in your calculations.
b) Test your function for the compounds shown in the following table, for
masses from 1 to 10 g:
In my function file, i've got:
function [ n ] = nmoles(m, MW)
%% Finds number of moles
m = (1:10); %% mass range
MW = [78.115 46.07 102.3]; %% Values from the table
n=m/MW; %%formula provided by the textbook
My main file only has:
nmoles(m,MW)
I'm getting an error: "Error using / Matrix dimensions must agree"
Also: Error in nmoles (line 10) n=m/MW;
I'm inexperienced with MATLAB and still learning syntax but I assume that my formula is incorrect and i'm using the wrong symbol to divide, though i'm not sure how to correct this. Also, how would i incorporate the meshgrid function into my anwser?
Here is how your function should probably look like:
function [ n ] = nmoles(m, MW)
% Finds number of moles
[mv,MWv] = meshgrid(m, MW); % extends m and MW to match all combinations.
n = mv./MWv; %formula provided by the textbook
end
And then your main script should be:
m = 1:10; % mass range
MW = [78.115 46.07 102.3]; % Values from the table
nmoles(m, MW)
You had 3 mistakes:
If you get m and MW as input to the function, your not suppose to define them within it.
Because you want the number of moles for each combination of mass and molar weight, you use meshgrid.
When you want to perform an elementwise division or multiplication on 2 arrays, put a . before the / or *. In MATLAB everything is a matrix by default, and so this operations are interpreted as matrix multiplication and division by default. If you want to do a regular division or multiplication you use .* and ./. This is true also for power (^ and .^).

Replaceable function and function calls from strings

The following three questions are tied together so please forgive the length of the post.
Using Dymola 2016.
Using a replaceable function call within a model provides the opportunity for the user to have the drop down options. Example below:
model Test1
parameter Real x = 1;
Real y;
replaceable function a=b constrainedby d annotation(choicesAllMatching=true);
equation
y = a(x);
end Test1;
Doing the same replaceable function call within a function seems to not permit the same drop down functionality with the the function is called (i.e. right click call function in package browser. I assume this is intentional as a function is typically called within other functions/models. Example below:
function Test2
input Real x;
output Real y;
replaceable function a=b constrainedby d annotation(choicesAllMatching=true);
algorithm
y :=a(x);
end Test2;
Question #1. Is it possible to use a replaceable function call within a function in the same way you do a model? If so, what is the appropriate syntax? Alternative approach?
Alternatively, a different option would be to perform the replaceable function call in the model and then pass the result to another function that then makes the appropriate call. Example shown below:
model Test3mod
parameter Real x = 1;
Real y;
replaceable function a=b constrainedby d annotation(choicesAllMatching=true);
equation
y = Test3func(x,a);
end Test3mod;
Which passes parameter x and function handle a to:
function Test3func
input Real x;
input ???? a;
output Real y;
algorithm
y :=a(x);
end Test3func;
Question #2. Is this allowable in Modelica and if so, how? Alternative approach?
Question #3. Is it possible to define a string and turn that into a the name of a function. Example below:
model Test4
parameter String 'functionname';
parameter Real x = 1;
Real y;
equation
y = functionname(x);
end Test4;
Thank you in advance! I appreciate your feedback as I continue to explore the use of Modelica.
This should work fine:
model Test3mod
parameter Real x = 1;
Real y;
replaceable function a=b constrainedby d annotation(choicesAllMatching=true);
equation
y = Test3Func(x,a);
end blah;
function Test3func
input Real x;
input d f;
output Real y;
algorithm
y := f(x);
end Test3func;

Modelica Class Method

I would like to use a class function/method in my Modelica model as follows:
optimization Moo(objective=-x(finalTime), startTime = 0, finalTime = 12)
parameter Real e = 0.05;
Real x(start=2, fixed=true, min=0, max=100);
input Real v (min=0, max=1);
function omega
input Real t;
output Real y;
algorithm
y := e;
end omega;
equation
der(x) = v*omega(time);
constraint
v<=1;
end Moo;
I would like the variable e in the function omega to be a variable so that I can easily change its value at a later point in time when I am doing a parameter sweep. Unfortunately, the function omega does not seem to know about the variable e and the JModelica compiler returns the error:
Cannot find class or component declaration for e
I would naïvely expect that since omega and e belong to the same class omega would be able to see e.
Is there a way to achieve this?
Member functions are not supported in Modelica, so a function declared inside a model acts like a standalone function without having access to the surrounding model variables.
Member functions are not allowed due to functions need to be pure, i.e. they are not allowed to have any side effect. This is a fundamental assumption in Modelica that makes it possible for a tool to apply symbolic transformation and rearrange calculations.
You can have something like a member function, if you explicitly pass the needed variables as additional input to the function. See this example:
package MemberFunction
model A
Real x=1;
function get_x = MemberFunction.get(u=x);
end A;
function get
input Real u;
output Real y;
algorithm
y := u;
end get;
model Test
A a;
Real x;
equation
x = a.get_x();
end Test;
end MemberFunction;

Cross characteristics of a non-linear equation in Matlab

I'd like to create a Matlab plot of propeller angular velocity in terms of applied current. The point is, this requires combining two interdependent sets of data.
Firstly, drag coefficient c_d depends on angular velocity omega (I have no formula, just data) as seen on the plot below - the characteristics c_d(omega) could be easily linearised as c_d(omega) = p*omega + p_0.
Secondly, omega depends not only on applied current i, but also on the drag coefficient c_d(omega).
A script that solves the case, where c_d is constant below. It must be somehow possible to join those two using Matlab commands. Thanks for any help.
%%Lookup table for drag coefficient c_d
c_d_lookup = [248.9188579 0.036688351; %[\omega c_d]
280.2300647 0.037199094;
308.6091183 0.037199094;
338.6636881 0.03779496;
365.8908244 0.038305703;
393.9557188 0.039156941;
421.9158934 0.039667683;
452.2846224 0.040348674;
480.663676 0.041199911;
511.032405 0.042051149;
538.9925796 0.042561892;
567.2669135 0.043242882;
598.4734005 0.043668501;
624.1297405 0.044264368;
651.9851954 0.044604863;
683.6105614 0.045200729];
subplot(2,1,1)
plot(c_d_lookup(:,1), c_d_lookup(:,2))
title('This is how c_d depends on \omega')
ylabel('c_d')
xlabel('\omega [rad/s]')
%%Calculate propeller angular speed in terms of applied current. omega
%%depends on c_d, which in turn depends on omega. The formula is:
% omega(i) = sqrt(a*i / (b * c_d(omega)))
% Where:
% i - applied current
% omega - propeller angular velocity
% a,b - coefficients
i = [1:15];
a = 0.0718;
b = 3.8589e-005;
%If c_d was constant, I'd do:
omega_i = sqrt(a .* i / (b * 0.042));
subplot(2,1,2)
plot(i, omega_i)
ylabel({'Propeller ang. vel.', '\omega [rad/s]'})
xlabel('Applied current i[A]')
title('Propeller angular velocity in terms of applied current')
EDIT:
Trying to follow bdecaf's solution. So I created a function c_d_find, like so:
function c_d = c_d_find(omega, c_d_lookup)
c_d = interp1(c_d_lookup(:,1), c_d_lookup(:,2), omega, 'linear', 'extrap');
end
I don't know anything about Matlab function handles, but seem to understand the idea... In Matlab command window I typed:
f = #(omega) omega - sqrt(a .* i / (b * c_d_find(omega, c_d_lookup)))
which I hope created the correct function handle. What do I do next? Executing the below doesn't work:
>> omega_consistent = fzero(f,0)
??? Operands to the || and && operators must be convertible to logical scalar
values.
Error in ==> fzero at 333
elseif ~isfinite(fx) || ~isreal(fx)
hmmm...
Wonder if I understand correctly - but looks like you are looking for a consistent solution.
Your equations don't look to complicated I would outline the solution like this:
Write a function function c_d = c_d_find(omega) that does some interpolation or so
make a function handle like f = #(omega) omega - sqrt(a .* i / (b * c_d_find(omega))) - this is zero for consistent omega
calculate a consistent omega with omega_consistent =fzero(f,omega_0)

difference equations in MATLAB - why the need to switch signs?

Perhaps this is more of a math question than a MATLAB one, not really sure. I'm using MATLAB to compute an economic model - the New Hybrid ISLM model - and there's a confusing step where the author switches the sign of the solution.
First, the author declares symbolic variables and sets up a system of difference equations. Note that the suffixes "a" and "2t" both mean "time t+1", "2a" means "time t+2" and "t" means "time t":
%% --------------------------[2] MODEL proc-----------------------------%%
% Define endogenous vars ('a' denotes t+1 values)
syms y2a pi2a ya pia va y2t pi2t yt pit vt ;
% Monetary policy rule
ia = q1*ya+q2*pia;
% ia = q1*(ya-yt)+q2*pia; %%option speed limit policy
% Model equations
IS = rho*y2a+(1-rho)*yt-sigma*(ia-pi2a)-ya;
AS = beta*pi2a+(1-beta)*pit+alpha*ya-pia+va;
dum1 = ya-y2t;
dum2 = pia-pi2t;
MPs = phi*vt-va;
optcon = [IS ; AS ; dum1 ; dum2; MPs];
Edit: The equations that are going into the matrix, as they would appear in a textbook are as follows (curly braces indicate time period values, greek letters are parameters):
First equation:
y{t+1} = rho*y{t+2} + (1-rho)*y{t} - sigma*(i{t+1}-pi{t+2})
Second equation:
pi{t+1} = beta*pi{t+2} + (1-beta)*pi{t} + alpha*y{t+1} + v{t+1}
Third and fourth are dummies:
y{t+1} = y{t+1}
pi{t+1} = pi{t+1}
Fifth is simple:
v{t+1} = phi*v{t}
Moving on, the author computes the matrix A:
%% ------------------ [3] Linearization proc ------------------------%%
% Differentiation
xx = [y2a pi2a ya pia va y2t pi2t yt pit vt] ; % define vars
jopt = jacobian(optcon,xx);
% Define Linear Coefficients
coef = eval(jopt);
B = [ -coef(:,1:5) ] ;
C = [ coef(:,6:10) ] ;
% B[c(t+1) l(t+1) k(t+1) z(t+1)] = C[c(t) l(t) k(t) z(t)]
A = inv(C)*B ; %(Linearized reduced form )
As far as I understand, this A is the solution to the system. It's the matrix that turns time t+1 and t+2 variables into t and t+1 variables (it's a forward-looking model). My question is essentially why is it necessary to reverse the signs of all the partial derivatives in B in order to get this solution? I'm talking about this step:
B = [ -coef(:,1:5) ] ;
Reversing the sign here obviously reverses the sign of every component of A, but I don't have a clear understanding of why it's necessary. My apologies if the question is unclear or if this isn't the best place to ask.
I think the key is that the model is forward-looking, so the slopes (the partial derivatives) need to be reversed to go backward in time. One way to think of it is to say that the jacobian() function always calculates derivatives in the forward-time direction.
You've got an output vector of states called optcon = [IS;AS;dum1;dum2;MPs], and two vectors of input states [y2 pi2 y pi v]. The input vector at time t+1 is [y2a pi2a ya pia va], and the input vector at time t is [y2t pi2t yt pit vt]. These two are concatenated into a single vector for the call to jacobian(), then separated after. The same thing could have been done in two calls. The first 5 columns of the output of jacobian() are the partial derivatives of optcon with respect to the input vector at time t+1, and the second 5 columns are with respect to the input vector at time t.
In order to get the reduced form, you need to come up with two equations for optcon at time t+1. The second half of coef is just what is needed. But the first half of coef is the equation for optcon at time t+2. The trick is to reverse the signs of the partial derivatives to get linearized coefficients that take the input vector at t+1 to the output optcon at t+1.