function s_gaussian1d(x,xcent,fwhm)
  !---------------------------------------------------------------------
  ! @ public
  ! Compute gaussian value at X, peaks at 1 (single precision)
  !---------------------------------------------------------------------
  real(kind=4) :: s_gaussian1d
  real(kind=4), intent(in) :: x
  real(kind=4), intent(in) :: xcent
  real(kind=4), intent(in) :: fwhm
  ! Local
  real(kind=4) :: sigma
  !
  sigma = fwhm/(2.0*sqrt(2.0*log(2.0)))
  !
  s_gaussian1d = exp(-(x-xcent)**2/(2.0*sigma*sigma))
  !
end function s_gaussian1d
!
function d_gaussian1d(x,xcent,fwhm)
  use phys_const
  !---------------------------------------------------------------------
  ! @ public
  ! Compute gaussian value at X, peaks at 1 (double precision)
  !---------------------------------------------------------------------
  real(kind=8) :: d_gaussian1d
  real(kind=8), intent(in) :: x
  real(kind=8), intent(in) :: xcent
  real(kind=8), intent(in) :: fwhm
  ! Local
  real(kind=8) :: sigma
  !
  sigma = fwhm/(2.d0*sqrt(2.d0*log(2.d0)))
  !
  d_gaussian1d = exp(-(x-xcent)**2/(2.d0*sigma*sigma))
  !
end function d_gaussian1d
!
function s_normal1d(x,xcent,sigma)
  use phys_const
  !---------------------------------------------------------------------
  ! @ public
  ! Compute normal distribution value at X, area is 1 (single precision)
  !---------------------------------------------------------------------
  real(kind=4) :: s_normal1d
  real(kind=4), intent(in) :: x
  real(kind=4), intent(in) :: xcent
  real(kind=4), intent(in) :: sigma
  !
  s_normal1d = exp(-(x-xcent)**2/(2.d0*sigma*sigma)) / (sigma*sqrt(2*pi))
  !
end function s_normal1d
!
function d_normal1d(x,xcent,sigma)
  use phys_const
  !---------------------------------------------------------------------
  ! @ public
  ! Compute normal distribution value at X, area is 1 (double precision)
  !---------------------------------------------------------------------
  real(kind=8) :: d_normal1d
  real(kind=8), intent(in) :: x
  real(kind=8), intent(in) :: xcent
  real(kind=8), intent(in) :: sigma
  !
  d_normal1d = exp(-(x-xcent)**2/(2.d0*sigma*sigma)) / (sigma*sqrt(2*pi))
  !
end function d_normal1d
!
subroutine gauss2d_convolution(a1,b1,t1,a2,b2,t2,a3,b3,t3,error)
  !---------------------------------------------------------------------
  ! @ public
  ! Compute the parameters of the 2D gaussian resulting from the
  ! convolution of 2 2D gaussians:
  !   1 * 2 => 3
  ! Knowing 1 and 2 find 3.
  !---------------------------------------------------------------------
  real(kind=4), intent(in)    :: a1    ! [same] First gaussian major axis
  real(kind=4), intent(in)    :: b1    ! [same] First gaussian minor axis
  real(kind=4), intent(in)    :: t1    ! [rad]  First gaussian position angle
  real(kind=4), intent(in)    :: a2    ! [same] Second gaussian major axis
  real(kind=4), intent(in)    :: b2    ! [same] Second gaussian minor axis
  real(kind=4), intent(in)    :: t2    ! [rad]  Second gaussian position angle
  real(kind=4), intent(out)   :: a3    ! [same] Result major axis
  real(kind=4), intent(out)   :: b3    ! [same] Result minor axis
  real(kind=4), intent(out)   :: t3    ! [rad]  Result position angle
  logical,      intent(inout) :: error ! Logical error flag
  ! Local
  real(kind=4) :: c1,s1,c2,s2
  real(kind=4) :: alpha,beta,gamma,s,t,u
  !
  c1 = cos(t1)
  s1 = sin(t1)
  c2 = cos(t2)
  s2 = sin(t2)
  !
  alpha = (a1*c1)**2 + (b1*s1)**2 + (a2*c2)**2 + (b2*s2)**2
  beta  = (a1*s1)**2 + (b1*c1)**2 + (a2*s2)**2 + (b2*c2)**2
  gamma = 2.0*( (a1**2-b1**2)*s1*c1 +  (a2**2-b2**2)*s2*c2 )
  !
  s = alpha+beta
  u = alpha-beta
  t = sqrt(u**2+gamma**2)
  !
  ! New values updated in place
  a3 = sqrt(0.5*(s+t))
  b3 = sqrt(0.5*(s-t))
  t3 = 0.5 * atan2(gamma,u)  ! No issue here, except the very extreme case where
                             ! we convolve a Dirac by a Dirac
  !
end subroutine gauss2d_convolution
!
subroutine gauss2d_deconvolution(a1,b1,t1,a3,b3,t3,a2,b2,t2,error)
  use gmath_interfaces, except_this=>gauss2d_deconvolution
  use gmath_messaging
  !---------------------------------------------------------------------
  ! @ public
  ! Compute the parameters of the 2D gaussian resulting from the
  ! deconvolution of 2 2D gaussians:
  !   1 * 2 => 3
  ! Knowing 1 and 3 find 2.
  !---------------------------------------------------------------------
  real(kind=4), intent(in)    :: a1    ! [same] First gaussian major axis
  real(kind=4), intent(in)    :: b1    ! [same] First gaussian minor axis
  real(kind=4), intent(in)    :: t1    ! [rad]  First gaussian position angle
  real(kind=4), intent(in)    :: a3    ! [same] Result major axis
  real(kind=4), intent(in)    :: b3    ! [same] Result minor axis
  real(kind=4), intent(in)    :: t3    ! [rad]  Result position angle
  real(kind=4), intent(out)   :: a2    ! [same] Second gaussian major axis
  real(kind=4), intent(out)   :: b2    ! [same] Second gaussian minor axis
  real(kind=4), intent(out)   :: t2    ! [rad]  Second gaussian position angle
  logical,      intent(inout) :: error ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='GAUSS2D'
  real(kind=4) :: c1,s1,c3,s3
  real(kind=4) :: alpha,beta,gamma,s,t,u
  !
  c1 = cos(t1)
  s1 = sin(t1)
  c3 = cos(t3)
  s3 = sin(t3)
  !
  alpha = (a3*c3)**2 + (b3*s3)**2 - (a1*c1)**2 - (b1*s1)**2
  beta  = (a3*s3)**2 + (b3*c3)**2 - (a1*s1)**2 - (b1*c1)**2
  gamma = 2.0*( (a3**2-b3**2)*s3*c3 - (a1**2-b1**2)*s1*c1 )
  !
  s = alpha+beta
  u = alpha-beta
  t = sqrt(u**2+gamma**2)
  !
  ! Sanity check
  if (t.gt.s) then
    call gmath_message(seve%e,rname,'Final resolution is not reachable from input resolution')
    error = .true.
    return
  endif
  !
  ! New values updated in place
  a2 = sqrt(0.5*(s+t))
  b2 = sqrt(0.5*(s-t))
  t2 = 0.5 * atan2(gamma,u)
  !
end subroutine gauss2d_deconvolution
