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.
ppm.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/ppm.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: 10.4 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    ! PPM.f90: 1d slope-limited, piecewise parabolic recon.
31    !
32    ! Darren Engwirda
33    ! 08-Sep-2016
34    ! de2363 [at] columbia [dot] edu
35    !
36    !
37 
38    ! P. Colella and PR. Woodward, The Piecewise Parabolic
39    ! Method (PPM) for gas-dynamical simulations., J. Comp.
40    ! Phys., 54 (1), 1984, 174-201,
41    ! https://doi.org/10.1016/0021-9991(84)90143-8
42    !
43
44    pure subroutine ppm(npos,nvar,ndof,delx, &
45        &               fdat,fhat,edge,oscl, &
46        &               dmin,ilim,wlim,halo)
47
48
49    !
50    ! NPOS  no. edges over grid.
51    ! NVAR  no. state variables.
52    ! NDOF  no. degrees-of-freedom per grid-cell.
53    ! DELX  grid-cell spacing array. LENGTH(DELX) == +1 if
54    !       spacing is uniform .
55    ! FDAT  grid-cell moments array. FDAT is an array with
56    !       SIZE = NDOF-by-NVAR-by-NPOS-1 .
57    ! FHAT  grid-cell re-con. array. FHAT is an array with
58    !       SIZE = MDOF-by-NVAR-by-NPOS-1 .
59    ! EDGE  edge-centred interp. for function-value. EDGE
60    !       is an array with SIZE = NVAR-by-NPOS .
61    ! OSCL  grid-cell oscil. dof.'s. OSCL is an array with
62    !       SIZE = +2  -by-NVAR-by-NPOS-1 .
63    ! DMIN  min. grid-cell spacing thresh .
64    ! ILIM  cell slope-limiting selection .
65    ! WLIM  wall slope-limiting selection .
66    ! HALO  width of re-con. stencil, symmetric about mid. .
67    !
68
69        implicit none
70
71    !------------------------------------------- arguments !
72        integer, intent(in)  :: npos,nvar,ndof
73        real*8 , intent(in)  :: dmin
74        real*8 , intent(out) :: fhat(:,:,:)
75        real*8 , intent(in)  :: oscl(:,:,:)
76        real*8 , intent(in)  :: delx(:)
77        real*8 , intent(in)  :: fdat(:,:,:)
78        real*8 , intent(in)  :: edge(:,:)
79        integer, intent(in)  :: ilim,wlim,halo
80
81    !------------------------------------------- variables !
82        integer :: ipos,ivar,iill,iirr,head,tail
83        real*8  :: ff00,ffll,ffrr,hh00,hhll,hhrr
84        integer :: mono
85        real*8  :: fell,ferr
86        real*8  :: dfds(-1:+1)
87        real*8  :: wval(+1:+2)
88        real*8  :: uhat(+1:+3)
89        real*8  :: lhat(+1:+3)
90       
91        head = +1; tail = npos - 1
92
93        if (npos.eq.2) then
94    !----- default to reduced order if insufficient points !
95        do  ivar = +1, nvar
96            fhat(1,ivar,+1) = &
97        &   fdat(1,ivar,+1)
98            fhat(2,ivar,+1) = 0.d0
99            fhat(3,ivar,+1) = 0.d0
100        end do
101        end if
102
103        if (npos.le.2) return
104
105    !------------------- reconstruct function on each cell !
106
107        uhat = +0.d+0
108        lhat = +0.d+0
109
110        do  ipos = +1 , npos-1
111
112        iill = max(head,ipos-1)
113        iirr = min(tail,ipos+1)
114
115        do  ivar = +1 , nvar-0
116
117    !----------------------------- cell mean + edge values !
118   
119            ff00 = fdat(1,ivar,ipos)
120            ffll = fdat(1,ivar,iill)
121            ffrr = fdat(1,ivar,iirr)
122
123            fell = edge(ivar,ipos+0)
124            ferr = edge(ivar,ipos+1)
125
126    !----------------------------- calc. LL/00/RR gradient !
127   
128            if (size(delx).gt.+1) then
129
130            hh00 = delx(ipos)
131            hhll = delx(iill)
132            hhrr = delx(iirr)
133
134            call plsv (ffll,hhll,ff00, &
135    &                  hh00,ffrr,hhrr, &
136    &                  dfds)
137            else
138           
139            call plsc (ffll,ff00,ffrr, &
140    &                  dfds)
141   
142            end if
143
144    !----------------------------- calc. cell-wise profile !
145   
146            select case(ilim)
147            case (null_limit)
148
149    !----------------------------- calc. unlimited profile !   
150               
151            call ppmfn(ff00,ffll,ffrr, &
152    &                  fell,ferr,dfds, &
153    &                  uhat,lhat,mono)
154           
155    !----------------------------- pref. unlimited profile !
156
157            wval(1) = +1.d+0
158            wval(2) = +0.d+0
159           
160            case (mono_limit)
161           
162    !----------------------------- calc. monotonic profile !
163             
164            call ppmfn(ff00,ffll,ffrr, &
165    &                  fell,ferr,dfds, &
166    &                  uhat,lhat,mono)
167           
168    !----------------------------- pref. monotonic profile !
169
170            wval(1) = +0.d+0
171            wval(2) = +1.d+0
172           
173            case (weno_limit)
174
175    !----------------------------- calc. unlimited profile ! 
176           
177            call ppmfn(ff00,ffll,ffrr, &
178    &                  fell,ferr,dfds, &
179    &                  uhat,lhat,mono)
180
181            if (mono.gt.+0) then
182 
183    !----------------------------- calc. WENO-type weights !
184     
185            call wenoi(npos,delx,oscl, &
186    &                  ipos,ivar,halo, &
187    &                  wlim,wval)
188           
189            else
190               
191    !----------------------------- pref. unlimited profile !
192
193            wval(1) = +1.d+0
194            wval(2) = +0.d+0
195           
196            end if
197           
198            end select
199 
200    !----------------------------- blend "null" and "mono" !
201               
202            fhat(1,ivar,ipos) = &
203    &       wval(1) * uhat(1) + &
204    &       wval(2) * lhat(1)
205            fhat(2,ivar,ipos) = &
206    &       wval(1) * uhat(2) + &
207    &       wval(2) * lhat(2)
208            fhat(3,ivar,ipos) = &
209    &       wval(1) * uhat(3) + &
210    &       wval(2) * lhat(3)
211
212        end do
213
214        end do
215       
216        return
217
218    end  subroutine
219
220    !--------- assemble piecewise parabolic reconstruction !
221   
222    pure subroutine ppmfn(ff00,ffll,ffrr,fell,&
223        &                 ferr,dfds,uhat,lhat,&
224        &                 mono)
225
226    !
227    ! FF00  centred grid-cell mean.
228    ! FFLL  left -biased grid-cell mean.
229    ! FFRR  right-biased grid-cell mean.
230    ! FELL  left -biased edge interp.
231    ! FERR  right-biased edge interp.
232    ! DFDS  piecewise linear gradients in local co-ord.'s.
233    !       DFDS(+0) is a centred, slope-limited estimate,
234    !       DFDS(-1), DFDS(+1) are left- and right-biased
235    !       estimates (unlimited).
236    ! UHAT  unlimited PPM reconstruction coefficients .
237    ! LHAT  monotonic PPM reconstruction coefficients .
238    ! MONO  slope-limiting indicator, MONO > +0 if some
239    !       limiting has occured .
240    !
241
242        implicit none
243
244    !------------------------------------------- arguments !
245        real*8 , intent(in)    :: ff00
246        real*8 , intent(in)    :: ffll,ffrr
247        real*8 , intent(inout) :: fell,ferr
248        real*8 , intent(in)    :: dfds(-1:+1)
249        real*8 , intent(out)   :: uhat(+1:+3)
250        real*8 , intent(out)   :: lhat(+1:+3)
251        integer, intent(out)   :: mono
252         
253    !------------------------------------------- variables !
254        real*8  :: turn
255       
256        mono  = 0
257       
258    !-------------------------------- "null" slope-limiter !
259
260        uhat( 1 ) = &
261    & + (3.0d+0 / 2.0d+0) * ff00 &
262    & - (1.0d+0 / 4.0d+0) *(ferr+fell)
263        uhat( 2 ) = &
264    & + (1.0d+0 / 2.0d+0) *(ferr-fell)
265        uhat( 3 ) = &
266    & - (3.0d+0 / 2.0d+0) * ff00 &
267    & + (3.0d+0 / 4.0d+0) *(ferr+fell)
268   
269    !-------------------------------- "mono" slope-limiter !
270       
271        if((ffrr - ff00) * &
272    &      (ff00 - ffll) .lt. 0.d+0) then
273
274    !----------------------------------- "flatten" extrema !
275   
276            mono = +1
277
278            lhat(1) = ff00
279            lhat(2) = 0.d0
280            lhat(3) = 0.d0
281             
282            return
283             
284        end if
285
286    !----------------------------------- limit edge values !
287   
288        if((ffll - fell) * &
289    &      (fell - ff00) .le. 0.d+0) then
290
291            mono = +1
292       
293            fell = ff00 - dfds(0)
294
295        end if
296
297        if((ffrr - ferr) * &
298    &      (ferr - ff00) .le. 0.d+0) then
299
300            mono = +1
301
302            ferr = ff00 + dfds(0)
303         
304        end if
305   
306    !----------------------------------- update ppm coeff. !
307
308        lhat( 1 ) = &
309    & + (3.0d+0 / 2.0d+0) * ff00 &
310    & - (1.0d+0 / 4.0d+0) *(ferr+fell)
311        lhat( 2 ) = &
312    & + (1.0d+0 / 2.0d+0) *(ferr-fell)
313        lhat( 3 ) = &
314    & - (3.0d+0 / 2.0d+0) * ff00 &
315    & + (3.0d+0 / 4.0d+0) *(ferr+fell)
316
317    !----------------------------------- limit cell values !
318   
319        if (abs(lhat(3)) .gt. &
320    &       abs(lhat(2))*.5d+0) then
321
322        turn = -0.5d+0 * lhat(2) &
323    &                  / lhat(3)
324
325        if ((turn .ge. -1.d+0)&
326    &  .and.(turn .le. +0.d+0)) then
327
328        mono =   +2
329
330    !--------------------------- push TURN onto lower edge !
331
332        ferr =   +3.0d+0  * ff00 &
333    &            -2.0d+0  * fell
334
335        lhat( 1 ) = &
336    & + (3.0d+0 / 2.0d+0) * ff00 &
337    & - (1.0d+0 / 4.0d+0) *(ferr+fell)
338        lhat( 2 ) = &
339    & + (1.0d+0 / 2.0d+0) *(ferr-fell)
340        lhat( 3 ) = &
341    & - (3.0d+0 / 2.0d+0) * ff00 &
342    & + (3.0d+0 / 4.0d+0) *(ferr+fell)
343
344        else &
345    &   if ((turn .gt. +0.d+0)&
346    &  .and.(turn .le. +1.d+0)) then
347
348        mono =   +2
349
350    !--------------------------- push TURN onto upper edge !
351   
352        fell =   +3.0d+0  * ff00 &
353    &            -2.0d+0  * ferr
354
355        lhat( 1 ) = &
356    & + (3.0d+0 / 2.0d+0) * ff00 &
357    & - (1.0d+0 / 4.0d+0) *(ferr+fell)
358        lhat( 2 ) = &
359    & + (1.0d+0 / 2.0d+0) *(ferr-fell)
360        lhat( 3 ) = &
361    & - (3.0d+0 / 2.0d+0) * ff00 &
362    & + (3.0d+0 / 4.0d+0) *(ferr+fell)
363   
364        end if
365     
366        end if
367   
368        return
369   
370    end subroutine
371
372
373
Note: See TracBrowser for help on using the repository browser.