Embedding an fsolve into an ODE as opposed to using DAE solver in Scilab - scilab

I am trying to embed a Fsolve to solve this non-linear system in Scilab.
I have solved the problem with the DAE, so I know what to expect, but I am struggling with embedding the Fsolve.
Here is the full copy of the code, DAE included.
I'm not sure where to embed the fsolve function.
//dassl approach
//given data
p=[20.086, 8100, 20.086, 20.086, 4050, 1E-17, 1E-11, 1E-17] //mol/kgh
ynames = ['y1' 'y2' 'y3' 'y4' 'y5' 'y6' 'y7' 'y8' 'y9' 'y10']
y0=[1.5776, 0.32, 0, 0, 0, 0.0131, 4.0E-06, 4.0E-06, 0, 0]'//initial conditions
t0=0
t=linspace(0,1,1000)
dy0 = [0 0 0 0 0 0 0 0 0 0]'
function [f,r]=BatchRXorDassl(t,y,dy)
f(1)=-p(3)*y(2)*y(8)-dy(1)
f(2)=-p(1)*y(2)*y(6)+p(2)*y(10)-p(3)*y(2)*y(8)-dy(2)
f(3)=p(3)*y(2)*y(8)+p(4)*y(4)*y(6)-p(5)*y(9)-dy(3)
f(4)=-p(4)*y(4)*y(6)+p(5)*y(9)-dy(4)
f(5)=p(1)*y(2)*y(6)-p(2)*y(10)-dy(5)
f(6)=-p(1)*y(2)*y(6)-p(4)*y(4)*y(6)+p(2)*y(10)+p(5)*y(9)-dy(6)
f(7)=-0.0131+y(6)+y(8)+y(9)+y(10)-y(7)
f(8)=p(7)*y(1)-y(8)*(p(7)+y(7))
f(9)=p(8)*y(3)-y(9)*(p(8)+y(7))
f(10)=p(6)*y(5)-y(10)*(p(6)+y(7))
r=0
endfunction
y=dassl([y0,dy0],t0,t,BatchRXorDassl)
y=y'
tplot = y(:,1)
yplot = y(:,2:11)
clf(11), scf(11)
plot(tplot,yplot)
xlabel('t (s)')
ylabel('C')
legend(ynames,-4)
xtitle('Batch Reactor Concentration Profiles')
////embedded fsolve approach
////given data
//p=[20.086, 8100, 20.086, 20.086, 4050, 1E-17, 1E-11, 1E-17] //mol/kgh
//ynames = ['y1' 'y2' 'y3' 'y4' 'y5' 'y6' 'y7' 'y8' 'y9' 'y10']
//y0=[1.5776, 0.32, 0, 0, 0, 0.0131, 4.0E-06, 4.0E-06, 0, 0]'//initial conditions
//t0=0
//t=linspace(0,1,1000)
//function ff=fsolvve(y)
// y1 = y(1)
// y2 = y(2)
// y3 = y(3)
// y4 = y(4)
// y5 = y(5)
// y6 = y(6)
// y7 = y(7)
// y8 = y(8)
// y9 = y(9)
// y10 = y(10)
// ff(1) = -0.0131+y(6)+y(8)+y(9)+y(10)-y(7)
// ff(2) = p(7)*y(1)-y(8)*(p(7)+y(7))
// ff(3) = p(8)*y(3)-y(9)*(p(8)+y(7))
// ff(4) = p(6)*y(5)-y(10)*(p(6)+y(7))
// ff(5) = -p(3)*y(2)*y(8)
// ff(6) = -p(1)*y(2)*y(6)+p(2)*y(10)-p(3)*y(2)*y(8)
// ff(7) = p(3)*y(2)*y(8)+p(4)*y(4)*y(6)-p(5)*y(9)
// ff(8) = -p(4)*y(4)*y(6)+p(5)*y(9)
// ff(9) = p(1)*y(2)*y(6)-p(2)*y(10)
// ff(10) = -p(1)*y(2)*y(6)-p(4)*y(4)*y(6)+p(2)*y(10)+p(5)*y(9)
//endfunction
//yfsolve0 = [0 0 0 0 0 0 0 0 0 0]'
//yfsolve = fsolve(yfsolve0,fsolvve)

The following code does what you want if you considerably relax the default RTOL and ATOL of ode:
p = [20.086, 8100, 20.086, 20.086, 4050, 1E-17, 1E-11, 1E-17] //mol/kgh
ynames = ['y1' 'y2' 'y3' 'y4' 'y5' 'y6' 'y7' 'y8' 'y9' 'y10']
y0 = [1.5776, 0.32, 0, 0, 0, 0.0131, 4.0E-06, 4.0E-06, 0, 0]'//initial condition
t0 = 0
t = linspace(0,1,1000)
function dy = rhs(t,y1)
y2 = fsolve([1;1;1;1],list(cstr,y1));
y = [y1;y2];
dy = [-p(3)*y(2)*y(8)
p(1)*y(2)*y(6)+p(2)*y(10)-p(3)*y(2)*y(8)
p(3)*y(2)*y(8)+p(4)*y(4)*y(6)-p(5)*y(9)
-p(4)*y(4)*y(6)+p(5)*y(9)
p(1)*y(2)*y(6)-p(2)*y(10)
-p(1)*y(2)*y(6)-p(4)*y(4)*y(6)+p(2)*y(10)+p(5)*y(9)];
endfunction
function g = cstr(y2,y1)
g = [-0.0131+y1(6)+y2(2)+y2(3)+y2(4)-y2(1)
p(7)*y1(1)-y2(2)*(p(7)+y2(1))
p(8)*y1(3)-y2(3)*(p(8)+y2(1))
p(6)*y1(5)-y2(4)*(p(6)+y2(1))];
endfunction
y1 = ode(y0(1:6),t0,t,1e-3,1e-3,rhs)
Having to do that show that it is nonsense to proceed that way. Please realize that fsolve uses an iterative algorithm and that with this approach you even cannot even take an adequate initial vector for it. If you absolutely want to use ode I can propose a much better approach using implicit differentiation.

Related

How to move object across axis?

I have an interactive plot and I want to move topoplot position across the x-axis according to the slider (or red vertical bar) position.
How can I do that?
In an ideal situation, the topoplot moves until some border (so it would be partially out of the screen).
Also, is it possible to put a line connecting the topolot with a red vertical line?
This is my script with prerequisite functions:
using Makie
using GLMakie
using PyMNE
using JLD2 # loading data
using TopoPlots
using StatsBase # mean/std
using Pipe
using ColorSchemes
using Colors
using LinearAlgebra
function eegHeadMatrix(positions, center, radius)
oldCenter = mean(positions)
oldRadius, _ = findmax(x-> LinearAlgebra.norm(x .- oldCenter),
positions)
radF = radius/oldRadius
return Makie.Mat4f(radF, 0, 0, 0,
0, radF, 0, 0,
0, 0, 1, 0,
center[1]-oldCenter[1]*radF, center[2]-
oldCenter[2]*radF, 0, 1)
end
struct NullInterpolator <: TopoPlots.Interpolator
end
function (ni::NullInterpolator)(
xrange::LinRange, yrange::LinRange,
positions::AbstractVector{<: Point{2}}, data::AbstractVector{<:Number})
return zeros(length(xrange),length(yrange))
end
function posToColor(pos)
cx = 0.5 - pos[1]
cy = 0.5 - pos[2]
rx = cx * 0.7071068 + cy * 0.7071068
ry = cx * -0.7071068 + cy * 0.7071068
b = 1.0 - (2*sqrt(cx^2+cy^2))^2
return RGB(0.5 - rx*1.414, 0.5 - ry*1.414, b)
end
This is the main function
f = Figure(backgroundcolor = RGBf(0.98, 0.98, 0.98), resolution = (1500, 700))
# interaction
xs = range(-0.3, length=size(dat_e, 2), step=1 ./ 128)
sg = SliderGrid(f[4, 1:2],
(label="time", range=xs, format = "{:.3f} ms", startvalue = 0),
)
time = sg.sliders[1].value
str = lift(t -> "[$(round(t, digits = 3)) ms]", time)
topo_slice = lift((t, data) -> mean(data[1:30, indexin(t, xs), :], dims=2)[:,1], time, dat_e)
# butterfly plot
ax = Axis(f[2:3, 1:2], xlabel = "Time [s]", ylabel = "Voltage amplitude [µV]")
N = 1:length(pos) #1:4
hidespines!(ax, :t, :r)
GLMakie.xlims!(-0.3, 1.2)
hlines!(0, color = :gray, linewidth = 1)
vlines!(0, color = :gray, linewidth = 1)
times = range(-0.3, length=size(dat_e,2), step=1 ./ 128)
specialColors = ColorScheme(vcat(RGB(1,1,1.),[posToColor(pos) for pos in pos[N]]...))
for i in N
mean_trial = mean(dat_e[i,:,:], dims=2)[:,1]
lines!(times, mean_trial, color = specialColors[i])
end
hidedecorations!(ax, label = false, ticks = false, ticklabels = false)
# text
vlines!(time, color = :red, linewidth = 1)
text!(time, 8, text = str, align = (:center, :center))
# topoplot
topo_axis = Axis(f[1, 1:2], width = 178, height = 178, aspect = DataAspect())
Makie.xlims!(low = -0.2, high = 1.2)
Makie.ylims!(low = -0.2, high = 1.2)
topoMatrix = eegHeadMatrix(pos[N], (0.5, 0.5), 0.5)
topo = eeg_topoplot!(topo_axis, topo_slice, # averaging all trial of 30 participants on Xth msec
raw.ch_names[1:30];
positions=pos, # produced automatically from ch_names
#interpolation=DelaunayMesh(),
enlarge=1,
extrapolation=GeomExtrapolation(enlarge=1.0, geometry=Circle),
label_text=false)
hidedecorations!(current_axis())
hidespines!(current_axis())
f

Boundary constrain leads to internal loop, what happens here and why?

My Script ceases to work for my easy conduction problem. Could somebody explain to me why the following line of code T.faceValue.constrain(alp/lam*(Tu-T.faceValue),where=mesh.exteriorFaces) # Boundary Condition for Solver results in fipy giving up on me?
Full Code:
cv=900.
lam=5.
alp=300.
T0 = 25.
Tu = 400.
cellSize = 0.05
radius = 1.
mesh = Gmsh2D('''
cellSize = %(cellSize)g;
radius = %(radius)g;
Point(1) = {0, 0, 0, cellSize};
Point(2) = {-radius, 0, 0, cellSize};
Point(3) = {0, radius, 0, cellSize};
Point(4) = {radius, 0, 0, cellSize};
Point(5) = {0, -radius, 0, cellSize};
Circle(6) = {2, 1, 3};
Circle(7) = {3, 1, 4};
Circle(8) = {4, 1, 5};
Circle(9) = {5, 1, 2};
Line Loop(10) = {6, 7, 8, 9};
Plane Surface(11) = {10};
''' % locals()) # doctest: +GMSH
T = CellVariable(name = "HeatingUp",mesh = mesh,value = T0)
viewer = None
if __name__ == '__main__':
try:
viewer = Viewer(vars=T, datamin=T0, datamax=Tu)
viewer.plotMesh()
input("Irregular circular mesh. Press <return> to proceed") # doctest: +GMSH
except:
print("Unable to create a viewer for an irregular mesh (try Matplotlib2DViewer or MayaviViewer)")
# =============================================================================
eq = TransientTerm(coeff=rho*cv)==DiffusionTerm(coeff=lam)
T.faceValue.constrain(alp/lam*(Tu-T.faceValue),where=mesh.exteriorFaces) # Boundary Condition for Solver
timeStepDuration = 0.1
steps = 10
for step in range(steps):
eq.solve(var=T, dt=timeStepDuration) # doctest: +GMSH
if viewer is not None:
viewer.plot() # doctest: +GMSH
``
You've written that T.faceValue depends on T.faceValue, which depends on T.faceValue, which depends on T.faceValue, ... FiPy has dutifully provided you with the infinite loop that you requested.
Just write T.faceValue.constrain(Tu * (alp/lam) / (1 + alp/lam), where=mesh.exteriorFaces).
In the more likely event that you wanted to relate the gradient to the value at the boundary, please see the discussion on Robin conditions.

How to Set a User-Defined Colormap in Octave?

I have a trivial piece of code that calculates some quantity and plots it as contours:
%Calculate Biot number vs. h for a selected material
h = (0:5:1000)';
mat = "Copper";
lambda = 386;
r = (0:0.25:50); %In cm
R = r./100; %In m
%Calculate matrix of Bi values
% R = length(h) x C = length(r)
Bi = (h.*R)/lambda;
%Contour Plot of results
%Set boundaries at Bi = 0, 0.1, 1
conts = [0, 0.1, 1];
ptitle = ["Biot Number for a ", mat, " Sphere"];
%Create a personalized colormap with 30 values.
% 0<Bi<0.1 Green
% 0.1<=Bi<1 Yellow
% Bi >= 1 Red
my_green = [229,255,204]./255;
my_yellow = [255,255,204]./255;
my_pink = [255,229,204]./255;
my_cmap = [repmat(my_green, 10, 1); repmat(my_yellow, 10, 1); repmat(my_pink, 10, 1) ];
clf;
colormap (my_cmap);
contourf(h, r, Bi, conts, 'showtext', 'on');
title(ptitle)
xlabel ("h(W/m^2*K)");
ylabel ("r(cm)");
The result is missing the intermediate color (yellow):
What can be done about this?
You have too few contours, so the wrong color is chosen. If you do contourf(h, r, Bi, 0:0.2:1, 'showtext', 'on'); you get:
Also, I'd suggest to make the "green" and the "yellow" more different, as it might be difficult to differentiate them on some displays.
Here's what I meant by "playing around with L, M, N:
conts = [0, 0.1, 1];
ptitle = ["Biot Number for a ", mat, " Sphere"];
%Create a personalized colormap
my_green = [229,255,204]./255;
my_yellow = [255,255,204]./255;
my_pink = [255,229,204]./255;
my_cmap = [repmat(my_green, 10, 1); repmat(my_yellow, 90, 1); repmat(my_pink, 1, 1) ];
figure(); contourf(h, r, Bi, conts, 'showtext', 'on');
colormap (my_cmap);
caxis([0 1.01])
title(ptitle)
xlabel ("h(W/m^2*K)");
ylabel ("r(cm)");
BTW, I ran this on MATLAB R2018a in case you're wondering why you're not getting the exact same thing.
Adding the code below to define countours and to generate the colormap, the process can be automated.
conts = [0, 0.05, 0.1, 0.3, 0.7, 1];
%Create a personalized colormap with 50 values distributed proportionally to Bi values
step = 50/max(max(Bi));
L = ceil(step*0.1);
M = ceil(step*(1-0.1));
H = ceil(step*(max(max(Bi))-1));
my_green = [229,255,204]./255;
my_yellow = [255,255,204]./255;
my_pink = [255,229,204]./255;
my_cmap = [repmat(my_green, L, 1); repmat(my_yellow, M, 1); repmat(my_pink, H, 1)];
Obtaining:

Trapezoid Integration in Scilab - Polygon Color Fill Stops

I have been working on a program in Scilab that numerically integrates a function by the trapezoidal rule (without using the built-in function). I have no problem with the integration or plotting the function, but I want to overlay the real function on a plot of the trapezoids, colored in.
For some reason, when I set the bounds a = 0 to b = 3, no problem, I get exactly what I want. However, when I set the bounds above 3, the trapezoids will still plot (by lines), but they won't be colored in. In the code below, the color stops at 3. If I plot 0 to 6, for example, the color stops half-way through. 3 to 6, and there is no color at all.
Here are the relevant sections of code:
deff('[y] = f(x)','y = e^(x^2)'); // Definition of function
a = 0; // Lower bound
b = 4; // Upper bound
n = 20; // Number of intervals
h = ((b - a)/n); // Interval spacing
x = a:h:b; // Array of positions for division
and
for i = 1:n+1
y(i) = f(x(i));
end
and
for i = 1:n // Plot colored trapezoids
x_start = a+(h*(i-1));
x_end = a+(h*(i));
y_start = y(i);
y_end = y(i+1);
xpts = [x_start, x_end, x_end, x_start];
ypts = [y_start, y_end, 0, 0];
xfpoly(xpts,ypts,3);
end
This is the plot output for a = 0, b = 3
What version of Scilab are you using?
I tried your code with Scilab 5.4.1 (64bit) and I got uncolored trapezoids, but with 5.5.2 (64bit) all the shapes are nice green.
So maybe there was some bugfix between these versions.
I also changed your function definition from 'y = e^(x^2)' to 'y = %e^(x^2)' since the Euler number is a predefined variable (at least in 5.5.2).
clc;
clear;
deff('[y] = f(x)','y = %e^(x^2)'); // Definition of function
a = 0; // Lower bound
b = 6; // Upper bound
n = 100; // Number of intervals
h = ((b - a)/n); // Interval spacing
x = a:h:b; // Array of positions for division
for i = 1:n+1
y(i) = f(x(i));
end
scf(0);
clf(0);
plot2d(x,y);
for i = 1:n // Plot colored trapezoids
x_start = a+(h*(i-1));
x_end = a+(h*(i));
y_start = y(i);
y_end = y(i+1);
xpts = [x_start, x_end, x_end, x_start];
ypts = [y_start, y_end, 0, 0];
xfpoly(xpts,ypts,3);
end

Reset margins in the wireframe plot using lattice R package

I am trying to plot a 3D graph in lattice using wireframe. I want to reset the margins between the 3d plot and the R window,
The top margins is too big and this wastes lots of space when I convert it into postscript files. I am trying to reduce to margins.
I tried the following R code par(mar=c(4,3,3,1)+0.1).
However nothing is happening.
Try this snippet, adapted from https://stat.ethz.ch/pipermail/r-help/2007-January/123556.html. It worked for me.
library(lattice)
theme.novpadding <- list(
layout.heights = list(
top.padding = 0,
main.key.padding = 0,
key.axis.padding = 0,
axis.xlab.padding = 0,
xlab.key.padding = 0,
key.sub.padding = 0,
bottom.padding = 0
),
layout.widths = list(
left.padding = 0,
key.ylab.padding = 0,
ylab.axis.padding = 0,
axis.key.padding = 0,
right.padding = 0
)
)
wireframe(volcano, shade = TRUE,
aspect = c(61/87, 0.4),
#par.settings = theme.novpadding, # uncomment this
light.source = c(10,0,10))

Resources