LCOV - code coverage report
Current view: top level - src/motion/mc - mc_coordinates.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:d1f8d1b) Lines: 298 420 71.0 %
Date: 2024-11-29 06:42:44 Functions: 6 9 66.7 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief contains miscellaneous subroutines used in the Monte Carlo runs,mostly
      10             : !>      geared towards changes in coordinates
      11             : !> \author MJM
      12             : ! **************************************************************************************************
      13             : MODULE mc_coordinates
      14             :    USE cell_types,                      ONLY: cell_type,&
      15             :                                               get_cell
      16             :    USE cp_subsys_types,                 ONLY: cp_subsys_get,&
      17             :                                               cp_subsys_type
      18             :    USE force_env_methods,               ONLY: force_env_calc_energy_force
      19             :    USE force_env_types,                 ONLY: force_env_get,&
      20             :                                               force_env_type
      21             :    USE kinds,                           ONLY: dp
      22             :    USE mathconstants,                   ONLY: pi
      23             :    USE mc_types,                        ONLY: get_mc_molecule_info,&
      24             :                                               get_mc_par,&
      25             :                                               mc_molecule_info_type,&
      26             :                                               mc_simpar_type
      27             :    USE message_passing,                 ONLY: mp_comm_type
      28             :    USE molecule_types,                  ONLY: molecule_type
      29             :    USE parallel_rng_types,              ONLY: rng_stream_type
      30             :    USE particle_list_types,             ONLY: particle_list_type
      31             :    USE physcon,                         ONLY: angstrom
      32             : #include "../../base/base_uses.f90"
      33             : 
      34             :    IMPLICIT NONE
      35             : 
      36             :    PRIVATE
      37             : 
      38             :    PRIVATE :: generate_avbmc_insertion
      39             : 
      40             :    PUBLIC :: generate_cbmc_swap_config, &
      41             :              get_center_of_mass, mc_coordinate_fold, &
      42             :              find_mc_test_molecule, &
      43             :              create_discrete_array, &
      44             :              check_for_overlap, &
      45             :              rotate_molecule, &
      46             :              cluster_search
      47             : 
      48             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'mc_coordinates'
      49             : 
      50             : CONTAINS
      51             : 
      52             : ! **************************************************************************************************
      53             : !> \brief looks for overlaps (intermolecular distances less than rmin)
      54             : !> \param force_env the force environment containing the coordinates
      55             : !> \param nchains the number of molecules of each type in the box
      56             : !> \param nunits the number of interaction sites for each molecule
      57             : !> \param loverlap returns .TRUE. if atoms overlap
      58             : !> \param mol_type an array that indicates the type of each molecule
      59             : !> \param cell_length the length of the box...if none is specified,
      60             : !>                     it uses the cell found in the force_env
      61             : !> \param molecule_number if present, just look for overlaps with this
      62             : !>            molecule
      63             : !>
      64             : !>      Suitable for parallel use.
      65             : !> \author MJM
      66             : ! **************************************************************************************************
      67        8650 :    SUBROUTINE check_for_overlap(force_env, nchains, nunits, loverlap, mol_type, &
      68             :                                 cell_length, molecule_number)
      69             : 
      70             :       TYPE(force_env_type), POINTER                      :: force_env
      71             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: nchains, nunits
      72             :       LOGICAL, INTENT(OUT)                               :: loverlap
      73             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: mol_type
      74             :       REAL(KIND=dp), DIMENSION(1:3), INTENT(IN), &
      75             :          OPTIONAL                                        :: cell_length
      76             :       INTEGER, INTENT(IN), OPTIONAL                      :: molecule_number
      77             : 
      78             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'check_for_overlap'
      79             : 
      80             :       INTEGER                                            :: handle, imol, iunit, jmol, jstart, &
      81             :                                                             junit, nend, nstart, nunit, nunits_i, &
      82             :                                                             nunits_j
      83             :       LOGICAL                                            :: lall
      84             :       REAL(KIND=dp)                                      :: dist, rmin
      85        8650 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: r
      86             :       REAL(KIND=dp), DIMENSION(1:3)                      :: abc, box_length, RIJ
      87             :       TYPE(cell_type), POINTER                           :: cell
      88             :       TYPE(cp_subsys_type), POINTER                      :: oldsys
      89             :       TYPE(particle_list_type), POINTER                  :: particles
      90             : 
      91             : ! begin the timing of the subroutine
      92             : 
      93        8650 :       CALL timeset(routineN, handle)
      94             : 
      95        8650 :       NULLIFY (oldsys, particles)
      96             : 
      97             : ! initialize some stuff
      98        8650 :       loverlap = .FALSE.
      99        8650 :       rmin = 3.57106767_dp ! 1 angstrom squared
     100             : 
     101             : ! get the particle coordinates and the cell length
     102        8650 :       CALL force_env_get(force_env, cell=cell, subsys=oldsys)
     103        8650 :       CALL get_cell(cell, abc=abc)
     104        8650 :       CALL cp_subsys_get(oldsys, particles=particles)
     105             : 
     106       57316 :       ALLOCATE (r(1:3, 1:MAXVAL(nunits), 1:SUM(nchains)))
     107             : 
     108        8650 :       IF (PRESENT(cell_length)) THEN
     109          82 :          box_length(1:3) = cell_length(1:3)
     110             :       ELSE
     111        8568 :          box_length(1:3) = abc(1:3)
     112             :       END IF
     113             : 
     114             : ! put the coordinates into an easier matrix to manipulate
     115        8650 :       junit = 0
     116       66446 :       DO imol = 1, SUM(nchains)
     117       46438 :          nunit = nunits(mol_type(imol))
     118      162532 :          DO iunit = 1, nunit
     119      107444 :             junit = junit + 1
     120      476214 :             r(1:3, iunit, imol) = particles%els(junit)%r(1:3)
     121             :          END DO
     122             :       END DO
     123             : 
     124             : ! now let's find the LJ energy between all the oxygens and
     125             : ! the charge interactions
     126        8650 :       lall = .TRUE.
     127        8650 :       jstart = 1
     128        8650 :       IF (PRESENT(molecule_number)) THEN
     129        1808 :          lall = .FALSE.
     130        1808 :          nstart = molecule_number
     131        1808 :          nend = molecule_number
     132             :       ELSE
     133       14584 :          nstart = 1
     134       14584 :          nend = SUM(nchains(:))
     135             :       END IF
     136       30992 :       DO imol = nstart, nend
     137       23626 :          IF (lall) jstart = imol + 1
     138       23626 :          nunits_i = nunits(mol_type(imol))
     139      159526 :          DO jmol = jstart, SUM(nchains(:))
     140       93258 :             IF (imol == jmol) CYCLE
     141       91452 :             nunits_j = nunits(mol_type(jmol))
     142             : 
     143      350352 :             DO iunit = 1, nunits_i
     144      754516 :                DO junit = 1, nunits_j
     145             : ! find the minimum image distance
     146             :                   RIJ(1) = r(1, iunit, imol) - r(1, junit, jmol) - &
     147             :                            box_length(1)*ANINT( &
     148      425984 :                            (r(1, iunit, imol) - r(1, junit, jmol))/box_length(1))
     149             :                   RIJ(2) = r(2, iunit, imol) - r(2, junit, jmol) - &
     150             :                            box_length(2)*ANINT( &
     151      425984 :                            (r(2, iunit, imol) - r(2, junit, jmol))/box_length(2))
     152             :                   RIJ(3) = r(3, iunit, imol) - r(3, junit, jmol) - &
     153             :                            box_length(3)*ANINT( &
     154      425984 :                            (r(3, iunit, imol) - r(3, junit, jmol))/box_length(3))
     155             : 
     156      425984 :                   dist = RIJ(1)**2 + RIJ(2)**2 + RIJ(3)**2
     157             : 
     158      662542 :                   IF (dist < rmin) THEN
     159        1284 :                      loverlap = .TRUE.
     160        1284 :                      DEALLOCATE (r)
     161             : 
     162        1284 :                      CALL timestop(handle)
     163             :                      RETURN
     164             :                   END IF
     165             : 
     166             :                END DO
     167             :             END DO
     168             :          END DO
     169             :       END DO
     170             : 
     171        7366 :       DEALLOCATE (r)
     172             : 
     173             : ! end the timing
     174        7366 :       CALL timestop(handle)
     175             : 
     176        8650 :    END SUBROUTINE check_for_overlap
     177             : 
     178             : ! **************************************************************************************************
     179             : !> \brief calculates the center of mass of a given molecule
     180             : !> \param coordinates the coordinates of the atoms in the molecule
     181             : !> \param natom the number of atoms in the molecule
     182             : !> \param center_of_mass the coordinates of the center of mass
     183             : !> \param mass the mass of the atoms in the molecule
     184             : !>
     185             : !>    Designed for parallel use.
     186             : !> \author MJM
     187             : ! **************************************************************************************************
     188        3432 :    SUBROUTINE get_center_of_mass(coordinates, natom, center_of_mass, &
     189        1144 :                                  mass)
     190             : 
     191             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: coordinates
     192             :       INTEGER, INTENT(IN)                                :: natom
     193             :       REAL(KIND=dp), DIMENSION(1:3), INTENT(OUT)         :: center_of_mass
     194             :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: mass
     195             : 
     196             :       CHARACTER(len=*), PARAMETER :: routineN = 'get_center_of_mass'
     197             : 
     198             :       INTEGER                                            :: handle, i, iatom
     199             :       REAL(KIND=dp)                                      :: total_mass
     200             : 
     201             : ! begin the timing of the subroutine
     202             : 
     203        1144 :       CALL timeset(routineN, handle)
     204             : 
     205        3544 :       total_mass = SUM(mass(1:natom))
     206        1144 :       center_of_mass(:) = 0.0E0_dp
     207             : 
     208        3544 :       DO iatom = 1, natom
     209       10744 :          DO i = 1, 3
     210             :             center_of_mass(i) = center_of_mass(i) + &
     211        9600 :                                 mass(iatom)*coordinates(i, iatom)
     212             :          END DO
     213             :       END DO
     214             : 
     215        4576 :       center_of_mass(1:3) = center_of_mass(1:3)/total_mass
     216             : 
     217             : ! end the timing
     218        1144 :       CALL timestop(handle)
     219             : 
     220        1144 :    END SUBROUTINE get_center_of_mass
     221             : 
     222             : ! **************************************************************************************************
     223             : !> \brief folds all the coordinates into the center simulation box using
     224             : !>      a center of mass cutoff
     225             : !> \param coordinates the coordinates of the atoms in the system
     226             : !> \param nchains_tot the total number of molecules in the box
     227             : !> \param mol_type an array that indicates the type of every molecule in the box
     228             : !> \param mass the mass of every atom for all molecule types
     229             : !> \param nunits the number of interaction sites for each molecule type
     230             : !> \param box_length an array for the lengths of the simulation box sides
     231             : !>
     232             : !>      Designed for parallel use.
     233             : !> \author MJM
     234             : ! **************************************************************************************************
     235           0 :    SUBROUTINE mc_coordinate_fold(coordinates, nchains_tot, mol_type, mass, nunits, box_length)
     236             : 
     237             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: coordinates
     238             :       INTEGER, INTENT(IN)                                :: nchains_tot
     239             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: mol_type
     240             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: mass
     241             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: nunits
     242             :       REAL(KIND=dp), DIMENSION(1:3), INTENT(IN)          :: box_length
     243             : 
     244             :       CHARACTER(len=*), PARAMETER :: routineN = 'mc_coordinate_fold'
     245             : 
     246             :       INTEGER                                            :: end_atom, handle, iatom, imolecule, &
     247             :                                                             jatom, molecule_type, natoms, &
     248             :                                                             start_atom
     249             :       REAL(KIND=dp), DIMENSION(1:3)                      :: center_of_mass
     250             : 
     251             : ! begin the timing of the subroutine
     252             : 
     253           0 :       CALL timeset(routineN, handle)
     254             : 
     255             : ! loop over all molecules
     256           0 :       end_atom = 0
     257           0 :       DO imolecule = 1, nchains_tot
     258           0 :          molecule_type = mol_type(imolecule)
     259           0 :          natoms = nunits(molecule_type)
     260           0 :          start_atom = end_atom + 1
     261           0 :          end_atom = start_atom + natoms - 1
     262             :          CALL get_center_of_mass(coordinates(:, start_atom:end_atom), &
     263           0 :                                  natoms, center_of_mass(:), mass(:, molecule_type))
     264           0 :          DO iatom = 1, natoms
     265           0 :             jatom = iatom + start_atom - 1
     266             :             coordinates(1, jatom) = coordinates(1, jatom) - &
     267           0 :                                     box_length(1)*FLOOR(center_of_mass(1)/box_length(1))
     268             :             coordinates(2, jatom) = coordinates(2, jatom) - &
     269           0 :                                     box_length(2)*FLOOR(center_of_mass(2)/box_length(2))
     270             :             coordinates(3, jatom) = coordinates(3, jatom) - &
     271           0 :                                     box_length(3)*FLOOR(center_of_mass(3)/box_length(2))
     272             :          END DO
     273             : 
     274             :       END DO
     275             : 
     276             : ! end the timing
     277           0 :       CALL timestop(handle)
     278             : 
     279           0 :    END SUBROUTINE mc_coordinate_fold
     280             : 
     281             : ! **************************************************************************************************
     282             : !> \brief takes the last molecule in a force environment and moves it around
     283             : !>      to different center of mass positions and orientations, selecting one
     284             : !>      based on the rosenbluth weight
     285             : !> \param force_env the force environment containing the coordinates
     286             : !> \param BETA the value of 1/kT for this simulations, in a.u.
     287             : !> \param max_val ...
     288             : !> \param min_val ...
     289             : !> \param exp_max_val ...
     290             : !> \param exp_min_val ...
     291             : !> \param nswapmoves the number of desired trial configurations
     292             : !> \param rosenbluth_weight the Rosenbluth weight for this set of configs
     293             : !> \param start_atom the atom number that the molecule to be swapped starts on
     294             : !> \param natoms_tot the total number of interaction sites in the box
     295             : !> \param nunits the number of interaction sites for every molecule_type
     296             : !> \param nunits_mol ...
     297             : !> \param mass the mass for every interaction site of every molecule type
     298             : !> \param loverlap the flag that indicates if all of the configs have an
     299             : !>                  atomic overlap
     300             : !> \param choosen_energy the energy of the chosen config
     301             : !> \param old_energy the energy that we subtract from all of the trial
     302             : !>        energies to prevent numerical overflows
     303             : !> \param ionode indicates if we're on the main CPU
     304             : !> \param lremove is this the Rosenbluth weight for a removal box?
     305             : !> \param mol_type an array that contains the molecule type for every atom in the box
     306             : !> \param nchains the number of molecules of each type in this box
     307             : !> \param source the MPI source value, for broadcasts
     308             : !> \param group the MPI group value, for broadcasts
     309             : !> \param rng_stream the random number stream that we draw from
     310             : !> \param avbmc_atom ...
     311             : !> \param rmin ...
     312             : !> \param rmax ...
     313             : !> \param move_type ...
     314             : !> \param target_atom ...
     315             : !> \par Optional Avbmc Flags
     316             : !>      - avbmc_atom: the atom number that serves for the target atom in each
     317             : !>        molecule (1 is the first atom in the molecule, etc.)
     318             : !>      - rmin: the minimum AVBMC radius for the shell around the target
     319             : !>      - rmax: the maximum AVBMC radius for the shell around the target
     320             : !>      - move_type: generate configs in the "in" or "out" volume
     321             : !>      - target_atom: the number of the avbmc atom in the target molecule
     322             : !> \par
     323             : !>      Suitable for parallel.
     324             : !> \author MJM
     325             : ! **************************************************************************************************
     326          44 :    SUBROUTINE generate_cbmc_swap_config(force_env, BETA, max_val, min_val, exp_max_val, &
     327          88 :                                         exp_min_val, nswapmoves, rosenbluth_weight, start_atom, natoms_tot, nunits, nunits_mol, &
     328          44 :                                         mass, loverlap, choosen_energy, old_energy, ionode, lremove, mol_type, nchains, source, &
     329             :                                         group, rng_stream, avbmc_atom, rmin, rmax, move_type, target_atom)
     330             : 
     331             :       TYPE(force_env_type), POINTER                      :: force_env
     332             :       REAL(KIND=dp), INTENT(IN)                          :: BETA, max_val, min_val, exp_max_val, &
     333             :                                                             exp_min_val
     334             :       INTEGER, INTENT(IN)                                :: nswapmoves
     335             :       REAL(KIND=dp), INTENT(OUT)                         :: rosenbluth_weight
     336             :       INTEGER, INTENT(IN)                                :: start_atom, natoms_tot
     337             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: nunits
     338             :       INTEGER, INTENT(IN)                                :: nunits_mol
     339             :       REAL(dp), DIMENSION(1:nunits_mol), INTENT(IN)      :: mass
     340             :       LOGICAL, INTENT(OUT)                               :: loverlap
     341             :       REAL(KIND=dp), INTENT(OUT)                         :: choosen_energy
     342             :       REAL(KIND=dp), INTENT(IN)                          :: old_energy
     343             :       LOGICAL, INTENT(IN)                                :: ionode, lremove
     344             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: mol_type, nchains
     345             :       INTEGER, INTENT(IN)                                :: source
     346             :       TYPE(mp_comm_type)                                 :: group
     347             :       TYPE(rng_stream_type), INTENT(INOUT)               :: rng_stream
     348             :       INTEGER, INTENT(IN), OPTIONAL                      :: avbmc_atom
     349             :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: rmin, rmax
     350             :       CHARACTER(LEN=*), INTENT(IN), OPTIONAL             :: move_type
     351             :       INTEGER, INTENT(IN), OPTIONAL                      :: target_atom
     352             : 
     353             :       CHARACTER(len=*), PARAMETER :: routineN = 'generate_cbmc_swap_config'
     354             : 
     355             :       INTEGER                                            :: atom_number, choosen, end_atom, handle, &
     356             :                                                             i, iatom, imolecule, imove, &
     357             :                                                             molecule_number
     358             :       LOGICAL                                            :: all_overlaps
     359          44 :       LOGICAL, ALLOCATABLE, DIMENSION(:)                 :: loverlap_array
     360             :       REAL(KIND=dp)                                      :: bias_energy, exponent, rand, &
     361             :                                                             total_running_weight
     362          44 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: boltz_weights, trial_energy
     363          44 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: r_old
     364          44 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: r
     365             :       REAL(KIND=dp), DIMENSION(1:3)                      :: abc, center_of_mass, diff, r_insert
     366             :       TYPE(cell_type), POINTER                           :: cell
     367             :       TYPE(cp_subsys_type), POINTER                      :: oldsys
     368             :       TYPE(particle_list_type), POINTER                  :: particles
     369             : 
     370             : ! begin the timing of the subroutine
     371             : 
     372          44 :       CALL timeset(routineN, handle)
     373             : 
     374          44 :       NULLIFY (oldsys)
     375             : ! get the particle coordinates and the cell length
     376          44 :       CALL force_env_get(force_env, cell=cell, subsys=oldsys)
     377          44 :       CALL get_cell(cell, abc=abc)
     378          44 :       CALL cp_subsys_get(oldsys, particles=particles)
     379             : 
     380             : ! do some checking to make sure we have all the data we need
     381          44 :       IF (PRESENT(avbmc_atom)) THEN
     382             :          IF (.NOT. PRESENT(rmin) .OR. .NOT. PRESENT(rmax) .OR. &
     383           0 :              .NOT. PRESENT(move_type) .OR. .NOT. PRESENT(target_atom)) THEN
     384           0 :             CPABORT('AVBMC swap move is missing information!')
     385             :          END IF
     386             :       END IF
     387             : 
     388         132 :       ALLOCATE (r_old(1:3, 1:natoms_tot))
     389         176 :       ALLOCATE (r(1:3, 1:natoms_tot, 1:nswapmoves))
     390         132 :       ALLOCATE (trial_energy(1:nswapmoves))
     391          88 :       ALLOCATE (boltz_weights(1:nswapmoves))
     392         132 :       ALLOCATE (loverlap_array(1:nswapmoves))
     393             : 
     394             : ! initialize the arrays that need it
     395         220 :       loverlap_array(:) = .FALSE.
     396          44 :       loverlap = .FALSE.
     397         220 :       boltz_weights(:) = 0.0_dp
     398         220 :       trial_energy(:) = 0.0_dp
     399       18492 :       r(:, :, :) = 0.0_dp
     400          44 :       choosen_energy = 0.0_dp
     401          44 :       rosenbluth_weight = 0.0_dp
     402             : 
     403             : ! save the positions of the molecules
     404         220 :       DO imove = 1, nswapmoves
     405        4788 :          DO iatom = 1, natoms_tot
     406       18448 :             r(1:3, iatom, imove) = particles%els(iatom)%r(1:3)
     407             :          END DO
     408             :       END DO
     409             : 
     410             : ! save the remove coordinates
     411        1186 :       DO iatom = 1, natoms_tot
     412        4612 :          r_old(1:3, iatom) = r(1:3, iatom, 1)
     413             :       END DO
     414             : 
     415             : ! figure out the numbers of the first and last atoms in the molecule
     416          44 :       end_atom = start_atom + nunits_mol - 1
     417             : ! figure out which molecule number we're on
     418          44 :       molecule_number = 0
     419          44 :       atom_number = 1
     420         456 :       DO imolecule = 1, SUM(nchains(:))
     421         368 :          IF (atom_number == start_atom) THEN
     422          44 :             molecule_number = imolecule
     423          44 :             EXIT
     424             :          END IF
     425         324 :          atom_number = atom_number + nunits(mol_type(imolecule))
     426             :       END DO
     427          44 :       IF (molecule_number == 0) CALL cp_abort(__LOCATION__, &
     428           0 :                                               'CBMC swap move cannot find which molecule number it needs')
     429             : 
     430          44 :       IF (lremove) THEN
     431             :          CALL check_for_overlap(force_env, nchains, nunits, loverlap_array(1), &
     432          22 :                                 mol_type)
     433          22 :          CALL group%bcast(loverlap_array(1), source)
     434             : 
     435          22 :          IF (loverlap_array(1)) THEN
     436           0 :             IF (ionode) THEN
     437           0 :                WRITE (*, *) start_atom, end_atom, natoms_tot
     438           0 :                DO iatom = 1, natoms_tot
     439           0 :                   WRITE (*, *) r(1:3, iatom, 1)
     440             :                END DO
     441             :             END IF
     442           0 :             CPABORT('CBMC swap move found an overlap in the old config')
     443             :          END IF
     444             :       END IF
     445             : 
     446         220 :       DO imove = 1, nswapmoves
     447             : 
     448             : ! drop into serial
     449         176 :          IF (ionode) THEN
     450             : 
     451          88 :             IF (PRESENT(avbmc_atom)) THEN
     452             : ! find an AVBMC insertion point
     453             :                CALL generate_avbmc_insertion(rmin, rmax, &
     454             :                                              r_old(1:3, target_atom), &
     455           0 :                                              move_type, r_insert(:), abc(:), rng_stream)
     456             : 
     457           0 :                DO i = 1, 3
     458           0 :                   diff(i) = r_insert(i) - r_old(i, start_atom + avbmc_atom - 1)
     459             :                END DO
     460             : 
     461             :             ELSE
     462             : ! find a new insertion point somewhere in the box
     463         352 :                DO i = 1, 3
     464         264 :                   rand = rng_stream%next()
     465         352 :                   r_insert(i) = rand*abc(i)
     466             :                END DO
     467             : 
     468             : ! find the center of mass of the insertion molecule
     469             :                CALL get_center_of_mass(r(:, start_atom:end_atom, imove), nunits_mol, &
     470          88 :                                        center_of_mass(:), mass(:))
     471             : 
     472             : ! move the molecule to the insertion point
     473             : 
     474         352 :                DO i = 1, 3
     475         352 :                   diff(i) = r_insert(i) - center_of_mass(i)
     476             :                END DO
     477             : 
     478             :             END IF
     479             : 
     480         256 :             DO iatom = start_atom, end_atom
     481         760 :                r(1:3, iatom, imove) = r(1:3, iatom, imove) + diff(1:3)
     482             :             END DO
     483             : 
     484             : ! rotate the molecule...this routine is only made for serial use
     485             :             CALL rotate_molecule(r(:, start_atom:end_atom, imove), mass(:), &
     486          88 :                                  nunits_mol, rng_stream)
     487             : 
     488          88 :             IF (imove == 1 .AND. lremove) THEN
     489         293 :                DO iatom = 1, natoms_tot
     490        1139 :                   r(1:3, iatom, 1) = r_old(1:3, iatom)
     491             :                END DO
     492             :             END IF
     493             : 
     494             :          END IF
     495             : 
     496         176 :          CALL group%bcast(r(:, :, imove), source)
     497             : 
     498             : ! calculate the energy and boltzman weight of the config
     499         512 :          DO iatom = start_atom, end_atom
     500        1520 :             particles%els(iatom)%r(1:3) = r(1:3, iatom, imove)
     501             :          END DO
     502             : 
     503             :          CALL check_for_overlap(force_env, nchains, nunits, loverlap_array(imove), &
     504         176 :                                 mol_type, molecule_number=molecule_number)
     505         176 :          IF (loverlap_array(imove)) THEN
     506           6 :             boltz_weights(imove) = 0.0_dp
     507           6 :             CYCLE
     508             :          END IF
     509             : 
     510         170 :          CALL force_env_calc_energy_force(force_env, calc_force=.FALSE.)
     511             :          CALL force_env_get(force_env, &
     512         170 :                             potential_energy=bias_energy)
     513             : 
     514         170 :          trial_energy(imove) = (bias_energy - old_energy)
     515         170 :          exponent = -BETA*trial_energy(imove)
     516             : 
     517         214 :          IF (exponent .GT. exp_max_val) THEN
     518           0 :             boltz_weights(imove) = max_val
     519         170 :          ELSEIF (exponent .LT. exp_min_val) THEN
     520           2 :             boltz_weights(imove) = min_val
     521             :          ELSE
     522         168 :             boltz_weights(imove) = EXP(exponent)
     523             :          END IF
     524             : 
     525             :       END DO
     526             : 
     527             : ! now we need to pick a configuration based on the Rosenbluth weight,
     528             : ! which is just the sum of the Boltzmann weights
     529         220 :       rosenbluth_weight = SUM(boltz_weights(:))
     530          44 :       IF (rosenbluth_weight .EQ. 0.0_dp .AND. lremove) THEN
     531             : ! should never have 0.0 for an old weight...causes a divide by zero
     532             : ! in the acceptance rule
     533           0 :          IF (ionode) THEN
     534           0 :             WRITE (*, *) boltz_weights(1:nswapmoves)
     535           0 :             WRITE (*, *) start_atom, end_atom, lremove
     536           0 :             WRITE (*, *) loverlap_array(1:nswapmoves)
     537           0 :             WRITE (*, *) natoms_tot
     538           0 :             WRITE (*, *)
     539           0 :             DO iatom = 1, natoms_tot
     540           0 :                WRITE (*, *) r(1:3, iatom, 1)*angstrom
     541             :             END DO
     542             :          END IF
     543           0 :          CPABORT('CBMC swap move found a bad old weight')
     544             :       END IF
     545          44 :       all_overlaps = .TRUE.
     546          44 :       total_running_weight = 0.0E0_dp
     547          44 :       choosen = 0
     548          44 :       IF (ionode) THEN
     549          22 :          rand = rng_stream%next()
     550             : !         CALL random_number(rand)
     551             :       END IF
     552          44 :       CALL group%bcast(rand, source)
     553          98 :       DO imove = 1, nswapmoves
     554          98 :          IF (loverlap_array(imove)) CYCLE
     555          94 :          all_overlaps = .FALSE.
     556          94 :          total_running_weight = total_running_weight + boltz_weights(imove)
     557          94 :          IF (total_running_weight .GE. rand*rosenbluth_weight) THEN
     558             :             choosen = imove
     559             :             EXIT
     560             :          END IF
     561             :       END DO
     562             : 
     563          44 :       IF (all_overlaps) THEN
     564           0 :          loverlap = .TRUE.
     565             : 
     566             : ! if this is an old configuration, we always choose the first one...
     567             : ! this should never be the case, but I'm testing something
     568           0 :          IF (lremove) THEN
     569           0 :             IF (ionode) THEN
     570           0 :                WRITE (*, *) boltz_weights(1:nswapmoves)
     571           0 :                WRITE (*, *) start_atom, end_atom, lremove
     572           0 :                WRITE (*, *) loverlap_array(1:nswapmoves)
     573           0 :                DO iatom = 1, natoms_tot
     574           0 :                   WRITE (*, *) r(1:3, iatom, 1)
     575             :                END DO
     576             :             END IF
     577           0 :             CPABORT('CBMC swap move found all overlaps for the remove config')
     578             :          END IF
     579             : 
     580           0 :          DEALLOCATE (r_old)
     581           0 :          DEALLOCATE (r)
     582           0 :          DEALLOCATE (trial_energy)
     583           0 :          DEALLOCATE (boltz_weights)
     584           0 :          DEALLOCATE (loverlap_array)
     585           0 :          CALL timestop(handle)
     586           0 :          RETURN
     587             :       END IF
     588             : 
     589             : ! make sure a configuration was chosen
     590          44 :       IF (choosen == 0) &
     591           0 :          CPABORT('CBMC swap move failed to select config')
     592             : 
     593             : ! if this is an old configuration, we always choose the first one
     594          44 :       IF (lremove) choosen = 1
     595             : 
     596             : ! set the energy for the configuration
     597          44 :       choosen_energy = trial_energy(choosen)
     598             : 
     599             : ! copy the coordinates to the force environment
     600        1186 :       DO iatom = 1, natoms_tot
     601        4612 :          particles%els(iatom)%r(1:3) = r(1:3, iatom, choosen)
     602             :       END DO
     603             : 
     604          44 :       DEALLOCATE (r_old)
     605          44 :       DEALLOCATE (r)
     606          44 :       DEALLOCATE (trial_energy)
     607          44 :       DEALLOCATE (boltz_weights)
     608          44 :       DEALLOCATE (loverlap_array)
     609             : 
     610             : ! end the timing
     611          44 :       CALL timestop(handle)
     612             : 
     613          44 :    END SUBROUTINE generate_cbmc_swap_config
     614             : 
     615             : ! **************************************************************************************************
     616             : !> \brief rotates a molecule randomly around the center of mass,
     617             : !>      sequentially in x, y, and z directions
     618             : !> \param r the coordinates of the molecule to rotate
     619             : !> \param mass the mass of all the atoms in the molecule
     620             : !> \param natoms the number of atoms in the molecule
     621             : !> \param rng_stream the stream we pull random numbers from
     622             : !>
     623             : !>    Use only in serial.
     624             : !> \author MJM
     625             : ! **************************************************************************************************
     626          98 :    SUBROUTINE rotate_molecule(r, mass, natoms, rng_stream)
     627             : 
     628             :       INTEGER, INTENT(IN)                                :: natoms
     629             :       REAL(KIND=dp), DIMENSION(1:natoms), INTENT(IN)     :: mass
     630             :       REAL(KIND=dp), DIMENSION(1:3, 1:natoms), &
     631             :          INTENT(INOUT)                                   :: r
     632             :       TYPE(rng_stream_type), INTENT(INOUT)               :: rng_stream
     633             : 
     634             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'rotate_molecule'
     635             : 
     636             :       INTEGER                                            :: handle, iunit
     637             :       REAL(KIND=dp)                                      :: cosdg, dgamma, rand, rx, rxnew, ry, &
     638             :                                                             rynew, rz, rznew, sindg
     639             :       REAL(KIND=dp), DIMENSION(1:3)                      :: center_of_mass
     640             : 
     641             : ! begin the timing of the subroutine
     642             : 
     643          98 :       CALL timeset(routineN, handle)
     644             : 
     645             : ! find the center of mass of the molecule
     646          98 :       CALL get_center_of_mass(r(:, :), natoms, center_of_mass(:), mass(:))
     647             : 
     648             : ! call a random number to figure out how far we're moving
     649          98 :       rand = rng_stream%next()
     650          98 :       dgamma = pi*(rand - 0.5E0_dp)*2.0E0_dp
     651             : 
     652             : ! *** set up the rotation matrix ***
     653             : 
     654          98 :       cosdg = COS(dgamma)
     655          98 :       sindg = SIN(dgamma)
     656             : 
     657             : ! ***    ROTATE UNITS OF I AROUND X-AXIS ***
     658             : 
     659         296 :       DO iunit = 1, natoms
     660         198 :          ry = r(2, iunit) - center_of_mass(2)
     661         198 :          rz = r(3, iunit) - center_of_mass(3)
     662         198 :          rynew = cosdg*ry + sindg*rz
     663         198 :          rznew = cosdg*rz - sindg*ry
     664             : 
     665         198 :          r(2, iunit) = rynew + center_of_mass(2)
     666         296 :          r(3, iunit) = rznew + center_of_mass(3)
     667             : 
     668             :       END DO
     669             : 
     670             : ! ***    ROTATE UNITS OF I AROUND y-AXIS ***
     671             : 
     672         296 :       DO iunit = 1, natoms
     673         198 :          rx = r(1, iunit) - center_of_mass(1)
     674         198 :          rz = r(3, iunit) - center_of_mass(3)
     675         198 :          rxnew = cosdg*rx + sindg*rz
     676         198 :          rznew = cosdg*rz - sindg*rx
     677             : 
     678         198 :          r(1, iunit) = rxnew + center_of_mass(1)
     679         296 :          r(3, iunit) = rznew + center_of_mass(3)
     680             : 
     681             :       END DO
     682             : 
     683             : ! ***    ROTATE UNITS OF I AROUND z-AXIS ***
     684             : 
     685         296 :       DO iunit = 1, natoms
     686         198 :          rx = r(1, iunit) - center_of_mass(1)
     687         198 :          ry = r(2, iunit) - center_of_mass(2)
     688         198 :          rxnew = cosdg*rx + sindg*ry
     689         198 :          rynew = cosdg*ry - sindg*rx
     690             : 
     691         198 :          r(1, iunit) = rxnew + center_of_mass(1)
     692         296 :          r(2, iunit) = rynew + center_of_mass(2)
     693             : 
     694             :       END DO
     695             : 
     696             : ! end the timing
     697          98 :       CALL timestop(handle)
     698             : 
     699          98 :    END SUBROUTINE rotate_molecule
     700             : 
     701             : ! **************************************************************************************************
     702             : !> \brief selects a molecule at random to perform a MC move on...you can specify
     703             : !>      the box the molecule should be in, its type, both, or neither
     704             : !> \param mc_molecule_info the structure that contains some global molecule data
     705             : !> \param start_atom the number of the first atom in the chosen molecule in relation
     706             : !>        to the force_env it's in
     707             : !> \param box_number the box the chosen molecule is in
     708             : !> \param molecule_type the type of molecule the chosen molecule is
     709             : !> \param rng_stream the stream we pull random numbers from
     710             : !> \param box if present, tells the routine which box to grab a molecule from
     711             : !> \param molecule_type_old if present, tells the routine which molecule type to select from
     712             : !> \author MJM
     713             : ! **************************************************************************************************
     714         816 :    SUBROUTINE find_mc_test_molecule(mc_molecule_info, start_atom, &
     715             :                                     box_number, molecule_type, rng_stream, box, molecule_type_old)
     716             : 
     717             :       TYPE(mc_molecule_info_type), POINTER               :: mc_molecule_info
     718             :       INTEGER, INTENT(OUT)                               :: start_atom, box_number, molecule_type
     719             :       TYPE(rng_stream_type), INTENT(INOUT)               :: rng_stream
     720             :       INTEGER, INTENT(IN), OPTIONAL                      :: box, molecule_type_old
     721             : 
     722             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'find_mc_test_molecule'
     723             : 
     724             :       INTEGER                                            :: handle, ibox, imol_type, imolecule, &
     725             :                                                             jbox, molecule_number, nchains_tot, &
     726             :                                                             start_mol
     727         816 :       INTEGER, DIMENSION(:), POINTER                     :: mol_type, nunits
     728         816 :       INTEGER, DIMENSION(:, :), POINTER                  :: nchains
     729             :       REAL(KIND=dp)                                      :: rand
     730             : 
     731             : ! begin the timing of the subroutine
     732             : 
     733         816 :       CALL timeset(routineN, handle)
     734             : 
     735         816 :       NULLIFY (nunits, mol_type, nchains)
     736             :       CALL get_mc_molecule_info(mc_molecule_info, nchains=nchains, nunits=nunits, &
     737         816 :                                 mol_type=mol_type)
     738             : 
     739             : ! initialize the outgoing variables
     740         816 :       start_atom = 0
     741         816 :       box_number = 0
     742         816 :       molecule_type = 0
     743             : 
     744         816 :       IF (PRESENT(box) .AND. PRESENT(molecule_type_old)) THEN
     745             : ! only need to find the atom number the molecule starts on
     746         253 :          rand = rng_stream%next()
     747         253 :          molecule_number = CEILING(rand*REAL(nchains(molecule_type_old, box), KIND=dp))
     748             : 
     749         253 :          start_mol = 1
     750         253 :          DO jbox = 1, box - 1
     751         253 :             start_mol = start_mol + SUM(nchains(:, jbox))
     752             :          END DO
     753             : 
     754             : ! adjust to take into account molecules of other types in the box
     755         253 :          DO imol_type = 1, molecule_type_old - 1
     756         253 :             molecule_number = molecule_number + nchains(imol_type, box)
     757             :          END DO
     758             : 
     759         253 :          start_atom = 1
     760         981 :          DO imolecule = 1, molecule_number - 1
     761         981 :             start_atom = start_atom + nunits(mol_type(start_mol + imolecule - 1))
     762             :          END DO
     763             : 
     764         563 :       ELSEIF (PRESENT(box)) THEN
     765             : ! any molecule in box...need to find molecule type and start atom
     766           0 :          rand = rng_stream%next()
     767           0 :          molecule_number = CEILING(rand*REAL(SUM(nchains(:, box)), KIND=dp))
     768             : 
     769           0 :          start_mol = 1
     770           0 :          DO jbox = 1, box - 1
     771           0 :             start_mol = start_mol + SUM(nchains(:, jbox))
     772             :          END DO
     773             : 
     774           0 :          molecule_type = mol_type(start_mol + molecule_number - 1)
     775             : 
     776             : ! now the starting atom
     777           0 :          start_atom = 1
     778           0 :          DO imolecule = 1, molecule_number - 1
     779           0 :             start_atom = start_atom + nunits(mol_type(start_mol + imolecule - 1))
     780             :          END DO
     781             : 
     782         563 :       ELSEIF (PRESENT(molecule_type_old)) THEN
     783             : ! any molecule of type molecule_type_old...need to find box number and start atom
     784         563 :          rand = rng_stream%next()
     785        1162 :          molecule_number = CEILING(rand*REAL(SUM(nchains(molecule_type_old, :)), KIND=dp))
     786             : 
     787             : ! find which box it's in
     788         563 :          nchains_tot = 0
     789         578 :          DO ibox = 1, SIZE(nchains(molecule_type_old, :))
     790         578 :             IF (molecule_number .LE. nchains(molecule_type_old, ibox)) THEN
     791         563 :                box_number = ibox
     792         563 :                EXIT
     793             :             END IF
     794          15 :             molecule_number = molecule_number - nchains(molecule_type_old, ibox)
     795             :          END DO
     796             : 
     797         563 :          start_mol = 1
     798         578 :          DO jbox = 1, box_number - 1
     799         608 :             start_mol = start_mol + SUM(nchains(:, jbox))
     800             :          END DO
     801             : 
     802             : ! now find the starting atom number
     803         713 :          DO imol_type = 1, molecule_type_old - 1
     804         713 :             molecule_number = molecule_number + nchains(imol_type, box_number)
     805             :          END DO
     806         563 :          start_atom = 1
     807        3237 :          DO imolecule = 1, molecule_number - 1
     808        3237 :             start_atom = start_atom + nunits(mol_type(start_mol + imolecule - 1))
     809             :          END DO
     810             : 
     811             :       ELSE
     812             : ! no restrictions...need to find all pieces of data
     813           0 :          nchains_tot = 0
     814           0 :          DO ibox = 1, SIZE(nchains(1, :))
     815           0 :             nchains_tot = nchains_tot + SUM(nchains(:, ibox))
     816             :          END DO
     817           0 :          rand = rng_stream%next()
     818           0 :          molecule_number = CEILING(rand*REAL(nchains_tot, KIND=dp))
     819             : 
     820           0 :          molecule_type = mol_type(molecule_number)
     821             : 
     822             : ! now which box it's in
     823           0 :          DO ibox = 1, SUM(nchains(1, :))
     824           0 :             IF (molecule_number .LE. SUM(nchains(:, ibox))) THEN
     825           0 :                box_number = ibox
     826           0 :                EXIT
     827             :             END IF
     828           0 :             molecule_number = molecule_number - SUM(nchains(:, ibox))
     829             :          END DO
     830             : 
     831             : ! now find the starting atom number
     832           0 :          start_mol = 1
     833           0 :          DO jbox = 1, box_number - 1
     834           0 :             start_mol = start_mol + SUM(nchains(:, jbox))
     835             :          END DO
     836           0 :          start_atom = 1
     837           0 :          DO imolecule = 1, molecule_number - 1
     838           0 :             start_atom = start_atom + nunits(mol_type(start_mol + imolecule - 1))
     839             :          END DO
     840             : 
     841             :       END IF
     842             : 
     843             : ! make sure things are good
     844         816 :       IF (PRESENT(box)) box_number = box
     845         816 :       IF (PRESENT(molecule_type_old)) molecule_type = molecule_type_old
     846             : 
     847         816 :       CPASSERT(start_atom /= 0)
     848         816 :       CPASSERT(box_number /= 0)
     849         816 :       CPASSERT(molecule_type /= 0)
     850             : 
     851             : ! end the timing
     852         816 :       CALL timestop(handle)
     853             : 
     854         816 :    END SUBROUTINE find_mc_test_molecule
     855             : 
     856             : ! **************************************************************************************************
     857             : !> \brief generates an array that tells us which sides of the simulation
     858             : !>      cell we can increase or decrease using a discrete volume move
     859             : !> \param cell the lengths of the sides of the cell
     860             : !> \param discrete_array the array that indicates which sides we can move
     861             : !> \param step_size the size of the discrete volume move
     862             : !>
     863             : !>    Suitable for parallel.
     864             : !> \author MJM
     865             : ! **************************************************************************************************
     866           0 :    SUBROUTINE create_discrete_array(cell, discrete_array, step_size)
     867             : 
     868             : ! 1 is for increase, 2 is for decrease
     869             : ! 1 is for "yes, we can do the move", 0 is for no
     870             : 
     871             :       REAL(dp), DIMENSION(1:3), INTENT(IN)               :: cell
     872             :       INTEGER, DIMENSION(1:3, 1:2), INTENT(OUT)          :: discrete_array
     873             :       REAL(dp), INTENT(IN)                               :: step_size
     874             : 
     875             :       INTEGER                                            :: iside
     876             :       REAL(dp)                                           :: high_value, length1, length2, low_value
     877             : 
     878           0 :       discrete_array(:, :) = 0
     879             : 
     880           0 :       length1 = ABS(cell(1) - cell(2))
     881           0 :       length2 = ABS(cell(2) - cell(3))
     882             : 
     883             : ! now let's figure out all the different cases
     884           0 :       IF (length1 .LT. 0.01_dp*step_size .AND. &
     885             :           length2 .LT. 0.01_dp*step_size) THEN
     886             : ! all sides are equal, so we can move up or down
     887           0 :          discrete_array(1:3, 1) = 1
     888           0 :          discrete_array(1:3, 2) = 1
     889             :       ELSE
     890             : 
     891             : ! find the low value and the high value
     892           0 :          high_value = -1.0_dp
     893           0 :          low_value = cell(1)*cell(2)*cell(3)
     894           0 :          DO iside = 1, 3
     895           0 :             IF (cell(iside) .LT. low_value) low_value = cell(iside)
     896           0 :             IF (cell(iside) .GT. high_value) high_value = cell(iside)
     897             :          END DO
     898           0 :          DO iside = 1, 3
     899             : ! now we see if the value is a high value or a low value...it can only be
     900             : ! one of the two
     901           0 :             IF (ABS(cell(iside) - low_value) .LT. 0.01_dp*step_size) THEN
     902             : ! low value, we can only increase the cell size
     903           0 :                discrete_array(iside, 1) = 1
     904           0 :                discrete_array(iside, 2) = 0
     905             :             ELSE
     906             : ! high value, we can only decrease the cell size
     907           0 :                discrete_array(iside, 1) = 0
     908           0 :                discrete_array(iside, 2) = 1
     909             :             END IF
     910             :          END DO
     911             :       END IF
     912             : 
     913           0 :    END SUBROUTINE create_discrete_array
     914             : 
     915             : ! **************************************************************************************************
     916             : !> \brief generates an insertion point in either the "in" or the "out" volume
     917             : !>      of a target atom, where the "in" volume is a shell with inner radius
     918             : !>       rmin and outer radius rmax
     919             : !> \param rmin the minimum AVBMC radius for the shell around the target
     920             : !> \param rmax the maximum AVBMC radius for the shell around the target
     921             : !> \param r_target the coordinates of the target atom
     922             : !> \param move_type generate configs in the "in" or "out" volume
     923             : !> \param r_insert the output insertion site
     924             : !> \param abc the lengths of the sides of the simulation box
     925             : !> \param rng_stream the random number stream that we draw from
     926             : !>
     927             : !>      Use only in serial.
     928             : !> \author MJM
     929             : ! **************************************************************************************************
     930           0 :    SUBROUTINE generate_avbmc_insertion(rmin, rmax, r_target, &
     931             :                                        move_type, r_insert, abc, rng_stream)
     932             : 
     933             :       REAL(KIND=dp), INTENT(IN)                          :: rmin, rmax
     934             :       REAL(KIND=dp), DIMENSION(1:3), INTENT(IN)          :: r_target
     935             :       CHARACTER(LEN=*), INTENT(IN)                       :: move_type
     936             :       REAL(KIND=dp), DIMENSION(1:3), INTENT(OUT)         :: r_insert
     937             :       REAL(KIND=dp), DIMENSION(1:3), INTENT(IN)          :: abc
     938             :       TYPE(rng_stream_type), INTENT(INOUT)               :: rng_stream
     939             : 
     940             :       INTEGER                                            :: i
     941             :       REAL(dp)                                           :: dist, eta_1, eta_2, eta_sq, rand
     942             :       REAL(dp), DIMENSION(1:3)                           :: RIJ
     943             : 
     944           0 :       r_insert(1:3) = 0.0_dp
     945             : 
     946           0 :       IF (move_type == 'in') THEN
     947             : ! generate a random unit vector, from Allen and Tildesley
     948             :          DO
     949           0 :             eta_1 = rng_stream%next()
     950           0 :             eta_2 = rng_stream%next()
     951           0 :             eta_sq = eta_1**2 + eta_2**2
     952           0 :             IF (eta_sq .LT. 1.0_dp) THEN
     953           0 :                r_insert(1) = 2.0_dp*eta_1*SQRT(1.0_dp - eta_sq)
     954           0 :                r_insert(2) = 2.0_dp*eta_2*SQRT(1.0_dp - eta_sq)
     955           0 :                r_insert(3) = 1.0_dp - 2.0_dp*eta_sq
     956             :                EXIT
     957             :             END IF
     958             :          END DO
     959             : 
     960             : ! now scale that vector to be within the "in" region
     961           0 :          rand = rng_stream%next()
     962             :          r_insert(1:3) = r_insert(1:3)*(rand*(rmax**3 - rmin**3) + rmin**3)** &
     963           0 :                          (1.0_dp/3.0_dp)
     964             : 
     965           0 :          r_insert(1:3) = r_target(1:3) + r_insert(1:3)
     966             :       ELSE
     967             : 
     968             : ! find a new insertion point somewhere in the box
     969             :          DO
     970           0 :             DO i = 1, 3
     971           0 :                rand = rng_stream%next()
     972           0 :                r_insert(i) = rand*abc(i)
     973             :             END DO
     974             : 
     975             : ! make sure it's not in the "in" region
     976             :             RIJ(1) = r_insert(1) - r_target(1) - abc(1)* &
     977           0 :                      ANINT((r_insert(1) - r_target(1))/abc(1))
     978             :             RIJ(2) = r_insert(2) - r_target(2) - abc(2)* &
     979           0 :                      ANINT((r_insert(2) - r_target(2))/abc(2))
     980             :             RIJ(3) = r_insert(3) - r_target(3) - abc(3)* &
     981           0 :                      ANINT((r_insert(3) - r_target(3))/abc(3))
     982             : 
     983           0 :             dist = RIJ(1)**2 + RIJ(2)**2 + RIJ(3)**2
     984             : 
     985           0 :             IF (dist .LT. rmin**2 .OR. dist .GT. rmax**2) THEN
     986             :                EXIT
     987             :             END IF
     988             : 
     989             :          END DO
     990             :       END IF
     991             : 
     992           0 :    END SUBROUTINE generate_avbmc_insertion
     993             : 
     994             : ! *****************************************************************************
     995             : ! **************************************************************************************************
     996             : !> \brief determine the number of cluster present in the given configuration
     997             : !>   based on the rclus value
     998             : !> \param mc_par the mc parameters for the force env
     999             : !> \param force_env the force environment containing the coordinates
    1000             : !> \param cluster ...
    1001             : !> \param nchains the number of molecules of each type in the box
    1002             : !> \param nunits the number of interaction sites for each molecule
    1003             : !> \param mol_type an array that indicates the type of each molecule
    1004             : !> \param total_clus ...
    1005             : !> \par
    1006             : !>    Original Multiparticle/Cluster Translation paper:
    1007             : !> Orkoulas, Gerassimos, and Athanassios Z. Panagiotopoulos. Free energy and
    1008             : !> phase equilibria for the restricted primitive model of ionic fluids from Monte
    1009             : !> Carlo simulations. J. Chem. Phys. 1994,101.2,1452-1459.
    1010             : !> \author Himanshu Goel
    1011             : ! **************************************************************************************************
    1012             : 
    1013          20 :    SUBROUTINE cluster_search(mc_par, force_env, cluster, nchains, nunits, mol_type, total_clus)
    1014             : 
    1015             :       TYPE(mc_simpar_type), POINTER                      :: mc_par
    1016             :       TYPE(force_env_type), POINTER                      :: force_env
    1017             :       INTEGER, DIMENSION(:, :), INTENT(INOUT)            :: cluster
    1018             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: nchains, nunits, mol_type
    1019             :       INTEGER, INTENT(INOUT)                             :: total_clus
    1020             : 
    1021             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cluster_search'
    1022             : 
    1023             :       INTEGER                                            :: counter, handle, imol, iunit, jmol, &
    1024             :                                                             junit, nend, nstart, nunit, nunits_i, &
    1025             :                                                             nunits_j
    1026          20 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: clusmat, decision
    1027             :       LOGICAL                                            :: lclus
    1028             :       REAL(KIND=dp)                                      :: dx, dy, dz, rclus, rclussquare, rsquare
    1029          20 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: xcoord, ycoord, zcoord
    1030          20 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: r
    1031             :       REAL(KIND=dp), DIMENSION(1:3)                      :: abc
    1032             :       TYPE(cell_type), POINTER                           :: cell
    1033             :       TYPE(cp_subsys_type), POINTER                      :: oldsys
    1034             :       TYPE(particle_list_type), POINTER                  :: particles
    1035             : 
    1036             : ! begin the timing of the subroutine
    1037             : 
    1038          20 :       CALL timeset(routineN, handle)
    1039             : 
    1040          20 :       NULLIFY (oldsys, particles)
    1041             : 
    1042             : ! Getting Particle Coordinates
    1043             : 
    1044          20 :       CALL force_env_get(force_env, cell=cell, subsys=oldsys)
    1045          20 :       CALL get_cell(cell, abc=abc)
    1046          20 :       CALL cp_subsys_get(oldsys, particles=particles)
    1047          20 :       CALL get_mc_par(mc_par, rclus=rclus)
    1048             : 
    1049         120 :       ALLOCATE (r(1:3, 1:MAXVAL(nunits), 1:SUM(nchains)))
    1050             : 
    1051             : ! Arranging particles coordinates into an easier matrix
    1052          40 :       nend = SUM(nchains(:))
    1053             :       junit = 0
    1054         120 :       DO imol = 1, nend
    1055         100 :          nunit = nunits(mol_type(imol))
    1056         320 :          DO iunit = 1, nunit
    1057         200 :             junit = junit + 1
    1058         900 :             r(1:3, iunit, imol) = particles%els(junit)%r(1:3)
    1059             :          END DO
    1060             :       END DO
    1061             : 
    1062          20 :       counter = 0
    1063             : 
    1064             : ! Allocating the size of matrix and decision matrix
    1065          80 :       ALLOCATE (clusmat(nend), decision(nend))
    1066             : 
    1067             : !Initialize
    1068         120 :       DO imol = 1, nend
    1069         100 :          decision(imol) = 0
    1070         120 :          clusmat(imol) = 0
    1071             :       END DO
    1072             : 
    1073          20 :       rclussquare = rclus*rclus
    1074             : ! Starting the cluster count loop
    1075         720 :       DO WHILE (SUM(decision) .LT. nend)
    1076         300 :          DO nstart = 1, nend
    1077         300 :             IF (clusmat(nstart) .EQ. 0) THEN
    1078         100 :                counter = counter + 1
    1079         100 :                clusmat(nstart) = counter
    1080         100 :                EXIT
    1081             :             END IF
    1082             :          END DO
    1083             : 
    1084         100 :          lclus = .TRUE.
    1085         320 :          DO WHILE (lclus .EQV. .TRUE.)
    1086         900 :             DO imol = 1, nend
    1087         800 :                nunits_i = nunits(mol_type(imol))
    1088             : ! Allocating the xcoord,ycoord,zcoord based upon the size of molecule nunits
    1089         800 :                lclus = .FALSE.
    1090         900 :                IF (clusmat(imol) .EQ. counter .AND. decision(imol) .EQ. 0) THEN
    1091         500 :                   ALLOCATE (xcoord(nunits_i), ycoord(nunits_i), zcoord(nunits_i))
    1092         100 :                   decision(imol) = 1
    1093         100 :                   lclus = .TRUE.
    1094         300 :                   DO iunit = 1, nunits_i
    1095         200 :                      xcoord(iunit) = r(1, iunit, imol)
    1096         200 :                      ycoord(iunit) = r(2, iunit, imol)
    1097         300 :                      zcoord(iunit) = r(3, iunit, imol)
    1098             :                   END DO
    1099             :                   EXIT
    1100             :                END IF
    1101             :             END DO
    1102         300 :             IF (lclus .EQV. .TRUE.) THEN
    1103         600 :                DO jmol = 1, nend
    1104         500 :                   nunits_j = nunits(mol_type(jmol))
    1105         600 :                   IF (clusmat(jmol) .EQ. 0 .AND. decision(jmol) .EQ. 0) THEN
    1106             : !Calculating the distance between atoms
    1107         600 :                      DO iunit = 1, nunits_i
    1108        1400 :                         DO junit = 1, nunits_j
    1109         800 :                            dx = xcoord(iunit) - r(1, junit, jmol)
    1110         800 :                            dy = ycoord(iunit) - r(2, junit, jmol)
    1111         800 :                            dz = zcoord(iunit) - r(3, junit, jmol)
    1112         800 :                            dx = dx - abc(1)*ANINT(dx/abc(1))
    1113         800 :                            dy = dy - abc(2)*ANINT(dy/abc(2))
    1114         800 :                            dz = dz - abc(3)*ANINT(dz/abc(3))
    1115         800 :                            rsquare = (dx*dx) + (dy*dy) + (dz*dz)
    1116             : !Checking the distance based on rclus square(rclussq)
    1117        1200 :                            IF (rsquare .LT. rclussquare) THEN
    1118           0 :                               clusmat(jmol) = counter
    1119             :                            END IF
    1120             :                         END DO
    1121             :                      END DO
    1122             :                   END IF
    1123             :                END DO
    1124         100 :                DEALLOCATE (xcoord, ycoord, zcoord)
    1125             :             END IF
    1126             :          END DO
    1127             :       END DO
    1128             : 
    1129             : !Putting cluster information in a cluster matrix
    1130          20 :       total_clus = counter
    1131             : 
    1132         120 :       DO imol = 1, counter
    1133         620 :          DO jmol = 1, nend
    1134         600 :             IF (imol .EQ. clusmat(jmol)) THEN
    1135         100 :                cluster(imol, jmol) = jmol
    1136             :             END IF
    1137             :          END DO
    1138             :       END DO
    1139          20 :       DEALLOCATE (r)
    1140          20 :       DEALLOCATE (decision)
    1141          20 :       DEALLOCATE (clusmat)
    1142             : 
    1143             : ! end the timing
    1144          20 :       CALL timestop(handle)
    1145             : 
    1146          60 :    END SUBROUTINE cluster_search
    1147             : 
    1148             : END MODULE mc_coordinates
    1149             : 

Generated by: LCOV version 1.15