core_update_state_impl Subroutine

public subroutine core_update_state_impl(plan, state, src_q, mpi)

ソース電荷から FMM state を更新する。

Arguments

Type IntentOptional Attributes Name
type(fmm_plan_type), intent(in) :: plan

構築済みの FMM 計画。

type(fmm_state_type), intent(inout) :: state

更新対象の state。

real(kind=dp), intent(in) :: src_q(:)
type(mpi_context), intent(in), optional :: mpi

与えると M2L の target node を rank で分担し、局所展開を allgather で揃える。


Calls

proc~~core_update_state_impl~~CallsGraph proc~core_update_state_impl core_update_state_impl proc~active_tree_level_bounds active_tree_level_bounds proc~core_update_state_impl->proc~active_tree_level_bounds proc~active_tree_level_node active_tree_level_node proc~core_update_state_impl->proc~active_tree_level_node proc~active_tree_max_depth active_tree_max_depth proc~core_update_state_impl->proc~active_tree_max_depth proc~initialize_fmm_state initialize_fmm_state proc~core_update_state_impl->proc~initialize_fmm_state proc~mpi_allgatherv_inplace_i32 mpi_allgatherv_inplace_i32 proc~core_update_state_impl->proc~mpi_allgatherv_inplace_i32 proc~mpi_allgatherv_inplace_real_dp mpi_allgatherv_inplace_real_dp proc~core_update_state_impl->proc~mpi_allgatherv_inplace_real_dp proc~mpi_get_rank_size mpi_get_rank_size proc~core_update_state_impl->proc~mpi_get_rank_size proc~refresh_periodic_shell_mean_state refresh_periodic_shell_mean_state proc~core_update_state_impl->proc~refresh_periodic_shell_mean_state proc~refresh_periodic_zero_mode_state refresh_periodic_zero_mode_state proc~core_update_state_impl->proc~refresh_periodic_zero_mode_state proc~reset_periodic_shell_mean_state reset_periodic_shell_mean_state proc~initialize_fmm_state->proc~reset_periodic_shell_mean_state proc~integrate_local_polynomial integrate_local_polynomial proc~refresh_periodic_zero_mode_state->proc~integrate_local_polynomial proc~locate_zero_mode_interval locate_zero_mode_interval proc~refresh_periodic_zero_mode_state->proc~locate_zero_mode_interval proc~zero_mode_charge_primitive zero_mode_charge_primitive proc~refresh_periodic_zero_mode_state->proc~zero_mode_charge_primitive proc~zero_mode_interval_origin zero_mode_interval_origin proc~refresh_periodic_zero_mode_state->proc~zero_mode_interval_origin proc~zero_mode_heights_coincide zero_mode_heights_coincide proc~locate_zero_mode_interval->proc~zero_mode_heights_coincide proc~zero_mode_charge_primitive->proc~integrate_local_polynomial proc~zero_mode_charge_primitive->proc~zero_mode_interval_origin

Source Code

  subroutine core_update_state_impl(plan, state, src_q, mpi)
    type(fmm_plan_type), intent(in) :: plan
    type(fmm_state_type), intent(inout) :: state
    real(dp), intent(in) :: src_q(:)
    type(mpi_context), intent(in), optional :: mpi
    integer(i32) :: n_target_nodes, source_idx, cell, rank, rank_count, block_begin, block_end
    integer(i32), allocatable :: block_counts(:), block_offsets(:)
    real(dp) :: total_charge, e_bottom, phi_gauge, z_gauge

    if (.not. plan%built) error stop 'FMM plan is not built.'
    if (size(src_q) /= plan%nsrc) error stop 'src_q size does not match plan.'

    state%ready = .false.
    call ensure_state_capacity(plan, state)
    if (plan%periodic_k0_ready) then
      total_charge = sum(src_q)
      z_gauge = plan%periodic_k0_plan%break_z(1)
      e_bottom = -0.5_dp*total_charge/(eps0*plan%periodic_k0_plan%area_xy)
      phi_gauge = 0.0_dp
      do source_idx = 1_i32, plan%nsrc
        phi_gauge = phi_gauge - 0.5_dp*src_q(source_idx)* &
                    (sum(plan%periodic_k0_plan%panel(source_idx)%z)/3.0_dp - z_gauge)/ &
                    (eps0*plan%periodic_k0_plan%area_xy)
      end do
      call refresh_periodic_zero_mode_state( &
        plan%periodic_k0_plan, src_q, e_bottom, z_gauge, phi_gauge, state%periodic_k0_state &
        )
      call refresh_periodic_shell_mean_state(plan%periodic_shell_mean, src_q, state%periodic_shell_mean_state)
    end if
    if (plan%periodic_root_operator_ready) then
      if (allocated(state%periodic_multipole)) then
        if (any(shape(state%periodic_multipole) /= [plan%ncoef, plan%periodic_root_source_count])) then
          deallocate (state%periodic_multipole)
        end if
      end if
      if (.not. allocated(state%periodic_multipole)) then
        allocate (state%periodic_multipole(plan%ncoef, plan%periodic_root_source_count))
      end if
      state%periodic_multipole = 0.0_dp
      do source_idx = 1_i32, plan%nsrc
        cell = plan%periodic_source_cell(source_idx)
        state%periodic_multipole(:, cell) = state%periodic_multipole(:, cell) + &
                                            src_q(source_idx)*plan%periodic_source_p2m_basis(:, source_idx)
      end do
      if (allocated(state%anchor_local)) then
        if (any(shape(state%anchor_local) /= [plan%ncoef, plan%periodic_operator_anchor_count])) then
          deallocate (state%anchor_local, state%anchor_local_active)
        end if
      end if
      if (.not. allocated(state%anchor_local)) then
        allocate (state%anchor_local(plan%ncoef, plan%periodic_operator_anchor_count), &
                  state%anchor_local_active(plan%periodic_operator_anchor_count))
      end if
      state%anchor_local = 0.0_dp
      state%anchor_local_active = 0_i32
    end if
    n_target_nodes = merge(plan%target_nnode, plan%nnode, plan%target_tree_ready)
    rank = 0_i32
    rank_count = 1_i32
    if (present(mpi)) call mpi_get_rank_size(rank, rank_count, mpi)
    call m2l_rank_blocks(plan, n_target_nodes, rank_count, block_counts, block_offsets)
    block_begin = block_offsets(rank + 1_i32) + 1_i32
    block_end = block_offsets(rank + 1_i32) + block_counts(rank + 1_i32)
    !$omp parallel default(none) shared(plan, state, src_q, n_target_nodes, block_begin, block_end)
    if (associated(state%multipole_active)) then
      !$omp workshare
      state%multipole_active = 0_i32
      !$omp end workshare
    end if
    if (associated(state%local_active)) then
      !$omp workshare
      state%local_active = 0_i32
      !$omp end workshare
    end if
    if (plan%nsrc > 0_i32) then
      !$omp workshare
      state%src_q = src_q
      !$omp end workshare
    end if
    if (plan%nsource_leaf <= 0_i32 .and. associated(state%multipole)) then
      !$omp workshare
      state%multipole = 0.0d0
      !$omp end workshare
    end if
    if (plan%m2l_pair_count <= 0_i32 .and. associated(state%local)) then
      !$omp workshare
      state%local = 0.0d0
      !$omp end workshare
    end if

    call p2m_leaf_moments(plan, state)
    call m2m_upward_pass(plan, state)
    if (n_target_nodes > 0_i32) call m2l_accumulate(plan, state, block_begin, block_end)
    !$omp end parallel

    if (rank_count > 1_i32 .and. n_target_nodes > 0_i32 .and. plan%m2l_pair_count > 0_i32) then
      call mpi_allgatherv_inplace_real_dp(mpi, state%local, block_counts*plan%ncoef, block_offsets*plan%ncoef)
      call mpi_allgatherv_inplace_i32(mpi, state%local_active, block_counts, block_offsets)
    end if

    !$omp parallel default(none) shared(plan, state, n_target_nodes)
    if (n_target_nodes > 0_i32) then
      call apply_periodic_target_correction(plan, state)
      call l2l_downward_pass(plan, state)
    end if
    !$omp end parallel

    state%ready = .true.
    state%update_count = state%update_count + 1_i32
  end subroutine core_update_state_impl