1 #include <petscconvest.h> /*I "petscconvest.h" I*/ 2 #include <petscts.h> 3 #include <petscdmplex.h> 4 5 #include <petsc/private/petscconvestimpl.h> 6 7 static PetscErrorCode PetscConvEstSetTS_Private(PetscConvEst ce, PetscObject solver) 8 { 9 PetscClassId id; 10 11 PetscFunctionBegin; 12 PetscCall(PetscObjectGetClassId(ce->solver, &id)); 13 PetscCheck(id == TS_CLASSID,PetscObjectComm((PetscObject) ce), PETSC_ERR_ARG_WRONG, "Solver was not a TS"); 14 PetscCall(TSGetDM((TS) ce->solver, &ce->idm)); 15 PetscFunctionReturn(0); 16 } 17 18 static PetscErrorCode PetscConvEstInitGuessTS_Private(PetscConvEst ce, PetscInt r, DM dm, Vec u) 19 { 20 PetscFunctionBegin; 21 PetscCall(TSComputeInitialCondition((TS) ce->solver, u)); 22 PetscFunctionReturn(0); 23 } 24 25 static PetscErrorCode PetscConvEstComputeErrorTS_Private(PetscConvEst ce, PetscInt r, DM dm, Vec u, PetscReal errors[]) 26 { 27 TS ts = (TS) ce->solver; 28 PetscErrorCode (*exactError)(TS, Vec, Vec); 29 30 PetscFunctionBegin; 31 PetscCall(TSGetComputeExactError(ts, &exactError)); 32 if (exactError) { 33 Vec e; 34 PetscInt f; 35 36 PetscCall(VecDuplicate(u, &e)); 37 PetscCall(TSComputeExactError(ts, u, e)); 38 PetscCall(VecNorm(e, NORM_2, errors)); 39 for (f = 1; f < ce->Nf; ++f) errors[f] = errors[0]; 40 PetscCall(VecDestroy(&e)); 41 } else { 42 PetscReal t; 43 44 PetscCall(TSGetSolveTime(ts, &t)); 45 PetscCall(DMComputeL2FieldDiff(dm, t, ce->exactSol, ce->ctxs, u, errors)); 46 } 47 PetscFunctionReturn(0); 48 } 49 50 static PetscErrorCode PetscConvEstGetConvRateTS_Temporal_Private(PetscConvEst ce, PetscReal alpha[]) 51 { 52 TS ts = (TS) ce->solver; 53 Vec u; 54 PetscReal *dt, *x, *y, slope, intercept; 55 PetscInt Ns, oNs, Nf = ce->Nf, f, Nr = ce->Nr, r; 56 57 PetscFunctionBegin; 58 PetscCall(TSGetSolution(ts, &u)); 59 PetscCall(PetscMalloc1(Nr+1, &dt)); 60 PetscCall(TSGetTimeStep(ts, &dt[0])); 61 PetscCall(TSGetMaxSteps(ts, &oNs)); 62 Ns = oNs; 63 for (r = 0; r <= Nr; ++r) { 64 if (r > 0) { 65 dt[r] = dt[r-1]/ce->r; 66 Ns = PetscCeilReal(Ns*ce->r); 67 } 68 PetscCall(TSSetTime(ts, 0.0)); 69 PetscCall(TSSetStepNumber(ts, 0)); 70 PetscCall(TSSetTimeStep(ts, dt[r])); 71 PetscCall(TSSetMaxSteps(ts, Ns)); 72 PetscCall(PetscConvEstComputeInitialGuess(ce, r, NULL, u)); 73 PetscCall(TSSolve(ts, u)); 74 PetscCall(PetscLogEventBegin(ce->event, ce, 0, 0, 0)); 75 PetscCall(PetscConvEstComputeError(ce, r, ce->idm, u, &ce->errors[r*Nf])); 76 PetscCall(PetscLogEventEnd(ce->event, ce, 0, 0, 0)); 77 for (f = 0; f < Nf; ++f) { 78 ce->dofs[r*Nf+f] = 1.0/dt[r]; 79 PetscCall(PetscLogEventSetDof(ce->event, f, ce->dofs[r*Nf+f])); 80 PetscCall(PetscLogEventSetError(ce->event, f, ce->errors[r*Nf+f])); 81 } 82 /* Monitor */ 83 PetscCall(PetscConvEstMonitorDefault(ce, r)); 84 } 85 /* Fit convergence rate */ 86 if (Nr) { 87 PetscCall(PetscMalloc2(Nr+1, &x, Nr+1, &y)); 88 for (f = 0; f < Nf; ++f) { 89 for (r = 0; r <= Nr; ++r) { 90 x[r] = PetscLog10Real(dt[r]); 91 y[r] = PetscLog10Real(ce->errors[r*Nf+f]); 92 } 93 PetscCall(PetscLinearRegression(Nr+1, x, y, &slope, &intercept)); 94 /* Since lg err = s lg dt + b */ 95 alpha[f] = slope; 96 } 97 PetscCall(PetscFree2(x, y)); 98 } 99 /* Reset solver */ 100 PetscCall(TSSetConvergedReason(ts, TS_CONVERGED_ITERATING)); 101 PetscCall(TSSetTime(ts, 0.0)); 102 PetscCall(TSSetStepNumber(ts, 0)); 103 PetscCall(TSSetTimeStep(ts, dt[0])); 104 PetscCall(TSSetMaxSteps(ts, oNs)); 105 PetscCall(PetscConvEstComputeInitialGuess(ce, 0, NULL, u)); 106 PetscCall(PetscFree(dt)); 107 PetscFunctionReturn(0); 108 } 109 110 static PetscErrorCode PetscConvEstGetConvRateTS_Spatial_Private(PetscConvEst ce, PetscReal alpha[]) 111 { 112 TS ts = (TS) ce->solver; 113 Vec uInitial; 114 DM *dm; 115 PetscObject disc; 116 PetscReal *x, *y, slope, intercept; 117 PetscInt Nr = ce->Nr, r, Nf = ce->Nf, f, dim, oldlevel, oldnlev; 118 void *ctx; 119 120 PetscFunctionBegin; 121 PetscCheck(ce->r == 2.0,PetscObjectComm((PetscObject) ce), PETSC_ERR_SUP, "Only refinement factor 2 is currently supported (not %g)", (double) ce->r); 122 PetscCall(DMGetDimension(ce->idm, &dim)); 123 PetscCall(DMGetApplicationContext(ce->idm, &ctx)); 124 PetscCall(DMPlexSetRefinementUniform(ce->idm, PETSC_TRUE)); 125 PetscCall(DMGetRefineLevel(ce->idm, &oldlevel)); 126 PetscCall(PetscMalloc1((Nr+1), &dm)); 127 PetscCall(TSGetSolution(ts, &uInitial)); 128 /* Loop over meshes */ 129 dm[0] = ce->idm; 130 for (r = 0; r <= Nr; ++r) { 131 Vec u; 132 #if defined(PETSC_USE_LOG) 133 PetscLogStage stage; 134 #endif 135 char stageName[PETSC_MAX_PATH_LEN]; 136 const char *dmname, *uname; 137 138 PetscCall(PetscSNPrintf(stageName, PETSC_MAX_PATH_LEN-1, "ConvEst Refinement Level %D", r)); 139 #if defined(PETSC_USE_LOG) 140 PetscCall(PetscLogStageGetId(stageName, &stage)); 141 if (stage < 0) PetscCall(PetscLogStageRegister(stageName, &stage)); 142 #endif 143 PetscCall(PetscLogStagePush(stage)); 144 if (r > 0) { 145 if (!ce->noRefine) { 146 PetscCall(DMRefine(dm[r-1], MPI_COMM_NULL, &dm[r])); 147 PetscCall(DMSetCoarseDM(dm[r], dm[r-1])); 148 } else { 149 DM cdm, rcdm; 150 151 PetscCall(DMClone(dm[r-1], &dm[r])); 152 PetscCall(DMCopyDisc(dm[r-1], dm[r])); 153 PetscCall(DMGetCoordinateDM(dm[r-1], &cdm)); 154 PetscCall(DMGetCoordinateDM(dm[r], &rcdm)); 155 PetscCall(DMCopyDisc(cdm, rcdm)); 156 } 157 PetscCall(DMCopyTransform(ce->idm, dm[r])); 158 PetscCall(PetscObjectGetName((PetscObject) dm[r-1], &dmname)); 159 PetscCall(PetscObjectSetName((PetscObject) dm[r], dmname)); 160 for (f = 0; f <= Nf; ++f) { 161 PetscErrorCode (*nspconstr)(DM, PetscInt, PetscInt, MatNullSpace *); 162 163 PetscCall(DMGetNullSpaceConstructor(dm[r-1], f, &nspconstr)); 164 PetscCall(DMSetNullSpaceConstructor(dm[r], f, nspconstr)); 165 } 166 } 167 PetscCall(DMViewFromOptions(dm[r], NULL, "-conv_dm_view")); 168 /* Create solution */ 169 PetscCall(DMCreateGlobalVector(dm[r], &u)); 170 PetscCall(DMGetField(dm[r], 0, NULL, &disc)); 171 PetscCall(PetscObjectGetName(disc, &uname)); 172 PetscCall(PetscObjectSetName((PetscObject) u, uname)); 173 /* Setup solver */ 174 PetscCall(TSReset(ts)); 175 PetscCall(TSSetDM(ts, dm[r])); 176 PetscCall(DMTSSetBoundaryLocal(dm[r], DMPlexTSComputeBoundary, ctx)); 177 PetscCall(DMTSSetIFunctionLocal(dm[r], DMPlexTSComputeIFunctionFEM, ctx)); 178 PetscCall(DMTSSetIJacobianLocal(dm[r], DMPlexTSComputeIJacobianFEM, ctx)); 179 PetscCall(TSSetTime(ts, 0.0)); 180 PetscCall(TSSetStepNumber(ts, 0)); 181 PetscCall(TSSetFromOptions(ts)); 182 /* Create initial guess */ 183 PetscCall(PetscConvEstComputeInitialGuess(ce, r, dm[r], u)); 184 PetscCall(TSSolve(ts, u)); 185 PetscCall(PetscLogEventBegin(ce->event, ce, 0, 0, 0)); 186 PetscCall(PetscConvEstComputeError(ce, r, dm[r], u, &ce->errors[r*Nf])); 187 PetscCall(PetscLogEventEnd(ce->event, ce, 0, 0, 0)); 188 for (f = 0; f < Nf; ++f) { 189 PetscSection s, fs; 190 PetscInt lsize; 191 192 /* Could use DMGetOutputDM() to add in Dirichlet dofs */ 193 PetscCall(DMGetLocalSection(dm[r], &s)); 194 PetscCall(PetscSectionGetField(s, f, &fs)); 195 PetscCall(PetscSectionGetConstrainedStorageSize(fs, &lsize)); 196 PetscCallMPI(MPI_Allreduce(&lsize, &ce->dofs[r*Nf+f], 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) ts))); 197 PetscCall(PetscLogEventSetDof(ce->event, f, ce->dofs[r*Nf+f])); 198 PetscCall(PetscLogEventSetError(ce->event, f, ce->errors[r*Nf+f])); 199 } 200 /* Monitor */ 201 PetscCall(PetscConvEstMonitorDefault(ce, r)); 202 if (!r) { 203 /* PCReset() does not wipe out the level structure */ 204 SNES snes; 205 KSP ksp; 206 PC pc; 207 208 PetscCall(TSGetSNES(ts, &snes)); 209 PetscCall(SNESGetKSP(snes, &ksp)); 210 PetscCall(KSPGetPC(ksp, &pc)); 211 PetscCall(PCMGGetLevels(pc, &oldnlev)); 212 } 213 /* Cleanup */ 214 PetscCall(VecDestroy(&u)); 215 PetscCall(PetscLogStagePop()); 216 } 217 for (r = 1; r <= Nr; ++r) { 218 PetscCall(DMDestroy(&dm[r])); 219 } 220 /* Fit convergence rate */ 221 PetscCall(PetscMalloc2(Nr+1, &x, Nr+1, &y)); 222 for (f = 0; f < Nf; ++f) { 223 for (r = 0; r <= Nr; ++r) { 224 x[r] = PetscLog10Real(ce->dofs[r*Nf+f]); 225 y[r] = PetscLog10Real(ce->errors[r*Nf+f]); 226 } 227 PetscCall(PetscLinearRegression(Nr+1, x, y, &slope, &intercept)); 228 /* Since h^{-dim} = N, lg err = s lg N + b = -s dim lg h + b */ 229 alpha[f] = -slope * dim; 230 } 231 PetscCall(PetscFree2(x, y)); 232 PetscCall(PetscFree(dm)); 233 /* Restore solver */ 234 PetscCall(TSReset(ts)); 235 { 236 /* PCReset() does not wipe out the level structure */ 237 SNES snes; 238 KSP ksp; 239 PC pc; 240 241 PetscCall(TSGetSNES(ts, &snes)); 242 PetscCall(SNESGetKSP(snes, &ksp)); 243 PetscCall(KSPGetPC(ksp, &pc)); 244 PetscCall(PCMGSetLevels(pc, oldnlev, NULL)); 245 PetscCall(DMSetRefineLevel(ce->idm, oldlevel)); /* The damn DMCoarsen() calls in PCMG can reset this */ 246 } 247 PetscCall(TSSetDM(ts, ce->idm)); 248 PetscCall(DMTSSetBoundaryLocal(ce->idm, DMPlexTSComputeBoundary, ctx)); 249 PetscCall(DMTSSetIFunctionLocal(ce->idm, DMPlexTSComputeIFunctionFEM, ctx)); 250 PetscCall(DMTSSetIJacobianLocal(ce->idm, DMPlexTSComputeIJacobianFEM, ctx)); 251 PetscCall(TSSetConvergedReason(ts, TS_CONVERGED_ITERATING)); 252 PetscCall(TSSetTime(ts, 0.0)); 253 PetscCall(TSSetStepNumber(ts, 0)); 254 PetscCall(TSSetFromOptions(ts)); 255 PetscCall(TSSetSolution(ts, uInitial)); 256 PetscCall(PetscConvEstComputeInitialGuess(ce, 0, NULL, uInitial)); 257 PetscFunctionReturn(0); 258 } 259 260 PetscErrorCode PetscConvEstUseTS(PetscConvEst ce, PetscBool checkTemporal) 261 { 262 PetscFunctionBegin; 263 PetscValidHeaderSpecific(ce, PETSC_OBJECT_CLASSID, 1); 264 ce->ops->setsolver = PetscConvEstSetTS_Private; 265 ce->ops->initguess = PetscConvEstInitGuessTS_Private; 266 ce->ops->computeerror = PetscConvEstComputeErrorTS_Private; 267 if (checkTemporal) { 268 ce->ops->getconvrate = PetscConvEstGetConvRateTS_Temporal_Private; 269 } else { 270 ce->ops->getconvrate = PetscConvEstGetConvRateTS_Spatial_Private; 271 } 272 PetscFunctionReturn(0); 273 } 274