adjacency_node.F90 Source File


This file depends on

sourcefile~~adjacency_node.f90~~EfferentGraph sourcefile~adjacency_node.f90 adjacency_node.F90 sourcefile~core.f90 core.F90 sourcefile~adjacency_node.f90->sourcefile~core.f90 sourcefile~allocate.f90 allocate.F90 sourcefile~core.f90->sourcefile~allocate.f90 sourcefile~check_range.f90 check_range.F90 sourcefile~core.f90->sourcefile~check_range.f90 sourcefile~deallocate.f90 deallocate.F90 sourcefile~core.f90->sourcefile~deallocate.f90 sourcefile~error.f90 error.F90 sourcefile~core.f90->sourcefile~error.f90 sourcefile~fortran_utils.f90 fortran_utils.F90 sourcefile~core.f90->sourcefile~fortran_utils.f90 sourcefile~string_utils.f90 string_utils.F90 sourcefile~core.f90->sourcefile~string_utils.f90 sourcefile~types.f90 types.F90 sourcefile~core.f90->sourcefile~types.f90 sourcefile~unique.f90 unique.F90 sourcefile~core.f90->sourcefile~unique.f90 sourcefile~vtk.f90 vtk.F90 sourcefile~core.f90->sourcefile~vtk.f90 sourcefile~vtk_constants.f90 vtk_constants.F90 sourcefile~core.f90->sourcefile~vtk_constants.f90 sourcefile~allocate.f90->sourcefile~error.f90 sourcefile~deallocate.f90->sourcefile~error.f90 sourcefile~memory_stats_wrapper.f90 memory_stats_wrapper.F90 sourcefile~fortran_utils.f90->sourcefile~memory_stats_wrapper.f90 sourcefile~signal_flag_wrapper.f90 signal_flag_wrapper.F90 sourcefile~fortran_utils.f90->sourcefile~signal_flag_wrapper.f90 sourcefile~system_info_wrapper.f90 system_info_wrapper.F90 sourcefile~fortran_utils.f90->sourcefile~system_info_wrapper.f90 sourcefile~string_utils.f90->sourcefile~allocate.f90 sourcefile~array.f90 array.F90 sourcefile~types.f90->sourcefile~array.f90 sourcefile~gauss.f90 gauss.F90 sourcefile~types.f90->sourcefile~gauss.f90 sourcefile~pointer.f90 pointer.F90 sourcefile~types.f90->sourcefile~pointer.f90 sourcefile~variable.f90 variable.F90 sourcefile~types.f90->sourcefile~variable.f90 sourcefile~vector.f90 vector.F90 sourcefile~types.f90->sourcefile~vector.f90 sourcefile~unique.f90->sourcefile~allocate.f90 sourcefile~vtk.f90->sourcefile~allocate.f90 sourcefile~vtk.f90->sourcefile~deallocate.f90 sourcefile~vtk.f90->sourcefile~unique.f90 sourcefile~vtk.f90->sourcefile~vtk_constants.f90 sourcefile~vtk.f90->sourcefile~array.f90 sourcefile~vtk_wrapper.f90 vtk_wrapper.F90 sourcefile~vtk.f90->sourcefile~vtk_wrapper.f90 sourcefile~vtu_wrapper.f90 vtu_wrapper.F90 sourcefile~vtk.f90->sourcefile~vtu_wrapper.f90 sourcefile~array.f90->sourcefile~allocate.f90 sourcefile~array.f90->sourcefile~deallocate.f90 sourcefile~c_utils.f90 c_utils.F90 sourcefile~memory_stats_wrapper.f90->sourcefile~c_utils.f90 sourcefile~signal_flag.f90 signal_flag.F90 sourcefile~signal_flag_wrapper.f90->sourcefile~signal_flag.f90 sourcefile~system_info_wrapper.f90->sourcefile~c_utils.f90 sourcefile~variable.f90->sourcefile~allocate.f90 sourcefile~c_utils.f90->sourcefile~signal_flag.f90 sourcefile~memory_stats.f90 memory_stats.F90 sourcefile~c_utils.f90->sourcefile~memory_stats.f90 sourcefile~system_info.f90 system_info.F90 sourcefile~c_utils.f90->sourcefile~system_info.f90

Files dependent on this one

sourcefile~~adjacency_node.f90~~AfferentGraph sourcefile~adjacency_node.f90 adjacency_node.F90 sourcefile~adjacency.f90 adjacency.F90 sourcefile~adjacency.f90->sourcefile~adjacency_node.f90 sourcefile~reordering.f90 reordering.F90 sourcefile~reordering.f90->sourcefile~adjacency_node.f90 sourcefile~domain.f90 domain.F90 sourcefile~domain.f90->sourcefile~adjacency.f90 sourcefile~domain.f90->sourcefile~reordering.f90 sourcefile~domain_manager.f90 domain_manager.F90 sourcefile~domain.f90->sourcefile~domain_manager.f90 sourcefile~domain_manager.f90->sourcefile~adjacency.f90 sourcefile~domain_manager.f90->sourcefile~reordering.f90 sourcefile~methods.f90 methods.F90 sourcefile~methods.f90->sourcefile~reordering.f90 sourcefile~to_original.f90 to_original.F90 sourcefile~to_original.f90->sourcefile~reordering.f90 sourcefile~to_reordered.f90 to_reordered.F90 sourcefile~to_reordered.f90->sourcefile~reordering.f90 sourcefile~boundary_interface.f90 boundary_interface.F90 sourcefile~boundary_interface.f90->sourcefile~domain.f90 sourcefile~matrix.f90 matrix.F90 sourcefile~boundary_interface.f90->sourcefile~matrix.f90 sourcefile~boundary_manager.f90 boundary_manager.F90 sourcefile~boundary_manager.f90->sourcefile~domain.f90 sourcefile~boundary_manager.f90->sourcefile~boundary_interface.f90 sourcefile~boundary_manager.f90->sourcefile~matrix.f90 sourcefile~ftdss.f90 ftdss.F90 sourcefile~ftdss.f90->sourcefile~domain.f90 sourcefile~thermal_interface.f90 thermal_interface.F90 sourcefile~ftdss.f90->sourcefile~thermal_interface.f90 sourcefile~boundary.f90 boundary.F90 sourcefile~ftdss.f90->sourcefile~boundary.f90 sourcefile~initial.f90 initial.F90 sourcefile~ftdss.f90->sourcefile~initial.f90 sourcefile~output.f90 output.F90 sourcefile~ftdss.f90->sourcefile~output.f90 sourcefile~initial_interface.f90 initial_interface.F90 sourcefile~initial_interface.f90->sourcefile~domain.f90 sourcefile~initial_interface.f90->sourcefile~boundary.f90 sourcefile~initial_manager.f90 initial_manager.F90 sourcefile~initial_manager.f90->sourcefile~domain.f90 sourcefile~initial_manager.f90->sourcefile~initial_interface.f90 sourcefile~matrix_base.f90 matrix_base.F90 sourcefile~matrix_base.f90->sourcefile~domain.f90 sourcefile~matrix_coo.f90 matrix_coo.F90 sourcefile~matrix_coo.f90->sourcefile~domain.f90 sourcefile~matrix_coo.f90->sourcefile~matrix_base.f90 sourcefile~matrix_crs.f90 matrix_crs.F90 sourcefile~matrix_crs.f90->sourcefile~domain.f90 sourcefile~matrix_crs.f90->sourcefile~matrix_base.f90 sourcefile~matrix_crs.f90->sourcefile~matrix_coo.f90 sourcefile~matrix_dense.f90 matrix_dense.F90 sourcefile~matrix_dense.f90->sourcefile~domain.f90 sourcefile~matrix_dense.f90->sourcefile~matrix_base.f90 sourcefile~output_interface.f90 output_interface.F90 sourcefile~output_interface.f90->sourcefile~domain.f90 sourcefile~output_interface.f90->sourcefile~matrix.f90 sourcefile~thermal_interface.f90->sourcefile~domain.f90 sourcefile~thermal_interface.f90->sourcefile~boundary.f90 sourcefile~thermal_interface.f90->sourcefile~matrix.f90 sourcefile~solver.f90 solver.F90 sourcefile~thermal_interface.f90->sourcefile~solver.f90 sourcefile~boundary.f90->sourcefile~boundary_interface.f90 sourcefile~boundary.f90->sourcefile~boundary_manager.f90 sourcefile~boundary_adiabatic.f90 boundary_adiabatic.F90 sourcefile~boundary_adiabatic.f90->sourcefile~boundary_interface.f90 sourcefile~boundary_base.f90 boundary_base.F90 sourcefile~boundary_base.f90->sourcefile~boundary_interface.f90 sourcefile~boundary_dirichlet.f90 boundary_dirichlet.F90 sourcefile~boundary_dirichlet.f90->sourcefile~boundary_interface.f90 sourcefile~initial.f90->sourcefile~initial_interface.f90 sourcefile~initial.f90->sourcefile~initial_manager.f90 sourcefile~initial_laplace.f90 initial_laplace.F90 sourcefile~initial_laplace.f90->sourcefile~initial_interface.f90 sourcefile~initial_uniform.f90 initial_uniform.F90 sourcefile~initial_uniform.f90->sourcefile~initial_interface.f90 sourcefile~matrix.f90->sourcefile~matrix_base.f90 sourcefile~matrix.f90->sourcefile~matrix_coo.f90 sourcefile~matrix.f90->sourcefile~matrix_crs.f90 sourcefile~matrix.f90->sourcefile~matrix_dense.f90 sourcefile~output.f90->sourcefile~output_interface.f90 sourcefile~output_base.f90 output_base.F90 sourcefile~output_base.f90->sourcefile~output_interface.f90 sourcefile~output_observation.f90 output_observation.F90 sourcefile~output_observation.f90->sourcefile~output_interface.f90 sourcefile~output_overall_base.f90 output_overall_base.F90 sourcefile~output_overall_base.f90->sourcefile~output_interface.f90 sourcefile~output_overall_vtk.f90 output_overall_vtk.F90 sourcefile~output_overall_vtk.f90->sourcefile~output_interface.f90 sourcefile~output_overall_vtu.f90 output_overall_vtu.F90 sourcefile~output_overall_vtu.f90->sourcefile~output_interface.f90 sourcefile~output_system_logger.f90 output_system_logger.F90 sourcefile~output_system_logger.f90->sourcefile~output_interface.f90 sourcefile~thermal.f90 thermal.F90 sourcefile~thermal.f90->sourcefile~thermal_interface.f90 sourcefile~thermal_3phase.f90 thermal_3phase.F90 sourcefile~thermal_3phase.f90->sourcefile~thermal_interface.f90 sourcefile~solver_factory.f90 solver_factory.F90 sourcefile~solver_factory.f90->sourcefile~matrix.f90 sourcefile~solver.f90->sourcefile~solver_factory.f90

Source Code

module domain_adjacency_adjacency_node
    use, intrinsic :: iso_fortran_env, only: int32, int64
    use :: stdlib_sorting, only:sort
    use :: module_core, only:allocate_array, deallocate_array

    implicit none
    private

    public :: type_node_adjacency

    type :: type_node_adjacency
        integer(int32) :: num_nodes = 0
        integer(int32), allocatable :: ptr(:)
        integer(int32), allocatable :: ind(:)
    contains
        procedure, pass(self), public :: initialize => initialize_node_adjacency
        procedure, pass(self), public :: is_adjacent => check_node_adjacent
        procedure, pass(self), public :: get_degree => get_node_degree
        procedure, pass(self), public :: get_num_nodes => get_num_nodes
        ! 追加: 指定ノードの隣接ノードリストを取得
        procedure, pass(self), public :: get_neighbors => get_node_neighbors
        procedure, pass(self), public :: destroy => destroy_node_adjacency
    end type type_node_adjacency

contains

    !================================================================!
    !【コントローラー】初期化処理のメインフロー
    !================================================================!
    subroutine initialize_node_adjacency(self, num_nodes_in, num_elems, &
                                         elements_conn_data, elements_ptr)
        class(type_node_adjacency), intent(inout) :: self
        integer(int32), intent(in) :: num_nodes_in, num_elems
        integer(int32), intent(in) :: elements_conn_data(:)
        integer(int32), intent(in) :: elements_ptr(:)

        integer(int32), allocatable :: edge_i(:), edge_j(:)
        integer(int32) :: edge_count, istat

        self%num_nodes = num_nodes_in

        ! ステップ1: 要素情報から全てのエッジ(ノードペア)を抽出
        call generate_all_edges(num_elems, elements_ptr, elements_conn_data, &
                                edge_i, edge_j, edge_count, istat)
        if (istat /= 0) then
            print *, "Error in generate_all_edges"
            return
        end if

        ! ステップ2: エッジリストからCSR形式の隣接グラフを構築
        call build_csr_from_edges(self, edge_i, edge_j, edge_count)

        call deallocate_array(edge_i)
        call deallocate_array(edge_j)
    end subroutine initialize_node_adjacency

    !================================================================!
    !【ステップ1】要素情報から全てのエッジ(ノードペア)を抽出
    !================================================================!
    subroutine generate_all_edges(num_elems, elem_ptr, elem_data, &
                                  edge_i, edge_j, edge_count, istat)
        integer(int32), intent(in) :: num_elems, elem_ptr(:), elem_data(:)
        integer(int32), allocatable, intent(out) :: edge_i(:), edge_j(:)
        integer(int32), intent(out) :: edge_count, istat

        integer(int32) :: i, j, k, n1, n2, start_idx, end_idx, est_edges

        istat = 0
        est_edges = size(elem_data) * 4 ! 推定サイズ
        call allocate_array(edge_i, est_edges)
        call allocate_array(edge_j, est_edges)
        edge_count = 0

        do i = 1, num_elems
            start_idx = elem_ptr(i)
            end_idx = elem_ptr(i + 1) - 1
            do j = start_idx, end_idx
                do k = j + 1, end_idx
                    edge_count = edge_count + 1
                    if (edge_count > est_edges) then
                        istat = -1; return ! メモリ見積もりエラー
                    end if
                    n1 = elem_data(j)
                    n2 = elem_data(k)
                    if (n1 < n2) then
                        edge_i(edge_count) = n1
                        edge_j(edge_count) = n2
                    else
                        edge_i(edge_count) = n2
                        edge_j(edge_count) = n1
                    end if
                end do
            end do
        end do
    end subroutine generate_all_edges

    !================================================================!
    !【ステップ2】エッジリストからCSR形式の隣接グラフを構築
    !================================================================!
    subroutine build_csr_from_edges(self, edge_i_in, edge_j_in, edge_count_in)
        class(type_node_adjacency), intent(inout) :: self
        integer(int32), intent(in) :: edge_i_in(:), edge_j_in(:), edge_count_in

        integer(int64), allocatable :: sort_keys(:)
        integer(int32), allocatable :: temp_deg(:), temp_pos(:)
        integer(int32) :: unique_count, i, n1, n2, total_adj

        if (edge_count_in == 0) then
            call allocate_array(self%ptr, self%num_nodes + 1_int32)
            call allocate_array(self%ind, 0_int32)
            self%ptr = 1
            return
        end if

        call allocate_array(sort_keys, int(edge_count_in, kind=int64))
        do i = 1, edge_count_in
            sort_keys(i) = int(edge_i_in(i), int64) * (self%num_nodes + 1) &
                           + int(edge_j_in(i), int64)
        end do
        call sort(sort_keys)

        unique_count = 1
        do i = 2, edge_count_in
            if (sort_keys(i) > sort_keys(i - 1)) then
                unique_count = unique_count + 1
                sort_keys(unique_count) = sort_keys(i)
            end if
        end do

        call allocate_array(temp_deg, self%num_nodes)
        temp_deg = 0

        do i = 1, unique_count
            n1 = int(sort_keys(i) / (self%num_nodes + 1))
            n2 = int(mod(sort_keys(i), int(self%num_nodes + 1, int64)))
            temp_deg(n1) = temp_deg(n1) + 1
            temp_deg(n2) = temp_deg(n2) + 1
        end do

        call allocate_array(self%ptr, self%num_nodes + 1_int32)
        self%ptr(1) = 1
        do i = 1, self%num_nodes
            self%ptr(i + 1) = self%ptr(i) + temp_deg(i)
        end do

        total_adj = self%ptr(self%num_nodes + 1) - 1
        call allocate_array(self%ind, total_adj)
        call allocate_array(temp_pos, self%num_nodes)
        temp_pos = self%ptr(1:self%num_nodes)

        do i = 1, unique_count
            n1 = int(sort_keys(i) / (self%num_nodes + 1))
            n2 = int(mod(sort_keys(i), int(self%num_nodes + 1, int64)))
            self%ind(temp_pos(n1)) = n2
            temp_pos(n1) = temp_pos(n1) + 1
            self%ind(temp_pos(n2)) = n1
            temp_pos(n2) = temp_pos(n2) + 1
        end do

        call deallocate_array(sort_keys)
        call deallocate_array(temp_deg)
        call deallocate_array(temp_pos)
    end subroutine build_csr_from_edges

    !================================================================!
    ! 照会・取得・解放用サブルーチン
    !================================================================!
    function check_node_adjacent(self, i, j) result(is_adj)
        class(type_node_adjacency), intent(in) :: self
        integer(int32), intent(in) :: i, j; logical :: is_adj
        integer(int32) :: k, startp, endp

        is_adj = .false.
        if (i < 1 .or. i > self%num_nodes .or. j < 1 .or. j > self%num_nodes) return

        startp = self%ptr(i)
        endp = self%ptr(i + 1) - 1

        do k = startp, endp
            if (self%ind(k) == j) then
                is_adj = .true.
                return
            end if
        end do
    end function

    function get_node_degree(self, i) result(deg)
        class(type_node_adjacency), intent(in) :: self
        integer(int32), intent(in) :: i; integer(int32) :: deg
        if (i < 1 .or. i > self%num_nodes) then
            deg = 0
        else
            deg = self%ptr(i + 1) - self%ptr(i)
        end if
    end function

    function get_num_nodes(self) result(n)
        class(type_node_adjacency), intent(in) :: self
        integer(int32) :: n
        n = self%num_nodes
    end function

    subroutine destroy_node_adjacency(self)
        class(type_node_adjacency), intent(inout) :: self
        if (allocated(self%ptr)) call deallocate_array(self%ptr)
        if (allocated(self%ind)) call deallocate_array(self%ind)
        self%num_nodes = 0
    end subroutine

    !================================================================!
    !【追加】指定されたノードの隣接ノードリストを取得する
    !================================================================!
    subroutine get_node_neighbors(self, node_id, neighbors)
        class(type_node_adjacency), intent(in) :: self
        integer(int32), intent(in) :: node_id
        integer(int32), allocatable, intent(out) :: neighbors(:)

        integer(int32) :: degree, start_p, end_p

        if (node_id < 1 .or. node_id > self%num_nodes) then
            ! 不正なノードIDの場合は、0サイズの配列を返す
            if (allocated(neighbors)) deallocate (neighbors)
            allocate (neighbors(0))
            return
        end if

        ! 1. 隣接ノードの数(次数)を計算
        start_p = self%ptr(node_id)
        end_p = self%ptr(node_id + 1) - 1
        degree = end_p - start_p + 1

        ! 2. 戻り値の配列を確保]
        if (allocated(neighbors)) deallocate (neighbors)
        allocate (neighbors(degree))

        ! 3. self%indから隣接ノードのリストをコピー
        neighbors = self%ind(start_p:end_p)

    end subroutine get_node_neighbors

end module domain_adjacency_adjacency_node