\subsubsection{BlueGene/P}
Mark to write later. There is currently no native acceleration on this
-platform, but the default plain C kernels will work.
+platform, but the default plain C kernels will work. There will be
+accelerated Verlet kernels in 4.6 release.
\subsubsection{BlueGene/Q}
-Mark to write later. There is currently no native acceleration on this
-platform, but the default plain C kernels will work.
+There is currently no native acceleration on this platform, but the
+default plain C kernels will work.
+
+Only static linking with XL compilers is supported by \gromacs{}. Dynamic
+linking would be supported by the architecture and \gromacs{}, but has no
+advantages other than disk space, and is generally discouraged on
+BlueGene for performance reasons.
+
+Computation on BlueGene floating-point units is always done in
+double-precision. However, single-precision builds of \gromacs{} are
+still normal and encouraged. The BlueGene hardware automatically
+converts values stored in single precision in memory to double
+precision in registers for computation, converts the results back to
+single precision correctly, and does so for no additional cost. As
+with other platforms, doing the whole computation in double precision
+normally shows no improvement in accuracy and costs twice as much time
+moving memory around.
+
+You need to arrange for FFTW to be installed correctly, following the
+above instructions.
+
+mpicc is used for compiling and linking. This can make it awkward to
+attempt to use IBM's optimized BLAS/LAPACK called ESSL. Since mdrun is
+the only part of \gromacs{} that should normally run on the compute
+nodes, and there is nearly no need for linear algebra support for
+mdrun, it is recommended to use the \gromacs{} built-in linear algebra
+routines.
+
+cmake .. -DCMAKE_TOOLCHAIN_FILE=BlueGeneQ-static-XL-C -DCMAKE_PREFIX_PATH=/your/fftw/installation/prefix
+make mdrun
+make install-mdrun
+
+It is possible to configure and make the remaining \gromacs{} tools
+with the compute node toolchain, but as none of those tools are
+\mpi{}-aware, this would not normally be useful. Instead, these should
+be planned to run on the login node, and a seperate \gromacs{}
+installation performed for that using the login node's toolchain.
\section{Tested platforms}
#include "orires.h"
#include "gmx_wallcycle.h"
#include "gmx_omp_nthreads.h"
+#include "gmx_omp.h"
/*For debugging, start at v(-dt/2) for velolcity verlet -- uncomment next line */
/*#define STARTFROMDT2*/
} gmx_sd_sigma_t;
typedef struct {
- /* The random state */
- gmx_rng_t gaussrand;
+ /* The random state for ngaussrand threads.
+ * Normal thermostats need just 1 random number generator,
+ * but SD and BD with OpenMP parallelization need 1 for each thread.
+ */
+ int ngaussrand;
+ gmx_rng_t *gaussrand;
/* BD stuff */
real *bd_rf;
/* SD stuff */
}
}
-static gmx_stochd_t *init_stochd(FILE *fplog,t_inputrec *ir)
+/* Allocates and initializes sd->gaussrand[i] for i=1, i<sd->ngaussrand,
+ * Using seeds generated from sd->gaussrand[0].
+ */
+static void init_multiple_gaussrand(gmx_stochd_t *sd)
+{
+ int ngr,i;
+ unsigned int *seed;
+
+ ngr = sd->ngaussrand;
+ snew(seed,ngr);
+
+ for(i=1; i<ngr; i++)
+ {
+ seed[i] = gmx_rng_uniform_uint32(sd->gaussrand[0]);
+ }
+
+#pragma omp parallel num_threads(ngr)
+ {
+ int th;
+
+ th = gmx_omp_get_thread_num();
+ if (th > 0)
+ {
+ /* Initialize on each thread to have thread-local memory alloced */
+ sd->gaussrand[th] = gmx_rng_init(seed[th]);
+ }
+ }
+
+ sfree(seed);
+}
+
+static gmx_stochd_t *init_stochd(FILE *fplog,t_inputrec *ir,int nthreads)
{
gmx_stochd_t *sd;
gmx_sd_const_t *sdc;
- int ngtc,n;
+ int ngtc,n,th;
real y;
snew(sd,1);
/* Initiate random number generator for langevin type dynamics,
* for BD, SD or velocity rescaling temperature coupling.
*/
- sd->gaussrand = gmx_rng_init(ir->ld_seed);
+ if (ir->eI == eiBD || EI_SD(ir->eI))
+ {
+ sd->ngaussrand = nthreads;
+ }
+ else
+ {
+ sd->ngaussrand = 1;
+ }
+ snew(sd->gaussrand,sd->ngaussrand);
+
+ /* Initialize the first random generator */
+ sd->gaussrand[0] = gmx_rng_init(ir->ld_seed);
+
+ if (sd->ngaussrand > 1)
+ {
+ /* Initialize the rest of the random number generators,
+ * using the first one to generate seeds.
+ */
+ init_multiple_gaussrand(sd);
+ }
ngtc = ir->opts.ngtc;
void get_stochd_state(gmx_update_t upd,t_state *state)
{
- gmx_rng_get_state(upd->sd->gaussrand,state->ld_rng,state->ld_rngi);
+ /* Note that we only get the state of the first random generator,
+ * even if there are multiple. This avoids repetition.
+ */
+ gmx_rng_get_state(upd->sd->gaussrand[0],state->ld_rng,state->ld_rngi);
}
void set_stochd_state(gmx_update_t upd,t_state *state)
{
- gmx_rng_set_state(upd->sd->gaussrand,state->ld_rng,state->ld_rngi[0]);
+ gmx_stochd_t *sd;
+ int i;
+
+ sd = upd->sd;
+
+ gmx_rng_set_state(sd->gaussrand[0],state->ld_rng,state->ld_rngi[0]);
+
+ if (sd->ngaussrand > 1)
+ {
+ /* We only end up here with SD or BD with OpenMP.
+ * Destroy and reinitialize the rest of the random number generators,
+ * using seeds generated from the first one.
+ * Although this doesn't recover the previous state,
+ * it at least avoids repetition, which is most important.
+ * Exaclty restoring states with all MPI+OpenMP setups is difficult
+ * and as the integrator is random to start with, doesn't gain us much.
+ */
+ for(i=1; i<sd->ngaussrand; i++)
+ {
+ gmx_rng_destroy(sd->gaussrand[i]);
+ }
+
+ init_multiple_gaussrand(sd);
+ }
}
gmx_update_t init_update(FILE *fplog,t_inputrec *ir)
if (ir->eI == eiBD || EI_SD(ir->eI) || ir->etc == etcVRESCALE || ETC_ANDERSEN(ir->etc))
{
- upd->sd = init_stochd(fplog,ir);
+ upd->sd = init_stochd(fplog,ir,gmx_omp_nthreads_get(emntUpdate));
}
upd->xp = NULL;
}
static void do_update_sd1(gmx_stochd_t *sd,
- int start,int homenr,double dt,
+ gmx_rng_t gaussrand,
+ int start,int nrend,double dt,
rvec accel[],ivec nFreeze[],
real invmass[],unsigned short ptype[],
unsigned short cFREEZE[],unsigned short cACC[],
{
gmx_sd_const_t *sdc;
gmx_sd_sigma_t *sig;
- gmx_rng_t gaussrand;
real kT;
int gf=0,ga=0,gt=0;
real ism,sd_V;
sdc = sd->sdc;
sig = sd->sdsig;
- if (homenr > sd->sd_V_nalloc)
+ if (nrend-start > sd->sd_V_nalloc)
{
- sd->sd_V_nalloc = over_alloc_dd(homenr);
+ sd->sd_V_nalloc = over_alloc_dd(nrend-start);
srenew(sd->sd_V,sd->sd_V_nalloc);
}
- gaussrand = sd->gaussrand;
for(n=0; n<ngtc; n++)
{
sig[n].V = sqrt(kT*(1 - sdc[n].em*sdc[n].em));
}
- for(n=start; n<start+homenr; n++)
+ for(n=start; n<nrend; n++)
{
ism = sqrt(invmass[n]);
if (cFREEZE)
}
}
-static void do_update_sd2(gmx_stochd_t *sd,gmx_bool bInitStep,
- int start,int homenr,
+static void do_update_sd2(gmx_stochd_t *sd,
+ gmx_rng_t gaussrand,
+ gmx_bool bInitStep,
+ int start,int nrend,
rvec accel[],ivec nFreeze[],
real invmass[],unsigned short ptype[],
unsigned short cFREEZE[],unsigned short cACC[],
* half of the update, needs to be remembered for the second half.
*/
rvec *sd_V;
- gmx_rng_t gaussrand;
real kT;
int gf=0,ga=0,gt=0;
real vn=0,Vmh,Xmh;
sdc = sd->sdc;
sig = sd->sdsig;
- if (homenr > sd->sd_V_nalloc)
+ if (nrend-start > sd->sd_V_nalloc)
{
- sd->sd_V_nalloc = over_alloc_dd(homenr);
+ sd->sd_V_nalloc = over_alloc_dd(nrend-start);
srenew(sd->sd_V,sd->sd_V_nalloc);
}
sd_V = sd->sd_V;
- gaussrand = sd->gaussrand;
if (bFirstHalf)
{
}
}
- for (n=start; n<start+homenr; n++)
+ for (n=start; n<nrend; n++)
{
ism = sqrt(invmass[n]);
if (cFREEZE)
break;
case etcVRESCALE:
vrescale_tcoupl(inputrec,ekind,dttc,
- state->therm_integral,upd->sd->gaussrand);
+ state->therm_integral,upd->sd->gaussrand[0]);
break;
}
/* rescale in place here */
int start,homenr,nrend,i,n,m,g,d;
tensor vir_con;
rvec *vbuf,*xprime=NULL;
+ int nth,th;
if (constr) {bDoConstr=TRUE;}
if (bFirstHalf && !EI_VV(inputrec->eI)) {bDoConstr=FALSE;}
{
xprime = get_xprime(state,upd);
- /* The second part of the SD integration */
- do_update_sd2(upd->sd,FALSE,start,homenr,
- inputrec->opts.acc,inputrec->opts.nFreeze,
- md->invmass,md->ptype,
- md->cFREEZE,md->cACC,md->cTC,
- state->x,xprime,state->v,force,state->sd_X,
- inputrec->opts.ngtc,inputrec->opts.tau_t,
- inputrec->opts.ref_t,FALSE);
+ nth = gmx_omp_nthreads_get(emntUpdate);
+
+#pragma omp parallel for num_threads(nth) schedule(static)
+ for(th=0; th<nth; th++)
+ {
+ int start_th,end_th;
+
+ start_th = start + ((nrend-start)* th )/nth;
+ end_th = start + ((nrend-start)*(th+1))/nth;
+
+ /* The second part of the SD integration */
+ do_update_sd2(upd->sd,upd->sd->gaussrand[th],
+ FALSE,start_th,end_th,
+ inputrec->opts.acc,inputrec->opts.nFreeze,
+ md->invmass,md->ptype,
+ md->cFREEZE,md->cACC,md->cTC,
+ state->x,xprime,state->v,force,state->sd_X,
+ inputrec->opts.ngtc,inputrec->opts.tau_t,
+ inputrec->opts.ref_t,FALSE);
+ }
inc_nrnb(nrnb, eNR_UPDATE, homenr);
if (bDoConstr)
nth = gmx_omp_nthreads_get(emntUpdate);
}
-# pragma omp parallel for num_threads(nth) schedule(static) private(alpha)
+#pragma omp parallel for num_threads(nth) schedule(static) private(alpha)
for(th=0; th<nth; th++)
{
int start_th,end_th;
}
break;
case (eiSD1):
- do_update_sd1(upd->sd,start,homenr,dt,
+ do_update_sd1(upd->sd,upd->sd->gaussrand[th],
+ start_th,end_th,dt,
inputrec->opts.acc,inputrec->opts.nFreeze,
md->invmass,md->ptype,
md->cFREEZE,md->cACC,md->cTC,
/* The SD update is done in 2 parts, because an extra constraint step
* is needed
*/
- do_update_sd2(upd->sd,bInitStep,start,homenr,
+ do_update_sd2(upd->sd,upd->sd->gaussrand[th],
+ bInitStep,start_th,end_th,
inputrec->opts.acc,inputrec->opts.nFreeze,
md->invmass,md->ptype,
md->cFREEZE,md->cACC,md->cTC,
TRUE);
break;
case (eiBD):
- do_update_bd(start,nrend,dt,
+ do_update_bd(start_th,end_th,dt,
inputrec->opts.nFreeze,md->invmass,md->ptype,
md->cFREEZE,md->cTC,
state->x,xprime,state->v,force,
inputrec->bd_fric,
inputrec->opts.ngtc,inputrec->opts.tau_t,inputrec->opts.ref_t,
- upd->sd->bd_rf,upd->sd->gaussrand);
+ upd->sd->bd_rf,upd->sd->gaussrand[th]);
break;
case (eiVV):
case (eiVVAK):
}
upd->randatom_list_init = TRUE;
}
- andersen_tcoupl(ir,md,state,upd->sd->gaussrand,rate,
+ andersen_tcoupl(ir,md,state,upd->sd->gaussrand[0],rate,
(ir->etc==etcANDERSEN)?idef:NULL,
constr?get_nblocks(constr):0,
constr?get_sblock(constr):NULL,
# To help us fund GROMACS development, we humbly ask that you cite
# the research papers on the package. Check out http://www.gromacs.org.
#
-enable_testing()
-add_test(TestExec_mdrun-h ../src/kernel/mdrun -h)
+set(REGRESSIONTEST_PATH "" CACHE PATH "Directory containing regressiontests")
+mark_as_advanced(REGRESSIONTEST_PATH)
+option(REGRESSIONTEST_DOWNLOAD
+ "Automatically download regressiontests. Tests can be run with ctest." no)
+if(REGRESSIONTEST_DOWNLOAD AND CMAKE_VERSION VERSION_LESS "2.8.2")
+ message(WARNING "REGRESSIONTEST_DOWNLOAD requires cmake >=2.8.2. Please update cmake or manually download the regressiontests.")
+ set(REGRESSIONTEST_DOWNLOAD FALSE CACHE BOOL
+ "REGRESSIONTEST_DOWNLOAD not supported with cmake ${CMAKE_VERSION}" FORCE)
+endif()
+if(REGRESSIONTEST_DOWNLOAD)
+ if("${PROJECT_VERSION}" MATCHES "-dev")
+ set(REGRESSIONTEST_VERSION master)
+ else()
+ set(REGRESSIONTEST_VERSION ${PROJECT_VERSION})
+ endif()
+ set(REGRESSIONTEST_URL
+ http://gerrit.gromacs.org/download/regressiontests-${REGRESSIONTEST_VERSION}.tar.gz)
+ set(REGRESSIONTEST_FILE "${CMAKE_CURRENT_BINARY_DIR}/regressiontests.tgz")
+ message("Downloading: ${REGRESSIONTEST_URL}")
+ file(DOWNLOAD ${REGRESSIONTEST_URL} "${REGRESSIONTEST_FILE}" SHOW_PROGRESS STATUS status LOG log)
+ list(GET status 0 status_code)
+ list(GET status 1 status_string)
+
+ if(NOT status_code EQUAL 0)
+ message(FATAL_ERROR "error: downloading '${REGRESSIONTEST_URL}' failed
+status_code: ${status_code}
+status_string: ${status_string}
+log: ${log}")
+ endif()
+
+ set(REGRESSIONTEST_PATH
+ "${CMAKE_CURRENT_BINARY_DIR}/regressiontests-${REGRESSIONTEST_VERSION}"
+ CACHE PATH "Path to auto-downloaded regressiontests" FORCE)
+ file(REMOVE_RECURSE "${REGRESSIONTEST_PATH}") #delete potential prior folder
+ execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${REGRESSIONTEST_FILE}"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+ if(NOT EXISTS ${REGRESSIONTEST_PATH}/gmxtest.pl)
+ message(FATAL_ERROR "Download incorrect. Doesn't contain required gmxtest.pl")
+ endif()
+ set(REGRESSIONTEST_DOWNLOAD OFF CACHE BOOL "Tests already downloaded. Set to yes to download again" FORCE)
+endif()
+
+if(REGRESSIONTEST_PATH AND (GMX_BLUEGENE OR CMAKE_CROSSCOMPILING OR CMAKE_CONFIGURATION_TYPES))
+ #Bluegene requires us to compile both front-end and back-end binaries (single build is insufficient)
+ message(WARNING
+ "With cross-compiling or multi-configuration generators (e.g. Visual Studio), running regressiontests from build system is not supported. Please run gmxtest.pl directly.")
+ set(REGRESSIONTEST_PATH OFF CACHE BOOL
+ "With cross-compiling or multi-configuration generators, running regressiontests from build system is not supported." FORCE)
+endif()
+
+if(REGRESSIONTEST_PATH)
+ if(NOT EXISTS ${REGRESSIONTEST_PATH}/gmxtest.pl)
+ message(FATAL_ERROR
+ "REGRESSIONTEST_PATH invalid. The path needs to contain gmxtest.pl.")
+ endif()
+ if(GMX_DOUBLE)
+ list(APPEND ARGS -double)
+ endif()
+ if(GMX_LIB_MPI AND NOT MPIEXEC) #autodetection failed or CC=mpicc was used
+ message(WARNING
+ "Please set MPIEXEC. Otherwise mpirun is assumed for runnings tests.")
+ endif()
+ if(GMX_LIB_MPI)
+ set(GMX_TEST_NUMBER_PROCS 8 CACHE STRING "Number of processors used for testing")
+ mark_as_advanced(GMX_TEST_NUMBER_PROCS)
+ list(APPEND ARGS -np ${GMX_TEST_NUMBER_PROCS})
+ if(MPIEXEC)
+ list(APPEND ARGS -mpirun ${MPIEXEC})
+ endif()
+ #We should use MPIEXEC_NUMPROC_FLAG but gmxtest.pl doesn't let us pass it
+ endif()
+ if(GMX_BINARY_SUFFIX)
+ list(APPEND ARGS -suffix ${GMX_BINARY_SUFFIX})
+ endif()
+ #crosscompile is only used to disable checking whether binaries work
+ #given that we know they are there and that mdrun might not be exectuable
+ #(e.g. Cray) we enable it.
+ list(APPEND ARGS -crosscompile)
+
+ set(REGRESSIONTEST_EXTRA_ARGS "" CACHE STRING
+ "Extra arguments passed to gmxtest")
+ mark_as_advanced(REGRESSIONTEST_EXTRA_ARGS)
+ list(APPEND ARGS ${REGRESSIONTEST_EXTRA_ARGS})
+
+ list(APPEND ARGS -noverbose -nosuffix)
+
+ if(GMX_NATIVE_WINDOWS)
+ set(PATH_SEPARATOR "\\;")
+ #replacing \ with / shouldn't be neccessary. But otherwise "..\bin\;c:\.."
+ #gets turned into "...\bin\\c:\.." don't know why and don't have a better
+ #workaround. This workaround doesn't hurt.
+ string(REPLACE "\\" "/" PATH "$ENV{PATH}")
+ #protect ; (don't treat as list)
+ string(REPLACE ";" "\\;" PATH "${PATH}")
+ else()
+ set(PATH_SEPARATOR ":")
+ set(PATH "$ENV{PATH}")
+ endif()
+
+ foreach(FOLDER kernel tools gmxlib mdlib) #lib folders might be needed for
+ #e.g. DLLs. For GMX paths native ("\") is needed for GMXLIB detection
+ file(TO_NATIVE_PATH "${CMAKE_BINARY_DIR}/src/${FOLDER}" DIR)
+ set(PATH "${DIR}${PATH_SEPARATOR}${PATH}")
+ endforeach()
+
+ find_program(PERL_EXECUTABLE NAMES "perl")
+ mark_as_advanced(PERL_EXECUTABLE)
+
+ if (NOT PERL_EXECUTABLE)
+ message(FATAL_ERROR "Perl not found. Install perl, set PERL_EXECUTABLE to the perl location, or unset REGRESSIONTEST_PATH to disable testing.")
+ endif()
+
+ #currently not testing tools because they don't contain any useful tests
+ foreach(subtest simple complex kernel freeenergy pdb2gmx)
+ add_test(NAME regressiontests/${subtest}
+ #windows requires the command to be perl and not the script
+ COMMAND perl "${REGRESSIONTEST_PATH}/gmxtest.pl" ${subtest} ${ARGS})
+ set_tests_properties(regressiontests/${subtest} PROPERTIES
+ ENVIRONMENT "PATH=${PATH}")
+ endforeach()
+endif()