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

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.

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

How to interact with plot using keyboard arros?

My interactive plot (topoplot) reacts to mouse signals, but how to make it reacting to keyboard signals?
Here is my code:
f = Figure()
xs = 1:1:193 #range(-30, 120, length = size(dat_e, 2))
sg = SliderGrid(f[2, 1],
(label="time", range=xs, format = "{:d} ms", startvalue = 100),
)
time = sg.sliders[1].value
str = lift(t -> "[$t ms]", time)
topo_slice = lift((t, data) -> mean(data[1:30, t, :], dims=2)[:,1], time, dat_e)
topo_axis = Axis(f[1, 1], aspect = DataAspect())
topo = eeg_topoplot!(topo_axis, topo_slice,
raw.ch_names[1:30];
positions=pos, # produced automatically from ch_names
label_text=true) # aspect ratio, correlation of height and width
text!(topo_axis, 1, 1, text = str, align = (:center, :center))
#topo_slice = lift((t, data) -> data[:, :, t], time, topo)
xlims!(-0.2, 1.1)
ylims!(-0.2, 1.2)
hidedecorations!(topo_axis)
hidespines!(topo_axis)
f
There is an official instruction https://docs.juliahub.com/AbstractPlotting/6fydZ/0.12.11/interaction.html, but as usual with Julia documentations, there is no example and I have no idea how implement it in my code.
How my plot looks like:
Expanding on the answer from before:
T = 10
pts = range(-1, 1, length=100)
ts = reshape(1:T, 1, 1, :)
topo = cos.(pts) .+ cos.(ts .* pts')
fig = Figure()
ax = Axis(fig[1, 1])
sg = SliderGrid(fig[2,1],
(label="time", range=1:T))
time = sg.sliders[1].value
str = lift(t -> "[$t ms]", time)
text!(ax, str)
topo_slice = lift((t, data) -> data[:, :, t], time, topo)
# decrement/increment slider with left/right keys
on(events(fig).keyboardbutton) do btn
if btn.action in (Keyboard.press, Keyboard.repeat)
if btn.key == Keyboard.left
set_close_to!(sg.sliders[1], time[] - 1)
elseif btn.key == Keyboard.right
set_close_to!(sg.sliders[1], time[] + 1)
end
end
end
contour!(ax, topo_slice)
hidedecorations!(ax)
hidespines!(ax)
fig

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

White area in Mathematica ListPlot

When I create and plot this list:
var = 2;
okList = {{0.8, var, 0.8, 0.8}, {0, 0.3, 0.6, 0.9}, {0, 1, 2, 3}};
lp = ListDensityPlot[okList, ColorFunction -> "SandyTerrain"]
or, unscaled, like this:
lp = ListDensityPlot[okList, ColorFunction -> "SandyTerrain",
ColorFunctionScaling -> False]
I get a fully coloured square, as I'd expect.
But when I try this:
var = 0.8;
list = {{0.8, var, 0.8, 0.8}, {0, 0.3, 0.6, 0.9}, {0, 1, 2, 3}};
problem = ListDensityPlot[list, ColorFunction -> "SandyTerrain"]
I get a white patch in the corner.
which plotting with ColorFunctionScaling->False doesn't get rid of
The ColorFunction SandyTerrain doesn't have any white in it, so this must be ListDensityPlot not plotting anything in that area.
What could cause this to happen, and how do I stop it?
It's getting clipped by the automatic plot range calculation. Try with PlotRange -> All or ClippingStyle -> Automatic.

Resources