New URL for NEMO forge!   http://forge.nemo-ocean.eu

Since March 2022 along with NEMO 4.2 release, the code development moved to a self-hosted GitLab.
This present forge is now archived and remained online for history.
rmap1d.h90 in NEMO/branches/2020/dev_r13312_AGRIF-03-04_jchanut_vinterp_tstep/ext/PPR/src – NEMO

source: NEMO/branches/2020/dev_r13312_AGRIF-03-04_jchanut_vinterp_tstep/ext/PPR/src/rmap1d.h90 @ 13926

Last change on this file since 13926 was 13926, checked in by jchanut, 4 years ago

#2222, add Piecewise Polynomial Reconstruction library

File size: 13.3 KB
Line 
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
Note: See TracBrowser for help on using the repository browser.