Actual source code: ex5.c
1: static char help[] = "Nonlinear, time-dependent. Developed from radiative_surface_balance.c \n";
2: /*
3: Contributed by Steve Froehlich, Illinois Institute of Technology
5: Usage:
6: mpiexec -n <np> ./ex5 [options]
7: ./ex5 -help [view petsc options]
8: ./ex5 -ts_type sundials -ts_view
9: ./ex5 -da_grid_x 20 -da_grid_y 20 -log_view
10: ./ex5 -da_grid_x 20 -da_grid_y 20 -ts_type rosw -ts_atol 1.e-6 -ts_rtol 1.e-6
11: ./ex5 -drawcontours -draw_pause 0.1 -draw_fields 0,1,2,3,4
12: */
14: /*
15: -----------------------------------------------------------------------
17: Governing equations:
19: R = s*(Ea*Ta^4 - Es*Ts^4)
20: SH = p*Cp*Ch*wind*(Ta - Ts)
21: LH = p*L*Ch*wind*B(q(Ta) - q(Ts))
22: G = k*(Tgnd - Ts)/dz
24: Fnet = R + SH + LH + G
26: du/dt = -u*(du/dx) - v*(du/dy) - 2*omeg*sin(lat)*v - (1/p)*(dP/dx)
27: dv/dt = -u*(dv/dx) - v*(dv/dy) + 2*omeg*sin(lat)*u - (1/p)*(dP/dy)
28: dTs/dt = Fnet/(Cp*dz) - Div([u*Ts, v*Ts]) + D*Lap(Ts)
29: = Fnet/(Cs*dz) - u*(dTs/dx) - v*(dTs/dy) + D*(Ts_xx + Ts_yy)
30: dp/dt = -Div([u*p,v*p])
31: = - u*dp/dx - v*dp/dy
32: dTa/dt = Fnet/Cp
34: Equation of State:
36: P = p*R*Ts
38: -----------------------------------------------------------------------
40: Program considers the evolution of a two dimensional atmosphere from
41: sunset to sunrise. There are two components:
42: 1. Surface energy balance model to compute diabatic dT (Fnet)
43: 2. Dynamical model using simplified primitive equations
45: Program is to be initiated at sunset and run to sunrise.
47: Inputs are:
48: Surface temperature
49: Dew point temperature
50: Air temperature
51: Temperature at cloud base (if clouds are present)
52: Fraction of sky covered by clouds
53: Wind speed
54: Precipitable water in centimeters
55: Wind direction
57: Inputs are read in from the text file ex5_control.txt. To change an
58: input value use ex5_control.txt.
60: Solvers:
61: Backward Euler = default solver
62: Sundials = fastest and most accurate, requires Sundials libraries
64: This model is under development and should be used only as an example
65: and not as a predictive weather model.
66: */
68: #include <petscts.h>
69: #include <petscdm.h>
70: #include <petscdmda.h>
72: /* stefan-boltzmann constant */
73: #define SIG 0.000000056703
74: /* absorption-emission constant for surface */
75: #define EMMSFC 1
76: /* amount of time (seconds) that passes before new flux is calculated */
77: #define TIMESTEP 1
79: /* variables of interest to be solved at each grid point */
80: typedef struct {
81: PetscScalar Ts, Ta; /* surface and air temperature */
82: PetscScalar u, v; /* wind speed */
83: PetscScalar p; /* density */
84: } Field;
86: /* User defined variables. Used in solving for variables of interest */
87: typedef struct {
88: DM da; /* grid */
89: PetscScalar csoil; /* heat constant for layer */
90: PetscScalar dzlay; /* thickness of top soil layer */
91: PetscScalar emma; /* emission parameter */
92: PetscScalar wind; /* wind speed */
93: PetscScalar dewtemp; /* dew point temperature (moisture in air) */
94: PetscScalar pressure1; /* sea level pressure */
95: PetscScalar airtemp; /* temperature of air near boundary layer inversion */
96: PetscScalar Ts; /* temperature at the surface */
97: PetscScalar fract; /* fraction of sky covered by clouds */
98: PetscScalar Tc; /* temperature at base of lowest cloud layer */
99: PetscScalar lat; /* Latitude in degrees */
100: PetscScalar init; /* initialization scenario */
101: PetscScalar deep_grnd_temp; /* temperature of ground under top soil surface layer */
102: } AppCtx;
104: /* Struct for visualization */
105: typedef struct {
106: PetscBool drawcontours; /* flag - 1 indicates drawing contours */
107: PetscViewer drawviewer;
108: PetscInt interval;
109: } MonitorCtx;
111: /* Inputs read in from text file */
112: struct in {
113: PetscScalar Ts; /* surface temperature */
114: PetscScalar Td; /* dewpoint temperature */
115: PetscScalar Tc; /* temperature of cloud base */
116: PetscScalar fr; /* fraction of sky covered by clouds */
117: PetscScalar wnd; /* wind speed */
118: PetscScalar Ta; /* air temperature */
119: PetscScalar pwt; /* precipitable water */
120: PetscScalar wndDir; /* wind direction */
121: PetscScalar lat; /* latitude */
122: PetscReal time; /* time in hours */
123: PetscScalar init;
124: };
126: /* functions */
127: extern PetscScalar emission(PetscScalar); /* sets emission/absorption constant depending on water vapor content */
128: extern PetscScalar calc_q(PetscScalar); /* calculates specific humidity */
129: extern PetscScalar mph2mpers(PetscScalar); /* converts miles per hour to meters per second */
130: extern PetscScalar Lconst(PetscScalar); /* calculates latent heat constant taken from Satellite estimates of wind speed and latent heat flux over the global oceans., Bentamy et al. */
131: extern PetscScalar fahr_to_cel(PetscScalar); /* converts Fahrenheit to Celsius */
132: extern PetscScalar cel_to_fahr(PetscScalar); /* converts Celsius to Fahrenheit */
133: extern PetscScalar calcmixingr(PetscScalar, PetscScalar); /* calculates mixing ratio */
134: extern PetscScalar cloud(PetscScalar); /* cloud radiative parameterization */
135: extern PetscErrorCode FormInitialSolution(DM, Vec, void *); /* Specifies initial conditions for the system of equations (PETSc defined function) */
136: extern PetscErrorCode RhsFunc(TS, PetscReal, Vec, Vec, void *); /* Specifies the user defined functions (PETSc defined function) */
137: extern PetscErrorCode Monitor(TS, PetscInt, PetscReal, Vec, void *); /* Specifies output and visualization tools (PETSc defined function) */
138: extern PetscErrorCode readinput(struct in *put); /* reads input from text file */
139: extern PetscErrorCode calcfluxs(PetscScalar, PetscScalar, PetscScalar, PetscScalar, PetscScalar, PetscScalar *); /* calculates upward IR from surface */
140: extern PetscErrorCode calcfluxa(PetscScalar, PetscScalar, PetscScalar, PetscScalar *); /* calculates downward IR from atmosphere */
141: extern PetscErrorCode sensibleflux(PetscScalar, PetscScalar, PetscScalar, PetscScalar *); /* calculates sensible heat flux */
142: extern PetscErrorCode potential_temperature(PetscScalar, PetscScalar, PetscScalar, PetscScalar, PetscScalar *); /* calculates potential temperature */
143: extern PetscErrorCode latentflux(PetscScalar, PetscScalar, PetscScalar, PetscScalar, PetscScalar *); /* calculates latent heat flux */
144: extern PetscErrorCode calc_gflux(PetscScalar, PetscScalar, PetscScalar *); /* calculates flux between top soil layer and underlying earth */
146: int main(int argc, char **argv)
147: {
148: PetscInt time; /* amount of loops */
149: struct in put;
150: PetscScalar rh; /* relative humidity */
151: PetscScalar x; /* memory variable for relative humidity calculation */
152: PetscScalar deep_grnd_temp; /* temperature of ground under top soil surface layer */
153: PetscScalar emma; /* absorption-emission constant for air */
154: PetscScalar pressure1 = 101300; /* surface pressure */
155: PetscScalar mixratio; /* mixing ratio */
156: PetscScalar airtemp; /* temperature of air near boundary layer inversion */
157: PetscScalar dewtemp; /* dew point temperature */
158: PetscScalar sfctemp; /* temperature at surface */
159: PetscScalar pwat; /* total column precipitable water */
160: PetscScalar cloudTemp; /* temperature at base of cloud */
161: AppCtx user; /* user-defined work context */
162: MonitorCtx usermonitor; /* user-defined monitor context */
163: TS ts;
164: SNES snes;
165: DM da;
166: Vec T, rhs; /* solution vector */
167: Mat J; /* Jacobian matrix */
168: PetscReal ftime, dt;
169: PetscInt steps, dof = 5;
170: PetscBool use_coloring = PETSC_TRUE;
171: MatFDColoring matfdcoloring = 0;
172: PetscBool monitor_off = PETSC_FALSE;
173: PetscBool prunejacobian = PETSC_FALSE;
175: PetscFunctionBeginUser;
176: PetscCall(PetscInitialize(&argc, &argv, NULL, help));
178: /* Inputs */
179: PetscCall(readinput(&put));
181: sfctemp = put.Ts;
182: dewtemp = put.Td;
183: cloudTemp = put.Tc;
184: airtemp = put.Ta;
185: pwat = put.pwt;
187: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Initial Temperature = %g\n", (double)sfctemp)); /* input surface temperature */
189: deep_grnd_temp = sfctemp - 10; /* set underlying ground layer temperature */
190: emma = emission(pwat); /* accounts for radiative effects of water vapor */
192: /* Converts from Fahrenheit to Celsius */
193: sfctemp = fahr_to_cel(sfctemp);
194: airtemp = fahr_to_cel(airtemp);
195: dewtemp = fahr_to_cel(dewtemp);
196: cloudTemp = fahr_to_cel(cloudTemp);
197: deep_grnd_temp = fahr_to_cel(deep_grnd_temp);
199: /* Converts from Celsius to Kelvin */
200: sfctemp += 273;
201: airtemp += 273;
202: dewtemp += 273;
203: cloudTemp += 273;
204: deep_grnd_temp += 273;
206: /* Calculates initial relative humidity */
207: x = calcmixingr(dewtemp, pressure1);
208: mixratio = calcmixingr(sfctemp, pressure1);
209: rh = (x / mixratio) * 100;
211: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Initial RH = %.1f percent\n\n", (double)rh)); /* prints initial relative humidity */
213: time = 3600 * put.time; /* sets amount of timesteps to run model */
215: /* Configure PETSc TS solver */
216: /*------------------------------------------*/
218: /* Create grid */
219: PetscCall(DMDACreate2d(PETSC_COMM_WORLD, DM_BOUNDARY_PERIODIC, DM_BOUNDARY_PERIODIC, DMDA_STENCIL_STAR, 20, 20, PETSC_DECIDE, PETSC_DECIDE, dof, 1, NULL, NULL, &da));
220: PetscCall(DMSetFromOptions(da));
221: PetscCall(DMSetUp(da));
222: PetscCall(DMDASetUniformCoordinates(da, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0));
224: /* Define output window for each variable of interest */
225: PetscCall(DMDASetFieldName(da, 0, "Ts"));
226: PetscCall(DMDASetFieldName(da, 1, "Ta"));
227: PetscCall(DMDASetFieldName(da, 2, "u"));
228: PetscCall(DMDASetFieldName(da, 3, "v"));
229: PetscCall(DMDASetFieldName(da, 4, "p"));
231: /* set values for appctx */
232: user.da = da;
233: user.Ts = sfctemp;
234: user.fract = put.fr; /* fraction of sky covered by clouds */
235: user.dewtemp = dewtemp; /* dew point temperature (mositure in air) */
236: user.csoil = 2000000; /* heat constant for layer */
237: user.dzlay = 0.08; /* thickness of top soil layer */
238: user.emma = emma; /* emission parameter */
239: user.wind = put.wnd; /* wind speed */
240: user.pressure1 = pressure1; /* sea level pressure */
241: user.airtemp = airtemp; /* temperature of air near boundar layer inversion */
242: user.Tc = cloudTemp; /* temperature at base of lowest cloud layer */
243: user.init = put.init; /* user chosen initiation scenario */
244: user.lat = 70 * 0.0174532; /* converts latitude degrees to latitude in radians */
245: user.deep_grnd_temp = deep_grnd_temp; /* temp in lowest ground layer */
247: /* set values for MonitorCtx */
248: usermonitor.drawcontours = PETSC_FALSE;
249: PetscCall(PetscOptionsHasName(NULL, NULL, "-drawcontours", &usermonitor.drawcontours));
250: if (usermonitor.drawcontours) {
251: PetscReal bounds[] = {1000.0, -1000., -1000., -1000., 1000., -1000., 1000., -1000., 1000, -1000, 100700, 100800};
252: PetscCall(PetscViewerDrawOpen(PETSC_COMM_WORLD, 0, 0, 0, 0, 300, 300, &usermonitor.drawviewer));
253: PetscCall(PetscViewerDrawSetBounds(usermonitor.drawviewer, dof, bounds));
254: }
255: usermonitor.interval = 1;
256: PetscCall(PetscOptionsGetInt(NULL, NULL, "-monitor_interval", &usermonitor.interval, NULL));
258: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
259: Extract global vectors from DA;
260: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
261: PetscCall(DMCreateGlobalVector(da, &T));
262: PetscCall(VecDuplicate(T, &rhs)); /* r: vector to put the computed right-hand side */
264: PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
265: PetscCall(TSSetProblemType(ts, TS_NONLINEAR));
266: PetscCall(TSSetType(ts, TSBEULER));
267: PetscCall(TSSetRHSFunction(ts, rhs, RhsFunc, &user));
269: /* Set Jacobian evaluation routine - use coloring to compute finite difference Jacobian efficiently */
270: PetscCall(DMSetMatType(da, MATAIJ));
271: PetscCall(DMCreateMatrix(da, &J));
272: if (use_coloring) {
273: ISColoring iscoloring;
274: PetscInt ncolors;
276: PetscCall(DMCreateColoring(da, IS_COLORING_GLOBAL, &iscoloring));
277: PetscCall(MatFDColoringCreate(J, iscoloring, &matfdcoloring));
278: PetscCall(MatFDColoringSetFromOptions(matfdcoloring));
279: PetscCall(MatFDColoringSetUp(J, iscoloring, matfdcoloring));
280: PetscCall(ISColoringGetColors(iscoloring, NULL, &ncolors, NULL));
281: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "DMColoring generates %" PetscInt_FMT " colors\n", ncolors));
282: PetscCall(ISColoringDestroy(&iscoloring));
283: PetscCall(TSSetIJacobian(ts, J, J, TSComputeIJacobianDefaultColor, NULL));
284: } else {
285: PetscCall(TSGetSNES(ts, &snes));
286: PetscCall(SNESSetJacobian(snes, J, J, SNESComputeJacobianDefault, NULL));
287: }
289: /* Define what to print for ts_monitor option */
290: PetscCall(PetscOptionsHasName(NULL, NULL, "-monitor_off", &monitor_off));
291: if (!monitor_off) PetscCall(TSMonitorSet(ts, Monitor, &usermonitor, NULL));
292: dt = TIMESTEP; /* initial time step */
293: ftime = TIMESTEP * time;
294: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "time %" PetscInt_FMT ", ftime %g hour, TIMESTEP %g\n", time, (double)(ftime / 3600), (double)dt));
296: PetscCall(TSSetTimeStep(ts, dt));
297: PetscCall(TSSetMaxSteps(ts, time));
298: PetscCall(TSSetMaxTime(ts, ftime));
299: PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER));
300: PetscCall(TSSetSolution(ts, T));
301: PetscCall(TSSetDM(ts, da));
303: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
304: Set runtime options
305: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
306: PetscCall(PetscOptionsGetBool(NULL, NULL, "-prune_jacobian", &prunejacobian, NULL));
307: PetscCall(TSSetFromOptions(ts));
308: if (prunejacobian && matfdcoloring) {
309: PetscRandom rctx;
310: Vec Tdot;
311: /* Compute the Jacobian with randomized vector values to capture the sparsity pattern for coloring */
312: PetscCall(VecDuplicate(T, &Tdot));
313: PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rctx));
314: PetscCall(PetscRandomSetInterval(rctx, 1.0, 2.0));
315: PetscCall(VecSetRandom(T, rctx));
316: PetscCall(VecSetRandom(Tdot, rctx));
317: PetscCall(PetscRandomDestroy(&rctx));
318: PetscCall(TSSetUp(ts));
319: PetscCall(TSComputeIJacobian(ts, 0.0, T, Tdot, 0.12345, J, J, PETSC_FALSE));
320: PetscCall(VecDestroy(&Tdot));
321: PetscCall(MatFDColoringDestroy(&matfdcoloring));
322: PetscCall(TSPruneIJacobianColor(ts, J, J));
323: }
324: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
325: Solve nonlinear system
326: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
327: PetscCall(FormInitialSolution(da, T, &user));
328: PetscCall(TSSolve(ts, T));
329: PetscCall(TSGetSolveTime(ts, &ftime));
330: PetscCall(TSGetStepNumber(ts, &steps));
331: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Solution T after %g hours %" PetscInt_FMT " steps\n", (double)(ftime / 3600), steps));
333: if (matfdcoloring) PetscCall(MatFDColoringDestroy(&matfdcoloring));
334: if (usermonitor.drawcontours) PetscCall(PetscViewerDestroy(&usermonitor.drawviewer));
335: PetscCall(MatDestroy(&J));
336: PetscCall(VecDestroy(&T));
337: PetscCall(VecDestroy(&rhs));
338: PetscCall(TSDestroy(&ts));
339: PetscCall(DMDestroy(&da));
341: PetscCall(PetscFinalize());
342: return 0;
343: }
344: /*****************************end main program********************************/
345: /*****************************************************************************/
346: /*****************************************************************************/
347: /*****************************************************************************/
348: PetscErrorCode calcfluxs(PetscScalar sfctemp, PetscScalar airtemp, PetscScalar emma, PetscScalar fract, PetscScalar cloudTemp, PetscScalar *flux)
349: {
350: PetscFunctionBeginUser;
351: *flux = SIG * ((EMMSFC * emma * PetscPowScalarInt(airtemp, 4)) + (EMMSFC * fract * (1 - emma) * PetscPowScalarInt(cloudTemp, 4)) - (EMMSFC * PetscPowScalarInt(sfctemp, 4))); /* calculates flux using Stefan-Boltzmann relation */
352: PetscFunctionReturn(PETSC_SUCCESS);
353: }
355: PetscErrorCode calcfluxa(PetscScalar sfctemp, PetscScalar airtemp, PetscScalar emma, PetscScalar *flux) /* this function is not currently called upon */
356: {
357: PetscScalar emm = 0.001;
359: PetscFunctionBeginUser;
360: *flux = SIG * (-emm * (PetscPowScalarInt(airtemp, 4))); /* calculates flux usinge Stefan-Boltzmann relation */
361: PetscFunctionReturn(PETSC_SUCCESS);
362: }
363: PetscErrorCode sensibleflux(PetscScalar sfctemp, PetscScalar airtemp, PetscScalar wind, PetscScalar *sheat)
364: {
365: PetscScalar density = 1; /* air density */
366: PetscScalar Cp = 1005; /* heat capacity for dry air */
367: PetscScalar wndmix; /* temperature change from wind mixing: wind*Ch */
369: PetscFunctionBeginUser;
370: wndmix = 0.0025 + 0.0042 * wind; /* regression equation valid for neutral and stable BL */
371: *sheat = density * Cp * wndmix * (airtemp - sfctemp); /* calculates sensible heat flux */
372: PetscFunctionReturn(PETSC_SUCCESS);
373: }
375: PetscErrorCode latentflux(PetscScalar sfctemp, PetscScalar dewtemp, PetscScalar wind, PetscScalar pressure1, PetscScalar *latentheat)
376: {
377: PetscScalar density = 1; /* density of dry air */
378: PetscScalar q; /* actual specific humitity */
379: PetscScalar qs; /* saturation specific humidity */
380: PetscScalar wndmix; /* temperature change from wind mixing: wind*Ch */
381: PetscScalar beta = .4; /* moisture availability */
382: PetscScalar mr; /* mixing ratio */
383: PetscScalar lhcnst; /* latent heat of vaporization constant = 2501000 J/kg at 0c */
384: /* latent heat of saturation const = 2834000 J/kg */
385: /* latent heat of fusion const = 333700 J/kg */
387: PetscFunctionBeginUser;
388: wind = mph2mpers(wind); /* converts wind from mph to meters per second */
389: wndmix = 0.0025 + 0.0042 * wind; /* regression equation valid for neutral BL */
390: lhcnst = Lconst(sfctemp); /* calculates latent heat of evaporation */
391: mr = calcmixingr(sfctemp, pressure1); /* calculates saturation mixing ratio */
392: qs = calc_q(mr); /* calculates saturation specific humidty */
393: mr = calcmixingr(dewtemp, pressure1); /* calculates mixing ratio */
394: q = calc_q(mr); /* calculates specific humidty */
396: *latentheat = density * wndmix * beta * lhcnst * (q - qs); /* calculates latent heat flux */
397: PetscFunctionReturn(PETSC_SUCCESS);
398: }
400: PetscErrorCode potential_temperature(PetscScalar temp, PetscScalar pressure1, PetscScalar pressure2, PetscScalar sfctemp, PetscScalar *pottemp)
401: {
402: PetscScalar kdry; /* poisson constant for dry atmosphere */
403: PetscScalar pavg; /* average atmospheric pressure */
404: /* PetscScalar mixratio; mixing ratio */
405: /* PetscScalar kmoist; poisson constant for moist atmosphere */
407: PetscFunctionBeginUser;
408: /* mixratio = calcmixingr(sfctemp,pressure1); */
410: /* initialize poisson constant */
411: kdry = 0.2854;
412: /* kmoist = 0.2854*(1 - 0.24*mixratio); */
414: pavg = ((0.7 * pressure1) + pressure2) / 2; /* calculates simple average press */
415: *pottemp = temp * (PetscPowScalar(pressure1 / pavg, kdry)); /* calculates potential temperature */
416: PetscFunctionReturn(PETSC_SUCCESS);
417: }
418: extern PetscScalar calcmixingr(PetscScalar dtemp, PetscScalar pressure1)
419: {
420: PetscScalar e; /* vapor pressure */
421: PetscScalar mixratio; /* mixing ratio */
423: dtemp = dtemp - 273; /* converts from Kelvin to Celsius */
424: e = 6.11 * (PetscPowScalar(10, (7.5 * dtemp) / (237.7 + dtemp))); /* converts from dew point temp to vapor pressure */
425: e = e * 100; /* converts from hPa to Pa */
426: mixratio = (0.622 * e) / (pressure1 - e); /* computes mixing ratio */
427: mixratio = mixratio * 1; /* convert to g/Kg */
429: return mixratio;
430: }
431: extern PetscScalar calc_q(PetscScalar rv)
432: {
433: PetscScalar specific_humidity; /* define specific humidity variable */
434: specific_humidity = rv / (1 + rv); /* calculates specific humidity */
435: return specific_humidity;
436: }
438: PetscErrorCode calc_gflux(PetscScalar sfctemp, PetscScalar deep_grnd_temp, PetscScalar *Gflux)
439: {
440: PetscScalar k; /* thermal conductivity parameter */
441: PetscScalar n = 0.38; /* value of soil porosity */
442: PetscScalar dz = 1; /* depth of layer between soil surface and deep soil layer */
443: PetscScalar unit_soil_weight = 2700; /* unit soil weight in kg/m^3 */
445: PetscFunctionBeginUser;
446: k = ((0.135 * (1 - n) * unit_soil_weight) + 64.7) / (unit_soil_weight - (0.947 * (1 - n) * unit_soil_weight)); /* dry soil conductivity */
447: *Gflux = (k * (deep_grnd_temp - sfctemp) / dz); /* calculates flux from deep ground layer */
448: PetscFunctionReturn(PETSC_SUCCESS);
449: }
450: extern PetscScalar emission(PetscScalar pwat)
451: {
452: PetscScalar emma;
454: emma = 0.725 + 0.17 * PetscLog10Real(PetscRealPart(pwat));
456: return emma;
457: }
458: extern PetscScalar cloud(PetscScalar fract)
459: {
460: PetscScalar emma = 0;
462: /* modifies radiative balance depending on cloud cover */
463: if (fract >= 0.9) emma = 1;
464: else if (0.9 > fract && fract >= 0.8) emma = 0.9;
465: else if (0.8 > fract && fract >= 0.7) emma = 0.85;
466: else if (0.7 > fract && fract >= 0.6) emma = 0.75;
467: else if (0.6 > fract && fract >= 0.5) emma = 0.65;
468: else if (0.4 > fract && fract >= 0.3) emma = emma * 1.086956;
469: return emma;
470: }
471: extern PetscScalar Lconst(PetscScalar sfctemp)
472: {
473: PetscScalar Lheat;
474: sfctemp -= 273; /* converts from kelvin to celsius */
475: Lheat = 4186.8 * (597.31 - 0.5625 * sfctemp); /* calculates latent heat constant */
476: return Lheat;
477: }
478: extern PetscScalar mph2mpers(PetscScalar wind)
479: {
480: wind = ((wind * 1.6 * 1000) / 3600); /* converts wind from mph to meters per second */
481: return wind;
482: }
483: extern PetscScalar fahr_to_cel(PetscScalar temp)
484: {
485: temp = (5 * (temp - 32)) / 9; /* converts from farhrenheit to celsius */
486: return temp;
487: }
488: extern PetscScalar cel_to_fahr(PetscScalar temp)
489: {
490: temp = ((temp * 9) / 5) + 32; /* converts from celsius to farhrenheit */
491: return temp;
492: }
493: PetscErrorCode readinput(struct in *put)
494: {
495: int i;
496: char x;
497: FILE *ifp;
498: double tmp;
500: PetscFunctionBeginUser;
501: ifp = fopen("ex5_control.txt", "r");
502: PetscCheck(ifp, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open input file");
503: for (i = 0; i < 110; i++) PetscCheck(fscanf(ifp, "%c", &x) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
504: PetscCheck(fscanf(ifp, "%lf", &tmp) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
505: put->Ts = tmp;
507: for (i = 0; i < 43; i++) PetscCheck(fscanf(ifp, "%c", &x) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
508: PetscCheck(fscanf(ifp, "%lf", &tmp) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
509: put->Td = tmp;
511: for (i = 0; i < 43; i++) PetscCheck(fscanf(ifp, "%c", &x) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
512: PetscCheck(fscanf(ifp, "%lf", &tmp) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
513: put->Ta = tmp;
515: for (i = 0; i < 43; i++) PetscCheck(fscanf(ifp, "%c", &x) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
516: PetscCheck(fscanf(ifp, "%lf", &tmp) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
517: put->Tc = tmp;
519: for (i = 0; i < 43; i++) PetscCheck(fscanf(ifp, "%c", &x) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
520: PetscCheck(fscanf(ifp, "%lf", &tmp) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
521: put->fr = tmp;
523: for (i = 0; i < 43; i++) PetscCheck(fscanf(ifp, "%c", &x) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
524: PetscCheck(fscanf(ifp, "%lf", &tmp) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
525: put->wnd = tmp;
527: for (i = 0; i < 43; i++) PetscCheck(fscanf(ifp, "%c", &x) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
528: PetscCheck(fscanf(ifp, "%lf", &tmp) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
529: put->pwt = tmp;
531: for (i = 0; i < 43; i++) PetscCheck(fscanf(ifp, "%c", &x) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
532: PetscCheck(fscanf(ifp, "%lf", &tmp) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
533: put->wndDir = tmp;
535: for (i = 0; i < 43; i++) PetscCheck(fscanf(ifp, "%c", &x) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
536: PetscCheck(fscanf(ifp, "%lf", &tmp) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
537: put->time = tmp;
539: for (i = 0; i < 63; i++) PetscCheck(fscanf(ifp, "%c", &x) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
540: PetscCheck(fscanf(ifp, "%lf", &tmp) == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read file");
541: put->init = tmp;
542: PetscFunctionReturn(PETSC_SUCCESS);
543: }
545: /* ------------------------------------------------------------------- */
546: PetscErrorCode FormInitialSolution(DM da, Vec Xglobal, void *ctx)
547: {
548: AppCtx *user = (AppCtx *)ctx; /* user-defined application context */
549: PetscInt i, j, xs, ys, xm, ym, Mx, My;
550: Field **X;
552: PetscFunctionBeginUser;
553: PetscCall(DMDAGetInfo(da, PETSC_IGNORE, &Mx, &My, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE));
555: /* Get pointers to vector data */
556: PetscCall(DMDAVecGetArray(da, Xglobal, &X));
558: /* Get local grid boundaries */
559: PetscCall(DMDAGetCorners(da, &xs, &ys, NULL, &xm, &ym, NULL));
561: /* Compute function over the locally owned part of the grid */
563: if (user->init == 1) {
564: for (j = ys; j < ys + ym; j++) {
565: for (i = xs; i < xs + xm; i++) {
566: X[j][i].Ts = user->Ts - i * 0.0001;
567: X[j][i].Ta = X[j][i].Ts - 5;
568: X[j][i].u = 0;
569: X[j][i].v = 0;
570: X[j][i].p = 1.25;
571: if ((j == 5 || j == 6) && (i == 4 || i == 5)) X[j][i].p += 0.00001;
572: if ((j == 5 || j == 6) && (i == 12 || i == 13)) X[j][i].p += 0.00001;
573: }
574: }
575: } else {
576: for (j = ys; j < ys + ym; j++) {
577: for (i = xs; i < xs + xm; i++) {
578: X[j][i].Ts = user->Ts;
579: X[j][i].Ta = X[j][i].Ts - 5;
580: X[j][i].u = 0;
581: X[j][i].v = 0;
582: X[j][i].p = 1.25;
583: }
584: }
585: }
587: /* Restore vectors */
588: PetscCall(DMDAVecRestoreArray(da, Xglobal, &X));
589: PetscFunctionReturn(PETSC_SUCCESS);
590: }
592: /*
593: RhsFunc - Evaluates nonlinear function F(u).
595: Input Parameters:
596: . ts - the TS context
597: . t - current time
598: . Xglobal - input vector
599: . F - output vector
600: . ptr - optional user-defined context, as set by SNESSetFunction()
602: Output Parameter:
603: . F - rhs function vector
604: */
605: PetscErrorCode RhsFunc(TS ts, PetscReal t, Vec Xglobal, Vec F, void *ctx)
606: {
607: AppCtx *user = (AppCtx *)ctx; /* user-defined application context */
608: DM da = user->da;
609: PetscInt i, j, Mx, My, xs, ys, xm, ym;
610: PetscReal dhx, dhy;
611: Vec localT;
612: Field **X, **Frhs; /* structures that contain variables of interest and left hand side of governing equations respectively */
613: PetscScalar csoil = user->csoil; /* heat constant for layer */
614: PetscScalar dzlay = user->dzlay; /* thickness of top soil layer */
615: PetscScalar emma = user->emma; /* emission parameter */
616: PetscScalar wind = user->wind; /* wind speed */
617: PetscScalar dewtemp = user->dewtemp; /* dew point temperature (moisture in air) */
618: PetscScalar pressure1 = user->pressure1; /* sea level pressure */
619: PetscScalar airtemp = user->airtemp; /* temperature of air near boundary layer inversion */
620: PetscScalar fract = user->fract; /* fraction of the sky covered by clouds */
621: PetscScalar Tc = user->Tc; /* temperature at base of lowest cloud layer */
622: PetscScalar lat = user->lat; /* latitude */
623: PetscScalar Cp = 1005.7; /* specific heat of air at constant pressure */
624: PetscScalar Rd = 287.058; /* gas constant for dry air */
625: PetscScalar diffconst = 1000; /* diffusion coefficient */
626: PetscScalar f = 2 * 0.0000727 * PetscSinScalar(lat); /* coriolis force */
627: PetscScalar deep_grnd_temp = user->deep_grnd_temp; /* temp in lowest ground layer */
628: PetscScalar Ts, u, v, p;
629: PetscScalar u_abs, u_plus, u_minus, v_abs, v_plus, v_minus;
631: PetscScalar sfctemp1, fsfc1, Ra;
632: PetscScalar sheat; /* sensible heat flux */
633: PetscScalar latentheat; /* latent heat flux */
634: PetscScalar groundflux; /* flux from conduction of deep ground layer in contact with top soil */
635: PetscInt xend, yend;
637: PetscFunctionBeginUser;
638: PetscCall(DMGetLocalVector(da, &localT));
639: PetscCall(DMDAGetInfo(da, PETSC_IGNORE, &Mx, &My, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE));
641: dhx = (PetscReal)(Mx - 1) / (5000 * (Mx - 1)); /* dhx = 1/dx; assume 2D space domain: [0.0, 1.e5] x [0.0, 1.e5] */
642: dhy = (PetscReal)(My - 1) / (5000 * (Mx - 1)); /* dhy = 1/dy; */
644: /*
645: Scatter ghost points to local vector,using the 2-step process
646: DAGlobalToLocalBegin(),DAGlobalToLocalEnd().
647: By placing code between these two statements, computations can be
648: done while messages are in transition.
649: */
650: PetscCall(DMGlobalToLocalBegin(da, Xglobal, INSERT_VALUES, localT));
651: PetscCall(DMGlobalToLocalEnd(da, Xglobal, INSERT_VALUES, localT));
653: /* Get pointers to vector data */
654: PetscCall(DMDAVecGetArrayRead(da, localT, &X));
655: PetscCall(DMDAVecGetArray(da, F, &Frhs));
657: /* Get local grid boundaries */
658: PetscCall(DMDAGetCorners(da, &xs, &ys, NULL, &xm, &ym, NULL));
660: /* Compute function over the locally owned part of the grid */
661: /* the interior points */
662: xend = xs + xm;
663: yend = ys + ym;
664: for (j = ys; j < yend; j++) {
665: for (i = xs; i < xend; i++) {
666: Ts = X[j][i].Ts;
667: u = X[j][i].u;
668: v = X[j][i].v;
669: p = X[j][i].p; /*P = X[j][i].P; */
671: sfctemp1 = (double)Ts;
672: PetscCall(calcfluxs(sfctemp1, airtemp, emma, fract, Tc, &fsfc1)); /* calculates surface net radiative flux */
673: PetscCall(sensibleflux(sfctemp1, airtemp, wind, &sheat)); /* calculate sensible heat flux */
674: PetscCall(latentflux(sfctemp1, dewtemp, wind, pressure1, &latentheat)); /* calculates latent heat flux */
675: PetscCall(calc_gflux(sfctemp1, deep_grnd_temp, &groundflux)); /* calculates flux from earth below surface soil layer by conduction */
676: PetscCall(calcfluxa(sfctemp1, airtemp, emma, &Ra)); /* Calculates the change in downward radiative flux */
677: fsfc1 = fsfc1 + latentheat + sheat + groundflux; /* adds radiative, sensible heat, latent heat, and ground heat flux yielding net flux */
679: /* convective coefficients for upwinding */
680: u_abs = PetscAbsScalar(u);
681: u_plus = .5 * (u + u_abs); /* u if u>0; 0 if u<0 */
682: u_minus = .5 * (u - u_abs); /* u if u <0; 0 if u>0 */
684: v_abs = PetscAbsScalar(v);
685: v_plus = .5 * (v + v_abs); /* v if v>0; 0 if v<0 */
686: v_minus = .5 * (v - v_abs); /* v if v <0; 0 if v>0 */
688: /* Solve governing equations */
689: /* P = p*Rd*Ts; */
691: /* du/dt -> time change of east-west component of the wind */
692: Frhs[j][i].u = -u_plus * (u - X[j][i - 1].u) * dhx - u_minus * (X[j][i + 1].u - u) * dhx /* - u(du/dx) */
693: - v_plus * (u - X[j - 1][i].u) * dhy - v_minus * (X[j + 1][i].u - u) * dhy /* - v(du/dy) */
694: - (Rd / p) * (Ts * (X[j][i + 1].p - X[j][i - 1].p) * 0.5 * dhx + p * 0 * (X[j][i + 1].Ts - X[j][i - 1].Ts) * 0.5 * dhx) /* -(R/p)[Ts(dp/dx)+ p(dTs/dx)] */
695: /* -(1/p)*(X[j][i+1].P - X[j][i-1].P)*dhx */
696: + f * v;
698: /* dv/dt -> time change of north-south component of the wind */
699: Frhs[j][i].v = -u_plus * (v - X[j][i - 1].v) * dhx - u_minus * (X[j][i + 1].v - v) * dhx /* - u(dv/dx) */
700: - v_plus * (v - X[j - 1][i].v) * dhy - v_minus * (X[j + 1][i].v - v) * dhy /* - v(dv/dy) */
701: - (Rd / p) * (Ts * (X[j + 1][i].p - X[j - 1][i].p) * 0.5 * dhy + p * 0 * (X[j + 1][i].Ts - X[j - 1][i].Ts) * 0.5 * dhy) /* -(R/p)[Ts(dp/dy)+ p(dTs/dy)] */
702: /* -(1/p)*(X[j+1][i].P - X[j-1][i].P)*dhy */
703: - f * u;
705: /* dT/dt -> time change of temperature */
706: Frhs[j][i].Ts = (fsfc1 / (csoil * dzlay)) /* Fnet/(Cp*dz) diabatic change in T */
707: - u_plus * (Ts - X[j][i - 1].Ts) * dhx - u_minus * (X[j][i + 1].Ts - Ts) * dhx /* - u*(dTs/dx) advection x */
708: - v_plus * (Ts - X[j - 1][i].Ts) * dhy - v_minus * (X[j + 1][i].Ts - Ts) * dhy /* - v*(dTs/dy) advection y */
709: + diffconst * ((X[j][i + 1].Ts - 2 * Ts + X[j][i - 1].Ts) * dhx * dhx /* + D(Ts_xx + Ts_yy) diffusion */
710: + (X[j + 1][i].Ts - 2 * Ts + X[j - 1][i].Ts) * dhy * dhy);
712: /* dp/dt -> time change of */
713: Frhs[j][i].p = -u_plus * (p - X[j][i - 1].p) * dhx - u_minus * (X[j][i + 1].p - p) * dhx /* - u*(dp/dx) */
714: - v_plus * (p - X[j - 1][i].p) * dhy - v_minus * (X[j + 1][i].p - p) * dhy; /* - v*(dp/dy) */
716: Frhs[j][i].Ta = Ra / Cp; /* dTa/dt time change of air temperature */
717: }
718: }
720: /* Restore vectors */
721: PetscCall(DMDAVecRestoreArrayRead(da, localT, &X));
722: PetscCall(DMDAVecRestoreArray(da, F, &Frhs));
723: PetscCall(DMRestoreLocalVector(da, &localT));
724: PetscFunctionReturn(PETSC_SUCCESS);
725: }
727: PetscErrorCode Monitor(TS ts, PetscInt step, PetscReal time, Vec T, void *ctx)
728: {
729: const PetscScalar *array;
730: MonitorCtx *user = (MonitorCtx *)ctx;
731: PetscViewer viewer = user->drawviewer;
732: PetscReal norm;
734: PetscFunctionBeginUser;
735: PetscCall(VecNorm(T, NORM_INFINITY, &norm));
737: if (step % user->interval == 0) {
738: PetscCall(VecGetArrayRead(T, &array));
739: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "step %" PetscInt_FMT ", time %8.1f, %6.4f, %6.4f, %6.4f, %6.4f, %6.4f, %6.4f\n", step, (double)time, (double)(((array[0] - 273) * 9) / 5 + 32), (double)(((array[1] - 273) * 9) / 5 + 32), (double)array[2], (double)array[3], (double)array[4], (double)array[5]));
740: PetscCall(VecRestoreArrayRead(T, &array));
741: }
743: if (user->drawcontours) PetscCall(VecView(T, viewer));
744: PetscFunctionReturn(PETSC_SUCCESS);
745: }
747: /*TEST
749: build:
750: requires: !complex !single
752: test:
753: args: -ts_max_steps 130 -monitor_interval 60
754: output_file: output/ex5.out
755: requires: !complex !single
756: localrunfiles: ex5_control.txt
758: test:
759: suffix: 2
760: nsize: 4
761: args: -ts_max_steps 130 -monitor_interval 60
762: output_file: output/ex5.out
763: localrunfiles: ex5_control.txt
764: requires: !complex !single
766: # Test TSPruneIJacobianColor() for improved FD coloring
767: test:
768: suffix: 3
769: nsize: 4
770: args: -ts_max_steps 130 -monitor_interval 60 -prune_jacobian -mat_coloring_view
771: requires: !complex !single
772: localrunfiles: ex5_control.txt
774: TEST*/