1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #ifdef HAVE_FEENABLEEXCEPT 9 #define _GNU_SOURCE 10 #include 11 #if 0 12 #include "fe-handling-example.c" 13 #endif 14 #endif 15 16 int const Nt_max = 50000; 17 int const Nx_max = 10000; 18 19 int noout = 0; 20 int savi = 0; 21 int outi = 100; 22 int save = 0; 23 char const *alg = "ftcs"; 24 char const *prec = "double"; 25 char const *ic = "const(1)"; 26 double alpha = 0.2; 27 double dt = 0.004; 28 double dx = 0.1; 29 double bc0 = 0; 30 double bc1 = 1; 31 double maxt = 2.0; 32 33 double *curr=0, *last=0, *change_history=0, *exact=0, *error_history=0; 34 double *cn_Amat = 0; 35 36 int Nx = (int) (1/0.1+1.5); 37 int Nt = (int) (1 / 0.004); 38 39 /* 40 * Utilities 41 */ 42 static double 43 l2_norm(int n, double const *a, double const *b) 44 { 45 int i; 46 double sum = 0; 47 for (i = 0; i < n; i++) 48 { 49 double diff = a[i] - b[i]; 50 sum += diff * diff; 51 } 52 return sum; 53 } 54 55 static void 56 copy(int n, double *dst, double const *src) 57 { 58 int i; 59 for (i = 0; i < n; i++) 60 dst[i] = src[i]; 61 } 62 63 #define TSTART -1 64 #define TFINAL -2 65 #define RESIDUAL -3 66 #define ERROR -4 67 static void 68 write_array(int t, int n, double dx, double const *a) 69 { 70 int i; 71 char fname[32]; 72 FILE *outf; 73 74 if (noout) return; 75 76 if (t == TSTART) 77 snprintf(fname, sizeof(fname), "heat_soln_00000.curve"); 78 else if (t == TFINAL) 79 snprintf(fname, sizeof(fname), "heat_soln_final.curve"); 80 else if (t == RESIDUAL) 81 snprintf(fname, sizeof(fname), "change.curve"); 82 else if (t == ERROR) 83 snprintf(fname, sizeof(fname), "error.curve"); 84 else 85 { 86 if (a == exact) 87 snprintf(fname, sizeof(fname), "heat_exact_%05d.curve", t); 88 else 89 snprintf(fname, sizeof(fname), "heat_soln_%05d.curve", t); 90 } 91 92 outf = fopen(fname,"w"); 93 for (i = 0; i < n; i++) 94 fprintf(outf, "%8.4g %8.4g\n", i*dx, a[i]); 95 fclose(outf); 96 } 97 98 99 static void 100 r83_np_fa(int n, double *a) 101 /* 102 Licensing: This code is distributed under the GNU LGPL license. 103 Modified: 30 May 2009 Author: John Burkardt 104 Modified by Mark C. Miller, July 23, 2017 105 */ 106 { 107 int i; 108 109 for ( i = 1; i <= n-1; i++ ) 110 { 111 assert ( a[1+(i-1)*3] != 0.0 ); 112 /* 113 Store the multiplier in L. 114 */ 115 a[2+(i-1)*3] = a[2+(i-1)*3] / a[1+(i-1)*3]; 116 /* 117 Modify the diagonal entry in the next column. 118 */ 119 a[1+i*3] = a[1+i*3] - a[2+(i-1)*3] * a[0+i*3]; 120 } 121 122 assert( a[1+(n-1)*3] != 0.0 ); 123 } 124 125 static void 126 initialize(void) 127 { 128 curr = (double *) calloc(Nx, sizeof(double)); 129 last = (double *) calloc(Nx, sizeof(double)); 130 if (save) 131 { 132 exact = (double *) calloc(Nx, sizeof(double)); 133 change_history = (double *) calloc(Nt, sizeof(double)); 134 error_history = (double *) calloc(Nt, sizeof(double)); 135 } 136 137 assert(strncmp(alg, "ftcs", 4)==0 || 138 strncmp(alg, "upwind15", 8)==0 || 139 strncmp(alg, "crankn", 6)==0); 140 141 #ifdef HAVE_FEENABLEEXCEPT 142 feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW); 143 #endif 144 145 if (!strncmp(alg, "crankn", 6)) 146 { 147 /* 148 We do some additional initialization work for Crank-Nicolson. 149 The matrix A does not change with time. We can set it once, 150 factor it once, and solve repeatedly. 151 */ 152 int i; 153 double w = alpha * dt / dx / dx; 154 155 cn_Amat = ( double * ) malloc ( 3 * Nx * sizeof ( double ) ); 156 157 cn_Amat[0+0*3] = 0.0; 158 cn_Amat[1+0*3] = 1.0; 159 cn_Amat[0+1*3] = 0.0; 160 161 for ( i = 1; i < Nx - 1; i++ ) 162 { 163 cn_Amat[2+(i-1)*3] = - w; 164 cn_Amat[1+ i *3] = 1.0 + 2.0 * w; 165 cn_Amat[0+(i+1)*3] = - w; 166 } 167 168 cn_Amat[2+(Nx-2)*3] = 0.0; 169 cn_Amat[1+(Nx-1)*3] = 1.0; 170 cn_Amat[2+(Nx-1)*3] = 0.0; 171 172 /* 173 Factor the matrix. 174 */ 175 r83_np_fa(Nx, cn_Amat); 176 } 177 } 178 179 #define HANDLE_ARG(VAR, TYPE, STYLE, HELP) \ 180 { \ 181 void *valp = (void*) &VAR; \ 182 int const len = strlen(#VAR)+1; \ 183 for (i = 1; i < argc; i++) \ 184 {\ 185 char const *style = #STYLE; \ 186 int valid_style = style[1]=='d'||style[1]=='g'||style[1]=='s'; \ 187 if (strncmp(argv[i], #VAR"=", len)) \ 188 continue; \ 189 assert(valid_style); \ 190 if (strlen(argv[i]+len)) \ 191 {\ 192 if (style[1] == 'd') /* int */ \ 193 *((int*) valp) = (int) strtol(argv[i]+len,0,10); \ 194 else if (style[1] == 'g') /* double */ \ 195 *((double*) valp) = (double) strtod(argv[i]+len,0); \ 196 else if (style[1] == 's') /* char* */ \ 197 *((char**) valp) = (char*) strdup(argv[i]+len); \ 198 }\ 199 }\ 200 if (help) \ 201 {\ 202 char tmp[256]; \ 203 int len = snprintf(tmp, sizeof(tmp), " %s=" #STYLE, \ 204 #VAR, VAR);\ 205 snprintf(tmp, sizeof(tmp), "%s (%s)", #HELP, #TYPE); \ 206 fprintf(stderr, " %s=" #STYLE "%*s\n", \ 207 #VAR, VAR, 80-len, tmp);\ 208 }\ 209 else \ 210 fprintf(stderr, " %s="#STYLE"\n", \ 211 #VAR, VAR);\ 212 } 213 214 static void 215 process_args(int argc, char **argv) 216 { 217 int i; 218 int help = 0; 219 220 /* quick pass for 'help' anywhere on command line */ 221 for (i = 0; i < argc && !help; i++) 222 help = 0!=strcasestr(argv[i], "help"); 223 224 if (help) 225 { 226 fprintf(stderr, "Usage:\n"); 227 fprintf(stderr, " ./heat = =...\n"); 228 } 229 230 HANDLE_ARG(prec, char*, %s, precision half|float|double|quad); 231 HANDLE_ARG(alpha, double, %g, material thermal diffusivity); 232 HANDLE_ARG(dx, double, %g, x-incriment (1/dx->int)); 233 HANDLE_ARG(dt, double, %g, t-incriment); 234 HANDLE_ARG(maxt, double, %g, max. time to run simulation to); 235 HANDLE_ARG(bc0, double, %g, bc @ x=0: u(0,t)); 236 HANDLE_ARG(bc1, double, %g, bc @ x=1: u(1,t)); 237 HANDLE_ARG(ic, char*, %s, ic @ t=0: u(x,0)); 238 HANDLE_ARG(alg, char*, %s, algorithm ftcs|upwind15|crankn); 239 HANDLE_ARG(savi, int, %d, save every i-th solution step); 240 HANDLE_ARG(save, int, %d, save error in every saved solution); 241 HANDLE_ARG(outi, int, %d, output progress every i-th solution step); 242 HANDLE_ARG(noout, int, %d, disable all file outputs); 243 244 if (help) 245 { 246 fprintf(stderr, "Examples...\n"); 247 fprintf(stderr, " ./heat Nx=51 dt=0.002 alg=ftcs\n"); 248 fprintf(stderr, " ./heat Nx=51 bc0=5 bc1=10\n"); 249 exit(1); 250 } 251 252 } 253 254 static void 255 set_initial_condition(int n, double *a, double dx, char const *ic) 256 { 257 int i; 258 double x; 259 260 if (!strncmp(ic, "const(", 6)) /* const(val) */ 261 { 262 double cval = strtod(ic+6, 0); 263 for (i = 0; i < n; i++) 264 a[i] = cval; 265 } 266 else if (!strncmp(ic, "step(", 5)) /* step(left,xmid,right) */ 267 { 268 char *p; 269 double left = strtod(ic+5, &p); 270 double xmid = strtod(p+1, &p); 271 double right = strtod(p+1, 0); 272 for (i = 0, x = 0; i < n; i++, x+=dx) 273 { 274 if (x < xmid) a[i] = left; 275 else a[i] = right; 276 } 277 } 278 else if (!strncmp(ic, "ramp(", 5)) /* ramp(left,right) */ 279 { 280 char *p; 281 double left = strtod(ic+5, &p); 282 double right = strtod(p+1, 0); 283 double dv = (right-left)/(n-1); 284 for (i = 0, x = left; i < n; i++, x+=dv) 285 a[i] = x; 286 } 287 else if (!strncmp(ic, "rand(", 5)) /* rand(seed,amp) */ 288 { 289 char *p; 290 int seed = (int) strtol(ic+5,&p,10); 291 double amp = strtod(p+1, 0); 292 const double maxr = ((long long)1<<31)-1; 293 srandom(seed); 294 for (i = 0; i < n; i++) 295 a[i] = amp * random()/maxr; 296 } 297 else if (!strncmp(ic, "sin(Pi*x)", 9)) /* rand(seed,amp) */ 298 { 299 for (i = 0, x = 0; i < n; i++, x+=dx) 300 a[i] = sin(M_PI*x); 301 } 302 else if (!strncmp(ic, "spikes(", 7)) /* spikes(Amp,Loc,Amp,Loc,...) */ 303 { 304 char const *p = &ic[6]; 305 for (i = 0, x = 0; i < n; i++) 306 a[i] = 0; 307 while (*p != ')') 308 { 309 char *ep_amp, *ep_idx; 310 double amp = strtod(p+1, &ep_amp); 311 int idx = (int) strtod(ep_amp+1, &ep_idx); 312 assert(idx0 && save) 492 { 493 compute_exact_solution(Nx, exact, dx, ic, alpha, ti*dt, bc0, bc1); 494 if (savi && ti%savi==0) 495 write_array(ti, Nx, dx, exact); 496 } 497 498 if (ti>0 && savi && ti%savi==0) 499 write_array(ti, Nx, dx, curr); 500 501 change = l2_norm(Nx, curr, last); 502 if (save) 503 { 504 change_history[ti] = change; 505 error_history[ti] = l2_norm(Nx, curr, exact); 506 } 507 508 copy(Nx, last, curr); 509 510 if (outi && ti%outi==0) 511 { 512 printf("Iteration %04d: last change l2=%g\n", ti, change); 513 } 514 } 515 516 write_array(TFINAL, Nx, dx, curr); 517 if (save) 518 { 519 write_array(RESIDUAL, ti, dt, change_history); 520 write_array(ERROR, ti, dt, error_history); 521 } 522 523 return finalize(ti, maxt, change); 524 }