ellipse_acf Subroutine

public subroutine ellipse_acf(tabin, long, larg, p_acv, cut, scale_xy, omp)

Note

Function that returns p_acv which contains parameters on anisotropy.

  • p_acv(1) = axe_a, ellipsis big axis
  • p_acv(2) = axe_b, ellipsis small axis
  • p_acv(3) = axe_a/axe_b another anisotropy factor
  • p_acv(4) = nint(angle/inc_a), main texture orientation
  • p_acv(5) = ray_pente, radius of greatest slope
  • p_acv(6) = max_pente, greatest slope
  • p_acv(7) = max_pente/min_pente slope anisotropy factor
  • p_acv(8) = highest curvature/smallest curvature, curvature anisotropy factor

Arguments

Type IntentOptional Attributes Name
real(kind=R8), intent(in), dimension(1:long, 1:larg) :: tabin

surface acf array

integer(kind=I4), intent(in) :: long

surface length

integer(kind=I4), intent(in) :: larg

surface width

real(kind=R8), intent(out), dimension(1:8) :: p_acv

vector containing anisotropy outputs

real(kind=R8), intent(in), optional :: cut

cut height

real(kind=R8), intent(in), dimension(1:2) :: scale_xy

lag along x and y in micrometers

logical(kind=I4), intent(in) :: omp

multithreaded ?


Calls

proc~~ellipse_acf~~CallsGraph proc~ellipse_acf ellipse_acf get_unit get_unit proc~ellipse_acf->get_unit omp_get_num_procs omp_get_num_procs proc~ellipse_acf->omp_get_num_procs sort_array2 sort_array2 proc~ellipse_acf->sort_array2

Called by

proc~~ellipse_acf~~CalledByGraph proc~ellipse_acf ellipse_acf proc~correlation_parameters correlation_parameters proc~correlation_parameters->proc~ellipse_acf program~test_anisotropy test_anisotropy program~test_anisotropy->proc~ellipse_acf program~test_anisotropy->proc~correlation_parameters

Source Code

   subroutine ellipse_acf(tabin, long, larg, p_acv, cut, scale_xy, omp)
   !================================================================================================
   !< @note Function that returns p_acv which contains parameters on anisotropy.
   !<
   !<  - p_acv(1) = axe_a,                                ellipsis big axis
   !<  - p_acv(2) = axe_b,                                ellipsis small axis
   !<  - p_acv(3) = axe_a/axe_b                           another anisotropy factor
   !<  - p_acv(4) = nint(angle/inc_a),                    main texture orientation
   !<  - p_acv(5) = ray_pente,                            radius of greatest slope
   !<  - p_acv(6) = max_pente,                            greatest slope
   !<  - p_acv(7) = max_pente/min_pente                   slope anisotropy factor
   !<  - p_acv(8) = highest curvature/smallest curvature, curvature anisotropy factor
   !<
   !<  @endnote
   !------------------------------------------------------------------------------------------------
   implicit none
   integer(kind=I4), intent(in )                             :: long       !! *surface length*
   integer(kind=I4), intent(in )                             :: larg       !! *surface width*
   logical(kind=I4), intent(in )                             :: omp        !! *multithreaded ?*
   real   (kind=R8), intent(in ), optional                   :: cut        !! *cut height*
   real   (kind=R8), intent(in ), dimension(1:long, 1:larg)  :: tabin      !! *surface acf array*
   real   (kind=R8), intent(in ), dimension(1:2)             :: scale_xy   !! *lag along x and y in micrometers*
   real   (kind=R8), intent(out), dimension(1:8)             :: p_acv      !! *vector containing anisotropy outputs*

      integer(kind=I4) :: i, k, ll, p, q, qp, qm, nb_p, nx, ny, lo2, la2, funit, nb_th
      logical(kind=I4) :: verif
      real   (kind=R8) :: x, y, xb, yb, xm, ym, xp, yp, inc_a
      real   (kind=R8) :: r, r1, rc, theta, h0, hh, h1, h2, h3, h4, coupe, pente_locale, pente_locale_precede
      real   (kind=R8) :: angle, axe_a, axe_b, ech_x, ech_y, ech_z, ech_r
      real   (kind=R8) :: min_pente, max_pente, ray_pente
      real   (kind=R8) :: c, s

      integer(kind=I4), dimension(0:179) :: p_min, e_angle
      integer(kind=I4), dimension(1:2)   :: loc_max!, imax_acv
      real   (kind=R8), dimension(0:179) :: pente_max
      real   (kind=R8), dimension(0:359) :: ellipse

      real   (kind=R8), allocatable, dimension(:,:) :: tabou, tab_tmp
      real   (kind=R8), allocatable, dimension(:)   :: courbure

      ech_x = scale_xy(1)  !SCALE_IMG%dx * unit2IUf(SCALE_IMG%dx_unit) / 1.e-6  ! x lag in micron
      ech_y = scale_xy(2)  !SCALE_IMG%dy * unit2IUf(SCALE_IMG%dy_unit) / 1.e-6  ! y lag in micron
      ech_z = 1.                                                                ! acf(0,0) = 1

      loc_max(1:2) = maxloc( tabin(1:long, 1:larg) )
      lo2 = loc_max(1)
      la2 = loc_max(2)

      !  on prend une surface carrée inscrite
      ll = min(lo2, la2) - 1

      allocate(    tabou(0:ll, 0:359) )
      allocate( courbure(      0:359) )
      tabou    = EPS_R8
      courbure = EPS_R8

!~       ! avec fftw, il faut mettre le max de l'acv en (lo2,la2)
!~       imax_acv = maxloc( tabin(1:long, 1:larg) )

      allocate( tab_tmp(1:long, 1:larg) )

      tab_tmp(1:long, 1:larg) = tabin(1:long, 1:larg)

      verif = .false.

      if ( verif ) then ! sortie xyz
         call get_unit(funit)
         open(funit,file='out/test_pol.dat')
      endif

      !  angle increment for polar representation of the rosette
      inc_a = 2*PI_R8/360

      !  determination of heights on a rosette diameter, obtained by linear interpolation :
      !  a point “falls” into a rectangular element [h1,h2,h3,h4], its height is determined by lin. interp.
      nb_p = 0

      nb_th = 1
      if (omp) nb_th = omp_get_num_procs()

      !$OMP PARALLEL DEFAULT(SHARED) NUM_THREADS(nb_th) IF (omp)
      !$OMP DO SCHEDULE (STATIC,(ll+1)/nb_th) PRIVATE(p,r,q,theta,x,y,xm,ym,h1,h2,h3,h4,hh)

      do p = 0, ll                !  identifying a point on the diameter
         r = p                    !  corresponding algebraic radius
         do q = 0, 359            !  angular increment identification
            theta = q*inc_a

            !  projection on x and y of the point marked by its radius and angle, taking the lower integer,
            !  gives the number of the bottom line and left-hand column of the rectangle
            !  the remainder (x-nx) represents the abscissa of the point in the rectangle with sides=1
            !  the 0.9999 coefficient is used to avoid falling right on an existing point
            x = lo2 + r * cos(theta) * 0.9999_R8 ; nx = floor(x) ; xb = x -nx
            y = la2 + r * sin(theta) * 0.9999_R8 ; ny = floor(y) ; yb = y -ny

            xm = UN -xb ; xp = xb
            ym = UN -yb ; yp = yb

            if ( nx+1 <= long .and. ny+1 <= larg .and. &
                 nx   >= 1    .and. ny   >= 1) then
               ! attention r may be greater than lo2 or la2
               h1 = tab_tmp(nx   , ny   )
               h2 = tab_tmp(nx +1, ny   )
               h3 = tab_tmp(nx +1, ny +1)
               h4 = tab_tmp(nx   , ny +1)

               hh = h1*xm*ym + h2*xp*ym + h3*xp*yp + h4*xm*yp
               tabou(p, q) = hh
               nb_p = nb_p +1
            else
               hh = 0.
            endif
            if ( verif ) write(funit,*) real(x,kind=R4), real(y,kind=R4), real(hh,kind=R4)
         enddo
      enddo

      !$OMP END DO
      !$OMP END PARALLEL

      deallocate( tab_tmp )

      if ( verif ) close(funit)

      if ( present(cut) ) then
         coupe = cut
      else
         coupe  = 0.5
      endif

      do q = 0, 359        !  angle en deg

         theta = q*inc_a   !  angle en rad
         ech_r = sqrt( (ech_x*cos(theta))**2 + &   !
                       (ech_y*sin(theta))**2 )     !  unit according to angle q
         ellipse(q)  = (ll -1)*ech_r               !  max value of ellipse radius

         do p = 0, ll -1                           !  identifying a point on the diameter

            r1 = p                                 !  algebraic radius
            h1 = tabou( p   , q )
            h2 = tabou( p +1, q )
            if (abs(h2) < 10*EPS_R8) exit          !  useful for ll = floor(sqrt(UN*(lo2**2 +la2**2))) -1

            if (h1 > coupe .and. h2 < coupe) then
               rc = r1 +(h1 -coupe)/(h1 -h2)
               ellipse(q)  = rc*ech_r
               exit  ! if you don't pass here: no intersection with the cutting plane -> max value taken by default
            endif

         enddo

         ! curvature averaged over 3 points
         rc = 0
         do p = 1, 3

            h0 = tabou( p - 1, q )
            h1 = tabou( p    , q )
            h2 = tabou( p + 1, q )
            if (abs(h2) < 10*EPS_R8) exit          !  useful for ll = floor(sqrt(UN*(lo2**2 +la2**2))) -1

            rc = rc + ( h0 - 2 * h1 + h2 )

         enddo
         courbure(q) = - ( rc / ( 2 * ech_r**2 ) ) / 3.

      enddo

      do q = 0, 179
         e_angle(q) = 2 * q ! angle doubled for the continuity of sin and cos
      enddo

      call sort_array2( tab_inout = ellipse(0:179),                   &  !
                             tab1 = e_angle(0:179),                   &  !
                                n = 180 )                                !

      axe_b   = sum(ellipse(  0:  2))/3.
      axe_a   = sum(ellipse(177:179))/3.

      c = sum( cos(e_angle(175:179) * PI_R8 / 180) ) / 5.
      s = sum( sin(e_angle(175:179) * PI_R8 / 180) ) / 5.

      angle   = atan2(s, c) * 180 / PI_R8 / 2     ! angle halfed (see above)

      p_acv(1) = axe_a
      p_acv(2) = axe_b
      p_acv(3) = axe_a/axe_b
      p_acv(4) = nint(angle)

      !-----------------------------------------------

      p_min(0:179) = ll -1
      do q = 0, 179                                !  incrément angulaire

         qp = q +1 ; if (qp>179) qp = 0
         qm = q -1 ; if (qm<0  ) qm = 179
         theta = q*inc_a
         ech_r = sqrt( (ech_x*cos(theta))**2 +  &  !
                       (ech_y*sin(theta))**2 )     !  unit according to angle q

         pente_locale_precede = 0._R8
         do p = 1, ll-1

            pente_locale = ( (tabou(p+1, q ) -tabou(p-1, q )) /  2              )**2 +   &  !
                           ( (tabou(p  , qp) -tabou(p  , qm)) / (2 * p * inc_a) )**2        !

            pente_locale = sqrt( pente_locale ) * ech_z / ech_r

            if ( abs( pente_locale ) < abs( pente_locale_precede ) ) then
               p_min(q) = p                                             !  the steepest slope distance is recorded
               exit
            else
               pente_locale_precede = pente_locale
            endif

         enddo

      enddo

      call sort_array2( tab_inout = p_min(0:179),  &  !
                        n         = 180 )             !

      k = int( sum( p_min(0:4) ) / 5., kind = I4 )          !  the minimum distance

      do q = 0, 179                                         !  angular increment

         qp = q +1 ; if (qp > 179) qp = 0
         qm = q -1 ; if (qm < 0  ) qm = 179
         theta = q * inc_a

         ech_r = sqrt( ( ech_x * cos(theta) )**2 + &  !
                        (ech_y * sin(theta) )**2 )    !  unit according to angle q

         pente_locale = ( (tabou(k+1, q ) - tabou(k-1, q )) /  2              )**2 +   &  !
                        ( (tabou(k  , qp) - tabou(k  , qm)) / (2 * k * inc_a) )**2        !

         pente_locale = sqrt( pente_locale ) * ech_z / ech_r
         pente_max(q) =  abs( pente_locale )                               !  for angle q, greater slope

      enddo

      do q = 0, 179
         e_angle(q) = q
      enddo

      call sort_array2( tab_inout = pente_max(0:179),                   &  !
                             tab1 =   e_angle(0:179),                   &  !
                                n = 180 )                                  !

      angle = sum( e_angle(175:179) ) / 5.

      theta = angle*inc_a
      ech_r = sqrt( ( ech_x * cos(theta) )**2 +    &  !
                    ( ech_y * sin(theta) )**2 )       !  unit according to angle q

      min_pente = sum( pente_max(  0:  2) ) / 3.
      max_pente = sum( pente_max(177:179) ) / 3.
      ray_pente = k * ech_r

      p_acv(5) = ray_pente
      p_acv(6) = max_pente
      p_acv(7) = max_pente / min_pente         !  anisotropy indicator
      p_acv(8) = maxval( courbure(0:359) ) / minval( courbure(0:359) )

      deallocate( tabou, courbure )

   return
   endsubroutine ellipse_acf