module m_turbine_model !! Abstract interface for turbine forcing models (actuator disc, actuator !! line) !! !! A turbine model is a backend-agnostic physics object: it samples the flow !! at actuator points and accumulates a momentum source back onto the RHS !! fields (du, dv, dw). It is owned and driven entirely by the flow case !! (see m_case_wind_turbine) and therefore knows nothing about the solver, !! the case, or the `iturbine` switch - the case decides which concrete model !! to allocate and when to call it. !! !! Concrete implementations: !! - turbine_dummy_t (m_turbine_dummy): no-op / iturbine=0, the fallback !! - alm_t (m_alm) : actuator line model !! - adm_t (m_adm) : actuator disc model use m_allocator, only: allocator_t use m_base_backend, only: base_backend_t use m_common, only: dp use m_checkpoint_state, only: checkpoint_state_t use m_field, only: field_t use m_mesh, only: mesh_t implicit none type, abstract, extends(checkpoint_state_t) :: turbine_model_t contains procedure(init_iface), deferred :: init procedure(update_iface), deferred :: update procedure(project_forces_iface), deferred :: project_forces procedure(write_output_iface), deferred :: write_output procedure(setup_output_iface), deferred :: setup_output procedure(finalise_iface), deferred :: finalise end type turbine_model_t abstract interface subroutine init_iface(self, backend, mesh, host_allocator, dt) !! Set up turbine geometry/state (read config files, place actuator !! points, build smearing kernels, ...). Called once after the solver !! exists. The model caches whatever context it needs (backend, mesh, !! host_allocator) so the per-step hooks below take only fields. import :: turbine_model_t, base_backend_t, mesh_t, allocator_t, dp implicit none class(turbine_model_t), intent(inout) :: self class(base_backend_t), target, intent(in) :: backend type(mesh_t), target, intent(in) :: mesh type(allocator_t), target, intent(in) :: host_allocator real(dp), intent(in) :: dt end subroutine init_iface subroutine update_iface(self, t, dt) !! Advance the turbine internal state (blade kinematics, rotor speed, !! velocity filtering) by one step. Called once per substep before !! project_forces. import :: turbine_model_t, dp implicit none class(turbine_model_t), intent(inout) :: self real(dp), intent(in) :: t, dt end subroutine update_iface subroutine project_forces_iface(self, du, dv, dw, u, v, w) !! Sample the velocity field at the actuator points and accumulate the !! turbine momentum source into the RHS fields du, dv, dw. Uses the !! backend/mesh cached at init. import :: turbine_model_t, field_t implicit none class(turbine_model_t), intent(inout) :: self class(field_t), intent(inout) :: du, dv, dw class(field_t), intent(in) :: u, v, w end subroutine project_forces_iface subroutine write_output_iface(self, iter, is_root) !! Write per-turbine diagnostics (power, thrust, loads). import :: turbine_model_t implicit none class(turbine_model_t), intent(inout) :: self integer, intent(in) :: iter logical, intent(in) :: is_root end subroutine write_output_iface subroutine setup_output_iface(self, is_root, append) import :: turbine_model_t class(turbine_model_t), intent(inout) :: self logical, intent(in) :: is_root, append end subroutine setup_output_iface subroutine finalise_iface(self) import :: turbine_model_t class(turbine_model_t), intent(inout) :: self end subroutine finalise_iface end interface end module m_turbine_model