1 /*============================================================================
2 * Radiation solver operations.
3 *============================================================================*/
4
5 /* This file is part of Code_Saturne, a general-purpose CFD tool.
6
7 Copyright (C) 1998-2021 EDF S.A.
8
9 This program is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free Software
11 Foundation; either version 2 of the License, or (at your option) any later
12 version.
13
14 This program is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 details.
18
19 You should have received a copy of the GNU General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
21 Street, Fifth Floor, Boston, MA 02110-1301, USA. */
22
23 /*----------------------------------------------------------------------------*/
24
25 #include "cs_defs.h"
26 #include "cs_math.h"
27
28 /*----------------------------------------------------------------------------
29 * Standard C library headers
30 *----------------------------------------------------------------------------*/
31
32 #include <assert.h>
33 #include <errno.h>
34 #include <stdio.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <math.h>
38 #include <float.h>
39
40 #if defined(HAVE_MPI)
41 #include <mpi.h>
42 #endif
43
44 /*----------------------------------------------------------------------------
45 * Local headers
46 *----------------------------------------------------------------------------*/
47
48 #include "bft_error.h"
49 #include "bft_mem.h"
50 #include "bft_printf.h"
51
52 #include "cs_log.h"
53 #include "cs_mesh.h"
54 #include "cs_mesh_quantities.h"
55 #include "cs_parall.h"
56 #include "cs_parameters.h"
57 #include "cs_sles.h"
58 #include "cs_sles_it.h"
59 #include "cs_timer.h"
60 #include "cs_time_step.h"
61
62 #include "cs_rad_transfer.h"
63
64 /*----------------------------------------------------------------------------
65 * Header for the current file
66 *----------------------------------------------------------------------------*/
67
68 #include "cs_rad_transfer_fsck.h"
69
70 /*----------------------------------------------------------------------------*/
71
72 BEGIN_C_DECLS
73
74 /*=============================================================================
75 * Additional Doxygen documentation
76 *============================================================================*/
77
78 /* \file cs_rad_transfer_fsck.c.f90 */
79
80 /*! \cond DOXYGEN_SHOULD_SKIP_THIS */
81
82 /*=============================================================================
83 * Local static variables
84 *============================================================================*/
85
86 static int ipass = 0;
87
88 static cs_real_t *gi;
89 static cs_real_t *tt;
90 static cs_real_t *kpco2;
91 static cs_real_t *kph2o;
92 static cs_real_t *wv;
93 static cs_real_t *dwv;
94 static cs_real_t *kmfs;
95 static cs_real_t *gq;
96
97 /*=============================================================================
98 * Local const variables
99 *============================================================================*/
100
101 const int ng = 100;
102 const int nt = 38;
103 const int nconc = 5;
104 const int nband = 450;
105 const int maxit = 1000;
106 const int imlinear = 0;
107 const int im3dspline = 7;
108 const int im1dspline = 2;
109 const int im2dspline = 6;
110 const cs_real_t eps = 3e-14;
111 const cs_real_t x_kg[5] = {0.0001, 0.25, 0.5, 0.75, 1.0};
112
113 /*=============================================================================
114 * Private function definitions
115 *============================================================================*/
116
117 /*----------------------------------------------------------------------------*/
118 /*!
119 * \brief Convert a line of values in a file into an array of cs_real_t and
120 * returns the number of values read
121 *
122 * \param[in] radfile pointer to file for reading values
123 * \param[in] values array for values storage
124 * \param[in] nvalues number of values read
125 */
126 /*----------------------------------------------------------------------------*/
127
128 static inline void
_line_to_array(FILE * radfile,cs_real_t values[],int * nvalues)129 _line_to_array(FILE *radfile,
130 cs_real_t values[],
131 int *nvalues)
132 {
133 char line[256];
134 fgets(line, 256, radfile);
135 int index = 0;
136
137 /* now read all info along the line */
138 while (strlen(line) > 1) {
139 char temp[256];
140 /* store next value in string format */
141 sscanf(line, "%s", temp);
142 /* read and convert to double precision */
143 sscanf(temp, "%lf", &(values[index]));
144 /* increase index in array */
145 index++;
146
147 int l = strlen(temp);
148 int i = 0;
149 while (line[i] == ' ')
150 i++;
151 snprintf(temp, 256, "%s", &line[l+i]);
152 strcpy(line, temp);
153 }
154
155 *nvalues = index;
156 }
157
158 /*----------------------------------------------------------------------------*/
159 /*!
160 * \brief number of segents
161 *
162 * \param[in] trad Reference temperature
163 * \param[in] t Local Temperature
164 * \param[in] xco2 CO2 volume fraction
165 * \param[in] xh2o H2O volume fraction
166 * \param[in] interp_method Interpolation method
167 * \param[inout] itx[4][4] itx[0]: TPlanck; iTx[1]: Tloc;
168 * iTx[2]: xCO2; iTx[3] = xH2O
169 */
170 /*----------------------------------------------------------------------------*/
171
172 inline static void
_gridposnbsg1(cs_real_t trad,cs_real_t t,cs_real_t xco2,cs_real_t xh2o,int interp_method,int itx[4][4])173 _gridposnbsg1(cs_real_t trad,
174 cs_real_t t,
175 cs_real_t xco2,
176 cs_real_t xh2o,
177 int interp_method,
178 int itx[4][4])
179 {
180 int itrad[4] = {0};
181 int ita[4] = {0};
182 int ico2a[4] = {0};
183 int ih2oa[4] = {0};
184
185 /* Mole fraction interpolation: determine xCO2 */
186
187 int i = 0;
188 int j = nconc - 1;
189 int ip = (i + j) / 2;
190 while (j - i > 1) {
191 if (xco2 < x_kg[ip])
192 j = ip;
193 else
194 i = ip;
195 ip = (i + j) / 2;
196 }
197
198 /* spline on x */
199
200 if (interp_method == im2dspline) {
201
202 if ((i > 0) && (i < nconc - 2)) {
203 ico2a[0] = i - 1;
204 ico2a[1] = i;
205 ico2a[2] = i + 1;
206 ico2a[3] = i + 2;
207 }
208 else if (i == 0) {
209 ico2a[0] = 0;
210 ico2a[1] = 1;
211 ico2a[2] = 2;
212 ico2a[3] = 3;
213 }
214 else if (i == nconc - 2) {
215 ico2a[0] = nconc - 4;
216 ico2a[1] = nconc - 3;
217 ico2a[2] = nconc - 2;
218 ico2a[3] = nconc - 1;
219 }
220 else
221 cs_log_printf(CS_LOG_DEFAULT, _("x grid failure, i = %d"), i);
222 }
223 /* linear in x */
224 else {
225 if (i < 0) //not possible...
226 i = 0;
227 else if (i > nconc - 2)
228 i = nconc - 2;
229 ico2a[0] = i;
230 ico2a[1] = i + 1;
231 }
232
233 /* Mole fraction interpolation: determine xH2O */
234
235 i = 0;
236 j = nconc - 1;
237 ip = (i + j) / 2;
238 while (j - i > 1) {
239 if (xh2o < x_kg[ip])
240 j = ip;
241 else
242 i = ip;
243 ip = (i + j) / 2;
244 }
245
246 /* spline on x */
247 if (interp_method == im2dspline) {
248
249 if ((i > 0) && (i < nconc - 2)) {
250 ih2oa[0] = i - 1;
251 ih2oa[1] = i;
252 ih2oa[2] = i + 1;
253 ih2oa[3] = i + 2;
254 }
255 else if (i == 0) {
256 ih2oa[0] = 0;
257 ih2oa[1] = 1;
258 ih2oa[2] = 2;
259 ih2oa[3] = 3;
260 }
261 else if (i == nconc - 2) {
262 ih2oa[0] = nconc - 4;
263 ih2oa[1] = nconc - 3;
264 ih2oa[2] = nconc - 2;
265 ih2oa[3] = nconc - 1;
266 }
267 else
268 cs_log_printf(CS_LOG_DEFAULT, _("x grid failure, i = %d"), i);
269 }
270 /* linear in x */
271 else {
272 if (i < 0) //not possible...
273 i = 0;
274 else if (i > nconc - 2)
275 i = nconc - 2;
276 ih2oa[0] = i;
277 ih2oa[1] = i + 1;
278 }
279
280 /* Temperature interpolation */
281
282 i = 0;
283 j = nt - 1;
284 ip = (i + j) / 2;
285 while (j - i > 1) {
286 if (t < tt[ip])
287 j = ip;
288 else
289 i = ip;
290 ip = (i + j) / 2;
291 }
292
293 /* spline in t */
294 if (interp_method != 0) {
295
296 if ((i > 0) && (i < nt - 2)) {
297 ita[0] = i - 1;
298 ita[1] = i;
299 ita[2] = i + 1;
300 ita[3] = i + 2;
301 }
302 else if (i == 0) {
303 ita[0] = 0;
304 ita[1] = 1;
305 ita[2] = 2;
306 ita[3] = 3;
307 }
308 else if (i == nt - 1) {
309 ita[0] = nt - 4;
310 ita[1] = nt - 3;
311 ita[2] = nt - 2;
312 ita[3] = nt - 1;
313 }
314 else
315 cs_log_printf(CS_LOG_DEFAULT, _("t grid failure, i = %d"), i);
316 }
317 /* linear in t */
318 else {
319 if (i < 0)
320 i = 0;
321 else if (i > nt - 2)
322 i = nt - 2;
323 ita[0] = i;
324 ita[1] = i + 1;
325 }
326
327 /* Determine closest Planck temperature in database
328 lower than local temperature */
329
330 i = 0;
331 j = nt - 1;
332 ip = (i + j) / 2;
333 while (j - i > 1) {
334 if (trad < tt[ip])
335 j = ip;
336 else
337 i = ip;
338 ip = (i + j) / 2;
339 }
340
341 /* spline in t */
342 if (interp_method != 0) {
343 if ((i > 0) && (i < nt - 2)) {
344 itrad[0] = i - 1;
345 itrad[1] = i;
346 itrad[2] = i + 1;
347 itrad[3] = i + 2;
348 }
349 else if (i == 0) {
350 itrad[0] = 0;
351 itrad[1] = 1;
352 itrad[2] = 2;
353 itrad[3] = 3;
354 }
355 else if (i == nt - 2) {
356 itrad[0] = nt - 4;
357 itrad[1] = nt - 3;
358 itrad[2] = nt - 2;
359 itrad[3] = nt - 1;
360 }
361 else
362 cs_log_printf(CS_LOG_DEFAULT, _("t grid failure, i = %d"), i);
363 }
364 /* linear in t */
365 else {
366 if (i < 0)
367 i = 0;
368 else if (i > nt - 1) {
369 i = nt - 1;
370 }
371 itrad[0] = i;
372 itrad[1] = i + 1;
373 }
374
375 /* attribution itx */
376
377 for (int k = 0; k < 4; k++) {
378 itx[0][k] = itrad[k];
379 itx[1][k] = ita[k];
380 itx[2][k] = ico2a[k];
381 itx[3][k] = ih2oa[k];
382 }
383 }
384
385 /*----------------------------------------------------------------------------*/
386 /*!
387 * \brief This subroutine evaluates the cubic spline function
388 *
389 * seval = y(i) + b(i)*(u-x(i)) + c(i)*(u-x(i))**2 + d(i)*(u-x(i))**3
390 *
391 * where x(i) .lt. u .lt. x(i+1), using horner's rule
392 *
393 * if u .lt. x(1) then i = 1 is used.
394 * if u .ge. x(n) then i = n is used.
395 *
396 * if u is not in the same interval as the previous call, then a
397 * binary search is performed to determine the proper interval.
398 *
399 * \param[in] n Number of data points
400 * \param[in] u Abscissa at which the spline is to be evaluated
401 * \param[in] x,y Arrays of data abscissas and ordinates
402 * \param[in] b,c,d Arrays of spline coefficients computed by spline
403 */
404 /*----------------------------------------------------------------------------*/
405
406 inline static cs_real_t
_seval(int n,cs_real_t u,cs_real_t x[],cs_real_t y[],cs_real_t b[],cs_real_t c[],cs_real_t d[])407 _seval(int n,
408 cs_real_t u,
409 cs_real_t x[],
410 cs_real_t y[],
411 cs_real_t b[],
412 cs_real_t c[],
413 cs_real_t d[])
414 {
415 int i = 0;
416 if (i > n)
417 i = 0;
418
419 /* Binary search */
420 if ( u < x[i]
421 || u > x[i + 1]) {
422 i = 0;
423 int j = n;
424 int k = (j + i)/2;
425 while (j > i + 1) {
426 if (u < x[k])
427 j = k;
428 else
429 i = k;
430 }
431 }
432 /* Evaluate spline */
433 cs_real_t dx = u - x[i];
434
435 return y[i] + dx * (b[i] + dx * (c[i] + dx * d[i]));
436 }
437
438 /*----------------------------------------------------------------------------*/
439 /*!
440 * \brief 1-d monotonic spline interpolation: coefficients
441 * The coefficients b(i), c(i), and d(i), i = 1,2,...,n are computed
442 * for a monotonically varying cubic interpolating spline
443 *
444 * s(x) = y(i) + b(i)*(x-x(i)) + c(i)*(x-x(i))**2 + d(i)*(x-x(i))**3
445 * for x(i) .le. x .le. x(i+1)
446 * with y(i+1).ge.y(i) (all i) or y(i+1).lt.y(i) (all i)
447 *
448 ********************************************************************************
449 *
450 * THEORY FROM 'MONOTONE PIECEWISE CUBIC INTERPOLATION',
451 * BY F.N. FRITSCH AND R.E. CARLSON IN SIAM J.NUMER.ANAL.,V.17,P.238
452 *
453 ********************************************************************************
454 *
455 * Y(I) = S(X(I))
456 * B(I) = SP(X(I))
457 * C(I) = SPP(X(I))/2
458 * D(I) = SPPP(X(I))/6 (DERIVATIVE FROM THE RIGHT)
459 *
460 * THE ACCOMPANYING FUNCTION SUBPROGRAM SEVAL CAN BE USED
461 * TO EVALUATE THE SPLINE.
462 *
463 * \param[in] n Number of data points or knots (n.ge.2)
464 * \param[in] x Abscissa of the knots in strictly increasing order
465 * \param[in] y Ordinates of the knots
466 * \param[out] b,c,d Arrays of spline coefficients as defined above
467 */
468 /*----------------------------------------------------------------------------*/
469
470 inline static void
_splmi(int n,cs_real_t x[],cs_real_t y[],cs_real_t b[],cs_real_t c[],cs_real_t d[])471 _splmi(int n,
472 cs_real_t x[],
473 cs_real_t y[],
474 cs_real_t b[],
475 cs_real_t c[],
476 cs_real_t d[])
477 {
478 cs_real_t delta[n], h[n], al[n], be[n];
479
480 int nm1 = n - 1;
481
482 if (n < 2)
483 return;
484
485 if (n >= 3) {
486
487 /* Calculate the h(i) and delta(i) */
488 for (int i = 0; i < nm1; i++) {
489 al[i] = 0.0;
490 be[i] = 0.0;
491 h[i] = x[i + 1] - x[i];
492 delta[i] = (y[i + 1] - y[i]) / h[i];
493 }
494
495 /* calculate first values for al and be by 3-point difference */
496 if (CS_ABS(delta[0]) < eps)
497 al[0] = ( pow((h[0] + h[1]), 2.0) * y[1]
498 - pow (h[0], 2.0) * y[2]
499 - h[1] * (2.0 * h[0] + h[1]) * y[0])
500 / (h[1] * (h[0] + h[1]) * (y[1] - y[0]));
501
502 for (int i = 1; i < nm1; i++) {
503 if (CS_ABS(delta[0]) < eps)
504 al[i] = ( pow(h[i - 1], 2.0) * y[i + 1]
505 + (pow (h[i], 2.0) - pow (h[i - 1], 2.0)) * y[i]
506 - pow (h[i], 2.0) * y[i - 1])
507 / (h[i - 1] * (h[i] + h[i - 1]) * (y[i + 1] - y[i]));
508
509 }
510
511 int nm2 = n - 2;
512 for (int i = 0; i < nm2; i++) {
513 if (CS_ABS(delta[0]) < eps)
514 be[i] = ( pow(h[i], 2.0) * y[i + 2]
515 + (pow (h[i + 1], 2.0) - pow (h[i], 2.0)) * y[i + 1]
516 - pow (h[i + 1], 2.0) * y[i])
517 / (h[i + 1] * (h[i] + h[i + 1]) * (y[i + 1] - y[i]));
518
519 }
520
521 if (CS_ABS(delta[0]) < eps) {
522 be[n - 2] = ( h[n - 3] * (2.0 * h[n - 2] + h[n - 3]) * y[n - 1]
523 - pow((h[n - 2] + h[n - 3]), 2.0) * y[n - 2]
524 + pow (h[n - 2], 2.0) * y[n - 3])
525 / (h[n - 3] * (h[n - 2] + h[n - 3]) * (y[n - 1] - y[n - 2]));
526 }
527
528 /* Correct values for al and be */
529 for (int i = 0; i < nm1; i++) {
530 if ( al[i] + be[i] > 2.0
531 && 2.0 * al[i] + be[i] > 3.0
532 && al[i] + 2.0 * be[i] > 3.0) {
533
534 cs_real_t phi = al[i] - pow((2.0 * al[i] + be[i] - 3.0), 2.0)
535 / (al[i] + be[i] - 2.0) / 3.0;
536
537 if (phi < 0.0) {
538 cs_real_t ti = 3.0 / sqrt (pow (al[i], 2.0) + pow (be[i], 2.0));
539 al[i] = ti * al[i];
540 be[i] = ti * be[i];
541 }
542
543 }
544 }
545
546 /* Calculate spline coefficients */
547
548 for (int i = 0; i < nm1; i++) {
549 d[i] = (al[i] + be[i] - 2.0) * delta[i] / (pow (h[i], 2.0));
550 c[i] = (3.0 - 2.0 * al[i] - be[i]) * delta[i] / (h[i]);
551 b[i] = al[i] * delta[i];
552 if (b[i] * delta[i] < 0.0) {
553 b[i] = delta[i];
554 c[i] = 0.0;
555 d[i] = 0.0;
556 }
557 }
558
559 b[n - 1] = be[n - 2] * delta[n - 2];
560 c[n - 1] = 0.0;
561 d[n - 1] = 0.0;
562
563 }
564 else if (n == 2) {
565
566 b[0] = (y[1] - y[0]) / (x[1] - x[0]);
567 c[0] = 0.0;
568 d[0] = 0.0;
569 b[1] = b[0];
570 c[1] = 0.0;
571 d[1] = 0.0;
572
573 }
574 }
575
576 /*----------------------------------------------------------------------------*/
577 /*!
578 * \brief simple_interpg
579 *
580 * \param[in] nxy
581 * \param[in] xx
582 * \param[in] yy
583 * \param[in] ni
584 * \param[in] xi
585 * \param[out] yi
586 */
587 /*----------------------------------------------------------------------------*/
588
589 static inline void
_simple_interpg(int nxy,cs_real_t xx[],cs_real_t yy[],int ni,cs_real_t xi[],cs_real_t yi[])590 _simple_interpg (int nxy,
591 cs_real_t xx[],
592 cs_real_t yy[],
593 int ni,
594 cs_real_t xi[],
595 cs_real_t yi[])
596 {
597 int ibgn = 0;
598
599 for (int iq = 0; iq < ni; iq++) {
600
601 for (int i = ibgn; i < nxy; i++) {
602
603 if (xi[iq] < xx[0]) {
604 yi[iq] = yy[0] * xi[iq] / CS_MAX(1e-09, xx[0]);
605 break;
606 }
607 else if (xi[iq] > xx[nxy])
608 yi[iq] = yy[nxy];
609
610
611 /* interpolate */
612 if (CS_ABS(xi[iq] - xx[i]) / (xx[i] + 1e-15) < 0.001) {
613 yi[iq] = yy[i];
614 ibgn = i;
615 break;
616 }
617 else if (xx[i] > xi[iq]) {
618 yi[iq] = yy[i - 1]
619 + (yy[i] - yy[i - 1]) * (xi[iq] - xx[i - 1])
620 / CS_MAX(1e-09, (xx[i] - xx[i - 1]));
621 ibgn = i;
622 break;
623 }
624 }
625 }
626
627 if (CS_ABS(xi[ni] - xx[nxy]) / (xx[nxy] + 1e-15) < 0.001)
628 yi[ni] = yy[nxy];
629 }
630
631 /*----------------------------------------------------------------------------*/
632 /*!
633 * \brief interpolation4d
634 *
635 * \param[in] trad Reference temperature
636 * \param[in] t Local temperature
637 * \param[in] xco2 Reference CO2 volume fraction
638 * \param[in] xh2o Reference H2O volume fraction
639 * \param[in] interp_method Interpolation method
640 * \param[out] gdb
641 * \param[out] kdb
642 */
643 /*----------------------------------------------------------------------------*/
644
645 inline static void
_interpolation4d(cs_real_t trad,cs_real_t t,cs_real_t xco2,cs_real_t xh2o,int interp_method,cs_real_t gdb[],cs_real_t kdb[])646 _interpolation4d(cs_real_t trad,
647 cs_real_t t,
648 cs_real_t xco2,
649 cs_real_t xh2o,
650 int interp_method,
651 cs_real_t gdb[],
652 cs_real_t kdb[])
653 {
654 int itx[4][4];
655 int nix, nit;
656
657 cs_real_t *karray, *kint1, *kint2, *kint3;
658 BFT_MALLOC(karray, ng*4*4*4*4, cs_real_t);
659 BFT_MALLOC(kint1, ng*4*4*4, cs_real_t);
660 BFT_MALLOC(kint2, ng*4*4, cs_real_t);
661 BFT_MALLOC(kint3, ng*4, cs_real_t);
662
663 cs_real_t *b, *c, *d, *kg_t2, *kg_x2;
664 BFT_MALLOC(b, 4, cs_real_t);
665 BFT_MALLOC(c, 4, cs_real_t);
666 BFT_MALLOC(d, 4, cs_real_t);
667 BFT_MALLOC(kg_t2, 4, cs_real_t);
668 BFT_MALLOC(kg_x2, 4, cs_real_t);
669
670 /* Determine positions in x and T
671 * in the NB database for interpolation. */
672 for (int i = 0; i < ng; i++)
673 gdb[i] = gi[i];
674
675 /* number of interpolation points along t & x: 2 linear or 4 spline */
676 _gridposnbsg1(trad,
677 t,
678 xco2,
679 xh2o,
680 interp_method,
681 itx);
682
683 /* spline over x */
684 if (interp_method == im2dspline)
685 nix = 4;
686 else
687 nix = 2;
688
689 /* spline over t */
690 if (interp_method != 0)
691 nit = 4;
692 else
693 nit = 2;
694
695 /* Attribute interpolation point indexes along T & x */
696
697 int itrada[4] = {0, 0, 0, 0};
698 int ita[4] = {0, 0, 0, 0};
699 int ico2a[4] = {0, 0, 0, 0};
700 int ih2oa[4] = {0, 0, 0, 0};
701
702 for (int i = 0; i < nit; i++) {
703 itrada[i] = itx[0][i];
704 ita[i] = itx[1][i];
705 }
706
707 for (int i = 0; i < nix; i++) {
708 ico2a[i] = itx[2][i];
709 ih2oa[i] = itx[3][i];
710 }
711
712 for (int ih2o = 0; ih2o < nix; ih2o++) {
713 for (int ico2 = 0; ico2 < nix; ico2++) {
714 for (int it = 0; it < nit; it++) {
715 for (int itrad = 0; itrad < nit; itrad++) {
716 for (int ig = 0; ig < ng; ig++) {
717 karray[ ih2o
718 + ico2*4
719 + it*4*4
720 + itrad*4*4*4
721 + ig*4*4*4*4] =
722 kmfs[ ih2oa[ih2o]
723 + ico2a[ico2]*nconc
724 + ita[it]*nconc*nconc
725 + itrada[itrad]*nconc*nconc*nt
726 + ig*nconc*nconc*nt*nt];
727 }
728 }
729 }
730 }
731 }
732
733 /* Interpolation on XH2O; spline over x */
734
735 if (interp_method == im2dspline) {
736 for (int ico2 = 0; ico2 < nix; ico2++) {
737 for (int it = 0; it < nit; it++) {
738 for (int itrad = 0; itrad < nit; itrad++) {
739 for (int ig = 0; ig < ng; ig++) {
740 kg_x2[0] = x_kg[ih2oa[0]];
741 kg_x2[1] = x_kg[ih2oa[1]];
742 kg_x2[2] = x_kg[ih2oa[2]];
743 kg_x2[3] = x_kg[ih2oa[3]];
744 int ih2o = 0;
745 int nargs = 4;
746 _splmi(nargs,
747 kg_x2,
748 &karray[ih2o + ico2*4 + it*4*4 + itrad*4*4*4 + ig*4*4*4*4],
749 b,
750 c,
751 d);
752
753 kint1[ico2 + it*4 + itrad*4*4 + ig*4*4*4]
754 = _seval(nargs,
755 xh2o,
756 kg_x2,
757 &karray[ih2o + ico2*4 + it*4*4 + itrad*4*4*4 + ig*4*4*4*4],
758 b,
759 c,
760 d);
761 }
762 }
763 }
764 }
765 }
766 else {
767 cs_real_t wx = (xh2o - x_kg[ih2oa[0]]) / (x_kg[ih2oa[1]] - x_kg[ih2oa[0]]);
768 for (int ico2 = 0; ico2 < nix; ico2++) {
769 for (int it = 0; it < nit; it++) {
770 for (int itrad = 0; itrad < nit; itrad++) {
771 for (int ig = 0; ig < ng; ig++) {
772 kint1[ico2 + it*4 + itrad*4*4 + ig*4*4*4]
773 = wx * karray[1 + ico2*4 + it*4*4 + itrad*4*4*4 + ig*4*4*4*4]
774 + (1.0 - wx) * karray[0 + ico2*4 + it*4*4 + itrad*4*4*4 + ig*4*4*4*4];
775 }
776 }
777 }
778 }
779 }
780
781 /* Interpolation on XCO2: spline over x */
782
783 if (interp_method == im2dspline) {
784 for (int it = 0; it < nit; it++) {
785 for (int itrad = 0; itrad < nit; itrad++) {
786 for (int ig = 0; ig < ng; ig++) {
787 kg_x2[0] = x_kg[ico2a[0]];
788 kg_x2[1] = x_kg[ico2a[1]];
789 kg_x2[2] = x_kg[ico2a[2]];
790 kg_x2[3] = x_kg[ico2a[3]];
791
792 int ico2 = 0;
793 int nargs = 4;
794 _splmi(nargs,
795 kg_x2,
796 &kint1[ico2 + it*4 + itrad*4*4 + ig*4*4*4],
797 b,
798 c,
799 d);
800 kint2[it + itrad*4 + ig*4*4]
801 = _seval(nargs,
802 xco2,
803 kg_x2,
804 &kint1[ico2 + it*4 + itrad*4*4 + ig*4*4*4],
805 b,
806 c,
807 d);
808 }
809 }
810 }
811 }
812 else {
813 cs_real_t wx = (xco2 - x_kg[ico2a[0]]) / (x_kg[ico2a[1]] - x_kg[ico2a[0]]);
814 for (int it = 0; it < nit; it++) {
815 for (int itrad = 0; itrad < nit; itrad++) {
816 for (int ig = 0; ig < ng; ig++) {
817 kint2[it + itrad*4 + ig*4*4]
818 = wx * kint1[1 + it*4 + itrad*4*4 + ig*4*4*4]
819 + (1.0 - wx) * kint1[0 + it*4 + itrad*4*4 + ig*4*4*4];
820 }
821 }
822 }
823 }
824
825 /* Interpolation on T: spline on t */
826
827 if (interp_method != 0) {
828 for (int itrad = 0; itrad < nit; itrad++) {
829 for (int ig = 0; ig < ng; ig++) {
830 kg_t2[0] = tt[ita[0]];
831 kg_t2[1] = tt[ita[1]];
832 kg_t2[2] = tt[ita[2]];
833 kg_t2[3] = tt[ita[3]];
834 int nargs = 4;
835 _splmi (nargs,
836 kg_t2,
837 &kint2[0 + itrad*4 + ig*4*4],
838 b,
839 c,
840 d);
841 kint3[itrad + ig*4] = _seval(nargs,
842 t,
843 kg_t2,
844 &kint2[0 + itrad*4 + ig*4*4],
845 b,
846 c,
847 d);
848 }
849 }
850 }
851 else {
852 cs_real_t wt = (t - tt[ita[0]]) / (tt[ita[1]] - tt[ita[0]]);
853 for (int itrad = 0; itrad < nit; itrad++) {
854 for (int ig = 0; ig < ng; ig++) {
855 kint3[itrad + ig*4] = wt * kint2[1 + itrad*4 + ig*4*4]
856 + (1.0 - wt) * kint2[0 + itrad*4 + ig*4*4];
857 }
858 }
859 }
860
861 /* Interpolation on Trad: spline */
862
863 if (interp_method != 0) {
864 for (int ig = 0; ig < ng; ig++) {
865 kg_t2[0] = tt[itrada[0]];
866 kg_t2[1] = tt[itrada[1]];
867 kg_t2[2] = tt[itrada[2]];
868 kg_t2[3] = tt[itrada[3]];
869 int nargs = 4;
870 _splmi(nargs,
871 kg_t2,
872 &kint3[0 + ig*4],
873 b,
874 c,
875 d);
876 kdb[ig] = _seval(nargs,
877 trad,
878 kg_t2,
879 &kint3[0 + ig*4],
880 b,
881 c,
882 d);
883 }
884 }
885 else {
886 cs_real_t wt = (trad - tt[itrada[0]]) / (tt[itrada[1]] - tt[itrada[0]]);
887 for (int ig = 0; ig < ng; ig++) {
888 kdb[ig] = wt * kint3[1 + ig*4] + (1.0 - wt) * kint3[0 + ig*4];
889 }
890 }
891
892 /* Free memory */
893 BFT_FREE(karray);
894 BFT_FREE(kint1);
895 BFT_FREE(kint2);
896 BFT_FREE(kint3);
897 BFT_FREE(b);
898 BFT_FREE(c);
899 BFT_FREE(d);
900 BFT_FREE(kg_t2);
901 BFT_FREE(kg_x2);
902 }
903
904 /*! (DOXYGEN_SHOULD_SKIP_THIS) \endcond */
905
906 /*=============================================================================
907 * Public function definitions
908 *============================================================================*/
909
910 /*----------------------------------------------------------------------------*/
911 /*!
912 * \brief Determine the radiation coefficients of the FSCK model
913 * as well as the corresponding weights.
914 *
915 * \param[in] pco2 CO2 volume fraction
916 * \param[in] ph2o H2O volume fraction
917 * \param[in] teloc gas temperature
918 * \param[out] kloc radiation coefficient of the i different gases
919 * \param[out] aloc weights of the i different gases in cells
920 * \param[out] alocb weights of the i different gases at boundaries
921 */
922 /*----------------------------------------------------------------------------*/
923
924 void
cs_rad_transfer_fsck(const cs_real_t * restrict pco2,const cs_real_t * restrict ph2o,const cs_real_t * restrict teloc,cs_real_t * restrict kloc,cs_real_t * restrict aloc,cs_real_t * restrict alocb)925 cs_rad_transfer_fsck(const cs_real_t *restrict pco2,
926 const cs_real_t *restrict ph2o,
927 const cs_real_t *restrict teloc,
928 cs_real_t *restrict kloc,
929 cs_real_t *restrict aloc,
930 cs_real_t *restrict alocb)
931 {
932 /* Initialization */
933
934 cs_real_t *gfskref, *kfskref, *kfsk, *gfsk, *gg1;
935 cs_real_t *kg1, *as, *ag, *aw, *kloctmp;
936
937 BFT_MALLOC(gfskref, ng, cs_real_t);
938 BFT_MALLOC(kfskref, ng, cs_real_t);
939 BFT_MALLOC(gfsk, ng, cs_real_t);
940 BFT_MALLOC(kfsk, ng, cs_real_t);
941 BFT_MALLOC(gg1, ng, cs_real_t);
942 BFT_MALLOC(kg1, ng, cs_real_t);
943 BFT_MALLOC(as, ng, cs_real_t);
944
945 BFT_MALLOC(ag, cs_glob_rad_transfer_params->nwsgg, cs_real_t);
946 BFT_MALLOC(aw, cs_glob_rad_transfer_params->nwsgg, cs_real_t);
947 BFT_MALLOC(kloctmp, cs_glob_rad_transfer_params->nwsgg, cs_real_t);
948
949 cs_field_t *f_bound_t = cs_field_by_name_try("boundary_temperature");
950 cs_real_t *tpfsck = f_bound_t->val;
951
952 /* Read the data base files */
953
954 ipass++;
955 if (ipass == 1) { /* Read parameters files */
956
957 FILE *radfile = NULL;
958 const char *pathdatadir = cs_base_get_pkgdatadir();
959 char filepath[256];
960
961 BFT_MALLOC(gi, ng, cs_real_t);
962 BFT_MALLOC(tt, nt, cs_real_t);
963 BFT_MALLOC(kpco2, nt, cs_real_t);
964 BFT_MALLOC(kph2o, nt, cs_real_t);
965 BFT_MALLOC(wv, nband, cs_real_t);
966 BFT_MALLOC(dwv, nband, cs_real_t);
967
968 BFT_MALLOC(kmfs, nconc * nconc * nt *nt *ng, cs_real_t);
969
970 /* Read k-distributions */
971 {
972 snprintf(filepath, 256, "%s/data/thch/dp_radiat_MFS", pathdatadir);
973 radfile = fopen(filepath, "r");
974 char line[256];
975 for (int cco2 = 0; cco2 < nconc; cco2++) {
976 for (int ch2o = 0; ch2o < nconc; ch2o++) {
977 for (int it = 0; it < nt; it++) {
978 for (int itrad = 0; itrad < nt; itrad++) {
979 fgets(line, 256, radfile);
980 fgets(line, 256, radfile);
981 for (int ig = 0; ig < ng; ig++) {
982 cs_real_t temp[2] = {0.};
983 int nvalues;
984 _line_to_array(radfile, temp, &nvalues);
985 assert(nvalues == 2);
986 gi[ig] = temp[0];
987 kmfs[ ch2o
988 + cco2*nconc
989 + it*nconc*nconc
990 + itrad*nconc*nconc*nt
991 + ig*nconc*nconc*nt*nt] = temp[1];
992 }
993 }
994 }
995 }
996 }
997 fclose(radfile);
998 }
999
1000 /* Read the Planck coefficients */
1001 {
1002 snprintf(filepath, 256, "%s/data/thch/dp_radiat_Planck_CO2", pathdatadir);
1003 radfile = fopen(filepath, "r");
1004 for (int it = 0; it < nt; it++) {
1005 cs_real_t temp[2] = {0.};
1006 int nvalues;
1007 _line_to_array(radfile, temp, &nvalues);
1008 assert(nvalues == 2);
1009 tt[it] = temp[0];
1010 kpco2[it] = temp[1];
1011 }
1012 fclose(radfile);
1013 }
1014
1015 {
1016 snprintf(filepath, 256, "%s/data/thch/dp_radiat_Planck_H2O", pathdatadir);
1017 radfile = fopen(filepath, "r");
1018 for (int it = 0; it < nt; it++) {
1019 cs_real_t temp[2] = {0.};
1020 int nvalues;
1021 _line_to_array(radfile, temp, &nvalues);
1022 assert(nvalues == 2);
1023 tt[it] = temp[0];
1024 kph2o[it] = temp[1];
1025 }
1026 fclose(radfile);
1027 }
1028
1029 /* Read the wavelength interval */
1030 {
1031 snprintf(filepath, 256, "%s/data/thch/dp_radiat_wave", pathdatadir);
1032 radfile = fopen(filepath, "r");
1033 for (int iwvnb = 0; iwvnb < nband; iwvnb++) {
1034 cs_real_t temp[2] = {0.};
1035 int nvalues;
1036 _line_to_array(radfile, temp, &nvalues);
1037 assert(nvalues == 2);
1038 wv[iwvnb] = temp[0];
1039 dwv[iwvnb] = temp[1];
1040 }
1041 fclose(radfile);
1042 }
1043
1044 /* Gaussian quadrature */
1045
1046 /* Allocation */
1047 BFT_MALLOC(gq, cs_glob_rad_transfer_params->nwsgg, cs_real_t);
1048 int m = (cs_glob_rad_transfer_params->nwsgg + 1) / 2;
1049 cs_real_t *p1, *p2, *p3, *pp;
1050 cs_real_t *z, *z1, *arth;
1051 bool *unfinished;
1052 BFT_MALLOC(p1, m, cs_real_t);
1053 BFT_MALLOC(p2, m, cs_real_t);
1054 BFT_MALLOC(p3, m, cs_real_t);
1055 BFT_MALLOC(pp, m, cs_real_t);
1056 BFT_MALLOC(z, m, cs_real_t);
1057 BFT_MALLOC(z1, m, cs_real_t);
1058 BFT_MALLOC(arth, m, cs_real_t);
1059 BFT_MALLOC(unfinished, m, bool);
1060
1061 /* Boundaries */
1062 cs_real_t x1 = 0.0;
1063 cs_real_t x2 = 1.0;
1064
1065 /* Given the lower and upper limits of integration x1 and x2, this routine
1066 * returns arrays x[0..n-1]
1067 * and w[0..n-1] of length n, containing the abscissas and weights of the
1068 * Gauss-Legendre n-point
1069 * quadrature formula. The parameter EPS is the relative precision.
1070 * Note that internal computations are done in double precision. */
1071
1072 int n = cs_glob_rad_transfer_params->nwsgg;
1073
1074 /* The roots are symmetric in the interval, so we only have to find half of them. */
1075
1076 cs_real_t xm = 0.5 * (x2 + x1);
1077 cs_real_t xl = 0.5 * (x2 - x1);
1078
1079 for (int i = 0; i < m; i++)
1080 arth[i] = i;
1081
1082 /* initial aproximation of the roots */
1083
1084 for (int i = 0; i < m; i++) {
1085 z[i] = cos(cs_math_pi * (arth[i] - 0.25) / (n + 0.5));
1086 unfinished[i] = true;
1087 }
1088
1089 /* Newton's method carried out simultaneously on the roots */
1090 int its;
1091 for (its = 0; its < maxit; its++) {
1092
1093 /* initialisation */
1094
1095 for (int j = 0; j < m; j++) {
1096 if (unfinished[j]) {
1097 p1[j] = 1.0;
1098 p2[j] = 0.0;
1099 }
1100 }
1101
1102 for (int j = 0; j < n; j++) {
1103 for (int i = 0; i < m; i++) {
1104 p3[i] = p2[i];
1105 p2[i] = p1[i];
1106 p1[i] = ((2.0 * j - 1.0) * z[i] * p2[i] - (j - 1.0) * p3[i]) / j;
1107 }
1108 }
1109
1110 /* p1 now contains the desired Legendre polynomials.
1111 * We next compute pp, its derivative, by a standard relation involving
1112 * also p2, the polynomial of one lower order. */
1113
1114 for (int j = 0; j < m; j++) {
1115 pp[j] = n * (z[j] * p1[j] - p2[j]) / (z[j] * z[j] - 1.0);
1116 z1[j] = z[j];
1117 z[j] = z1[j] - p1[j] / pp[j];
1118 unfinished[j] = (CS_ABS(z[j] - z1[j]) > eps);
1119 }
1120
1121 /* check if we should continue */
1122 int cont = 0;
1123 for (int j = 0; j < m; j++) {
1124 cont = 1;
1125 }
1126 if (cont == 0)
1127 break;
1128
1129 }
1130
1131 if (its == maxit)
1132 cs_log_printf(CS_LOG_DEFAULT, "Maximum number of iterations during GAULEG");
1133
1134 /* Scale the root to the desired interval, and put in its symmetric counterpart. */
1135
1136 for (int j = 0; j < m; j++) {
1137 gq[j] = xm - xl * z[j];
1138 gq[n - j + 1] = xm + xl * z[j];
1139 }
1140
1141 /* Compute the weight and its symmetric counterpart. */
1142
1143 for (int j = 0; j < m; j++) {
1144 cs_glob_rad_transfer_params->wq[j] = 2.0 * xl / ((1.0 - pow (z[j], 2.0)) * pow (pp[j], 2.0));
1145 cs_glob_rad_transfer_params->wq[n - j + 1] = cs_glob_rad_transfer_params->wq[j];
1146 }
1147
1148 BFT_FREE(p1);
1149 BFT_FREE(p2);
1150 BFT_FREE(p3);
1151 BFT_FREE(pp);
1152 BFT_FREE(z);
1153 BFT_FREE(z1);
1154 BFT_FREE(arth);
1155 BFT_FREE(unfinished);
1156
1157 }
1158
1159 /* Compute the reference state */
1160
1161 cs_real_t pco2ref = 0.0;
1162 cs_real_t ph2oref = 0.0;
1163 cs_real_t tref = 0.0;
1164 cs_real_t sum1 = 0.0;
1165 cs_real_t sum2 = 0.0;
1166
1167 for (cs_lnum_t iel = 0; iel < cs_glob_mesh->n_cells; iel++) {
1168
1169 /* Calculation of pco2ref and ph2oref */
1170 pco2ref += pco2[iel] * cs_glob_mesh_quantities->cell_vol[iel];
1171 ph2oref += ph2o[iel] * cs_glob_mesh_quantities->cell_vol[iel];
1172
1173 /* Calculation of tref */
1174 /* Interplolation of Planck coefficient for mix */
1175 cs_real_t kp;
1176 if (teloc[iel] <= tt[0])
1177 kp = pco2[iel] * kpco2[0] + ph2o[iel] * kph2o[0];
1178 else if (teloc[iel] >= tt[nt - 1])
1179 kp = pco2[iel] * kpco2[nt - 1] + ph2o[iel] * kpco2[nt - 1];
1180 else {
1181 kp = 0.;
1182 for (int it = 0; it < nt - 1; it++) {
1183 if ((teloc[iel] >= tt[it]) && (teloc[iel] < tt[it + 1])) {
1184 cs_real_t kp1 = pco2[iel] * kpco2[it] + ph2o[iel] * kph2o[it];
1185 cs_real_t kp2 = pco2[iel] * kpco2[it + 1] + ph2o[iel] * kph2o[it + 1];
1186 kp = (kp2 - kp1) / (tt[it + 1] - tt[it]) * (teloc[iel] - tt[it]) + kp1;
1187 break;
1188 }
1189 }
1190 }
1191 cs_real_t kpt4dv = kp
1192 * pow(teloc[iel], 4.0)
1193 * cs_glob_mesh_quantities->cell_vol[iel];
1194 sum1 += kpt4dv * teloc[iel];
1195 sum2 += kpt4dv;
1196 }
1197
1198 if (cs_glob_rank_id >= 0) {
1199 cs_parall_sum(1, CS_DOUBLE, &pco2ref);
1200 cs_parall_sum(1, CS_DOUBLE, &ph2oref);
1201 cs_parall_sum(1, CS_DOUBLE, &sum1);
1202 cs_parall_sum(1, CS_DOUBLE, &sum2);
1203 }
1204
1205 pco2ref /= cs_glob_mesh_quantities->tot_vol;
1206 ph2oref /= cs_glob_mesh_quantities->tot_vol;
1207 tref = sum1 / sum2;
1208
1209 /* Interpolation */
1210
1211 /* Determination of the k-distribution at the reference state */
1212 int interp_method = imlinear;
1213 _interpolation4d(tref,
1214 tref,
1215 pco2ref,
1216 ph2oref,
1217 interp_method,
1218 gfskref,
1219 kfskref);
1220
1221 /* [m^-1] */
1222 for (int i = 0; i < ng; i++)
1223 kfskref[i] *= 100.0;
1224
1225 for (cs_lnum_t iel = 0; iel < cs_glob_mesh->n_cells; iel++) {
1226
1227 /* Determination of the local absorbtion coefficient */
1228 for (int i = 0; i < ng; i++) {
1229 kfsk[i] = 0.;
1230 gfsk[i] = 0.;
1231 }
1232 _interpolation4d (tref,
1233 teloc[iel],
1234 pco2[iel],
1235 ph2o[iel],
1236 interp_method,
1237 gfsk,
1238 kfsk);
1239 /* [m^-1] */
1240 for (int i = 0; i < ng; i++)
1241 kfsk[i] *= 100.0;
1242
1243 _simple_interpg(ng,
1244 gfsk,
1245 kfsk,
1246 cs_glob_rad_transfer_params->nwsgg,
1247 gq,
1248 kloctmp);
1249 for (int i = 0; i < cs_glob_rad_transfer_params->nwsgg; i++)
1250 kloc[i * cs_glob_mesh->n_cells + iel] = kloctmp[i];
1251
1252 /* Determination of the local weights */
1253 for (int i = 0; i < ng; i++) {
1254 kfsk[i] = 0.;
1255 gfsk[i] = 0.;
1256 }
1257 _interpolation4d(teloc[iel],
1258 tref,
1259 pco2ref,
1260 ph2oref,
1261 interp_method,
1262 gg1,
1263 kg1);
1264 /* [m^-1] */
1265 for (int i = 0; i < ng; i++)
1266 kg1[i] *= 100.0;
1267
1268 _simple_interpg(ng,
1269 kg1,
1270 gg1,
1271 ng,
1272 kfskref,
1273 gfsk);
1274 as[0] = (gfsk[1] - gfsk[0]) / (gfskref[1] - gfskref[0] + 1e-15);
1275 as[ng-1] = (gfsk[ng-1] - gfsk[ng - 2]) / (gfskref[ng-1] - gfskref[ng - 2] + 1e-15);
1276 for (int k = 1; k < ng - 1; k++)
1277 as[k] = (gfsk[k + 1] - gfsk[k - 1]) / (gfskref[k + 1] - gfskref[k - 1] + 1e-15);
1278 _simple_interpg(ng,
1279 gfskref,
1280 as,
1281 cs_glob_rad_transfer_params->nwsgg,
1282 gq,
1283 ag);
1284 for (int i = 0; i < cs_glob_rad_transfer_params->nwsgg; i++)
1285 aloc[i * cs_glob_mesh->n_cells + iel] = ag[i];
1286
1287 }
1288
1289 for (cs_lnum_t ifac = 0; ifac < cs_glob_mesh->n_b_faces; ifac++) {
1290 _interpolation4d(tpfsck[ifac],
1291 tref,
1292 pco2ref,
1293 ph2oref,
1294 interp_method,
1295 gg1,
1296 kg1);
1297 for (int i = 0; i < ng; i++)
1298 kg1[i] *= 100.0;
1299
1300 _simple_interpg(ng,
1301 kg1,
1302 gg1,
1303 ng,
1304 kfskref,
1305 gfsk);
1306 as[0] = (gfsk[1] - gfsk[0]) / (gfskref[1] - gfskref[0] + 1e-15);
1307 as[ng] = (gfsk[ng] - gfsk[ng - 1]) / (gfskref[ng] - gfskref[ng - 1] + 1e-15);
1308 for (int k = 1; k < ng - 1; k++)
1309 as[k] = (gfsk[k + 1] - gfsk[k - 1]) / (gfskref[k + 1] - gfskref[k - 1] + 1e-15);
1310 _simple_interpg(ng,
1311 gfskref,
1312 as,
1313 cs_glob_rad_transfer_params->nwsgg,
1314 gq,
1315 aw);
1316 for (int i = 0; i < cs_glob_rad_transfer_params->nwsgg; i++)
1317 alocb[i * cs_glob_mesh->n_b_faces + ifac] = aw[i];
1318 }
1319
1320 /* free memory */
1321 if (cs_glob_time_step->nt_cur == cs_glob_time_step->nt_max) {
1322 BFT_FREE(gi);
1323 BFT_FREE(tt);
1324 BFT_FREE(kpco2);
1325 BFT_FREE(kph2o);
1326 BFT_FREE(wv);
1327 BFT_FREE(dwv);
1328 BFT_FREE(kmfs);
1329 BFT_FREE(gq);
1330 }
1331
1332 BFT_FREE(kloctmp);
1333 }
1334
1335 /*----------------------------------------------------------------------------*/
1336
1337 END_C_DECLS
1338