submodule_sph_particles_sph_variables.f90 Source File


This file depends on

sourcefile~~submodule_sph_particles_sph_variables.f90~~EfferentGraph sourcefile~submodule_sph_particles_sph_variables.f90 submodule_sph_particles_sph_variables.f90 sourcefile~module_sph_particles.f90 module_sph_particles.f90 sourcefile~submodule_sph_particles_sph_variables.f90->sourcefile~module_sph_particles.f90 sourcefile~module_utility.f90 module_utility.f90 sourcefile~submodule_sph_particles_sph_variables.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_sph_variables.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) sph_variables

  !****************************************************
  !
  !# This SUBMODULE contains the implementation of
  !  the method of TYPE sph_particles
  !  that computes the |sph| variables.
  !
  !  FT 16.10.2020
  !
  !  Renamed from particles_methods to
  !  particles_sph_variables upon improving modularity
  !
  !  FT 12.07.2021
  !
  !  @note Last updated: FT 27.10.2022
  !
  !****************************************************


  USE constants,  ONLY: half, c_light2
  USE utility,    ONLY: zero, one, two, three, eos$poly, eos$pwpoly, &
                        eos$tabu$compose


  IMPLICIT NONE


  CONTAINS


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


  MODULE PROCEDURE compute_sph_hydro

    !************************************************
    !
    !# Computes the hydro fields on a section of the
    !  particles specified as input.
    !  First, computes the |sph| pressure starting
    !  from the |sph| baryon mass density, and the
    !  specific internal energy. The pressure is
    !  computed differently for different |eos|, and
    !  for cold and hot systems.
    !  Then computes the enthalpy and the sound speed
    !  accordingly.
    !
    !  FT 02.12.2022
    !
    !************************************************

    USE units,    ONLY: m0c2_cu
    USE numerics, ONLY: linear_interpolation
    USE pwp_EOS,  ONLY: select_EOS_parameters, gen_pwp_eos, Gamma_th_1

    IMPLICIT NONE

    INTEGER:: a, dim_table
    DOUBLE PRECISION:: tmp, tmp2, kappa_poly, gamma_poly
    LOGICAL:: verb

    IF(PRESENT(verbose))THEN
      verb= verbose
    ELSE
      verb=.TRUE.
    ENDIF

    ASSOCIATE( eos_id => NINT(eqos% eos_parameters(1)) )

    detect_eos: IF( eos_id == eos$poly )THEN
    ! If the |eos| is polytropic

      kappa_poly= eqos% eos_parameters(poly$kappa)
      gamma_poly= eqos% eos_parameters(poly$gamma)

      IF(verb) PRINT *, " * Computing pressure and specific internal energy", &
               " from the baryon mass density, using the exact formulas for", &
               " single polytropic EOS..."
      IF(verb) PRINT *
      ! Formulas from Read et al. (2009), https://arxiv.org/abs/0812.2163

      detect_cold_system: IF( this% cold_system )THEN
      ! If the system is cold, compute pressure and specific energy
      ! exactly using the polytropic EOS

        IF(verb) PRINT *, " * Assuming a cold system: no thermal component", &
                          " considered."
        IF(verb) PRINT *

        !
        !-- Leaving the following code here, commented, because it allows
        !-- to test the pwp_eos MODULE using single polytropes
        !-- All tests were passed on 23.02.2022
        !
    !      CALL select_EOS_parameters( 'soft' )
    !
    !      DO a= npart_in, npart_fin, 1
    !
    !        CALL gen_pwp_eos( rho_rest= this% nlrf_sph(a)*m0c2_cu, &
    !                          u_cold= u(a), P_cold= Pr(a), cs= cs(a) )
    !
    !        !CALL gen_pwp_eos( this% nlrf_sph(a)*m0c2_cu, &
    !        !                  this% u_sph(a), tmp, &
    !        !                  u(a), &
    !        !                  Pr(a), cs(a) )
    !      ENDDO

        !$OMP PARALLEL DO DEFAULT( NONE ) &
        !$OMP             SHARED( Pr, m0c2_cu, u, npart_in, npart_fin, &
        !$OMP                     nlrf, enthalpy, cs, &
        !$OMP                     gamma_poly, kappa_poly ) &
        !$OMP             PRIVATE( a )
        DO a= 1, npart_fin - npart_in + 1, 1

          Pr(a)= kappa_poly*(nlrf(a)*m0c2_cu)**gamma_poly

          ! Using this internal energy gives machine-precision relative errors
          ! after the recovery, since it is computed from nlrf_sph
          ! Using the internal energy from the ID gives larger errors
          u(a)= ( Pr(a)/(nlrf(a)*m0c2_cu*(gamma_poly - one)) )

          enthalpy(a)= one + u(a) + Pr(a)/(nlrf(a)*m0c2_cu)

          cs(a)= SQRT( gamma_poly*Pr(a)/(nlrf(a)*m0c2_cu*enthalpy(a)) )

          Pr(a)= Pr(a)/m0c2_cu

        ENDDO
        !$OMP END PARALLEL DO

      ELSE
      ! If the system is hot, that is, has a thermal component, then
      ! the density and the specific energy (the latter including both
      ! cold and thermal part) should be supplied within the ID.
      ! The pressure is computed using them (see pwp_EOS MODULE).

        IF(verb) PRINT *, " * Assuming a hot system: thermal component", &
                          " considered."
        IF(verb) PRINT *

        !$OMP PARALLEL DO DEFAULT( NONE ) &
        !$OMP             SHARED( Pr, m0c2_cu, u, npart_in, npart_fin, &
        !$OMP                     nlrf, enthalpy, cs, this, &
        !$OMP                     gamma_poly, kappa_poly ) &
        !$OMP             PRIVATE( a )
        DO a= 1, npart_fin - npart_in + 1, 1

          u(a)= this% specific_energy(a)

          Pr(a)= &
          ! cold pressure
          kappa_poly*(nlrf(a)*m0c2_cu)**gamma_poly &
          + &
          ! thermal pressure
          Gamma_th_1*( nlrf(a)*m0c2_cu )* &
          MAX( u(a) - ( Pr(a)/(nlrf(a)*m0c2_cu*(gamma_poly - one) ) ), zero )

          enthalpy(a)= one + u(a) + Pr(a)/(nlrf(a)*m0c2_cu)

          cs(a)= SQRT( gamma_poly*Pr(a)/(nlrf(a)*m0c2_cu*enthalpy(a)) )

          Pr(a)= Pr(a)/m0c2_cu

        ENDDO
        !$OMP END PARALLEL DO

      ENDIF detect_cold_system

    ELSEIF( eos_id == eos$pwpoly )THEN
    ! If the |eos| is piecewise polytropic

      IF(verb) PRINT *, " * Computing pressure and specific internal energy", &
               " from the baryon mass density, using the exact formulas for", &
               " piecewise polytropic EOS..."
      IF(verb) PRINT *

      detect_hot_system: IF( this% cold_system )THEN
      ! If the system is cold, compute pressure and specific energy
      ! exactly using the piecewise polytropic EOS

        IF(verb) PRINT *, " * Assuming a cold system: no thermal component", &
                          " considered."
        IF(verb) PRINT *

        CALL select_EOS_parameters( eqos% eos_name )

        !$OMP PARALLEL DO DEFAULT( NONE ) &
        !$OMP             SHARED( nlrf, Pr, m0c2_cu, u, cs, &
        !$OMP                     npart_in, npart_fin ) &
        !$OMP             PRIVATE( a )
        DO a= 1, npart_fin - npart_in + 1, 1

          CALL gen_pwp_eos( rho_rest= nlrf(a)*m0c2_cu, &
                            u_cold= u(a), P_cold= Pr(a), cs= cs(a) )

          Pr(a)= Pr(a)/m0c2_cu

        ENDDO
        !$OMP END PARALLEL DO

      ELSE
      ! If the system is hot, that is, has a thermal component, then
      ! the density and the specific energy (the latter including both
      ! cold and thermal part) should be supplied in the ID.
      ! The pressure is computed using them (see pwp_EOS MODULE).

        IF(verb) PRINT *, " * Assuming a hot system: thermal component", &
                          " considered."
        IF(verb) PRINT *

        CALL select_EOS_parameters( eqos% eos_name )

        !$OMP PARALLEL DO DEFAULT( NONE ) &
        !$OMP             SHARED( nlrf, Pr, m0c2_cu, u, cs, this, &
        !$OMP                     npart_in, npart_fin ) &
        !$OMP             PRIVATE( a, tmp, tmp2 )
        DO a= 1, npart_fin - npart_in + 1, 1

          u(a)= this% specific_energy(a)

          CALL gen_pwp_eos( nlrf(a)*m0c2_cu, tmp, &
                            tmp2, u(a), Pr(a), cs(a) )

          Pr(a)= Pr(a)/m0c2_cu

        ENDDO
        !$OMP END PARALLEL DO

      ENDIF detect_hot_system

    ELSEIF( eos_id == eos$tabu$compose )THEN
    ! If the |eos| is tabulated in the CompOSE format

      IF(verb) PRINT *, " * Computing pressure and specific internal energy", &
               " from the baryon mass density, using the provided table..."
      IF(verb) PRINT *

      dim_table= SIZE(eqos% table_eos(1,:))

      !$OMP PARALLEL DO DEFAULT( NONE ) &
      !$OMP             SHARED( Pr, m0c2_cu, u, npart_in, npart_fin, &
      !$OMP                     nlrf, enthalpy, cs, eqos, dim_table ) &
      !$OMP             PRIVATE( a )
      DO a= 1, npart_fin - npart_in + 1, 1

        Pr(a)= linear_interpolation &
      (nlrf(a)*m0c2_cu, dim_table, eqos% table_eos(14,:), eqos% table_eos(4,:))

        u(a)= linear_interpolation &
      (nlrf(a)*m0c2_cu, dim_table, eqos% table_eos(10,:), eqos% table_eos(4,:))

        enthalpy(a)= one + u(a) + Pr(a)/(nlrf(a)*m0c2_cu)

        cs(a)= zero!SQRT( gamma_poly*Pr(a)/(nlrf(a)*m0c2_cu*enthalpy(a)) )

        Pr(a)= Pr(a)/m0c2_cu

      ENDDO
      !$OMP END PARALLEL DO

    ENDIF detect_eos

    END ASSOCIATE

  END PROCEDURE compute_sph_hydro


  MODULE PROCEDURE compute_and_print_sph_variables

    !************************************************
    !
    !# Compute the |sph| variables from the
    !  |id|, and print them to a binary file to be
    !  read by |sphincsbssn|, and to a formatted file
    !
    !  FT 18.09.2020
    !
    !************************************************

    USE constants,           ONLY: amu, third, Msun, m2cm
    USE utility,             ONLY: MSun_geo, zero, one, &
                                   compute_g4, determinant_sym4x4, &
                                   spacetime_vector_norm_sym4x4, km2m, &
                                   sph_path
    USE units,               ONLY: set_units
    USE matrix,              ONLY: determinant_4x4_matrix
    USE sph_variables,       ONLY: npart, &  ! particle number
                                   n1,    &  ! particle number for star 1
                                   n2,    &  ! particle number for star 2
                                   pos_u, &  ! particle positions
                                   vel_u, &  ! particle velocities in
                                             ! coordinate frame
                                   nlrf,  &  ! baryon number density in
                                             ! local rest frame
                                   !ehat,  &  ! canonical energy per baryon
                                   nu,    &  ! canonical baryon number per
                                             ! particle
                                   Theta, &  ! Generalized Lorentz factor
                                   h,     &  ! Smoothing length
                                   Pr,    &  ! Pressure
                                   u,     &  ! Specific internal energy in local
                                             ! rest frame (no kinetic energy)
                                   temp,  &  ! Temperature
                                   av,    &  ! Dissipation
                                   ye,    &  ! Electron fraction
                                   divv,  &  ! Divergence of velocity vel_u
                                   cs,    &  ! Sound speed
                                   allocate_SPH_memory, &
                                   deallocate_SPH_memory
    USE metric_on_particles, ONLY: allocate_metric_on_particles, &
                                   deallocate_metric_on_particles, &
                                   sq_det_g4, g4_ll
    USE options,             ONLY: basename
    USE input_output,        ONLY: dcount, write_SPHINCS_dump, read_options
    USE APM,                 ONLY: density_loop
    USE options,             ONLY: ndes
    USE set_h,               ONLY: exact_nei_tree_update
    USE gradient,            ONLY: allocate_gradient, deallocate_gradient
    USE alive_flag,          ONLY: alive
    USE APM,                 ONLY: assign_h
    USE RCB_tree_3D,         ONLY: iorig, allocate_RCB_tree_memory_3D, &
                                   deallocate_RCB_tree_memory_3D
    USE analyze,             ONLY: compute_adm_momentum_fluid_fields!, COM, lin_mom
    USE tensor,              ONLY: n_sym4x4, &
                                   itt, itx, ity, itz, &
                                   ixx, ixy, ixz, iyy, iyz, izz

    IMPLICIT NONE

    ! The flag call_flag is set different than 0 if the SUBROUTINE
    ! compute_and_print_sph_variables is called
    INTEGER, SAVE:: call_flag= 0

    INTEGER:: a, i_matter
    INTEGER:: n_problematic_h

    DOUBLE PRECISION:: g4(n_sym4x4)
    DOUBLE PRECISION:: det

    LOGICAL, PARAMETER:: debug= .FALSE.

    !CHARACTER(LEN= :), ALLOCATABLE:: compose_namefile
    CHARACTER(LEN= :), ALLOCATABLE:: finalnamefile

    LOGICAL:: tabu_eos

    TYPE(timer):: find_h_bruteforce_timer

    find_h_bruteforce_timer= timer( "find_h_bruteforce_timer" )

    CALL this% sph_computer_timer% start_timer()

    PRINT *, "** Executing the compute_and_print_sph_variables " &
             // "subroutine..."
    PRINT *

    !
    !-- Set up the MODULE variables from MODULE sph_variables
    !-- (used by write_SPHINCS_dump).
    !-- If write_SPHINCS_dump had arguments, it would not be needed
    !-- to assign values to the MODULE variables.
    !-- The TYPE-bound variables could be passed as arguments.
    !
    npart= this% npart
    n1   = this% npart_i(1)
    IF( this% n_matter == 2 ) n2= this% npart_i(2)

    CALL set_units('NSM')
    CALL read_options

    CALL allocate_SPH_memory
    CALL allocate_metric_on_particles( this% npart )

    !$OMP PARALLEL DO DEFAULT( NONE ) &
    !$OMP             SHARED( this, pos_u, h, nu ) &
    !$OMP             PRIVATE( a )
    assign_module_variables: DO a= 1, this% npart, 1
      pos_u(:,a)= this% pos(:,a)
      h    (a)  = this% h  (a)
      nu   (a)  = this% nu (a)
    ENDDO assign_module_variables
    !$OMP END PARALLEL DO

    IF( debug ) PRINT *, "1"

    !---------------------------------------------------------------!
    ! Compute SPH density estimate after updating the neighbor tree !
    ! (nu has to be assigned before this step)  !                   !
    !---------------------------------------------------------------!

    CALL allocate_RCB_tree_memory_3D(npart)
    iorig(1:npart)= (/ (a,a=1,npart) /)

    CALL allocate_gradient( npart )

    IF( debug ) PRINT *, "-1"

    PRINT *, " * Assigning h..."
    PRINT *

    ! Determine smoothing length so that each particle has exactly
    ! ndes neighbours
    CALL assign_h( ndes, &
                   this% npart, &
                   this% pos, this% h, & ! Input
                   h )                   ! Output

    IF( debug ) PRINT *, "101.5"

    CALL find_h_bruteforce_timer% start_timer()
    n_problematic_h= 0
    check_h: DO a= 1, this% npart, 1

      IF( ISNAN( h(a) ) .OR. h(a) <= zero )THEN

        n_problematic_h= n_problematic_h + 1

        h(a)= find_h_backup( a, this% npart, this% pos, ndes )

        IF( ISNAN( h(a) ) .OR. h(a) <= zero )THEN
          PRINT *, "** ERROR! h=0 on particle ", a, "even with the brute", &
                   " force method."
          PRINT *, "   Particle position: ", this% pos(:,a)
          STOP
        ENDIF

      ENDIF

    ENDDO check_h
    CALL find_h_bruteforce_timer% stop_timer()
    CALL find_h_bruteforce_timer% print_timer( 2 )

    PRINT *, " * The smoothing length was found brute-force for ", &
             n_problematic_h, " particles."
    PRINT *

    PRINT *, " * Computing neighbours' tree..."
    PRINT *

    IF( SUM(this% nu, DIM= 1)/SIZE(this% nu) == zero )THEN
      PRINT *, "** ERROR! Average nu= 0. Are you assigning values to the ", &
               "TYPE-bound array?"
      PRINT *, "Stopping..."
      STOP
    ENDIF

    CALL exact_nei_tree_update( ndes,        &
                                this% npart, &
                                this% pos,   &
                                this% nu )

    CALL find_h_bruteforce_timer% start_timer()
    n_problematic_h= 0
    check_h2: DO a= 1, this% npart, 1

      IF( ISNAN( h(a) ) .OR. h(a) <= zero )THEN

        n_problematic_h= n_problematic_h + 1
        h(a)= find_h_backup( a, this% npart, this% pos, ndes )
        PRINT *, h(a)
        IF( ISNAN( h(a) ) .OR. h(a) <= zero )THEN
          PRINT *, "** ERROR! h=0 on particle ", a, "even with the brute", &
                   " force method."
          PRINT *, "   Particle position: ", this% pos(:,a)
          STOP
        ENDIF

      ENDIF

    ENDDO check_h2
    CALL find_h_bruteforce_timer% stop_timer()
    CALL find_h_bruteforce_timer% print_timer( 2 )

    PRINT *, " * The smoothing length was found brute-force for ", &
             n_problematic_h, " particles."
    PRINT *

    ! Update the member variable storing the smoothing length
    this% h= h

    !
    !-- Compute the SPH estimate of the relativistic density variable nstar
    !
    PRINT *, " * Computing the SPH estimate of the relativistic density ", &
             "variable nstar..."
    PRINT *

    CALL density_loop( this% npart,     &
                       this% pos,       &
                       this% nu,        &
                       this% h,         &
                       this% nstar_sph )

    IF( debug ) PRINT *, "20"

    !
    !-- Compute square root of minus the determinant of the spacetime metric,
    !-- and the generalized Lorentz factor.
    !-- They are needed to compute nlrf from the SPH estimate of nstar
    !
    !$OMP PARALLEL DO DEFAULT( NONE ) &
    !$OMP             SHARED( this, sq_det_g4 ) &
    !$OMP             PRIVATE( a, g4, det )
    compute_det_and_theta_on_particles: DO a= 1, this% npart, 1

      ! Coordinate velocity of the fluid [c]
      this% v(0,a)= one
      this% v(1,a)= this% lapse(a)*this% v_euler_x(a) &
                    - this% shift_x(a)
      this% v(2,a)= this% lapse(a)*this% v_euler_y(a) &
                    - this% shift_y(a)
      this% v(3,a)= this% lapse(a)*this% v_euler_z(a) &
                    - this% shift_z(a)

      CALL compute_g4( this% lapse(a), &
                       [this% shift_x(a), this% shift_y(a), this% shift_z(a)], &
                       [this% g_xx(a), this% g_xy(a), this% g_xz(a), &
                        this% g_yy(a), this% g_yz(a), this% g_zz(a)], g4 )

      CALL determinant_sym4x4( g4, det )
      IF( ABS(det) < 1D-10 )THEN
        PRINT *, "The determinant of the spacetime metric is " &
                 // "effectively 0 at particle ", a
        PRINT *
        STOP
      ELSEIF( det > 0 )THEN
        PRINT *, "The determinant of the spacetime metric is " &
                 // "positive at particle ", a
        PRINT *
        STOP
      ENDIF
      sq_det_g4(a)= SQRT(-det)

      !
      !-- Generalized Lorentz factor
      !
      this% Theta(a)= zero
      CALL spacetime_vector_norm_sym4x4( g4, this% v(:,a), this% Theta(a) )
      IF( this% Theta(a) > zero )THEN
        PRINT *, "** ERROR! The computing frame particle 4-velocity is ", &
                 "spacelike at particle ", a
        PRINT *, " * Its norm is ",this% Theta(a)
        PRINT *, " * Stopping.."
        PRINT *
        STOP
      ELSEIF( this% Theta(a) == zero )THEN
        PRINT *, "** ERROR! The computing frame particle 4-velocity is ", &
                 "null at particle ", a
        PRINT *, " * Its norm is ", this% Theta(a)
        PRINT *, " * Stopping.."
        PRINT *
        STOP
      ENDIF
      this% Theta(a)= one/SQRT(-this% Theta(a))

    ENDDO compute_det_and_theta_on_particles
    !$OMP END PARALLEL DO

    IF( debug ) PRINT *, "21"

    !-------------------------------------------------------------------------!
    !-------------------------------------------------------------------------!
    ! This point here is CRUCIAL: the particle distribution may NOT resolve   !
    ! properly the steep density gradient at the surface, even if the APM     !
    ! is used. This implies that the kernel interpolated nstar_sph will be    !
    ! different than nstar computed directly from the ID (computed below),    !
    ! close to the surface.                                                   !
    ! The error can be such that the recovery fails in SPHINCS_BSSN, and      !
    ! this is of course a problem. Now, the density used in SPHINCS_BSSN      !
    ! during the evolution is not the one given by the ID. Hence nlrf_sph,    !
    ! computed from nstar_sph, should be used instead of nlrf given by the    !
    ! ID, so that the density on the particles corresponds to the density     !
    ! that "they see", that is, the kernel interpolated density that uses     !
    ! these values of nu.                                                     !
    !-------------------------------------------------------------------------!
    !-------------------------------------------------------------------------!

    !$OMP PARALLEL DO DEFAULT( NONE ) &
    !$OMP             SHARED( this, nlrf, sq_det_g4 ) &
    !$OMP             PRIVATE( a )
    compute_nlrf: DO a= 1, this% npart, 1

      ! Baryon mass density in the local rest frame
      this% nlrf_sph(a)= (this% nstar_sph(a)/this% Theta(a))/sq_det_g4(a)
      nlrf(a)          = this% nlrf_sph(a)
      ! Particle volume
      this% pvol(a)            = this% nu(a)/this% nstar_sph(a)
      ! Particle number density
      this% particle_density(a)= this% nstar_sph(a)/this% nu(a)

    ENDDO compute_nlrf
    !$OMP END PARALLEL DO

    IF( debug ) PRINT *, "22"

    !
    !-- Assign remaining particle properties to MODULE variables
    !
    !$OMP PARALLEL DO DEFAULT( NONE ) &
    !$OMP             SHARED( this, vel_u, Theta, temp, av, divv ) &
    !$OMP             PRIVATE( a )
    assign_module_variables2: DO a= 1, this% npart, 1
      ! Computing frame spatial velocity
      vel_u(:,a)= this% v(1:3,a)
      ! Generalized Lorentz factor
      Theta(a)  = this% Theta(a)
      ! Temperature
      temp(a)   = zero
      ! Disspation parameter
      av(a)     = zero
      ! Velocity divergence
      divv(a)   = zero
    ENDDO assign_module_variables2
    !$OMP END PARALLEL DO

    IF( debug ) PRINT *, "3"

    !
    !-- Compute nlrf and nstar from the ID (for diagnostics)
    !-- pressure and specific internal energy are already assigned
    !
    !$OMP PARALLEL DO DEFAULT( NONE ) &
    !$OMP             SHARED( this, sq_det_g4 ) &
    !$OMP             PRIVATE( a )
    compute_densities_from_id: DO a= 1, this% npart, 1
      this% nlrf (a)= this% baryon_density(a)
      this% nstar(a)= ( this% nlrf(a)*this% Theta(a) )*sq_det_g4(a)
    ENDDO compute_densities_from_id
    !$OMP END PARALLEL DO

    IF( debug ) PRINT *, "4"

    !-----------------------------------------------------------------------!
    ! Computation of the hydrodynamical fields.                             !
    ! They are computed using the EOS, starting from the SPH estimate of    !
    ! the baryon mass density.                                              !
    ! If the system is hot (that is, a thermal part is needed), the thermal !
    ! part is added, if a single or polytropic EOS is used. It is not       !
    ! added if a tabulated EOS is used.                                     !
    !-----------------------------------------------------------------------!

    matter_objects_loop: DO i_matter= 1, this% n_matter, 1

      ASSOCIATE( npart_in  => this% npart_fin(i_matter-1) + 1, &
                 npart_fin => this% npart_fin(i_matter) )

      CALL this% compute_sph_hydro(npart_in, npart_fin, &
        this% all_eos(i_matter), &
        this% nlrf_sph(npart_in:npart_fin), u(npart_in:npart_fin), &
        Pr(npart_in:npart_fin), this% enthalpy(npart_in:npart_fin), &
        cs(npart_in:npart_fin) &
      )

      END ASSOCIATE

    ENDDO matter_objects_loop

    this% pressure_sph= Pr
    this% u_sph       = u

    !------------------!
    ! Assignment of Ye !
    !------------------!

    assign_ye_on_particles: IF( this% compose_eos )THEN

      PRINT *, "** Assigning electron fraction using the CompOSE data..."!, &
               !TRIM(this% compose_path)//TRIM(this% compose_filename)

      !compose_namefile= TRIM(this% compose_path)//TRIM(this% compose_filename)
      !CALL this% read_compose_composition( compose_namefile )

      CALL this% compute_Ye()

      PRINT *, " * electron fraction assigned."
      PRINT *

    ELSE

      this% Ye= zero

    ENDIF assign_ye_on_particles
    Ye= this% Ye

    CALL this% sph_computer_timer% stop_timer()

    !
    !-- Printouts
    !
    !"(A28,E15.8,A10)"
    DO i_matter= 1, this% n_matter, 1

      ASSOCIATE( npart_in   => this% npart_i(i_matter-1) + 1, &
                 npart_fin  => this% npart_i(i_matter-1) +    &
                               this% npart_i(i_matter) )

      PRINT *, " * Maximum baryon density on object", i_matter, "=", &
                MAXVAL(this% baryon_density(npart_in:npart_fin), DIM=1) &
                /((Msun_geo*km2m*m2cm)**3)*(amu), " g cm^{-3}"
                !*amu/(m2cm**3), " amu cm^{-3} (TODO: CHECK UNITS)"
      PRINT *, " * Minimum baryon density on object", i_matter, "=", &
                MINVAL( this% baryon_density(npart_in:npart_fin), DIM=1) &
                /((Msun_geo*km2m*m2cm)**3)*(amu), " g cm^{-3}"
                !*amu/(m2cm**3), " amu cm^{-3} (TODO: CHECK UNITS)"
      PRINT *, " * Ratio between the two=", &
               MAXVAL(this% baryon_density(npart_in:npart_fin), DIM=1)/ &
               MINVAL(this% baryon_density(npart_in:npart_fin), DIM=1)
      PRINT *

      PRINT *, " * Maximum interpolated nlrf on object", i_matter, "=", &
               MAXVAL( this% nlrf_sph(npart_in:npart_fin), DIM= 1 ) &
               /((Msun_geo*km2m*m2cm)**3), " baryon cm^{-3}"
               !" m0c2_cu (TODO: CHECK UNITS)"!, &
               !"baryon Msun_geo^{-3}"
      PRINT *, " * Minimum interpolated nlrf on object", i_matter, "=", &
               MINVAL( this% nlrf_sph(npart_in:npart_fin), DIM= 1 ) &
               /((Msun_geo*km2m*m2cm)**3), " baryon cm^{-3}"
               !" m0c2_cu (TODO: CHECK UNITS)"!, &
               !"baryon Msun_geo^{-3}"
      PRINT *, " * Ratio between the two=", &
               MAXVAL( this% nlrf_sph(npart_in:npart_fin), DIM= 1 )/ &
               MINVAL( this% nlrf_sph(npart_in:npart_fin), DIM= 1 )
      PRINT *

      PRINT *, " * Maximum pressure", i_matter, "=", &
               MAXVAL( this% pressure_sph(npart_in:npart_fin), DIM= 1 ) &
               *amu*c_light2/((Msun_geo*km2m*m2cm)**3), " Ba"
               !" m0c2_cu (TODO: CHECK UNITS)"!, &
               !"baryon Msun_geo^{-3}"
      PRINT *, " * Minimum pressure", i_matter, "=", &
               MINVAL( this% pressure_sph(npart_in:npart_fin), DIM= 1 ) &
               *amu*c_light2/((Msun_geo*km2m*m2cm)**3), " Ba"
               !" m0c2_cu (TODO: CHECK UNITS)"!, &
               !"baryon Msun_geo^{-3}"
      PRINT *, " * Ratio between the two=", &
               MAXVAL( this% pressure_sph(npart_in:npart_fin), DIM= 1 )/ &
               MINVAL( this% pressure_sph(npart_in:npart_fin), DIM= 1 )
      PRINT *

      PRINT *, " * Maximum specific internal energy", i_matter, "=", &
               MAXVAL( this% u_sph(npart_in:npart_fin), DIM= 1 ), " c^2"
               !" m0c2_cu (TODO: CHECK UNITS)"!, &
               !"baryon Msun_geo^{-3}"
      PRINT *, " * Minimum specific internal energy", i_matter, "=", &
               MINVAL( this% u_sph(npart_in:npart_fin), DIM= 1 ), " c^2"
               !" m0c2_cu (TODO: CHECK UNITS)"!, &
               !"baryon Msun_geo^{-3}"
      PRINT *, " * Ratio between the two=", &
               MAXVAL( this% u_sph(npart_in:npart_fin), DIM= 1 )/ &
               MINVAL( this% u_sph(npart_in:npart_fin), DIM= 1 )
      PRINT *

      END ASSOCIATE

    ENDDO

    !
    !-- Printing the SPH ID to a binary file, for SPHINCS_BSSN
    !
    IF( this% export_bin )THEN

      IF( PRESENT(namefile) )THEN

        finalnamefile= TRIM(namefile)//"00000"
        dcount= -1 ! since it is increased before writing
        CALL write_SPHINCS_dump(finalnamefile)

      ELSE

        basename= "NSNS."
        dcount= -1 ! since it is increased before writing
        CALL write_SPHINCS_dump()

      ENDIF

    ENDIF


    !-------------!
    ! Diagnostics !
    !-------------!

    !
    !-- Test the recovery
    !
    ! Set tabu_eos to .TRUE. if any of the matter objects use a tabulated EOS
    tabu_eos= .FALSE.
    DO i_matter= 1, this% n_matter, 1

      tabu_eos= tabu_eos &
                .OR. &
                (NINT(this% all_eos(i_matter)% eos_parameters(1)) &
                 == eos$tabu$compose)

    ENDDO
    IF( .NOT.tabu_eos )THEN
    ! TODO: as of 14.04.2023, SPHINCS_BSSN does not support tabulated EOS,
    !       hence the recovery should not be called when using tabulated EOS

      CALL this% test_recovery( this% npart,       &
                                this% pos,         &
                                this% nlrf_sph,    &
                                this% u_sph,       &
                                this% pressure_sph, &
                                this% v(1:3,:),    &
                                this% theta,       &
                                this% nstar_sph )

    ENDIF

    ! Use MODULE variables (DEBUGGING)
    !CALL this% test_recovery( npart,       &
    !                          pos_u,         &
    !                          nlrf,    &
    !                          u,       &
    !                          Pr, &
    !                          vel_u,    &
    !                          Theta,       &
    !                          this% nstar_sph )


    ! Test the recovery on ech matter object separately
    ! DO i_matter= 1, this% n_matter, 1
    !
    !   PRINT *, " * Testing recovery on matter object", i_matter, "..."
    !   PRINT *
    !
    !   IF( i_matter > 9 )THEN
    !     WRITE( i_mat, "(I2)" ) i_matter
    !   ELSE
    !     WRITE( i_mat, "(I1)" ) i_matter
    !   ENDIF
    !   finalnamefile= "recovery_test-"//TRIM(i_mat)//".dat"
    !
    !   ASSOCIATE( npart_in   => this% npart_i(i_matter-1) + 1, &
    !              npart_fin  => this% npart_i(i_matter-1) +    &
    !                            this% npart_i(i_matter) )
    !
    !   CALL this% test_recovery( this% npart_i    (i_matter),               &
    !                             this% pos        (:,npart_in:npart_fin),   &
    !                             this% nlrf_sph   (npart_in:npart_fin),     &
    !                             this% u_sph      (npart_in:npart_fin),     &
    !                             this% pressure_sph(npart_in:npart_fin),     &
    !                             this% v          (1:3,npart_in:npart_fin), &
    !                             this% theta      (npart_in:npart_fin),     &
    !                             this% nstar_sph  (npart_in:npart_fin),     &
    !                             finalnamefile )
    !
    !   END ASSOCIATE
    !
    ! ENDDO

    !CALL exact_nei_tree_update( ndes,        &
    !                            this% npart, &
    !                            this% pos,   &
    !                            this% nu )
    !this% h= h

    CALL compute_and_print_quality_indicators &
      (this% npart, this% pos, this% h, this% nu, this% nstar_sph, &
       TRIM(sph_path))


    ALLOCATE( this% adm_linear_momentum_i( this% n_matter, 3 ) )
    this% adm_linear_momentum_fluid= zero
    DO i_matter= 1, this% n_matter, 1

      PRINT *, " * Estimating the ADM linear momentum using the canonical ", &
               "SPH momentum per baryon on the particles, ", &
               "on matter object ", i_matter, "..."
      PRINT *

      ASSOCIATE( npart_in   => this% npart_i(i_matter-1) + 1, &
                 npart_fin  => this% npart_i(i_matter-1) +    &
                               this% npart_i(i_matter) )

      CALL compute_adm_momentum_fluid_fields(                             &
                                  npart_fin - npart_in + 1,               &
                                  this% lapse(npart_in:npart_fin),        &
                                  this% shift_x(npart_in:npart_fin),      &
                                  this% shift_y(npart_in:npart_fin),      &
                                  this% shift_z(npart_in:npart_fin),      &
                                  this% g_xx(npart_in:npart_fin),         &
                                  this% g_xy(npart_in:npart_fin),         &
                                  this% g_xz(npart_in:npart_fin),         &
                                  this% g_yy(npart_in:npart_fin),         &
                                  this% g_yz(npart_in:npart_fin),         &
                                  this% g_zz(npart_in:npart_fin),         &
                                  this% nu(npart_in:npart_fin),           &
                                  this% Theta(npart_in:npart_fin),        &
                                  this% nlrf_sph(npart_in:npart_fin),     &
                                  this% pressure_sph(npart_in:npart_fin),  &
                                  this% u_sph(npart_in:npart_fin),        &
                                  this% v(1:3,npart_in:npart_fin),        &
                                  this% adm_linear_momentum_i(i_matter,:) )

      PRINT *, "   SPH estimate of the ADM linear momentum computed using ", &
               "the canonical momentum per baryon, on matter object", &
               i_matter,"= "
      PRINT *, "   (", this% adm_linear_momentum_i(i_matter, 1), ","
      PRINT *, "    ", this% adm_linear_momentum_i(i_matter, 2), ","
      PRINT *, "    ", this% adm_linear_momentum_i(i_matter, 3), ") Msun*c"
      PRINT *
      this% adm_linear_momentum_fluid= this% adm_linear_momentum_fluid + &
                                       this% adm_linear_momentum_i(i_matter,:)

      END ASSOCIATE

    ENDDO
    PRINT *, "   SPH estimate of the ADM momentum of the fluid ", &
             "computed using the canonical momentum per baryon= "
    PRINT *, "   (", this% adm_linear_momentum_fluid(1), ","
    PRINT *, "    ", this% adm_linear_momentum_fluid(2), ","
    PRINT *, "    ", this% adm_linear_momentum_fluid(3), ") Msun*c"
    PRINT *


    IF( ASSOCIATED(this% post_process_sph_id) )THEN

      CALL this% post_process_sph_id( this% npart, this% pos, &
                                    this% nlrf_sph, &
                                    this% u_sph, &
                                    this% pressure_sph, this% v(1:3,:), &
                                    this% theta, this% nstar_sph, this% nu, &
                                    this% g_xx,      &
                                    this% g_xy,      &
                                    this% g_xz,      &
                                    this% g_yy,      &
                                    this% g_yz,      &
                                    this% g_zz,      &
                                    this% lapse,     &
                                    this% shift_x,   &
                                    this% shift_y,   &
                                    this% shift_z,   &
                                    this% adm_linear_momentum_fluid, &
                                    this% adm_mass )

    ELSE

      PRINT *, "** ERROR! The PROCEDURE POINTER post_process_sph_id ", &
               "is not associated with any PROCEDURE!"
      PRINT *, " * Stopping..."
      PRINT *
      STOP

    ENDIF

    vel_u= this% v(1:3,:)

    this% adm_linear_momentum_fluid= zero
    DO i_matter= 1, this% n_matter, 1

      PRINT *, " * Estimating the ADM linear momentum using the canonical ", &
               "SPH momentum per baryon on the particles, ", &
               "on matter object ", i_matter, "..."
      PRINT *

      ASSOCIATE( npart_in   => this% npart_i(i_matter-1) + 1, &
                 npart_fin  => this% npart_i(i_matter-1) +    &
                               this% npart_i(i_matter) )

      CALL compute_adm_momentum_fluid_fields(                             &
                                  npart_fin - npart_in + 1,               &
                                  this% lapse(npart_in:npart_fin),        &
                                  this% shift_x(npart_in:npart_fin),      &
                                  this% shift_y(npart_in:npart_fin),      &
                                  this% shift_z(npart_in:npart_fin),      &
                                  this% g_xx(npart_in:npart_fin),         &
                                  this% g_xy(npart_in:npart_fin),         &
                                  this% g_xz(npart_in:npart_fin),         &
                                  this% g_yy(npart_in:npart_fin),         &
                                  this% g_yz(npart_in:npart_fin),         &
                                  this% g_zz(npart_in:npart_fin),         &
                                  this% nu(npart_in:npart_fin),           &
                                  this% Theta(npart_in:npart_fin),        &
                                  this% nlrf_sph(npart_in:npart_fin),     &
                                  this% pressure_sph(npart_in:npart_fin),  &
                                  this% u_sph(npart_in:npart_fin),        &
                                  vel_u(1:3,npart_in:npart_fin),        &
                                  this% adm_linear_momentum_i(i_matter,:) )

      PRINT *, "   SPH estimate of the ADM linear momentum computed using ", &
               "the canonical momentum per baryon, on matter object", &
               i_matter,"= "
      PRINT *, "   (", this% adm_linear_momentum_i(i_matter, 1), ","
      PRINT *, "    ", this% adm_linear_momentum_i(i_matter, 2), ","
      PRINT *, "    ", this% adm_linear_momentum_i(i_matter, 3), ") Msun*c"
      PRINT *
      this% adm_linear_momentum_fluid= this% adm_linear_momentum_fluid + &
                                       this% adm_linear_momentum_i(i_matter,:)

      END ASSOCIATE

    ENDDO
    PRINT *, "   SPH estimate of the ADM momentum of the fluid ", &
             "computed using the canonical momentum per baryon= "
    PRINT *, "   (", this% adm_linear_momentum_fluid(1), ","
    PRINT *, "    ", this% adm_linear_momentum_fluid(2), ","
    PRINT *, "    ", this% adm_linear_momentum_fluid(3), ") Msun*c"
    PRINT *

    !
    !-- Exporting the SPH ID to a binary file, for SPHINCS_BSSN
    !
 !   IF( this% export_bin )THEN
 !
 !     IF( PRESENT(namefile) )THEN
 !
 !       finalnamefile= TRIM( namefile ) // "00000"
 !       dcount= -1 ! since it is increased before writing
 !       CALL write_SPHINCS_dump( finalnamefile )
 !
 !     ELSE
 !
 !       basename= "NSNS."
 !       dcount= -1 ! since it is increased before writing
 !       CALL write_SPHINCS_dump()
 !
 !     ENDIF
 !
 !   ENDIF

    !
    !-- Compute particle number density
    !

    PRINT *, " * Computing particle number density by kernel interpolation..."
    PRINT *
    nu= one
    CALL density_loop( this% npart, this% pos, nu, h, &
                       this% particle_density_sph )

    IF( debug ) PRINT *, "100"

    !CALL COM( this% npart, this% pos, this% nu, &
    !          com_x_newt, com_y_newt, com_z_newt, com_d_newt )
    !CALL COM( this% npart_i(1), this% pos(:,1:this% npart_i(1)), &
    !          this% nu(1:this% npart_i(1)), &
    !          com_x_newt, com_y_newt, com_z_newt, com_d_newt )

    !CALL COM_1PN( this% npart, this% pos, this% v, &
    !              !this% v_euler_x, &
    !              this% nu, this% baryon_density, &
    !              this% specific_energy, this% nstar_sph, sq_detg4, gg4, &
    !              com_x_1pn, com_y_1pn, com_z_1pn, com_d_1pn )
    !CALL COM_1PN( this% npart_i(1), this% pos(:,1:this% npart_i(1)), &
    !              this% v(1:3,1:this% npart_i(1)), &
    !              !this% v_euler_x, &
    !              this% nu(1:this% npart_i(1)), &!/sq_det_g4(1:this% npart_i(1))/this% Theta(1:this% npart_i(1)), &
    !              !this% baryon_density(1:this% npart_i(1)), &
    !              this% nlrf_sph(1:this% npart_i(1)), &
    !              this% u_sph(1:this% npart_i(1)), &
    !              this% nstar_sph(1:this% npart_i(1)), &
    !              sq_det_g4(1:this% npart_i(1)), &
    !              gg4(:,1:this% npart_i(1)), &
    !              com_x_1pn, com_y_1pn, com_z_1pn, com_d_1pn, mass_1pn )

    IF( debug ) PRINT *, "101"

    !nu   = this% nu
    !vel_u= this% v(1:3,:)
    !CALL lin_mom( pnorm_newt, px_newt, py_newt, pz_newt )
    !CALL momentum_1pn( this% npart, this% pos, &
    !                   this% v, &
    !                   !this% v_euler_x, &
    !                   this% nu, this% baryon_density, &
    !                   this% specific_energy, this% pressure_sph, &
    !                   this% nstar_sph, this% h, &
    !                   sq_detg4, gg4, px, py, pz )
    !CALL momentum_1pn( this% npart, this% pos, &
    !                   this% v, &
    !                   !this% v_euler_x, &
    !                   this% nu, &
    !                   this% nlrf_sph, &
    !                   this% u_sph, &
    !                   this% pressure_sph, &
    !                   this% nstar_sph, &
    !                   this% h, &
    !                   sq_detg4, gg4, px, py, pz )

    !PRINT *, "LORENE mass:            ", this% masses(1), mass_1pn*amu/Msun
    !PRINT *, "LORENE COM:            ", &
    !         this% barycenter(1,:)! + this% barycenter(2,:)
    !PRINT *, "Newtonian COM:         ", &
    !         com_x_newt, com_y_newt, com_z_newt!, com_d_newt
    !PRINT *, "1PN COM:               ", &
    !         com_x_1pn, com_y_1pn, com_z_1pn!, com_d_1pn
    !PRINT *, "Newtonian spacetime momentum:", px_newt/SUM(nu,DIM=1), py_newt/SUM(nu,DIM=1), pz_newt/SUM(nu,DIM=1), pnorm_newt/SUM(nu,DIM=1)
    !PRINT *, "1PN spacetime momentum:", px/mass_1pn, py/mass_1pn, pz/mass_1pn, pnorm/mass_1pn
    !PRINT *
    !PRINT *

    !
    !-- Deallocate MODULE variables
    !
    PRINT *, " * Deallocating MODULE variables..."
    PRINT *
    IF( ALLOCATED(g4_ll) ) CALL deallocate_metric_on_particles
    CALL deallocate_gradient
    DEALLOCATE( alive )
    CALL deallocate_RCB_tree_memory_3D
    CALL deallocate_SPH_memory

    !STOP

    call_flag= call_flag + 1
    this% call_flag= call_flag

    PRINT *, "** Subroutine compute_and_print_sph_variables executed."
    PRINT *

  END PROCEDURE compute_and_print_sph_variables


END SUBMODULE sph_variables