PetscSolverNavierStokes.cc 11.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/******************************************************************************
 *
 * AMDiS - Adaptive multidimensional simulations
 *
 * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved.
 * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis
 *
 * Authors: 
 * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 *
 * This file is part of AMDiS
 *
 * See also license.opensource.txt in the distribution.
 * 
 ******************************************************************************/
20
21
22
23



#include "parallel/PetscSolverNavierStokes.h"
24
#include "parallel/PetscHelper.h"
Thomas Witkowski's avatar
blub    
Thomas Witkowski committed
25
#include "TransformDOF.h"
26

27
namespace AMDiS { namespace Parallel {
28
29
30

  using namespace std;

31

32
  PetscErrorCode pcSchurShell(PC pc, Vec x, Vec y)
Thomas Witkowski's avatar
Thomas Witkowski committed
33
34
35
  {
    void *ctx;
    PCShellGetContext(pc, &ctx);
36
    NavierStokesSchurData* data = static_cast<NavierStokesSchurData*>(ctx);
Thomas Witkowski's avatar
Thomas Witkowski committed
37

38
39
40
41
42
43
44
45
46
47
    // Project out constant null space
    {
      int vecSize;
      VecGetSize(x, &vecSize);
      PetscScalar vecSum;
      VecSum(x, &vecSum);
      vecSum = vecSum / static_cast<PetscScalar>(-1.0 * vecSize);
      VecShift(x, vecSum); 
    }

48
49
50
    KSPSolve(data->kspLaplace, x, y);
    MatMult(data->matConDif, y, x);
    KSPSolve(data->kspMass, x, y);
51
52
    
    PetscFunctionReturn(0);
53
  }
54
  
55
56

  PetscSolverNavierStokes::PetscSolverNavierStokes(string name)
57
    : PetscSolverGlobalMatrix(name, false),
58
      pressureComponent(-1),
59
      pressureNullSpace(true),
60
      useOldInitialGuess(false),
61
62
63
      velocitySolutionMode(0),
      massSolutionMode(0),
      laplaceSolutionMode(0),
64
      massMatrixSolver(NULL),
65
66
67
      laplaceMatrixSolver(NULL),
      nu(NULL),
      invTau(NULL),
Thomas Witkowski's avatar
blub    
Thomas Witkowski committed
68
69
      solution(NULL),
      phase(NULL)
70
  {
Thomas Witkowski's avatar
blub    
Thomas Witkowski committed
71
    Parameters::get(initFileStr + "->navierstokes->pressure component", 
72
73
74
		    pressureComponent);
    TEST_EXIT(pressureComponent >= 0)
      ("For using PETSc stokes solver you must define a pressure component!\n");
75
76
77
78

    Parameters::get(initFileStr + "->navierstokes->pressure null space",
		    pressureNullSpace);
    TEST_EXIT(pressureNullSpace)("This is not yet tested, may be wrong!\n");
79
80
81

    Parameters::get(initFileStr + "->navierstokes->use old initial guess", 
		    useOldInitialGuess);
82
83
84
85
86
87
88
89
90

    Parameters::get(initFileStr + "->navierstokes->velocity solver", 
		    velocitySolutionMode);

    Parameters::get(initFileStr + "->navierstokes->mass solver", 
		    massSolutionMode);

    Parameters::get(initFileStr + "->navierstokes->laplace solver", 
		    laplaceSolutionMode);
91
92
93
94
95
96
97
98
  }


  void PetscSolverNavierStokes::solvePetscMatrix(SystemVector &vec, 
						 AdaptInfo *adaptInfo)
  {
    FUNCNAME("PetscSolverNavierStokes::solvePetscMatrix()");

99
    if (useOldInitialGuess) {      
100
101
102
103
104
105
106
107
108
109
      VecSet(getVecSolInterior(), 0.0);
      
      for (int i = 0; i < solution->getSize(); i++)
	setDofVector(getVecSolInterior(), solution->getDOFVector(i), i, true);
      
      vecSolAssembly();
      KSPSetInitialGuessNonzero(kspInterior, PETSC_TRUE);
    }

    PetscSolverGlobalMatrix::solvePetscMatrix(vec, adaptInfo);
110
111
112
  }


113
  void PetscSolverNavierStokes::initSolver(KSP &ksp)
114
115
116
  {
    FUNCNAME("PetscSolverNavierStokes::initSolver()");

117
    // Create FGMRES based outer solver
118
119
    
    MSG("CREATE POS 1: %p\n", &ksp);
120
    KSPCreate(domainComm, &ksp);
121
    KSPSetOperators(ksp, getMatInterior(), getMatInterior(), SAME_NONZERO_PATTERN);
122
    KSPMonitorSet(ksp, KSPMonitorTrueResidualNorm, PETSC_NULL, PETSC_NULL);
123
    petsc_helper::setSolver(ksp, "ns_", KSPFGMRES, PCNONE, getRelative(), getTolerance(), getMaxIterations());
Thomas Witkowski's avatar
blub    
Thomas Witkowski committed
124
    
125
    // Create null space information.
126
127
    if (pressureNullSpace)
      setConstantNullSpace(ksp, pressureComponent, true);
128
129
130
131
132
133
134
  }


  void PetscSolverNavierStokes::initPreconditioner(PC pc)
  {
    FUNCNAME("PetscSolverNavierStokes::initPreconditioner()");

135
    Timer t;
136

Thomas Witkowski's avatar
blub    
Thomas Witkowski committed
137
138
139
140
    TEST_EXIT(nu)("nu pointer not set!\n");
    TEST_EXIT(invTau)("invtau pointer not set!\n");
    TEST_EXIT(solution)("solution pointer not set!\n");

Thomas Witkowski's avatar
Thomas Witkowski committed
141
142
    int dim = componentSpaces[pressureComponent]->getMesh()->getDim();

143
    vector<int> velocityComponents;
144
145
    for (size_t i = 0; i < dim; i++)
      velocityComponents.push_back(i);
146

147
148
149
    PCSetType(pc, PCFIELDSPLIT);
    PCFieldSplitSetType(pc, PC_COMPOSITE_SCHUR);
    PCFieldSplitSetSchurFactType(pc, PC_FIELDSPLIT_SCHUR_FACT_FULL);
150

151
152
    createFieldSplit(pc, "velocity", velocityComponents);
    createFieldSplit(pc, "pressure", pressureComponent);
153
    PCSetFromOptions(pc);
154

Thomas Witkowski's avatar
Thomas Witkowski committed
155
    KSPSetUp(kspInterior);
156
157
158
159
160

    KSP *subKsp;
    int nSubKsp;
    PCFieldSplitGetSubKSP(pc, &nSubKsp, &subKsp);

161

162
163
164
165
166
167
168
    TEST_EXIT(nSubKsp == 2)
      ("Wrong numer of KSPs inside of the fieldsplit preconditioner!\n");

    KSP kspVelocity = subKsp[0];
    KSP kspSchur = subKsp[1];
    PetscFree(subKsp);

169
170
171
    switch (velocitySolutionMode) {
    case 0:      
      petsc_helper::setSolver(kspVelocity, "", 
172
 			      KSPRICHARDSON, PCHYPRE, 0.0, 1e-14, 1);
173
174
175
176
177
178
179
180
181
      break;
    case 1:
      petsc_helper::setSolverWithLu(kspVelocity, "", KSPPREONLY, 
				    PCLU, MATSOLVERMUMPS , 0.0, 1e-14, 1);
      break;
    default:
      ERROR_EXIT("No velocity solution mode %d available!\n", velocitySolutionMode);
    }
    
182
183

    KSPSetType(kspSchur, KSPPREONLY);
184
    PC pcSub;
185
186
187
188
    KSPGetPC(kspSchur, &pcSub);
    PCSetType(pcSub, PCSHELL);
    PCShellSetApply(pcSub, pcSchurShell);
    PCShellSetContext(pcSub, &matShellContext);
189

190
191
    if (pressureNullSpace)
      setConstantNullSpace(kspSchur);
192

193
    // === Mass matrix solver ===
194
195
196

    const FiniteElemSpace *pressureFeSpace = componentSpaces[pressureComponent];
    DOFMatrix massMatrix(pressureFeSpace, pressureFeSpace);
197
198
199
    {
      Operator massOp(pressureFeSpace, pressureFeSpace);
      ZeroOrderTerm *massTerm = NULL;
200
      if ((!phase) || (*nu == 0.0))
201
202
	massTerm = new Simple_ZOT;
      else
203
        massTerm = new VecAtQP_ZOT(phase);
204
205
206
207
      massOp.addTerm(massTerm);
      massMatrix.assembleOperator(massOp);
      delete massTerm;
    }
208
209
210
211
212
213
214
    massMatrixSolver = createSubSolver(pressureComponent, "mass_");
    massMatrixSolver->fillPetscMatrix(&massMatrix);


    // === Laplace matrix solver ===

    DOFMatrix laplaceMatrix(pressureFeSpace, pressureFeSpace);
215
216
217
    {
      Operator laplaceOp(pressureFeSpace, pressureFeSpace);
      SecondOrderTerm *laplaceTerm = NULL;      
218
      if ((!phase) || (*nu == 0.0))
219
220
	laplaceTerm = new Simple_SOT;
      else
221
	laplaceTerm = new VecAtQP_SOT(phase);
222
223
224
225
      laplaceOp.addTerm(laplaceTerm);
      laplaceMatrix.assembleOperator(laplaceOp);
      delete laplaceTerm;
    }
226
    laplaceMatrixSolver = createSubSolver(pressureComponent, string("laplace_"));
227
228
229
230
231
    laplaceMatrixSolver->fillPetscMatrix(&laplaceMatrix);


    // === Create convection-diffusion operator ===

232
233
    DOFVector<double> vx(pressureFeSpace, "vx");
    DOFVector<double> vy(pressureFeSpace, "vy");
Thomas Witkowski's avatar
Thomas Witkowski committed
234
    DOFVector<double> vz(pressureFeSpace, "vz");
Thomas Witkowski's avatar
blub    
Thomas Witkowski committed
235
    DOFVector<double> vp(pressureFeSpace, "vp");
236
    vx.interpol(solution->getDOFVector(0));
237
238
239
    if (dim >= 2)
      vy.interpol(solution->getDOFVector(1));
    if (dim >= 3)
Thomas Witkowski's avatar
Thomas Witkowski committed
240
      vz.interpol(solution->getDOFVector(2));
241
242

    DOFMatrix conDifMatrix(pressureFeSpace, pressureFeSpace);
Thomas Witkowski's avatar
blub    
Thomas Witkowski committed
243

244
245
246
247
248
249
250
251
252
253
254
255
256
257
    {
      Operator conDifOp(pressureFeSpace, pressureFeSpace);
      
      ZeroOrderTerm *conDif0 = NULL;
      SecondOrderTerm *conDif1 = NULL;
      FirstOrderTerm *conDif2 = NULL, *conDif3 = NULL, *conDif4 = NULL;

      if (!phase) {
	MSG("INIT WITHOUT PHASE!\n");
	
	conDif0 = new Simple_ZOT(*invTau);
	conDifOp.addTerm(conDif0);
	conDif1 = new Simple_SOT(*nu);
	conDifOp.addTerm(conDif1);
258
	conDif2 = new VecAtQP_FOT(&vx, NULL, 0);
259
	conDifOp.addTerm(conDif2, GRD_PHI);
260
261
262
263
	if (dim >= 2) {
	  conDif3 = new VecAtQP_FOT(&vy, NULL, 1);
	  conDifOp.addTerm(conDif3, GRD_PHI);
	}
264
	if (dim == 3) {
265
	  conDif4 = new VecAtQP_FOT(&vz, NULL, 2);	
266
267
	  conDifOp.addTerm(conDif4, GRD_PHI);
	}
268
      } else { // no phase given
269
270
271
	
	vp.interpol(phase);
	
272
273
	if (*nu > 0.0) {
	  conDif0 = new VecAtQP_ZOT(&vp, NULL, *invTau);
274
	  conDifOp.addTerm(conDif0);	
275
	  conDif1 = new VecAtQP_SOT(&vp, NULL, *nu);
276
	  conDifOp.addTerm(conDif1);	
277
	  conDif2 = new Vec2AtQP_FOT(&vx, &vp, NULL, 0);
278
279
	  conDifOp.addTerm(conDif2, GRD_PHI);
	  
280
281
282
283
	  if (dim >= 2) {
	    conDif3 = new Vec2AtQP_FOT(&vy, &vp, NULL, 1);
	    conDifOp.addTerm(conDif3, GRD_PHI);
	  }
284
	  if (dim == 3) {
285
	    conDif4 = new Vec2AtQP_FOT(&vz, &vp, NULL, 2);
286
287
288
289
290
291
292
293
294
295
	    conDifOp.addTerm(conDif4, GRD_PHI);
	  }
	} else {	  
	  conDif0 = new VecAtQP_ZOT(&vp, new LinearInterpolation(*rho1,*rho2,*invTau));
	  conDifOp.addTerm(conDif0);	
	  conDif1 = new VecAtQP_SOT(&vp, new LinearInterpolation(*nu1,*nu2));
	  conDifOp.addTerm(conDif1);	
	  conDif2 = new Vec2AtQP_FOT(&vx, &vp, new LinearInterpolation2(*rho1,*rho2), 0);
	  conDifOp.addTerm(conDif2, GRD_PHI);
	  
296
297
298
299
	  if (dim >= 2) {
	    conDif3 = new Vec2AtQP_FOT(&vy, &vp, new LinearInterpolation2(*rho1,*rho2), 1);
	    conDifOp.addTerm(conDif3, GRD_PHI);
	  }
300
301
302
303
	  if (dim == 3) {
	    conDif4 = new Vec2AtQP_FOT(&vz, &vp, new LinearInterpolation2(*rho1,*rho2), 2);
	    conDifOp.addTerm(conDif4, GRD_PHI);
	  }
304
	}
305
      }/**/
Thomas Witkowski's avatar
blub    
Thomas Witkowski committed
306

307
      conDifMatrix.assembleOperator(conDifOp);
Thomas Witkowski's avatar
Thomas Witkowski committed
308

309
310
311
      delete conDif0;
      delete conDif1;
      delete conDif2;
312
313
      if (dim >= 2)
	delete conDif3;
314
315
      if (dim == 3)
	delete conDif4;
Thomas Witkowski's avatar
blub    
Thomas Witkowski committed
316
    }
317
318
319
320

    conDifMatrixSolver = createSubSolver(pressureComponent, "condif_");
    conDifMatrixSolver->fillPetscMatrix(&conDifMatrix);

321
322

    // === Setup solver ===
323
324
325
326
327

    matShellContext.kspMass = massMatrixSolver->getSolver();
    matShellContext.kspLaplace = laplaceMatrixSolver->getSolver();
    matShellContext.matConDif = conDifMatrixSolver->getMatInterior();    

328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
    switch (massSolutionMode) {
    case 0:
      petsc_helper::setSolver(matShellContext.kspMass, "mass_", 
			      KSPCG, PCJACOBI, 0.0, 1e-14, 2);
      break;
    case 1:
      petsc_helper::setSolverWithLu(matShellContext.kspMass, "mass_", KSPRICHARDSON, 
				    PCLU, MATSOLVERMUMPS, 0.0, 1e-14, 1);
      break;
    default:
      ERROR_EXIT("No mass solution mode %d available!\n", massSolutionMode);
    }

    switch (laplaceSolutionMode) {
    case 0:
      petsc_helper::setSolver(matShellContext.kspLaplace, "laplace_", 
344
 			      KSPRICHARDSON, PCHYPRE, 0.0, 1e-14, 1);
345
346
347
348
349
350
351
352
353
      break;
    case 1:
      petsc_helper::setSolverWithLu(matShellContext.kspLaplace, "mass_", 
				    KSPRICHARDSON, PCLU, MATSOLVERMUMPS, 
				    0.0, 1e-14, 1);
      break;
    default:
      ERROR_EXIT("No laplace solution mode %d available!\n", laplaceSolutionMode);
    }
Thomas Witkowski's avatar
blub    
Thomas Witkowski committed
354

355
    setConstantNullSpace(matShellContext.kspLaplace);
356
357

    MSG("Setup of Navier-Stokes preconditioner needed %.5f seconds\n", 
358
	t.elapsed());
359
360
  }

361

362
363
364
365
366
  void PetscSolverNavierStokes::exitPreconditioner(PC pc)
  {
    FUNCNAME("PetscSolverNavierStokes::exitPreconditioner()");

    massMatrixSolver->destroyMatrixData();
367
    massMatrixSolver->destroyVectorData();
368
    laplaceMatrixSolver->destroyMatrixData();
369
    laplaceMatrixSolver->destroyVectorData();
370
    conDifMatrixSolver->destroyMatrixData();
371
    conDifMatrixSolver->destroyVectorData();
372

373
374
375
376
377
    massMatrixSolver->destroyVectorData();
    laplaceMatrixSolver->destroyVectorData();
    conDifMatrixSolver->destroyVectorData();
    
    
378
379
380
381
382
383
384
385
386
    delete massMatrixSolver;
    massMatrixSolver = NULL;

    delete laplaceMatrixSolver;
    laplaceMatrixSolver = NULL;

    delete conDifMatrixSolver;
    conDifMatrixSolver = NULL;
  }
387
} }