@@ -156,6 +156,7 @@ template<class Shape> class UpdaterMuVT : public Updater
156
156
m_mc; // !< The MC Integrator this Updater is associated with
157
157
unsigned int m_npartition; // !< The number of partitions to use for Gibbs ensemble
158
158
bool m_gibbs; // !< True if we simulate a Gibbs ensemble
159
+ uint16_t m_move_type_seed; // !< Random number seed to use for move types.
159
160
160
161
GPUVector<Scalar4> m_postype_backup; // !< Backup of postype array
161
162
@@ -347,6 +348,8 @@ UpdaterMuVT<Shape>::UpdaterMuVT(std::shared_ptr<SystemDefinition> sysdef,
347
348
m_gibbs = true ;
348
349
}
349
350
351
+ m_move_type_seed = m_sysdef->getSeed ();
352
+
350
353
#ifdef ENABLE_MPI
351
354
if (m_gibbs)
352
355
{
@@ -361,6 +364,52 @@ UpdaterMuVT<Shape>::UpdaterMuVT(std::shared_ptr<SystemDefinition> sysdef,
361
364
362
365
m_exec_conf->msg ->notice (5 ) << " Constructing UpdaterMuVT: Gibbs ensemble with "
363
366
<< m_npartition << " partitions" << std::endl;
367
+
368
+ // Ensure that the user sets unique seeds on all partitions so that local trial moves
369
+ // are decorrelated.
370
+ unsigned int my_partition = this ->m_exec_conf ->getPartition ();
371
+ unsigned int my_group = this ->m_exec_conf ->getPartition () / npartition;
372
+ uint16_t my_seed = this ->m_sysdef ->getSeed ();
373
+
374
+ for (unsigned int check_partition = 0 ;
375
+ check_partition < this ->m_exec_conf ->getNPartitions ();
376
+ check_partition++)
377
+ {
378
+ unsigned int check_group = check_partition / npartition;
379
+ uint16_t check_seed = my_seed;
380
+ MPI_Bcast (&check_seed,
381
+ 1 ,
382
+ MPI_UINT16_T,
383
+ check_partition * m_exec_conf->getMPIConfig ()->getNRanks (),
384
+ m_exec_conf->getHOOMDWorldMPICommunicator ());
385
+
386
+ if (my_group == check_group && my_partition != check_partition && my_seed == check_seed)
387
+ {
388
+ std::ostringstream s;
389
+ s << " Each partition within a group must set a unique seed. " ;
390
+ s << " Partition " << check_partition << " 's " << " seed (" << check_seed << " ) " ;
391
+ s << " matches partition " << my_partition << " 's" ;
392
+ throw std::runtime_error (s.str ());
393
+ }
394
+ }
395
+
396
+ // synchronize move types across all ranks within each group
397
+ for (unsigned int group = 0 ; group < this ->m_exec_conf ->getNPartitions () / npartition;
398
+ group++)
399
+ {
400
+ uint16_t tmp = m_move_type_seed;
401
+ MPI_Bcast (&tmp,
402
+ 1 ,
403
+ MPI_UINT16_T,
404
+ group * npartition * this ->m_exec_conf ->getNRanks (),
405
+ m_exec_conf->getHOOMDWorldMPICommunicator ());
406
+
407
+ unsigned int my_group = this ->m_exec_conf ->getPartition () / npartition;
408
+ if (my_group == group)
409
+ {
410
+ m_move_type_seed = tmp;
411
+ }
412
+ }
364
413
}
365
414
else
366
415
#endif
@@ -865,9 +914,11 @@ template<class Shape> void UpdaterMuVT<Shape>::update(uint64_t timestep)
865
914
866
915
// initialize random number generator
867
916
unsigned int group = (m_exec_conf->getPartition () / m_npartition);
917
+ unsigned int partition = (m_exec_conf->getPartition () % m_npartition);
868
918
869
- hoomd::RandomGenerator rng (
870
- hoomd::Seed (hoomd::RNGIdentifier::UpdaterMuVT, timestep, this ->m_sysdef ->getSeed ()),
919
+ // Make a RNG that is seeded the same across the whole group
920
+ hoomd::RandomGenerator rng_group (
921
+ hoomd::Seed (hoomd::RNGIdentifier::UpdaterMuVTGroup, timestep, m_move_type_seed),
871
922
hoomd::Counter (group));
872
923
873
924
bool active = true ;
@@ -884,31 +935,30 @@ template<class Shape> void UpdaterMuVT<Shape>::update(uint64_t timestep)
884
935
// the other MPI partition
885
936
if (m_gibbs)
886
937
{
887
- unsigned int p = m_exec_conf->getPartition () % m_npartition;
888
-
889
938
// choose a random pair of communicating boxes
890
- src = hoomd::UniformIntDistribution (m_npartition - 1 )(rng );
891
- dest = hoomd::UniformIntDistribution (m_npartition - 2 )(rng );
939
+ src = hoomd::UniformIntDistribution (m_npartition - 1 )(rng_group );
940
+ dest = hoomd::UniformIntDistribution (m_npartition - 2 )(rng_group );
892
941
if (src <= dest)
893
942
dest++;
894
943
895
- if (p == src)
944
+ if (partition == src)
896
945
{
897
946
m_gibbs_other = (dest + group * m_npartition) * m_exec_conf->getNRanks ();
898
947
mod = 0 ;
899
948
}
900
- if (p == dest)
949
+ if (partition == dest)
901
950
{
902
951
m_gibbs_other = (src + group * m_npartition) * m_exec_conf->getNRanks ();
903
952
mod = 1 ;
904
953
}
905
- if (p != src && p != dest)
954
+ if (partition != src && partition != dest)
906
955
{
907
956
active = false ;
908
957
}
909
958
910
959
// order the expanded ensembles
911
- volume_move = hoomd::detail::generate_canonical<Scalar>(rng) < m_volume_move_probability;
960
+ Scalar r = hoomd::detail::generate_canonical<Scalar>(rng_group);
961
+ volume_move = r < m_volume_move_probability;
912
962
913
963
if (active && m_exec_conf->getRank () == 0 )
914
964
{
@@ -973,7 +1023,14 @@ template<class Shape> void UpdaterMuVT<Shape>::update(uint64_t timestep)
973
1023
#endif
974
1024
975
1025
// whether we insert or remove a particle
976
- bool insert = m_gibbs ? mod : hoomd::UniformIntDistribution (1 )(rng);
1026
+ bool insert = m_gibbs ? mod : hoomd::UniformIntDistribution (1 )(rng_group);
1027
+
1028
+ // Use a partition specific RNG stream on each partition in Gibbs ensembles.
1029
+ hoomd::RandomGenerator rng_insert_remove (
1030
+ hoomd::Seed (hoomd::RNGIdentifier::UpdaterMuVTInsertRemove,
1031
+ timestep,
1032
+ this ->m_sysdef ->getSeed ()),
1033
+ hoomd::Counter (group, partition));
977
1034
978
1035
if (insert)
979
1036
{
@@ -992,7 +1049,7 @@ template<class Shape> void UpdaterMuVT<Shape>::update(uint64_t timestep)
992
1049
{
993
1050
// choose a random particle type out of those being inserted or removed
994
1051
type = m_transfer_types[hoomd::UniformIntDistribution (
995
- (unsigned int )(m_transfer_types.size () - 1 ))(rng )];
1052
+ (unsigned int )(m_transfer_types.size () - 1 ))(rng_insert_remove )];
996
1053
}
997
1054
else
998
1055
{
@@ -1045,23 +1102,23 @@ template<class Shape> void UpdaterMuVT<Shape>::update(uint64_t timestep)
1045
1102
1046
1103
// Propose a random position uniformly in the box
1047
1104
Scalar3 f;
1048
- f.x = hoomd::detail::generate_canonical<Scalar>(rng );
1049
- f.y = hoomd::detail::generate_canonical<Scalar>(rng );
1105
+ f.x = hoomd::detail::generate_canonical<Scalar>(rng_insert_remove );
1106
+ f.y = hoomd::detail::generate_canonical<Scalar>(rng_insert_remove );
1050
1107
if (m_sysdef->getNDimensions () == 2 )
1051
1108
{
1052
1109
f.z = Scalar (0.5 );
1053
1110
}
1054
1111
else
1055
1112
{
1056
- f.z = hoomd::detail::generate_canonical<Scalar>(rng );
1113
+ f.z = hoomd::detail::generate_canonical<Scalar>(rng_insert_remove );
1057
1114
}
1058
1115
vec3<Scalar> pos_test = vec3<Scalar>(m_pdata->getGlobalBox ().makeCoordinates (f));
1059
1116
1060
1117
Shape shape_test (quat<Scalar>(), param);
1061
1118
if (shape_test.hasOrientation ())
1062
1119
{
1063
1120
// set particle orientation
1064
- shape_test.orientation = generateRandomOrientation (rng , ndim);
1121
+ shape_test.orientation = generateRandomOrientation (rng_insert_remove , ndim);
1065
1122
}
1066
1123
1067
1124
if (m_gibbs)
@@ -1140,7 +1197,8 @@ template<class Shape> void UpdaterMuVT<Shape>::update(uint64_t timestep)
1140
1197
bool accept = false ;
1141
1198
if (nonzero)
1142
1199
{
1143
- accept = (hoomd::detail::generate_canonical<double >(rng) < exp (lnboltzmann));
1200
+ accept = (hoomd::detail::generate_canonical<double >(rng_insert_remove)
1201
+ < exp (lnboltzmann));
1144
1202
}
1145
1203
1146
1204
#ifdef ENABLE_MPI
@@ -1190,24 +1248,19 @@ template<class Shape> void UpdaterMuVT<Shape>::update(uint64_t timestep)
1190
1248
// try removing a particle
1191
1249
unsigned int tag = UINT_MAX;
1192
1250
1193
- // in Gibbs ensemble, we should not use correlated random numbers with box 1
1194
- hoomd::RandomGenerator rng_local (hoomd::Seed (hoomd::RNGIdentifier::UpdaterMuVTBox1,
1195
- timestep,
1196
- this ->m_sysdef ->getSeed ()),
1197
- hoomd::Counter (group));
1198
-
1199
1251
// choose a random particle type out of those being transferred
1200
1252
assert (m_transfer_types.size () > 0 );
1201
1253
unsigned int type = m_transfer_types[hoomd::UniformIntDistribution (
1202
- (unsigned int )(m_transfer_types.size () - 1 ))(rng_local )];
1254
+ (unsigned int )(m_transfer_types.size () - 1 ))(rng_insert_remove )];
1203
1255
1204
1256
// choose a random particle of that type
1205
1257
unsigned int nptl_type = getNumParticlesType (type);
1206
1258
1207
1259
if (nptl_type)
1208
1260
{
1209
1261
// get random tag of given type
1210
- unsigned int type_offset = hoomd::UniformIntDistribution (nptl_type - 1 )(rng_local);
1262
+ unsigned int type_offset
1263
+ = hoomd::UniformIntDistribution (nptl_type - 1 )(rng_insert_remove);
1211
1264
tag = getNthTypeTag (type, type_offset);
1212
1265
}
1213
1266
@@ -1319,8 +1372,8 @@ template<class Shape> void UpdaterMuVT<Shape>::update(uint64_t timestep)
1319
1372
// apply acceptance criterion
1320
1373
if (nonzero)
1321
1374
{
1322
- accept
1323
- = (hoomd::detail::generate_canonical< double >(rng_local) < exp (lnboltzmann));
1375
+ accept = (hoomd::detail::generate_canonical< double >(rng_insert_remove)
1376
+ < exp (lnboltzmann));
1324
1377
}
1325
1378
else
1326
1379
{
@@ -1410,18 +1463,20 @@ template<class Shape> void UpdaterMuVT<Shape>::update(uint64_t timestep)
1410
1463
1411
1464
if (mod == 0 )
1412
1465
{
1413
- Scalar ln_V_new = log (V / V_other)
1414
- + (hoomd::detail::generate_canonical<Scalar>(rng) - Scalar (0.5 ))
1415
- * m_max_vol_rescale;
1466
+ Scalar ln_V_new
1467
+ = log (V / V_other)
1468
+ + (hoomd::detail::generate_canonical<Scalar>(rng_group) - Scalar (0.5 ))
1469
+ * m_max_vol_rescale;
1416
1470
V_new = (V + V_other) * exp (ln_V_new) / (Scalar (1.0 ) + exp (ln_V_new));
1417
1471
V_new_other
1418
1472
= (V + V_other) * (Scalar (1.0 ) - exp (ln_V_new) / (Scalar (1.0 ) + exp (ln_V_new)));
1419
1473
}
1420
1474
else
1421
1475
{
1422
- Scalar ln_V_new = log (V_other / V)
1423
- + (hoomd::detail::generate_canonical<Scalar>(rng) - Scalar (0.5 ))
1424
- * m_max_vol_rescale;
1476
+ Scalar ln_V_new
1477
+ = log (V_other / V)
1478
+ + (hoomd::detail::generate_canonical<Scalar>(rng_group) - Scalar (0.5 ))
1479
+ * m_max_vol_rescale;
1425
1480
V_new
1426
1481
= (V + V_other) * (Scalar (1.0 ) - exp (ln_V_new) / (Scalar (1.0 ) + exp (ln_V_new)));
1427
1482
}
@@ -1538,7 +1593,7 @@ template<class Shape> void UpdaterMuVT<Shape>::update(uint64_t timestep)
1538
1593
+ log (V_new_other / V_other) * (Scalar)(other_ndof + 1 ) + lnb
1539
1594
+ other_lnb;
1540
1595
1541
- accept = hoomd::detail::generate_canonical<double >(rng ) < exp (arg);
1596
+ accept = hoomd::detail::generate_canonical<double >(rng_group ) < exp (arg);
1542
1597
accept &= !(has_overlaps || other_result);
1543
1598
1544
1599
// communicate if accepted
0 commit comments