dfs_pie_accumulate Subroutine

private recursive subroutine dfs_pie_accumulate(primary_atoms, primary_n_atoms, n_primaries, max_atoms, clique, clique_size, current_atoms, n_current_atoms, candidates, n_candidates, max_k_level, atom_sets, coefficients, n_terms, max_terms, error)

DFS helper: accumulate PIE coefficients for intersections

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: primary_atoms(:,:)

Precomputed atom lists

integer, intent(in) :: primary_n_atoms(:)

Atom counts

integer, intent(in) :: n_primaries
integer, intent(in) :: max_atoms
integer, intent(in) :: clique(:)

Current clique

integer, intent(in) :: clique_size

Size of current clique

integer, intent(in) :: current_atoms(:)

Atoms in current intersection

integer, intent(in) :: n_current_atoms

Number of atoms in intersection

integer, intent(in) :: candidates(:)

Candidate primaries

integer, intent(in) :: n_candidates
integer, intent(in) :: max_k_level
integer, intent(inout), allocatable :: atom_sets(:,:)
integer, intent(inout), allocatable :: coefficients(:)
integer(kind=int64), intent(inout) :: n_terms
integer(kind=int64), intent(inout) :: max_terms
type(error_t), intent(inout) :: error

Error status


Calls

proc~~dfs_pie_accumulate~~CallsGraph proc~dfs_pie_accumulate dfs_pie_accumulate proc~dfs_pie_accumulate->proc~dfs_pie_accumulate new_clique new_clique proc~dfs_pie_accumulate->new_clique proc~atom_sets_equal atom_sets_equal proc~dfs_pie_accumulate->proc~atom_sets_equal proc~error_has_error error_t%error_has_error proc~dfs_pie_accumulate->proc~error_has_error proc~grow_pie_storage grow_pie_storage proc~dfs_pie_accumulate->proc~grow_pie_storage proc~intersect_atom_lists intersect_atom_lists proc~dfs_pie_accumulate->proc~intersect_atom_lists test_intersect test_intersect proc~dfs_pie_accumulate->test_intersect proc~error_set error_t%error_set proc~grow_pie_storage->proc~error_set to_char to_char proc~grow_pie_storage->to_char

Called by

proc~~dfs_pie_accumulate~~CalledByGraph proc~dfs_pie_accumulate dfs_pie_accumulate proc~dfs_pie_accumulate->proc~dfs_pie_accumulate proc~gmbe_enumerate_pie_terms gmbe_enumerate_pie_terms proc~gmbe_enumerate_pie_terms->proc~dfs_pie_accumulate proc~run_fragmented_calculation run_fragmented_calculation proc~run_fragmented_calculation->proc~gmbe_enumerate_pie_terms proc~run_calculation run_calculation proc~run_calculation->proc~run_fragmented_calculation proc~compute_energy_and_forces compute_energy_and_forces proc~compute_energy_and_forces->proc~run_calculation proc~run_multi_molecule_calculations run_multi_molecule_calculations proc~run_multi_molecule_calculations->proc~run_calculation program~main main program~main->proc~run_calculation program~main->proc~run_multi_molecule_calculations

Variables

Type Visibility Attributes Name Initial
integer, private :: candidate_idx
integer, private :: candidate_pos
logical, private :: found
integer, private :: i
integer, private :: n_new_atoms
integer, private :: n_new_candidates
integer, private, allocatable :: new_atoms(:)
integer, private, allocatable :: new_candidates(:)
integer, private :: sign
integer(kind=int64), private :: term_idx

Source Code

   recursive subroutine dfs_pie_accumulate(primary_atoms, primary_n_atoms, n_primaries, max_atoms, &
                                           clique, clique_size, current_atoms, n_current_atoms, &
                                           candidates, n_candidates, max_k_level, &
                                           atom_sets, coefficients, n_terms, max_terms, error)
      !! DFS helper: accumulate PIE coefficients for intersections
      integer, intent(in) :: primary_atoms(:, :)    !! Precomputed atom lists
      integer, intent(in) :: primary_n_atoms(:)     !! Atom counts
      integer, intent(in) :: n_primaries, max_atoms
      integer, intent(in) :: clique(:)              !! Current clique
      integer, intent(in) :: clique_size            !! Size of current clique
      integer, intent(in) :: current_atoms(:)       !! Atoms in current intersection
      integer, intent(in) :: n_current_atoms        !! Number of atoms in intersection
      integer, intent(in) :: candidates(:)          !! Candidate primaries
      integer, intent(in) :: n_candidates
      integer, intent(in) :: max_k_level
      integer, allocatable, intent(inout) :: atom_sets(:, :)
      integer, allocatable, intent(inout) :: coefficients(:)
      integer(int64), intent(inout) :: n_terms
      integer(int64), intent(inout) :: max_terms
      type(error_t), intent(inout) :: error         !! Error status

      integer :: sign, i, candidate_idx, candidate_pos
      integer(int64) :: term_idx
      integer, allocatable :: new_atoms(:), new_candidates(:)
      integer :: n_new_atoms, n_new_candidates
      logical :: found

      ! Skip empty intersections
      if (n_current_atoms == 0) return

      ! Compute PIE sign: (+1) for odd clique size, (-1) for even
      sign = merge(1, -1, mod(clique_size, 2) == 1)

      ! Find or create entry for this atom set
      found = .false.
      do term_idx = 1_int64, n_terms
         if (atom_sets_equal(atom_sets(:, term_idx), current_atoms, n_current_atoms)) then
            coefficients(term_idx) = coefficients(term_idx) + sign
            found = .true.
            exit
         end if
      end do

      if (.not. found) then
         ! New atom set
         if (n_terms >= max_terms) then
            call grow_pie_storage(atom_sets, coefficients, max_terms, max_atoms, error)
            if (error%has_error()) return
         end if
         n_terms = n_terms + 1_int64
         atom_sets(1:n_current_atoms, n_terms) = current_atoms(1:n_current_atoms)
         atom_sets(n_current_atoms + 1:, n_terms) = -1
         coefficients(n_terms) = sign
      end if

      ! Stop if we've reached maximum clique size
      if (clique_size >= max_k_level) return
      if (n_candidates == 0) return

      ! Try adding each candidate to the clique
      allocate (new_atoms(max_atoms))
      allocate (new_candidates(n_primaries))

      do i = 1, n_candidates
         candidate_idx = candidates(i)

         ! Compute intersection with this candidate
         call intersect_atom_lists(current_atoms, n_current_atoms, &
                                   primary_atoms(:, candidate_idx), primary_n_atoms(candidate_idx), &
                                   new_atoms, n_new_atoms)

         ! Skip if no intersection
         if (n_new_atoms == 0) cycle

         ! New candidates: must come after this one and overlap with new_atoms
         n_new_candidates = 0
         do candidate_pos = i + 1, n_candidates
            block
               integer :: test_candidate, test_n_intersect
               integer, allocatable :: test_intersect(:)
               test_candidate = candidates(candidate_pos)

               allocate (test_intersect(max_atoms))
               call intersect_atom_lists(new_atoms, n_new_atoms, &
                                         primary_atoms(:, test_candidate), primary_n_atoms(test_candidate), &
                                         test_intersect, test_n_intersect)

               if (test_n_intersect > 0) then
                  n_new_candidates = n_new_candidates + 1
                  new_candidates(n_new_candidates) = test_candidate
               end if
               deallocate (test_intersect)
            end block
         end do

         ! Recurse
         block
            integer :: new_clique(clique_size + 1)
            new_clique(1:clique_size) = clique(1:clique_size)
            new_clique(clique_size + 1) = candidate_idx

            call dfs_pie_accumulate(primary_atoms, primary_n_atoms, n_primaries, max_atoms, &
                                    new_clique, clique_size + 1, new_atoms, n_new_atoms, &
                                    new_candidates, n_new_candidates, max_k_level, &
                                    atom_sets, coefficients, n_terms, max_terms, error)
            if (error%has_error()) then
               deallocate (new_atoms, new_candidates)
               return
            end if
         end block
      end do

      deallocate (new_atoms, new_candidates)

   end subroutine dfs_pie_accumulate