1 | |
---|
2 | ! |
---|
3 | ! This program may be freely redistributed under the |
---|
4 | ! condition that the copyright notices (including this |
---|
5 | ! entire header) are not removed, and no compensation |
---|
6 | ! is received through use of the software. Private, |
---|
7 | ! research, and institutional use is free. You may |
---|
8 | ! distribute modified versions of this code UNDER THE |
---|
9 | ! CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE |
---|
10 | ! TO IT IN THE SAME FILE REMAIN UNDER COPYRIGHT OF THE |
---|
11 | ! ORIGINAL AUTHOR, BOTH SOURCE AND OBJECT CODE ARE |
---|
12 | ! MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR |
---|
13 | ! NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution |
---|
14 | ! of this code as part of a commercial system is |
---|
15 | ! permissible ONLY BY DIRECT ARRANGEMENT WITH THE |
---|
16 | ! AUTHOR. (If you are not directly supplying this |
---|
17 | ! code to a customer, and you are instead telling them |
---|
18 | ! how they can obtain it for free, then you are not |
---|
19 | ! required to make any arrangement with me.) |
---|
20 | ! |
---|
21 | ! Disclaimer: Neither I nor: Columbia University, the |
---|
22 | ! National Aeronautics and Space Administration, nor |
---|
23 | ! the Massachusetts Institute of Technology warrant |
---|
24 | ! or certify this code in any way whatsoever. This |
---|
25 | ! code is provided "as-is" to be used at your own risk. |
---|
26 | ! |
---|
27 | ! |
---|
28 | |
---|
29 | ! |
---|
30 | ! RMAP1D.f90: high-order integral re-mapping operators. |
---|
31 | ! |
---|
32 | ! Darren Engwirda |
---|
33 | ! 31-Mar-2019 |
---|
34 | ! de2363 [at] columbia [dot] edu |
---|
35 | ! |
---|
36 | ! |
---|
37 | |
---|
38 | subroutine rmap1d(npos,nnew,nvar,ndof,xpos, & |
---|
39 | & xnew,fdat,fnew,bclo,bcup, & |
---|
40 | & work,opts,tCPU) |
---|
41 | |
---|
42 | ! |
---|
43 | ! NPOS no. edges in old grid. |
---|
44 | ! NNEW no. edges in new grid. |
---|
45 | ! NVAR no. discrete variables to remap. |
---|
46 | ! NDOF no. degrees-of-freedom per cell. |
---|
47 | ! XPOS old grid edge positions. XPOS is a length NPOS |
---|
48 | ! array . |
---|
49 | ! XNEW new grid edge positions. XNEW is a length NNEW |
---|
50 | ! array . |
---|
51 | ! FDAT grid-cell moments on old grid. FNEW has SIZE = |
---|
52 | ! NDOF-by-NVAR-by-NNEW-1 . |
---|
53 | ! FNEW grid-cell moments on new grid. FNEW has SIZE = |
---|
54 | ! NDOF-by-NVAR-by-NNEW-1 . |
---|
55 | ! BCLO boundary condition at lower endpoint . |
---|
56 | ! BCHI boundary condition at upper endpoint . |
---|
57 | ! WORK method work-space. See RCON-WORK for details . |
---|
58 | ! OPTS method parameters. See RCON-OPTS for details . |
---|
59 | ! TCPU method tcpu-timer. |
---|
60 | ! |
---|
61 | |
---|
62 | implicit none |
---|
63 | |
---|
64 | !------------------------------------------- arguments ! |
---|
65 | integer, intent( in) :: npos,nnew |
---|
66 | integer, intent( in) :: nvar,ndof |
---|
67 | class(rmap_work), intent(inout):: work |
---|
68 | class(rmap_opts), intent(inout):: opts |
---|
69 | real*8 , intent( in) :: xpos(:) |
---|
70 | real*8 , intent( in) :: xnew(:) |
---|
71 | real*8 , intent( in) :: fdat(:,:,:) |
---|
72 | real*8 , intent(out) :: fnew(:,:,:) |
---|
73 | type (rcon_ends), intent(in) :: bclo(:) |
---|
74 | type (rcon_ends), intent(in) :: bcup(:) |
---|
75 | type (rmap_tics), & |
---|
76 | & intent(inout) , optional :: tCPU |
---|
77 | |
---|
78 | real*8 , parameter :: RTOL = +1.d-14 |
---|
79 | |
---|
80 | !------------------------------------------- variables ! |
---|
81 | integer :: ipos |
---|
82 | real*8 :: diff,spac,same,xtol |
---|
83 | real*8 :: delx(1) |
---|
84 | logical :: uniform |
---|
85 | |
---|
86 | # ifdef __PPR_TIMER__ |
---|
87 | integer(kind=8) :: ttic,ttoc,rate |
---|
88 | # endif |
---|
89 | |
---|
90 | if (ndof.lt.1) return |
---|
91 | if (npos.lt.2) return |
---|
92 | if (nnew.lt.2) return |
---|
93 | if (nvar.lt.1) return |
---|
94 | |
---|
95 | !------------- calc. grid-spacing and check uniformity ! |
---|
96 | |
---|
97 | same = (xpos(npos)& |
---|
98 | - xpos( +1)) / (npos-1) |
---|
99 | |
---|
100 | uniform = .true. |
---|
101 | |
---|
102 | xtol = same * RTOL |
---|
103 | |
---|
104 | do ipos = +1 , npos-1, +1 |
---|
105 | |
---|
106 | spac = xpos(ipos+1) & |
---|
107 | & - xpos(ipos+0) |
---|
108 | |
---|
109 | diff = abs(spac - same) |
---|
110 | |
---|
111 | if (diff.gt.xtol) then |
---|
112 | |
---|
113 | uniform = .false. |
---|
114 | |
---|
115 | end if |
---|
116 | |
---|
117 | work% & |
---|
118 | & cell_spac(ipos) = spac |
---|
119 | |
---|
120 | end do |
---|
121 | |
---|
122 | !uniform = .false. |
---|
123 | |
---|
124 | !------------- reconstruct FHAT over all cells in XPOS ! |
---|
125 | |
---|
126 | if (.not. uniform) then |
---|
127 | |
---|
128 | !------------------------------------ variable spacing ! |
---|
129 | call rcon1d(npos,nvar,ndof, & |
---|
130 | & work%cell_spac, & |
---|
131 | & fdat,bclo,bcup, & |
---|
132 | & work%cell_func, & |
---|
133 | & work,opts,tCPU) |
---|
134 | |
---|
135 | else |
---|
136 | |
---|
137 | !------------------------------------ constant spacing ! |
---|
138 | delx(1) = work%cell_spac(1) |
---|
139 | |
---|
140 | call rcon1d(npos,nvar,ndof, & |
---|
141 | & delx, & |
---|
142 | & fdat,bclo,bcup, & |
---|
143 | & work%cell_func, & |
---|
144 | & work,opts,tCPU) |
---|
145 | |
---|
146 | end if |
---|
147 | |
---|
148 | !------------- remap FDAT from XPOS to XNEW using FHAT ! |
---|
149 | |
---|
150 | __TIC__ |
---|
151 | |
---|
152 | select case(opts%cell_meth) |
---|
153 | case(pcm_method) |
---|
154 | !------------------------------------ 1st-order method ! |
---|
155 | call imap1d(npos,nnew,nvar, & |
---|
156 | & ndof, +1, & |
---|
157 | & xpos,xnew, & |
---|
158 | & work%cell_func, & |
---|
159 | & fdat,fnew,xtol) |
---|
160 | |
---|
161 | case(plm_method) |
---|
162 | !------------------------------------ 2nd-order method ! |
---|
163 | call imap1d(npos,nnew,nvar, & |
---|
164 | & ndof, +2, & |
---|
165 | & xpos,xnew, & |
---|
166 | & work%cell_func, & |
---|
167 | & fdat,fnew,xtol) |
---|
168 | |
---|
169 | case(ppm_method) |
---|
170 | !------------------------------------ 3rd-order method ! |
---|
171 | call imap1d(npos,nnew,nvar, & |
---|
172 | & ndof, +3, & |
---|
173 | & xpos,xnew, & |
---|
174 | & work%cell_func, & |
---|
175 | & fdat,fnew,xtol) |
---|
176 | |
---|
177 | case(pqm_method) |
---|
178 | !------------------------------------ 5th-order method ! |
---|
179 | call imap1d(npos,nnew,nvar, & |
---|
180 | & ndof, +5, & |
---|
181 | & xpos,xnew, & |
---|
182 | & work%cell_func, & |
---|
183 | & fdat,fnew,xtol) |
---|
184 | |
---|
185 | end select |
---|
186 | |
---|
187 | __TOC__(tCPU,rmap_time) |
---|
188 | |
---|
189 | return |
---|
190 | |
---|
191 | end subroutine |
---|
192 | |
---|
193 | !------------ IMAP1D: 1-dimensional degree-k remapping ! |
---|
194 | |
---|
195 | pure subroutine imap1d(npos,nnew,nvar,ndof, & |
---|
196 | & mdof,xpos,xnew,fhat, & |
---|
197 | & fdat,fnew,XTOL) |
---|
198 | |
---|
199 | ! |
---|
200 | ! NPOS no. edges in old grid. |
---|
201 | ! NNEW no. edges in new grid. |
---|
202 | ! NVAR no. discrete variables to remap. |
---|
203 | ! NDOF no. degrees-of-freedom per cell. |
---|
204 | ! MDOF no. degrees-of-freedom per FHAT. |
---|
205 | ! XPOS old grid edge positions. XPOS is a length NPOS |
---|
206 | ! array . |
---|
207 | ! XNEW new grid edge positions. XNEW is a length NNEW |
---|
208 | ! array . |
---|
209 | ! FHAT reconstruction over old grid. FHAT has SIZE = |
---|
210 | ! MDOF-by-NVAR-by-NPOS-1 . |
---|
211 | ! FDAT grid-cell moments on old grid. FDAT has SIZE = |
---|
212 | ! NDOF-by-NVAR-by-NPOS-1 . |
---|
213 | ! FNEW grid-cell moments on new grid. FNEW has SIZE = |
---|
214 | ! NDOF-by-NVAR-by-NNEW-1 . |
---|
215 | ! XTOL min. grid-cell thickness . |
---|
216 | ! |
---|
217 | |
---|
218 | implicit none |
---|
219 | |
---|
220 | !------------------------------------------- arguments ! |
---|
221 | integer, intent( in) :: npos,nnew |
---|
222 | integer, intent( in) :: nvar |
---|
223 | integer, intent( in) :: ndof,mdof |
---|
224 | real*8 , intent( in) :: xpos(:) |
---|
225 | real*8 , intent( in) :: xnew(:) |
---|
226 | real*8 , intent( in) :: fhat(:,:,:) |
---|
227 | real*8 , intent( in) :: fdat(:,:,:) |
---|
228 | real*8 , intent(out) :: fnew(:,:,:) |
---|
229 | real*8 , intent( in) :: XTOL |
---|
230 | |
---|
231 | !------------------------------------------- variables ! |
---|
232 | integer :: kpos,ipos,ivar,idof |
---|
233 | integer :: pos0,pos1,vmin,vmax |
---|
234 | real*8 :: xmid,xhat,khat,stmp |
---|
235 | real*8 :: xxlo,xxhi,sslo,sshi,intf |
---|
236 | real*8 :: vvlo( +1:+5) |
---|
237 | real*8 :: vvhi( +1:+5) |
---|
238 | real*8 :: ivec( +1:+5) |
---|
239 | real*8 :: sdat( +1:nvar) |
---|
240 | real*8 :: snew( +1:nvar) |
---|
241 | real*8 :: serr( +1:nvar) |
---|
242 | integer :: kmin( +1:nvar) |
---|
243 | integer :: kmax( +1:nvar) |
---|
244 | |
---|
245 | integer, parameter :: INTB = -1 ! integral basis |
---|
246 | |
---|
247 | !------------- remap FDAT from XPOS to XNEW using FHAT ! |
---|
248 | |
---|
249 | kmin = +1 ; kmax = +1 |
---|
250 | pos0 = +1 ; pos1 = +1 |
---|
251 | |
---|
252 | do kpos = +1, nnew-1 |
---|
253 | |
---|
254 | !------ first cell in XPOS overlapping with XNEW(KPOS) ! |
---|
255 | |
---|
256 | pos1 = max(pos1,1) |
---|
257 | |
---|
258 | do pos0 = pos1, npos-1 |
---|
259 | |
---|
260 | if (xpos(pos0+1)& |
---|
261 | & .gt. xnew(kpos+0)) exit |
---|
262 | |
---|
263 | end do |
---|
264 | |
---|
265 | !------ final cell in XPOS overlapping with XNEW(KPOS) ! |
---|
266 | |
---|
267 | do pos1 = pos0, npos-1 |
---|
268 | |
---|
269 | if (xpos(pos1+0)& |
---|
270 | & .ge. xnew(kpos+1)) exit |
---|
271 | |
---|
272 | end do |
---|
273 | |
---|
274 | pos1 = pos1 - 1 |
---|
275 | |
---|
276 | !------------- integrate FHAT across overlapping cells ! |
---|
277 | |
---|
278 | khat = xnew(kpos+1) & |
---|
279 | & - xnew(kpos+0) |
---|
280 | khat = max (khat , XTOL) |
---|
281 | |
---|
282 | do idof = +1,ndof |
---|
283 | do ivar = +1,nvar |
---|
284 | |
---|
285 | fnew(idof,ivar,kpos) = 0.d0 |
---|
286 | |
---|
287 | end do |
---|
288 | end do |
---|
289 | |
---|
290 | do ipos = pos0, pos1 |
---|
291 | |
---|
292 | !------------------------------- integration endpoints ! |
---|
293 | |
---|
294 | xxlo = max (xpos(ipos+0) , & |
---|
295 | & xnew(kpos+0)) |
---|
296 | xxhi = min (xpos(ipos+1) , & |
---|
297 | & xnew(kpos+1)) |
---|
298 | |
---|
299 | !------------------------------- local endpoint coords ! |
---|
300 | |
---|
301 | xmid = xpos(ipos+1) * .5d0 & |
---|
302 | & + xpos(ipos+0) * .5d0 |
---|
303 | xhat = xpos(ipos+1) * .5d0 & |
---|
304 | & - xpos(ipos+0) * .5d0 |
---|
305 | |
---|
306 | sslo = & |
---|
307 | & (xxlo-xmid) / max(xhat,XTOL) |
---|
308 | sshi = & |
---|
309 | & (xxhi-xmid) / max(xhat,XTOL) |
---|
310 | |
---|
311 | !------------------------------- integral basis vector ! |
---|
312 | |
---|
313 | call bfun1d(INTB,mdof, & |
---|
314 | sslo,vvlo) |
---|
315 | call bfun1d(INTB,mdof, & |
---|
316 | sshi,vvhi) |
---|
317 | |
---|
318 | ivec = vvhi - vvlo |
---|
319 | |
---|
320 | !--------- integrate FHAT across the overlap XXLO:XXHI ! |
---|
321 | |
---|
322 | do ivar = +1, nvar |
---|
323 | |
---|
324 | intf = dot_product ( & |
---|
325 | & ivec(+1:mdof), & |
---|
326 | & fhat(+1:mdof,ivar,ipos-0) ) |
---|
327 | |
---|
328 | intf = intf * xhat |
---|
329 | |
---|
330 | !--------- accumulate integral contributions from IPOS ! |
---|
331 | |
---|
332 | fnew( +1,ivar,kpos) = & |
---|
333 | & fnew( +1,ivar,kpos) + intf |
---|
334 | |
---|
335 | end do |
---|
336 | |
---|
337 | end do |
---|
338 | |
---|
339 | !------------------------------- finalise KPOS profile ! |
---|
340 | |
---|
341 | do ivar = +1, nvar |
---|
342 | |
---|
343 | fnew( +1,ivar,kpos) = & |
---|
344 | & fnew( +1,ivar,kpos) / khat |
---|
345 | |
---|
346 | !--------- keep track of MIN/MAX for defect correction ! |
---|
347 | |
---|
348 | vmax = kmax(ivar) |
---|
349 | vmin = kmin(ivar) |
---|
350 | |
---|
351 | if(fnew(1,ivar,kpos) & |
---|
352 | & .gt.fnew(1,ivar,vmax) ) then |
---|
353 | |
---|
354 | kmax(ivar) = kpos |
---|
355 | |
---|
356 | else & |
---|
357 | & if(fnew(1,ivar,kpos) & |
---|
358 | & .lt.fnew(1,ivar,vmin) ) then |
---|
359 | |
---|
360 | kmin(ivar) = kpos |
---|
361 | |
---|
362 | end if |
---|
363 | |
---|
364 | end do |
---|
365 | |
---|
366 | end do |
---|
367 | |
---|
368 | !--------- defect corrections: Kahan/Babuska/Neumaier. ! |
---|
369 | |
---|
370 | ! Carefully compute column sums, leading to a defect |
---|
371 | ! wrt. column-wise conservation. Use KBN approach to |
---|
372 | ! account for FP roundoff. |
---|
373 | |
---|
374 | sdat = 0.d0; serr = 0.d0 |
---|
375 | do ipos = +1, npos-1 |
---|
376 | do ivar = +1, nvar-0 |
---|
377 | |
---|
378 | !------------------------------- integrate old profile ! |
---|
379 | |
---|
380 | xhat = xpos(ipos+1) & |
---|
381 | & - xpos(ipos+0) |
---|
382 | |
---|
383 | intf = xhat*fdat(1,ivar,ipos) |
---|
384 | |
---|
385 | stmp = sdat(ivar) + intf |
---|
386 | |
---|
387 | if (abs(sdat(ivar)) & |
---|
388 | & .ge. abs(intf)) then |
---|
389 | |
---|
390 | serr(ivar) = & |
---|
391 | & serr(ivar) + ((sdat(ivar)-stmp)+intf) |
---|
392 | |
---|
393 | else |
---|
394 | |
---|
395 | serr(ivar) = & |
---|
396 | & serr(ivar) + ((intf-stmp)+sdat(ivar)) |
---|
397 | |
---|
398 | end if |
---|
399 | |
---|
400 | sdat(ivar) = stmp |
---|
401 | |
---|
402 | end do |
---|
403 | end do |
---|
404 | |
---|
405 | sdat = sdat + serr |
---|
406 | |
---|
407 | snew = 0.d0; serr = 0.d0 |
---|
408 | do ipos = +1, nnew-1 |
---|
409 | do ivar = +1, nvar-0 |
---|
410 | |
---|
411 | !------------------------------- integrate new profile ! |
---|
412 | |
---|
413 | khat = xnew(ipos+1) & |
---|
414 | & - xnew(ipos+0) |
---|
415 | |
---|
416 | intf = khat*fnew(1,ivar,ipos) |
---|
417 | |
---|
418 | stmp = snew(ivar) + intf |
---|
419 | |
---|
420 | if (abs(snew(ivar)) & |
---|
421 | & .ge. abs(intf)) then |
---|
422 | |
---|
423 | serr(ivar) = & |
---|
424 | & serr(ivar) + ((snew(ivar)-stmp)+intf) |
---|
425 | |
---|
426 | else |
---|
427 | |
---|
428 | serr(ivar) = & |
---|
429 | & serr(ivar) + ((intf-stmp)+snew(ivar)) |
---|
430 | |
---|
431 | end if |
---|
432 | |
---|
433 | snew(ivar) = stmp |
---|
434 | |
---|
435 | end do |
---|
436 | end do |
---|
437 | |
---|
438 | snew = snew + serr |
---|
439 | serr = sdat - snew |
---|
440 | |
---|
441 | !--------- defect corrections: nudge away from extrema ! |
---|
442 | |
---|
443 | ! Add a correction to remapped state to impose exact |
---|
444 | ! conservation. Via sign(correction), nudge min/max. |
---|
445 | ! cell means, such that monotonicity is not violated |
---|
446 | ! near extrema... |
---|
447 | |
---|
448 | do ivar = +1, nvar-0 |
---|
449 | |
---|
450 | if (serr(ivar) .gt. 0.d0) then |
---|
451 | |
---|
452 | vmin = kmin(ivar) |
---|
453 | |
---|
454 | fnew(1,ivar,vmin) = & |
---|
455 | & fnew(1,ivar,vmin) + & |
---|
456 | & serr(ivar)/(xnew(vmin+1)-xnew(vmin+0)) |
---|
457 | |
---|
458 | else & |
---|
459 | & if (serr(ivar) .lt. 0.d0) then |
---|
460 | |
---|
461 | vmax = kmax(ivar) |
---|
462 | |
---|
463 | fnew(1,ivar,vmax) = & |
---|
464 | & fnew(1,ivar,vmax) + & |
---|
465 | & serr(ivar)/(xnew(vmax+1)-xnew(vmax+0)) |
---|
466 | |
---|
467 | end if |
---|
468 | |
---|
469 | end do |
---|
470 | |
---|
471 | !------------------------------- new profile now final ! |
---|
472 | |
---|
473 | return |
---|
474 | |
---|
475 | end subroutine |
---|
476 | |
---|
477 | |
---|
478 | |
---|