calcul_asfc_spl_all Subroutine

private subroutine calcul_asfc_spl_all(tab_in, scal, asfc_res)

Return the asfc of a surface. The different grids are obtained by spline of degree 3

Arguments

Type IntentOptional Attributes Name
real(kind=R8), intent(in), dimension(1:scal%xres, 1:scal%yres) :: tab_in

input surface

type(SCALE_SURF), intent(in) :: scal

surface characteristics

real(kind=R8), intent(out), dimension(1:2) :: asfc_res

result: asfc, adjustment factor


Calls

proc~~calcul_asfc_spl_all~~CallsGraph proc~calcul_asfc_spl_all calcul_asfc_spl_all db2ink db2ink proc~calcul_asfc_spl_all->db2ink db2val db2val proc~calcul_asfc_spl_all->db2val lmder1 lmder1 proc~calcul_asfc_spl_all->lmder1 proc~calcul_aire calcul_aire proc~calcul_asfc_spl_all->proc~calcul_aire proc~df_boltz df_boltz proc~calcul_asfc_spl_all->proc~df_boltz proc~f_boltz f_boltz proc~calcul_asfc_spl_all->proc~f_boltz proc~init_beta_boltz init_beta_boltz proc~calcul_asfc_spl_all->proc~init_beta_boltz proc~locate locate proc~calcul_asfc_spl_all->proc~locate

Called by

proc~~calcul_asfc_spl_all~~CalledByGraph proc~calcul_asfc_spl_all calcul_asfc_spl_all proc~calcul_asfc calcul_asfc proc~calcul_asfc->proc~calcul_asfc_spl_all

Source Code

   subroutine calcul_asfc_spl_all(tab_in, scal, asfc_res)
   !================================================================================================
  !! Return the *asfc* of a surface. The different grids are obtained by spline of degree 3
   implicit none
   type(SCALE_SURF), intent(in )                                      :: scal     !! *surface characteristics*
   real   (kind=R8), intent(in ), dimension(1:scal%xres, 1:scal%yres) :: tab_in   !! *input surface*
   real   (kind=R8), intent(out), dimension(1:2)                      :: asfc_res !! *result: asfc, adjustment factor*

      integer(kind=I4), parameter :: idx = 0    ! [[db2val]] input
      integer(kind=I4), parameter :: idy = 0    ! [[db2val]] input

      real(kind=R8), allocatable, dimension(:) :: x        ! x points in original grid
      real(kind=R8), allocatable, dimension(:) :: y        ! y points in original grid

      integer(kind=I4) :: long_new              ! number of points in x dimension for new grid
      integer(kind=I4) :: larg_new              ! number of points in y dimension for new grid

      real(kind=R8), allocatable, dimension(:)   :: x_new    ! new grid x points
      real(kind=R8), allocatable, dimension(:)   :: y_new    ! new grid y points
      real(kind=R8), allocatable, dimension(:,:) :: tab_ou   ! new grid function evaluations

      real(kind=R8), allocatable, dimension(:,:) :: coeff, coeff_tmp
      real(kind=R8), allocatable, dimension(:)   :: tx, tx_tmp       ! x knots
      real(kind=R8), allocatable, dimension(:)   :: ty, ty_tmp       ! y knots

      real(kind=R8)    :: val, rr
      integer(kind=I4) :: i, j, k, ip, long_tmp, larg_tmp
      integer(kind=I4) :: iflag
      integer(kind=I4) :: inbvx, inbvy, iloy
      integer(kind=I4) :: nb_pt

      integer(kind=I4), dimension(1:8) :: d1, d2

      real(kind=R8), dimension(1:nb_beta) :: beta
      real(kind=R8), dimension(1:npp)     :: vec_l, vec_s

      real(kind=R8), dimension(1:npp) :: vec_x  ! points coordinates
      real(kind=R8), dimension(1:npp) :: vec_y  ! points coordinates

      real(kind=R8), dimension(1:8)       :: gx, gy, vf

      real(kind=R8) :: asfc1, asfc2, aire, aire_lin, aire_tmp, x1, x2, y1, y2, val_x, val_y, width, height, hx, hy, hhx, hhy

      logical(kind=I4) :: new_it

      integer(kind=I4) :: long, larg

      long = scal%xres
      larg = scal%yres

      if (out_lin) open(unit=unit_out_lin, file="out/asfc_lin_spl_all.txt")
      if (out_spl) open(unit=unit_out_spl, file="out/asfc_spl_spl_all.txt")

      width  = scal%lx
      height = scal%ly

      hx =  width/(long -1)
      hy = height/(larg -1)

      ! définition d'abscisses pour l'interpolation par splines
      allocate( x(1:long), y(1:larg) )
      do i = 1, long
         x(i) = hx*real(i-1, kind=R8)
      enddo
      do j = 1, larg
         y(j) = hy*real(j-1, kind=R8)
      enddo

      rr =          (real(long0, kind=R8)/long)**(UN/npp)    ! facteur de réduction pour aller du maillage initial au maillage minimal avec npp points
      rr = max( rr, (real(larg0, kind=R8)/larg)**(UN/npp) )  ! facteur de réduction pour aller du maillage initial au maillage minimal avec npp points

      allocate( x_new(1:long),              &
                y_new(1:larg),              &  ! nouvelles abscisses
               tab_ou(1:long, 1:larg) )

      x_new(1:long)          = x(1:long)
      y_new(1:larg)          = y(1:larg)
      tab_ou(1:long, 1:larg) = tab_in(1:long, 1:larg)

      ! pour chaque réduction de maillage, calcul du maillage résultant et de l'aire relative associée
      !.............................................................
      long_new = long
      larg_new = larg
      hhx      = hx
      hhy      = hy
      nb_pt    = 1
      new_it   = .true.
      do ip = 1, npp +1

         if (new_it) then

            long_tmp = long_new
            larg_tmp = larg_new

            ! calcul de l'aire relative
            call calcul_aire(tab_ou(1:long_tmp, 1:larg_tmp), long_tmp, larg_tmp, hhx, hhy, aire_lin)!, rx=real(long-1, kind=R8)/(long_tmp-1), &
                                                                                          ! ry=real(larg-1, kind=R8)/(larg_tmp-1))

            allocate( coeff_tmp(1:long_tmp, 1:larg_tmp) )

            allocate( tx_tmp(1:(long_tmp +kx)),  &
                      ty_tmp(1:(larg_tmp +ky)) )

            iflag = 0
            call db2ink(   x = x_new(1:long_tmp),                 &
                          nx = long_tmp,                          &
                           y = y_new(1:larg_tmp),                 &
                          ny = larg_tmp,                          &
                         fcn = tab_ou(1:long_tmp, 1:larg_tmp),    &
                          kx = kx,                                &
                          ky = ky,                                &
                          tx = tx_tmp(1:(long_tmp +kx)),          &
                          ty = ty_tmp(1:(larg_tmp +ky)),          &
                       bcoef = coeff_tmp(1:long_tmp, 1:larg_tmp), &
                       iflag = iflag)

            if (iflag/=1) then
               write(*,*) iflag, long_tmp, larg_tmp, kx, ky
               stop 'error calling db2ink'
            endif

            if (ip==1) then
               allocate( coeff(1:long, 1:larg) )
               allocate( tx(1:(long +kx)),  &
                         ty(1:(larg +ky)) )
               coeff(1:long, 1:larg) = coeff_tmp(1:long, 1:larg)
                  tx(1:(long +kx))   =    tx_tmp(1:(long +kx))
                  ty(1:(larg +ky))   =    ty_tmp(1:(larg +ky))
            endif

            inbvx = 1
            inbvy = 1
            iloy  = 1

            aire_tmp = 0._R8
!~             !$OMP PARALLEL DEFAULT(SHARED) NUM_THREADS(NB_PROCS) IF(MULTI_PROCS2)
!~             !$OMP DO SCHEDULE (STATIC,(larg_tmp-1)/NB_PROCS) PRIVATE(i, k, iflag, val, y1, y2, x1, x2, d1, d2, gx, gy, vf) FIRSTPRIVATE(inbvx, inbvy, iloy) REDUCTION(+:aire_tmp)
               do j = 1, larg_tmp -1
                  y1 = y_new(j) +(hhy/2)*(UN -UN/sqrt(3._R8))
                  y2 = y_new(j) +(hhy/2)*(UN +UN/sqrt(3._R8))

                  do i = 1, long_tmp -1
                     x1 = x_new(i) +(hhx/2)*(UN -UN/sqrt(3._R8))
                     x2 = x_new(i) +(hhx/2)*(UN +UN/sqrt(3._R8))

                     d1(1:8) = [ 1,  0,  1,  0,  1,  0,  1,  0]
                     d2(1:8) = [ 0,  1,  0,  1,  0,  1,  0,  1]
                     gx(1:8) = [x1, x1, x1, x1, x2, x2, x2, x2]
                     gy(1:8) = [y1, y1, y2, y2, y1, y1, y2, y2]

                     do k = 1, 8
                        call db2val(xval = gx(k),                             &
                                    yval = gy(k),                             &
                                     idx = d1(k),                             &
                                     idy = d2(k),                             &
                                      tx = tx_tmp(1:(long_tmp +kx)),          &
                                      ty = ty_tmp(1:(larg_tmp +ky)),          &
                                      nx = long_tmp,                          &
                                      ny = larg_tmp,                          &
                                      kx = kx,                                &
                                      ky = ky,                                &
                                   bcoef = coeff_tmp(1:long_tmp, 1:larg_tmp), &
                                       f = vf(k),                             &
                                   iflag = iflag,                             &
                                   inbvx = inbvx,                             &
                                   inbvy = inbvy,                             &
                                    iloy = iloy)
                        if (iflag/=0) then
                           write(*,*) iflag
                           stop 'error calling db2val'
                        endif
                     enddo
                     do k = 1, 4
                        val_x = vf(2*k -1)
                        val_y = vf(2*k   )
                        aire_tmp = aire_tmp +sqrt( UN +val_x**2 +val_y**2 )
                     enddo

                  enddo
               enddo
!~             !$OMP END DO
!~             !$OMP END PARALLEL

            aire = aire_tmp*( hhx/2 )*( hhy/2 )
            aire = aire/(width*height)

            vec_x(nb_pt) = log( (hhx*1e6)*(hhy*1e6)/2 )
            vec_l(nb_pt) = log(aire_lin)
            vec_s(nb_pt) = log(aire    )

            if (out_lin .and. nb_pt>1) write(unit_out_lin, *) vec_x(nb_pt -1), vec_l(nb_pt -1)
            if (out_spl .and. nb_pt>1) write(unit_out_spl, *) vec_x(nb_pt -1), vec_s(nb_pt -1)

            if (out_ter) write(*, *) hhx, hhy, aire, ip

         endif

         if (ip == npp +1) then
            deallocate( x_new, y_new, x, y, tab_ou, coeff, tx, ty, coeff_tmp, tx_tmp, ty_tmp )
            exit
         endif

         long_new = nint(long*(rr**ip))   ! nb points en suite géométrique
         larg_new = nint(larg*(rr**ip))

         new_it = .true.
         if (long_new==long_tmp .or. larg_new==larg_tmp) then
            new_it = .false.
            cycle ! à découper trop fin, on peut tomber sur les mêmes entiers
         endif

         hhx =  width/(long_new -1)
         hhy = height/(larg_new -1)

         nb_pt = nb_pt +1

         deallocate( x_new, y_new, tab_ou )
           allocate( x_new(1:long_new),              &
                     y_new(1:larg_new),              &  ! nouvelles abscisses
                    tab_ou(1:long_new, 1:larg_new) )

         do i = 1, long_new
            x_new(i) = hhx*real(i-1, kind=R8)
         enddo

         do j = 1, larg_new
            y_new(j) = hhy*real(j-1, kind=R8)
         enddo

         inbvx = 1
         inbvy = 1
         iloy  = 1

         ! calcul des hauteurs de la surface interpolée
!~          !$OMP PARALLEL DEFAULT(SHARED) NUM_THREADS(NB_PROCS) IF(MULTI_PROCS2)
!~          !$OMP DO SCHEDULE (STATIC,larg_new/NB_PROCS) PRIVATE(i, iflag, val) FIRSTPRIVATE(inbvx, inbvy, iloy)
            do j = 1, larg_new
            do i = 1, long_new
               call db2val(xval = x_new(i),              &
                           yval = y_new(j),              &
                            idx = idx,                   &
                            idy = idy,                   &
                             tx = tx(1:(long +kx)),      &
                             ty = ty(1:(larg +ky)),      &
                             nx = long,                  &
                             ny = larg,                  &
                             kx = kx,                    &
                             ky = ky,                    &
                          bcoef = coeff(1:long, 1:larg), &
                              f = val,                   &
                          iflag = iflag,                 &
                          inbvx = inbvx,                 &
                          inbvy = inbvy,                 &
                           iloy = iloy)
               if (iflag/=0) error stop 'error calling db2val'
               iflag = 0
               tab_ou(i, j) = val
            enddo
            enddo
!~          !$OMP END DO
!~          !$OMP END PARALLEL

         deallocate( coeff_tmp, tx_tmp, ty_tmp )

      enddo
      if (out_lin) close(unit_out_lin)
      if (out_spl) close(unit_out_spl)
      !.............................................................
      nb_pt = nb_pt -1

      vec_y(1:nb_pt) = vec_s(1:nb_pt)
      call interpolate_asfc( bt = beta(1:nb_beta),    &
                           n_bt = nb_beta,            &
                           n_pt = nb_pt,              &
                            asf = asfc1,              &
                             r2 = asfc2)

      asfc_res = [-1000*asfc1, asfc2]

   return
   contains

      subroutine interpolate_asfc(bt, n_bt, n_pt, asf, r2)
      !================================================================================================
      !< @note Function that fits the data points for the asfc determination.<br/>
      !        \(f\_boltz(x_i)=\beta_2 + \beta_3 \tanh \left( \dfrac{x_i -\beta_1}{\beta_4} \right) \)
      !
      !  @endnote
      !------------------------------------------------------------------------------------------------
      implicit none
      integer(kind=I4), intent(in )                    :: n_bt !! *number of parameters*
      integer(kind=I4), intent(in )                    :: n_pt !! *data vector length*
      real   (kind=R8), intent(out), dimension(1:n_bt) :: bt   !! *vector \(\beta\) of parameters*
      real   (kind=R8), intent(out)                    :: asf  !! *Asfc number*
      real   (kind=R8), intent(out)                    :: r2   !! *correlation number to assess validity of the Asfc calculus*

         real   (kind=R8), dimension(1:n_pt, 1:n_bt) :: jacob
         real   (kind=R8), dimension(1:n_pt)         :: v_x, v_y, res_y, pentes
         integer(kind=I4)                            :: i0, i, j, info
         real   (kind=R8)                            :: delta1, delta2, y_mean

         v_x(1:n_pt) = vec_x(1:n_pt)

         ! smoothing
         v_y(1) = vec_y(1)
         do i = 1 + 1, n_pt - 1

            v_y(i) = 0.25_R8 * ( vec_y(i - 1) + 2 * vec_y(i) + vec_y(i + 1) )

         enddo
         v_y(n_pt) = vec_y(n_pt)

         call init_beta_boltz(   bt = bt(1:n_bt),     & !
                               n_bt = n_bt,           & !
                                v_x = v_x(1:n_pt),    & !
                                v_y = v_y(1:n_pt),    & !
                               n_pt = n_pt)             !

         res_y(1:n_pt)         = 0._R8
         jacob(1:n_pt, 1:n_bt) = 0._R8

         call lmder1(   fcn = lmder1_f,               & !
                          m = n_pt,                   & !
                          n = n_bt,                   & !
                          x = bt(1:n_bt),             & !
                       fvec = res_y(1:n_pt),          & !
                       fjac = jacob(1:n_pt, 1:n_bt),  & !
                     ldfjac = n_pt,                   & !
                        tol = 1.0e-8_R8,              & !
                       info = info)                     !

         delta1 = 0._R8
         delta2 = 0._R8
         y_mean = sum( vec_y(1:n_pt) )/n_pt
         do i = 1, n_pt
            delta1 = delta1 +( vec_y(i) -f_boltz(xi = vec_x(i),   & !
                                               beta = bt(1:n_bt), & !
                                             n_beta = n_bt)       & !
                             )**2
            delta2 = delta2 +( vec_y(i) -y_mean )**2
         enddo
         r2 = 1._R8 -delta1/delta2

   !~       if (r2<0) then
   !~       do i=1,n_pt
   !~       write(99,*) v_x(i), v_y(i)
   !~       enddo
   !~       stop 'error'
   !~       endif

         i0 = locate(n = n_pt,        & !
                    xx = v_x(1:n_pt), & !
                     x = bt(1))         !

         j = 0
         do i = i0 -5, i0 +5
            if (i<1 .or. i>n_pt) cycle
            j = j +1
            pentes(j) = +df_boltz(  xi = v_x(i),     & !
                                  beta = bt(1:n_bt), & !
                                n_beta = n_bt,       & !
                                  ivar = 0)            !
         enddo

         asf = sum( pentes(1:j)/j )

      return
      endsubroutine interpolate_asfc

      subroutine lmder1_f(m, n, x, fvec, fjac, ldfjac, iflag)
      !================================================================================================
      !< @note Function called by [[lmder1]] as part of **minpack**, modified by
      !        [Burkardt](https://people.sc.fsu.edu/~jburkardt/f_src/minpack/minpack.html) <br/>
      !        According *iflag* value it calculates the function [[f_boltz]] at the data points
      !        or the jacobian.
      !
      !  @endnote
      !------------------------------------------------------------------------------------------------
      implicit none
      integer(kind=I4), intent(in   )                           :: m       !! *number of points*
      integer(kind=I4), intent(in   )                           :: n       !! *number of parameters*
      integer(kind=I4), intent(in   )                           :: ldfjac  !! *leading dimension of fjac, which must be at least n*
      integer(kind=I4), intent(in   )                           :: iflag   !! *which calculus to perform*
      real   (kind=R8), intent(out  ), dimension(1:m)           :: fvec    !! *vector of f_boltz(xi)*
      real   (kind=R8), intent(out  ), dimension(1:ldfjac, 1:n) :: fjac    !! *jacobian*
      real   (kind=R8), intent(inout), dimension(1:n)           :: x       !! *parameter values*

         integer(kind=I4) :: i, k

         select case (iflag)
            case(0)
               continue

            case(1)
               do i = 1, m
                  fvec(i) = f_boltz(     xi = vec_x(i),  &  !
                                       beta = x(1:n),    &  !
                                     n_beta = n)         &  !
                            -vec_y(i)
               enddo

            case(2)
               do i = 1, m
               do k = 1, n
                  fjac(i, k) = df_boltz(xi = vec_x(i), & !
                                      beta = x(1:n),   & !
                                      ivar = k,        & !
                                    n_beta = n)          !
               enddo
               enddo

            case default
               write ( *, '(a)' ) ' '
               write ( *, '(a)' ) 'LMDER1_F - Fatal error!'
               write ( *, '(a,i6)' ) '  Called with unexpected value of IFLAG = ', iflag
               stop

         endselect
      return
      endsubroutine lmder1_f

   endsubroutine calcul_asfc_spl_all