Full Multigrid Cycle
But first: the full multigrid algorithm (FMG).
So now that we've seen how to make a v-cycle, how can we make it so that we need only run the algorithm once, rather than running it many times and waiting for convergence? The answer lies with the first guess. The answer to this problem greatly depends on the initial conditions on the grid; if those initial conditions are set 'properly', then the convergence should be instant.
A trivial example: in the original equation, Del U = F, if we set U to zero when F is zero, our first guess is the right answer.
But how do we get there?
Well, if we start off at the coarsest possible level on the grid, and solve the problem there, we'll have a very coarse solution. If we then interpolate that answer to the next finer level, we'll get a slightly less coarse solution. Of course, to solve that slightly less coarse grid level, we'll just do a regular v-cycle, using residuals and everything that we did before. So, by the third-coarsest level, we use the result from the second-coarsest level as the start, and then solve via a v-cycle.
The claim is that, if done properly (ie, if the upconversion from coarse to fine level is done with at least tricubic interpolation for a second-order derivative approximation), the coarse-to-fine guesses will converge to a reasonable solution within 1 iteration.
Some code:
function outGuess = FullMultiGridSolver(inSize, inNumSteps, inF)
%at each level, the solution is accomplished by a call to
%ComplexMultiGridSolver, and the up interpolation is accomplished
%by CubicInterpolator.
theRealSize = inSize+1;
if (inNumSteps == 0)
%just solve it if it's that small
%guess at rand, and then go from there
rand('seed', 40234513);
theGuess = rand(theRealSize);
for i = 1:10000theGuess = GaussSeidelStep(theGuess, ...
zeros(max(size(theGuess))), inF);
end; % really, could just solve this directly; but this will be %fast enough
outGuess = theGuess
else
%ok, now just call the full multigrid solver, interpolate the
%result, solve it, and then return.
theFSubsample = Generate2xSubsample(inF);
theGuess = FullMultiGridSolver(inSize/2, inNumSteps-1, theFSubsample);
theUpsampleGuess = CubicInterpolator(theGuess);
theUpsampleGuess = SimpleMultiGridSolver(theUpsampleGuess, ...
inF, inNumSteps);
outGuess = theUpsampleGuess;
end
So, some to go with that, you'll need the Cubic Interpolation:
function outResult = CubicInterpolator(inGrid)
%does a cubic interpolation on interior points, and linear
%interpolation near the edges, in order to create a new guess for the
%'next level up' in the fullmultigrid solver
sizes = size(inGrid);
for i = 1:sizes(1)
for j = 1:sizes(2)outResult((i-1)*2+1, (j-1)*2+1) = inGrid(i, j);
end;
end;
%interpolate in one direction
[newX, newY] = size(inGrid);
newX = (newX-1) *2+1;
newY = (newY-1) *2+1;
denominator = 1/16;
for i = 1:2:newX
j = 2;
outResult(i, j) = 0.5*(outResult(i, j-1)+ outResult(i, j+1));
j = newY-1;
outResult(i, j) = 0.5*(outResult(i, j-1)+ outResult(i, j+1));
end;
for i = 1:2:newX
for j = 4:2:newY-3outResult(i, j) = denominator*(-1*outResult(i, j-3)+ 9*outResult(i, j+1) + ...
9*outResult(i, j-1)+ -1*outResult(i, j+3));
end;
end;
% now t'other
for (j = 1:newY)
i = 2;outResult(i, j) = 0.5*(outResult(i-1, j)+ outResult(i+1, j));
outResult(i, j) = 0.5*(outResult(i-1, j)+ outResult(i+1, j));
i = newX - 1;
end
for i = 4:2:newX-3
for j = 1:newYoutResult(i, j) = denominator*(-1*outResult(i-3, j)+ 9*outResult(i+1, j) + ...
9*outResult(i-1, j)+ -1*outResult(i+3, j));
end;
end;
A slight modification needs to be made to the SimpleMultiGridSolver code in order to work with this code; I leave that as an 'exercise to the reader' (basically, you need to change the return code to be the guess itself as a result of the iteration, rather than the other stuff from before).


