运行 Java 多线程下的分子动力学模拟程序
Run Java Molecular Dynamic simulation program in multithreading
我这里有这个小程序,我必须让它在多线程中工作。我尝试这样做,但是当将线程数设置为 1 时,程序似乎按预期运行。所以,一般程序运行正常。但是如果我设置值让我们说 2 或 4。变得疯狂。我没有得到所需的结果。好像是计算出了问题。我用头撞墙,试图找出问题所在,但我尝试的一切似乎都无法解决问题。这是顺序代码:
/*
* "Physics" part of code adapted from Dan Schroeder's applet at:
*
* http://physics.weber.edu/schroeder/software/mdapplet.html
*/
import java.awt.* ;
import javax.swing.* ;
public class MD {
// Size of simulation
final static int N = 2000 ; // Number of "atoms"
final static double BOX_WIDTH = 100.0 ;
// Initial state - controls temperature of system
//final static double VELOCITY = 3.0 ; // gaseous
final static double VELOCITY = 2.0 ; // gaseous/"liquid"
//final static double VELOCITY = 1.0 ; // "crystalline"
final static double INIT_SEPARATION = 2.2 ; // in atomic radii
// Simulation
final static double DT = 0.01 ; // Time step
// Display
final static int WINDOW_SIZE = 800 ;
final static int DELAY = 0 ;
final static int OUTPUT_FREQ = 20 ;
// Physics constants
final static double ATOM_RADIUS = 0.5 ;
final static double WALL_STIFFNESS = 500.0 ;
final static double GRAVITY = 0.005 ;
final static double FORCE_CUTOFF = 3.0 ;
// Atom positions
static double [] x = new double [N] ;
static double [] y = new double [N] ;
// Atom velocities
static double [] vx = new double [N] ;
static double [] vy = new double [N] ;
// Atom accelerations
static double [] ax = new double [N] ;
static double [] ay = new double [N] ;
public static void main(String args []) throws Exception {
Display display = new Display() ;
// Define initial state of atoms
int sqrtN = (int) (Math.sqrt((double) N) + 0.5) ;
double initSeparation = INIT_SEPARATION * ATOM_RADIUS ;
for(int i = 0 ; i < N ; i++) {
// lay out atoms regularly, so no overlap
x [i] = (0.5 + i % sqrtN) * initSeparation ;
y [i] = (0.5 + i / sqrtN) * initSeparation ;
vx [i] = (2 * Math.random() - 1) * VELOCITY ;
vy [i] = (2 * Math.random() - 1) * VELOCITY ;
}
int iter = 0 ;
while(true) {
if(iter % OUTPUT_FREQ == 0) {
System.out.println("iter = " + iter + ", time = " + iter * DT) ;
display.repaint() ;
Thread.sleep(DELAY) ;
}
// Verlet integration:
// http://en.wikipedia.org/wiki/Verlet_integration#Velocity_Verlet
double dtOver2 = 0.5 * DT;
double dtSquaredOver2 = 0.5 * DT * DT;
for (int i = 0; i < N; i++) {
x[i] += (vx[i] * DT) + (ax[i] * dtSquaredOver2);
// update position
y[i] += (vy[i] * DT) + (ay[i] * dtSquaredOver2);
vx[i] += (ax[i] * dtOver2); // update velocity halfway
vy[i] += (ay[i] * dtOver2);
}
computeAccelerations();
for (int i = 0; i < N; i++) {
vx[i] += (ax[i] * dtOver2);
// finish updating velocity with new acceleration
vy[i] += (ay[i] * dtOver2);
}
iter++ ;
}
}
// Compute accelerations of all atoms from current positions:
static void computeAccelerations() {
double dx, dy; // separations in x and y directions
double dx2, dy2, rSquared, rSquaredInv, attract, repel, fOverR, fx, fy;
// first check for bounces off walls, and include gravity (if any):
for (int i = 0; i < N; i++) {
if (x[i] < ATOM_RADIUS) {
ax[i] = WALL_STIFFNESS * (ATOM_RADIUS - x[i]);
}
else if (x[i] > (BOX_WIDTH - ATOM_RADIUS)) {
ax[i] = WALL_STIFFNESS * (BOX_WIDTH - ATOM_RADIUS - x[i]);
}
else {
ax[i] = 0.0;
}
if (y[i] < ATOM_RADIUS) {
ay[i] = (WALL_STIFFNESS * (ATOM_RADIUS - y[i]));
}
else if (y[i] > (BOX_WIDTH - ATOM_RADIUS)) {
ay[i] = (WALL_STIFFNESS * (BOX_WIDTH - ATOM_RADIUS - y[i]));
}
else {
ay[i] = 0;
}
ay[i] -= GRAVITY ;
}
double forceCutoff2 = FORCE_CUTOFF * FORCE_CUTOFF ;
// Now compute interaction forces (Lennard-Jones potential).
// This is where the program spends most of its time.
for (int i = 1; i < N; i++) {
for (int j = 0; j < i; j++) { // loop over all distinct pairs
dx = x[i] - x[j];
dx2 = dx * dx;
if (dx2 < forceCutoff2) { // make sure they're close enough to bother
dy = y[i] - y[j];
dy2 = dy * dy;
if (dy2 < forceCutoff2) {
rSquared = dx2 + dy2;
if (rSquared < forceCutoff2) {
rSquaredInv = 1.0 / rSquared;
attract = rSquaredInv * rSquaredInv * rSquaredInv;
repel = attract * attract;
fOverR = 24.0 * ((2.0 * repel) - attract) * rSquaredInv;
fx = fOverR * dx;
fy = fOverR * dy;
ax[i] += fx; // add this force on to i's acceleration (mass = 1)
ay[i] += fy;
ax[j] -= fx; // Newton's 3rd law
ay[j] -= fy;
}
}
}
}
}
}
static class Display extends JPanel {
static final double SCALE = WINDOW_SIZE / BOX_WIDTH ;
static final int DIAMETER =
Math.max((int) (SCALE * 2 * ATOM_RADIUS), 2) ;
Display() {
setPreferredSize(new Dimension(WINDOW_SIZE, WINDOW_SIZE)) ;
JFrame frame = new JFrame("MD");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(this);
frame.pack();
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
g.setColor(Color.WHITE) ;
g.fillRect(0, 0, WINDOW_SIZE, WINDOW_SIZE) ;
g.setColor(Color.BLUE) ;
for(int i = 0 ; i < N ; i++) {
g.fillOval((int) (SCALE * (x [i] - ATOM_RADIUS)),
WINDOW_SIZE - 1 - (int) (SCALE * (y [i] + ATOM_RADIUS)),
DIAMETER, DIAMETER) ;
}
}
}
}
有人能找出问题所在吗?
begin
和 end
被声明为静态的,因此所有线程在计算期间都错误地使用了相同的变量。
A) begin/end 将被错误地设置为线程之间在其方法 运行()
开始时竞争条件的随机输出
B) 所有线程都可能在相同的索引范围内工作,忽略位置、速度、加速度数组的其余部分。
另外所有线程都是运行宁不必要完全相同的代码:
for (int i = 0; i < N; i++) {
x[i] += (vx[i] * DT) + (ax[i] * dtSquaredOver2);
// update position
...
我会建议将所有变量更改为实例变量,然后将代码修改为静态,仅那些应该在线程之间共享的变量。静态变量的读取没问题,如果它们是独占的,则必须检查写入。 (写入 x、vx 的不同部分...从这个意义上说,数组是 'exclusive',只需确保索引不重叠)。
我这里有这个小程序,我必须让它在多线程中工作。我尝试这样做,但是当将线程数设置为 1 时,程序似乎按预期运行。所以,一般程序运行正常。但是如果我设置值让我们说 2 或 4。变得疯狂。我没有得到所需的结果。好像是计算出了问题。我用头撞墙,试图找出问题所在,但我尝试的一切似乎都无法解决问题。这是顺序代码:
/*
* "Physics" part of code adapted from Dan Schroeder's applet at:
*
* http://physics.weber.edu/schroeder/software/mdapplet.html
*/
import java.awt.* ;
import javax.swing.* ;
public class MD {
// Size of simulation
final static int N = 2000 ; // Number of "atoms"
final static double BOX_WIDTH = 100.0 ;
// Initial state - controls temperature of system
//final static double VELOCITY = 3.0 ; // gaseous
final static double VELOCITY = 2.0 ; // gaseous/"liquid"
//final static double VELOCITY = 1.0 ; // "crystalline"
final static double INIT_SEPARATION = 2.2 ; // in atomic radii
// Simulation
final static double DT = 0.01 ; // Time step
// Display
final static int WINDOW_SIZE = 800 ;
final static int DELAY = 0 ;
final static int OUTPUT_FREQ = 20 ;
// Physics constants
final static double ATOM_RADIUS = 0.5 ;
final static double WALL_STIFFNESS = 500.0 ;
final static double GRAVITY = 0.005 ;
final static double FORCE_CUTOFF = 3.0 ;
// Atom positions
static double [] x = new double [N] ;
static double [] y = new double [N] ;
// Atom velocities
static double [] vx = new double [N] ;
static double [] vy = new double [N] ;
// Atom accelerations
static double [] ax = new double [N] ;
static double [] ay = new double [N] ;
public static void main(String args []) throws Exception {
Display display = new Display() ;
// Define initial state of atoms
int sqrtN = (int) (Math.sqrt((double) N) + 0.5) ;
double initSeparation = INIT_SEPARATION * ATOM_RADIUS ;
for(int i = 0 ; i < N ; i++) {
// lay out atoms regularly, so no overlap
x [i] = (0.5 + i % sqrtN) * initSeparation ;
y [i] = (0.5 + i / sqrtN) * initSeparation ;
vx [i] = (2 * Math.random() - 1) * VELOCITY ;
vy [i] = (2 * Math.random() - 1) * VELOCITY ;
}
int iter = 0 ;
while(true) {
if(iter % OUTPUT_FREQ == 0) {
System.out.println("iter = " + iter + ", time = " + iter * DT) ;
display.repaint() ;
Thread.sleep(DELAY) ;
}
// Verlet integration:
// http://en.wikipedia.org/wiki/Verlet_integration#Velocity_Verlet
double dtOver2 = 0.5 * DT;
double dtSquaredOver2 = 0.5 * DT * DT;
for (int i = 0; i < N; i++) {
x[i] += (vx[i] * DT) + (ax[i] * dtSquaredOver2);
// update position
y[i] += (vy[i] * DT) + (ay[i] * dtSquaredOver2);
vx[i] += (ax[i] * dtOver2); // update velocity halfway
vy[i] += (ay[i] * dtOver2);
}
computeAccelerations();
for (int i = 0; i < N; i++) {
vx[i] += (ax[i] * dtOver2);
// finish updating velocity with new acceleration
vy[i] += (ay[i] * dtOver2);
}
iter++ ;
}
}
// Compute accelerations of all atoms from current positions:
static void computeAccelerations() {
double dx, dy; // separations in x and y directions
double dx2, dy2, rSquared, rSquaredInv, attract, repel, fOverR, fx, fy;
// first check for bounces off walls, and include gravity (if any):
for (int i = 0; i < N; i++) {
if (x[i] < ATOM_RADIUS) {
ax[i] = WALL_STIFFNESS * (ATOM_RADIUS - x[i]);
}
else if (x[i] > (BOX_WIDTH - ATOM_RADIUS)) {
ax[i] = WALL_STIFFNESS * (BOX_WIDTH - ATOM_RADIUS - x[i]);
}
else {
ax[i] = 0.0;
}
if (y[i] < ATOM_RADIUS) {
ay[i] = (WALL_STIFFNESS * (ATOM_RADIUS - y[i]));
}
else if (y[i] > (BOX_WIDTH - ATOM_RADIUS)) {
ay[i] = (WALL_STIFFNESS * (BOX_WIDTH - ATOM_RADIUS - y[i]));
}
else {
ay[i] = 0;
}
ay[i] -= GRAVITY ;
}
double forceCutoff2 = FORCE_CUTOFF * FORCE_CUTOFF ;
// Now compute interaction forces (Lennard-Jones potential).
// This is where the program spends most of its time.
for (int i = 1; i < N; i++) {
for (int j = 0; j < i; j++) { // loop over all distinct pairs
dx = x[i] - x[j];
dx2 = dx * dx;
if (dx2 < forceCutoff2) { // make sure they're close enough to bother
dy = y[i] - y[j];
dy2 = dy * dy;
if (dy2 < forceCutoff2) {
rSquared = dx2 + dy2;
if (rSquared < forceCutoff2) {
rSquaredInv = 1.0 / rSquared;
attract = rSquaredInv * rSquaredInv * rSquaredInv;
repel = attract * attract;
fOverR = 24.0 * ((2.0 * repel) - attract) * rSquaredInv;
fx = fOverR * dx;
fy = fOverR * dy;
ax[i] += fx; // add this force on to i's acceleration (mass = 1)
ay[i] += fy;
ax[j] -= fx; // Newton's 3rd law
ay[j] -= fy;
}
}
}
}
}
}
static class Display extends JPanel {
static final double SCALE = WINDOW_SIZE / BOX_WIDTH ;
static final int DIAMETER =
Math.max((int) (SCALE * 2 * ATOM_RADIUS), 2) ;
Display() {
setPreferredSize(new Dimension(WINDOW_SIZE, WINDOW_SIZE)) ;
JFrame frame = new JFrame("MD");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(this);
frame.pack();
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
g.setColor(Color.WHITE) ;
g.fillRect(0, 0, WINDOW_SIZE, WINDOW_SIZE) ;
g.setColor(Color.BLUE) ;
for(int i = 0 ; i < N ; i++) {
g.fillOval((int) (SCALE * (x [i] - ATOM_RADIUS)),
WINDOW_SIZE - 1 - (int) (SCALE * (y [i] + ATOM_RADIUS)),
DIAMETER, DIAMETER) ;
}
}
}
}
有人能找出问题所在吗?
begin
和 end
被声明为静态的,因此所有线程在计算期间都错误地使用了相同的变量。
A) begin/end 将被错误地设置为线程之间在其方法 运行()
开始时竞争条件的随机输出B) 所有线程都可能在相同的索引范围内工作,忽略位置、速度、加速度数组的其余部分。
另外所有线程都是运行宁不必要完全相同的代码:
for (int i = 0; i < N; i++) {
x[i] += (vx[i] * DT) + (ax[i] * dtSquaredOver2);
// update position
...
我会建议将所有变量更改为实例变量,然后将代码修改为静态,仅那些应该在线程之间共享的变量。静态变量的读取没问题,如果它们是独占的,则必须检查写入。 (写入 x、vx 的不同部分...从这个意义上说,数组是 'exclusive',只需确保索引不重叠)。