$treeview $search $mathjax
|
Palabos
Version 1.1
$projectbrief
|
$projectbrief
|
$searchbox |
00001 /* This file is part of the Palabos library. 00002 * 00003 * Copyright (C) 2011 FlowKit Sarl 00004 * Avenue de Chailly 23 00005 * 1012 Lausanne, Switzerland 00006 * E-mail contact: contact@flowkit.com 00007 * 00008 * The most recent release of Palabos can be downloaded at 00009 * <http://www.palabos.org/> 00010 * 00011 * The library Palabos is free software: you can redistribute it and/or 00012 * modify it under the terms of the GNU Affero General Public License as 00013 * published by the Free Software Foundation, either version 3 of the 00014 * License, or (at your option) any later version. 00015 * 00016 * The library is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Affero General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Affero General Public License 00022 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00023 */ 00024 00028 #ifndef FINITE_DIFFERENCE_WRAPPER_2D_HH 00029 #define FINITE_DIFFERENCE_WRAPPER_2D_HH 00030 00031 #include "finiteDifference/fdWrapper2D.h" 00032 #include "finiteDifference/fdFunctional2D.h" 00033 #include "atomicBlock/reductiveDataProcessorWrapper2D.h" 00034 #include "atomicBlock/dataProcessorWrapper2D.h" 00035 #include "multiBlock/reductiveMultiDataProcessorWrapper2D.h" 00036 #include "multiBlock/multiDataProcessorWrapper2D.h" 00037 #include "multiGrid/gridConversion2D.h" 00038 00039 00040 namespace plb { 00041 00042 template<typename T> 00043 void computeXderivative(MultiScalarField2D<T>& value, MultiScalarField2D<T>& derivative, Box2D const& domain) { 00044 plint boundaryWidth = 1; 00045 applyProcessingFunctional ( 00046 new BoxXderivativeFunctional2D<T>, domain, value, derivative, boundaryWidth ); 00047 } 00048 00049 template<typename T> 00050 std::auto_ptr<MultiScalarField2D<T> > computeXderivative(MultiScalarField2D<T>& value, Box2D const& domain) { 00051 MultiScalarField2D<T>* derivative = new MultiScalarField2D<T>(value, domain); 00052 computeXderivative(value, *derivative, domain); 00053 return std::auto_ptr<MultiScalarField2D<T> >(derivative); 00054 } 00055 00056 template<typename T> 00057 std::auto_ptr<MultiScalarField2D<T> > computeXderivative(MultiScalarField2D<T>& value) { 00058 return computeXderivative(value, value.getBoundingBox()); 00059 } 00060 00061 00062 template<typename T> 00063 void computeYderivative(MultiScalarField2D<T>& value, MultiScalarField2D<T>& derivative, Box2D const& domain) { 00064 plint boundaryWidth = 1; 00065 applyProcessingFunctional ( 00066 new BoxYderivativeFunctional2D<T>, domain, value, derivative, boundaryWidth ); 00067 } 00068 00069 template<typename T> 00070 std::auto_ptr<MultiScalarField2D<T> > computeYderivative(MultiScalarField2D<T>& value, Box2D const& domain) { 00071 MultiScalarField2D<T>* derivative = new MultiScalarField2D<T>(value, domain); 00072 computeYderivative(value, *derivative, domain); 00073 return std::auto_ptr<MultiScalarField2D<T> >(derivative); 00074 } 00075 00076 template<typename T> 00077 std::auto_ptr<MultiScalarField2D<T> > computeYderivative(MultiScalarField2D<T>& value) { 00078 return computeYderivative(value, value.getBoundingBox()); 00079 } 00080 00081 template<typename T> 00082 void computeGradientNorm(MultiScalarField2D<T>& value, MultiScalarField2D<T>& derivative, Box2D const& domain) { 00083 plint boundaryWidth = 1; 00084 applyProcessingFunctional ( 00085 new BoxGradientNormFunctional2D<T>, domain, value, derivative, boundaryWidth ); 00086 } 00087 00088 template<typename T> 00089 std::auto_ptr<MultiScalarField2D<T> > computeGradientNorm(MultiScalarField2D<T>& value, Box2D const& domain) { 00090 MultiScalarField2D<T>* derivative = new MultiScalarField2D<T>(value, domain); 00091 computeGradientNorm(value, *derivative, domain); 00092 return std::auto_ptr<MultiScalarField2D<T> >(derivative); 00093 } 00094 00095 template<typename T> 00096 std::auto_ptr<MultiScalarField2D<T> > computeGradientNorm(MultiScalarField2D<T>& value) { 00097 return computeGradientNorm(value, value.getBoundingBox()); 00098 } 00099 00100 00101 template<typename T> 00102 std::auto_ptr<MultiScalarField2D<T> > computePoissonRHS(MultiTensorField2D<T,2>& velocity, Box2D const& domain) 00103 { 00104 std::auto_ptr<MultiScalarField2D<T> > ux = extractComponent(velocity, domain, 0); 00105 std::auto_ptr<MultiScalarField2D<T> > uy = extractComponent(velocity, domain, 1); 00106 00107 std::auto_ptr<MultiScalarField2D<T> > dx_ux = computeXderivative(*ux, domain); 00108 std::auto_ptr<MultiScalarField2D<T> > dy_ux = computeYderivative(*ux, domain); 00109 std::auto_ptr<MultiScalarField2D<T> > dx_uy = computeXderivative(*uy, domain); 00110 std::auto_ptr<MultiScalarField2D<T> > dy_uy = computeYderivative(*uy, domain); 00111 00112 std::auto_ptr<MultiScalarField2D<T> > term1 = multiply(*dx_ux, *dx_ux, domain); 00113 std::auto_ptr<MultiScalarField2D<T> > term2 = multiply((T)2, *multiply(*dx_uy, *dy_ux, domain), domain); 00114 std::auto_ptr<MultiScalarField2D<T> > term3 = multiply(*dy_uy, *dy_uy, domain); 00115 00116 std::auto_ptr<MultiScalarField2D<T> > rhs = add(*term1, *add(*term2, *term3)); 00117 return rhs; 00118 } 00119 00120 template<typename T> 00121 std::auto_ptr<MultiScalarField2D<T> > computePoissonRHS(MultiTensorField2D<T,2>& velocity) { 00122 return computePoissonRHS(velocity, velocity.getBoundingBox()); 00123 } 00124 00125 template<typename T> 00126 void poissonIterate(MultiScalarField2D<T>& oldPressure, MultiScalarField2D<T>& newPressure, 00127 MultiScalarField2D<T>& rhs, T beta, Box2D const& domain) 00128 { 00129 std::vector<MultiScalarField2D<T>* > fields; 00130 fields.push_back(&oldPressure); 00131 fields.push_back(&newPressure); 00132 fields.push_back(&rhs); 00133 plint boundaryWidth=1; 00134 applyProcessingFunctional ( 00135 new BoxPoissonIteration2D<T>(beta), domain, fields, boundaryWidth ); 00136 } 00137 00138 template<typename T> 00139 T computePoissonResidue(MultiScalarField2D<T>& pressure, MultiScalarField2D<T>& rhs, Box2D const& domain) { 00140 BoxPoissonResidueFunctional2D<T> functional; 00141 applyProcessingFunctional(functional, domain, pressure, rhs); 00142 return functional.getMaxResidue(); 00143 } 00144 00145 /* ************ Wrapper for one Jacobi iteration *************** */ 00146 template<typename T> 00147 void JacobiIteration( MultiScalarField2D<T>& u_h, MultiScalarField2D<T>& new_u_h, 00148 MultiScalarField2D<T>& rhs, Box2D const& domain ){ 00149 00150 std::vector<MultiScalarField2D<T>* > fields; 00151 fields.push_back(&u_h); 00152 fields.push_back(&new_u_h); 00153 fields.push_back(&rhs); 00154 plint boundaryWidth=1; 00155 applyProcessingFunctional ( 00156 new JacobiIteration2D<T>(), domain, fields, boundaryWidth ); 00157 00158 } 00159 00160 /* ************ Wrapper for one Gauss-Seidel iteration *************** */ 00161 template<typename T> 00162 void GaussSeidelIteration( MultiScalarField2D<T>& u_h, MultiScalarField2D<T>& jacobi_u_h, 00163 MultiScalarField2D<T>& new_u_h, MultiScalarField2D<T>& rhs, Box2D const& domain ) 00164 { 00165 std::vector<MultiScalarField2D<T>* > fields; 00166 fields.push_back(&u_h); 00167 fields.push_back(&jacobi_u_h); 00168 fields.push_back(&new_u_h); 00169 fields.push_back(&rhs); 00170 plint boundaryWidth=1; 00171 applyProcessingFunctional ( 00172 new GaussSeidelIteration2D<T>(), domain, fields, boundaryWidth ); 00173 } 00174 00175 /* ************ Wrapper for Gauss-Seidel defect computation *************** */ 00176 template<typename T> 00177 MultiScalarField2D<T>* computeGaussSeidelDefect(MultiScalarField2D<T>& u_h, MultiScalarField2D<T>& rhs, 00178 Box2D const& domain) 00179 { 00180 MultiScalarField2D<T>* residual = new MultiScalarField2D<T>(u_h); 00181 std::vector<MultiScalarField2D<T>* > fields; 00182 fields.push_back(&u_h); 00183 fields.push_back(residual); 00184 fields.push_back(&rhs); 00185 plint boundaryWidth=1; 00186 applyProcessingFunctional ( 00187 new GaussSeidelDefect2D<T>(), domain, fields,boundaryWidth); 00188 00189 return residual; 00190 } 00191 00192 template<typename T> 00193 T computeEuclidianNorm(MultiScalarField2D<T>& matrix, Box2D const& domain){ 00194 T av = computeAverage( *multiply(matrix,matrix),domain); 00195 return sqrt(av); 00196 } 00197 00198 00199 /* ************ Gauss-Seidel Solver *************** */ 00200 template<typename T> 00201 void GaussSeidelSolver( MultiScalarField2D<T>& initialValue, 00202 MultiScalarField2D<T>& result, 00203 MultiScalarField2D<T>& rhs, Box2D const& domain, T tolerance, plint maxIter ) 00204 { 00205 T originalNorm; 00206 T newNorm; 00207 plint infoIt=100; 00208 00209 // to contain the Jacobi result 00210 MultiScalarField2D<T> jacobiValue(initialValue); 00211 jacobiValue.reset(); 00212 00213 // computation of the initial residual. We will stop when currentResidual=tolerance*initialResidual 00214 // or when we have made maxIter iterations 00215 MultiScalarField2D<T>* defect = computeGaussSeidelDefect<T>(initialValue, rhs, domain); 00216 originalNorm = computeEuclidianNorm<T>(*defect, domain); 00217 delete defect; 00218 00219 // MAIN LOOP 00220 for (plint iT=0; iT<maxIter; ++iT){ 00221 // use one Jacobi iteration 00222 JacobiIteration<T>(initialValue, jacobiValue, rhs, domain); 00223 00224 // with this jacobiValue, make one gauss-sidel iteration (eliminate the asynchronie for parallelism) 00225 GaussSeidelIteration<T>(initialValue, jacobiValue, result, rhs, domain); 00226 00227 // compute the new residual norm to know if we continue 00228 defect = computeGaussSeidelDefect<T>(result, rhs, domain); 00229 newNorm = computeEuclidianNorm<T>(*defect, domain); 00230 delete defect; 00231 00232 if (newNorm < tolerance*originalNorm) 00233 { 00234 pcout << "Gauss-Seidel iterations: " << iT << std::endl; 00235 break; 00236 } 00237 00238 // result becomes the new initial value 00239 result.swap(initialValue); 00240 00241 if (iT%infoIt==0 && iT>0){ 00242 pcout << "Gauss-Seidel iteration " << iT << " : error=" << newNorm/originalNorm 00243 << " : NORM=" << newNorm << std::endl; 00244 } 00245 } 00246 pcout << "Gauss-Seidel iterations: " << maxIter << std::endl; 00247 } 00248 00249 /* ************ MultiGrid method *************** */ 00251 template<typename T> 00252 MultiScalarField2D<T>* smooth( MultiScalarField2D<T>& initialValue, 00253 MultiScalarField2D<T>& rhs, Box2D const& domain, 00254 plint smoothIters){ 00255 // create the solution for Jacobi 00256 MultiScalarField2D<T> jacobiValue(initialValue); 00257 jacobiValue.reset(); 00258 00259 // copy initialValue 00260 MultiScalarField2D<T> initialCopy(initialValue); 00261 // the result holder 00262 MultiScalarField2D<T>* newValue = new MultiScalarField2D<T>(initialValue); 00263 00264 // iteration over the original system: one Jacobi + one Gauss-Seidel 00265 plint v1 = smoothIters; 00266 for (plint iV1=0; iV1< v1; ++iV1){ 00267 newValue->swap(initialCopy); 00268 JacobiIteration<T>(initialCopy, jacobiValue, rhs, domain); 00269 GaussSeidelIteration<T>(initialCopy, jacobiValue, *newValue, rhs, domain); 00270 } 00271 00272 return newValue; 00273 } 00274 00276 template<typename T> 00277 MultiScalarField2D<T>* smoothAndInterpolate( MultiScalarField2D<T>& initialValue, 00278 MultiScalarField2D<T>& rhs, Box2D const& domain, 00279 plint smoothIters ) 00280 { 00281 // smooth 00282 MultiScalarField2D<T>* coarseNewValue = smooth(initialValue,rhs,domain,smoothIters); 00283 // interpolate 00284 MultiScalarField2D<T>* fineNewValue = new MultiScalarField2D<T>(*refine<T>(*coarseNewValue,1,-1,-1,-1)); 00285 delete coarseNewValue; 00286 00287 return fineNewValue; 00288 } 00289 00291 template<typename T> 00292 MultiScalarField2D<T>* smoothAndComputeError( MultiScalarField2D<T>& initialValue, MultiScalarField2D<T>& rhs, 00293 Box2D const& domain, T& newError, plint smoothIters ){ 00294 00295 MultiScalarField2D<T>* newValue = smooth(initialValue,rhs,domain,smoothIters); 00296 // compute the new defect norm 00297 MultiScalarField2D<T>* newDefect = computeGaussSeidelDefect<T>(*newValue, rhs, domain); 00298 newError = computeEuclidianNorm<T>(*newDefect, domain); 00299 delete newDefect; 00300 00301 return newValue; 00302 } 00303 00305 template<typename T> 00306 MultiScalarField2D<T>* smoothAndComputeCoarseDefect( MultiScalarField2D<T>& initialValue, 00307 MultiScalarField2D<T>& rhs, Box2D const& domain, 00308 plint smoothIters ){ 00309 00310 MultiScalarField2D<T>* newValue = smooth(initialValue,rhs,domain,smoothIters); 00311 // compute the new defect norm 00312 MultiScalarField2D<T>* newDefect = computeGaussSeidelDefect<T>(*newValue, rhs, domain); 00313 MultiScalarField2D<T>* coarseDefect = new MultiScalarField2D<T>(*coarsen<T>(*newDefect, 1, -1,1,1)); 00314 delete newDefect; 00315 00316 return coarseDefect; 00317 } 00318 00319 template<typename T> 00320 void generateRHS(MultiScalarField2D<T>& originalRHS, std::vector<MultiScalarField2D<T>* >& rhs){ 00321 plint vectorSize = (plint) rhs.size(); 00322 rhs[vectorSize-1] = new MultiScalarField2D<T>(originalRHS); 00323 for (plint iLevel=vectorSize-2; iLevel>=0; iLevel--){ 00324 rhs[iLevel] = new MultiScalarField2D<T>( *coarsen<T>(*rhs[iLevel+1],1,-1,1,1)); 00325 } 00326 } 00327 00328 template<typename T> 00329 T multiGridVCycle( MultiScalarField2D<T>& initialValue, MultiScalarField2D<T>& newValue, 00330 MultiScalarField2D<T>& rhs, Box2D const& domain, plint depth ){ 00331 00332 00333 PLB_PRECONDITION(depth>=1); 00334 00335 // containers of the values to not lose anything 00336 std::vector<MultiScalarField2D<T>* > newValues(depth+1); 00337 std::vector<MultiScalarField2D<T>* > defects(depth+1); 00338 00339 plint smoothIters1 = 5; 00340 plint smoothIters2 = 5; 00341 // we go down until the level before the coarsest 00342 newValues[depth] = smooth<T>(initialValue,rhs,initialValue.getBoundingBox(), smoothIters1); 00343 defects[depth] = computeGaussSeidelDefect<T>(*newValues[depth],rhs,initialValue.getBoundingBox()); 00344 defects[depth-1] = new MultiScalarField2D<T>(*coarsen<T>(*defects[depth],1,-1,1,1)); 00345 *defects[depth-1] = *plb::multiply(-1.0,*defects[depth-1]); 00346 00348 for (plint iLevel=depth-1; iLevel>=1; iLevel--){ 00349 00350 // create initial solution = 0 00351 MultiScalarField2D<T> initialSolution(*defects[iLevel]); 00352 initialSolution.reset(); 00353 // smooth the new system 00354 newValues[iLevel] = smooth<T>( initialSolution,*defects[iLevel], 00355 initialSolution.getBoundingBox(), smoothIters1); 00356 MultiScalarField2D<T>* tempDefect = 00357 computeGaussSeidelDefect<T>(*newValues[iLevel],*defects[iLevel],newValues[iLevel]->getBoundingBox()); 00358 defects[iLevel-1] = new 00359 MultiScalarField2D<T>(*coarsen<T>(*tempDefect,1,-1,1,1)); 00360 *defects[iLevel-1] = *plb::multiply(-1.0,*defects[iLevel-1]); // change the sign 00361 delete tempDefect; 00362 } 00363 00365 // resolve the system exactly for the coarse system 00366 MultiScalarField2D<T> initialValueCoarse(*defects[0]); 00367 MultiScalarField2D<T> resultCoarse(*defects[0]); // container for the coarse solution to the correction scheme 00368 initialValueCoarse.reset(); // for the correction 0 is a good first approximation 00369 00370 T tolerance = 1e-5; 00371 plint maxIter = 100; 00372 GaussSeidelSolver<T>( initialValueCoarse, resultCoarse, 00373 *defects[0],resultCoarse.getBoundingBox(),tolerance, maxIter ); 00374 00375 newValues[0] = new MultiScalarField2D<T>(resultCoarse); 00376 // we interpolate the error computed in the coarse grid and add it to the original result from level 1 00377 MultiScalarField2D<T>* v_h = new MultiScalarField2D<T>(*refine<T>( *newValues[0], 1, -1 ,-1,-1)); 00378 // compute new approximation as newValue = u_h + v_h 00379 *newValues[1] = *plb::add(*newValues[1],*v_h); 00380 delete v_h; 00381 00383 // go up interpolating and smoothing up to the level before the finest 00384 for (plint iLevel=1; iLevel<depth; ++iLevel){ 00385 MultiScalarField2D<T>* tempNewVal = smoothAndInterpolate<T>( *newValues[iLevel], *defects[iLevel], 00386 newValues[iLevel]->getBoundingBox(), smoothIters2); 00387 *newValues[iLevel+1] = *plb::add(*newValues[iLevel+1],*tempNewVal); 00388 delete tempNewVal; 00389 00390 } 00391 00392 // we smooth and compute the new error in the finest level 00393 T newError = 0.0; 00394 MultiScalarField2D<T>* result = smoothAndComputeError( *newValues[depth], rhs, 00395 newValues[depth]->getBoundingBox(), 00396 newError, smoothIters2 ); 00397 // copy new initial value 00398 newValue = *result; 00399 delete result; 00400 00401 // CLEAN-UP 00402 for (plint iLevel = 0; iLevel <= depth; ++iLevel){ 00403 delete newValues[iLevel]; 00404 delete defects[iLevel]; 00405 } 00406 00407 return newError; 00408 } 00409 00410 template<typename T> 00411 std::vector<MultiScalarField2D<T>* > fullMultiGrid( MultiScalarField2D<T>& initialValue, 00412 MultiScalarField2D<T>& originalRhs, Box2D const& domain, 00413 plint gridLevels, plint ncycles ) 00414 { 00415 PLB_PRECONDITION( gridLevels>=2 && ncycles>=1 ); 00416 00417 std::vector<MultiScalarField2D<T>* > rhs(gridLevels); 00418 std::vector<MultiScalarField2D<T>* > solutions(gridLevels); 00419 00420 // create all the right-hand sides from restriction over rhs 00421 generateRHS(originalRhs, rhs); 00422 00423 // Initial solution computed exactly on the coarsest grid 00424 MultiScalarField2D<T> initialSolution(*rhs[0]); 00425 MultiScalarField2D<T> initialValueCoarse(*rhs[0]); 00426 initialValueCoarse.reset(); 00427 GaussSeidelSolver<T>(initialValueCoarse, initialSolution, *rhs[0],initialSolution.getBoundingBox()); 00428 solutions[0] = new MultiScalarField2D<T>(initialSolution); 00429 00430 // MAIN LOOP (at each time we add one more level) 00431 for (plint iLevel=1; iLevel<gridLevels; ++iLevel){ 00432 pcout << "Level: " << iLevel << std::endl; 00433 // interpolate the iLevel-1 solution 00434 MultiScalarField2D<T>* initialSolutionLevel = new 00435 MultiScalarField2D<T>( *refine<T>(*solutions[iLevel-1],1,-1,-1,-1) ); 00436 MultiScalarField2D<T> newValue(*initialSolutionLevel); 00437 // for each level we itere ncycles 00438 for (plint iNcycle=0; iNcycle<ncycles*iLevel; ++iNcycle){ 00439 // we use a V cycle with the current number of grids 00440 T error; 00441 error = multiGridVCycle<T>( *initialSolutionLevel, newValue, *rhs[iLevel], domain, iLevel); 00442 pcout << "\tError=" << error << std::endl; 00443 newValue.swap(*initialSolutionLevel); 00444 } 00445 00446 // save the current level solution 00447 solutions[iLevel] = new MultiScalarField2D<T>(*initialSolutionLevel); 00448 delete initialSolutionLevel; 00449 } 00450 00451 // CLEAN-UP 00452 for (plint iLevel=0; iLevel<gridLevels; ++iLevel){ 00453 delete rhs[iLevel]; 00454 } 00455 00456 return solutions; 00457 } 00458 00459 template<typename T> 00460 std::vector<MultiScalarField2D<T>* > simpleMultiGrid( MultiScalarField2D<T>& initialValue, 00461 MultiScalarField2D<T>& originalRhs, Box2D const& domain, 00462 plint gridLevels ) 00463 { 00464 PLB_PRECONDITION( gridLevels>=2 ); 00465 00466 std::vector<MultiScalarField2D<T>* > rhs(gridLevels); 00467 std::vector<MultiScalarField2D<T>* > solutions(gridLevels); 00468 00469 // create all the right-hand sides from restriction over rhs 00470 generateRHS(originalRhs, rhs); 00471 00472 // Initial solution computed exactly on the coarsest grid 00473 pcout << "Level: 0" << std::endl; 00474 pcout << "Size of the field : " << rhs[0]->getNx() << " x " << rhs[0]->getNy() << std::endl; 00475 MultiScalarField2D<T> initialSolution(*rhs[0]); 00476 MultiScalarField2D<T> initialValueCoarse(*rhs[0]); 00477 initialValueCoarse.reset(); 00478 GaussSeidelSolver<T>(initialValueCoarse, initialSolution, *rhs[0],initialSolution.getBoundingBox()); 00479 solutions[0] = new MultiScalarField2D<T>(initialSolution); 00480 00481 // MAIN LOOP (at each time we add one more level) 00482 for (plint iLevel=1; iLevel<gridLevels; ++iLevel){ 00483 pcout << "Level: " << iLevel << std::endl; 00484 00485 // interpolate the iLevel-1 solution 00486 MultiScalarField2D<T>* initialSolutionLevel = new 00487 MultiScalarField2D<T>( *refine<T>(*solutions[iLevel-1],1,-1,-1,-1) ); 00488 MultiScalarField2D<T> newValue(*initialSolutionLevel); 00489 pcout << "Size of the field : " << newValue.getNx() << " x " << newValue.getNy() << std::endl; 00490 GaussSeidelSolver<T>(*initialSolutionLevel, newValue, *rhs[iLevel],initialSolutionLevel->getBoundingBox()); 00491 00492 // save the current level solution 00493 solutions[iLevel] = new MultiScalarField2D<T>(*initialSolutionLevel); 00494 delete initialSolutionLevel; 00495 } 00496 00497 // CLEAN-UP 00498 for (plint iLevel=0; iLevel<gridLevels; ++iLevel){ 00499 delete rhs[iLevel]; 00500 } 00501 00502 return solutions; 00503 } 00504 00505 00506 00507 00508 } // namespace plb 00509 00510 #endif // FINITE_DIFFERENCE_WRAPPER_2D_HH
1.6.3
1.6.3