forked from pencil-code/pencil-code
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdetonate.f90
422 lines (420 loc) · 12.6 KB
/
detonate.f90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
! $Id$
!
! This module searches for gravitationally collapsing sites and
! detonates them.
!
!** AUTOMATIC CPARAM.INC GENERATION ****************************
! Declare (for generation of cparam.inc) the number of f array
! variables and auxiliary variables added by this module
!
! CPARAM logical, parameter :: ldetonate = .true.
!
! MAUX CONTRIBUTION 1
! COMMUNICATED AUXILIARIES 1
!
!***************************************************************
module Detonate
!
use Cdata
use Messages, only: svn_id, fatal_error, warning
!
implicit none
!
include 'detonate.h'
!
! Runtime parameters
!
character(len=labellen) :: det_scale = 'linear' ! Scaling of the energy input at detonation with density
integer :: det_njeans = 4 ! Minimum number of cells per Jeans length for stability
integer :: det_nsmooth = 1 ! Number of times to smooth the point detonation
integer :: det_radius = 2 ! Radius of a local region in number of cells
real :: det_factor = 1.0 ! Scale factor of the energy input
!
namelist /detonate_run_pars/ det_scale, det_njeans, det_nsmooth, det_radius, det_factor
!
! Diagnostic variables
!
integer :: idiag_detn = 0 ! DIAG_DOC: Number of detonated sites (summed over time steps between adjacent outputs)
integer :: idiag_dettot = 0 ! DIAG_DOC: Total energy input (summed over time steps between adjacent outputs)
!
! Module variables
!
logical, dimension(-nghost:nghost,-nghost:nghost,-nghost:nghost) :: mask_sphere = .false.
integer :: nxg = 0, nyg = 0, nzg = 0
integer :: power = 0
real :: deth0 = 0.0
real :: jeans = 0.0
real :: tgentle = 0.0
!
contains
!***********************************************************************
subroutine register_detonate
!
! Set up indices for variables.
!
! 06-feb-14/ccyang: coded
!
use FArrayManager, only: farray_register_auxiliary
!
if (lroot) call svn_id("$Id$")
!
call farray_register_auxiliary('detonate', idet, communicated=.true.)
!
endsubroutine register_detonate
!***********************************************************************
subroutine initialize_detonate(f)
!
! Initializes module specific variables for later use.
!
! 14-feb-14/ccyang: coded
!
use General, only: keep_compiler_quiet
use EquationOfState, only: cs20, get_gamma_etc
use SharedVariables, only: get_shared_variable
!
real, dimension(mx,my,mz,mfarray), intent(in) :: f
!
real, pointer :: tsg
integer :: istat
integer :: i, j, k
real :: volume, gamma, gamma_m1
!
call keep_compiler_quiet(f)
!
! This module currently only works with thermal_energy.
!
if (.not.lthermal_energy) call fatal_error('initialize_detonate','currently only works with thermal_energy')
!
! If called by start.f90: nothing to do.
!
if (lstart) return
call get_gamma_etc(gamma)
gamma_m1=gamma-1.
!
! Calculate the conversion factor between density and energy for Jeans
! stability.
!
if (nzgrid /= 1) then
call fatal_error('initialize_detonate', '3D Jeans stability criterion is under construction')
else
jeans = real(det_njeans) * G_Newton * dxmax / (gamma * gamma_m1)
endif
!
! Make a spherical mask.
!
nxg = merge(nghost, 0, nxgrid > 1)
nyg = merge(nghost, 0, nygrid > 1)
nzg = merge(nghost, 0, nzgrid > 1)
forall (i=-nxg:nxg, j=-nyg:nyg, k=-nzg:nzg, i*i+j*j+k*k <= det_radius**2) mask_sphere(i,j,k) = .true.
!
! Check the scaling of the energy input with density.
!
scale: select case (det_scale)
!
case ('linear') scale
! Calculate the volume of the mask.
ndim: select case (count((/ nxgrid > 1, nygrid > 1, nzgrid > 1 /)))
case (0) ndim
volume = 0.0
case (1) ndim
volume = real(2 * det_radius)
case (2) ndim
volume = pi * real(det_radius**2)
case (3) ndim
volume = pi / 3.0 * real(4 * det_radius**3)
endselect ndim
power = 1
deth0 = det_factor * volume * cs20
!
case ('quadratic', 'binding') scale
power = 2
if (nzgrid > 1) then
call fatal_error('initialize_detonate','quadratic scaling for 3D is under construction')
else
deth0 = det_factor * (8.0 * pi / 3.0) * G_Newton * dxmax * det_radius**3
endif
!
case default scale
call fatal_error('initialize_detonate','no such det_scale: '//trim(det_scale))
endselect scale
!
! Get tselfgrav_gentle.
!
if (lselfgravity) then
call get_shared_variable('tselfgrav_gentle', tsg)
tgentle = tsg
endif
!
endsubroutine initialize_detonate
!***********************************************************************
subroutine read_detonate_run_pars(iostat)
!
use File_io, only: parallel_unit
!
integer, intent(out) :: iostat
!
read(parallel_unit, NML=detonate_run_pars, IOSTAT=iostat)
!
endsubroutine read_detonate_run_pars
!***********************************************************************
subroutine write_detonate_run_pars(unit)
!
integer, intent(in) :: unit
!
write(unit, NML=detonate_run_pars)
!
endsubroutine write_detonate_run_pars
!***********************************************************************
subroutine rprint_detonate(lreset, lwrite)
!
! Reads and registers print parameters.
!
! 06-feb-14/ccyang: dummy
!
use Diagnostics, only: parse_name
use General, only: keep_compiler_quiet
!
logical, intent(in) :: lreset
logical, intent(in), optional :: lwrite
!
integer :: iname
!
! Reset diagnostic indices if requested.
!
reset: if (lreset) then
idiag_detn = 0
idiag_dettot = 0
endif reset
!
! Parse names in print.in.
!
diagnos: do iname = 1, nname
call parse_name(iname, cname(iname), cform(iname), 'detn', idiag_detn)
call parse_name(iname, cname(iname), cform(iname), 'dettot', idiag_dettot)
enddo diagnos
!
! lwrite should be phased out.
!
if (present(lwrite)) call keep_compiler_quiet(lwrite)
!
endsubroutine rprint_detonate
!***********************************************************************
subroutine detonate_before_boundary(f)
!
! Possibility to modify the f before boundary conmmunications.
!
! 14-feb-14/ccyang: coded
!
use Boundcond, only: zero_ghosts, update_ghosts
use Diagnostics, only: sum_mn_name
use Mpicomm, only: mpiallreduce_or, mpireduce_sum_int, mpireduce_sum
!
real, dimension(mx,my,mz,mfarray), intent(inout) :: f
!
logical, dimension(mx,my,mz) :: mask
logical :: flag
integer :: ndet
real :: esum
!
! Detonate only before one full time-step.
!
if (lfirst .and. .not. lpencil_check_at_work) then
!
! Initialize the detonation energy field to zero.
!
f(l1:l2,m1:m2,n1:n2,idet) = 0.0
!
! Check Jeans stability for each cell.
!
call zero_ghosts(f, ieth)
call update_ghosts(f, ieth)
call zero_ghosts(f, ilnrho)
call update_ghosts(f, ilnrho)
mask = jeans_unstable(exp(f(:,:,:,ilnrho)), f(:,:,:,ieth))
!
! Sift out collapsing sites.
!
if (any(mask)) call collapsing(f, mask)
!
! Detonate them.
!
call mpiallreduce_or(any(mask), flag)
if (flag) then
call set_detonations(f, mask)
if (ldiagnos) then
call sum_mn_name((/real(count(mask))/),idiag_detn,lplain=.true.)
call sum_mn_name((/total_energy(f)/),idiag_dettot,lplain=.true.)
endif
endif
!
endif
endsubroutine detonate_before_boundary
!***********************************************************************
!***********************************************************************
! LOCAL PROCEDURES GO BELOW HERE.
!***********************************************************************
!***********************************************************************
elemental logical function jeans_unstable(rho, eth)
!
! Returns true if a cell is considered Jeans unstable given its density
! and internal energy.
!
! 08-feb-14/ccyang: coded.
!
real, intent(in) :: rho, eth
!
real :: eth_min
!
! Find the minimum internal energy for Jeans stability.
!
if (nzgrid /= 1) then
! 3D run: rho is volume mass density
else
! 2D run: rho is surface mass density
eth_min = jeans * rho**2
endif
!
! Compare it with the actual energy.
!
jeans_unstable = eth <= eth_min
!
endfunction jeans_unstable
!***********************************************************************
subroutine collapsing(f, unstable)
!
! Searches for collapsing sites in Jeans unstable regions.
!
! 12-feb-14/ccyang: coded
!
real, dimension(mx,my,mz,mfarray), intent(in) :: f
logical, dimension(mx,my,mz), intent(inout) :: unstable
!
logical, dimension(mx,my,mz) :: work
integer, dimension(3) :: center
integer :: ll1, ll2, mm1, mm2, nn1, nn2
integer :: i, j, k
real :: divu
!
! Loop over each cell and check if it is a local maximum and converging.
!
work = .false.
center = (/ nxg + 1, nyg + 1, nzg + 1 /)
zscan: do k = n1, n2
nn1 = k - nzg
nn2 = k + nzg
yscan: do j = m1, m2
mm1 = j - nyg
mm2 = j + nyg
xscan: do i = l1, l2
ll1 = i - nxg
ll2 = i + nxg
localmax: if (all(unstable(ll1:ll2,mm1:mm2,nn1:nn2) .and. mask_sphere(-nxg:nxg,-nyg:nyg,-nzg:nzg) &
.eqv. mask_sphere(-nxg:nxg,-nyg:nyg,-nzg:nzg)) .and. &
all(maxloc(f(ll1:ll2,mm1:mm2,nn1:nn2,irho), &
mask=mask_sphere(-nxg:nxg,-nyg:nyg,-nzg:nzg)) == center)) then
divu = 0.0
if (nxgrid > 1) divu = divu + derivative(f(ll1:ll2,j,k,iux), dx_1(i))
if (nygrid > 1) divu = divu + derivative(f(i,mm1:mm2,k,iuy), dy_1(j))
if (nzgrid > 1) divu = divu + derivative(f(i,j,nn1:nn2,iuz), dz_1(k))
if (divu < 0.0) work(i,j,k) = .true.
endif localmax
enddo xscan
enddo yscan
enddo zscan
unstable = work
!
endsubroutine collapsing
!***********************************************************************
subroutine set_detonations(f, mask)
!
! Detonates cells specified by mask.
!
! 19-feb-14/ccyang: coded
!
use Boundcond, only: zero_ghosts, update_ghosts
use Sub, only: smooth
!
real, dimension(mx,my,mz,mfarray), intent(inout) :: f
logical, dimension(mx,my,mz), intent(in) :: mask
!
integer :: i
real :: deth
!
if (t < tgentle) then
deth = 0.5 * deth0 * (1.0 - cos(pi * t / tgentle))
else
deth = deth0
endif
!
! Put in point energy where mask is .true.
!
if (ldensity_nolog) then
where(mask(l1:l2,m1:m2,n1:n2)) f(l1:l2,m1:m2,n1:n2,idet) = deth * f(l1:l2,m1:m2,n1:n2,irho)**power
else
where(mask(l1:l2,m1:m2,n1:n2)) f(l1:l2,m1:m2,n1:n2,idet) = deth * exp(power * f(l1:l2,m1:m2,n1:n2,ilnrho))
endif
!
! Smooth it by det_nsmooth times.
!
rep: do i = 1, det_nsmooth
call zero_ghosts(f, idet)
call update_ghosts(f, idet)
call smooth(f, idet)
enddo rep
!
! Add it to the energy field.
!
f(l1:l2,m1:m2,n1:n2,ieth) = f(l1:l2,m1:m2,n1:n2,ieth) + f(l1:l2,m1:m2,n1:n2,idet)
!
endsubroutine set_detonations
!***********************************************************************
real function derivative(a, dx1)
!
! Returns the first derivative at the center of a seven-point data
! array.
!
! 19-jan-13/ccyang: coded.
!
real, dimension(-3:3), intent(in) :: a
real, intent(in) :: dx1
!
real, parameter :: sixtieth = 1.0 / 60.0
!
derivative = sixtieth * dx1 * ((a(3) - a(-3)) - 9.0 * (a(2) - a(-2)) + 45.0 * (a(1) - a(-1)))
!
endfunction derivative
!***********************************************************************
real function total_energy(f)
!
! Returns total energy input by detonation.
!
! 14-feb-14/ccyang: coded
!
real, dimension(mx,my,mz,mfarray), intent(inout) :: f
!
real, dimension(nx) :: dx
integer :: j, k
real :: dy, dz
!
! Initialization
!
total_energy = 0.0
if (nxgrid > 1) then
dx = xprim(l1:l2)
else
dx = 1.0
endif
!
! Integrate the det field.
!
zdir: do k = n1, n2
dz = merge(zprim(k), 1.0, nzgrid > 1)
ydir: do j = m1, m2
dy = merge(yprim(j), 1.0, nygrid > 1)
total_energy = total_energy + sum(dz * dy * dx * f(l1:l2,j,k,idet), mask=f(l1:l2,j,k,idet)>0.0)
enddo ydir
enddo zdir
!
endfunction total_energy
!***********************************************************************
endmodule Detonate