@@ -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