module classes_dipoles_neighbourhood use, intrinsic :: iso_fortran_env, only: DP => REAL64 use procedures_checks, only: check_positive use procedures_dipolar_interactions_micro, only: dipolar_energy_is_negative implicit none private type, abstract, public :: Abstract_Dipolar_Neighbourhood private real(DP) :: max_distance = 0._DP contains procedure :: set => Abstract_set procedure :: get_max_distance => Abstract_get_max_distance procedure :: meet => Abstract_meet end type Abstract_Dipolar_Neighbourhood type, extends(Abstract_Dipolar_Neighbourhood), public :: Concrete_Dipolar_Neighbourhood end type Concrete_Dipolar_Neighbourhood type, extends(Abstract_Dipolar_Neighbourhood), public :: Null_Dipolar_Neighbourhood contains procedure :: set => Null_set procedure :: get_max_distance => Null_get_max_distance procedure :: are_neighbour => Null_are_neighbour end type Null_Dipolar_Neighbourhood type, public :: Dipolar_Neighbourhood_Wrapper class(Abstract_Dipolar_Neighbourhood), allocatable :: neighbourhood end type Dipolar_Neighbourhood_Wrapper type, public :: Dipolar_Neighbourhood_Line type(Dipolar_Neighbourhood_Wrapper), allocatable :: line(:) end type Dipolar_Neighbourhood_Line contains !implementation Abstract_Dipolar_Neighbourhood subroutine Abstract_set(this, max_distance) class(Abstract_Dipolar_Neighbourhood), intent(inout) :: this real(DP), intent(in) :: max_distance call check_positive("Abstract_Dipolar_Neighbourhood: set", "max_distance", max_distance) this%max_distance = max_distance end subroutine Abstract_set pure real(DP) function Abstract_get_max_distance(this) result(max_distance) class(Abstract_Dipolar_Neighbourhood), intent(in) :: this max_distance = this%max_distance end function Abstract_get_max_distance !> @todo Alternative to \( \vec{r}_ij \cdot \mu_i \geq 0 \)? pure subroutine Abstract_meet(this, overlap, ij_are_neighbour, min_distance, vector_ij, & orientation_i, orientation_j) class(Abstract_Dipolar_Neighbourhood), intent(in) :: this logical, intent(out) :: overlap, ij_are_neighbour real(DP), intent(in) :: min_distance real(DP), dimension(:), intent(in) :: vector_ij, orientation_i, orientation_j real(DP) :: distance_ij distance_ij = norm2(vector_ij) if (distance_ij < min_distance) then overlap = .true. return else overlap = .false. end if ij_are_neighbour = distance_ij < this%max_distance .and. & dipolar_energy_is_negative(vector_ij, orientation_i, orientation_j) .and. & dot_product(vector_ij, orientation_i) >= 0._DP end subroutine Abstract_meet !end implementation Abstract_Dipolar_Neighbourhood !implementation Null_Dipolar_Neighbourhood subroutine Null_set(this, max_distance) class(Null_Dipolar_Neighbourhood), intent(inout) :: this real(DP), intent(in) :: max_distance end subroutine Null_set pure real(DP) function Null_get_max_distance(this) result(max_distance) class(Null_Dipolar_Neighbourhood), intent(in) :: this max_distance = 0._DP end function Null_get_max_distance pure subroutine Null_are_neighbour(this, overlap, ij_are_neighbour, min_distance, vector_ij,& orientation_i, orientation_j) class(Null_Dipolar_Neighbourhood), intent(in) :: this logical, intent(out) :: overlap, ij_are_neighbour real(DP), intent(in) :: min_distance real(DP), dimension(:), intent(in) :: vector_ij, orientation_i, orientation_j overlap = .false.; ij_are_neighbour = .false. end subroutine Null_are_neighbour !end implementation Null_Dipolar_Neighbourhood end module classes_dipoles_neighbourhood