TreeMig Code
Loading...
Searching...
No Matches
DispersalKernel.f90
Go to the documentation of this file.
1! ==============================================================================
2!
3! Module : DispersalKernel.f90
4!
5! Remarks: contains the SUBROUTINEs + functions
6! CalculateAndStoreDispersalKernelOfSpecies (<GetSpc)
7! DispersalKernel (<CalculateAndStoreDispersalKernelOfSpecies)
8! DoubleKernel (<DispersalKernel )
9! SingleKernel (<DispersalKernel AND/OR <DoubleKernel)
10! (F) CenterToCenterValue (<SingleKernel)
11! (F) KernelValue (<CenterToCenterValue )
12! ==============================================================================
13! ********************************************
14
15! ==============================================================================
45! ==============================================================================
48
49 use all_par, only: spec, &
51
52 IMPLICIT NONE
53
54 ! Passed variables>--------------------------------------------------------------------------------
55 LOGICAL, INTENT(IN) :: doFFT ! dispersal with FFT or direct?
56 INTEGER, INTENT(IN) :: isp ! species index
57
58 ! Local variables>---------------------------------------------------------------------------------
59 INTEGER :: ii, jj
60
61 LOGICAL :: uniqueDispersalKernel
62 ! Here the SUBROUTINE starts>**********************************************************************
63
64 uniquedispersalkernel = .true.
65 !----- If same parameters already in other species, take that kernel and store it
66 do ii = 1, isp - 1
67 if ((spec(isp)%alfa1 == spec(ii)%alfa1) .AND. &
68 (spec(isp)%alfa2 == spec(ii)%alfa2) .AND. &
69 (spec(isp)%dispFac == spec(ii)%dispFac)) then ! kernel already exists
70 spec(isp)%rad = spec(ii)%rad
71 call allocatespeckernel(spec(isp)%rad, isp) ! allocate the array for the kernel
72!
73 !--- store the kernel values of already calculated kernel to the current kernel;
74 spec(isp)%kernel(:, :) = 0
75 spec(isp)%kernel = spec(ii)%kernel
76 uniquedispersalkernel = .false.
77 exit
78 end if ! same parameters already exist
79 end do !ii
80
81 if (readdispersalkernel) then ! if wished, the dispersal kernel is read in, +- never used
82 read (dispersalkernel_file%unit, *) spec(isp)%rad
83 call allocatespeckernel(spec(isp)%rad, isp)
84 do ii = -spec(isp)%rad, spec(isp)%rad
85 read (dispersalkernel_file%unit, *) (spec(isp)%kernel(ii, jj), jj=-spec(isp)%rad, spec(isp)%rad)
86 end do
87 else
88 !----- If these parameters appear first time, kernel has to be calculated
89 if (uniquedispersalkernel) then
90 kerneltype = 1
91 if (spec(isp)%dispFac < 1.0) kerneltype = 2
92 call dispersalkernel(isp)
93 end if ! if uniqueDispersalKernel
94
95 ! Write the kernel to "DispersalKernelNew_File", only for the first species
96 if (isp == 1) then
97 do ii = -spec(isp)%rad, spec(isp)%rad
98 do jj = -spec(isp)%rad, spec(isp)%rad
99 write (dispersalkernelnew_file%unit, '(F14.6,4I8,3F14.6)') &
100 cellsidelength, isp, spec(isp)%rad, ii, jj, cellsidelength*ii, &
101 cellsidelength*jj, spec(isp)%kernel(ii, jj)
102 end do
103 end do
104 end if ! isp == 1
105 end if ! readDispersalKernel
106 if (dofft) then ! if FFT is switched on
107 CALL setdimsforfft(isp) ! the area dimensions for the FFT convolution are determined and stored
108 CALL allocatespectransformedkernel( isp ) ! the area for the transformed kernel is allocated
109 ! the Fourier Transform of the kernel is calculated and stored to spec(i)%kernel_FT
111 end if !doFFT
113
114
115! ==============================================================================
141! ==============================================================================
142SUBROUTINE dispersalkernel(isp)
143 ! CALL modules for TYPE definitions and +- fixed variables>---------------------------------------------------------------
145
146 IMPLICIT NONE
147
148 ! <Passed variables>--------------------------------------------------------------------------------
149 INTEGER, INTENT(in) :: isp ! species index
150
151 ! <Local variables>---------------------------------------------------------------------------------
152 INTEGER :: radi
153 REAL :: alfa
154
155 ! <Here the SUBROUTINE starts>**********************************************************************
156 if (.NOT. dispersaldifferent) then
158 elseif (kerneltype == 1) then
159 alfa = spec(isp)%alfa1
160 call singlekernel(alfa, cellsidelength, epskernel, radi)
161 elseif (kerneltype == 2) then
162 call doublekernel(spec(isp)%dispFac, spec(isp)%alfa1, spec(isp)%alfa2, cellsidelength, epskernel, radi)
163 end if
164 call allocatespeckernel(radi, isp)
165 spec(isp)%kernel = kernel
166 deallocate (kernel)
167 spec(isp)%rad = radi
168end SUBROUTINE dispersalkernel
169
170! ==============================================================================
197! ==============================================================================
198SUBROUTINE singlekernel(alpha, cellSideLength, epsKernel, rad_c)
199 Use all_par, Only: kernel, kernelfine
200 IMPLICIT NONE
201 ! <Passed variables>--------------------------------------------------------------------------------
202
203 REAL, INTENT(in) :: alpha, cellSideLength, epsKernel
204 INTEGER, INTENT(out) :: rad_c ! > radius of kernel of actual discretization in grid cell number
205 ! <Local variables>---------------------------------------------------------------------------------
206 INTEGER :: latwin, latwingr, latwinstart, latwinend, & ! > index of relative window latitude
207 lonwin, lonwingr, lonwinstart, lonwinend, & ! > index of relative window longitude
208 icellSideLengthFak, radMax! >, irad ! > for switching between min. and actual discretization
209 REAL :: krnlsm, radFac,rad_m, &
210 cellSideLengthMin, &
211 CenterToCenterValue
212
213 ! <Here the SUBROUTINE starts>**********************************************************************
214 ! ---- determine radius of actual kernel so that kernel reaches only to the value epskernel
215 ! kernel (x) = (1/alpha)* exp(-x/alpha) ==> epskernel = (1/alpha) * exp(- x_epskernel / alpha)
216 ! ==> epskernel * alpha = exp(- x_epskernel / alpha) ==> ln(epskernel * alpha)= - x_epskernel / alpha
217 ! ==> x_epskernel = - alpha * ln(epskernel * alpha)
218 radfac = min(20., -log(epskernel)) ! > at which distance (in m) has the kernel function decreased down to the epskernel value?
219 rad_m = alpha * radfac ! > radius of actual discretization (in meters)
220 rad_c = int((rad_m)/cellsidelength + 1.0) ! > radius of actual discretization (in grid cell number)
221
222 ! ----- Determine settings of fine discretization kernel
223 cellsidelengthmin = 1000.0/32.0 ! > side length of totally finest discretization, about 0.0001 of kernel cut off, ...
224 cellsidelengthmin = min(cellsidelengthmin, cellsidelength) ! > ... not larger than actual side length
225 icellsidelengthfak = cellsidelength/cellsidelengthmin ! > ratio actual to finest discretization
226 radmax = rad_m / cellsidelengthmin + 1 ! > radius of finest discretization in number of grid cells (The 20 is sufficient at small gridsizes)
227 ! ---- allocate and initialize the fine and actual kernel
228 call allocatekernel(radmax, "kernelFine")
229 call allocatekernel(rad_c, "kernel ")
230
231 kernel = 0.0
232 kernelfine = 0.0
233 ! ----- fine discretization kernel, calculate one quadrant
234 kernellat: do latwin = 0, radmax
235 kernellon: do lonwin = 0, radmax
236 kernelfine(latwin, lonwin) = centertocentervalue(alpha, cellsidelengthmin, latwin, lonwin) ! > this calculates the values of the kernel
237 end do kernellon
238 end do kernellat
239 ! ----- fine discretization kernel, copy this one quadrant to other quadrants
240 kernellat2: do latwin = -radmax, radmax
241 kernellon2: do lonwin = -radmax, radmax
242 if ((latwin < 0) .or. (lonwin < 0)) &
243 kernelfine(latwin, lonwin) = kernelfine(abs(latwin), abs(lonwin))
244 end do kernellon2
245 end do kernellat2
246 ! ----- The kernel on the coarse (i.e. actual) grid is calculated by
247 ! ----- summing over the kernel values in all fine-grid cells in each coarse-grid cell
248 kernellat1: do latwingr = -rad_c, rad_c
249 kernellon1: do lonwingr = -rad_c, rad_c
250 latwinstart = max(min(radmax, latwingr*icellsidelengthfak - icellsidelengthfak/2), -radmax)
251 latwinend = max(min(radmax, latwingr*icellsidelengthfak + icellsidelengthfak/2), -radmax)
252 lonwinstart = max(min(radmax, lonwingr*icellsidelengthfak - icellsidelengthfak/2), -radmax)
253 lonwinend = max(min(radmax, lonwingr*icellsidelengthfak + icellsidelengthfak/2), -radmax)
254 do latwin = latwinstart, latwinend
255 do lonwin = lonwinstart, lonwinend
256 kernel(latwingr, lonwingr) = kernel(latwingr, lonwingr) + kernelfine(latwin, lonwin)/2
257 end do ! >----- lonwin
258 end do ! >----- latwin
259 end do kernellon1
260 end do kernellat1
261 deallocate (kernelfine)
262 ! ----- Normalize kernel, sum = 1
263 krnlsm = 0
264 do latwingr = -rad_c, rad_c
265 do lonwingr = -rad_c, rad_c
266 krnlsm = krnlsm + kernel(latwingr, lonwingr)
267 end do
268 end do
269 kernel = kernel/krnlsm
270end SUBROUTINE singlekernel
271
272! ==============================================================================
292! ==============================================================================
293SUBROUTINE doublekernel(dispFac, alfa1, alfa2, cellSideLength, epsKernel, rad_c)
294 Use all_par, Only: kernel, kernel1, kernel2
295 ! <CALL modules for TYPE definitions and +- fixed variables>---------------------------------------------------------------
296 IMPLICIT NONE
297
298 REAL, INTENT(in) :: alfa1, alfa2, dispFac, cellSideLength, epsKernel
299 ! REAL, allocatable, INTENT(out) :: kernel
300 INTEGER, INTENT(out) :: rad_c
301 ! <Local variables>---------------------------------------------------------------------------------
302 INTEGER :: rad1, rad2
303 ! <Here the SUBROUTINE starts >**********************************************************************
304 if ((1.0 - dispfac) .gt. 0.0) then
305 ! > calculate and store wider kernel
306 call singlekernel(alfa2, cellsidelength, epskernel, rad2)
307 call allocatekernel(rad2, "kernel2 ")
309 ! > calculate and store narrower kernel
310 call singlekernel(alfa1, cellsidelength, epskernel, rad1)! > narrower kernel
311 call allocatekernel(rad1, "kernel1 ") ! > narrower kernel
313 ! > Put together the double kernel: dispfac * narrower kernel + ( 1-dispfac )* wider kernel
314 rad_c = rad2
315 call allocatekernel(rad_c, "kernel ")
316 kernel = (1.-dispfac)*kernel2 ! > the wider kernel
317 kernel(-rad1:rad1, -rad1:rad1) = kernel(-rad1:rad1, -rad1:rad1) + dispfac*kernel1 ! > ...plus the smaller kernel
318 deallocate (kernel1)
319 deallocate (kernel2)
320 else
321 call singlekernel(alfa1, cellsidelength, epskernel, rad_c)
322 end if
323end SUBROUTINE doublekernel
324
325! ==============================================================================
340! ==============================================================================
341
342REAL function centertocentervalue(alpha, cellSideLength, latwin, lonwin)
343IMPLICIT NONE
344INTEGER, INTENT(in) :: latwin, lonwin
345REAL, INTENT(in) :: alpha, cellsidelength
346REAL :: dist, & !> distance from source to target
348dist = sqrt((real(latwin)**2) + (real(lonwin)**2))*cellsidelength
349centertocentervalue = kernelvalue(dist, alpha)
350end function centertocentervalue
351
352! ==============================================================================
363! ==============================================================================
364REAL function kernelvalue(dist, alpha)
365IMPLICIT NONE
366REAL, INTENT(in) :: dist, alpha
367kernelvalue = exp(-dist/alpha) ! should be set to zero if smaller than epskernel
368end function kernelvalue
369
subroutine allocatespeckernel(rad, ispec)
AllocateSpecKernel.
subroutine allocatespectransformedkernel(ispec)
AllocateSpecTransformedKernel.
subroutine allocatekernel(rad, vartxt)
AllocateKernel.
real function centertocentervalue(alpha, cellsidelength, latwin, lonwin)
CenterToCenterValue
subroutine calculateandstoredispersalkernelofspecies(isp, dofft)
CalculateAndStoreDispersalKernelOfSpecies
subroutine dispersalkernel(isp)
DispersalKernel
subroutine doublekernel(dispfac, alfa1, alfa2, cellsidelength, epskernel, rad_c)
DoubleKernel
subroutine singlekernel(alpha, cellsidelength, epskernel, rad_c)
SingleKernel
real function kernelvalue(dist, alpha)
KernelValue
subroutine setdimsforfft(ispec)
SetDimsForFFT
subroutine calculatekerneltransformation(isp)
CalculateKernelTransformation.
integer kerneltype
Definition All_par.f90:66
real cellsidelength
Definition All_par.f90:63
real, dimension(:, :), allocatable kernel2
Definition All_par.f90:154
type(specproperties), dimension(maxspc) spec
Definition All_par.f90:345
logical dispersaldifferent
Definition All_par.f90:72
type(wroutp) true
Definition All_par.f90:143
real, dimension(:, :), allocatable kernel1
Definition All_par.f90:154
real, dimension(:, :), allocatable kernel
Definition All_par.f90:62
real epskernel
Definition All_par.f90:64
real, dimension(:, :), allocatable kernelfine
Definition All_par.f90:154
type(wroutp) false
Definition All_par.f90:143
real alpha_all
Definition All_par.f90:62
integer, parameter max
Definition All_par.f90:98
logical readdispersalkernel
Definition All_par.f90:76
type(file) dispersalkernelnew_file
type(file) dispersalkernel_file