:issue:`2381`
+Fixed FEP calculations with SHAKE
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+All SHAKE + FEP calculations accumulated wrong values to dH/dl output,
+but in some cases the result will look the same.
+
+:issue:`2434`
+
Fixed handling of mdp ``define`` statement assigning preprocessor values
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Now .mdp files can configure the topology with values, as originally
Patch provdied by Veselin Kolev to quiet some compiler warnings.
:issue:`2400`
+
+Work around gcc-6 bug in tabulated group non-bonded kernels
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+With the gcc-6 compiler, AVX and -O3, which is the default,
+the tabulated non-bonded kernels of the (deprecated) group
+cutoff-scheme produced incorrect energies and forces.
+The errors are so large that they could not have caused latent issues.
+
+:issue:`2424`
+
+Detect correct AMD Zen SMT topology
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+On recent AMD Zen processors, hardware thread detection and pinning
+handling have been fixed, improving performance.
+
+:issue:`2388`
+
+Fix sharing of the AWH bias over multiple simulations
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Sharing the AWH bias over multiple simulations only worked when
+each simulation was running on a single MPI rank. When a simulation
+itself used multiple MPI ranks, the run would stop with an MPI error.
+
+:issue:`2433`
+
+Miscellaneous
+^^^^^^^^^^^^^
+
+Made multi-atom TPI reproducible with different compilers
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
gmx::ArrayRef<const double> biasForce =
biasCts.bias.calcForceAndUpdateBias(coordValue,
&biasPotential, &biasPotentialJump,
+ commRecord_,
multiSimRecord_,
t, step, seed_, fplog);
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2015,2016,2017, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
Bias::calcForceAndUpdateBias(const awh_dvec coordValue,
double *awhPotential,
double *potentialJump,
+ const t_commrec *commRecord,
const gmx_multisim_t *ms,
double t,
gmx_int64_t step,
{
state_.updateFreeEnergyAndAddSamplesToHistogram(dimParams_, grid_,
params_,
- ms, t, step, fplog,
+ commRecord, ms,
+ t, step, fplog,
&updateList_);
if (params_.convolveForce)
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2015,2016,2017, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
* \param[in] coordValue The current coordinate value(s).
* \param[out] awhPotential Bias potential.
* \param[out] potentialJump Change in bias potential for this bias.
+ * \param[in] commRecord Struct for intra-simulation communication.
* \param[in] ms Struct for multi-simulation communication.
* \param[in] t Time.
* \param[in] step Time step.
calcForceAndUpdateBias(const awh_dvec coordValue,
double *awhPotential,
double *potentialJump,
+ const t_commrec *commRecord,
const gmx_multisim_t *ms,
double t,
gmx_int64_t step,
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2015,2016,2017, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
namespace
{
+/*! \brief
+ * Sum an array over all simulations on the master rank of each simulation.
+ *
+ * \param[in,out] arrayRef The data to sum.
+ * \param[in] multiSimComm Struct for multi-simulation communication.
+ */
+void sumOverSimulations(gmx::ArrayRef<int> arrayRef,
+ const gmx_multisim_t *multiSimComm)
+{
+ gmx_sumi_sim(arrayRef.size(), arrayRef.data(), multiSimComm);
+}
+
+/*! \brief
+ * Sum an array over all simulations on the master rank of each simulation.
+ *
+ * \param[in,out] arrayRef The data to sum.
+ * \param[in] multiSimComm Struct for multi-simulation communication.
+ */
+void sumOverSimulations(gmx::ArrayRef<double> arrayRef,
+ const gmx_multisim_t *multiSimComm)
+{
+ gmx_sumd_sim(arrayRef.size(), arrayRef.data(), multiSimComm);
+}
+
+/*! \brief
+ * Sum an array over all simulations on all ranks of each simulation.
+ *
+ * This assumes the data is identical on all ranks within each simulation.
+ *
+ * \param[in,out] arrayRef The data to sum.
+ * \param[in] commRecord Struct for intra-simulation communication.
+ * \param[in] multiSimComm Struct for multi-simulation communication.
+ */
+template<typename T>
+void sumOverSimulations(gmx::ArrayRef<T> arrayRef,
+ const t_commrec *commRecord,
+ const gmx_multisim_t *multiSimComm)
+{
+ if (MASTER(commRecord))
+ {
+ sumOverSimulations(arrayRef, multiSimComm);
+ }
+ if (commRecord->nnodes > 1)
+ {
+ gmx_bcast(arrayRef.size()*sizeof(T), arrayRef.data(), commRecord);
+ }
+}
+
/*! \brief
* Sum PMF over multiple simulations, when requested.
*
* \param[in,out] pointState The state of the points in the bias.
* \param[in] numSharedUpdate The number of biases sharing the histogram.
+ * \param[in] commRecord Struct for intra-simulation communication.
* \param[in] multiSimComm Struct for multi-simulation communication.
*/
void sumPmf(gmx::ArrayRef<PointState> pointState,
int numSharedUpdate,
+ const t_commrec *commRecord,
const gmx_multisim_t *multiSimComm)
{
if (numSharedUpdate == 1)
buffer[i] = pointState[i].inTargetRegion() ? std::exp(static_cast<float>(pointState[i].logPmfSum())) : 0;
}
- gmx_sumd_sim(buffer.size(), buffer.data(), multiSimComm);
+ sumOverSimulations(gmx::ArrayRef<double>(buffer), commRecord, multiSimComm);
/* Take log again to get (non-normalized) PMF */
double normFac = 1.0/numSharedUpdate;
FILE *fplog,
int maxNumWarnings) const
{
+ GMX_ASSERT(fplog != nullptr, "Warnings can only be issued if there is log file.");
const double maxHistogramRatio = 0.5; /* Tolerance for printing a warning about the histogram ratios */
/* Sum up the histograms and get their normalization */
*
* \param[in,out] updateList Update list for this simulation (assumed >= npoints long).
* \param[in] numPoints Total number of points.
+ * \param[in] commRecord Struct for intra-simulation communication.
* \param[in] multiSimComm Struct for multi-simulation communication.
*/
void mergeSharedUpdateLists(std::vector<int> *updateList,
int numPoints,
+ const t_commrec *commRecord,
const gmx_multisim_t *multiSimComm)
{
std::vector<int> numUpdatesOfPoint;
}
/* Sum over the sims to get all the flagged points */
- gmx_sumi_sim(numPoints, numUpdatesOfPoint.data(), multiSimComm);
+ sumOverSimulations(arrayRefFromArray(numUpdatesOfPoint.data(), numPoints), commRecord, multiSimComm);
/* Collect the indices of the flagged points in place. The resulting array will be the merged update list.*/
updateList->clear();
* \param[in,out] pointState The state of the points in the bias.
* \param[in,out] weightSumCovering The weights for checking covering.
* \param[in] numSharedUpdate The number of biases sharing the histrogram.
+ * \param[in] commRecord Struct for intra-simulation communication.
* \param[in] multiSimComm Struct for multi-simulation communication.
* \param[in] localUpdateList List of points with data.
*/
void sumHistograms(gmx::ArrayRef<PointState> pointState,
gmx::ArrayRef<double> weightSumCovering,
int numSharedUpdate,
+ const t_commrec *commRecord,
const gmx_multisim_t *multiSimComm,
const std::vector<int> &localUpdateList)
{
coordVisits[localIndex] = ps.numVisitsIteration();
}
- gmx_sumd_sim(weightSum.size(), weightSum.data(), multiSimComm);
- gmx_sumd_sim(coordVisits.size(), coordVisits.data(), multiSimComm);
+ sumOverSimulations(gmx::ArrayRef<double>(weightSum), commRecord, multiSimComm);
+ sumOverSimulations(gmx::ArrayRef<double>(coordVisits), commRecord, multiSimComm);
/* Transfer back the result */
for (size_t localIndex = 0; localIndex < localUpdateList.size(); localIndex++)
bool BiasState::isSamplingRegionCovered(const BiasParams ¶ms,
const std::vector<DimParams> &dimParams,
const Grid &grid,
+ const t_commrec *commRecord,
const gmx_multisim_t *multiSimComm) const
{
/* Allocate and initialize arrays: one for checking visits along each dimension,
/* For multiple dimensions this may not be the best way to do it. */
for (int d = 0; d < grid.numDimensions(); d++)
{
- gmx_sumi_sim(grid.axis(d).numPoints(), checkDim[d].covered.data(), multiSimComm);
+ sumOverSimulations(gmx::arrayRefFromArray(checkDim[d].covered.data(), grid.axis(d).numPoints()), commRecord, multiSimComm);
}
}
void BiasState::updateFreeEnergyAndAddSamplesToHistogram(const std::vector<DimParams> &dimParams,
const Grid &grid,
const BiasParams ¶ms,
+ const t_commrec *commRecord,
const gmx_multisim_t *multiSimComm,
double t,
gmx_int64_t step,
updateList);
if (params.numSharedUpdate > 1)
{
- mergeSharedUpdateLists(updateList, points_.size(), multiSimComm);
+ mergeSharedUpdateLists(updateList, points_.size(), commRecord, multiSimComm);
}
/* Reset the range for the next update */
/* Add samples to histograms for all local points and sync simulations if needed */
sumHistograms(points_, weightSumCovering_,
- params.numSharedUpdate, multiSimComm, *updateList);
+ params.numSharedUpdate, commRecord, multiSimComm, *updateList);
- sumPmf(points_, params.numSharedUpdate, multiSimComm);
+ sumPmf(points_, params.numSharedUpdate, commRecord, multiSimComm);
/* Renormalize the free energy if values are too large. */
bool needToNormalizeFreeEnergy = false;
if (inInitialStage())
{
detectedCovering = (params.isCheckStep(points_.size(), step) &&
- isSamplingRegionCovered(params, dimParams, grid, multiSimComm));
+ isSamplingRegionCovered(params, dimParams, grid,
+ commRecord, multiSimComm));
}
/* The weighthistogram size after this update. */
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2015,2016,2017, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
* \param[in] params The bias parameters.
* \param[in] dimParams Bias dimension parameters.
* \param[in] grid The grid.
+ * \param[in] commRecord Struct for intra-simulation communication.
* \param[in] multiSimComm Struct for multi-simulation communication.
* \returns true if covered.
*/
bool isSamplingRegionCovered(const BiasParams ¶ms,
const std::vector<DimParams> &dimParams,
const Grid &grid,
+ const t_commrec *commRecord,
const gmx_multisim_t *multiSimComm) const;
/*! \brief
* \param[in] dimParams The dimension parameters.
* \param[in] grid The grid.
* \param[in] params The bias parameters.
+ * \param[in] commRecord Struct for intra-simulation communication.
* \param[in] ms Struct for multi-simulation communication.
* \param[in] t Time.
* \param[in] step Time step.
void updateFreeEnergyAndAddSamplesToHistogram(const std::vector<DimParams> &dimParams,
const Grid &grid,
const BiasParams ¶ms,
+ const t_commrec *commRecord,
const gmx_multisim_t *ms,
double t,
gmx_int64_t step,
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2015,2016,2017, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
/* The histogram is equilibrated at most once. */
equilibrateHistogram_ = !histogramIsEquilibrated(pointStates);
- std::string prefix = gmx::formatString("\nawh%d:", params.biasIndex + 1);
- if (!equilibrateHistogram_)
+ if (fplog != nullptr)
{
- fprintf(fplog, "%s equilibrated histogram at t = %g ps.\n", prefix.c_str(), t);
- }
- else if (!havePrintedAboutCovering_)
- {
- fprintf(fplog, "%s covered but histogram not equilibrated at t = %g ps.\n", prefix.c_str(), t);
- havePrintedAboutCovering_ = true; /* Just print once. */
+ std::string prefix = gmx::formatString("\nawh%d:", params.biasIndex + 1);
+ if (!equilibrateHistogram_)
+ {
+ fprintf(fplog, "%s equilibrated histogram at t = %g ps.\n", prefix.c_str(), t);
+ }
+ else if (!havePrintedAboutCovering_)
+ {
+ fprintf(fplog, "%s covered but histogram not equilibrated at t = %g ps.\n", prefix.c_str(), t);
+ havePrintedAboutCovering_ = true; /* Just print once. */
+ }
}
}
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2017, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
gmx::ArrayRef<const double> biasForce =
bias.calcForceAndUpdateBias(coordValue,
&potential, &potentialJump,
- nullptr, step, step, seed_, nullptr);
+ nullptr, nullptr, step, step, seed_,
+ nullptr);
force.push_back(biasForce[0]);
pot.push_back(potential);
double potentialJump = 0;
bias.calcForceAndUpdateBias(coordValue,
&potential, &potentialJump,
- nullptr, step, step, params.awhParams.seed, nullptr);
+ nullptr, nullptr,
+ step, step, params.awhParams.seed, nullptr);
inInitialStage = bias.state().inInitialStage();
if (!inInitialStage)
}
}
+/*! \brief The layout of the bits in the APIC ID */
+struct ApicIdLayout
+{
+ unsigned int hwThreadBits; //!< The number of least significant bits for hw-threads
+ unsigned int coreBits; //!< The number of core bits following the hw-thread bits
+};
+
+/*! \brief Detect the APIC ID layout for x2APIC
+ */
+ApicIdLayout
+detectX2ApicIdLayout()
+{
+ ApicIdLayout layout;
+
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+ executeX86CpuID(0xb, 0, &eax, &ebx, &ecx, &edx);
+ layout.hwThreadBits = eax & 0x1f;
+ executeX86CpuID(0xb, 1, &eax, &ebx, &ecx, &edx);
+ layout.coreBits = (eax & 0x1f) - layout.hwThreadBits;
+
+ return layout;
+}
+
+/*! \brief Detect the APIC ID layout for standard APIC or xAPIC on AMD
+ *
+ * \param[in] maxExtLevel The largest CPUID extended function input value supported by the processor implementation
+ */
+ApicIdLayout
+detectAmdApicIdLayout(unsigned int maxExtLevel)
+{
+ ApicIdLayout layout;
+
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+ executeX86CpuID(0x1, 0, &eax, &ebx, &ecx, &edx);
+ int family = ((eax & 0x0ff00000) >> 20) + ((eax & 0x00000f00) >> 8);
+ executeX86CpuID(0x80000001, 0, &eax, &ebx, &ecx, &edx);
+ bool haveExtendedTopology = (ecx & (1 << 22));
+
+ // NOTE: Here we assume 1 thread per core, unless we have family >= 17h
+ layout.hwThreadBits = 0;
+ if (family >= 0x17 &&
+ haveExtendedTopology &&
+ maxExtLevel >= 0x8000001e)
+ {
+ executeX86CpuID(0x8000001e, 1, &eax, &ebx, &ecx, &edx);
+ int numThreadsPerCore = ((ebx >> 8) & 0xff) + 1;
+ // NOTE: The AMD documentation only specifies the layout of apicid
+ // when we have 1 or 2 threads per core.
+ while (numThreadsPerCore > (1 << layout.hwThreadBits))
+ {
+ layout.hwThreadBits++;
+ }
+ }
+
+ // Get number of core bits in apic ID - try modern extended method first
+ executeX86CpuID(0x80000008, 0, &eax, &ebx, &ecx, &edx);
+ layout.coreBits = (ecx >> 12) & 0xf;
+ if (layout.coreBits == 0)
+ {
+ // Legacy method for old single/dual core AMD CPUs
+ int i = ecx & 0xf;
+ while (i >> layout.coreBits)
+ {
+ layout.coreBits++;
+ }
+ }
+
+ return layout;
+}
/*! \brief Try to detect basic CPU topology information using x86 cpuid
*
if (haveX2Apic || haveApic)
{
- unsigned int hwThreadBits;
- unsigned int coreBits;
+ ApicIdLayout layout;
// Get bits for cores and hardware threads
if (haveX2Apic)
{
- executeX86CpuID(0xb, 0, &eax, &ebx, &ecx, &edx);
- hwThreadBits = eax & 0x1f;
- executeX86CpuID(0xb, 1, &eax, &ebx, &ecx, &edx);
- coreBits = (eax & 0x1f) - hwThreadBits;
+ layout = detectX2ApicIdLayout();
}
else // haveApic
{
- // AMD without x2APIC does not support SMT - there are no hwthread bits in apic ID
- hwThreadBits = 0;
- // Get number of core bits in apic ID - try modern extended method first
- executeX86CpuID(0x80000008, 0, &eax, &ebx, &ecx, &edx);
- coreBits = (ecx >> 12) & 0xf;
- if (coreBits == 0)
+ if (detectX86Vendor() == CpuInfo::Vendor::Amd)
{
- // Legacy method for old single/dual core AMD CPUs
- int i = ecx & 0xf;
- while (i >> coreBits)
+ layout = detectAmdApicIdLayout(maxExtLevel);
+
+ if (layout.hwThreadBits > 1)
{
- coreBits++;
+ // At the time of writing this code we do not know what
+ // to do with more than 2 threads, so return empty.
+ return logicalProcessors;
}
}
+ else
+ {
+ // We do not know the APIC ID layout, return empty.
+ return logicalProcessors;
+ }
}
std::vector<unsigned int> apicID = detectX86ApicIDs(haveX2Apic);
// APIC IDs can be buggy, and it is always a mess. Typically more bits are
// reserved than needed, and the numbers might not increment by 1 even in
// a single socket or core. Extract, renumber, and check that things make sense.
- unsigned int hwThreadMask = (1 << hwThreadBits) - 1;
- unsigned int coreMask = (1 << coreBits) - 1;
+ unsigned int hwThreadMask = (1 << layout.hwThreadBits) - 1;
+ unsigned int coreMask = (1 << layout.coreBits) - 1;
std::vector<unsigned int> hwThreadRanks;
std::vector<unsigned int> coreRanks;
std::vector<unsigned int> socketRanks;
for (auto a : apicID)
{
hwThreadRanks.push_back( static_cast<int>( a & hwThreadMask ) );
- coreRanks.push_back( static_cast<int>( ( a >> hwThreadBits ) & coreMask ) );
- socketRanks.push_back( static_cast<int>( a >> ( coreBits + hwThreadBits ) ) );
+ coreRanks.push_back( static_cast<int>( ( a >> layout.hwThreadBits ) & coreMask ) );
+ socketRanks.push_back( static_cast<int>( a >> ( layout.coreBits + layout.hwThreadBits ) ) );
}
renumberIndex(&hwThreadRanks);
X86_Fma, //!< Fused-multiply add support (mainly for AVX)
X86_Fma4, //!< 4-operand FMA, only on AMD for now
X86_Hle, //!< Hardware lock elision
- X86_Htt, //!< Hyper-Threading supported (but maybe not enabled)
+ X86_Htt, //!< Hyper-Threading enabled (NOTE: might not match the CPUID HTT support flag)
X86_Intel, //!< This is an Intel x86 processor
X86_Lahf, //!< LAHF/SAHF support in 64 bits
X86_MisalignSse, //!< Support for misaligned SSE data instructions
nbl->table_vdw->stride = nbl->table_vdw->formatsize * nbl->table_vdw->ninteractions;
snew_aligned(nbl->table_vdw->data, nbl->table_vdw->stride*(nbl->table_vdw->n+1), 32);
+ /* NOTE: Using a single i-loop here leads to mix-up of data in table_vdw
+ * with (at least) gcc 6.2, 6.3 and 6.4 when compiled with -O3 and AVX
+ */
for (i = 0; i <= nbl->table_elec_vdw->n; i++)
{
for (j = 0; j < 4; j++)
{
nbl->table_elec->data[4*i+j] = nbl->table_elec_vdw->data[12*i+j];
}
+ }
+ for (i = 0; i <= nbl->table_elec_vdw->n; i++)
+ {
for (j = 0; j < 8; j++)
{
nbl->table_vdw->data[8*i+j] = nbl->table_elec_vdw->data[12*i+4+j];
gmx_bool bshakef(FILE *log, gmx_shakedata_t shaked,
real invmass[], int nblocks, int sblock[],
t_idef *idef, t_inputrec *ir, rvec x_s[], rvec prime[],
- t_nrnb *nrnb, real *scaled_lagrange_multiplier, real lambda, real *dvdlambda,
+ t_nrnb *nrnb, real * const scaled_lagrange_multiplier, real lambda, real *dvdlambda,
real invdt, rvec *v, gmx_bool bCalcVir, tensor vir_r_m_dr,
gmx_bool bDumpOnError, int econq)
{
t_iatom *iatoms;
- real dt_2, dvdl;
+ real *lam, dt_2, dvdl;
int i, n0, ncon, blen, type, ll;
int tnit = 0, trij = 0;
scaled_lagrange_multiplier[ll] = 0;
}
+ // TODO Rewrite this block so that it is obvious that i, iatoms
+ // and lam are all iteration variables. Is this easier if the
+ // sblock data structure is organized differently?
iatoms = &(idef->il[F_CONSTR].iatoms[sblock[0]]);
+ lam = scaled_lagrange_multiplier;
for (i = 0; (i < nblocks); )
{
blen = (sblock[i+1]-sblock[i]);
tnit += n0*blen;
trij += blen;
iatoms += 3*blen; /* Increment pointer! */
- scaled_lagrange_multiplier += blen;
+ lam += blen;
i++;
}
/* only for position part? */
rvec x_s[], /* Coords before update */
rvec prime[], /* Output coords */
t_nrnb *nrnb, /* Performance measure */
- real *lagr, /* The Lagrange multipliers */
+ real * const lagr, /* The Lagrange multipliers */
real lambda, /* FEP lambda */
real *dvdlambda, /* FEP force */
real invdt, /* 1/delta_t */
copy_rvec(x_mol[i-a_tp0], state_global->x[i]);
}
/* Rotate the molecule randomly */
+ real angleX = 2*M_PI*dist(rng);
+ real angleY = 2*M_PI*dist(rng);
+ real angleZ = 2*M_PI*dist(rng);
rotate_conf(a_tp1-a_tp0, as_rvec_array(state_global->x.data())+a_tp0, nullptr,
- 2*M_PI*dist(rng),
- 2*M_PI*dist(rng),
- 2*M_PI*dist(rng));
+ angleX, angleY, angleZ);
/* Shift to the insertion location */
for (i = a_tp0; i < a_tp1; i++)
{
static const char * const Contributors[] = {
"Emile Apol",
"Rossen Apostolov",
+ "Paul Bauer",
"Herman J.C. Berendsen",
"Par Bjelkmar",
"Aldert van Buuren",
"Rudi van Drunen",
"Anton Feenstra",
"Gerrit Groenhof",
+ "Aleksei Iupinov",
"Christoph Junghans",
"Anca Hamuraru",
"Vincent Hindriksen",
}
if (isMultiSim(ms))
{
- if (MASTER(cr))
+ if (SIMMASTER(cr))
{
MPI_Barrier(ms->mpi_comm_masters);
}