LCOV - code coverage report
Current view: top level - src/motion/mc - mc_coordinates.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 71.0 % 420 298
Test Date: 2026-07-25 06:35:44 Functions: 66.7 % 9 6

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 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 = 1.28558315_dp ! 0.6 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        32084 :       DO imol = nstart, nend
     137        24170 :          IF (lall) jstart = imol + 1
     138        24170 :          nunits_i = nunits(mol_type(imol))
     139       161714 :          DO jmol = jstart, SUM(nchains(:))
     140        93262 :             IF (imol == jmol) CYCLE
     141        91456 :             nunits_j = nunits(mol_type(jmol))
     142              : 
     143       353170 :             DO iunit = 1, nunits_i
     144       761138 :                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       430332 :                            (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       430332 :                            (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       430332 :                            (r(3, iunit, imol) - r(3, junit, jmol))/box_length(3))
     155              : 
     156       430332 :                   dist = RIJ(1)**2 + RIJ(2)**2 + RIJ(3)**2
     157              : 
     158       668612 :                   IF (dist < rmin) THEN
     159          736 :                      loverlap = .TRUE.
     160          736 :                      DEALLOCATE (r)
     161              : 
     162          736 :                      CALL timestop(handle)
     163              :                      RETURN
     164              :                   END IF
     165              : 
     166              :                END DO
     167              :             END DO
     168              :          END DO
     169              :       END DO
     170              : 
     171         7914 :       DEALLOCATE (r)
     172              : 
     173              : ! end the timing
     174         7914 :       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           44 :       loverlap_array(:) = .FALSE.
     396           44 :       loverlap = .FALSE.
     397           44 :       boltz_weights(:) = 0.0_dp
     398           44 :       trial_energy(:) = 0.0_dp
     399           44 :       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            2 :             boltz_weights(imove) = 0.0_dp
     507            2 :             CYCLE
     508              :          END IF
     509              : 
     510          174 :          CALL force_env_calc_energy_force(force_env, calc_force=.FALSE.)
     511              :          CALL force_env_get(force_env, &
     512          174 :                             potential_energy=bias_energy)
     513              : 
     514          174 :          trial_energy(imove) = (bias_energy - old_energy)
     515          174 :          exponent = -BETA*trial_energy(imove)
     516              : 
     517          218 :          IF (exponent > exp_max_val) THEN
     518            0 :             boltz_weights(imove) = max_val
     519          174 :          ELSE IF (exponent < exp_min_val) THEN
     520            6 :             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 == 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           98 :          all_overlaps = .FALSE.
     556           98 :          total_running_weight = total_running_weight + boltz_weights(imove)
     557           98 :          IF (total_running_weight >= 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) THEN
     591            0 :          CPABORT('CBMC swap move failed to select config')
     592              :       END IF
     593              : 
     594              : ! if this is an old configuration, we always choose the first one
     595           44 :       IF (lremove) choosen = 1
     596              : 
     597              : ! set the energy for the configuration
     598           44 :       choosen_energy = trial_energy(choosen)
     599              : 
     600              : ! copy the coordinates to the force environment
     601         1186 :       DO iatom = 1, natoms_tot
     602         4612 :          particles%els(iatom)%r(1:3) = r(1:3, iatom, choosen)
     603              :       END DO
     604              : 
     605           44 :       DEALLOCATE (r_old)
     606           44 :       DEALLOCATE (r)
     607           44 :       DEALLOCATE (trial_energy)
     608           44 :       DEALLOCATE (boltz_weights)
     609           44 :       DEALLOCATE (loverlap_array)
     610              : 
     611              : ! end the timing
     612           44 :       CALL timestop(handle)
     613              : 
     614           44 :    END SUBROUTINE generate_cbmc_swap_config
     615              : 
     616              : ! **************************************************************************************************
     617              : !> \brief rotates a molecule randomly around the center of mass,
     618              : !>      sequentially in x, y, and z directions
     619              : !> \param r the coordinates of the molecule to rotate
     620              : !> \param mass the mass of all the atoms in the molecule
     621              : !> \param natoms the number of atoms in the molecule
     622              : !> \param rng_stream the stream we pull random numbers from
     623              : !>
     624              : !>    Use only in serial.
     625              : !> \author MJM
     626              : ! **************************************************************************************************
     627           98 :    SUBROUTINE rotate_molecule(r, mass, natoms, rng_stream)
     628              : 
     629              :       INTEGER, INTENT(IN)                                :: natoms
     630              :       REAL(KIND=dp), DIMENSION(1:natoms), INTENT(IN)     :: mass
     631              :       REAL(KIND=dp), DIMENSION(1:3, 1:natoms), &
     632              :          INTENT(INOUT)                                   :: r
     633              :       TYPE(rng_stream_type), INTENT(INOUT)               :: rng_stream
     634              : 
     635              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'rotate_molecule'
     636              : 
     637              :       INTEGER                                            :: handle, iunit
     638              :       REAL(KIND=dp)                                      :: cosdg, dgamma, rand, rx, rxnew, ry, &
     639              :                                                             rynew, rz, rznew, sindg
     640              :       REAL(KIND=dp), DIMENSION(1:3)                      :: center_of_mass
     641              : 
     642              : ! begin the timing of the subroutine
     643              : 
     644           98 :       CALL timeset(routineN, handle)
     645              : 
     646              : ! find the center of mass of the molecule
     647           98 :       CALL get_center_of_mass(r(:, :), natoms, center_of_mass(:), mass(:))
     648              : 
     649              : ! call a random number to figure out how far we're moving
     650           98 :       rand = rng_stream%next()
     651           98 :       dgamma = pi*(rand - 0.5E0_dp)*2.0E0_dp
     652              : 
     653              : ! *** set up the rotation matrix ***
     654              : 
     655           98 :       cosdg = COS(dgamma)
     656           98 :       sindg = SIN(dgamma)
     657              : 
     658              : ! ***    ROTATE UNITS OF I AROUND X-AXIS ***
     659              : 
     660          296 :       DO iunit = 1, natoms
     661          198 :          ry = r(2, iunit) - center_of_mass(2)
     662          198 :          rz = r(3, iunit) - center_of_mass(3)
     663          198 :          rynew = cosdg*ry + sindg*rz
     664          198 :          rznew = cosdg*rz - sindg*ry
     665              : 
     666          198 :          r(2, iunit) = rynew + center_of_mass(2)
     667          296 :          r(3, iunit) = rznew + center_of_mass(3)
     668              : 
     669              :       END DO
     670              : 
     671              : ! ***    ROTATE UNITS OF I AROUND y-AXIS ***
     672              : 
     673          296 :       DO iunit = 1, natoms
     674          198 :          rx = r(1, iunit) - center_of_mass(1)
     675          198 :          rz = r(3, iunit) - center_of_mass(3)
     676          198 :          rxnew = cosdg*rx + sindg*rz
     677          198 :          rznew = cosdg*rz - sindg*rx
     678              : 
     679          198 :          r(1, iunit) = rxnew + center_of_mass(1)
     680          296 :          r(3, iunit) = rznew + center_of_mass(3)
     681              : 
     682              :       END DO
     683              : 
     684              : ! ***    ROTATE UNITS OF I AROUND z-AXIS ***
     685              : 
     686          296 :       DO iunit = 1, natoms
     687          198 :          rx = r(1, iunit) - center_of_mass(1)
     688          198 :          ry = r(2, iunit) - center_of_mass(2)
     689          198 :          rxnew = cosdg*rx + sindg*ry
     690          198 :          rynew = cosdg*ry - sindg*rx
     691              : 
     692          198 :          r(1, iunit) = rxnew + center_of_mass(1)
     693          296 :          r(2, iunit) = rynew + center_of_mass(2)
     694              : 
     695              :       END DO
     696              : 
     697              : ! end the timing
     698           98 :       CALL timestop(handle)
     699              : 
     700           98 :    END SUBROUTINE rotate_molecule
     701              : 
     702              : ! **************************************************************************************************
     703              : !> \brief selects a molecule at random to perform a MC move on...you can specify
     704              : !>      the box the molecule should be in, its type, both, or neither
     705              : !> \param mc_molecule_info the structure that contains some global molecule data
     706              : !> \param start_atom the number of the first atom in the chosen molecule in relation
     707              : !>        to the force_env it's in
     708              : !> \param box_number the box the chosen molecule is in
     709              : !> \param molecule_type the type of molecule the chosen molecule is
     710              : !> \param rng_stream the stream we pull random numbers from
     711              : !> \param box if present, tells the routine which box to grab a molecule from
     712              : !> \param molecule_type_old if present, tells the routine which molecule type to select from
     713              : !> \author MJM
     714              : ! **************************************************************************************************
     715          816 :    SUBROUTINE find_mc_test_molecule(mc_molecule_info, start_atom, &
     716              :                                     box_number, molecule_type, rng_stream, box, molecule_type_old)
     717              : 
     718              :       TYPE(mc_molecule_info_type), POINTER               :: mc_molecule_info
     719              :       INTEGER, INTENT(OUT)                               :: start_atom, box_number, molecule_type
     720              :       TYPE(rng_stream_type), INTENT(INOUT)               :: rng_stream
     721              :       INTEGER, INTENT(IN), OPTIONAL                      :: box, molecule_type_old
     722              : 
     723              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'find_mc_test_molecule'
     724              : 
     725              :       INTEGER                                            :: handle, ibox, imol_type, imolecule, &
     726              :                                                             jbox, molecule_number, nchains_tot, &
     727              :                                                             start_mol
     728          816 :       INTEGER, DIMENSION(:), POINTER                     :: mol_type, nunits
     729          816 :       INTEGER, DIMENSION(:, :), POINTER                  :: nchains
     730              :       REAL(KIND=dp)                                      :: rand
     731              : 
     732              : ! begin the timing of the subroutine
     733              : 
     734          816 :       CALL timeset(routineN, handle)
     735              : 
     736          816 :       NULLIFY (nunits, mol_type, nchains)
     737              :       CALL get_mc_molecule_info(mc_molecule_info, nchains=nchains, nunits=nunits, &
     738          816 :                                 mol_type=mol_type)
     739              : 
     740              : ! initialize the outgoing variables
     741          816 :       start_atom = 0
     742          816 :       box_number = 0
     743          816 :       molecule_type = 0
     744              : 
     745          816 :       IF (PRESENT(box) .AND. PRESENT(molecule_type_old)) THEN
     746              : ! only need to find the atom number the molecule starts on
     747          253 :          rand = rng_stream%next()
     748          253 :          molecule_number = CEILING(rand*REAL(nchains(molecule_type_old, box), KIND=dp))
     749              : 
     750          253 :          start_mol = 1
     751          253 :          DO jbox = 1, box - 1
     752          253 :             start_mol = start_mol + SUM(nchains(:, jbox))
     753              :          END DO
     754              : 
     755              : ! adjust to take into account molecules of other types in the box
     756          253 :          DO imol_type = 1, molecule_type_old - 1
     757          253 :             molecule_number = molecule_number + nchains(imol_type, box)
     758              :          END DO
     759              : 
     760          253 :          start_atom = 1
     761          981 :          DO imolecule = 1, molecule_number - 1
     762          981 :             start_atom = start_atom + nunits(mol_type(start_mol + imolecule - 1))
     763              :          END DO
     764              : 
     765          563 :       ELSE IF (PRESENT(box)) THEN
     766              : ! any molecule in box...need to find molecule type and start atom
     767            0 :          rand = rng_stream%next()
     768            0 :          molecule_number = CEILING(rand*REAL(SUM(nchains(:, box)), KIND=dp))
     769              : 
     770            0 :          start_mol = 1
     771            0 :          DO jbox = 1, box - 1
     772            0 :             start_mol = start_mol + SUM(nchains(:, jbox))
     773              :          END DO
     774              : 
     775            0 :          molecule_type = mol_type(start_mol + molecule_number - 1)
     776              : 
     777              : ! now the starting atom
     778            0 :          start_atom = 1
     779            0 :          DO imolecule = 1, molecule_number - 1
     780            0 :             start_atom = start_atom + nunits(mol_type(start_mol + imolecule - 1))
     781              :          END DO
     782              : 
     783          563 :       ELSE IF (PRESENT(molecule_type_old)) THEN
     784              : ! any molecule of type molecule_type_old...need to find box number and start atom
     785          563 :          rand = rng_stream%next()
     786         1162 :          molecule_number = CEILING(rand*REAL(SUM(nchains(molecule_type_old, :)), KIND=dp))
     787              : 
     788              : ! find which box it's in
     789          563 :          nchains_tot = 0
     790          578 :          DO ibox = 1, SIZE(nchains(molecule_type_old, :))
     791          578 :             IF (molecule_number <= nchains(molecule_type_old, ibox)) THEN
     792          563 :                box_number = ibox
     793          563 :                EXIT
     794              :             END IF
     795           15 :             molecule_number = molecule_number - nchains(molecule_type_old, ibox)
     796              :          END DO
     797              : 
     798          563 :          start_mol = 1
     799          578 :          DO jbox = 1, box_number - 1
     800          608 :             start_mol = start_mol + SUM(nchains(:, jbox))
     801              :          END DO
     802              : 
     803              : ! now find the starting atom number
     804          713 :          DO imol_type = 1, molecule_type_old - 1
     805          713 :             molecule_number = molecule_number + nchains(imol_type, box_number)
     806              :          END DO
     807          563 :          start_atom = 1
     808         3237 :          DO imolecule = 1, molecule_number - 1
     809         3237 :             start_atom = start_atom + nunits(mol_type(start_mol + imolecule - 1))
     810              :          END DO
     811              : 
     812              :       ELSE
     813              : ! no restrictions...need to find all pieces of data
     814            0 :          nchains_tot = 0
     815            0 :          DO ibox = 1, SIZE(nchains(1, :))
     816            0 :             nchains_tot = nchains_tot + SUM(nchains(:, ibox))
     817              :          END DO
     818            0 :          rand = rng_stream%next()
     819            0 :          molecule_number = CEILING(rand*REAL(nchains_tot, KIND=dp))
     820              : 
     821            0 :          molecule_type = mol_type(molecule_number)
     822              : 
     823              : ! now which box it's in
     824            0 :          DO ibox = 1, SUM(nchains(1, :))
     825            0 :             IF (molecule_number <= SUM(nchains(:, ibox))) THEN
     826            0 :                box_number = ibox
     827            0 :                EXIT
     828              :             END IF
     829            0 :             molecule_number = molecule_number - SUM(nchains(:, ibox))
     830              :          END DO
     831              : 
     832              : ! now find the starting atom number
     833            0 :          start_mol = 1
     834            0 :          DO jbox = 1, box_number - 1
     835            0 :             start_mol = start_mol + SUM(nchains(:, jbox))
     836              :          END DO
     837            0 :          start_atom = 1
     838            0 :          DO imolecule = 1, molecule_number - 1
     839            0 :             start_atom = start_atom + nunits(mol_type(start_mol + imolecule - 1))
     840              :          END DO
     841              : 
     842              :       END IF
     843              : 
     844              : ! make sure things are good
     845          816 :       IF (PRESENT(box)) box_number = box
     846          816 :       IF (PRESENT(molecule_type_old)) molecule_type = molecule_type_old
     847              : 
     848          816 :       CPASSERT(start_atom /= 0)
     849          816 :       CPASSERT(box_number /= 0)
     850          816 :       CPASSERT(molecule_type /= 0)
     851              : 
     852              : ! end the timing
     853          816 :       CALL timestop(handle)
     854              : 
     855          816 :    END SUBROUTINE find_mc_test_molecule
     856              : 
     857              : ! **************************************************************************************************
     858              : !> \brief generates an array that tells us which sides of the simulation
     859              : !>      cell we can increase or decrease using a discrete volume move
     860              : !> \param cell the lengths of the sides of the cell
     861              : !> \param discrete_array the array that indicates which sides we can move
     862              : !> \param step_size the size of the discrete volume move
     863              : !>
     864              : !>    Suitable for parallel.
     865              : !> \author MJM
     866              : ! **************************************************************************************************
     867            0 :    SUBROUTINE create_discrete_array(cell, discrete_array, step_size)
     868              : 
     869              : ! 1 is for increase, 2 is for decrease
     870              : ! 1 is for "yes, we can do the move", 0 is for no
     871              : 
     872              :       REAL(dp), DIMENSION(1:3), INTENT(IN)               :: cell
     873              :       INTEGER, DIMENSION(1:3, 1:2), INTENT(OUT)          :: discrete_array
     874              :       REAL(dp), INTENT(IN)                               :: step_size
     875              : 
     876              :       INTEGER                                            :: iside
     877              :       REAL(dp)                                           :: high_value, length1, length2, low_value
     878              : 
     879            0 :       discrete_array(:, :) = 0
     880              : 
     881            0 :       length1 = ABS(cell(1) - cell(2))
     882            0 :       length2 = ABS(cell(2) - cell(3))
     883              : 
     884              : ! now let's figure out all the different cases
     885            0 :       IF (length1 < 0.01_dp*step_size .AND. &
     886              :           length2 < 0.01_dp*step_size) THEN
     887              : ! all sides are equal, so we can move up or down
     888            0 :          discrete_array(1:3, 1) = 1
     889            0 :          discrete_array(1:3, 2) = 1
     890              :       ELSE
     891              : 
     892              : ! find the low value and the high value
     893            0 :          high_value = -1.0_dp
     894            0 :          low_value = cell(1)*cell(2)*cell(3)
     895            0 :          DO iside = 1, 3
     896            0 :             IF (cell(iside) < low_value) low_value = cell(iside)
     897            0 :             IF (cell(iside) > high_value) high_value = cell(iside)
     898              :          END DO
     899            0 :          DO iside = 1, 3
     900              : ! now we see if the value is a high value or a low value...it can only be
     901              : ! one of the two
     902            0 :             IF (ABS(cell(iside) - low_value) < 0.01_dp*step_size) THEN
     903              : ! low value, we can only increase the cell size
     904            0 :                discrete_array(iside, 1) = 1
     905            0 :                discrete_array(iside, 2) = 0
     906              :             ELSE
     907              : ! high value, we can only decrease the cell size
     908            0 :                discrete_array(iside, 1) = 0
     909            0 :                discrete_array(iside, 2) = 1
     910              :             END IF
     911              :          END DO
     912              :       END IF
     913              : 
     914            0 :    END SUBROUTINE create_discrete_array
     915              : 
     916              : ! **************************************************************************************************
     917              : !> \brief generates an insertion point in either the "in" or the "out" volume
     918              : !>      of a target atom, where the "in" volume is a shell with inner radius
     919              : !>       rmin and outer radius rmax
     920              : !> \param rmin the minimum AVBMC radius for the shell around the target
     921              : !> \param rmax the maximum AVBMC radius for the shell around the target
     922              : !> \param r_target the coordinates of the target atom
     923              : !> \param move_type generate configs in the "in" or "out" volume
     924              : !> \param r_insert the output insertion site
     925              : !> \param abc the lengths of the sides of the simulation box
     926              : !> \param rng_stream the random number stream that we draw from
     927              : !>
     928              : !>      Use only in serial.
     929              : !> \author MJM
     930              : ! **************************************************************************************************
     931            0 :    SUBROUTINE generate_avbmc_insertion(rmin, rmax, r_target, &
     932              :                                        move_type, r_insert, abc, rng_stream)
     933              : 
     934              :       REAL(KIND=dp), INTENT(IN)                          :: rmin, rmax
     935              :       REAL(KIND=dp), DIMENSION(1:3), INTENT(IN)          :: r_target
     936              :       CHARACTER(LEN=*), INTENT(IN)                       :: move_type
     937              :       REAL(KIND=dp), DIMENSION(1:3), INTENT(OUT)         :: r_insert
     938              :       REAL(KIND=dp), DIMENSION(1:3), INTENT(IN)          :: abc
     939              :       TYPE(rng_stream_type), INTENT(INOUT)               :: rng_stream
     940              : 
     941              :       INTEGER                                            :: i
     942              :       REAL(dp)                                           :: dist, eta_1, eta_2, eta_sq, rand
     943              :       REAL(dp), DIMENSION(1:3)                           :: RIJ
     944              : 
     945            0 :       r_insert(1:3) = 0.0_dp
     946              : 
     947            0 :       IF (move_type == 'in') THEN
     948              : ! generate a random unit vector, from Allen and Tildesley
     949              :          DO
     950            0 :             eta_1 = rng_stream%next()
     951            0 :             eta_2 = rng_stream%next()
     952            0 :             eta_sq = eta_1**2 + eta_2**2
     953            0 :             IF (eta_sq < 1.0_dp) THEN
     954            0 :                r_insert(1) = 2.0_dp*eta_1*SQRT(1.0_dp - eta_sq)
     955            0 :                r_insert(2) = 2.0_dp*eta_2*SQRT(1.0_dp - eta_sq)
     956            0 :                r_insert(3) = 1.0_dp - 2.0_dp*eta_sq
     957              :                EXIT
     958              :             END IF
     959              :          END DO
     960              : 
     961              : ! now scale that vector to be within the "in" region
     962            0 :          rand = rng_stream%next()
     963              :          r_insert(1:3) = r_insert(1:3)*(rand*(rmax**3 - rmin**3) + rmin**3)** &
     964            0 :                          (1.0_dp/3.0_dp)
     965              : 
     966            0 :          r_insert(1:3) = r_target(1:3) + r_insert(1:3)
     967              :       ELSE
     968              : 
     969              : ! find a new insertion point somewhere in the box
     970              :          DO
     971            0 :             DO i = 1, 3
     972            0 :                rand = rng_stream%next()
     973            0 :                r_insert(i) = rand*abc(i)
     974              :             END DO
     975              : 
     976              : ! make sure it's not in the "in" region
     977              :             RIJ(1) = r_insert(1) - r_target(1) - abc(1)* &
     978            0 :                      ANINT((r_insert(1) - r_target(1))/abc(1))
     979              :             RIJ(2) = r_insert(2) - r_target(2) - abc(2)* &
     980            0 :                      ANINT((r_insert(2) - r_target(2))/abc(2))
     981              :             RIJ(3) = r_insert(3) - r_target(3) - abc(3)* &
     982            0 :                      ANINT((r_insert(3) - r_target(3))/abc(3))
     983              : 
     984            0 :             dist = RIJ(1)**2 + RIJ(2)**2 + RIJ(3)**2
     985              : 
     986            0 :             IF (dist < rmin**2 .OR. dist > rmax**2) THEN
     987              :                EXIT
     988              :             END IF
     989              : 
     990              :          END DO
     991              :       END IF
     992              : 
     993            0 :    END SUBROUTINE generate_avbmc_insertion
     994              : 
     995              : ! *****************************************************************************
     996              : ! **************************************************************************************************
     997              : !> \brief determine the number of cluster present in the given configuration
     998              : !>   based on the rclus value
     999              : !> \param mc_par the mc parameters for the force env
    1000              : !> \param force_env the force environment containing the coordinates
    1001              : !> \param cluster ...
    1002              : !> \param nchains the number of molecules of each type in the box
    1003              : !> \param nunits the number of interaction sites for each molecule
    1004              : !> \param mol_type an array that indicates the type of each molecule
    1005              : !> \param total_clus ...
    1006              : !> \par
    1007              : !>    Original Multiparticle/Cluster Translation paper:
    1008              : !> Orkoulas, Gerassimos, and Athanassios Z. Panagiotopoulos. Free energy and
    1009              : !> phase equilibria for the restricted primitive model of ionic fluids from Monte
    1010              : !> Carlo simulations. J. Chem. Phys. 1994,101.2,1452-1459.
    1011              : !> \author Himanshu Goel
    1012              : ! **************************************************************************************************
    1013              : 
    1014           20 :    SUBROUTINE cluster_search(mc_par, force_env, cluster, nchains, nunits, mol_type, total_clus)
    1015              : 
    1016              :       TYPE(mc_simpar_type), POINTER                      :: mc_par
    1017              :       TYPE(force_env_type), POINTER                      :: force_env
    1018              :       INTEGER, DIMENSION(:, :), INTENT(INOUT)            :: cluster
    1019              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: nchains, nunits, mol_type
    1020              :       INTEGER, INTENT(INOUT)                             :: total_clus
    1021              : 
    1022              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cluster_search'
    1023              : 
    1024              :       INTEGER                                            :: counter, handle, imol, iunit, jmol, &
    1025              :                                                             junit, nend, nstart, nunit, nunits_i, &
    1026              :                                                             nunits_j
    1027           20 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: clusmat, decision
    1028              :       LOGICAL                                            :: lclus
    1029              :       REAL(KIND=dp)                                      :: dx, dy, dz, rclus, rclussquare, rsquare
    1030           20 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: xcoord, ycoord, zcoord
    1031           20 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: r
    1032              :       REAL(KIND=dp), DIMENSION(1:3)                      :: abc
    1033              :       TYPE(cell_type), POINTER                           :: cell
    1034              :       TYPE(cp_subsys_type), POINTER                      :: oldsys
    1035              :       TYPE(particle_list_type), POINTER                  :: particles
    1036              : 
    1037              : ! begin the timing of the subroutine
    1038              : 
    1039           20 :       CALL timeset(routineN, handle)
    1040              : 
    1041           20 :       NULLIFY (oldsys, particles)
    1042              : 
    1043              : ! Getting Particle Coordinates
    1044              : 
    1045           20 :       CALL force_env_get(force_env, cell=cell, subsys=oldsys)
    1046           20 :       CALL get_cell(cell, abc=abc)
    1047           20 :       CALL cp_subsys_get(oldsys, particles=particles)
    1048           20 :       CALL get_mc_par(mc_par, rclus=rclus)
    1049              : 
    1050          120 :       ALLOCATE (r(1:3, 1:MAXVAL(nunits), 1:SUM(nchains)))
    1051              : 
    1052              : ! Arranging particles coordinates into an easier matrix
    1053           40 :       nend = SUM(nchains(:))
    1054              :       junit = 0
    1055          120 :       DO imol = 1, nend
    1056          100 :          nunit = nunits(mol_type(imol))
    1057          320 :          DO iunit = 1, nunit
    1058          200 :             junit = junit + 1
    1059          900 :             r(1:3, iunit, imol) = particles%els(junit)%r(1:3)
    1060              :          END DO
    1061              :       END DO
    1062              : 
    1063           20 :       counter = 0
    1064              : 
    1065              : ! Allocating the size of matrix and decision matrix
    1066           80 :       ALLOCATE (clusmat(nend), decision(nend))
    1067              : 
    1068              : !Initialize
    1069          120 :       DO imol = 1, nend
    1070          100 :          decision(imol) = 0
    1071          120 :          clusmat(imol) = 0
    1072              :       END DO
    1073              : 
    1074           20 :       rclussquare = rclus*rclus
    1075              : ! Starting the cluster count loop
    1076          720 :       DO WHILE (SUM(decision) < nend)
    1077          300 :          DO nstart = 1, nend
    1078          300 :             IF (clusmat(nstart) == 0) THEN
    1079          100 :                counter = counter + 1
    1080          100 :                clusmat(nstart) = counter
    1081          100 :                EXIT
    1082              :             END IF
    1083              :          END DO
    1084              : 
    1085          100 :          lclus = .TRUE.
    1086          220 :          DO WHILE (lclus .EQV. .TRUE.)
    1087          900 :             DO imol = 1, nend
    1088          800 :                nunits_i = nunits(mol_type(imol))
    1089              : ! Allocating the xcoord,ycoord,zcoord based upon the size of molecule nunits
    1090          800 :                lclus = .FALSE.
    1091          900 :                IF (clusmat(imol) == counter .AND. decision(imol) == 0) THEN
    1092          500 :                   ALLOCATE (xcoord(nunits_i), ycoord(nunits_i), zcoord(nunits_i))
    1093          100 :                   decision(imol) = 1
    1094          100 :                   lclus = .TRUE.
    1095          300 :                   DO iunit = 1, nunits_i
    1096          200 :                      xcoord(iunit) = r(1, iunit, imol)
    1097          200 :                      ycoord(iunit) = r(2, iunit, imol)
    1098          300 :                      zcoord(iunit) = r(3, iunit, imol)
    1099              :                   END DO
    1100              :                   EXIT
    1101              :                END IF
    1102              :             END DO
    1103          200 :             IF (lclus .EQV. .TRUE.) THEN
    1104          600 :                DO jmol = 1, nend
    1105          500 :                   nunits_j = nunits(mol_type(jmol))
    1106          600 :                   IF (clusmat(jmol) == 0 .AND. decision(jmol) == 0) THEN
    1107              : !Calculating the distance between atoms
    1108          600 :                      DO iunit = 1, nunits_i
    1109         1400 :                         DO junit = 1, nunits_j
    1110          800 :                            dx = xcoord(iunit) - r(1, junit, jmol)
    1111          800 :                            dy = ycoord(iunit) - r(2, junit, jmol)
    1112          800 :                            dz = zcoord(iunit) - r(3, junit, jmol)
    1113          800 :                            dx = dx - abc(1)*ANINT(dx/abc(1))
    1114          800 :                            dy = dy - abc(2)*ANINT(dy/abc(2))
    1115          800 :                            dz = dz - abc(3)*ANINT(dz/abc(3))
    1116          800 :                            rsquare = (dx*dx) + (dy*dy) + (dz*dz)
    1117              : !Checking the distance based on rclus square(rclussq)
    1118         1200 :                            IF (rsquare < rclussquare) THEN
    1119            0 :                               clusmat(jmol) = counter
    1120              :                            END IF
    1121              :                         END DO
    1122              :                      END DO
    1123              :                   END IF
    1124              :                END DO
    1125          100 :                DEALLOCATE (xcoord, ycoord, zcoord)
    1126              :             END IF
    1127              :          END DO
    1128              :       END DO
    1129              : 
    1130              : !Putting cluster information in a cluster matrix
    1131           20 :       total_clus = counter
    1132              : 
    1133          120 :       DO imol = 1, counter
    1134          620 :          DO jmol = 1, nend
    1135          600 :             IF (imol == clusmat(jmol)) THEN
    1136          100 :                cluster(imol, jmol) = jmol
    1137              :             END IF
    1138              :          END DO
    1139              :       END DO
    1140           20 :       DEALLOCATE (r)
    1141           20 :       DEALLOCATE (decision)
    1142           20 :       DEALLOCATE (clusmat)
    1143              : 
    1144              : ! end the timing
    1145           20 :       CALL timestop(handle)
    1146              : 
    1147           60 :    END SUBROUTINE cluster_search
    1148              : 
    1149              : END MODULE mc_coordinates
    1150              : 
        

Generated by: LCOV version 2.0-1