PetscSolverNavierStokes.cc 11.5 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
65
66
67
68
69
      massMatrixSolver(nullptr),
      laplaceMatrixSolver(nullptr),
      nu(nullptr),
      invTau(nullptr),
      solution(nullptr),
      phase(nullptr)
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
123
124
125
    if (getInfo() >= 10)
      KSPMonitorSet(ksp, KSPMonitorDefault, PETSC_NULL, PETSC_NULL);
    else if (getInfo() >= 20)
      KSPMonitorSet(ksp, KSPMonitorTrueResidualNorm, PETSC_NULL, PETSC_NULL);
126
    petsc_helper::setSolver(ksp, "ns_", KSPFGMRES, PCNONE, getRelative(), getTolerance(), getMaxIterations());
Thomas Witkowski's avatar
blub    
Thomas Witkowski committed
127
    
128
    // Create null space information.
129
130
    if (pressureNullSpace)
      setConstantNullSpace(ksp, pressureComponent, true);
131
132
133
134
135
136
137
  }


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

138
    Timer t;
139

Thomas Witkowski's avatar
blub    
Thomas Witkowski committed
140
141
142
143
    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
144
145
    int dim = componentSpaces[pressureComponent]->getMesh()->getDim();

146
    vector<int> velocityComponents;
147
    for (int i = 0; i < dim; i++)
148
      velocityComponents.push_back(i);
149

150
151
152
    PCSetType(pc, PCFIELDSPLIT);
    PCFieldSplitSetType(pc, PC_COMPOSITE_SCHUR);
    PCFieldSplitSetSchurFactType(pc, PC_FIELDSPLIT_SCHUR_FACT_FULL);
153

154
155
    createFieldSplit(pc, "velocity", velocityComponents);
    createFieldSplit(pc, "pressure", pressureComponent);
156
    PCSetFromOptions(pc);
157

Thomas Witkowski's avatar
Thomas Witkowski committed
158
    KSPSetUp(kspInterior);
159
160
161
162
163

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

164

165
166
167
168
169
170
171
    TEST_EXIT(nSubKsp == 2)
      ("Wrong numer of KSPs inside of the fieldsplit preconditioner!\n");

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

172
173
174
    switch (velocitySolutionMode) {
    case 0:      
      petsc_helper::setSolver(kspVelocity, "", 
175
 			      KSPRICHARDSON, PCHYPRE, 0.0, 1e-14, 1);
176
177
178
179
180
181
182
183
184
      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);
    }
    
185
186

    KSPSetType(kspSchur, KSPPREONLY);
187
    PC pcSub;
188
189
190
191
    KSPGetPC(kspSchur, &pcSub);
    PCSetType(pcSub, PCSHELL);
    PCShellSetApply(pcSub, pcSchurShell);
    PCShellSetContext(pcSub, &matShellContext);
192

193
194
    if (pressureNullSpace)
      setConstantNullSpace(kspSchur);
195

196
    // === Mass matrix solver ===
197
198
199

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


    // === Laplace matrix solver ===

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


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

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

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

247
248
249
    {
      Operator conDifOp(pressureFeSpace, pressureFeSpace);
      
250
251
252
      ZeroOrderTerm *conDif0 = nullptr;
      SecondOrderTerm *conDif1 = nullptr;
      FirstOrderTerm *conDif2 = nullptr, *conDif3 = nullptr, *conDif4 = nullptr;
253
254
255
256
257
258
259
260

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

310
      conDifMatrix.assembleOperator(conDifOp);
Thomas Witkowski's avatar
Thomas Witkowski committed
311

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

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

324
325

    // === Setup solver ===
326
327
328
329
330

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

331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
    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_", 
347
 			      KSPRICHARDSON, PCHYPRE, 0.0, 1e-14, 1);
348
349
      break;
    case 1:
350
      petsc_helper::setSolverWithLu(matShellContext.kspLaplace, "laplace_", 
351
352
353
354
355
356
				    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
357

358
    setConstantNullSpace(matShellContext.kspLaplace);
359
360

    MSG("Setup of Navier-Stokes preconditioner needed %.5f seconds\n", 
361
	t.elapsed());
362
363
  }

364

365
366
367
368
369
  void PetscSolverNavierStokes::exitPreconditioner(PC pc)
  {
    FUNCNAME("PetscSolverNavierStokes::exitPreconditioner()");

    massMatrixSolver->destroyMatrixData();
370
    massMatrixSolver->destroyVectorData();
371
    laplaceMatrixSolver->destroyMatrixData();
372
    laplaceMatrixSolver->destroyVectorData();
373
    conDifMatrixSolver->destroyMatrixData();
374
    conDifMatrixSolver->destroyVectorData();
375

376
377
378
379
380
    massMatrixSolver->destroyVectorData();
    laplaceMatrixSolver->destroyVectorData();
    conDifMatrixSolver->destroyVectorData();
    
    
381
    delete massMatrixSolver;
382
    massMatrixSolver = nullptr;
383
384

    delete laplaceMatrixSolver;
385
    laplaceMatrixSolver = nullptr;
386
387

    delete conDifMatrixSolver;
388
    conDifMatrixSolver = nullptr;
389
  }
390
} }