Afivo  0.3
m_gaussians.f90
1 !> This module can be used to construct solutions consisting of one or more
2 !> Gaussians.
3 module m_gaussians
4 
5  implicit none
6  private
7 
8  integer, parameter :: dp = kind(0.0d0)
9 
10  !> A type to store a collection of gaussians in
11  type gauss_t
12  integer :: n_gauss !< Number of gaussians
13  integer :: n_dim !< Dimensionality
14  real(dp), allocatable :: ampl(:) !< Amplitudes
15  real(dp), allocatable :: sigma(:) !< Widths
16  real(dp), allocatable :: r0(:,:) !< Centers
17  end type gauss_t
18 
19  public :: gauss_t
20  public :: gauss_init
21  public :: gauss_value
22  public :: gauss_gradient
23  public :: gauss_laplacian
24  public :: gauss_laplacian_cyl
25  public :: gauss_4th
26 
27 contains
28 
29  !> Initialize a structure with parameters
30  subroutine gauss_init(gs, amplitudes, sigmas, locations)
31  type(gauss_t), intent(inout) :: gs !< Type storing the gaussians
32  real(dp), intent(in) :: amplitudes(:) !< Their amplitudes
33  real(dp), intent(in) :: sigmas(:) !< Their widths
34  real(dp), intent(in) :: locations(:,:) !< Their locations
35 
36  if (size(locations, 2) /= size(amplitudes) .or. &
37  size(sigmas) /= size(amplitudes)) then
38  stop "gauss_init: arguments do not match in size"
39  end if
40 
41  gs%n_gauss = size(amplitudes)
42  gs%n_dim = size(locations, 1)
43 
44  allocate(gs%ampl(gs%n_gauss))
45  allocate(gs%sigma(gs%n_gauss))
46  allocate(gs%r0(gs%n_dim, gs%n_gauss))
47 
48  gs%ampl = amplitudes
49  gs%sigma = sigmas
50  gs%r0 = locations
51  end subroutine gauss_init
52 
53  !> Return the value of the sum of gaussians at r
54  real(dp) function gauss_value(gs, r)
55  type(gauss_t), intent(in) :: gs
56  real(dp), intent(in) :: r(gs%n_dim)
57  integer :: n
58 
59  gauss_value = 0
60  do n = 1, gs%n_gauss
61  gauss_value = gauss_value + gauss_single(gs, r, n)
62  end do
63  end function gauss_value
64 
65  !> Return the value of a single gaussian at r
66  real(dp) function gauss_single(gs, r, ix)
67  type(gauss_t), intent(in) :: gs
68  real(dp), intent(in) :: r(gs%n_dim)
69  integer, intent(in) :: ix
70  real(dp) :: xrel(gs%n_dim)
71 
72  xrel = (r-gs%r0(:, ix)) / gs%sigma(ix)
73  gauss_single = gs%ampl(ix) * exp(-sum(xrel**2))
74  end function gauss_single
75 
76  subroutine gauss_gradient(gs, r, grad)
77  type(gauss_t), intent(in) :: gs
78  real(dp), intent(in) :: r(gs%n_dim)
79  real(dp), intent(out) :: grad(gs%n_dim)
80  integer :: ix
81  real(dp) :: xrel(gs%n_dim)
82 
83  grad = 0
84  do ix = 1, gs%n_gauss
85  xrel = (r-gs%r0(:, ix)) / gs%sigma(ix)
86  grad = grad - 2 * xrel/gs%sigma(ix) * &
87  gauss_single(gs, r, ix)
88  end do
89  end subroutine gauss_gradient
90 
91  !> Summed Laplacian of the gaussians in Cartesian coordinates
92  real(dp) function gauss_laplacian(gs, r)
93  type(gauss_t), intent(in) :: gs
94  real(dp), intent(in) :: r(gs%n_dim)
95  integer :: ix
96  real(dp) :: xrel(gs%n_dim)
97 
98  gauss_laplacian = 0
99  do ix = 1, gs%n_gauss
100  xrel = (r-gs%r0(:, ix)) / gs%sigma(ix)
101  gauss_laplacian = gauss_laplacian + 4/gs%sigma(ix)**2 * &
102  (sum(xrel**2) - 0.5_dp * gs%n_dim) * gauss_single(gs, r, ix)
103  end do
104  end function gauss_laplacian
105 
106  !> Summed Laplacian of the gaussians in (r,z) coordinates
107  real(dp) function gauss_laplacian_cyl(gs, r)
108  type(gauss_t), intent(in) :: gs
109  real(dp), intent(in) :: r(gs%n_dim)
110  integer :: ix
111  real(dp) :: xrel(gs%n_dim)
112 
113  gauss_laplacian_cyl = 0
114  do ix = 1, gs%n_gauss
115  xrel = (r-gs%r0(:, ix)) / gs%sigma(ix)
116  gauss_laplacian_cyl = gauss_laplacian_cyl + 4/gs%sigma(ix)**2 * &
117  (sum(xrel**2) - 1 - 0.5_dp * (r(1)-gs%r0(1, ix))/r(1)) * &
118  gauss_single(gs, r, ix)
119  end do
120  end function gauss_laplacian_cyl
121 
122  !> Fourth derivative of the gaussians in Cartesian coordinates
123  real(dp) function gauss_4th(gs, r)
124  type(gauss_t), intent(in) :: gs
125  real(dp), intent(in) :: r(gs%n_dim)
126  integer :: ix
127  real(dp) :: xrel(gs%n_dim), d4(gs%n_dim)
128 
129  d4 = 0
130  do ix = 1, gs%n_gauss
131  xrel = (r-gs%r0(:, ix)) / gs%sigma(ix)
132  d4 = d4 + gauss_single(gs, r, ix) / gs%sigma(ix)**4 * &
133  (16 * xrel**4 - 48 * xrel**2 + 12)
134  end do
135  gauss_4th = norm2(d4)
136  end function gauss_4th
137 
138 end module m_gaussians
This module can be used to construct solutions consisting of one or more Gaussians.
Definition: m_gaussians.f90:3
A type to store a collection of gaussians in.
Definition: m_gaussians.f90:11