3
$\begingroup$

I try to use BSplineFunction to creat a initial condition for NDSolve which has periodic boundary condition, that is realized by producing a coarse grid of random number:

ini = 1 + c*BSplineFunction[RandomReal[1, {30, 30, 1}], SplineClosed -> True];

SplineClosed -> True makes sure I can use it to consist with periodic boundary conditions in NDSolve.

I get into trouble: my BSplineFunction seems to be not a function of x and y. How can I describe it to be a function of x and y on a square domain with side length L (see my code)? I think that is the reason why NDSolve complains about when I try to use a spline surface acting as initial condition.

Working example:

Off[NDSolve::mxsst];
Clear["Global`*"]
L = 15;
c = -(1/20);
tmax = 1000;
a = 1/10;
b = 1;
m = 25;
ini = 1 + c*BSplineFunction[RandomReal[1, {30, 30, 1}], SplineClosed -> True];

sol = First[ h /. NDSolve[{D[h[x, y, t], t] +
Div[-a*h[x, y, t]^3*Grad[h[x, y, t], {x, y}], {x, y}] + 
Div[(b*m*h[x, y, t]^2*
Grad[h[x, y, t], {x, y}])/(2*(1 + b*h[x, y, t])^2), {x, y}] + 
Div[h[x, y, t]^3*Grad[Laplacian[h[x, y, t], {x, y}], {x, y}], {x, y}] == 0,
h[0, y, t] == h[L, y, t], h[x, 0, t] == h[x, L, t],
h[x, y, 0] == ini[x, y]},
h, {x, 0, L}, {y, 0, L}, {t, 0, tmax},
Method -> {"BDF", "MaxDifferenceOrder" -> 1}, 
MaxStepFraction -> 1/50]]

I have the following error:

NDSolve::ndnum: Encountered non-numerical value for a derivative at t == 0.`.

ReplaceAll::reps: "!({NDSolve[{<<1>>}, h, {x, 0, 15}, {y, 0, 15}, {t, 0, 1000}, Method -> {\"BDF\", \"MaxDifferenceOrder\" -> 1}, MaxStepFraction -> *FractionBox[(1), (50)]]}) is neither a list of replacement rules nor a valid dispatch table, and so cannot be used for replacing."

$\endgroup$
  • $\begingroup$ @Karsten7. Thanks. What is your mean by "fix" ini? I am confusing that when I try ini[0, 7] == ini[L, 7], MMA give me False. With SplineClosed -> True, I want to obtain a random disturbance which has periodicity at the sides of the square-domain [0,L]*[0,L], ini(0,y)=ini(L,y) and ini(x,0)=ini(x,L). With ur ini = 1 + c*BSplineFunction[RandomReal[1, {30, 30, 1}], SplineClosed -> True][##] &; NDSlove prompts >NDSolve`FiniteDifferenceDerivativeFunction::ddim: Data {{{0.993342},...,<<40>>,...,<<49>>,<<51>>} is not a rectangular tensor with dimensions {100,50}. How can I fix it? $\endgroup$ – Enter Mar 4 '15 at 3:35
  • $\begingroup$ The result of BSplineFunction is a parametric surface, with domain of each parameter normalized to $[0,1]$. $\endgroup$ – Silvia Oct 17 '15 at 14:41
1
$\begingroup$

In order to get an ini that will evaluate to a numerical value when evaluated as ini[x, y], one has to define it as

ini[x_, y_] = 1 + c*BSplineFunction[RandomReal[1, {30, 30, 1}], SplineClosed -> True][x, y]

It is important to use Set instead of SetDelayed in this case, as one doesn't want to use new random numbers every time ini is evaluated.
With this definition of ini

ini[0, 7] == ini[L, 7]
True

But one will get a new error when evaluating the rest of your code, because the output of ini is a List with a single entry instead of the single value expected by NDSolve. Therefore you have to replace

ini[x, y]

with

First@ini[x, y]

in your code for sol.


Edit:

Maybe

random = Table[{x, y, RandomReal[]}, {x, 0, L, L/10}, {y, 0, L, L/10}];
random[[All, -1, -1]] = random[[All, 1, -1]];
random[[-1, All, -1]] = random[[1, All, -1]];

iniIF = Interpolation[Flatten[random, 1]];
ini[x_, y_] := 1 + c*iniIF[x, y]

will be more in accordance with your intentions.
Or something like

ini[x_, y_] = 1 + c*BSplineFunction[RandomReal[1, {30, 30, 1}], 
  SplineClosed -> True][x/L, y/L]
$\endgroup$
  • $\begingroup$ @ Karsten7. I have read the link you provided. I guess you might miss something in ini[x_, y_] = 1 + c*BSplineFunction[RandomReal[1, {30, 30, 1}], SplineClosed -> True][x, y] during your copy&paste. Because when I use it by itself, I have this error: >Set::write: Tag Function in (1+c BSplineFunction[RandomReal[1,{30,30,1}],SplineClosed->True][##1]&)[x_,y_] is Protected. >> $\endgroup$ – Enter Mar 4 '15 at 5:32
  • $\begingroup$ @lxy You got that error because ini already has another definition. Please clear the old definition with Clear@ini and try again. $\endgroup$ – Karsten 7. Mar 4 '15 at 5:35
  • $\begingroup$ @ Karsten7. Yes, with Clear I get True. But, I have a bewilderment when I try L = 4 \[Pi]; c = -(1/20); ini[x_, y_] =1+c*BSplineFunction[RandomReal[1, {30, 30, 1}], SplineClosed -> True][x, y]; ini[0, 7] == ini[L, 7], MMA gives False. However, L = 12,or other integer it gives True. Very strange! $\endgroup$ – Enter Mar 4 '15 at 5:52
  • $\begingroup$ Maybe plotting ini´ will help to clarify: Plot[ini[x, 7], {x, 0, 15}]` & Plot3D[Flatten@ini[x, y], {x, 0, 15}, {y, 0, 15}]. Why should ini[0, 7] == ini[4 [Pi], 7] be True? $\endgroup$ – Karsten 7. Mar 4 '15 at 6:11
  • 1
    $\begingroup$ The error you describe in your last comment has nothing to do with ini. NSolve[NIntegrate[c1, {x, 0, L}, {y, 0, L}] == L^2, c1, Reals] would give you the same error. Try f1[c1_?NumericQ] := NIntegrate[c1 + ini[x, y], {x, 0, L}, {y, 0, L}] NMinimize[(f1[c1] - L^2)^2, c1] instead. $\endgroup$ – Karsten 7. Mar 4 '15 at 9:08

Not the answer you're looking for? Browse other questions tagged or ask your own question.