Skip to content

Commit 0b9efd0

Browse files
authored
Merge pull request #1851 from danielpeter/devel
updates scattering perturbations (w/ white noise simplification)
2 parents ab73047 + cfbe0a2 commit 0b9efd0

2 files changed

Lines changed: 287 additions & 26 deletions

File tree

src/generate_databases/model_scattering.f90

Lines changed: 231 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ module model_scattering_par
4343
integer :: num_target_materials = 0
4444
logical :: USE_ALL_MATERIALS = .false.
4545

46+
! white noise (otherwise von Karman noise distribution)
47+
logical :: USE_WHITE_NOISE = .false.
48+
49+
! von Karman distribution
4650
! perturbation array (regular x/y/z grid)
4751
real(kind=CUSTOM_REAL), dimension(:,:,:),allocatable :: perturbation_grid
4852
integer :: pert_Nx,pert_Ny,pert_Nz
@@ -260,6 +264,7 @@ subroutine setup_grid()
260264
implicit none
261265
real(kind=CUSTOM_REAL) :: x_min,x_min_all,y_min,y_min_all,z_min,z_min_all, &
262266
x_max,x_max_all,y_max,y_max_all,z_max,z_max_all
267+
real(kind=CUSTOM_REAL) :: x_min_elem,y_min_elem,z_min_elem,x_max_elem,y_max_elem,z_max_elem
263268
real(kind=CUSTOM_REAL) :: dim_x,dim_y,dim_z,dim_max
264269
real(kind=CUSTOM_REAL) :: elemsize_min,elemsize_max,elemsize_min_slice,elemsize_min_norm
265270
integer :: ispec,imaterial_id
@@ -268,14 +273,47 @@ subroutine setup_grid()
268273
if (num_target_materials == 0) return
269274

270275
! get mesh properties
271-
! Calculation of whole computational domain
272-
x_min = minval(xstore(:))
273-
x_max = maxval(xstore(:))
274-
y_min = minval(ystore(:))
275-
y_max = maxval(ystore(:))
276-
z_min = minval(zstore(:))
277-
z_max = maxval(zstore(:))
276+
if (USE_ALL_MATERIALS) then
277+
! Calculation of whole computational domain
278+
x_min = minval(xstore(:))
279+
x_max = maxval(xstore(:))
280+
y_min = minval(ystore(:))
281+
y_max = maxval(ystore(:))
282+
z_min = minval(zstore(:))
283+
z_max = maxval(zstore(:))
284+
else
285+
! only domains of target materials
286+
x_min = HUGEVAL
287+
y_min = HUGEVAL
288+
z_min = HUGEVAL
289+
290+
x_max = - HUGEVAL
291+
y_max = - HUGEVAL
292+
z_max = - HUGEVAL
293+
294+
do ispec = 1,NSPEC_AB
295+
! material id: index 1 has associated material number
296+
imaterial_id = mat_ext_mesh(1,ispec)
297+
298+
! check only elements for target materials (target id 0 means to apply to all materials)
299+
if (any(target_material_ids(:) == imaterial_id)) then
300+
! determine min/max extent of element
301+
call get_elem_minmax_xyz(x_min_elem,x_max_elem,y_min_elem,y_max_elem,z_min_elem,z_max_elem, &
302+
ispec,NSPEC_AB,NGLOB_AB,ibool,xstore,ystore,zstore)
303+
304+
! domain min/max
305+
x_min = min(x_min,x_min_elem)
306+
y_min = min(y_min,y_min_elem)
307+
z_min = min(z_min,z_min_elem)
308+
309+
x_max = max(x_max,x_max_elem)
310+
y_max = max(y_max,y_max_elem)
311+
z_max = max(z_max,z_max_elem)
312+
endif
313+
enddo
314+
endif
278315

316+
! determine min/max on all processes
279317
x_min_all = HUGEVAL
280318
y_min_all = HUGEVAL
281319
z_min_all = HUGEVAL
@@ -297,6 +335,10 @@ subroutine setup_grid()
297335
dim_y = y_max_all - y_min_all
298336
dim_z = z_max_all - z_min_all
299337

338+
if (dim_x < 0.0_CUSTOM_REAL) dim_x = 0.0_CUSTOM_REAL
339+
if (dim_y < 0.0_CUSTOM_REAL) dim_y = 0.0_CUSTOM_REAL
340+
if (dim_z < 0.0_CUSTOM_REAL) dim_z = 0.0_CUSTOM_REAL
341+
300342
! maximum mesh length
301343
dim_max = max(dim_x,dim_y,dim_z)
302344

@@ -321,6 +363,23 @@ subroutine setup_grid()
321363
call flush_IMAIN()
322364
endif
323365

366+
! check if domain volume found, otherwise target material ids won't match any in the mesh
367+
if (dim_x == 0.0_CUSTOM_REAL .or. dim_y == 0.0_CUSTOM_REAL .or. dim_z == 0.0_CUSTOM_REAL) then
368+
! user info
369+
if (myrank == 0) then
370+
write(IMAIN,*) ' no valid domain found (target material ids not found in mesh)'
371+
write(IMAIN,*) ' no perturbations will be applied...'
372+
write(IMAIN,*)
373+
call flush_IMAIN()
374+
endif
375+
! set zero targets
376+
num_target_materials = 0
377+
! all done
378+
return
379+
endif
380+
381+
! determine cell size for FFT grid
382+
!
324383
! get minimum element size
325384
elemsize_min_slice = HUGEVAL
326385
do ispec = 1, NSPEC_AB
@@ -466,9 +525,6 @@ subroutine generate_perturbations()
466525
integer :: num_seed
467526
integer,dimension(:),allocatable :: myseed
468527

469-
! debug output
470-
character(len=MAX_STRING_LEN) :: name
471-
472528
! external function
473529
real,external :: psd_vonKarman_3D
474530

@@ -479,6 +535,91 @@ subroutine generate_perturbations()
479535
! checks if anything to do
480536
if (num_target_materials == 0) return
481537

538+
! white noise
539+
! in case correlation length is smaller than GLL point distance, we use white noise
540+
!
541+
! correlation length
542+
! such that k * a ~ 1 (for correlation factor == 1)
543+
! a_corr = real(grid_lambda_min / (2.d0 * PI) * SCATTERING_CORRELATION,kind=CUSTOM_REAL)
544+
!
545+
! therefore
546+
! grid_lambda_min / (2.d0 * PI) * SCATTERING_CORRELATION < elemsize_min_norm / (NGLLX-1)
547+
! using the estimates for grid_lambda_min = ( elemsize_min_norm / (NGLLX-1) * 5), this is equal to
548+
! 5 / (2.d0 * PI) * SCATTERING_CORRELATION < 1
549+
! and
550+
! SCATTERING_CORRELATION < 1 / 5 * 2 * PI ~ 1.25
551+
! let's use white noise for factors < 1
552+
if (SCATTERING_CORRELATION < 1.0d0) then
553+
! set flag
554+
USE_WHITE_NOISE = .true.
555+
556+
! user output
557+
if (myrank == 0) then
558+
write(IMAIN,*) ' perturbation distribution : ','white noise (correlation factor < 1.0)'
559+
write(IMAIN,*) ' perturbation correlation factor : ',sngl(SCATTERING_CORRELATION)
560+
write(IMAIN,*) ' perturbation maximum amplitude : ',sngl(SCATTERING_STRENGTH)
561+
write(IMAIN,*)
562+
call flush_IMAIN()
563+
endif
564+
565+
! no need for FFTs, just random number generation
566+
!
567+
! initializes random number generator
568+
! seed with fixed value to make successive runs repeatable
569+
call random_seed(size=num_seed)
570+
allocate(myseed(num_seed))
571+
myseed(1:num_seed) = 12345
572+
call random_seed(put=myseed)
573+
574+
! visualization output (for debugging)
575+
if (SAVE_MESH_FILES .and. myrank == 0) then
576+
! file output of perturbation grid
577+
!
578+
! note: this perturbation grid is not actually used and allocated for white noise perturbations.
579+
! the file output here is meant for debugging and visualization.
580+
581+
! determines grid dimensions
582+
! next power of 2 for FFT
583+
npower_of_2 = int(log2(grid_length / grid_cell_size)) + 1
584+
N = 2**npower_of_2
585+
! limits minimum/maximum number of points for FFT
586+
!if (N < 1024) N = 1024 ! number of minimum points along x-direction (power of 2 for fft) 2**(10)
587+
!if (N < 512) N = 512 ! number of minimum points along x-direction (power of 2 for fft) 2**(9)
588+
if (N < 256) N = 256 ! number of minimum points along x-direction (power of 2 for fft) 2**(8)
589+
!if (N > 8192) N = 8192 ! number of maximum points along x-direction (power of 2 for fft) 2**(13)
590+
!if (N > 4096) N = 4096 ! number of maximum points along x-direction (power of 2 for fft) 2**(12)
591+
if (N > 2048) N = 2048 ! number of minimum points along x-direction (power of 2 for fft) 2**(11)
592+
! power of 2
593+
npower_of_2 = ceiling(log2(real(N)))
594+
! for mesh interpolations (uses double precision values)
595+
grid_dx = grid_length / (N-1) ! grid space increment, dx == dy == dz
596+
! for perturbation grid dimension
597+
pert_Nx = int(grid_dim_x / grid_normalization_factor / grid_dx) + 1
598+
pert_Ny = int(grid_dim_y / grid_normalization_factor / grid_dx) + 1
599+
pert_Nz = int(grid_dim_z / grid_normalization_factor / grid_dx) + 1
600+
! make sure perturbation grid is not bigger than wavenumber distribution array
601+
if (pert_Nx > N) pert_Nx = N
602+
if (pert_Ny > N) pert_Ny = N
603+
if (pert_Nz > N) pert_Nz = N
604+
605+
! user output
606+
if (myrank == 0) then
607+
write(IMAIN,*) ' grid spacing : dx = ',sngl(grid_dx * grid_normalization_factor),'(m)'
608+
write(IMAIN,*) ' perturbations: grid Nx/Ny/Nz = ',pert_Nx,'/',pert_Ny,'/',pert_Nz
609+
write(IMAIN,*)
610+
call flush_IMAIN()
611+
endif
612+
613+
! output VTU file for visual inspection
614+
call plot_grid_data()
615+
endif
616+
617+
! all done
618+
return
619+
endif
620+
621+
! from here on, we generate noise with von Karman distribution
622+
482623
! user output
483624
if (myrank == 0) then
484625
write(IMAIN,*) ' perturbation distribution : ','von Karman'
@@ -528,10 +669,10 @@ subroutine generate_perturbations()
528669
if (myrank == 0) then
529670
write(IMAIN,*) ' FFT using number of grid points : N = ',N
530671
write(IMAIN,*) ' FFT using power of 2 : npower_of_2 = ',npower_of_2
531-
write(IMAIN,*) ' grid spacing : dx = ',sngl(grid_dx * grid_normalization_factor),'(m)'
532672
! memory required
533673
mb_size = dble(N) * dble(N) * dble(N) * dble(CUSTOM_REAL) / 1024.d0 / 1024.d0
534-
write(IMAIN,*) ' grid memory size : ',sngl(mb_size),'MB'
674+
write(IMAIN,*) ' FFT using memory size : ',sngl(mb_size),'MB'
675+
write(IMAIN,*) ' grid spacing : dx = ',sngl(grid_dx * grid_normalization_factor),'(m)'
535676
write(IMAIN,*)
536677
call flush_IMAIN()
537678
endif
@@ -793,8 +934,7 @@ subroutine generate_perturbations()
793934
! visualization output
794935
if (SAVE_MESH_FILES .and. myrank == 0) then
795936
! output VTU file for visual inspection
796-
name = 'perturbation_grid'
797-
call plot_grid_data(perturbation_grid,pert_Nx,pert_Ny,pert_Nz,name)
937+
call plot_grid_data()
798938
endif
799939

800940
end subroutine generate_perturbations
@@ -853,17 +993,44 @@ end subroutine get_grid_average_max
853993
!-------------------------------------------------------------------------------------------------
854994
!
855995

856-
subroutine plot_grid_data(array,Nx,Ny,Nz,name)
996+
function get_random_perturbation_value() result(pert_val)
857997

858-
use constants, only: myrank,IMAIN,CUSTOM_REAL,MAX_STRING_LEN
859-
use model_scattering_par, only: grid_origin_x,grid_origin_y,grid_origin_z,grid_dx,grid_normalization_factor
998+
use constants, only: CUSTOM_REAL
999+
use shared_parameters, only: SCATTERING_STRENGTH
8601000

8611001
implicit none
1002+
real(kind=CUSTOM_REAL) :: pert_val
1003+
real(kind=CUSTOM_REAL) :: rand_val
8621004

863-
integer, intent(in) :: Nx,Ny,Nz
864-
real(kind=CUSTOM_REAL),dimension(Nx,Ny,Nz),intent(in) :: array
865-
character(len=MAX_STRING_LEN),intent(in) :: name
1005+
! random value between [0,1]
1006+
call random_number(rand_val)
1007+
1008+
! white noise between [-1,1]
1009+
pert_val = 2.0_CUSTOM_REAL * rand_val - 1.0_CUSTOM_REAL
1010+
1011+
! scale to target strength
1012+
pert_val = pert_val * real(SCATTERING_STRENGTH,kind=CUSTOM_REAL)
1013+
1014+
end function get_random_perturbation_value
1015+
1016+
!
1017+
!-------------------------------------------------------------------------------------------------
1018+
!
1019+
1020+
subroutine plot_grid_data()
1021+
1022+
use constants, only: myrank,IMAIN,CUSTOM_REAL,MAX_STRING_LEN
1023+
1024+
use model_scattering_par, only: grid_origin_x,grid_origin_y,grid_origin_z, &
1025+
grid_dx,grid_normalization_factor,USE_WHITE_NOISE
1026+
1027+
use model_scattering_par, only: &
1028+
array => perturbation_grid, &
1029+
Nx => pert_Nx, &
1030+
Ny => pert_Ny, &
1031+
Nz => pert_Nz
8661032

1033+
implicit none
8671034
! local parameters
8681035
integer :: ne,np,ixyz,n1,n2,n3,n4,n5,n6,n7,n8
8691036
integer :: i,j,k,ier
@@ -875,6 +1042,12 @@ subroutine plot_grid_data(array,Nx,Ny,Nz,name)
8751042
integer,dimension(:,:),allocatable :: total_dat_con
8761043
character(len=MAX_STRING_LEN) :: mesh_file,var_name
8771044

1045+
! for white noise
1046+
real(kind=CUSTOM_REAL),external :: get_random_perturbation_value
1047+
1048+
! file output
1049+
character(len=MAX_STRING_LEN) :: name
1050+
8781051
! regular grid
8791052
np = Nx * Ny * Nz ! total number of points
8801053
ne = (Nx-1) * (Ny-1) * (Nz-1) ! total number of elements
@@ -906,12 +1079,17 @@ subroutine plot_grid_data(array,Nx,Ny,Nz,name)
9061079
if (np /= ixyz) stop 'Invalid grid point'
9071080

9081081
! array value
909-
total_dat(np) = array(i,j,k)
1082+
if (USE_WHITE_NOISE) then
1083+
! random perturbation value
1084+
total_dat(np) = get_random_perturbation_value()
1085+
else
1086+
total_dat(np) = array(i,j,k)
1087+
endif
9101088

9111089
! grid point position [-L/2,L/2]
912-
total_dat_xyz(1,np) = grid_origin_x + (i-1) * cell_size
913-
total_dat_xyz(2,np) = grid_origin_y + (j-1) * cell_size
914-
total_dat_xyz(3,np) = grid_origin_z + (k-1) * cell_size
1090+
total_dat_xyz(1,np) = real(grid_origin_x + (i-1) * cell_size,kind=CUSTOM_REAL)
1091+
total_dat_xyz(2,np) = real(grid_origin_y + (j-1) * cell_size,kind=CUSTOM_REAL)
1092+
total_dat_xyz(3,np) = real(grid_origin_z + (k-1) * cell_size,kind=CUSTOM_REAL)
9151093
enddo
9161094
enddo
9171095
enddo
@@ -950,6 +1128,7 @@ subroutine plot_grid_data(array,Nx,Ny,Nz,name)
9501128
enddo
9511129

9521130
! VTU binary format
1131+
name = 'perturbation_grid'
9531132
mesh_file = 'OUTPUT_FILES/' // trim(name) // '.vtu'
9541133
var_name = 'val'
9551134
call write_VTU_movie_data_binary(ne,np,total_dat_xyz,total_dat_con,total_dat,mesh_file,var_name)
@@ -992,20 +1171,33 @@ subroutine model_scattering_add_perturbations(imaterial_id,xmesh,ymesh,zmesh, &
9921171
logical, intent(in) :: ANISOTROPY
9931172

9941173
! local parameters
995-
double precision :: pert_val,scaling
1174+
double precision :: pert_val
9961175
integer :: ix,iy,iz,Nx,Ny,Nz
9971176
! positioning
9981177
double precision :: offset_x,offset_y,offset_z
9991178
double precision :: spac_x,spac_y,spac_z
10001179
double precision :: gamma_interp_x,gamma_interp_y,gamma_interp_z
10011180
double precision :: val1,val2,val3,val4,val5,val6,val7,val8
10021181

1182+
! for white noise
1183+
real(kind=CUSTOM_REAL),external :: get_random_perturbation_value
1184+
10031185
! checks if anything to do
10041186
if (num_target_materials == 0) return
10051187

10061188
! check if we apply perturbation (to target materials only; target id 0 means to apply to all materials)
10071189
if (.not. (any(target_material_ids(:) == imaterial_id) .or. USE_ALL_MATERIALS)) return
10081190

1191+
! white noise
1192+
if (USE_WHITE_NOISE) then
1193+
! get random perturbation
1194+
pert_val = get_random_perturbation_value()
1195+
! apply perturbation to model parameters
1196+
call apply_perturbation(pert_val)
1197+
! all done
1198+
return
1199+
endif
1200+
10091201
! determine spacing and cell for linear interpolation
10101202
offset_x = (xmesh - grid_origin_x) / grid_normalization_factor ! position offset in mesh (normalized)
10111203
offset_y = (ymesh - grid_origin_y) / grid_normalization_factor
@@ -1098,8 +1290,19 @@ subroutine model_scattering_add_perturbations(imaterial_id,xmesh,ymesh,zmesh, &
10981290
! print *,'debug: loc ',sngl(xmesh),sngl(ymesh),sngl(zmesh),'ixyz',ix,iy,iz, &
10991291
! 'perturbation ',pert_val,'corners',val1,val2,val3,val4,val5,val6,val7,val8
11001292

1293+
! apply perturbation to model parameters
1294+
call apply_perturbation(pert_val)
1295+
1296+
contains
1297+
1298+
subroutine apply_perturbation(pert_val)
1299+
implicit none
1300+
double precision, intent(in) :: pert_val
1301+
! local parameters
1302+
real(kind=CUSTOM_REAL) :: scaling
1303+
11011304
! adds perturbation
1102-
scaling = 1.d0 + pert_val
1305+
scaling = real(1.d0 + pert_val,kind=CUSTOM_REAL)
11031306

11041307
! apply perturbation to model
11051308
! define new elastic parameters in the model
@@ -1131,4 +1334,6 @@ subroutine model_scattering_add_perturbations(imaterial_id,xmesh,ymesh,zmesh, &
11311334
c66 = scaling * c66
11321335
endif
11331336

1337+
end subroutine apply_perturbation
1338+
11341339
end subroutine model_scattering_add_perturbations

0 commit comments

Comments
 (0)