带有 FAS 校正的 MGRIT 算法

       ANSYS FLUENT 12.0 Theory Guide - 18.6.4 Full-Approximation Storage (FAS) Multigrid (enea.it)

        多重网格时间规约算法(MGRIT)允许对时间演化微分方程的求解进行时间域并行化。该过程基于多重网格规约技术:更多信息可以在原始MGRIT论文中找到: [1] "Parallel time integration with multigrid", R. Falgout, S. Friedhoff, Tz. V. Kolev, S. P. MacLachlan, and J. B. Schroder (https://computation.llnl.gov/projects/parallel-time-integration-multigrid/mgritPaper-2013-3.pdf)

% In short, the technique is rooted in multigrid reduction: the temporal
% nodes are divided in "Fine" and "Coarse":
% C   F   F   F   C   F   F   F   C   F   F   F   C
% o---x---x---x---o---x---x---x---o---x---x---x---o---> t
% t0  t1  t2  t3  t4  ...                         tf

       时间节点分为“细”和“粗”:两个连续 C 节点(例如,[t0, t4])之间的跨度定义了一个时间块。给定C节点的解,可以通过时间步进(F 松弛)恢复内部 F 节点的解,这个过程对于每个时间块是独立的。这就是时间并行化的潜力所在,因为不同的处理器可以并行地对不同的时间块进行积分。

        C 节点可以再次分为细和粗,做到真正的多重网格过程。在最粗层次上,解通过顺序应用时间步进程序(可能与较细层次使用的不同,在更大的时间步上定义)恢复。层次之间的对话通过逐点注入(限制)和注入+F松弛(插值)完成。非线性方程还实现了 FAS 校正方案。在所有层次上,可以应用F或FCF松弛。整个过程反复进行。

        此代码仅限于均匀时间网格,但仍然相当优化且灵活。特别是:

  • 已收敛的时间块不会被重新计算。(每次应用 F 松弛时,一个更多的时间块达到收敛。算法跟踪这一点并避免冗余计算)。请注意,规定的最大迭代次数不应超过每个 cycle 应用的F松弛次数(算法在这方面不检查收敛性)。
  • 可以规定任何可选择的多重网格 cycle。
  • 可以在不同层次上规定不同的时间步进器。
%% Initialisation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

verbose = false;

% Initialise multigrid cycle info:
maxLvl = length(NT);
% - here we generate a list of numbers identifying at which order the levels need to be visited,
%    and which action needs to be performed. The code is:
%    - i->i  : smooth   -> ex: 1-s-1
%    - i->i+1: restrict -> ex: 1-r-2
%    - i->i-1: correct  -> ex: 2-c-1
%    - i=maxLvl: direct solve
%    that is, I smooth (s) if I stay at the same level, restrict (r) if I move to coarser one,
%    correct (c) if I move to finer one
switch cycleType.name
	case 'V-cycle'
		% Descend all the way to the bottom, smoothing at each lvl, climb all the way back up, smoothing at each lvl
		% 1-s-1-r-2-s-2-r-3-s-3-r-4-c-3-s-3-c-2-s-1-s-1
		% NB: notice that if more smoothing iterations are needed, this can be easily adjusted
		levels = [repelem( 1:maxLvl-1, cycleType.it(1)+1 ), maxLvl, repelem( maxLvl-1:-1:1, cycleType.it(2)+1 )];

	case 'F-cycle'
		% Drop to bottom and slowly climb your way to the top, performing a complete V-cycle at each level:
		% 1-r-2-r-3-r-4-s-4-c-3-s-3-r-4-s-4-c-3-s-3-c-2-s-2...
		levels = 1:maxLvl;
		for i=(maxLvl-1):-1:1
			% the repelem defines the number of smoothing iterations at each level; the repmat defines the number of complete V-cycles
			temp   = [ repelem( i:maxLvl-1, cycleType.it(1)+1 ), maxLvl, repelem( maxLvl-1:-1:i, cycleType.it(2)+1 ) ];	% this is a V-cycle
			temp   = repmat( temp(1:end-1), [ 1, cycleType.it(3) ] );																								    % this is a V-cycle repeated cycleType.it(3) times
			levels = [levels, temp, i ];
		end

	case 'Custom'
		levels = cycleType.lvls;
		if max(levels)~=maxLvl
			error('MGRIT: there is a mismatch between the number of levels in the cycle prescribed and the discretisation info provided per level');			
		end		
	otherwise
		error('MGRIT: Type of MG cycle specified not recognised/implemented');

end
% plot(-levels,'x-');	% to make sure we're doing everything right


% Initialise discretisation-related stuff
t  = linspace(T(1),T(2),NT(1)+1);			% actual discretisation
M  = NT ./ NT([2:end,end]);           % ratio fine/coarse node (also, M-1 is the number of fine nodes in a chunk per level)
dT = (T(2)-T(1)) ./ NT(1:end);				% time step for solver
NX = size(u0,1);											% number of variables in the system

% Assign easier names for solvers 
timeStep = cell(maxLvl,1);
for lvl = 1:maxLvl 									  % the min is just to deal with the case length(Solver)==1
	% timeStep{lvl} = @( u0, p, i )  Solver{ min(lvl, length(Solver)) }  ( u0, Problem, dT(lvl), 1, T(1) + (p-1)*DT(lvl) + (i-1)*dT(lvl) );
  % timeStep{lvl} = @( u0, i )  Solver{ min(lvl, length(Solver)) }  ( u0, Problem, dT(lvl), 1, T(1) + (i-1)*dT(lvl) );
	timeStep{lvl} = @( u0, i )  Solver{ min(lvl, length(Solver)) }  ( u0, Problem{min(lvl, length(Problem))}, dT(lvl), 1, T(1) + (i-1)*dT(lvl) );
end

% Compute serial solution if needed
if( sSol )
	err = zeros(maxIT+1,NT(2)+1);					 % initialise error as well
	uS = Solver{1}( u0, Problem{1}, dT(1), NT(1), T(1) );
end

% Initialise useful info at all levels:
rhs     = cell(maxLvl,1);	 % right-hand side of system
u       = cell(maxLvl,1);  % complete solution
cIdx    = cell(maxLvl,1);  % indices corresponding to (unconverged) coarse nodes
fIdx    = cell(maxLvl,1);  % indices corresponding to (unconverged) fine nodes
for lvl = 1:maxLvl
	rhs{lvl}  = zeros( NX, NT(lvl)+1 );
	u{lvl}    = zeros( NX, NT(lvl)+1 );
	cIdx{lvl} = 1 : M(lvl) : (NT(lvl)+1);
	fIdx{lvl} = 1 : (NT(lvl)+1);
	fIdx{lvl}(cIdx{lvl}) = [];
	cIdx{lvl}(1) = [];		% initial condition is already known at all levels
end
u{1}(:,1)   = u0;
rhs{1}(:,1) = u0;

% Initialise solution using a coarse sweep at second level
% u{1}(:,[1,cIdx{1}]) = Solver{2}( u0, Problem{min(2, length(Problem))}, dT(2), NT(2), T(1) );

% notice that rhs at finest level is always considered to be [u0,0,0,...]'
% notice that fIdx at coarsest level is useless (no distinction btw coarse and fine nodes)


% Initialise output
outIdx = 1;
uOut = zeros( NX, NT(1)+1, length(printIt) );



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Main MG cycle
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if verbose 
	disp('Beginning Multigrid loop')
end

for MGcycle=1:maxIT
	% store error
	if( sSol )
		err(MGcycle,:) = max( abs( u{1}(:,1:M(1):end)-uS(:,1:M(1):end) ), [], 1 );
	end

	
	for step = 1:length(levels)-1
		lvl = levels(step);

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
		% Base case
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
		if lvl == maxLvl		
			if verbose 
				disp(strcat('- "Exact" solve, level: ', int2str(lvl), ' (bottom)'))
			end
			% Just perform a coarse sweep to solve AC*uC = bC, with AC = spdiag([-G,I],[-1,0])
			% - notice each equation is given by -G(u_{p-1}) + u_{p} = rhs_{p}
			% - so, to recover u_{p} I need to first propagate G(u_{p-1}) and then add the rhs to it
			for p = cIdx{lvl}
				uG  = timeStep{lvl}( u{lvl}( :, p-1 ), p-1 );     % propagation of u
				u{lvl}( :, p ) = uG( :, end ) + rhs{lvl}( :, p ); % correction
			end
		end


    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
		% MG recursion
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    %----------------------------------------------------------------------
		% Smoothen
		%----------------------------------------------------------------------
		if( levels(step) == levels(step+1) )
			if verbose 
				msg = '- F';
				if cycleType.FCF
					msg = strcat(msg,'-CF');
				end
				disp(strcat(msg, ' smoothing, level ', int2str(lvl)))
			end


			% F - smoothing: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
			% - Integrate over all fine nodes starting from values at coarse nodes
			% - This process can be carried in parallel over the time chunks
			% - Notice the integration stops right before the following coarse node
			for i = fIdx{lvl}
				% advance by one time step
				uF = timeStep{lvl}( u{lvl}( :, i-1 ), i-1 );
				% store solution
				u{lvl}( :, i ) = uF( :, end ) + rhs{lvl}( :, i ); 
			end
			% remove from the list of fine nodes to update all those coming before the first non-converged coarse
			%  that is, remove the first chunk
			fIdx{lvl} = fIdx{lvl}( fIdx{lvl} > min(cIdx{lvl}) );



			% If requested, add also CF - smoothing
			if cycleType.FCF

				% C - smoothing: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
				% - Integrate over the last step in the chunk to update value at following coarse node
				% - This process can be carried in parallel over the time chunks
				for p = cIdx{lvl}
					% advance by last time step
					uF = timeStep{lvl}( u{lvl}( :, p-1 ), p-1 );
						% store solution
					u{lvl}( :, p ) = uF( :, end ) + rhs{lvl}( :, p ); 
				end

				% At this point yet another chunk has reached convergence at this level: there is no need to modify this further
				% - Remove the node from the list of coarse nodes to update
				cIdx{lvl} = cIdx{lvl}( 2 : end );
				% - If global convergence is reached, then there's no need for additional refinement below this level
				if isempty(cIdx{lvl})
					% check at which step I'll be interpolating to a higher level
					nextStep = step + find( levels( (step+1) : end ) < lvl, 1 );
					if isempty( nextStep )
						% if none is found, then I'm at top level and I've reached convergence: stop the whole MGRIT iterations
						MGcycle = maxIT;
					else
						% else, skip to that interpolation step. Notice I need to backtrack twice because:
						% - at the end of this loop, the index is increased
						% - interpolation is done *before* moving to a higher level
						step = nextStep - 2;
					end
					break;
				end


				% F - smoothing: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
				% - Integrate over the following chunks (so, ignoring the first)
				% - This process can be carried in parallel over the time chunks
				for i = fIdx{lvl}
					% advance by one time step
					uF = timeStep{lvl}( u{lvl}( :, i-1 ), i-1 );
					% store solution
					u{lvl}( :, i ) = uF( :, end ) + rhs{lvl}( :, i ); 
				end
				% remove M-1 more nodes, ie (almost) one chunk, from the list of fine nodes to update
				fIdx{lvl} = fIdx{lvl}( M(lvl) : end );

			end	






    %----------------------------------------------------------------------
		% Restrict
		%----------------------------------------------------------------------
		elseif( levels(step) < levels(step+1) )
			if verbose 
				disp(strcat('- restricting, level: ', int2str(lvl), '->', int2str(lvl+1)))
			end
			% Compute residual and FAS correction and inject them to coarser level.
			% - In order to compute the residual, the final step of fine integration needs to be performed
			% - In order to compute the FAS correction, a coarse integration needs to be performed
			% - If this comes after a smoothing at the finest level, then yet another coarse node has reached convergence

			% Restricted at coarse level, equations satisfy: AFuF  = bF -> - F(uC_{p-1}) + uC_{p} = R(bF)_p 
			%  where uC = R(uF) is the restriction of the fine solution to the coarse level
			% The residual is then:  res = bF-AFuF = R(bF)_p + F(uC_{p-1}) - uC_{p}
			% FAS correction requests for an additional term to be added: AC(uC) -> -G(uC_{p-1}) + uC_{p} 
			% So at the end of the day, the rhs for the coarse level is given by:
			%  bC = R(bF) + F(uC) -uC + uC - G(uC) = R(bF) + F(uC) - G(uC)
			
			% - initialise temp variables to store F(uC) and G(uC)
			uF0 = u{lvl}( :, cIdx{lvl} );
			uG0 = u{lvl}( :, cIdx{lvl} );
			% - fill them
			for pp = 1:length(cIdx{lvl})				       % for each (non-converged) chunk
				p     = cIdx{lvl}(pp);
				prevP = p-M(lvl);
				% advance by last time step
				uF = timeStep{lvl  }( u{lvl}( :, p-1 ), p-1 );
				% coarse integrate over this chunk
				uG = timeStep{lvl+1}( u{lvl}( :, prevP ), prevP );
				% store solution
				uF0( :, pp ) = uF( :, end );
				uG0( :, pp ) = uG( :, end );
			end

			% If this restriction was preceded by a relaxation, then at this point yet another chunk has reached
			%  convergence at this level: there is no need to modify this further
			if ( step > 1 ) && ( levels(step-1) == levels(step) )
				% - Substitute exact solution in this coarse node
				u{lvl}( :, cIdx{lvl}(1) ) = uF0(:,1) + rhs{lvl}( :, cIdx{lvl}(1) );
				% - Discard first results from integration (now useless)
				uF0 = uF0( :, 2:end );
				uG0 = uG0( :, 2:end );
				% - Remove the node from the list of coarse nodes to update
				cIdx{lvl} = cIdx{lvl}( 2 : end );
			end

			% - If global convergence is reached, then there's no need for additional refinement below this level
			if isempty(cIdx{lvl})
				% check at which step I'll be interpolating to a higher level
				nextStep = step + find( levels( (step+1) : end ) < lvl, 1 );
				if isempty( nextStep )
					% if none is found, then I'm at top level and I've reached convergence: stop the whole MGRIT iterations
					MGcycle = maxIT;
				else
					% else, skip to that interpolation step. Notice I need to backtrack twice because:
					% - at the end of this loop, the index is increased
					% - interpolation is done *before* moving to a higher level
					step = nextStep - 2;
				end
				break;
			end

			% - update converged nodes at sublevels, too
			for subLvl = lvl+1:maxLvl
				fIdx{subLvl} = ( cIdx{subLvl-1} - 1 ) / M(subLvl-1) + 1; % collect all remaining nodes idx at sublvl
				temp = length(fIdx{subLvl}):-M(subLvl):1;                % of these, the coarse ones are intervalled as such
				cIdx{subLvl} = fIdx{subLvl}( temp(end:-1:1) );           % extract the coarse ones (in ascending order)
				fIdx{subLvl}( temp ) = [];                               % exclude coarse nodes from fine ones
			end
			
			% - finally, compute and inject residual + FAS correction
			rhs{lvl+1}( :, ((cIdx{lvl}(1)-1)/M(lvl)+1) : end ) = rhs{lvl}( :, cIdx{lvl} ) + uF0 - uG0;

			% - also initialise correction at coarser level
			%   - this is *not* equivalent to taking an additional C-relaxation,
			%      since uG0 had been computed with the *previous* level at the
			%      coarse nodes; regardless, it might improve the initial guess
			%      on the correction at the coarser level:
 			u{lvl}(:,cIdx{lvl}) = uF0 + rhs{lvl}(:,cIdx{lvl});
			%   - otherwise comment above to just take the current values of u (including the -eventually- freshly converged one)
			u{lvl+1}( :, max((cIdx{lvl}(1)-1)/M(lvl),1) : end ) = u{lvl}( :, [cIdx{lvl}-M(lvl),end] );
			





    %----------------------------------------------------------------------
		% Correct
    %----------------------------------------------------------------------
		elseif( levels(step) > levels(step+1) )
			if verbose 
				disp(strcat('- interpolating, level: ', int2str(lvl), '->', int2str(lvl-1)))
			end
			% Correction is made via ideal interpolation:
			% - Collect the values of the solution at this level
			% - Integrate at the finer level starting from these values (this is equivalent to F-relaxation at higher level)
			% - This makes the complete correction: *substitute* it to the solution at the finer level
      % - Notice the rhs *should* appear

      % Correct coarse points first: since injection is used, things simplify a bit, and I can just inject back
      u{lvl-1}(:,cIdx{lvl-1}) = u{lvl}( :, (end-length(cIdx{lvl-1})+1):end);
      % If there is a smoothing afterwards, using ideal interpolation is useless (its result gets overwritten),
      %  so only do it if that's not the case
      if ( step == length(levels)-1 ) || ( levels(step+1) ~= levels(step+2) )
				for i = fIdx{lvl-1}  % for each chunk at higher level (ie, each node at this level)				
					% advance by one time step
					uF = timeStep{lvl-1}( u{lvl-1}(:,i-1), i-1 );
					% store solution
					u{lvl-1}( :, i ) = uF( :, end ) + rhs{lvl-1}( :, i ); 
				end
      end	
		end


	% end of MG cycle
	end

	
	
	if verbose 
		disp(strcat('End of MG cycle #', int2str(MGcycle)))
	end


	% print temporary results
	if(MGcycle == printIt(outIdx) )
		uOut(:,:,outIdx) = u{1};
		outIdx = min(outIdx+1, length(printIt));
	end
	

% 	if(~mod(MGcycle,10))
% 		disp(strcat('MGRIT, iteration: ', num2str(MGcycle)));
% 	end	


end

% store final error as well
if( sSol )
	err(maxIT+1,:) = max( abs( u{1}(:,1:M(1):end)-uS(:,1:M(1):end) ), [], 1 );
end
% normalise error
% if( sSol )
% 	err = err/err(1);
% end


end

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值