2006-09-28 03:51:33 +08:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
2007-01-30 08:22:05 +08:00
|
|
|
http://lammps.sandia.gov, Sandia National Laboratories
|
|
|
|
Steve Plimpton, sjplimp@sandia.gov
|
2006-09-28 03:51:33 +08:00
|
|
|
|
|
|
|
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
|
|
|
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
|
|
|
certain rights in this software. This software is distributed under
|
|
|
|
the GNU General Public License.
|
|
|
|
|
|
|
|
See the README file in the top-level LAMMPS directory.
|
|
|
|
------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
// Park/Miller RNG
|
|
|
|
|
|
|
|
#include "math.h"
|
|
|
|
#include "random_park.h"
|
2007-06-20 21:17:59 +08:00
|
|
|
#include "domain.h"
|
|
|
|
#include "error.h"
|
2006-09-28 03:51:33 +08:00
|
|
|
|
2007-01-30 08:22:05 +08:00
|
|
|
using namespace LAMMPS_NS;
|
|
|
|
|
2006-09-28 03:51:33 +08:00
|
|
|
#define IA 16807
|
|
|
|
#define IM 2147483647
|
|
|
|
#define AM (1.0/IM)
|
|
|
|
#define IQ 127773
|
|
|
|
#define IR 2836
|
|
|
|
|
2007-06-20 21:17:59 +08:00
|
|
|
#define IA1 1366
|
|
|
|
#define IC1 150889
|
|
|
|
#define IM1 714025
|
|
|
|
#define IA2 8121
|
|
|
|
#define IC2 28411
|
|
|
|
#define IM2 134456
|
|
|
|
#define IA3 7141
|
|
|
|
#define IC3 54773
|
|
|
|
#define IM3 259200
|
|
|
|
|
2006-09-28 03:51:33 +08:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
|
2007-01-30 08:22:05 +08:00
|
|
|
RanPark::RanPark(LAMMPS *lmp, int seed_init) : Pointers(lmp)
|
2006-09-28 03:51:33 +08:00
|
|
|
{
|
2007-10-10 07:40:36 +08:00
|
|
|
if (seed_init <= 0) error->all("Invalid seed for Park random # generator");
|
2006-09-28 03:51:33 +08:00
|
|
|
seed = seed_init;
|
|
|
|
save = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
uniform RN
|
|
|
|
------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
double RanPark::uniform()
|
|
|
|
{
|
|
|
|
int k = seed/IQ;
|
|
|
|
seed = IA*(seed-k*IQ) - IR*k;
|
|
|
|
if (seed < 0) seed += IM;
|
|
|
|
double ans = AM*seed;
|
|
|
|
return ans;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
gaussian RN
|
|
|
|
------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
double RanPark::gaussian()
|
|
|
|
{
|
|
|
|
double first,v1,v2,rsq,fac;
|
|
|
|
|
|
|
|
if (!save) {
|
|
|
|
int again = 1;
|
|
|
|
while (again) {
|
|
|
|
v1 = 2.0*uniform()-1.0;
|
|
|
|
v2 = 2.0*uniform()-1.0;
|
|
|
|
rsq = v1*v1 + v2*v2;
|
|
|
|
if (rsq < 1.0 && rsq != 0.0) again = 0;
|
|
|
|
}
|
|
|
|
fac = sqrt(-2.0*log(rsq)/rsq);
|
|
|
|
second = v1*fac;
|
|
|
|
first = v2*fac;
|
|
|
|
save = 1;
|
|
|
|
} else {
|
|
|
|
first = second;
|
|
|
|
save = 0;
|
|
|
|
}
|
|
|
|
return first;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
2007-06-20 21:17:59 +08:00
|
|
|
reset the seed based on atom position within box and ibase = caller seed
|
|
|
|
combine 3 RNGs based on fractional position in box into one new seed
|
2006-09-28 03:51:33 +08:00
|
|
|
------------------------------------------------------------------------- */
|
|
|
|
|
2007-06-20 21:17:59 +08:00
|
|
|
void RanPark::reset(int ibase, double *coord)
|
2006-09-28 03:51:33 +08:00
|
|
|
{
|
2007-06-20 21:17:59 +08:00
|
|
|
// for orthogonal box, lamda = fractional position in box
|
|
|
|
// for triclinic box, convert to lamda coords
|
|
|
|
|
|
|
|
double lamda[3];
|
|
|
|
|
|
|
|
if (domain->triclinic == 0) {
|
|
|
|
lamda[0] = (coord[0] - domain->boxlo[0]) / domain->prd[0];
|
|
|
|
lamda[1] = (coord[1] - domain->boxlo[1]) / domain->prd[1];
|
|
|
|
lamda[2] = (coord[2] - domain->boxlo[2]) / domain->prd[2];
|
|
|
|
} else domain->x2lamda(coord,lamda);
|
|
|
|
|
|
|
|
// seed 1,2,3 = combination of atom coord in each dim and user-input seed
|
|
|
|
// map geometric extent into range of each of 3 RNGs
|
|
|
|
// warm-up each RNG by calling it twice
|
|
|
|
|
|
|
|
int seed1,seed2,seed3;
|
|
|
|
|
|
|
|
seed1 = static_cast<int> (lamda[0] * IM1);
|
|
|
|
seed1 = (seed1+ibase) % IM1;
|
|
|
|
seed1 = (seed1*IA1+IC1) % IM1;
|
|
|
|
seed1 = (seed1*IA1+IC1) % IM1;
|
|
|
|
|
|
|
|
seed2 = static_cast<int> (lamda[1] * IM2);
|
|
|
|
seed2 = (seed2+ibase) % IM2;
|
|
|
|
seed2 = (seed2*IA2+IC2) % IM2;
|
|
|
|
seed2 = (seed2*IA2+IC2) % IM2;
|
|
|
|
|
|
|
|
seed3 = static_cast<int> (lamda[2] * IM3);
|
|
|
|
seed3 = (seed3+ibase) % IM3;
|
|
|
|
seed3 = (seed3*IA3+IC3) % IM3;
|
|
|
|
seed3 = (seed3*IA3+IC3) % IM3;
|
|
|
|
|
|
|
|
// fraction = 0-1 with giving each dim an equal weighting
|
|
|
|
// use fraction to reset Park/Miller RNG seed
|
|
|
|
// warm-up master RNG with new seed by calling it twice
|
|
|
|
|
|
|
|
double fraction = 1.0*seed1/(3*IM1) + 1.0*seed2/(3*IM2) + 1.0*seed3/(3*IM3);
|
2006-09-28 03:51:33 +08:00
|
|
|
seed = static_cast<int> (fraction*IM) + 1;
|
|
|
|
if (seed >= IM) seed = IM-1;
|
2007-06-20 21:17:59 +08:00
|
|
|
|
|
|
|
uniform();
|
|
|
|
uniform();
|
2006-09-28 03:51:33 +08:00
|
|
|
}
|