Orchestrates one full fractional-step iteration.
This routine implements the high-level logic of the projection method. It coordinates the explicit momentum update, the elliptic pressure solve, and the final divergence-free correction.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(mesh_t), | intent(in) | :: | mesh |
The computational mesh. |
||
| type(flow_mpi_t), | intent(inout) | :: | flow |
MPI decomposition context. |
||
| type(bc_set_t), | intent(in) | :: | bc |
Boundary condition set. |
||
| type(case_params_t), | intent(in) | :: | params |
Case parameters (dt, rho, etc). |
||
| type(transport_properties_t), | intent(in) | :: | transport |
Physical property fields. |
||
| type(flow_fields_t), | intent(inout) | :: | fields |
Flow field containers to be updated. |
||
| type(solver_stats_t), | intent(inout) | :: | stats |
Diagnostic stats to be populated. |
subroutine advance_projection_step(mesh, flow, bc, params, transport, fields, stats) 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(transport_properties_t), intent(in) :: transport type(flow_fields_t), intent(inout) :: fields type(solver_stats_t), intent(inout) :: stats integer :: c integer, save :: projection_step_counter = 0 logical :: do_projection_diagnostics projection_step_counter = projection_step_counter + 1 do_projection_diagnostics = (mod(projection_step_counter, params%output_interval) == 0) .or. & (projection_step_counter == params%nsteps) call ensure_projection_workspace(mesh) call ensure_pressure_operator_cache(mesh, flow, bc) associate( & local_vec => projection_work%local_vec, & local_scalar => projection_work%local_scalar, & rhs_poisson => projection_work%rhs_poisson, & local_face_flux => projection_work%local_face_flux, & local_vec_star => projection_work%local_vec_star, & predicted_face_flux => projection_work%predicted_face_flux) ! 1. Predictor: Compute Explicit momentum RHS and Advance intermediate velocity u* call profiler_start('Projection_Momentum_RHS') call compute_momentum_rhs(mesh, flow, bc, params, transport, fields%u, fields%p, local_vec) call profiler_stop('Projection_Momentum_RHS') ! 2. Advance intermediate velocity u* locally ! This uses the PREVIOUS fields%rhs_old and the CURRENT local_vec call profiler_start('Projection_AB2') call advance_ab2(mesh, flow, params, fields, local_vec, local_vec_star) call profiler_stop('Projection_AB2') ! Store current RHS for next step (AB2) ! rhs_old is effectively partitioned; each rank only needs its owned cell values. fields%rhs_old = local_vec fields%rhs_old_valid = .true. fields%u_star = local_vec_star call profiler_start('Projection_Predict_Flux') call profiler_start('PredictFlux_Exchange_UStar') call flow_exchange_cell_matrix(flow, fields%u_star) call profiler_stop('PredictFlux_Exchange_UStar') ! 3. Interpolate predicted cell velocity to intermediate face fluxes call profiler_start('PredictFlux_Compute') call compute_predicted_face_flux(mesh, flow, bc, fields%u_star, predicted_face_flux) call profiler_stop('PredictFlux_Compute') ! 3b. Balance mass at open boundaries to prevent drift in closed-loop systems call profiler_start('PredictFlux_Balance') call balance_neumann_outlet_flux(mesh, flow, bc, predicted_face_flux) call profiler_stop('PredictFlux_Balance') call profiler_start('PredictFlux_Exchange_Face') call flow_exchange_face_scalar(flow, predicted_face_flux) call profiler_stop('PredictFlux_Exchange_Face') call profiler_stop('Projection_Predict_Flux') ! 4. Construct the Poisson RHS: b = -rho/dt * div(u*) call profiler_start('Projection_Poisson_RHS') call compute_flux_divergence(mesh, flow, predicted_face_flux, local_scalar) fields%div = local_scalar rhs_poisson = zero do c = flow%first_cell, flow%last_cell rhs_poisson(c) = -params%rho / params%dt * & fields%div(c) * mesh%cells(c)%volume end do ! Floating pressure handle: pin first cell if no Dirichlet BC exists if (.not. pressure_cache%has_dirichlet_pressure) then rhs_poisson(1) = zero end if fields%phi = zero call profiler_stop('Projection_Poisson_RHS') ! Solve Laplacian system for potential phi call profiler_start('Projection_PCG') call solve_pressure_correction(mesh, flow, bc, params, rhs_poisson, fields%phi, stats) call profiler_stop('Projection_PCG') ! 5. Update Pressure: p(n+1) = p(n) + phi call profiler_start('Projection_Pressure_Update') do c = flow%first_cell, flow%last_cell fields%p(c) = fields%p(c) + fields%phi(c) end do if (.not. pressure_cache%has_dirichlet_pressure) then fields%p(1) = zero end if call flow_exchange_cell_scalar(flow, fields%p) call profiler_stop('Projection_Pressure_Update') ! 6. Correct face fluxes and cell-centered velocity locally call profiler_start('Projection_Correction') call correct_face_flux(mesh, flow, bc, params, predicted_face_flux, fields%phi, local_face_flux) fields%face_flux = local_face_flux call flow_exchange_face_scalar(flow, fields%face_flux) call correct_cell_velocity(mesh, flow, bc, params, fields%u_star, fields%phi, local_vec) ! 7. Keep velocity ghosts current for the next predictor/species step. fields%u = local_vec call flow_exchange_cell_matrix(flow, fields%u) ! Divergence is only needed for diagnostics/output, so avoid computing ! and exchanging it on non-output steps. if (do_projection_diagnostics) then call compute_flux_divergence(mesh, flow, fields%face_flux, local_scalar) fields%div = local_scalar call flow_exchange_cell_scalar(flow, fields%div) end if call profiler_stop('Projection_Correction') if (do_projection_diagnostics) then call profiler_start('Projection_Diagnostics') call compute_flow_diagnostics(mesh, flow, bc, params, fields, stats) call profiler_stop('Projection_Diagnostics') end if end associate end subroutine advance_projection_step