Skip to main content

differential equations - NDSolve in NIntegrate function, numerical values as a symbolic variables


I'm trying to implement the following iterative scheme $g_{n+1}=g_n-\int_0^t\Phi(g_n) dt$, where $g_n$ is a source term in a PDE and $\Phi$ is the solution of an adjoit problem associated to the PDE which use the solution of the PDE as final data. to this aim we need many steps :



0) Take $g_0=0$.


1) Solve the PDE to obtain the solution $u(t,x,g_n)$.


2) Solve the adjoint PDE to obtain $\Phi(t,x,g_n)$.


3) Calculate $g_{n+1}(x)=g_n(x)-\int_0^t\Phi(t,x,g_n) dt$, and go to 1).




I tried this one


nsol = NDSolve[{D[u[t, x], t] == D[u[t, x], x, x] + #, u[0, x] == 1, 
u[t, 0] == u[t, 1] == 1}, u, {t, 0, 1}, {x, 0, 1}] &; (* Solve the pde with source # *)

nasol = NDSolve[{D[v[t, x], t] == -D[v[t, x], x, x],
v[1, x] == First[u[1, x] /. nsol[#]] - umes[x],
v[t, 0] == v[t, 1] == -0.05}, v, {t, 0, 1}, {x, 0, 1}] &; (* Solve the adjont problem *)

Phi := NIntegrate[Evaluate[First[v[t, #2] /. nasol[#1[x]]]], {t, 0, 1}]&;

(* Calculate the integral in step 3). Here is the problem !!*)

g[0][x_] := 0;
umes[x_] := First[u[1, x] /. nsol[g[0][x]]] + 0.05;
g[n_Integer?Positive][x_] := g[n - 1][x] - Phi[g[n - 1], x];(* iteration *)

Now when I test the program, it seems to work in a good way


In[68]:= Phi[g[0], 0.1]
Out[68]= -0.05
In[70]:= g[1][0.1]

Out[70]= 0.05

To turn the loop for calculating the function $g_2$ we need to put $g_1$ in step 1) and here is the problem : The functions Phi[g[1],x] is just a numerical function and not working for symbolic variable $x$ because of the NIntegrate. Hence, the same problem for g[1][x].


Here is the Mathematica error


In[80]:= Phi[g[0], x]


NIntegrate::inumr: The integrand <<1>> has evaluated to non-numerical values for all sampling points in the region with boundaries {{0,0.0547861}}.



I tried to use NumericQ for the variables but still not working. Also, I don't get how to close the loop using stopping condition like Norm[Phi(g[n][x],x]]<10^{-6}.



Finally, I notice that I'm new to Mathematica. Thanks for any help.



Answer



I show an algorithm for solving such problems. Calculation back is eliminated by replacing t'->-t, {-1,0}->{0,1}:


g[0][x_] := .01*x; n = 5;

Do[nsol[i] =
NDSolveValue[{D[u[t, x], t] == D[u[t, x], x, x] + g[i - 1][x],
u[0, x] == 1, u[t, 0] == 1, u[t, 1] == 1},
u, {t, 0, 1}, {x, 0, 1}];
nasol[i] =

NDSolveValue[{D[v[t, x], t] == D[v[t, x], x, x],
v[0, x] == nsol[i][1, x] - nsol[1][1, x] - .05, v[t, 0] == -.05,
v[t, 1] == -0.05}, v, {t, 0, 1}, {x, 0, 1}];
g[i] = Interpolation[
Table[{x, g[i - 1][x] - NIntegrate[nasol[i][t, x], {t, 0, 1}]}, {x,
0, 1, .1}]];, {i, 1, n}]



{Plot[Evaluate[Table[g[i][x], {i, 0, n}]], {x, 0, 1},

AxesLabel -> {"x", "g"}],
Plot3D[nsol[n][t, x], {t, 0, 1}, {x, 0, 1}, Mesh -> None,
ColorFunction -> Hue, AxesLabel -> {"t", "x", ""},
PlotLabel -> "nsol[n]"],
Plot3D[nasol[n][t, x], {t, 0, 1}, {x, 0, 1}, Mesh -> None,
ColorFunction -> Hue, AxesLabel -> {"t", "x", ""},
PlotLabel -> "nasol[n]", PlotRange -> All]}

fig1


In the case of 2D +1, we use summation instead of the NIntegrate[]. In this example npoints=8.



<< NumericalDifferentialEquationAnalysis`
gl[npoints_] :=
Block[{npo = npoints}, {pts, w} =
Transpose[GaussianQuadratureWeights[npo, 0, 1]]; {w, pts, npo}]

f[x_, y_] := 1; (* The exact source term to be constructed *)
Plot3D[f[t, x], {t, 0, 1}, {x, 0, 1},
ColorFunction -> "TemperatureMap", AxesLabel -> {"t", "x", ""},
PlotLabel -> "Source term f(x,y)", PlotLegends -> Automatic]


nsoleq = NDSolveValue[{D[u[t, x, y], t] ==
D[u[t, x, y], x, x] + D[u[t, x, y], y, y] + f[x, y],
u[0, x, y] == 0, u[t, x, 0] == 0, u[t, 0, y] == 0,
u[t, x, 1] == 0, u[t, 1, y] == 0},
u, {t, 0, 1}, {x, 0, 1}, {y, 0,
1}]; (* nsoleq[1,x,y] is the observation used in construction of \
the source term *)
Plot3D[nsoleq[1, x, y], {x, 0, 1}, {y, 0, 1},
ColorFunction -> "TemperatureMap", AxesLabel -> {"x", "y", ""},
PlotLabel -> "t=1", PlotLegends -> Automatic]

g[0][x_, y_] := 0.; (* Initialization of the iteration *)



With[{np0 = 16, np1 = .05, n = 40},
Do[nsol[i] =
NDSolveValue[{D[u[t, x, y], t] ==
D[u[t, x, y], x, x] + D[u[t, x, y], y, y] + g[i - 1][x, y],
u[0, x, y] == 0, u[t, x, 0] == 0, u[t, 0, y] == 0,
u[t, x, 1] == 0, u[t, 1, y] == 0},

u, {t, 0, 1}, {x, 0, 1}, {y, 0, 1}];

nasol[i] =
NDSolveValue[{D[v[t, x, y], t] ==
D[v[t, x, y], x, x] + D[v[t, x, y], y, y],
v[0, x, y] == nsol[i][1, x, y] - nsoleq[1, x, y],
v[t, x, 0] == 0, v[t, 0, y] == 0, v[t, x, 1] == 0,
v[t, 1, y] == 0}, v, {t, 0, 1}, {x, 0, 1}, {y, 0, 1},
Method -> {"MethodOfLines",
"SpatialDiscretization" -> {"TensorProductGrid",

"MinPoints" -> 5*15 + 1, "MaxPoints" -> 5*15 + 1,
"DifferenceOrder" -> Automatic}}];
pp = Interpolation[
Chop[Flatten[
Table[{{x, y},
Sum[nasol[i][gl[np0][[2]][[j]], x, y]*gl[np0][[1]][[j]], {j,
1, np0}]}, {x, 0, 1, np1}, {y, 0, 1, np1}], 1]]];
p[i][x_, y_] := pp[x, y] + 0.000001*g[i - 1][x, y];
nsol1[i] =
NDSolveValue[{D[u[t, x, y], t] ==

D[u[t, x, y], x, x] + D[u[t, x, y], y, y] + p[i][x, y],
u[0, x, y] == 0, u[t, x, 0] == 0, u[t, 0, y] == 0,
u[t, x, 1] == 0, u[t, 1, y] == 0},
u, {t, 0, 1}, {x, 0, 1}, {y, 0, 1}];
a[i] = (NIntegrate[
p[i][x, y]^2, {x, 0, 1}, {y, 0,
1}])/(NIntegrate[(nsol1[i][1, x, y])^2, {x, 0, 1}, {y, 0, 1}]);
g[i] = Interpolation[
Flatten[Table[{{x, y}, g[i - 1][x, y] - a[i]*(p[i][x, y])}, {x, 0,
1, np1}, {y, 0, 1, np1}], 1]]; npr = i;

If[Abs[g[i][.5, .5] - g[i - 1][.5, .5]] <= 10^-5, Break[]], {i, 1,
n}]]
{Plot3D[f[x, y], {x, 0, 1}, {y, 0, 1}, PlotLabel -> "Exact Source"],
Plot3D[g[n][x, y], {x, 0, 1}, {y, 0, 1},
PlotLabel -> "Constructed Source", PlotRange -> All]}

fig2


Comments

Popular posts from this blog

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...

dynamic - How can I make a clickable ArrayPlot that returns input?

I would like to create a dynamic ArrayPlot so that the rectangles, when clicked, provide the input. Can I use ArrayPlot for this? Or is there something else I should have to use? Answer ArrayPlot is much more than just a simple array like Grid : it represents a ranged 2D dataset, and its visualization can be finetuned by options like DataReversed and DataRange . These features make it quite complicated to reproduce the same layout and order with Grid . Here I offer AnnotatedArrayPlot which comes in handy when your dataset is more than just a flat 2D array. The dynamic interface allows highlighting individual cells and possibly interacting with them. AnnotatedArrayPlot works the same way as ArrayPlot and accepts the same options plus Enabled , HighlightCoordinates , HighlightStyle and HighlightElementFunction . data = {{Missing["HasSomeMoreData"], GrayLevel[ 1], {RGBColor[0, 1, 1], RGBColor[0, 0, 1], GrayLevel[1]}, RGBColor[0, 1, 0]}, {GrayLevel[0], GrayLevel...

Is there a way to do conditional matrix loop using 'continue'

I have the following: n = 3; m = 5; ww = RandomReal[{0, 0.1}, {n, n}]; uu = RandomReal[{0, 1}, {m, n}]; pp = RandomReal[{0, 1}, {n, n}]; ss = RandomInteger[{0, 5}, {m, n}]; Grid[{{"ww", "uu", "pp", "ss"}, {ww // TableForm, uu // TableForm, pp // TableForm, ss // TableForm}}, Spacings -> {5, 2}, Dividers -> All] where I would like to look at every element of matrix ss and produce a matrix tt , with zeroes at the locations in ss which have zeroes, and in all other positions do the following: tt = (-1/Subscript[ww, m]) Log[(1 - uu)/(Subscript[pp, m - 1])], where Subscript[ww, m] is the value at index of ww matrix and where Subscript[pp, m - 1] is the value at index-1 of pp matrix. So for example if the first value ever read from matrix ss happens to be 2, then value taken from matrix ww would be from the row 2, but from pp would be from row 1. Also how to tell difference between a 0 as a valid value from within the matrix elemen...