advance_species_transport Subroutine

public subroutine advance_species_transport(mesh, flow, bc, params, fields, species, transport)

Performs one explicit Euler step for species transport.

This routine evaluates: - Advective Fluxes: . - Diffusive Fluxes: . - Flux Correction: Subtracts to satisfy mass conservation. - Bounding & Normalization: Clamps and enforces locally.

Arguments

Type IntentOptional Attributes Name
type(mesh_t), intent(in) :: mesh

The computational mesh.

type(flow_mpi_t), intent(inout) :: flow

MPI decomposition data for synchronization.

type(bc_set_t), intent(in) :: bc

Boundary condition settings.

type(case_params_t), intent(in) :: params

Simulation parameters (dt, etc).

type(flow_fields_t), intent(in) :: fields

Flow field (velocity/face fluxes).

type(species_fields_t), intent(inout) :: species

Mass fraction fields to update.

type(transport_properties_t), intent(in) :: transport

Physical properties (diffusivities).


Calls

proc~~advance_species_transport~~CallsGraph proc~advance_species_transport mod_species::advance_species_transport proc~boundary_species mod_bc::boundary_species proc~advance_species_transport->proc~boundary_species proc~face_effective_neighbor mod_bc::face_effective_neighbor proc~advance_species_transport->proc~face_effective_neighbor proc~face_normal_distance mod_flow_projection::face_normal_distance proc~advance_species_transport->proc~face_normal_distance proc~flow_exchange_cell_matrix mod_mpi_flow::flow_exchange_cell_matrix proc~advance_species_transport->proc~flow_exchange_cell_matrix proc~is_periodic_face mod_bc::is_periodic_face proc~face_effective_neighbor->proc~is_periodic_face proc~fatal_error mod_kinds::fatal_error proc~face_normal_distance->proc~fatal_error proc~outward_normal mod_flow_projection::outward_normal proc~face_normal_distance->proc~outward_normal proc~patch_type_for_face mod_bc::patch_type_for_face proc~face_normal_distance->proc~patch_type_for_face mpi_irecv mpi_irecv proc~flow_exchange_cell_matrix->mpi_irecv mpi_isend mpi_isend proc~flow_exchange_cell_matrix->mpi_isend mpi_waitall mpi_waitall proc~flow_exchange_cell_matrix->mpi_waitall proc~check_mpi~2 mod_mpi_flow::check_mpi proc~flow_exchange_cell_matrix->proc~check_mpi~2 proc~flow_exchange_cell_matrix->proc~fatal_error proc~profiler_start mod_profiler::profiler_start proc~flow_exchange_cell_matrix->proc~profiler_start proc~profiler_stop mod_profiler::profiler_stop proc~flow_exchange_cell_matrix->proc~profiler_stop proc~check_mpi~2->proc~fatal_error proc~is_periodic_face->proc~patch_type_for_face mpi_wtime mpi_wtime proc~profiler_start->mpi_wtime proc~find_or_create_timer mod_profiler::find_or_create_timer proc~profiler_start->proc~find_or_create_timer proc~profiler_stop->mpi_wtime proc~profiler_stop->proc~find_or_create_timer proc~record_edge mod_profiler::record_edge proc~profiler_stop->proc~record_edge

Called by

proc~~advance_species_transport~~CalledByGraph proc~advance_species_transport mod_species::advance_species_transport program~lowmach_react_hex lowmach_react_hex program~lowmach_react_hex->proc~advance_species_transport

Source Code

   subroutine advance_species_transport(mesh, flow, bc, params, fields, species, transport)
      type(mesh_t), intent(in) :: mesh
      type(flow_mpi_t), intent(inout) :: flow
      type(bc_set_t), intent(in) :: bc
      type(case_params_t), intent(in) :: params
      type(flow_fields_t), intent(in) :: fields
      type(species_fields_t), intent(inout) :: species
      type(transport_properties_t), intent(in) :: transport

      real(rk), allocatable :: dY(:), diff_flux(:), adv_flux(:), Y_face_lin(:)
      real(rk) :: flux, face_area, dist, sum_diff_flux
      real(rk) :: Y_cell, Y_other, Y_face
      real(rk) :: diff_face
      integer :: c, f, fid, neighbor
      integer :: k
      real(rk) :: sum_Y
      logical :: is_dirichlet

      if (species%nspecies <= 0) return

      allocate(dY(species%nspecies))
      allocate(diff_flux(species%nspecies))
      allocate(adv_flux(species%nspecies))
      allocate(Y_face_lin(species%nspecies))

      species%Y_old = species%Y

      ! Iterate through MPI-owned cells
      do c = flow%first_cell, flow%last_cell
         dY = zero

         do f = 1, mesh%ncell_faces(c)
            fid = mesh%cell_faces(f,c)
            if (mesh%faces(fid)%owner == c) then
               flux = fields%face_flux(fid)
            else
               flux = -fields%face_flux(fid)
            end if
            neighbor = face_effective_neighbor(mesh, bc, fid, c)

            face_area = mesh%faces(fid)%area
            dist = face_normal_distance(mesh, bc, fid, c, neighbor)

            sum_diff_flux = zero
            do k = 1, species%nspecies
               Y_cell = species%Y_old(k, c)
               
               if (neighbor == 0) then
                  call boundary_species(mesh, bc, fid, k, Y_cell, Y_other, is_dirichlet)
               else
                  Y_other = species%Y_old(k, neighbor)
                  is_dirichlet = .true.
               end if

               ! 1. Advective flux using Upwind discretization.
               ! flux is oriented outward from the current cell.
               if (flux > zero) then
                  Y_face = Y_cell
               else
                  Y_face = Y_other
               end if
               adv_flux(k) = -flux * Y_face

               ! 2. Diffusive flux using central difference
               diff_flux(k) = zero
               if (neighbor /= 0 .or. is_dirichlet) then
                  if (neighbor == 0) then
                     diff_face = transport%diffusivity(k, c)
                  else
                     diff_face = 0.5_rk * (transport%diffusivity(k, c) + transport%diffusivity(k, neighbor))
                  end if
                  diff_flux(k) = diff_face * (Y_other - Y_cell) / dist * face_area
               end if
               
               sum_diff_flux = sum_diff_flux + diff_flux(k)
               Y_face_lin(k) = 0.5_rk * (Y_cell + Y_other)
            end do

            ! 3. Apply Correction Velocity to ensure mass conservation: sum(j_k) = 0
            do k = 1, species%nspecies
               dY(k) = dY(k) + adv_flux(k) + (diff_flux(k) - Y_face_lin(k) * sum_diff_flux)
            end do
         end do

         ! Explicit timestep update
         do k = 1, species%nspecies
            species%Y(k,c) = species%Y_old(k,c) + params%dt * dY(k) / mesh%cells(c)%volume
            
            ! Ensure boundedness: Y_k must remain in [0, 1]
            if (species%Y(k,c) < zero) species%Y(k,c) = zero
            if (species%Y(k,c) > one)  species%Y(k,c) = one
         end do

         ! Local renormalization: sum(Y_k) = 1
         sum_Y = zero
         do k = 1, species%nspecies
            sum_Y = sum_Y + species%Y(k,c)
         end do

         if (sum_Y > zero) then
            do k = 1, species%nspecies
               species%Y(k,c) = species%Y(k,c) / sum_Y
            end do
         end if
      end do

      deallocate(dY)
      deallocate(diff_flux)
      deallocate(adv_flux)
      deallocate(Y_face_lin)

      ! Synchronize updated species ghosts for the next transport/property step.
      call flow_exchange_cell_matrix(flow, species%Y)

   end subroutine advance_species_transport