postprocess.f90 Source File


This file depends on

sourcefile~~postprocess.f90~~EfferentGraph sourcefile~postprocess.f90 postprocess.f90 sourcefile~common.f90~3 common.f90 sourcefile~postprocess.f90->sourcefile~common.f90~3 sourcefile~field.f90 field.f90 sourcefile~postprocess.f90->sourcefile~field.f90 sourcefile~solver.f90 solver.f90 sourcefile~postprocess.f90->sourcefile~solver.f90 sourcefile~field.f90->sourcefile~common.f90~3 sourcefile~solver.f90->sourcefile~common.f90~3 sourcefile~solver.f90->sourcefile~field.f90 sourcefile~allocator.f90 allocator.f90 sourcefile~solver.f90->sourcefile~allocator.f90 sourcefile~backend.f90~3 backend.f90 sourcefile~solver.f90->sourcefile~backend.f90~3 sourcefile~config.f90 config.f90 sourcefile~solver.f90->sourcefile~config.f90 sourcefile~ibm.f90 ibm.f90 sourcefile~solver.f90->sourcefile~ibm.f90 sourcefile~mesh.f90 mesh.f90 sourcefile~solver.f90->sourcefile~mesh.f90 sourcefile~tdsops.f90~2 tdsops.f90 sourcefile~solver.f90->sourcefile~tdsops.f90~2 sourcefile~time_integrator.f90 time_integrator.f90 sourcefile~solver.f90->sourcefile~time_integrator.f90 sourcefile~vector_calculus.f90 vector_calculus.f90 sourcefile~solver.f90->sourcefile~vector_calculus.f90 sourcefile~allocator.f90->sourcefile~common.f90~3 sourcefile~allocator.f90->sourcefile~field.f90 sourcefile~backend.f90~3->sourcefile~common.f90~3 sourcefile~backend.f90~3->sourcefile~field.f90 sourcefile~backend.f90~3->sourcefile~allocator.f90 sourcefile~backend.f90~3->sourcefile~mesh.f90 sourcefile~backend.f90~3->sourcefile~tdsops.f90~2 sourcefile~poisson_fft.f90~3 poisson_fft.f90 sourcefile~backend.f90~3->sourcefile~poisson_fft.f90~3 sourcefile~config.f90->sourcefile~common.f90~3 sourcefile~ibm.f90->sourcefile~common.f90~3 sourcefile~ibm.f90->sourcefile~field.f90 sourcefile~ibm.f90->sourcefile~allocator.f90 sourcefile~ibm.f90->sourcefile~backend.f90~3 sourcefile~ibm.f90->sourcefile~mesh.f90 sourcefile~io_session.f90 io_session.f90 sourcefile~ibm.f90->sourcefile~io_session.f90 sourcefile~mesh.f90->sourcefile~common.f90~3 sourcefile~mesh.f90->sourcefile~field.f90 sourcefile~decomp_dummy.f90 decomp_dummy.f90 sourcefile~mesh.f90->sourcefile~decomp_dummy.f90 sourcefile~mesh_content.f90 mesh_content.f90 sourcefile~mesh.f90->sourcefile~mesh_content.f90 sourcefile~tdsops.f90~2->sourcefile~common.f90~3 sourcefile~time_integrator.f90->sourcefile~common.f90~3 sourcefile~time_integrator.f90->sourcefile~field.f90 sourcefile~time_integrator.f90->sourcefile~allocator.f90 sourcefile~time_integrator.f90->sourcefile~backend.f90~3 sourcefile~vector_calculus.f90->sourcefile~common.f90~3 sourcefile~vector_calculus.f90->sourcefile~field.f90 sourcefile~vector_calculus.f90->sourcefile~allocator.f90 sourcefile~vector_calculus.f90->sourcefile~backend.f90~3 sourcefile~vector_calculus.f90->sourcefile~tdsops.f90~2 sourcefile~decomp_dummy.f90->sourcefile~mesh_content.f90 sourcefile~io_session.f90->sourcefile~common.f90~3 sourcefile~io.f90 io.f90 sourcefile~io_session.f90->sourcefile~io.f90 sourcefile~io_base.f90 io_base.f90 sourcefile~io_session.f90->sourcefile~io_base.f90 sourcefile~mesh_content.f90->sourcefile~common.f90~3 sourcefile~poisson_fft.f90~3->sourcefile~common.f90~3 sourcefile~poisson_fft.f90~3->sourcefile~field.f90 sourcefile~poisson_fft.f90~3->sourcefile~mesh.f90 sourcefile~poisson_fft.f90~3->sourcefile~tdsops.f90~2 sourcefile~io.f90->sourcefile~common.f90~3 sourcefile~io.f90->sourcefile~io_base.f90 sourcefile~io_base.f90->sourcefile~common.f90~3

Files dependent on this one

sourcefile~~postprocess.f90~~AfferentGraph sourcefile~postprocess.f90 postprocess.f90 sourcefile~base_case.f90 base_case.f90 sourcefile~base_case.f90->sourcefile~postprocess.f90 sourcefile~channel.f90 channel.f90 sourcefile~channel.f90->sourcefile~base_case.f90 sourcefile~cylinder.f90 cylinder.f90 sourcefile~cylinder.f90->sourcefile~base_case.f90 sourcefile~generic.f90 generic.f90 sourcefile~generic.f90->sourcefile~base_case.f90 sourcefile~tgv.f90 tgv.f90 sourcefile~tgv.f90->sourcefile~base_case.f90 sourcefile~xcompact.f90 xcompact.f90 sourcefile~xcompact.f90->sourcefile~base_case.f90 sourcefile~xcompact.f90->sourcefile~channel.f90 sourcefile~xcompact.f90->sourcefile~cylinder.f90 sourcefile~xcompact.f90->sourcefile~generic.f90 sourcefile~xcompact.f90->sourcefile~tgv.f90

Source Code

module m_postprocess
  !! Computation of derived fields for snapshot output.
  !!
  !! Provides routines to compute quantities that are not part of
  !! the core time-stepping algorithm but are useful for analysis
  !! and visualisation (e.g. pressure on the vertex grid, vorticity
  !! magnitude, Q-criterion).

  use m_common, only: dp, DIR_X, DIR_Y, DIR_Z, VERT, &
                      RDR_X2Y, RDR_X2Z, RDR_Y2X, RDR_Z2X
  use m_field, only: field_t
  use m_solver, only: solver_t

  implicit none

  private
  public :: compute_derived_fields, compute_pressure_vert

contains

  subroutine compute_derived_fields(solver, output_vorticity, &
                                    output_qcriterion)
    !! Compute derived fields from the velocity gradient tensor.
    !!
    !! All 9 components of the velocity gradient tensor are computed
    !! once, then used to evaluate whichever quantities are enabled
    !! (vorticity magnitude, Q-criterion).
    implicit none

    class(solver_t), intent(inout) :: solver
    logical, intent(in) :: output_vorticity, output_qcriterion

    class(field_t), pointer :: &
      dudx, dudy_x, dudz_x, &
      dvdx, dvdy_x, dvdz_x, &
      dwdx, dwdy_x, dwdz_x
    class(field_t), pointer :: &
      u_y, dudy_y, u_z, dudz_z, &
      v_y, dvdy_y, v_z, dvdz_z, &
      w_y, dwdy_y, w_z, dwdz_z

    ! Lazily allocate output fields
    if (output_vorticity .and. .not. associated(solver%vort)) &
      solver%vort => solver%backend%allocator%get_block(DIR_X, VERT)
    if (output_qcriterion .and. .not. associated(solver%qcrit)) &
      solver%qcrit => solver%backend%allocator%get_block(DIR_X, VERT)

    ! --- Compute all 9 velocity gradient components ---

    ! du/dx (x-derivative in x-pencil, no reorder needed)
    dudx => solver%backend%allocator%get_block(DIR_X)
    call solver%backend%tds_solve(dudx, solver%u, &
                                  solver%xdirps%der1st)

    ! dv/dx
    dvdx => solver%backend%allocator%get_block(DIR_X)
    call solver%backend%tds_solve(dvdx, solver%v, &
                                  solver%xdirps%der1st)

    ! dw/dx
    dwdx => solver%backend%allocator%get_block(DIR_X)
    call solver%backend%tds_solve(dwdx, solver%w, &
                                  solver%xdirps%der1st)

    ! du/dy
    u_y => solver%backend%allocator%get_block(DIR_Y)
    dudy_y => solver%backend%allocator%get_block(DIR_Y)
    call solver%backend%reorder(u_y, solver%u, RDR_X2Y)
    call solver%backend%tds_solve(dudy_y, u_y, &
                                  solver%ydirps%der1st)
    dudy_x => solver%backend%allocator%get_block(DIR_X)
    call solver%backend%reorder(dudy_x, dudy_y, RDR_Y2X)
    call solver%backend%allocator%release_block(u_y)
    call solver%backend%allocator%release_block(dudy_y)

    ! dv/dy
    v_y => solver%backend%allocator%get_block(DIR_Y)
    dvdy_y => solver%backend%allocator%get_block(DIR_Y)
    call solver%backend%reorder(v_y, solver%v, RDR_X2Y)
    call solver%backend%tds_solve(dvdy_y, v_y, &
                                  solver%ydirps%der1st)
    dvdy_x => solver%backend%allocator%get_block(DIR_X)
    call solver%backend%reorder(dvdy_x, dvdy_y, RDR_Y2X)
    call solver%backend%allocator%release_block(v_y)
    call solver%backend%allocator%release_block(dvdy_y)

    ! dw/dy
    w_y => solver%backend%allocator%get_block(DIR_Y)
    dwdy_y => solver%backend%allocator%get_block(DIR_Y)
    call solver%backend%reorder(w_y, solver%w, RDR_X2Y)
    call solver%backend%tds_solve(dwdy_y, w_y, &
                                  solver%ydirps%der1st)
    dwdy_x => solver%backend%allocator%get_block(DIR_X)
    call solver%backend%reorder(dwdy_x, dwdy_y, RDR_Y2X)
    call solver%backend%allocator%release_block(w_y)
    call solver%backend%allocator%release_block(dwdy_y)

    ! du/dz
    u_z => solver%backend%allocator%get_block(DIR_Z)
    dudz_z => solver%backend%allocator%get_block(DIR_Z)
    call solver%backend%reorder(u_z, solver%u, RDR_X2Z)
    call solver%backend%tds_solve(dudz_z, u_z, &
                                  solver%zdirps%der1st)
    dudz_x => solver%backend%allocator%get_block(DIR_X)
    call solver%backend%reorder(dudz_x, dudz_z, RDR_Z2X)
    call solver%backend%allocator%release_block(u_z)
    call solver%backend%allocator%release_block(dudz_z)

    ! dv/dz
    v_z => solver%backend%allocator%get_block(DIR_Z)
    dvdz_z => solver%backend%allocator%get_block(DIR_Z)
    call solver%backend%reorder(v_z, solver%v, RDR_X2Z)
    call solver%backend%tds_solve(dvdz_z, v_z, &
                                  solver%zdirps%der1st)
    dvdz_x => solver%backend%allocator%get_block(DIR_X)
    call solver%backend%reorder(dvdz_x, dvdz_z, RDR_Z2X)
    call solver%backend%allocator%release_block(v_z)
    call solver%backend%allocator%release_block(dvdz_z)

    ! dw/dz
    w_z => solver%backend%allocator%get_block(DIR_Z)
    dwdz_z => solver%backend%allocator%get_block(DIR_Z)
    call solver%backend%reorder(w_z, solver%w, RDR_X2Z)
    call solver%backend%tds_solve(dwdz_z, w_z, &
                                  solver%zdirps%der1st)
    dwdz_x => solver%backend%allocator%get_block(DIR_X)
    call solver%backend%reorder(dwdz_x, dwdz_z, RDR_Z2X)
    call solver%backend%allocator%release_block(w_z)
    call solver%backend%allocator%release_block(dwdz_z)

    ! All 9 derivatives now in x-pencil layout:
    ! dudx, dudy_x, dudz_x
    ! dvdx, dvdy_x, dvdz_x
    ! dwdx, dwdy_x, dwdz_x

    ! Vorticity magnitude:
    ! |w| = sqrt((dw/dy-dv/dz)^2+(du/dz-dw/dx)^2+(dv/dx-du/dy)^2)
    if (output_vorticity) then
      solver%vort%data = sqrt( &
                         (dwdy_x%data - dvdz_x%data)**2 + &
                         (dudz_x%data - dwdx%data)**2 + &
                         (dvdx%data - dudy_x%data)**2 &
                         )
    end if

    ! Q-criterion:
    ! Q = -0.5*(dudx^2+dvdy^2+dwdz^2)
    !     - dudy*dvdx - dudz*dwdx - dvdz*dwdy
    if (output_qcriterion) then
      solver%qcrit%data = &
        -0.5_dp*(dudx%data**2 &
                 + dvdy_x%data**2 &
                 + dwdz_x%data**2) &
        - dudy_x%data*dvdx%data &
        - dudz_x%data*dwdx%data &
        - dvdz_x%data*dwdy_x%data
    end if

    ! Release all gradient fields
    call solver%backend%allocator%release_block(dudx)
    call solver%backend%allocator%release_block(dvdx)
    call solver%backend%allocator%release_block(dwdx)
    call solver%backend%allocator%release_block(dudy_x)
    call solver%backend%allocator%release_block(dvdy_x)
    call solver%backend%allocator%release_block(dwdy_x)
    call solver%backend%allocator%release_block(dudz_x)
    call solver%backend%allocator%release_block(dvdz_x)
    call solver%backend%allocator%release_block(dwdz_x)

  end subroutine compute_derived_fields

  subroutine compute_pressure_vert(solver)
    !! Interpolates the pressure field from CELL (DIR_Z) to VERT
    !! (DIR_X) for snapshot output and rescales from pseudo-pressure
    !! to physical (kinematic) pressure.
    implicit none

    class(solver_t), intent(inout) :: solver

    if (.not. associated(solver%pressure)) then
      error stop 'compute_pressure_vert: pressure not yet computed'
    end if

    ! Lazy allocate pressure_vert on first call
    if (.not. associated(solver%pressure_vert)) then
      solver%pressure_vert => &
        solver%backend%allocator%get_block(DIR_X, VERT)
    end if

    call solver%vector_calculus%interpl_c2v( &
      solver%pressure_vert, solver%pressure, &
      solver%xdirps%interpl_p2v, &
      solver%ydirps%interpl_p2v, &
      solver%zdirps%interpl_p2v &
      )

    ! Rescale pseudo-pressure to physical pressure: p'/dt -> p
    call solver%backend%vecadd( &
      1._dp/solver%dt, solver%pressure_vert, &
      0._dp, solver%pressure_vert &
      )

  end subroutine compute_pressure_vert

end module m_postprocess