submodule_sph_particles_quality_indicators.f90 Source File


This file depends on

sourcefile~~submodule_sph_particles_quality_indicators.f90~~EfferentGraph sourcefile~submodule_sph_particles_quality_indicators.f90 submodule_sph_particles_quality_indicators.f90 sourcefile~module_sph_particles.f90 module_sph_particles.f90 sourcefile~submodule_sph_particles_quality_indicators.f90->sourcefile~module_sph_particles.f90 sourcefile~module_utility.f90 module_utility.f90 sourcefile~submodule_sph_particles_quality_indicators.f90->sourcefile~module_utility.f90 sourcefile~module_sph_particles.f90->sourcefile~module_utility.f90 sourcefile~module_id_base.f90 module_id_base.f90 sourcefile~module_sph_particles.f90->sourcefile~module_id_base.f90 sourcefile~module_id_base.f90->sourcefile~module_utility.f90

Contents


Source Code

! File:         submodule_sph_particles_quality_indicators.f90
! Authors:      Francesco Torsello (FT)
!************************************************************************
! Copyright (C) 2020-2023 Francesco Torsello                            *
!                                                                       *
! This file is part of SPHINCS_ID                                       *
!                                                                       *
! SPHINCS_ID is free software: you can redistribute it and/or modify    *
! it under the terms of the GNU General Public License as published by  *
! the Free Software Foundation, either version 3 of the License, or     *
! (at your option) any later version.                                   *
!                                                                       *
! SPHINCS_ID is distributed in the hope that it will be useful,         *
! but WITHOUT ANY WARRANTY; without even the implied warranty of        *
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          *
! GNU General Public License for more details.                          *
!                                                                       *
! You should have received a copy of the GNU General Public License     *
! along with SPHINCS_ID. If not, see <https://www.gnu.org/licenses/>.   *
! The copy of the GNU General Public License should be in the file      *
! 'COPYING'.                                                            *
!************************************************************************

SUBMODULE(sph_particles) quality_indicators

  !****************************************************
  !
  !# This SUBMODULE contains the implementation of
  !  the methods of TYPE [[particles]]
  !  that computes the quality indicators, referring to
  !
  !  [Daniel J. Price, Smoothed Particle Hydrodynamics and Magnetohydrodynamics. Journal of Computational Physics, 231, 3, 759-794 (2012). DOI: 10.1016/j.jcp.2010.12.011](http://arxiv.org/abs/1012.1885){:target="_blank"},
  !  eqs.(64), (67) and (74-75)
  !
  !  [Rosswog, S. SPH Methods in the Modelling of Compact Objects. Living Rev Comput Astrophys 1, 1 (2015).](https://arxiv.org/abs/1406.4224){:target="_blank"},
  !  eqs.(6) and (9)
  !
  !  FT 05.10.2022
  !
  !****************************************************


  IMPLICIT NONE


  CONTAINS


  !-------------------!
  !--  SUBROUTINES  --!
  !-------------------!


  MODULE PROCEDURE compute_and_print_quality_indicators

    !****************************************************
    !
    !# Compute the quality indicators, referring to
    !
    !  [Daniel J. Price, Smoothed Particle Hydrodynamics and Magnetohydrodynamics. Journal of Computational Physics, 231, 3, 759-794 (2012). DOI: 10.1016/j.jcp.2010.12.011](http://arxiv.org/abs/1012.1885){:target="_blank"},
    !  eqs.(64), (67) and (74-75)
    !
    !  [Rosswog, S. SPH Methods in the Modelling of Compact Objects. Living Rev Comput Astrophys 1, 1 (2015).](https://arxiv.org/abs/1406.4224){:target="_blank"},
    !  eqs.(6) and (9)
    !
    !  FT 05.10.2022
    !
    !****************************************************

    USE kernel_table, ONLY: dv_table, dv_table_1,&
                            W_no_norm, n_tab_entry, &!dWdv_no_norm, &
                            interp_gradW_table,interp_W_gradW_table
    USE sphincs_sph,  ONLY: ncand, all_clists
    USE RCB_tree_3D,  ONLY: iorig, nic, nfinal, nprev, lpart, rpart
    USE options,      ONLY: ndes
    USE set_h,        ONLY: exact_nei_tree_update
    USE utility,      ONLY: zero, one, two

    IMPLICIT NONE

    DOUBLE PRECISION, DIMENSION(npart)    :: qi_1
    DOUBLE PRECISION, DIMENSION(3,npart)  :: qi_2
    DOUBLE PRECISION, DIMENSION(3,npart)  :: qi_3
    DOUBLE PRECISION, DIMENSION(3,3,npart):: qi_4
    DOUBLE PRECISION, DIMENSION(3,npart)  :: qi_ham

    INTEGER:: a, b, ill, l, itot, inde, index1, k

    DOUBLE PRECISION:: ha, ha_1, ha_3, ha_4, va, xa, ya, za, &
                       hb, hb_1, hb_3, hb_4, xb, yb, zb, rab, rab2, rab_1, &
                       ha2_4, hb2_4, dx, dy, dz

    DOUBLE PRECISION:: Wab_ha, Wi, Wi1, dvv, &
                       grW_ha_x, grW_ha_y, grW_ha_z, &
                       grW_hb_x, grW_hb_y, grW_hb_z, eab(3), &
                       Wa, grW, grWa, grWb, vb, vol_b

    LOGICAL, PARAMETER:: debug= .TRUE.

    INTEGER                      :: ios, unit_qi
    LOGICAL                      :: exist
    CHARACTER(LEN=:), ALLOCATABLE:: namefile, err_msg

    PRINT *, " * Computing the quality indicators..."

    ! exact_nei_tree_update updates h
    CALL exact_nei_tree_update( ndes, npart, pos, nu )

    qi_1  = zero
    qi_2  = zero
    qi_3  = zero
    qi_4  = zero
    qi_ham= zero
    !$OMP PARALLEL DO DEFAULT( NONE ) &
    !$OMP             SHARED( nfinal, nprev, iorig, lpart, rpart, nic,nu,nstar, &
    !$OMP                     ncand, all_clists, W_no_norm, pos, h, &
    !$OMP                     qi_1, qi_2, qi_3, qi_4, qi_ham ) &
    !$OMP             PRIVATE( ill, itot, a, b, l, &
    !$OMP                      ha, ha_1, ha_3, ha_4, ha2_4, &
    !$OMP                      hb, hb_1, hb_3, hb_4, hb2_4, &
    !$OMP                      xa, ya, za, xb, yb, zb, dx, dy, dz, rab2, &
    !$OMP                      inde, va, dv_table_1, index1, Wi, &
    !$OMP                      dvv, dv_table, Wab_ha, Wa, grW, Wi1, &
    !$OMP                      grW_ha_x, grW_ha_y, grW_ha_z, grWa, grWb, &
    !$OMP                      grW_hb_x, grW_hb_y, grW_hb_z, eab, rab, vb, &
    !$OMP                      rab_1, vol_b )
    lowest_level_cell_loop: DO ill= 1, nfinal

      itot= nprev + ill
      IF( nic(itot) == 0 ) CYCLE

      particle_loop: DO l= lpart(itot), rpart(itot)

        ! Set index of the particle in the lowest level cell
        a    = iorig(l)

        ! Compute smoothing lengths and its powers (used below)
        ha   = h(a)
        ha_1 = one/ha
        ha_3 = ha_1*ha_1*ha_1
        ha_4 = ha_3*ha_1
        ha2_4= two*two*ha*ha

        xa= pos(1,a)
        ya= pos(2,a)
        za= pos(3,a)

        candidate_loop: DO k= 1, ncand(ill)

          ! Set index of candidate particle
          b= all_clists(ill)% list(k)

          ! Compute smoothing lengths and its powers (used below)
          hb   = h(b)
          hb_1 = one/hb
          hb_3 = hb_1*hb_1*hb_1
          hb_4 = hb_3*hb_1
          hb2_4= two*two*hb*hb

          xb= pos(1,b)
          yb= pos(2,b)
          zb= pos(3,b)

          ! Compute distance between particles a and b
          dx= xa - xb
          dy= ya - yb
          dz= za - zb

          rab2 = dx*dx + dy*dy + dz*dz
          rab  = SQRT(rab2) + 1.D-30
          rab_1= one/rab

          ! If the distance between the particles a and b is larger than twice
          ! their smoothing lengths, move to next candidate particle
          ! This one is not a neighbour
          IF( rab2 > ha2_4 .AND. rab2 > hb2_4 ) CYCLE

          va= rab*ha_1

          ! Read kernel values
          inde  = MIN(INT(va*dv_table_1),n_tab_entry)
          index1= MIN(inde + 1,n_tab_entry)

          Wi = W_no_norm(inde)
          Wi1= W_no_norm(index1)

          dvv   = (va - DBLE(inde)*dv_table)*dv_table_1
          Wab_ha= Wi + (Wi1 - Wi)*dvv

          ! Compute normalized distance between the particles a and b
          eab(1)= dx*rab_1
          eab(2)= dy*rab_1
          eab(3)= dz*rab_1

          !
          !-- Interpolate kernel value, and its gradient,
          !-- at the distance between the particles
          !

          !DIR$ INLINE
          CALL interp_W_gradW_table( va, Wa, grW )
          Wa = Wa*ha_3
          grW= grW*ha_4

          grW_ha_x= grW*eab(1)
          grW_ha_y= grW*eab(2)
          grW_ha_z= grW*eab(3)

          vb= rab*hb_1

          !DIR$ INLINE
          CALL interp_gradW_table(vb,grW)
          grW= grW*hb_4

          grW_hb_x= grW*eab(1)
          grW_hb_y= grW*eab(2)
          grW_hb_z= grW*eab(3)

          ! Compute particle volume
          vol_b= nu(b)/nstar(b)

          !
          !-- Compute quality indicators
          !
          qi_1(a)= qi_1(a) + Wab_ha*vol_b

          qi_2(1,a)= qi_2(1,a) + (-dx)*Wab_ha*vol_b
          qi_2(2,a)= qi_2(2,a) + (-dy)*Wab_ha*vol_b
          qi_2(3,a)= qi_2(3,a) + (-dz)*Wab_ha*vol_b

          qi_3(1,a)= qi_3(1,a) + grW_ha_x*vol_b
          qi_3(2,a)= qi_3(2,a) + grW_ha_y*vol_b
          qi_3(3,a)= qi_3(3,a) + grW_ha_z*vol_b

          qi_4(1,1,a)= qi_4(1,1,a) + (-dx)*grW_ha_x*vol_b
          qi_4(1,2,a)= qi_4(1,2,a) + (-dx)*grW_ha_y*vol_b
          qi_4(1,3,a)= qi_4(1,3,a) + (-dx)*grW_ha_z*vol_b
          qi_4(2,1,a)= qi_4(2,1,a) + (-dy)*grW_ha_x*vol_b
          qi_4(2,2,a)= qi_4(2,2,a) + (-dy)*grW_ha_y*vol_b
          qi_4(2,3,a)= qi_4(2,3,a) + (-dy)*grW_ha_z*vol_b
          qi_4(3,1,a)= qi_4(3,1,a) + (-dz)*grW_ha_x*vol_b
          qi_4(3,2,a)= qi_4(3,2,a) + (-dz)*grW_ha_y*vol_b
          qi_4(3,3,a)= qi_4(3,3,a) + (-dz)*grW_ha_z*vol_b

          qi_ham(1,a)= qi_ham(1,a) &
                       + nu(b)*grW_ha_x*(one/nstar(a) + nstar(a)/nstar(b)**2)
          qi_ham(2,a)= qi_ham(2,a) &
                       + nu(b)*grW_ha_y*(one/nstar(a) + nstar(a)/nstar(b)**2)
          qi_ham(3,a)= qi_ham(3,a) &
                       + nu(b)*grW_ha_z*(one/nstar(a) + nstar(a)/nstar(b)**2)

        ENDDO candidate_loop

        !qi(a)= qi(a)/(nu(a)/nstar(a))

      ENDDO particle_loop

    ENDDO lowest_level_cell_loop
    !$OMP END PARALLEL DO

    PRINT *, " * Printing the quality indicators to file..."

    IF(PRESENT(path))THEN
      namefile= path//"quality_indicators.dat"
    ELSE
      namefile= "quality_indicators.dat"
    ENDIF
    unit_qi= 279465

    INQUIRE( FILE= TRIM(namefile), EXIST= exist )

    IF( exist )THEN
        OPEN( UNIT= unit_qi, FILE= TRIM(namefile), STATUS= "REPLACE", &
              FORM= "FORMATTED", &
              POSITION= "REWIND", ACTION= "WRITE", IOSTAT= ios, &
              IOMSG= err_msg )
    ELSE
        OPEN( UNIT= unit_qi, FILE= TRIM(namefile), STATUS= "NEW", &
              FORM= "FORMATTED", &
              ACTION= "WRITE", IOSTAT= ios, IOMSG= err_msg )
    ENDIF
    IF( ios > 0 )THEN
      PRINT *, "...error when opening " // TRIM(namefile), &
               ". The error message is", err_msg
      STOP
    ENDIF

    WRITE( UNIT = unit_qi, IOSTAT = ios, IOMSG = err_msg, FMT = * ) &
    "# Run ID [ccyymmdd-hhmmss.sss]: " // run_id

    WRITE( UNIT = unit_qi, IOSTAT = ios, IOMSG = err_msg, FMT = * ) &
    "# Quality indicators on the particles"
    IF( ios > 0 )THEN
      PRINT *, "...error when writing line 1 in " // TRIM(namefile), &
               ". The error message is", err_msg
      STOP
    ENDIF

    WRITE( UNIT = unit_qi, IOSTAT = ios, IOMSG = err_msg, FMT = * ) &
    "# column:      1        2       3       4       5", &
    "       6       7       8", &
    "       9       10      11", &
    "       12      13      14", &
    "       15      16      17", &
    "       18      19      20", &
    "       21      22      23"
    IF( ios > 0 )THEN
      PRINT *, "...error when writing line 2 in " // TRIM(namefile), &
               ". The error message is", err_msg
      STOP
    ENDIF

    WRITE( UNIT = unit_qi, IOSTAT = ios, IOMSG = err_msg, FMT = * ) &
    "#      particle index     x [Msun_geo]       ", &
    "       y [Msun_geo]       z [Msun_geo]       Q1", &
    "       Q2_x       Q2_y       Q2_z", &
    "       Q3_x       Q3_y       Q3_z", &
    "       Q4_xx       Q4_xy       Q4_xz", &
    "       Q4_yx       Q4_yy       Q4_yz", &
    "       Q4_zx       Q4_zy       Q4_zz", &
    "       Qhamilonian_x       Qhamilonian_y       Qhamilonian_z"
    IF( ios > 0 )THEN
      PRINT *, "...error when writing line 3 in " // TRIM(namefile), &
               ". The error message is", err_msg
      STOP
    ENDIF

    DO a= 1, npart, 1
      WRITE( UNIT = unit_qi, IOSTAT = ios, IOMSG = err_msg, FMT = * ) &
        a, &           ! 1
        pos(1,a), &    ! 2
        pos(2,a), &    ! 3
        pos(3,a), &    ! 4
        qi_1(a), &     ! 5
        qi_2(1,a), &   ! 6
        qi_2(2,a), &   ! 7
        qi_2(3,a), &   ! 8
        qi_3(1,a), &   ! 9
        qi_3(2,a), &   ! 10
        qi_3(3,a), &   ! 11
        qi_4(1,1,a), & ! 12
        qi_4(1,2,a), & ! 13
        qi_4(1,3,a), & ! 14
        qi_4(2,1,a), & ! 15
        qi_4(2,2,a), & ! 16
        qi_4(2,3,a), & ! 17
        qi_4(3,1,a), & ! 18
        qi_4(3,2,a), & ! 19
        qi_4(3,3,a), & ! 20
        qi_ham(1,a), & ! 21
        qi_ham(2,a), & ! 22
        qi_ham(3,a)    ! 23
    ENDDO

    CLOSE( UNIT= unit_qi )

    PRINT *, "   quality indicators printed to file ", namefile
    PRINT *


  END PROCEDURE compute_and_print_quality_indicators


END SUBMODULE quality_indicators