1 static const char help[] = "1D nonequilibrium radiation diffusion with Saha ionization model.\n\n"; 2 3 /* 4 This example implements the model described in 5 6 Rauenzahn, Mousseau, Knoll. "Temporal accuracy of the nonequilibrium radiation diffusion 7 equations employing a Saha ionization model" 2005. 8 9 The paper discusses three examples, the first two are nondimensional with a simple 10 ionization model. The third example is fully dimensional and uses the Saha ionization 11 model with realistic parameters. 12 */ 13 14 #include <petscts.h> 15 #include <petscdm.h> 16 #include <petscdmda.h> 17 18 typedef enum {BC_DIRICHLET,BC_NEUMANN,BC_ROBIN} BCType; 19 static const char *const BCTypes[] = {"DIRICHLET","NEUMANN","ROBIN","BCType","BC_",0}; 20 typedef enum {JACOBIAN_ANALYTIC,JACOBIAN_MATRIXFREE,JACOBIAN_FD_COLORING,JACOBIAN_FD_FULL} JacobianType; 21 static const char *const JacobianTypes[] = {"ANALYTIC","MATRIXFREE","FD_COLORING","FD_FULL","JacobianType","FD_",0}; 22 typedef enum {DISCRETIZATION_FD,DISCRETIZATION_FE} DiscretizationType; 23 static const char *const DiscretizationTypes[] = {"FD","FE","DiscretizationType","DISCRETIZATION_",0}; 24 typedef enum {QUADRATURE_GAUSS1,QUADRATURE_GAUSS2,QUADRATURE_GAUSS3,QUADRATURE_GAUSS4,QUADRATURE_LOBATTO2,QUADRATURE_LOBATTO3} QuadratureType; 25 static const char *const QuadratureTypes[] = {"GAUSS1","GAUSS2","GAUSS3","GAUSS4","LOBATTO2","LOBATTO3","QuadratureType","QUADRATURE_",0}; 26 27 typedef struct { 28 PetscScalar E; /* radiation energy */ 29 PetscScalar T; /* material temperature */ 30 } RDNode; 31 32 typedef struct { 33 PetscReal meter,kilogram,second,Kelvin; /* Fundamental units */ 34 PetscReal Joule,Watt; /* Derived units */ 35 } RDUnit; 36 37 typedef struct _n_RD *RD; 38 39 struct _n_RD { 40 void (*MaterialEnergy)(RD,const RDNode*,PetscScalar*,RDNode*); 41 DM da; 42 PetscBool monitor_residual; 43 DiscretizationType discretization; 44 QuadratureType quadrature; 45 JacobianType jacobian; 46 PetscInt initial; 47 BCType leftbc; 48 PetscBool view_draw; 49 char view_binary[PETSC_MAX_PATH_LEN]; 50 PetscBool test_diff; 51 PetscBool endpoint; 52 PetscBool bclimit; 53 PetscBool bcmidpoint; 54 RDUnit unit; 55 56 /* model constants, see Table 2 and RDCreate() */ 57 PetscReal rho,K_R,K_p,I_H,m_p,m_e,h,k,c,sigma_b,beta,gamma; 58 59 /* Domain and boundary conditions */ 60 PetscReal Eapplied; /* Radiation flux from the left */ 61 PetscReal L; /* Length of domain */ 62 PetscReal final_time; 63 }; 64 65 static PetscErrorCode RDDestroy(RD *rd) 66 { 67 PetscErrorCode ierr; 68 69 PetscFunctionBeginUser; 70 ierr = DMDestroy(&(*rd)->da);CHKERRQ(ierr); 71 ierr = PetscFree(*rd);CHKERRQ(ierr); 72 PetscFunctionReturn(0); 73 } 74 75 /* The paper has a time derivative for material energy (Eq 2) which is a dependent variable (computable from temperature 76 * and density through an uninvertible relation). Computing this derivative is trivial for trapezoid rule (used in the 77 * paper), but does not generalize nicely to higher order integrators. Here we use the implicit form which provides 78 * time derivatives of the independent variables (radiation energy and temperature), so we must compute the time 79 * derivative of material energy ourselves (could be done using AD). 80 * 81 * There are multiple ionization models, this interface dispatches to the one currently in use. 82 */ 83 static void RDMaterialEnergy(RD rd,const RDNode *n,PetscScalar *Em,RDNode *dEm) { rd->MaterialEnergy(rd,n,Em,dEm); } 84 85 /* Solves a quadratic equation while propagating tangents */ 86 static void QuadraticSolve(PetscScalar a,PetscScalar a_t,PetscScalar b,PetscScalar b_t,PetscScalar c,PetscScalar c_t,PetscScalar *x,PetscScalar *x_t) 87 { 88 PetscScalar 89 disc = b*b - 4.*a*c, 90 disc_t = 2.*b*b_t - 4.*a_t*c - 4.*a*c_t, 91 num = -b + PetscSqrtScalar(disc), /* choose positive sign */ 92 num_t = -b_t + 0.5/PetscSqrtScalar(disc)*disc_t, 93 den = 2.*a, 94 den_t = 2.*a_t; 95 *x = num/den; 96 *x_t = (num_t*den - num*den_t) / PetscSqr(den); 97 } 98 99 /* The primary model presented in the paper */ 100 static void RDMaterialEnergy_Saha(RD rd,const RDNode *n,PetscScalar *inEm,RDNode *dEm) 101 { 102 PetscScalar Em,alpha,alpha_t, 103 T = n->T, 104 T_t = 1., 105 chi = rd->I_H / (rd->k * T), 106 chi_t = -chi / T * T_t, 107 a = 1., 108 a_t = 0, 109 b = 4. * rd->m_p / rd->rho * PetscPowScalarReal(2. * PETSC_PI * rd->m_e * rd->I_H / PetscSqr(rd->h),1.5) * PetscExpScalar(-chi) * PetscPowScalarReal(chi,1.5), /* Eq 7 */ 110 b_t = -b*chi_t + 1.5*b/chi*chi_t, 111 c = -b, 112 c_t = -b_t; 113 QuadraticSolve(a,a_t,b,b_t,c,c_t,&alpha,&alpha_t); /* Solve Eq 7 for alpha */ 114 Em = rd->k * T / rd->m_p * (1.5*(1.+alpha) + alpha*chi); /* Eq 6 */ 115 if (inEm) *inEm = Em; 116 if (dEm) { 117 dEm->E = 0; 118 dEm->T = Em / T * T_t + rd->k * T / rd->m_p * (1.5*alpha_t + alpha_t*chi + alpha*chi_t); 119 } 120 } 121 /* Reduced ionization model, Eq 30 */ 122 static void RDMaterialEnergy_Reduced(RD rd,const RDNode *n,PetscScalar *Em,RDNode *dEm) 123 { 124 PetscScalar alpha,alpha_t, 125 T = n->T, 126 T_t = 1., 127 chi = -0.3 / T, 128 chi_t = -chi / T * T_t, 129 a = 1., 130 a_t = 0., 131 b = PetscExpScalar(chi), 132 b_t = b*chi_t, 133 c = -b, 134 c_t = -b_t; 135 QuadraticSolve(a,a_t,b,b_t,c,c_t,&alpha,&alpha_t); 136 if (Em) *Em = (1.+alpha)*T + 0.3*alpha; 137 if (dEm) { 138 dEm->E = 0; 139 dEm->T = alpha_t*T + (1.+alpha)*T_t + 0.3*alpha_t; 140 } 141 } 142 143 /* Eq 5 */ 144 static void RDSigma_R(RD rd,RDNode *n,PetscScalar *sigma_R,RDNode *dsigma_R) 145 { 146 *sigma_R = rd->K_R * rd->rho * PetscPowScalar(n->T,-rd->gamma); 147 dsigma_R->E = 0; 148 dsigma_R->T = -rd->gamma * (*sigma_R) / n->T; 149 } 150 151 /* Eq 4 */ 152 static void RDDiffusionCoefficient(RD rd,PetscBool limit,RDNode *n,RDNode *nx,PetscScalar *D_R,RDNode *dD_R,RDNode *dxD_R) 153 { 154 PetscScalar sigma_R,denom; 155 RDNode dsigma_R,ddenom,dxdenom; 156 157 RDSigma_R(rd,n,&sigma_R,&dsigma_R); 158 denom = 3. * rd->rho * sigma_R + (int)limit * PetscAbsScalar(nx->E) / n->E; 159 ddenom.E = -(int)limit * PetscAbsScalar(nx->E) / PetscSqr(n->E); 160 ddenom.T = 3. * rd->rho * dsigma_R.T; 161 dxdenom.E = (int)limit * (PetscRealPart(nx->E)<0 ? -1. : 1.) / n->E; 162 dxdenom.T = 0; 163 *D_R = rd->c / denom; 164 if (dD_R) { 165 dD_R->E = -rd->c / PetscSqr(denom) * ddenom.E; 166 dD_R->T = -rd->c / PetscSqr(denom) * ddenom.T; 167 } 168 if (dxD_R) { 169 dxD_R->E = -rd->c / PetscSqr(denom) * dxdenom.E; 170 dxD_R->T = -rd->c / PetscSqr(denom) * dxdenom.T; 171 } 172 } 173 174 static PetscErrorCode RDStateView(RD rd,Vec X,Vec Xdot,Vec F) 175 { 176 PetscErrorCode ierr; 177 DMDALocalInfo info; 178 PetscInt i; 179 const RDNode *x,*xdot,*f; 180 MPI_Comm comm; 181 182 PetscFunctionBeginUser; 183 ierr = PetscObjectGetComm((PetscObject)rd->da,&comm);CHKERRQ(ierr); 184 ierr = DMDAGetLocalInfo(rd->da,&info);CHKERRQ(ierr); 185 ierr = DMDAVecGetArrayRead(rd->da,X,(void*)&x);CHKERRQ(ierr); 186 ierr = DMDAVecGetArrayRead(rd->da,Xdot,(void*)&xdot);CHKERRQ(ierr); 187 ierr = DMDAVecGetArrayRead(rd->da,F,(void*)&f);CHKERRQ(ierr); 188 for (i=info.xs; i<info.xs+info.xm; i++) { 189 ierr = PetscSynchronizedPrintf(comm,"x[%D] (%10.2G,%10.2G) (%10.2G,%10.2G) (%10.2G,%10.2G)\n",i,PetscRealPart(x[i].E),PetscRealPart(x[i].T), 190 PetscRealPart(xdot[i].E),PetscRealPart(xdot[i].T), PetscRealPart(f[i].E),PetscRealPart(f[i].T));CHKERRQ(ierr); 191 } 192 ierr = DMDAVecRestoreArrayRead(rd->da,X,(void*)&x);CHKERRQ(ierr); 193 ierr = DMDAVecRestoreArrayRead(rd->da,Xdot,(void*)&xdot);CHKERRQ(ierr); 194 ierr = DMDAVecRestoreArrayRead(rd->da,F,(void*)&f);CHKERRQ(ierr); 195 ierr = PetscSynchronizedFlush(comm,PETSC_STDOUT);CHKERRQ(ierr); 196 PetscFunctionReturn(0); 197 } 198 199 static PetscScalar RDRadiation(RD rd,const RDNode *n,RDNode *dn) 200 { 201 PetscScalar sigma_p = rd->K_p * rd->rho * PetscPowScalar(n->T,-rd->beta), 202 sigma_p_T = -rd->beta * sigma_p / n->T, 203 tmp = 4.* rd->sigma_b*PetscSqr(PetscSqr(n->T)) / rd->c - n->E, 204 tmp_E = -1., 205 tmp_T = 4. * rd->sigma_b * 4 * n->T*(PetscSqr(n->T)) / rd->c, 206 rad = sigma_p * rd->c * rd->rho * tmp, 207 rad_E = sigma_p * rd->c * rd->rho * tmp_E, 208 rad_T = rd->c * rd->rho * (sigma_p_T * tmp + sigma_p * tmp_T); 209 if (dn) { 210 dn->E = rad_E; 211 dn->T = rad_T; 212 } 213 return rad; 214 } 215 216 static PetscScalar RDDiffusion(RD rd,PetscReal hx,const RDNode x[],PetscInt i,RDNode d[]) 217 { 218 PetscReal ihx = 1./hx; 219 RDNode n_L,nx_L,n_R,nx_R,dD_L,dxD_L,dD_R,dxD_R,dfluxL[2],dfluxR[2]; 220 PetscScalar D_L,D_R,fluxL,fluxR; 221 222 n_L.E = 0.5*(x[i-1].E + x[i].E); 223 n_L.T = 0.5*(x[i-1].T + x[i].T); 224 nx_L.E = (x[i].E - x[i-1].E)/hx; 225 nx_L.T = (x[i].T - x[i-1].T)/hx; 226 RDDiffusionCoefficient(rd,PETSC_TRUE,&n_L,&nx_L,&D_L,&dD_L,&dxD_L); 227 fluxL = D_L*nx_L.E; 228 dfluxL[0].E = -ihx*D_L + (0.5*dD_L.E - ihx*dxD_L.E)*nx_L.E; 229 dfluxL[1].E = +ihx*D_L + (0.5*dD_L.E + ihx*dxD_L.E)*nx_L.E; 230 dfluxL[0].T = (0.5*dD_L.T - ihx*dxD_L.T)*nx_L.E; 231 dfluxL[1].T = (0.5*dD_L.T + ihx*dxD_L.T)*nx_L.E; 232 233 n_R.E = 0.5*(x[i].E + x[i+1].E); 234 n_R.T = 0.5*(x[i].T + x[i+1].T); 235 nx_R.E = (x[i+1].E - x[i].E)/hx; 236 nx_R.T = (x[i+1].T - x[i].T)/hx; 237 RDDiffusionCoefficient(rd,PETSC_TRUE,&n_R,&nx_R,&D_R,&dD_R,&dxD_R); 238 fluxR = D_R*nx_R.E; 239 dfluxR[0].E = -ihx*D_R + (0.5*dD_R.E - ihx*dxD_R.E)*nx_R.E; 240 dfluxR[1].E = +ihx*D_R + (0.5*dD_R.E + ihx*dxD_R.E)*nx_R.E; 241 dfluxR[0].T = (0.5*dD_R.T - ihx*dxD_R.T)*nx_R.E; 242 dfluxR[1].T = (0.5*dD_R.T + ihx*dxD_R.T)*nx_R.E; 243 244 if (d) { 245 d[0].E = -ihx*dfluxL[0].E; 246 d[0].T = -ihx*dfluxL[0].T; 247 d[1].E = ihx*(dfluxR[0].E - dfluxL[1].E); 248 d[1].T = ihx*(dfluxR[0].T - dfluxL[1].T); 249 d[2].E = ihx*dfluxR[1].E; 250 d[2].T = ihx*dfluxR[1].T; 251 } 252 return ihx*(fluxR - fluxL); 253 } 254 255 static PetscErrorCode RDGetLocalArrays(RD rd,TS ts,Vec X,Vec Xdot,PetscReal *Theta,PetscReal *dt,Vec *X0loc,RDNode **x0,Vec *Xloc,RDNode **x,Vec *Xloc_t,RDNode **xdot) 256 { 257 PetscErrorCode ierr; 258 PetscBool istheta; 259 260 PetscFunctionBeginUser; 261 ierr = DMGetLocalVector(rd->da,X0loc);CHKERRQ(ierr); 262 ierr = DMGetLocalVector(rd->da,Xloc);CHKERRQ(ierr); 263 ierr = DMGetLocalVector(rd->da,Xloc_t);CHKERRQ(ierr); 264 265 ierr = DMGlobalToLocalBegin(rd->da,X,INSERT_VALUES,*Xloc);CHKERRQ(ierr); 266 ierr = DMGlobalToLocalEnd(rd->da,X,INSERT_VALUES,*Xloc);CHKERRQ(ierr); 267 ierr = DMGlobalToLocalBegin(rd->da,Xdot,INSERT_VALUES,*Xloc_t);CHKERRQ(ierr); 268 ierr = DMGlobalToLocalEnd(rd->da,Xdot,INSERT_VALUES,*Xloc_t);CHKERRQ(ierr); 269 270 /* 271 The following is a hack to subvert TSTHETA which is like an implicit midpoint method to behave more like a trapezoid 272 rule. These methods have equivalent linear stability, but the nonlinear stability is somewhat different. The 273 radiation system is inconvenient to write in explicit form because the ionization model is "on the left". 274 */ 275 ierr = PetscObjectTypeCompare((PetscObject)ts,TSTHETA,&istheta);CHKERRQ(ierr); 276 if (istheta && rd->endpoint) { 277 ierr = TSThetaGetTheta(ts,Theta);CHKERRQ(ierr); 278 } else *Theta = 1.; 279 280 ierr = TSGetTimeStep(ts,dt);CHKERRQ(ierr); 281 ierr = VecWAXPY(*X0loc,-(*Theta)*(*dt),*Xloc_t,*Xloc);CHKERRQ(ierr); /* back out the value at the start of this step */ 282 if (rd->endpoint) { 283 ierr = VecWAXPY(*Xloc,*dt,*Xloc_t,*X0loc);CHKERRQ(ierr); /* move the abscissa to the end of the step */ 284 } 285 286 ierr = DMDAVecGetArray(rd->da,*X0loc,x0);CHKERRQ(ierr); 287 ierr = DMDAVecGetArray(rd->da,*Xloc,x);CHKERRQ(ierr); 288 ierr = DMDAVecGetArray(rd->da,*Xloc_t,xdot);CHKERRQ(ierr); 289 PetscFunctionReturn(0); 290 } 291 292 static PetscErrorCode RDRestoreLocalArrays(RD rd,Vec *X0loc,RDNode **x0,Vec *Xloc,RDNode **x,Vec *Xloc_t,RDNode **xdot) 293 { 294 PetscErrorCode ierr; 295 296 PetscFunctionBeginUser; 297 ierr = DMDAVecRestoreArray(rd->da,*X0loc,x0);CHKERRQ(ierr); 298 ierr = DMDAVecRestoreArray(rd->da,*Xloc,x);CHKERRQ(ierr); 299 ierr = DMDAVecRestoreArray(rd->da,*Xloc_t,xdot);CHKERRQ(ierr); 300 ierr = DMRestoreLocalVector(rd->da,X0loc);CHKERRQ(ierr); 301 ierr = DMRestoreLocalVector(rd->da,Xloc);CHKERRQ(ierr); 302 ierr = DMRestoreLocalVector(rd->da,Xloc_t);CHKERRQ(ierr); 303 PetscFunctionReturn(0); 304 } 305 306 static PetscErrorCode RDCheckDomain_Private(RD rd,TS ts,Vec X,PetscBool *in) 307 { 308 PetscErrorCode ierr; 309 PetscInt minloc; 310 PetscReal min; 311 312 PetscFunctionBeginUser; 313 ierr = VecMin(X,&minloc,&min);CHKERRQ(ierr); 314 if (min < 0) { 315 SNES snes; 316 *in = PETSC_FALSE; 317 ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr); 318 ierr = SNESSetFunctionDomainError(snes);CHKERRQ(ierr); 319 ierr = PetscInfo3(ts,"Domain violation at %D field %D value %g\n",minloc/2,minloc%2,(double)min);CHKERRQ(ierr); 320 } else *in = PETSC_TRUE; 321 PetscFunctionReturn(0); 322 } 323 324 /* Energy and temperature must remain positive */ 325 #define RDCheckDomain(rd,ts,X) do { \ 326 PetscErrorCode _ierr; \ 327 PetscBool _in; \ 328 _ierr = RDCheckDomain_Private(rd,ts,X,&_in);CHKERRQ(_ierr); \ 329 if (!_in) PetscFunctionReturn(0); \ 330 } while (0) 331 332 static PetscErrorCode RDIFunction_FD(TS ts,PetscReal t,Vec X,Vec Xdot,Vec F,void *ctx) 333 { 334 PetscErrorCode ierr; 335 RD rd = (RD)ctx; 336 RDNode *x,*x0,*xdot,*f; 337 Vec X0loc,Xloc,Xloc_t; 338 PetscReal hx,Theta,dt; 339 DMDALocalInfo info; 340 PetscInt i; 341 342 PetscFunctionBeginUser; 343 RDCheckDomain(rd,ts,X); 344 ierr = RDGetLocalArrays(rd,ts,X,Xdot,&Theta,&dt,&X0loc,&x0,&Xloc,&x,&Xloc_t,&xdot);CHKERRQ(ierr); 345 ierr = DMDAVecGetArray(rd->da,F,&f);CHKERRQ(ierr); 346 ierr = DMDAGetLocalInfo(rd->da,&info);CHKERRQ(ierr); 347 VecZeroEntries(F); 348 349 hx = rd->L / (info.mx-1); 350 351 for (i=info.xs; i<info.xs+info.xm; i++) { 352 PetscReal rho = rd->rho; 353 PetscScalar Em_t,rad; 354 355 rad = (1.-Theta)*RDRadiation(rd,&x0[i],0) + Theta*RDRadiation(rd,&x[i],0); 356 if (rd->endpoint) { 357 PetscScalar Em0,Em1; 358 RDMaterialEnergy(rd,&x0[i],&Em0,NULL); 359 RDMaterialEnergy(rd,&x[i],&Em1,NULL); 360 Em_t = (Em1 - Em0) / dt; 361 } else { 362 RDNode dEm; 363 RDMaterialEnergy(rd,&x[i],NULL,&dEm); 364 Em_t = dEm.E * xdot[i].E + dEm.T * xdot[i].T; 365 } 366 /* Residuals are multiplied by the volume element (hx). */ 367 /* The temperature equation does not have boundary conditions */ 368 f[i].T = hx*(rho*Em_t + rad); 369 370 if (i == 0) { /* Left boundary condition */ 371 PetscScalar D_R,bcTheta = rd->bcmidpoint ? Theta : 1.; 372 RDNode n, nx; 373 374 n.E = (1.-bcTheta)*x0[0].E + bcTheta*x[0].E; 375 n.T = (1.-bcTheta)*x0[0].T + bcTheta*x[0].T; 376 nx.E = ((1.-bcTheta)*(x0[1].E-x0[0].E) + bcTheta*(x[1].E-x[0].E))/hx; 377 nx.T = ((1.-bcTheta)*(x0[1].T-x0[0].T) + bcTheta*(x[1].T-x[0].T))/hx; 378 switch (rd->leftbc) { 379 case BC_ROBIN: 380 RDDiffusionCoefficient(rd,rd->bclimit,&n,&nx,&D_R,0,0); 381 f[0].E = hx*(n.E - 2. * D_R * nx.E - rd->Eapplied); 382 break; 383 case BC_NEUMANN: 384 f[0].E = x[1].E - x[0].E; 385 break; 386 default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Case %D",rd->initial); 387 } 388 } else if (i == info.mx-1) { /* Right boundary */ 389 f[i].E = x[i].E - x[i-1].E; /* Homogeneous Neumann */ 390 } else { 391 PetscScalar diff = (1.-Theta)*RDDiffusion(rd,hx,x0,i,0) + Theta*RDDiffusion(rd,hx,x,i,0); 392 f[i].E = hx*(xdot[i].E - diff - rad); 393 } 394 } 395 ierr = RDRestoreLocalArrays(rd,&X0loc,&x0,&Xloc,&x,&Xloc_t,&xdot);CHKERRQ(ierr); 396 ierr = DMDAVecRestoreArray(rd->da,F,&f);CHKERRQ(ierr); 397 if (rd->monitor_residual) {ierr = RDStateView(rd,X,Xdot,F);CHKERRQ(ierr);} 398 PetscFunctionReturn(0); 399 } 400 401 static PetscErrorCode RDIJacobian_FD(TS ts,PetscReal t,Vec X,Vec Xdot,PetscReal a,Mat A,Mat B,void *ctx) 402 { 403 PetscErrorCode ierr; 404 RD rd = (RD)ctx; 405 RDNode *x,*x0,*xdot; 406 Vec X0loc,Xloc,Xloc_t; 407 PetscReal hx,Theta,dt; 408 DMDALocalInfo info; 409 PetscInt i; 410 411 PetscFunctionBeginUser; 412 RDCheckDomain(rd,ts,X); 413 ierr = RDGetLocalArrays(rd,ts,X,Xdot,&Theta,&dt,&X0loc,&x0,&Xloc,&x,&Xloc_t,&xdot);CHKERRQ(ierr); 414 ierr = DMDAGetLocalInfo(rd->da,&info);CHKERRQ(ierr); 415 hx = rd->L / (info.mx-1); 416 ierr = MatZeroEntries(B);CHKERRQ(ierr); 417 418 for (i=info.xs; i<info.xs+info.xm; i++) { 419 PetscInt col[3]; 420 PetscReal rho = rd->rho; 421 PetscScalar /*Em_t,rad,*/ K[2][6]; 422 RDNode dEm_t,drad; 423 424 /*rad = (1.-Theta)* */ RDRadiation(rd,&x0[i],0); /* + Theta* */ RDRadiation(rd,&x[i],&drad); 425 426 if (rd->endpoint) { 427 PetscScalar Em0,Em1; 428 RDNode dEm1; 429 RDMaterialEnergy(rd,&x0[i],&Em0,NULL); 430 RDMaterialEnergy(rd,&x[i],&Em1,&dEm1); 431 /*Em_t = (Em1 - Em0) / (Theta*dt);*/ 432 dEm_t.E = dEm1.E / (Theta*dt); 433 dEm_t.T = dEm1.T / (Theta*dt); 434 } else { 435 const PetscScalar epsilon = x[i].T * PETSC_SQRT_MACHINE_EPSILON; 436 RDNode n1; 437 RDNode dEm,dEm1; 438 PetscScalar Em_TT; 439 440 n1.E = x[i].E; 441 n1.T = x[i].T+epsilon; 442 RDMaterialEnergy(rd,&x[i],NULL,&dEm); 443 RDMaterialEnergy(rd,&n1,NULL,&dEm1); 444 /* The Jacobian needs another derivative. We finite difference here instead of 445 * propagating second derivatives through the ionization model. */ 446 Em_TT = (dEm1.T - dEm.T) / epsilon; 447 /*Em_t = dEm.E * xdot[i].E + dEm.T * xdot[i].T;*/ 448 dEm_t.E = dEm.E * a; 449 dEm_t.T = dEm.T * a + Em_TT * xdot[i].T; 450 } 451 452 ierr = PetscMemzero(K,sizeof(K));CHKERRQ(ierr); 453 /* Residuals are multiplied by the volume element (hx). */ 454 if (i == 0) { 455 PetscScalar D,bcTheta = rd->bcmidpoint ? Theta : 1.; 456 RDNode n, nx; 457 RDNode dD,dxD; 458 459 n.E = (1.-bcTheta)*x0[0].E + bcTheta*x[0].E; 460 n.T = (1.-bcTheta)*x0[0].T + bcTheta*x[0].T; 461 nx.E = ((1.-bcTheta)*(x0[1].E-x0[0].E) + bcTheta*(x[1].E-x[0].E))/hx; 462 nx.T = ((1.-bcTheta)*(x0[1].T-x0[0].T) + bcTheta*(x[1].T-x[0].T))/hx; 463 switch (rd->leftbc) { 464 case BC_ROBIN: 465 RDDiffusionCoefficient(rd,rd->bclimit,&n,&nx,&D,&dD,&dxD); 466 K[0][1*2+0] = (bcTheta/Theta)*hx*(1. -2.*D*(-1./hx) - 2.*nx.E*dD.E + 2.*nx.E*dxD.E/hx); 467 K[0][1*2+1] = (bcTheta/Theta)*hx*(-2.*nx.E*dD.T); 468 K[0][2*2+0] = (bcTheta/Theta)*hx*(-2.*D*(1./hx) - 2.*nx.E*dD.E - 2.*nx.E*dxD.E/hx); 469 break; 470 case BC_NEUMANN: 471 K[0][1*2+0] = -1./Theta; 472 K[0][2*2+0] = 1./Theta; 473 break; 474 default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Case %D",rd->initial); 475 } 476 } else if (i == info.mx-1) { 477 K[0][0*2+0] = -1./Theta; 478 K[0][1*2+0] = 1./Theta; 479 } else { 480 /*PetscScalar diff;*/ 481 RDNode ddiff[3]; 482 /*diff = (1.-Theta)*RDDiffusion(rd,hx,x0,i,0) + Theta* */ RDDiffusion(rd,hx,x,i,ddiff); 483 K[0][0*2+0] = -hx*ddiff[0].E; 484 K[0][0*2+1] = -hx*ddiff[0].T; 485 K[0][1*2+0] = hx*(a - ddiff[1].E - drad.E); 486 K[0][1*2+1] = hx*(-ddiff[1].T - drad.T); 487 K[0][2*2+0] = -hx*ddiff[2].E; 488 K[0][2*2+1] = -hx*ddiff[2].T; 489 } 490 491 K[1][1*2+0] = hx*(rho*dEm_t.E + drad.E); 492 K[1][1*2+1] = hx*(rho*dEm_t.T + drad.T); 493 494 col[0] = i-1; 495 col[1] = i; 496 col[2] = i+1<info.mx ? i+1 : -1; 497 ierr = MatSetValuesBlocked(B,1,&i,3,col,&K[0][0],INSERT_VALUES);CHKERRQ(ierr); 498 } 499 ierr = RDRestoreLocalArrays(rd,&X0loc,&x0,&Xloc,&x,&Xloc_t,&xdot);CHKERRQ(ierr); 500 ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 501 ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 502 if (A != B) { 503 ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 504 ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 505 } 506 PetscFunctionReturn(0); 507 } 508 509 /* Evaluate interpolants and derivatives at a select quadrature point */ 510 static void RDEvaluate(PetscReal interp[][2],PetscReal deriv[][2],PetscInt q,const RDNode x[],PetscInt i,RDNode *n,RDNode *nx) 511 { 512 PetscInt j; 513 n->E = 0; n->T = 0; nx->E = 0; nx->T = 0; 514 for (j=0; j<2; j++) { 515 n->E += interp[q][j] * x[i+j].E; 516 n->T += interp[q][j] * x[i+j].T; 517 nx->E += deriv[q][j] * x[i+j].E; 518 nx->T += deriv[q][j] * x[i+j].T; 519 } 520 } 521 522 /* 523 Various quadrature rules. The nonlinear terms are non-polynomial so no standard quadrature will be exact. 524 */ 525 static PetscErrorCode RDGetQuadrature(RD rd,PetscReal hx,PetscInt *nq,PetscReal weight[],PetscReal interp[][2],PetscReal deriv[][2]) 526 { 527 PetscInt q,j; 528 const PetscReal *refweight,(*refinterp)[2],(*refderiv)[2]; 529 530 PetscFunctionBeginUser; 531 switch (rd->quadrature) { 532 case QUADRATURE_GAUSS1: { 533 static const PetscReal ww[1] = {1.},ii[1][2] = {{0.5,0.5}},dd[1][2] = {{-1.,1.}}; 534 *nq = 1; refweight = ww; refinterp = ii; refderiv = dd; 535 } break; 536 case QUADRATURE_GAUSS2: { 537 static const PetscReal ii[2][2] = {{0.78867513459481287,0.21132486540518713},{0.21132486540518713,0.78867513459481287}},dd[2][2] = {{-1.,1.},{-1.,1.}},ww[2] = {0.5,0.5}; 538 *nq = 2; refweight = ww; refinterp = ii; refderiv = dd; 539 } break; 540 case QUADRATURE_GAUSS3: { 541 static const PetscReal ii[3][2] = {{0.8872983346207417,0.1127016653792583},{0.5,0.5},{0.1127016653792583,0.8872983346207417}}, 542 dd[3][2] = {{-1,1},{-1,1},{-1,1}},ww[3] = {5./18,8./18,5./18}; 543 *nq = 3; refweight = ww; refinterp = ii; refderiv = dd; 544 } break; 545 case QUADRATURE_GAUSS4: { 546 static const PetscReal ii[][2] = {{0.93056815579702623,0.069431844202973658}, 547 {0.66999052179242813,0.33000947820757187}, 548 {0.33000947820757187,0.66999052179242813}, 549 {0.069431844202973658,0.93056815579702623}}, 550 dd[][2] = {{-1,1},{-1,1},{-1,1},{-1,1}},ww[] = {0.17392742256872692,0.3260725774312731,0.3260725774312731,0.17392742256872692}; 551 552 *nq = 4; refweight = ww; refinterp = ii; refderiv = dd; 553 } break; 554 case QUADRATURE_LOBATTO2: { 555 static const PetscReal ii[2][2] = {{1.,0.},{0.,1.}},dd[2][2] = {{-1.,1.},{-1.,1.}},ww[2] = {0.5,0.5}; 556 *nq = 2; refweight = ww; refinterp = ii; refderiv = dd; 557 } break; 558 case QUADRATURE_LOBATTO3: { 559 static const PetscReal ii[3][2] = {{1,0},{0.5,0.5},{0,1}},dd[3][2] = {{-1,1},{-1,1},{-1,1}},ww[3] = {1./6,4./6,1./6}; 560 *nq = 3; refweight = ww; refinterp = ii; refderiv = dd; 561 } break; 562 default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unknown quadrature %d",(int)rd->quadrature); 563 } 564 565 for (q=0; q<*nq; q++) { 566 weight[q] = refweight[q] * hx; 567 for (j=0; j<2; j++) { 568 interp[q][j] = refinterp[q][j]; 569 deriv[q][j] = refderiv[q][j] / hx; 570 } 571 } 572 PetscFunctionReturn(0); 573 } 574 575 /* 576 Finite element version 577 */ 578 static PetscErrorCode RDIFunction_FE(TS ts,PetscReal t,Vec X,Vec Xdot,Vec F,void *ctx) 579 { 580 PetscErrorCode ierr; 581 RD rd = (RD)ctx; 582 RDNode *x,*x0,*xdot,*f; 583 Vec X0loc,Xloc,Xloc_t,Floc; 584 PetscReal hx,Theta,dt,weight[5],interp[5][2],deriv[5][2]; 585 DMDALocalInfo info; 586 PetscInt i,j,q,nq; 587 588 PetscFunctionBeginUser; 589 RDCheckDomain(rd,ts,X); 590 ierr = RDGetLocalArrays(rd,ts,X,Xdot,&Theta,&dt,&X0loc,&x0,&Xloc,&x,&Xloc_t,&xdot);CHKERRQ(ierr); 591 592 ierr = DMGetLocalVector(rd->da,&Floc);CHKERRQ(ierr); 593 ierr = VecZeroEntries(Floc);CHKERRQ(ierr); 594 ierr = DMDAVecGetArray(rd->da,Floc,&f);CHKERRQ(ierr); 595 ierr = DMDAGetLocalInfo(rd->da,&info);CHKERRQ(ierr); 596 597 /* Set up shape functions and quadrature for elements (assumes a uniform grid) */ 598 hx = rd->L / (info.mx-1); 599 ierr = RDGetQuadrature(rd,hx,&nq,weight,interp,deriv);CHKERRQ(ierr); 600 601 for (i=info.xs; i<PetscMin(info.xs+info.xm,info.mx-1); i++) { 602 for (q=0; q<nq; q++) { 603 PetscReal rho = rd->rho; 604 PetscScalar Em_t,rad,D_R,D0_R; 605 RDNode n,n0,nx,n0x,nt,ntx; 606 RDEvaluate(interp,deriv,q,x,i,&n,&nx); 607 RDEvaluate(interp,deriv,q,x0,i,&n0,&n0x); 608 RDEvaluate(interp,deriv,q,xdot,i,&nt,&ntx); 609 610 rad = (1.-Theta)*RDRadiation(rd,&n0,0) + Theta*RDRadiation(rd,&n,0); 611 if (rd->endpoint) { 612 PetscScalar Em0,Em1; 613 RDMaterialEnergy(rd,&n0,&Em0,NULL); 614 RDMaterialEnergy(rd,&n,&Em1,NULL); 615 Em_t = (Em1 - Em0) / dt; 616 } else { 617 RDNode dEm; 618 RDMaterialEnergy(rd,&n,NULL,&dEm); 619 Em_t = dEm.E * nt.E + dEm.T * nt.T; 620 } 621 RDDiffusionCoefficient(rd,PETSC_TRUE,&n0,&n0x,&D0_R,0,0); 622 RDDiffusionCoefficient(rd,PETSC_TRUE,&n,&nx,&D_R,0,0); 623 for (j=0; j<2; j++) { 624 f[i+j].E += (deriv[q][j] * weight[q] * ((1.-Theta)*D0_R*n0x.E + Theta*D_R*nx.E) 625 + interp[q][j] * weight[q] * (nt.E - rad)); 626 f[i+j].T += interp[q][j] * weight[q] * (rho * Em_t + rad); 627 } 628 } 629 } 630 if (info.xs == 0) { 631 switch (rd->leftbc) { 632 case BC_ROBIN: { 633 PetscScalar D_R,D_R_bc; 634 PetscReal ratio,bcTheta = rd->bcmidpoint ? Theta : 1.; 635 RDNode n, nx; 636 637 n.E = (1-bcTheta)*x0[0].E + bcTheta*x[0].E; 638 n.T = (1-bcTheta)*x0[0].T + bcTheta*x[0].T; 639 nx.E = (x[1].E-x[0].E)/hx; 640 nx.T = (x[1].T-x[0].T)/hx; 641 RDDiffusionCoefficient(rd,PETSC_TRUE,&n,&nx,&D_R,0,0); 642 RDDiffusionCoefficient(rd,rd->bclimit,&n,&nx,&D_R_bc,0,0); 643 ratio = PetscRealPart(D_R/D_R_bc); 644 if (ratio > 1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Limited diffusivity is greater than unlimited"); 645 if (ratio < 1e-3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Heavily limited diffusivity"); 646 f[0].E += -ratio*0.5*(rd->Eapplied - n.E); 647 } break; 648 case BC_NEUMANN: 649 /* homogeneous Neumann is the natural condition */ 650 break; 651 default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Case %D",rd->initial); 652 } 653 } 654 655 ierr = RDRestoreLocalArrays(rd,&X0loc,&x0,&Xloc,&x,&Xloc_t,&xdot);CHKERRQ(ierr); 656 ierr = DMDAVecRestoreArray(rd->da,Floc,&f);CHKERRQ(ierr); 657 ierr = VecZeroEntries(F);CHKERRQ(ierr); 658 ierr = DMLocalToGlobalBegin(rd->da,Floc,ADD_VALUES,F);CHKERRQ(ierr); 659 ierr = DMLocalToGlobalEnd(rd->da,Floc,ADD_VALUES,F);CHKERRQ(ierr); 660 ierr = DMRestoreLocalVector(rd->da,&Floc);CHKERRQ(ierr); 661 662 if (rd->monitor_residual) {ierr = RDStateView(rd,X,Xdot,F);CHKERRQ(ierr);} 663 PetscFunctionReturn(0); 664 } 665 666 static PetscErrorCode RDIJacobian_FE(TS ts,PetscReal t,Vec X,Vec Xdot,PetscReal a,Mat A,Mat B,void *ctx) 667 { 668 PetscErrorCode ierr; 669 RD rd = (RD)ctx; 670 RDNode *x,*x0,*xdot; 671 Vec X0loc,Xloc,Xloc_t; 672 PetscReal hx,Theta,dt,weight[5],interp[5][2],deriv[5][2]; 673 DMDALocalInfo info; 674 PetscInt i,j,k,q,nq; 675 PetscScalar K[4][4]; 676 677 PetscFunctionBeginUser; 678 RDCheckDomain(rd,ts,X); 679 ierr = RDGetLocalArrays(rd,ts,X,Xdot,&Theta,&dt,&X0loc,&x0,&Xloc,&x,&Xloc_t,&xdot);CHKERRQ(ierr); 680 ierr = DMDAGetLocalInfo(rd->da,&info);CHKERRQ(ierr); 681 hx = rd->L / (info.mx-1); 682 ierr = RDGetQuadrature(rd,hx,&nq,weight,interp,deriv);CHKERRQ(ierr); 683 ierr = MatZeroEntries(B);CHKERRQ(ierr); 684 for (i=info.xs; i<PetscMin(info.xs+info.xm,info.mx-1); i++) { 685 PetscInt rc[2]; 686 687 rc[0] = i; rc[1] = i+1; 688 ierr = PetscMemzero(K,sizeof(K));CHKERRQ(ierr); 689 for (q=0; q<nq; q++) { 690 PetscScalar D_R; 691 PETSC_UNUSED PetscScalar rad; 692 RDNode n,nx,nt,ntx,drad,dD_R,dxD_R,dEm; 693 RDEvaluate(interp,deriv,q,x,i,&n,&nx); 694 RDEvaluate(interp,deriv,q,xdot,i,&nt,&ntx); 695 rad = RDRadiation(rd,&n,&drad); 696 RDDiffusionCoefficient(rd,PETSC_TRUE,&n,&nx,&D_R,&dD_R,&dxD_R); 697 RDMaterialEnergy(rd,&n,NULL,&dEm); 698 for (j=0; j<2; j++) { 699 for (k=0; k<2; k++) { 700 K[j*2+0][k*2+0] += (+interp[q][j] * weight[q] * (a - drad.E) * interp[q][k] 701 + deriv[q][j] * weight[q] * ((D_R + dxD_R.E * nx.E) * deriv[q][k] + dD_R.E * nx.E * interp[q][k])); 702 K[j*2+0][k*2+1] += (+interp[q][j] * weight[q] * (-drad.T * interp[q][k]) 703 + deriv[q][j] * weight[q] * (dxD_R.T * deriv[q][k] + dD_R.T * interp[q][k]) * nx.E); 704 K[j*2+1][k*2+0] += interp[q][j] * weight[q] * drad.E * interp[q][k]; 705 K[j*2+1][k*2+1] += interp[q][j] * weight[q] * (a * rd->rho * dEm.T + drad.T) * interp[q][k]; 706 } 707 } 708 } 709 ierr = MatSetValuesBlocked(B,2,rc,2,rc,&K[0][0],ADD_VALUES);CHKERRQ(ierr); 710 } 711 if (info.xs == 0) { 712 switch (rd->leftbc) { 713 case BC_ROBIN: { 714 PetscScalar D_R,D_R_bc; 715 PetscReal ratio; 716 RDNode n, nx; 717 718 n.E = (1-Theta)*x0[0].E + Theta*x[0].E; 719 n.T = (1-Theta)*x0[0].T + Theta*x[0].T; 720 nx.E = (x[1].E-x[0].E)/hx; 721 nx.T = (x[1].T-x[0].T)/hx; 722 RDDiffusionCoefficient(rd,PETSC_TRUE,&n,&nx,&D_R,0,0); 723 RDDiffusionCoefficient(rd,rd->bclimit,&n,&nx,&D_R_bc,0,0); 724 ratio = PetscRealPart(D_R/D_R_bc); 725 ierr = MatSetValue(B,0,0,ratio*0.5,ADD_VALUES);CHKERRQ(ierr); 726 } break; 727 case BC_NEUMANN: 728 /* homogeneous Neumann is the natural condition */ 729 break; 730 default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Case %D",rd->initial); 731 } 732 } 733 734 ierr = RDRestoreLocalArrays(rd,&X0loc,&x0,&Xloc,&x,&Xloc_t,&xdot);CHKERRQ(ierr); 735 ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 736 ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 737 if (A != B) { 738 ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 739 ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 740 } 741 PetscFunctionReturn(0); 742 } 743 744 /* Temperature that is in equilibrium with the radiation density */ 745 static PetscScalar RDRadiationTemperature(RD rd,PetscScalar E) { return PetscPowScalar(E*rd->c/(4.*rd->sigma_b),0.25); } 746 747 static PetscErrorCode RDInitialState(RD rd,Vec X) 748 { 749 DMDALocalInfo info; 750 PetscInt i; 751 RDNode *x; 752 PetscErrorCode ierr; 753 754 PetscFunctionBeginUser; 755 ierr = DMDAGetLocalInfo(rd->da,&info);CHKERRQ(ierr); 756 ierr = DMDAVecGetArray(rd->da,X,&x);CHKERRQ(ierr); 757 for (i=info.xs; i<info.xs+info.xm; i++) { 758 PetscReal coord = i*rd->L/(info.mx-1); 759 switch (rd->initial) { 760 case 1: 761 x[i].E = 0.001; 762 x[i].T = RDRadiationTemperature(rd,x[i].E); 763 break; 764 case 2: 765 x[i].E = 0.001 + 100.*PetscExpReal(-PetscSqr(coord/0.1)); 766 x[i].T = RDRadiationTemperature(rd,x[i].E); 767 break; 768 case 3: 769 x[i].E = 7.56e-2 * rd->unit.Joule / PetscPowScalarInt(rd->unit.meter,3); 770 x[i].T = RDRadiationTemperature(rd,x[i].E); 771 break; 772 default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"No initial state %D",rd->initial); 773 } 774 } 775 ierr = DMDAVecRestoreArray(rd->da,X,&x);CHKERRQ(ierr); 776 PetscFunctionReturn(0); 777 } 778 779 static PetscErrorCode RDView(RD rd,Vec X,PetscViewer viewer) 780 { 781 PetscErrorCode ierr; 782 Vec Y; 783 const RDNode *x; 784 PetscScalar *y; 785 PetscInt i,m,M; 786 const PetscInt *lx; 787 DM da; 788 MPI_Comm comm; 789 790 PetscFunctionBeginUser; 791 /* 792 Create a DMDA (one dof per node, zero stencil width, same layout) to hold Trad 793 (radiation temperature). It is not necessary to create a DMDA for this, but this way 794 output and visualization will have meaningful variable names and correct scales. 795 */ 796 ierr = DMDAGetInfo(rd->da,0, &M,0,0, 0,0,0, 0,0,0,0,0,0);CHKERRQ(ierr); 797 ierr = DMDAGetOwnershipRanges(rd->da,&lx,0,0);CHKERRQ(ierr); 798 ierr = PetscObjectGetComm((PetscObject)rd->da,&comm);CHKERRQ(ierr); 799 ierr = DMDACreate1d(comm,DM_BOUNDARY_NONE,M,1,0,lx,&da);CHKERRQ(ierr); 800 ierr = DMSetFromOptions(da);CHKERRQ(ierr); 801 ierr = DMSetUp(da);CHKERRQ(ierr); 802 ierr = DMDASetUniformCoordinates(da,0.,rd->L,0.,0.,0.,0.);CHKERRQ(ierr); 803 ierr = DMDASetFieldName(da,0,"T_rad");CHKERRQ(ierr); 804 ierr = DMCreateGlobalVector(da,&Y);CHKERRQ(ierr); 805 806 /* Compute the radiation temperature from the solution at each node */ 807 ierr = VecGetLocalSize(Y,&m);CHKERRQ(ierr); 808 ierr = VecGetArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr); 809 ierr = VecGetArray(Y,&y);CHKERRQ(ierr); 810 for (i=0; i<m; i++) y[i] = RDRadiationTemperature(rd,x[i].E); 811 ierr = VecRestoreArrayRead(X,(const PetscScalar**)&x);CHKERRQ(ierr); 812 ierr = VecRestoreArray(Y,&y);CHKERRQ(ierr); 813 814 ierr = VecView(Y,viewer);CHKERRQ(ierr); 815 ierr = VecDestroy(&Y);CHKERRQ(ierr); 816 ierr = DMDestroy(&da);CHKERRQ(ierr); 817 PetscFunctionReturn(0); 818 } 819 820 static PetscErrorCode RDTestDifferentiation(RD rd) 821 { 822 MPI_Comm comm; 823 PetscErrorCode ierr; 824 RDNode n,nx; 825 PetscScalar epsilon; 826 827 PetscFunctionBeginUser; 828 ierr = PetscObjectGetComm((PetscObject)rd->da,&comm);CHKERRQ(ierr); 829 epsilon = 1e-8; 830 { 831 RDNode dEm,fdEm; 832 PetscScalar T0 = 1000.,T1 = T0*(1.+epsilon),Em0,Em1; 833 n.E = 1.; 834 n.T = T0; 835 rd->MaterialEnergy(rd,&n,&Em0,&dEm); 836 n.E = 1.+epsilon; 837 n.T = T0; 838 rd->MaterialEnergy(rd,&n,&Em1,0); 839 fdEm.E = (Em1-Em0)/epsilon; 840 n.E = 1.; 841 n.T = T1; 842 rd->MaterialEnergy(rd,&n,&Em1,0); 843 fdEm.T = (Em1-Em0)/(T0*epsilon); 844 ierr = PetscPrintf(comm,"dEm {%g,%g}, fdEm {%g,%g}, diff {%g,%g}\n",(double)PetscRealPart(dEm.E),(double)PetscRealPart(dEm.T), 845 (double)PetscRealPart(fdEm.E),(double)PetscRealPart(fdEm.T),(double)PetscRealPart(dEm.E-fdEm.E),(double)PetscRealPart(dEm.T-fdEm.T));CHKERRQ(ierr); 846 } 847 { 848 PetscScalar D0,D; 849 RDNode dD,dxD,fdD,fdxD; 850 n.E = 1.; n.T = 1.; nx.E = 1.; n.T = 1.; 851 RDDiffusionCoefficient(rd,rd->bclimit,&n,&nx,&D0,&dD,&dxD); 852 n.E = 1.+epsilon; n.T = 1.; nx.E = 1.; n.T = 1.; 853 RDDiffusionCoefficient(rd,rd->bclimit,&n,&nx,&D,0,0); fdD.E = (D-D0)/epsilon; 854 n.E = 1; n.T = 1.+epsilon; nx.E = 1.; n.T = 1.; 855 RDDiffusionCoefficient(rd,rd->bclimit,&n,&nx,&D,0,0); fdD.T = (D-D0)/epsilon; 856 n.E = 1; n.T = 1.; nx.E = 1.+epsilon; n.T = 1.; 857 RDDiffusionCoefficient(rd,rd->bclimit,&n,&nx,&D,0,0); fdxD.E = (D-D0)/epsilon; 858 n.E = 1; n.T = 1.; nx.E = 1.; n.T = 1.+epsilon; 859 RDDiffusionCoefficient(rd,rd->bclimit,&n,&nx,&D,0,0); fdxD.T = (D-D0)/epsilon; 860 ierr = PetscPrintf(comm,"dD {%g,%g}, fdD {%g,%g}, diff {%g,%g}\n",(double)PetscRealPart(dD.E),(double)PetscRealPart(dD.T), 861 (double)PetscRealPart(fdD.E),(double)PetscRealPart(fdD.T),(double)PetscRealPart(dD.E-fdD.E),(double)PetscRealPart(dD.T-fdD.T));CHKERRQ(ierr); 862 ierr = PetscPrintf(comm,"dxD {%g,%g}, fdxD {%g,%g}, diffx {%g,%g}\n",(double)PetscRealPart(dxD.E),(double)PetscRealPart(dxD.T), 863 (double)PetscRealPart(fdxD.E),(double)PetscRealPart(fdxD.T),(double)PetscRealPart(dxD.E-fdxD.E),(double)PetscRealPart(dxD.T-fdxD.T));CHKERRQ(ierr); 864 } 865 { 866 PetscInt i; 867 PetscReal hx = 1.; 868 PetscScalar a0; 869 RDNode n0[3],n1[3],d[3],fd[3]; 870 871 n0[0].E = 1.; 872 n0[0].T = 1.; 873 n0[1].E = 5.; 874 n0[1].T = 3.; 875 n0[2].E = 4.; 876 n0[2].T = 2.; 877 a0 = RDDiffusion(rd,hx,n0,1,d); 878 for (i=0; i<3; i++) { 879 ierr = PetscMemcpy(n1,n0,sizeof(n0));CHKERRQ(ierr); n1[i].E += epsilon; 880 fd[i].E = (RDDiffusion(rd,hx,n1,1,0)-a0)/epsilon; 881 ierr = PetscMemcpy(n1,n0,sizeof(n0));CHKERRQ(ierr); n1[i].T += epsilon; 882 fd[i].T = (RDDiffusion(rd,hx,n1,1,0)-a0)/epsilon; 883 ierr = PetscPrintf(comm,"ddiff[%D] {%g,%g}, fd {%g %g}, diff {%g,%g}\n",i,(double)PetscRealPart(d[i].E),(double)PetscRealPart(d[i].T), 884 (double)PetscRealPart(fd[i].E),(double)PetscRealPart(fd[i].T),(double)PetscRealPart(d[i].E-fd[i].E),(double)PetscRealPart(d[i].T-fd[i].T));CHKERRQ(ierr); 885 } 886 } 887 { 888 PetscScalar rad0,rad; 889 RDNode drad,fdrad; 890 n.E = 1.; n.T = 1.; 891 rad0 = RDRadiation(rd,&n,&drad); 892 n.E = 1.+epsilon; n.T = 1.; 893 rad = RDRadiation(rd,&n,0); fdrad.E = (rad-rad0)/epsilon; 894 n.E = 1.; n.T = 1.+epsilon; 895 rad = RDRadiation(rd,&n,0); fdrad.T = (rad-rad0)/epsilon; 896 ierr = PetscPrintf(comm,"drad {%g,%g}, fdrad {%g,%g}, diff {%g,%g}\n",(double)PetscRealPart(drad.E),(double)PetscRealPart(drad.T), 897 (double)PetscRealPart(fdrad.E),(double)PetscRealPart(fdrad.T),(double)PetscRealPart(drad.E-drad.E),(double)PetscRealPart(drad.T-fdrad.T));CHKERRQ(ierr); 898 } 899 PetscFunctionReturn(0); 900 } 901 902 static PetscErrorCode RDCreate(MPI_Comm comm,RD *inrd) 903 { 904 PetscErrorCode ierr; 905 RD rd; 906 PetscReal meter=0,kilogram=0,second=0,Kelvin=0,Joule=0,Watt=0; 907 908 PetscFunctionBeginUser; 909 *inrd = 0; 910 ierr = PetscNew(&rd);CHKERRQ(ierr); 911 912 ierr = PetscOptionsBegin(comm,NULL,"Options for nonequilibrium radiation-diffusion with RD ionization",NULL);CHKERRQ(ierr); 913 { 914 rd->initial = 1; 915 ierr = PetscOptionsInt("-rd_initial","Initial condition (1=Marshak, 2=Blast, 3=Marshak+)","",rd->initial,&rd->initial,0);CHKERRQ(ierr); 916 switch (rd->initial) { 917 case 1: 918 case 2: 919 rd->unit.kilogram = 1.; 920 rd->unit.meter = 1.; 921 rd->unit.second = 1.; 922 rd->unit.Kelvin = 1.; 923 break; 924 case 3: 925 rd->unit.kilogram = 1.e12; 926 rd->unit.meter = 1.; 927 rd->unit.second = 1.e9; 928 rd->unit.Kelvin = 1.; 929 break; 930 default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unknown initial condition %d",rd->initial); 931 } 932 /* Fundamental units */ 933 ierr = PetscOptionsReal("-rd_unit_meter","Length of 1 meter in nondimensional units","",rd->unit.meter,&rd->unit.meter,0);CHKERRQ(ierr); 934 ierr = PetscOptionsReal("-rd_unit_kilogram","Mass of 1 kilogram in nondimensional units","",rd->unit.kilogram,&rd->unit.kilogram,0);CHKERRQ(ierr); 935 ierr = PetscOptionsReal("-rd_unit_second","Time of a second in nondimensional units","",rd->unit.second,&rd->unit.second,0);CHKERRQ(ierr); 936 ierr = PetscOptionsReal("-rd_unit_Kelvin","Temperature of a Kelvin in nondimensional units","",rd->unit.Kelvin,&rd->unit.Kelvin,0);CHKERRQ(ierr); 937 /* Derived units */ 938 rd->unit.Joule = rd->unit.kilogram*PetscSqr(rd->unit.meter/rd->unit.second); 939 rd->unit.Watt = rd->unit.Joule/rd->unit.second; 940 /* Local aliases */ 941 meter = rd->unit.meter; 942 kilogram = rd->unit.kilogram; 943 second = rd->unit.second; 944 Kelvin = rd->unit.Kelvin; 945 Joule = rd->unit.Joule; 946 Watt = rd->unit.Watt; 947 948 ierr = PetscOptionsBool("-rd_monitor_residual","Display residuals every time they are evaluated","",rd->monitor_residual,&rd->monitor_residual,NULL);CHKERRQ(ierr); 949 ierr = PetscOptionsEnum("-rd_discretization","Discretization type","",DiscretizationTypes,(PetscEnum)rd->discretization,(PetscEnum*)&rd->discretization,NULL);CHKERRQ(ierr); 950 if (rd->discretization == DISCRETIZATION_FE) { 951 rd->quadrature = QUADRATURE_GAUSS2; 952 ierr = PetscOptionsEnum("-rd_quadrature","Finite element quadrature","",QuadratureTypes,(PetscEnum)rd->quadrature,(PetscEnum*)&rd->quadrature,NULL);CHKERRQ(ierr); 953 } 954 ierr = PetscOptionsEnum("-rd_jacobian","Type of finite difference Jacobian","",JacobianTypes,(PetscEnum)rd->jacobian,(PetscEnum*)&rd->jacobian,NULL);CHKERRQ(ierr); 955 switch (rd->initial) { 956 case 1: 957 rd->leftbc = BC_ROBIN; 958 rd->Eapplied = 4 * rd->unit.Joule / PetscPowRealInt(rd->unit.meter,3); 959 rd->L = 1. * rd->unit.meter; 960 rd->beta = 3.0; 961 rd->gamma = 3.0; 962 rd->final_time = 3 * second; 963 break; 964 case 2: 965 rd->leftbc = BC_NEUMANN; 966 rd->Eapplied = 0.; 967 rd->L = 1. * rd->unit.meter; 968 rd->beta = 3.0; 969 rd->gamma = 3.0; 970 rd->final_time = 1 * second; 971 break; 972 case 3: 973 rd->leftbc = BC_ROBIN; 974 rd->Eapplied = 7.503e6 * rd->unit.Joule / PetscPowRealInt(rd->unit.meter,3); 975 rd->L = 5. * rd->unit.meter; 976 rd->beta = 3.5; 977 rd->gamma = 3.5; 978 rd->final_time = 20e-9 * second; 979 break; 980 default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Initial %D",rd->initial); 981 } 982 ierr = PetscOptionsEnum("-rd_leftbc","Left boundary condition","",BCTypes,(PetscEnum)rd->leftbc,(PetscEnum*)&rd->leftbc,NULL);CHKERRQ(ierr); 983 ierr = PetscOptionsReal("-rd_E_applied","Radiation flux at left end of domain","",rd->Eapplied,&rd->Eapplied,NULL);CHKERRQ(ierr); 984 ierr = PetscOptionsReal("-rd_beta","Thermal exponent for photon absorption","",rd->beta,&rd->beta,NULL);CHKERRQ(ierr); 985 ierr = PetscOptionsReal("-rd_gamma","Thermal exponent for diffusion coefficient","",rd->gamma,&rd->gamma,NULL);CHKERRQ(ierr); 986 ierr = PetscOptionsBool("-rd_view_draw","Draw final solution","",rd->view_draw,&rd->view_draw,NULL);CHKERRQ(ierr); 987 ierr = PetscOptionsBool("-rd_endpoint","Discretize using endpoints (like trapezoid rule) instead of midpoint","",rd->endpoint,&rd->endpoint,NULL);CHKERRQ(ierr); 988 ierr = PetscOptionsBool("-rd_bcmidpoint","Impose the boundary condition at the midpoint (Theta) of the interval","",rd->bcmidpoint,&rd->bcmidpoint,NULL);CHKERRQ(ierr); 989 ierr = PetscOptionsBool("-rd_bclimit","Limit diffusion coefficient in definition of Robin boundary condition","",rd->bclimit,&rd->bclimit,NULL);CHKERRQ(ierr); 990 ierr = PetscOptionsBool("-rd_test_diff","Test differentiation in constitutive relations","",rd->test_diff,&rd->test_diff,NULL);CHKERRQ(ierr); 991 ierr = PetscOptionsString("-rd_view_binary","File name to hold final solution","",rd->view_binary,rd->view_binary,sizeof(rd->view_binary),NULL);CHKERRQ(ierr); 992 } 993 ierr = PetscOptionsEnd();CHKERRQ(ierr); 994 995 switch (rd->initial) { 996 case 1: 997 case 2: 998 rd->rho = 1.; 999 rd->c = 1.; 1000 rd->K_R = 1.; 1001 rd->K_p = 1.; 1002 rd->sigma_b = 0.25; 1003 rd->MaterialEnergy = RDMaterialEnergy_Reduced; 1004 break; 1005 case 3: 1006 /* Table 2 */ 1007 rd->rho = 1.17e-3 * kilogram / (meter*meter*meter); /* density */ 1008 rd->K_R = 7.44e18 * PetscPowRealInt(meter,5) * PetscPowReal(Kelvin,3.5) * PetscPowRealInt(kilogram,-2); /* */ 1009 rd->K_p = 2.33e20 * PetscPowRealInt(meter,5) * PetscPowReal(Kelvin,3.5) * PetscPowRealInt(kilogram,-2); /* */ 1010 rd->I_H = 2.179e-18 * Joule; /* Hydrogen ionization potential */ 1011 rd->m_p = 1.673e-27 * kilogram; /* proton mass */ 1012 rd->m_e = 9.109e-31 * kilogram; /* electron mass */ 1013 rd->h = 6.626e-34 * Joule * second; /* Planck's constant */ 1014 rd->k = 1.381e-23 * Joule / Kelvin; /* Boltzman constant */ 1015 rd->c = 3.00e8 * meter / second; /* speed of light */ 1016 rd->sigma_b = 5.67e-8 * Watt * PetscPowRealInt(meter,-2) * PetscPowRealInt(Kelvin,-4); /* Stefan-Boltzman constant */ 1017 rd->MaterialEnergy = RDMaterialEnergy_Saha; 1018 break; 1019 } 1020 1021 ierr = DMDACreate1d(comm,DM_BOUNDARY_NONE,20,sizeof(RDNode)/sizeof(PetscScalar),1,NULL,&rd->da);CHKERRQ(ierr); 1022 ierr = DMSetFromOptions(rd->da);CHKERRQ(ierr); 1023 ierr = DMSetUp(rd->da);CHKERRQ(ierr); 1024 ierr = DMDASetFieldName(rd->da,0,"E");CHKERRQ(ierr); 1025 ierr = DMDASetFieldName(rd->da,1,"T");CHKERRQ(ierr); 1026 ierr = DMDASetUniformCoordinates(rd->da,0.,1.,0.,0.,0.,0.);CHKERRQ(ierr); 1027 1028 *inrd = rd; 1029 PetscFunctionReturn(0); 1030 } 1031 1032 int main(int argc, char *argv[]) 1033 { 1034 PetscErrorCode ierr; 1035 RD rd; 1036 TS ts; 1037 SNES snes; 1038 Vec X; 1039 Mat A,B; 1040 PetscInt steps; 1041 PetscReal ftime; 1042 1043 ierr = PetscInitialize(&argc,&argv,0,help);if (ierr) return ierr; 1044 ierr = RDCreate(PETSC_COMM_WORLD,&rd);CHKERRQ(ierr); 1045 ierr = DMCreateGlobalVector(rd->da,&X);CHKERRQ(ierr); 1046 ierr = DMSetMatType(rd->da,MATAIJ);CHKERRQ(ierr); 1047 ierr = DMCreateMatrix(rd->da,&B);CHKERRQ(ierr); 1048 ierr = RDInitialState(rd,X);CHKERRQ(ierr); 1049 1050 ierr = TSCreate(PETSC_COMM_WORLD,&ts);CHKERRQ(ierr); 1051 ierr = TSSetProblemType(ts,TS_NONLINEAR);CHKERRQ(ierr); 1052 ierr = TSSetType(ts,TSTHETA);CHKERRQ(ierr); 1053 ierr = TSSetDM(ts,rd->da);CHKERRQ(ierr); 1054 switch (rd->discretization) { 1055 case DISCRETIZATION_FD: 1056 ierr = TSSetIFunction(ts,NULL,RDIFunction_FD,rd);CHKERRQ(ierr); 1057 if (rd->jacobian == JACOBIAN_ANALYTIC) {ierr = TSSetIJacobian(ts,B,B,RDIJacobian_FD,rd);CHKERRQ(ierr);} 1058 break; 1059 case DISCRETIZATION_FE: 1060 ierr = TSSetIFunction(ts,NULL,RDIFunction_FE,rd);CHKERRQ(ierr); 1061 if (rd->jacobian == JACOBIAN_ANALYTIC) {ierr = TSSetIJacobian(ts,B,B,RDIJacobian_FE,rd);CHKERRQ(ierr);} 1062 break; 1063 } 1064 ierr = TSSetMaxTime(ts,rd->final_time);CHKERRQ(ierr); 1065 ierr = TSSetTimeStep(ts,1e-3);CHKERRQ(ierr); 1066 ierr = TSSetExactFinalTime(ts,TS_EXACTFINALTIME_STEPOVER);CHKERRQ(ierr); 1067 ierr = TSSetFromOptions(ts);CHKERRQ(ierr); 1068 1069 A = B; 1070 ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr); 1071 switch (rd->jacobian) { 1072 case JACOBIAN_ANALYTIC: 1073 break; 1074 case JACOBIAN_MATRIXFREE: 1075 break; 1076 case JACOBIAN_FD_COLORING: { 1077 ierr = SNESSetJacobian(snes,A,B,SNESComputeJacobianDefaultColor,0);CHKERRQ(ierr); 1078 } break; 1079 case JACOBIAN_FD_FULL: 1080 ierr = SNESSetJacobian(snes,A,B,SNESComputeJacobianDefault,ts);CHKERRQ(ierr); 1081 break; 1082 } 1083 1084 if (rd->test_diff) { 1085 ierr = RDTestDifferentiation(rd);CHKERRQ(ierr); 1086 } 1087 ierr = TSSolve(ts,X);CHKERRQ(ierr); 1088 ierr = TSGetSolveTime(ts,&ftime);CHKERRQ(ierr); 1089 ierr = TSGetStepNumber(ts,&steps);CHKERRQ(ierr); 1090 ierr = PetscPrintf(PETSC_COMM_WORLD,"Steps %D final time %g\n",steps,(double)ftime);CHKERRQ(ierr); 1091 if (rd->view_draw) { 1092 ierr = RDView(rd,X,PETSC_VIEWER_DRAW_WORLD);CHKERRQ(ierr); 1093 } 1094 if (rd->view_binary[0]) { 1095 PetscViewer viewer; 1096 ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,rd->view_binary,FILE_MODE_WRITE,&viewer);CHKERRQ(ierr); 1097 ierr = RDView(rd,X,viewer);CHKERRQ(ierr); 1098 ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); 1099 } 1100 ierr = VecDestroy(&X);CHKERRQ(ierr); 1101 ierr = MatDestroy(&B);CHKERRQ(ierr); 1102 ierr = RDDestroy(&rd);CHKERRQ(ierr); 1103 ierr = TSDestroy(&ts);CHKERRQ(ierr); 1104 ierr = PetscFinalize(); 1105 return ierr; 1106 } 1107 /*TEST 1108 1109 test: 1110 args: -da_grid_x 20 -rd_initial 1 -rd_discretization fd -rd_jacobian fd_coloring -rd_endpoint -ts_max_time 1 -ts_dt 2e-1 -ts_theta_initial_guess_extrapolate 0 -ts_monitor -snes_monitor_short -ksp_monitor_short 1111 requires: !single 1112 1113 test: 1114 suffix: 2 1115 args: -da_grid_x 20 -rd_initial 1 -rd_discretization fe -rd_quadrature lobatto2 -rd_jacobian fd_coloring -rd_endpoint -ts_max_time 1 -ts_dt 2e-1 -ts_theta_initial_guess_extrapolate 0 -ts_monitor -snes_monitor_short -ksp_monitor_short 1116 requires: !single 1117 1118 test: 1119 suffix: 3 1120 nsize: 2 1121 args: -da_grid_x 20 -rd_initial 1 -rd_discretization fd -rd_jacobian analytic -rd_endpoint -ts_max_time 3 -ts_dt 1e-1 -ts_theta_initial_guess_extrapolate 0 -ts_monitor -snes_monitor_short -ksp_monitor_short 1122 requires: !single 1123 1124 TEST*/ 1125