#include "fix_imd.h"
#include "atom.h"
#include "comm.h"
#include "update.h"
#include "respa.h"
#include "domain.h"
#include "force.h"
#include "error.h"
#include "group.h"
#include "memory.h"
#include <cstdlib>
#include <cstring>
#if defined(_MSC_VER) || defined(__MINGW32__)
#include <winsock2.h>
#else
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/file.h>
#endif
#include <errno.h>
using namespace LAMMPS_NS;
using namespace FixConst;
typedef struct taginthash_t {
struct taginthash_node_t **bucket;
tagint size;
tagint entries;
tagint downshift;
tagint mask;
} taginthash_t;
typedef struct taginthash_node_t {
tagint data;
tagint key;
struct taginthash_node_t *next;
} taginthash_node_t;
#define HASH_FAIL -1
#define HASH_LIMIT 0.5
static void taginthash_init(taginthash_t *tptr, tagint buckets);
static tagint taginthash_lookup(const taginthash_t *tptr, tagint key);
static tagint *taginthash_keys(taginthash_t *tptr);
static tagint taginthash_insert(taginthash_t *tptr, tagint key, tagint data);
static void taginthash_destroy(taginthash_t *tptr);
static void id_sort(tagint *idmap, tagint left, tagint right);
static tagint taginthash(const taginthash_t *tptr, tagint key) {
tagint hashvalue;
hashvalue = (((key*1103515249)>>tptr->downshift) & tptr->mask);
if (hashvalue < 0) {
hashvalue = 0;
}
return hashvalue;
}
static void rebuild_table_tagint(taginthash_t *tptr) {
taginthash_node_t **old_bucket, *old_hash, *tmp;
tagint old_size, h, i;
old_bucket=tptr->bucket;
old_size=tptr->size;
taginthash_init(tptr, old_size<<1);
for (i=0; i<old_size; i++) {
old_hash=old_bucket[i];
while(old_hash) {
tmp=old_hash;
old_hash=old_hash->next;
h=taginthash(tptr, tmp->key);
tmp->next=tptr->bucket[h];
tptr->bucket[h]=tmp;
tptr->entries++;
}
}
free(old_bucket);
return;
}
void taginthash_init(taginthash_t *tptr, tagint buckets) {
if (buckets==0)
buckets=16;
tptr->entries=0;
tptr->size=2;
tptr->mask=1;
tptr->downshift=29;
while (tptr->size<buckets) {
tptr->size<<=1;
tptr->mask=(tptr->mask<<1)+1;
tptr->downshift--;
}
tptr->bucket=(taginthash_node_t **) calloc(tptr->size, sizeof(taginthash_node_t *));
return;
}
tagint taginthash_lookup(const taginthash_t *tptr, tagint key) {
tagint h;
taginthash_node_t *node;
h=taginthash(tptr, key);
for (node=tptr->bucket[h]; node!=NULL; node=node->next) {
if (node->key == key)
break;
}
return(node ? node->data : HASH_FAIL);
}
tagint *taginthash_keys(taginthash_t *tptr) {
tagint *keys;
taginthash_node_t *node;
keys = (tagint *)calloc(tptr->entries, sizeof(tagint));
for (tagint i=0; i < tptr->size; ++i) {
for (node=tptr->bucket[i]; node != NULL; node=node->next) {
keys[node->data] = node->key;
}
}
return keys;
}
tagint taginthash_insert(taginthash_t *tptr, tagint key, tagint data) {
tagint tmp;
taginthash_node_t *node;
tagint h;
if ((tmp=taginthash_lookup(tptr, key)) != HASH_FAIL)
return(tmp);
while (tptr->entries>=HASH_LIMIT*tptr->size)
rebuild_table_tagint(tptr);
h=taginthash(tptr, key);
node=(struct taginthash_node_t *) malloc(sizeof(taginthash_node_t));
node->data=data;
node->key=key;
node->next=tptr->bucket[h];
tptr->bucket[h]=node;
tptr->entries++;
return HASH_FAIL;
}
void taginthash_destroy(taginthash_t *tptr) {
taginthash_node_t *node, *last;
tagint i;
for (i=0; i<tptr->size; i++) {
node = tptr->bucket[i];
while (node != NULL) {
last = node;
node = node->next;
free(last);
}
}
if (tptr->bucket != NULL) {
free(tptr->bucket);
memset(tptr, 0, sizeof(taginthash_t));
}
}
static void id_sort(tagint *idmap, tagint left, tagint right)
{
tagint pivot, l_hold, r_hold;
l_hold = left;
r_hold = right;
pivot = idmap[left];
while (left < right) {
while ((idmap[right] >= pivot) && (left < right))
right--;
if (left != right) {
idmap[left] = idmap[right];
left++;
}
while ((idmap[left] <= pivot) && (left < right))
left++;
if (left != right) {
idmap[right] = idmap[left];
right--;
}
}
idmap[left] = pivot;
pivot = left;
left = l_hold;
right = r_hold;
if (left < pivot)
id_sort(idmap, left, pivot-1);
if (right > pivot)
id_sort(idmap, pivot+1, right);
}
#include <climits>
#if ( INT_MAX == 2147483647 )
typedef int int32;
#else
typedef short int32;
#endif
typedef struct {
int32 type;
int32 length;
} IMDheader;
#define IMDHEADERSIZE 8
#define IMDVERSION 2
typedef enum IMDType_t {
IMD_DISCONNECT,
IMD_ENERGIES,
IMD_FCOORDS,
IMD_GO,
IMD_HANDSHAKE,
IMD_KILL,
IMD_MDCOMM,
IMD_PAUSE,
IMD_TRATE,
IMD_IOERROR
} IMDType;
typedef struct {
int32 tstep;
float T;
float Etot;
float Epot;
float Evdw;
float Eelec;
float Ebond;
float Eangle;
float Edihe;
float Eimpr;
} IMDEnergies;
static int imd_handshake(void *);
static IMDType imd_recv_header(void *, int32 *);
static int imd_recv_mdcomm(void *, int32, int32 *, float *);
static int imd_recv_energies(void *, IMDEnergies *);
static int imd_recv_fcoords(void *, int32, float *);
static void imd_fill_header(IMDheader *header, IMDType type, int32 length);
static int32 imd_writen(void *s, const char *ptr, int32 n);
typedef struct {
struct sockaddr_in addr;
int addrlen;
int sd;
} imdsocket;
static int imdsock_init(void);
static void *imdsock_create(void);
static int imdsock_bind(void *, int);
static int imdsock_listen(void *);
static void *imdsock_accept(void *);
static int imdsock_write(void *, const void *, int);
static int imdsock_read(void *, void *, int);
static int imdsock_selread(void *, int);
static int imdsock_selwrite(void *, int);
static void imdsock_shutdown(void *);
static void imdsock_destroy(void *);
struct commdata {
tagint tag;
float x,y,z;
};
FixIMD::FixIMD(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 4)
error->all(FLERR,"Illegal fix imd command");
imd_port = force->inumeric(FLERR,arg[3]);
if (imd_port < 1024)
error->all(FLERR,"Illegal fix imd parameter: port < 1024");
unwrap_flag = 0;
nowait_flag = 0;
connect_msg = 1;
imd_fscale = 1.0;
imd_trate = 1;
int argsdone = 4;
while (argsdone+1 < narg) {
if (0 == strcmp(arg[argsdone], "unwrap")) {
if (0 == strcmp(arg[argsdone+1], "on")) {
unwrap_flag = 1;
} else {
unwrap_flag = 0;
}
} else if (0 == strcmp(arg[argsdone], "nowait")) {
if (0 == strcmp(arg[argsdone+1], "on")) {
nowait_flag = 1;
} else {
nowait_flag = 0;
}
} else if (0 == strcmp(arg[argsdone], "fscale")) {
imd_fscale = force->numeric(FLERR,arg[argsdone+1]);
} else if (0 == strcmp(arg[argsdone], "trate")) {
imd_trate = force->inumeric(FLERR,arg[argsdone+1]);
} else {
error->all(FLERR,"Unknown fix imd parameter");
}
++argsdone; ++argsdone;
}
if (imd_trate < 1)
error->all(FLERR,"Illegal fix imd parameter. trate < 1.");
bigint n = group->count(igroup);
if (n > MAXSMALLINT) error->all(FLERR,"Too many atoms for fix imd");
num_coords = static_cast<int> (n);
MPI_Comm_rank(world,&me);
clientsock = NULL;
localsock = NULL;
nlevels_respa = 0;
imd_inactive = 0;
imd_terminate = 0;
imd_forces = 0;
force_buf = NULL;
maxbuf = 0;
msgdata = NULL;
msglen = 0;
comm_buf = NULL;
idmap = NULL;
rev_idmap = NULL;
if (me == 0) {
imdsock_init();
localsock = imdsock_create();
clientsock = NULL;
if (imdsock_bind(localsock,imd_port)) {
perror("bind to socket failed");
imdsock_destroy(localsock);
imd_terminate = 1;
} else {
imdsock_listen(localsock);
}
}
MPI_Bcast(&imd_terminate, 1, MPI_INT, 0, world);
if (imd_terminate)
error->all(FLERR,"LAMMPS Terminated on error in IMD.");
size_one = sizeof(struct commdata);
#if defined(LAMMPS_ASYNC_IMD)
if (me == 0) {
if (screen)
fputs("Using fix imd with asynchronous I/O.\n",screen);
if (logfile)
fputs("Using fix imd with asynchronous I/O.\n",logfile);
pthread_mutex_init(&read_mutex, NULL);
pthread_mutex_init(&write_mutex, NULL);
pthread_cond_init(&write_cond, NULL);
pthread_mutex_lock(&write_mutex);
buf_has_data=0;
pthread_mutex_unlock(&write_mutex);
pthread_attr_init(&iot_attr);
pthread_attr_setdetachstate(&iot_attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&iothread, &iot_attr, &fix_imd_ioworker, this);
}
#endif
}
FixIMD::~FixIMD()
{
#if defined(LAMMPS_ASYNC_IMD)
if (me == 0) {
pthread_mutex_lock(&write_mutex);
buf_has_data=-1;
pthread_cond_signal(&write_cond);
pthread_mutex_unlock(&write_mutex);
pthread_join(iothread, NULL);
pthread_attr_destroy(&iot_attr);
pthread_mutex_destroy(&write_mutex);
pthread_cond_destroy(&write_cond);
}
#endif
taginthash_t *hashtable = (taginthash_t *)idmap;
memory->destroy(comm_buf);
memory->destroy(force_buf);
taginthash_destroy(hashtable);
delete hashtable;
free(rev_idmap);
imdsock_shutdown(clientsock);
imdsock_destroy(clientsock);
imdsock_shutdown(localsock);
imdsock_destroy(localsock);
clientsock=NULL;
localsock=NULL;
return;
}
int FixIMD::setmask()
{
int mask = 0;
mask |= POST_FORCE;
mask |= POST_FORCE_RESPA;
return mask;
}
void FixIMD::init()
{
if (strstr(update->integrate_style,"respa"))
nlevels_respa = ((Respa *) update->integrate)->nlevels;
return;
}
int FixIMD::reconnect()
{
imd_inactive = 0;
imd_terminate = 0;
if (me == 0) {
if (clientsock) return 1;
if (screen && connect_msg) {
if (nowait_flag) {
fprintf(screen,"Listening for IMD connection on port %d. Transfer rate %d.\n",imd_port, imd_trate);
} else {
fprintf(screen,"Waiting for IMD connection on port %d. Transfer rate %d.\n",imd_port, imd_trate);
}
}
connect_msg = 0;
clientsock = NULL;
if (nowait_flag) {
int retval = imdsock_selread(localsock,0);
if (retval > 0) {
clientsock = imdsock_accept(localsock);
} else {
imd_inactive = 1;
return 0;
}
} else {
int retval=0;
do {
retval = imdsock_selread(localsock, 60);
} while (retval <= 0);
clientsock = imdsock_accept(localsock);
}
if (!imd_inactive && !clientsock) {
if (screen)
fprintf(screen, "IMD socket accept error. Dropping connection.\n");
imd_terminate = 1;
return 0;
} else {
if (imd_handshake(clientsock)) {
if (screen)
fprintf(screen, "IMD handshake error. Dropping connection.\n");
imdsock_destroy(clientsock);
imd_terminate = 1;
return 0;
} else {
int32 length;
if (imdsock_selread(clientsock, 1) != 1 ||
imd_recv_header(clientsock, &length) != IMD_GO) {
if (screen)
fprintf(screen, "Incompatible IMD client version? Dropping connection.\n");
imdsock_destroy(clientsock);
imd_terminate = 1;
return 0;
} else {
return 1;
}
}
}
}
return 0;
}
void FixIMD::setup(int)
{
int i,j;
int nmax,nme,nlocal;
int *mask = atom->mask;
tagint *tag = atom->tag;
nlocal = atom->nlocal;
nme=0;
for (i=0; i < nlocal; ++i)
if (mask[i] & groupbit) ++nme;
MPI_Allreduce(&nme,&nmax,1,MPI_INT,MPI_MAX,world);
memory->destroy(comm_buf);
maxbuf = nmax*size_one;
comm_buf = (void *) memory->smalloc(maxbuf,"imd:comm_buf");
connect_msg = 1;
reconnect();
MPI_Bcast(&imd_inactive, 1, MPI_INT, 0, world);
MPI_Bcast(&imd_terminate, 1, MPI_INT, 0, world);
if (imd_terminate)
error->all(FLERR,"LAMMPS terminated on error in setting up IMD connection.");
taginthash_t *hashtable=new taginthash_t;
taginthash_init(hashtable, num_coords);
idmap = (void *)hashtable;
int tmp, ndata;
struct commdata *buf = static_cast<struct commdata *>(comm_buf);
if (me == 0) {
MPI_Status status;
MPI_Request request;
tagint *taglist = new tagint[num_coords];
int numtag=0;
for (i=0; i < nlocal; ++i) {
if (mask[i] & groupbit) {
taglist[numtag] = tag[i];
++numtag;
}
}
for (i=1; i < comm->nprocs; ++i) {
MPI_Irecv(comm_buf, maxbuf, MPI_BYTE, i, 0, world, &request);
MPI_Send(&tmp, 0, MPI_INT, i, 0, world);
MPI_Wait(&request, &status);
MPI_Get_count(&status, MPI_BYTE, &ndata);
ndata /= size_one;
for (j=0; j < ndata; ++j) {
taglist[numtag] = buf[j].tag;
++numtag;
}
}
id_sort(taglist, 0, num_coords-1);
for (i=0; i < num_coords; ++i) {
taginthash_insert(hashtable, taglist[i], i);
}
delete[] taglist;
rev_idmap=taginthash_keys(hashtable);
} else {
nme=0;
for (i=0; i < nlocal; ++i) {
if (mask[i] & groupbit) {
buf[nme].tag = tag[i];
++nme;
}
}
MPI_Recv(&tmp, 0, MPI_INT, 0, 0, world, MPI_STATUS_IGNORE);
MPI_Rsend(comm_buf, nme*size_one, MPI_BYTE, 0, 0, world);
}
return;
}
#if defined(LAMMPS_ASYNC_IMD)
void *fix_imd_ioworker(void *t)
{
FixIMD *imd=(FixIMD *)t;
imd->ioworker();
return NULL;
}
void FixIMD::ioworker()
{
while (1) {
pthread_mutex_lock(&write_mutex);
if (buf_has_data < 0) {
fprintf(screen,"Asynchronous I/O thread is exiting.\n");
buf_has_data=0;
pthread_mutex_unlock(&write_mutex);
pthread_exit(NULL);
} else if (buf_has_data > 0) {
if (clientsock && imdsock_selwrite(clientsock,0)) {
imd_writen(clientsock, msgdata, msglen);
}
delete[] msgdata;
buf_has_data=0;
pthread_mutex_unlock(&write_mutex);
} else {
pthread_cond_wait(&write_cond, &write_mutex);
pthread_mutex_unlock(&write_mutex);
}
}
}
#endif
void FixIMD::post_force(int )
{
if (imd_inactive) {
reconnect();
MPI_Bcast(&imd_inactive, 1, MPI_INT, 0, world);
MPI_Bcast(&imd_terminate, 1, MPI_INT, 0, world);
if (imd_terminate)
error->all(FLERR,"LAMMPS terminated on error in setting up IMD connection.");
if (imd_inactive)
return;
}
tagint *tag = atom->tag;
double **x = atom->x;
imageint *image = atom->image;
int nlocal = atom->nlocal;
int *mask = atom->mask;
struct commdata *buf;
if (me == 0) {
int imd_paused=0;
while ((imdsock_selread(clientsock, 0) > 0) || imd_paused) {
if (imd_inactive) break;
int32 length;
int msg = imd_recv_header(clientsock, &length);
switch(msg) {
case IMD_GO:
if (screen)
fprintf(screen, "Ignoring unexpected IMD_GO message.\n");
break;
case IMD_IOERROR:
if (screen)
fprintf(screen, "IMD connection lost.\n");
case IMD_DISCONNECT: {
imd_paused = 0;
imd_forces = 0;
memory->destroy(force_buf);
force_buf = NULL;
imdsock_destroy(clientsock);
clientsock = NULL;
if (screen)
fprintf(screen, "IMD client detached. LAMMPS run continues.\n");
connect_msg = 1;
reconnect();
if (imd_terminate) imd_inactive = 1;
break;
}
case IMD_KILL:
if (screen)
fprintf(screen, "IMD client requested termination of run.\n");
imd_inactive = 1;
imd_terminate = 1;
imd_paused = 0;
imdsock_destroy(clientsock);
clientsock = NULL;
break;
case IMD_PAUSE:
if (imd_paused) {
if (screen)
fprintf(screen, "Continuing run on IMD client request.\n");
imd_paused = 0;
} else {
if (screen)
fprintf(screen, "Pausing run on IMD client request.\n");
imd_paused = 1;
}
break;
case IMD_TRATE:
if (length > 0)
imd_trate = length;
if (screen)
fprintf(screen, "IMD client requested change of transfer rate. Now it is %d.\n", imd_trate);
break;
case IMD_ENERGIES: {
IMDEnergies dummy_energies;
imd_recv_energies(clientsock, &dummy_energies);
break;
}
case IMD_FCOORDS: {
float *dummy_coords = new float[3*length];
imd_recv_fcoords(clientsock, length, dummy_coords);
delete[] dummy_coords;
break;
}
case IMD_MDCOMM: {
int32 *imd_tags = new int32[length];
float *imd_fdat = new float[3*length];
imd_recv_mdcomm(clientsock, length, imd_tags, imd_fdat);
if (imd_forces < length) {
memory->destroy(force_buf);
force_buf = (void *) memory->smalloc(length*size_one,
"imd:force_buf");
}
imd_forces = length;
buf = static_cast<struct commdata *>(force_buf);
for (int ii=0; ii < length; ++ii) {
buf[ii].tag = rev_idmap[imd_tags[ii]];
buf[ii].x = imd_fdat[3*ii];
buf[ii].y = imd_fdat[3*ii+1];
buf[ii].z = imd_fdat[3*ii+2];
}
delete[] imd_tags;
delete[] imd_fdat;
break;
}
default:
if (screen)
fprintf(screen, "Unhandled incoming IMD message #%d. length=%d\n", msg, length);
break;
}
}
}
int old_imd_forces = imd_forces;
MPI_Bcast(&imd_trate, 1, MPI_INT, 0, world);
MPI_Bcast(&imd_inactive, 1, MPI_INT, 0, world);
MPI_Bcast(&imd_forces, 1, MPI_INT, 0, world);
MPI_Bcast(&imd_terminate, 1, MPI_INT, 0, world);
if (imd_terminate)
error->all(FLERR,"LAMMPS terminated on IMD request.");
if (imd_forces > 0) {
if (me != 0) {
if (old_imd_forces < imd_forces) {
if (force_buf != NULL)
memory->sfree(force_buf);
force_buf = memory->smalloc(imd_forces*size_one, "imd:force_buf");
}
}
MPI_Bcast(force_buf, imd_forces*size_one, MPI_BYTE, 0, world);
}
if (update->ntimestep % imd_trate) {
if (imd_forces > 0) {
double **f = atom->f;
buf = static_cast<struct commdata *>(force_buf);
for (int j=0; j < imd_forces; ++j) {
for (int i=0; i < nlocal; ++i) {
if (mask[i] & groupbit) {
if (buf[j].tag == tag[i]) {
f[i][0] += imd_fscale*buf[j].x;
f[i][1] += imd_fscale*buf[j].y;
f[i][2] += imd_fscale*buf[j].z;
}
}
}
}
}
return;
}
int i, k, nmax, nme=0;
for (i=0; i < nlocal; ++i)
if (mask[i] & groupbit) ++nme;
MPI_Allreduce(&nme,&nmax,1,MPI_INT,MPI_MAX,world);
if (nmax*size_one > maxbuf) {
memory->destroy(comm_buf);
maxbuf = nmax*size_one;
comm_buf = memory->smalloc(maxbuf,"imd:comm_buf");
}
int tmp, ndata;
buf = static_cast<struct commdata *>(comm_buf);
if (me == 0) {
MPI_Status status;
MPI_Request request;
msglen = 3*sizeof(float)*num_coords+IMDHEADERSIZE;
msgdata = new char[msglen];
imd_fill_header((IMDheader *)msgdata, IMD_FCOORDS, num_coords);
float *recvcoord = (float *) (msgdata+IMDHEADERSIZE);
if (unwrap_flag) {
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
double xy = domain->xy;
double xz = domain->xz;
double yz = domain->yz;
for (i=0; i<nlocal; ++i) {
if (mask[i] & groupbit) {
const tagint j = 3*taginthash_lookup((taginthash_t *)idmap, tag[i]);
if (j != 3*HASH_FAIL) {
int ix = (image[i] & IMGMASK) - IMGMAX;
int iy = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
int iz = (image[i] >> IMG2BITS) - IMGMAX;
if (domain->triclinic) {
recvcoord[j] = x[i][0] + ix * xprd + iy * xy + iz * xz;
recvcoord[j+1] = x[i][1] + iy * yprd + iz * yz;
recvcoord[j+2] = x[i][2] + iz * zprd;
} else {
recvcoord[j] = x[i][0] + ix * xprd;
recvcoord[j+1] = x[i][1] + iy * yprd;
recvcoord[j+2] = x[i][2] + iz * zprd;
}
}
}
}
} else {
for (i=0; i<nlocal; ++i) {
if (mask[i] & groupbit) {
const tagint j = 3*taginthash_lookup((taginthash_t *)idmap, tag[i]);
if (j != 3*HASH_FAIL) {
recvcoord[j] = x[i][0];
recvcoord[j+1] = x[i][1];
recvcoord[j+2] = x[i][2];
}
}
}
}
for (i=1; i < comm->nprocs; ++i) {
MPI_Irecv(comm_buf, maxbuf, MPI_BYTE, i, 0, world, &request);
MPI_Send(&tmp, 0, MPI_INT, i, 0, world);
MPI_Wait(&request, &status);
MPI_Get_count(&status, MPI_BYTE, &ndata);
ndata /= size_one;
for (k=0; k<ndata; ++k) {
const tagint j = 3*taginthash_lookup((taginthash_t *)idmap, buf[k].tag);
if (j != 3*HASH_FAIL) {
recvcoord[j] = buf[k].x;
recvcoord[j+1] = buf[k].y;
recvcoord[j+2] = buf[k].z;
}
}
}
#if defined(LAMMPS_ASYNC_IMD)
buf_has_data=1;
pthread_cond_signal(&write_cond);
pthread_mutex_unlock(&write_mutex);
#else
if (clientsock && imdsock_selwrite(clientsock,0)) {
imd_writen(clientsock, msgdata, msglen);
}
delete[] msgdata;
#endif
} else {
nme = 0;
if (unwrap_flag) {
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
double xy = domain->xy;
double xz = domain->xz;
double yz = domain->yz;
for (i=0; i<nlocal; ++i) {
if (mask[i] & groupbit) {
int ix = (image[i] & IMGMASK) - IMGMAX;
int iy = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
int iz = (image[i] >> IMG2BITS) - IMGMAX;
if (domain->triclinic) {
buf[nme].tag = tag[i];
buf[nme].x = x[i][0] + ix * xprd + iy * xy + iz * xz;
buf[nme].y = x[i][1] + iy * yprd + iz * yz;
buf[nme].z = x[i][2] + iz * zprd;
} else {
buf[nme].tag = tag[i];
buf[nme].x = x[i][0] + ix * xprd;
buf[nme].y = x[i][1] + iy * yprd;
buf[nme].z = x[i][2] + iz * zprd;
}
++nme;
}
}
} else {
for (i=0; i<nlocal; ++i) {
if (mask[i] & groupbit) {
buf[nme].tag = tag[i];
buf[nme].x = x[i][0];
buf[nme].y = x[i][1];
buf[nme].z = x[i][2];
++nme;
}
}
}
MPI_Recv(&tmp, 0, MPI_INT, 0, 0, world, MPI_STATUS_IGNORE);
MPI_Rsend(comm_buf, nme*size_one, MPI_BYTE, 0, 0, world);
}
return;
}
void FixIMD::post_force_respa(int vflag, int ilevel, int )
{
if (ilevel == nlevels_respa-1) post_force(vflag);
return;
}
double FixIMD::memory_usage(void)
{
return static_cast<double>(num_coords+maxbuf+imd_forces)*size_one;
}
int imdsock_init(void) {
#if defined(_MSC_VER) || defined(__MINGW32__)
int rc = 0;
static int initialized=0;
if (!initialized) {
WSADATA wsdata;
rc = WSAStartup(MAKEWORD(1,1), &wsdata);
if (rc == 0)
initialized = 1;
}
return rc;
#else
return 0;
#endif
}
void * imdsock_create(void) {
imdsocket * s;
s = (imdsocket *) malloc(sizeof(imdsocket));
if (s != NULL)
memset(s, 0, sizeof(imdsocket));
else return NULL;
if ((s->sd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
printf("Failed to open socket.");
free(s);
return NULL;
}
return (void *) s;
}
int imdsock_bind(void * v, int port) {
imdsocket *s = (imdsocket *) v;
memset(&(s->addr), 0, sizeof(s->addr));
s->addr.sin_family = PF_INET;
s->addr.sin_port = htons(port);
return bind(s->sd, (struct sockaddr *) &s->addr, sizeof(s->addr));
}
int imdsock_listen(void * v) {
imdsocket *s = (imdsocket *) v;
return listen(s->sd, 5);
}
void *imdsock_accept(void * v) {
int rc;
imdsocket *new_s = NULL, *s = (imdsocket *) v;
#if defined(ARCH_AIX5) || defined(ARCH_AIX5_64) || defined(ARCH_AIX6_64)
unsigned int len;
#define _SOCKLEN_TYPE unsigned int
#elif defined(SOCKLEN_T)
SOCKLEN_T len;
#define _SOCKLEN_TYPE SOCKLEN_T
#elif defined(_POSIX_SOURCE) || (defined(__APPLE__) && defined(__MACH__)) || defined(__linux)
socklen_t len;
#define _SOCKLEN_TYPE socklen_t
#else
#define _SOCKLEN_TYPE int
int len;
#endif
len = sizeof(s->addr);
rc = accept(s->sd, (struct sockaddr *) &s->addr, ( _SOCKLEN_TYPE * ) &len);
if (rc >= 0) {
new_s = (imdsocket *) malloc(sizeof(imdsocket));
if (new_s != NULL) {
*new_s = *s;
new_s->sd = rc;
}
}
return (void *)new_s;
}
int imdsock_write(void * v, const void *buf, int len) {
imdsocket *s = (imdsocket *) v;
#if defined(_MSC_VER) || defined(__MINGW32__)
return send(s->sd, (const char*) buf, len, 0);
#else
return write(s->sd, buf, len);
#endif
}
int imdsock_read(void * v, void *buf, int len) {
imdsocket *s = (imdsocket *) v;
#if defined(_MSC_VER) || defined(__MINGW32__)
return recv(s->sd, (char*) buf, len, 0);
#else
return read(s->sd, buf, len);
#endif
}
void imdsock_shutdown(void *v) {
imdsocket * s = (imdsocket *) v;
if (s == NULL)
return;
#if defined(_MSC_VER) || defined(__MINGW32__)
shutdown(s->sd, SD_SEND);
#else
shutdown(s->sd, 1);
#endif
}
void imdsock_destroy(void * v) {
imdsocket * s = (imdsocket *) v;
if (s == NULL)
return;
#if defined(_MSC_VER) || defined(__MINGW32__)
closesocket(s->sd);
#else
close(s->sd);
#endif
free(s);
}
int imdsock_selread(void *v, int sec) {
imdsocket *s = (imdsocket *)v;
fd_set rfd;
struct timeval tv;
int rc;
if (v == NULL) return 0;
FD_ZERO(&rfd);
FD_SET(s->sd, &rfd);
memset((void *)&tv, 0, sizeof(struct timeval));
tv.tv_sec = sec;
do {
rc = select(s->sd+1, &rfd, NULL, NULL, &tv);
} while (rc < 0 && errno == EINTR);
return rc;
}
int imdsock_selwrite(void *v, int sec) {
imdsocket *s = (imdsocket *)v;
fd_set wfd;
struct timeval tv;
int rc;
if (v == NULL) return 0;
FD_ZERO(&wfd);
FD_SET(s->sd, &wfd);
memset((void *)&tv, 0, sizeof(struct timeval));
tv.tv_sec = sec;
do {
rc = select(s->sd + 1, NULL, &wfd, NULL, &tv);
} while (rc < 0 && errno == EINTR);
return rc;
}
typedef union {
int32 i;
struct {
unsigned int highest : 8;
unsigned int high : 8;
unsigned int low : 8;
unsigned int lowest : 8;
} b;
} netint;
static int32 imd_htonl(int32 h) {
netint n;
n.b.highest = h >> 24;
n.b.high = h >> 16;
n.b.low = h >> 8;
n.b.lowest = h;
return n.i;
}
static int32 imd_ntohl(int32 n) {
netint u;
u.i = n;
return (u.b.highest << 24 | u.b.high << 16 | u.b.low << 8 | u.b.lowest);
}
static void imd_fill_header(IMDheader *header, IMDType type, int32 length) {
header->type = imd_htonl((int32)type);
header->length = imd_htonl(length);
}
static void swap_header(IMDheader *header) {
header->type = imd_ntohl(header->type);
header->length= imd_ntohl(header->length);
}
static int32 imd_readn(void *s, char *ptr, int32 n) {
int32 nleft;
int32 nread;
nleft = n;
while (nleft > 0) {
if ((nread = imdsock_read(s, ptr, nleft)) < 0) {
if (errno == EINTR)
nread = 0;
else
return -1;
} else if (nread == 0)
break;
nleft -= nread;
ptr += nread;
}
return n-nleft;
}
static int32 imd_writen(void *s, const char *ptr, int32 n) {
int32 nleft;
int32 nwritten;
nleft = n;
while (nleft > 0) {
if ((nwritten = imdsock_write(s, ptr, nleft)) <= 0) {
if (errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
ptr += nwritten;
}
return n;
}
int imd_handshake(void *s) {
IMDheader header;
imd_fill_header(&header, IMD_HANDSHAKE, 1);
header.length = IMDVERSION;
return (imd_writen(s, (char *)&header, IMDHEADERSIZE) != IMDHEADERSIZE);
}
IMDType imd_recv_header(void *s, int32 *length) {
IMDheader header;
if (imd_readn(s, (char *)&header, IMDHEADERSIZE) != IMDHEADERSIZE)
return IMD_IOERROR;
swap_header(&header);
*length = header.length;
return IMDType(header.type);
}
int imd_recv_mdcomm(void *s, int32 n, int32 *indices, float *forces) {
if (imd_readn(s, (char *)indices, 4*n) != 4*n) return 1;
if (imd_readn(s, (char *)forces, 12*n) != 12*n) return 1;
return 0;
}
int imd_recv_energies(void *s, IMDEnergies *energies) {
return (imd_readn(s, (char *)energies, sizeof(IMDEnergies))
!= sizeof(IMDEnergies));
}
int imd_recv_fcoords(void *s, int32 n, float *coords) {
return (imd_readn(s, (char *)coords, 12*n) != 12*n);
}