00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 #include "largefiles.h"
00064
00065 #include <stdio.h>
00066 #include <stdlib.h>
00067 #include <string.h>
00068 #include <ctype.h>
00069 #include <math.h>
00070 #include "molfile_plugin.h"
00071
00072 #include "periodic_table.h"
00073
00074 #define THISPLUGIN plugin
00075 #include "vmdconio.h"
00076
00077 #define VMDPLUGIN_STATIC
00078 #include "hash.h"
00079 #include "inthash.h"
00080
00081 #ifndef LAMMPS_DEBUG
00082 #define LAMMPS_DEBUG 0
00083 #endif
00084
00085 #ifndef M_PI_2
00086 #define M_PI_2 1.57079632679489661922
00087 #endif
00088
00089 #ifndef MIN
00090 #define MIN(A,B) ((A) < (B) ? (A) : (B))
00091 #endif
00092 #ifndef MAX
00093 #define MAX(A,B) ((A) > (B) ? (A) : (B))
00094 #endif
00095
00096
00097 #define SMALL 1.0e-12f
00098
00099
00100 #define LINE_LEN 1024
00101
00102
00103 #define KEY_ATOMS "NUMBER OF ATOMS"
00104 #define KEY_BOX "BOX BOUNDS"
00105 #define KEY_DATA "ATOMS"
00106 #define KEY_TSTEP "TIMESTEP"
00107 #define KEY_TIME "TIME"
00108
00109
00110 #define LAMMPS_COORD_NONE 0x000U
00111 #define LAMMPS_COORD_WRAPPED 0x001U
00112 #define LAMMPS_COORD_SCALED 0x002U
00113 #define LAMMPS_COORD_IMAGES 0x004U
00114 #define LAMMPS_COORD_UNWRAPPED 0x008U
00115 #define LAMMPS_COORD_UNKNOWN 0x010U
00116 #define LAMMPS_COORD_VELOCITIES 0x020U
00117 #define LAMMPS_COORD_FORCES 0x040U
00118 #define LAMMPS_COORD_DIPOLE 0x080U
00119 #define LAMMPS_COORD_TRICLINIC 0x100U
00120
00122 #define LAMMPS_MAX_NUM_FIELDS 64
00123 enum lammps_attribute {
00124 LAMMPS_FIELD_UNKNOWN=0,
00125 LAMMPS_FIELD_ATOMID, LAMMPS_FIELD_MOLID, LAMMPS_FIELD_TYPE,
00126 LAMMPS_FIELD_POSX, LAMMPS_FIELD_POSY, LAMMPS_FIELD_POSZ,
00127 LAMMPS_FIELD_POSXS, LAMMPS_FIELD_POSYS, LAMMPS_FIELD_POSZS,
00128 LAMMPS_FIELD_POSXU, LAMMPS_FIELD_POSYU, LAMMPS_FIELD_POSZU,
00129 LAMMPS_FIELD_POSXSU, LAMMPS_FIELD_POSYSU, LAMMPS_FIELD_POSZSU,
00130 LAMMPS_FIELD_IMGX, LAMMPS_FIELD_IMGY, LAMMPS_FIELD_IMGZ,
00131 LAMMPS_FIELD_VELX, LAMMPS_FIELD_VELY, LAMMPS_FIELD_VELZ,
00132 LAMMPS_FIELD_FORX, LAMMPS_FIELD_FORY, LAMMPS_FIELD_FORZ,
00133 LAMMPS_FIELD_CHARGE, LAMMPS_FIELD_RADIUS, LAMMPS_FIELD_DIAMETER,
00134 LAMMPS_FIELD_ELEMENT,LAMMPS_FIELD_MASS, LAMMPS_FIELD_QUATW,
00135 LAMMPS_FIELD_QUATI, LAMMPS_FIELD_QUATJ, LAMMPS_FIELD_QUATK,
00136 LAMMPS_FIELD_MUX, LAMMPS_FIELD_MUY, LAMMPS_FIELD_MUZ,
00137 LAMMPS_FIELD_USER0, LAMMPS_FIELD_USER1, LAMMPS_FIELD_USER2,
00138 LAMMPS_FIELD_USER3, LAMMPS_FIELD_USER4, LAMMPS_FIELD_USER5,
00139 LAMMPS_FIELD_USER6, LAMMPS_FIELD_USER7, LAMMPS_FIELD_USER8,
00140 LAMMPS_FILED_USER9
00141 };
00142
00143 typedef enum lammps_attribute l_attr_t;
00144
00145
00146 #ifdef _USE_ZLIB
00147 #include <zlib.h>
00148 #define FileDesc gzFile
00149 #define myFgets(buf,size,fd) gzgets(fd,buf,size)
00150 #define myFprintf gzprintf
00151 #define myFopen gzopen
00152 #define myFclose gzclose
00153 #define myRewind gzrewind
00154 #else
00155 #define FileDesc FILE*
00156 #define myFprintf fprintf
00157 #define myFopen fopen
00158 #define myFclose fclose
00159 #define myFgets(buf,size,fd) fgets(buf,size,fd)
00160 #define myRewind rewind
00161 #endif
00162
00163 typedef struct {
00164 FileDesc file;
00165 FILE *fp;
00166 char *file_name;
00167 int *atomtypes;
00168 int numatoms;
00169 int maxatoms;
00170 int nstep;
00171 unsigned int coord_data;
00172 float time;
00173 float dip2atoms;
00174 float dumx,dumy,dumz;
00175 int numfields;
00176 l_attr_t field[LAMMPS_MAX_NUM_FIELDS];
00177 inthash_t *idmap;
00178 int fieldinit;
00179 #if vmdplugin_ABIVERSION > 10
00180 molfile_timestep_metadata_t ts_meta;
00181 #endif
00182 } lammpsdata;
00183
00184 static int velinfo = 1;
00185
00186
00187 static void id_merge(int *output, int *left, int nl, int *right, int nr)
00188 {
00189 int i,l,r;
00190 i = l = r = 0;
00191 while ((l < nl) && (r < nr)) {
00192 if (left[l] < right[r])
00193 output[i++] = left[l++];
00194 else
00195 output[i++] = right[r++];
00196 }
00197 while (l < nl)
00198 output[i++] = left[l++];
00199 while (r < nr)
00200 output[i++] = right[r++];
00201 }
00202
00203
00204 static void id_sort(int *idmap, int num)
00205 {
00206 int *hold;
00207 int i,j,k;
00208
00209 hold = (int *)malloc(num*sizeof(int));
00210 if (hold == NULL) return;
00211
00212 for (i=1; i < num; i *=2) {
00213 memcpy(hold,idmap,num*sizeof(int));
00214 for (j=0; j < (num - i); j += 2*i) {
00215 k =(j+2*i > num) ? num-j-i : i;
00216 id_merge(idmap+j, hold+j, i, hold+j+i, k);
00217 }
00218 }
00219 free((void *)hold);
00220 }
00221
00228 static const char *remap_field(const char *tag, const char *list)
00229 {
00230 int i, pos, len, flag;
00231 const char *ptr;
00232 static char to[32], from[32];
00233
00234
00235 if ((!tag) || (!list))
00236 return tag;
00237
00238 ptr=list;
00239 i=pos=flag=0;
00240 len=strlen(list);
00241
00242
00243 while (pos < len) {
00244
00245 if (flag) {
00246 if (ptr[pos] == ',') {
00247 from[i] = '\0';
00248 if (0 == strcmp(tag,from)) {
00249
00250 if (strlen(to))
00251 return to;
00252
00253 flag=0;
00254 i=0;
00255 } else {
00256
00257 flag=0;
00258 i=0;
00259 }
00260 } else {
00261 from[i]=ptr[pos];
00262 if (i<30)
00263 ++i;
00264 }
00265 } else {
00266
00267 if (ptr[pos] == '=') {
00268 to[i] = '\0';
00269 flag=1;
00270 i=0;
00271 } else if (ptr[pos] == ',') {
00272 i=0;
00273 flag=0;
00274 } else {
00275 to[i]=ptr[pos];
00276 if (i<30)
00277 ++i;
00278 }
00279 }
00280 ++pos;
00281 }
00282
00283
00284 if (flag) {
00285 from[i] = '\0';
00286 if (0 == strcmp(tag,from)) {
00287
00288 if (strlen(to))
00289 return to;
00290 }
00291 }
00292
00293 return tag;
00294 }
00295
00301 static char* find_next_item(FileDesc fd, char* linebuf, int buflen) {
00302 char* ptr;
00303
00304 while(myFgets(linebuf, buflen, fd)) {
00305
00306
00307 ptr = linebuf;
00308 while (ptr && (*ptr == ' ' || *ptr == '\t'))
00309 ++ptr;
00310
00311
00312 if(0 == strncmp(ptr, "ITEM:", 5)) {
00313 ptr += 5;
00314 return ptr;
00315 }
00316 }
00317
00318 return NULL;
00319 }
00320
00329 static char *find_item_keyword(FileDesc fd, const char* keyword,
00330 char *linebuf, int buflen) {
00331 char *ptr;
00332 int len;
00333
00334 while(1) {
00335 ptr = find_next_item(fd, linebuf, buflen);
00336
00337 if (ptr == NULL)
00338 break;
00339
00340 while (ptr && (*ptr == ' ' || *ptr == '\t'))
00341 ++ptr;
00342
00343 #if LAMMPS_DEBUG
00344 fprintf(stderr, "text=%s/%s", keyword, ptr);
00345 #endif
00346 len = strlen(keyword);
00347 if (0 == strncmp(ptr, keyword, len) ) {
00348 ptr += len;
00349 if (*ptr == '\0' || *ptr == ' ' || *ptr == '\n' || *ptr == '\r') {
00350 #if LAMMPS_DEBUG
00351 fprintf(stderr, "return='%s'", ptr);
00352 #endif
00353 return ptr;
00354 } else continue;
00355 }
00356 }
00357 #if LAMMPS_DEBUG
00358 fprintf(stderr, "return='NULL'\n");
00359 #endif
00360 return NULL;
00361 }
00362
00363 static void *open_lammps_read(const char *filename, const char *filetype, int *natoms) {
00364 FileDesc fd;
00365 lammpsdata *data;
00366 char buffer[LINE_LEN];
00367 char *ptr;
00368 const char *envvar;
00369 long tmp, maxatoms;
00370
00371 fd = myFopen(filename, "rb");
00372 if (!fd) return NULL;
00373
00374 data = (lammpsdata *)calloc(1, sizeof(lammpsdata));
00375 data->file = fd;
00376 data->file_name = strdup(filename);
00377 data->dip2atoms = -1.0f;
00378 data->fieldinit = 0;
00379 velinfo = 1;
00380
00381 *natoms = 0;
00382 maxatoms = 0;
00383
00384 ptr = find_item_keyword(data->file, KEY_ATOMS, buffer, LINE_LEN);
00385 if (ptr == NULL) {
00386 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Unable to find '%s' item.\n",
00387 KEY_ATOMS);
00388 return NULL;
00389 }
00390
00391 if (!myFgets(buffer, LINE_LEN, data->file)) {
00392 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) dump file '%s' should "
00393 "have the number of atoms after line ITEM: %s\n",
00394 filename, KEY_ATOMS);
00395 return NULL;
00396 }
00397
00398 tmp = atol(buffer);
00399
00400 if (tmp > 0x7FFFFFFF) {
00401 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) dump file '%s' contains "
00402 "%ld atoms which is more than what this plugin supports.\n",
00403 filename, tmp);
00404 return NULL;
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 envvar=getenv("LAMMPSMAXATOMS");
00417 if (envvar) maxatoms = atol(envvar);
00418 data->dumx = data->dumy = data->dumz = 0.0f;
00419 envvar=getenv("LAMMPSDUMMYPOS");
00420 if (envvar) sscanf(envvar,"%f%f%f", &(data->dumx),
00421 &(data->dumy), &(data->dumz));
00422
00423 if (maxatoms > tmp) {
00424 vmdcon_printf(VMDCON_INFO, "lammpsplugin) provisioning space for up to "
00425 "%ld atoms.\n", maxatoms);
00426 } else maxatoms = tmp;
00427 *natoms = maxatoms;
00428
00429
00430
00431
00432
00433 envvar=getenv("LAMMPSDIPOLE2ATOMS");
00434 if (envvar) {
00435 data->dip2atoms = (float) strtod(envvar,NULL);
00436 maxatoms *= 2;
00437 tmp *=2;
00438 }
00439 *natoms = maxatoms;
00440
00441 data->maxatoms = maxatoms;
00442 data->numatoms = tmp;
00443 data->coord_data = LAMMPS_COORD_NONE;
00444 myRewind(data->file);
00445
00446 return data;
00447 }
00448
00449
00450 static int read_lammps_structure(void *mydata, int *optflags,
00451 molfile_atom_t *atoms) {
00452 int i, j;
00453 char buffer[LINE_LEN];
00454 lammpsdata *data = (lammpsdata *)mydata;
00455 int atomid, atomtype, needhash;
00456 float x, y, z;
00457 char *fieldlist;
00458 molfile_atom_t thisatom;
00459 const char *k;
00460 int *idlist=NULL;
00461
00462
00463 *optflags = MOLFILE_NOOPTIONS;
00464 data->coord_data = LAMMPS_COORD_NONE;
00465 memset(atoms, 0, data->numatoms * sizeof(molfile_atom_t));
00466
00467
00468 strcpy(thisatom.name,"@");
00469 strcpy(thisatom.type,"X");
00470 strcpy(thisatom.resname,"@@@");
00471 strcpy(thisatom.segid,"@@@");
00472 strcpy(thisatom.chain,"@");
00473 thisatom.resid = -1;
00474 thisatom.occupancy = -1.0;
00475 thisatom.bfactor = -1.0;
00476 thisatom.mass = 0.0;
00477 thisatom.charge = 0.0;
00478 thisatom.radius = 0.0;
00479 thisatom.atomicnumber = 0;
00480 for (i=data->numatoms; i < data->maxatoms; ++i)
00481 memcpy(atoms+i, &thisatom, sizeof(molfile_atom_t));
00482
00483 #if vmdplugin_ABIVERSION > 10
00484 data->ts_meta.count = -1;
00485 data->ts_meta.has_velocities = 0;
00486 #endif
00487
00488
00489 myRewind(data->file);
00490
00491
00492 fieldlist = find_item_keyword(data->file, KEY_BOX, buffer, LINE_LEN);
00493 if (fieldlist == NULL) {
00494 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Could not find box boundaries in timestep.\n");
00495 return MOLFILE_ERROR;
00496 }
00497 k = myFgets(buffer, LINE_LEN, data->file);
00498 if (k == NULL) {
00499 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Could not find box boundaries in timestep.\n");
00500 return MOLFILE_ERROR;
00501 }
00502
00503 j = sscanf(buffer, "%f%f%f", &x, &y, &z);
00504 if (j == 3) {
00505 data->coord_data |= LAMMPS_COORD_TRICLINIC;
00506 } else if (j < 2) {
00507 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Could not find box boundaries in timestep.\n");
00508 return MOLFILE_ERROR;
00509 }
00510
00511
00512 fieldlist = find_item_keyword(data->file, KEY_DATA, buffer, LINE_LEN);
00513 if (fieldlist == NULL) {
00514 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Couldn't find data to "
00515 "read structure from file '%s'.\n", data->file_name);
00516 return MOLFILE_ERROR;
00517 }
00518
00519 #if LAMMPS_DEBUG
00520 fprintf(stderr,"fieldlist for atoms: %s", fieldlist);
00521 #if 0
00522 fieldlist = strdup("\n");
00523 #endif
00524 #endif
00525
00526
00527 i = 0;
00528 k = strtok(fieldlist, " \t\n\r");
00529 if (k == NULL) {
00530
00531 vmdcon_printf(VMDCON_WARN, "lammpsplugin) Found old style trajectory. "
00532 "assuming data is ordered 'id type x|xs|xu y|ys|yu z|zs|zu [...]'.\n");
00533 data->coord_data |= LAMMPS_COORD_UNKNOWN;
00534 } else {
00535
00536 do {
00537
00538 const char *envvar;
00539 envvar=getenv("LAMMPSREMAPFIELDS");
00540 if (envvar)
00541 k=remap_field(k,envvar);
00542
00543 if (0 == strcmp(k, "id")) {
00544 data->field[i] = LAMMPS_FIELD_ATOMID;
00545 } else if (0 == strcmp(k, "mol")) {
00546 data->field[i] = LAMMPS_FIELD_MOLID;
00547 } else if (0 == strcmp(k, "type")) {
00548 data->field[i] = LAMMPS_FIELD_TYPE;
00549 } else if (0 == strcmp(k, "x")) {
00550 data->field[i] = LAMMPS_FIELD_POSX;
00551 data->coord_data |= LAMMPS_COORD_WRAPPED;
00552 } else if (0 == strcmp(k, "y")) {
00553 data->field[i] = LAMMPS_FIELD_POSY;
00554 data->coord_data |= LAMMPS_COORD_WRAPPED;
00555 } else if (0 == strcmp(k, "z")) {
00556 data->field[i] = LAMMPS_FIELD_POSZ;
00557 data->coord_data |= LAMMPS_COORD_WRAPPED;
00558 } else if (0 == strcmp(k, "xs")) {
00559 data->field[i] = LAMMPS_FIELD_POSXS;
00560 data->coord_data |= LAMMPS_COORD_SCALED;
00561 } else if (0 == strcmp(k, "ys")) {
00562 data->field[i] = LAMMPS_FIELD_POSYS;
00563 data->coord_data |= LAMMPS_COORD_SCALED;
00564 } else if (0 == strcmp(k, "zs")) {
00565 data->field[i] = LAMMPS_FIELD_POSZS;
00566 data->coord_data |= LAMMPS_COORD_SCALED;
00567 } else if (0 == strcmp(k, "xu")) {
00568 data->field[i] = LAMMPS_FIELD_POSXU;
00569 data->coord_data |= LAMMPS_COORD_UNWRAPPED;
00570 } else if (0 == strcmp(k, "yu")) {
00571 data->field[i] = LAMMPS_FIELD_POSYU;
00572 data->coord_data |= LAMMPS_COORD_UNWRAPPED;
00573 } else if (0 == strcmp(k, "zu")) {
00574 data->field[i] = LAMMPS_FIELD_POSZU;
00575 data->coord_data |= LAMMPS_COORD_UNWRAPPED;
00576 } else if (0 == strcmp(k, "xus")) {
00577 data->field[i] = LAMMPS_FIELD_POSXU;
00578 data->coord_data |= LAMMPS_COORD_UNWRAPPED;
00579 data->coord_data |= LAMMPS_COORD_SCALED;
00580 } else if (0 == strcmp(k, "yus")) {
00581 data->field[i] = LAMMPS_FIELD_POSYU;
00582 data->coord_data |= LAMMPS_COORD_UNWRAPPED;
00583 data->coord_data |= LAMMPS_COORD_SCALED;
00584 } else if (0 == strcmp(k, "zus")) {
00585 data->field[i] = LAMMPS_FIELD_POSZU;
00586 data->coord_data |= LAMMPS_COORD_UNWRAPPED;
00587 data->coord_data |= LAMMPS_COORD_SCALED;
00588 } else if (0 == strcmp(k, "ix")) {
00589 data->field[i] = LAMMPS_FIELD_IMGX;
00590 data->coord_data |= LAMMPS_COORD_IMAGES;
00591 } else if (0 == strcmp(k, "iy")) {
00592 data->field[i] = LAMMPS_FIELD_IMGY;
00593 data->coord_data |= LAMMPS_COORD_IMAGES;
00594 } else if (0 == strcmp(k, "iz")) {
00595 data->field[i] = LAMMPS_FIELD_IMGZ;
00596 data->coord_data |= LAMMPS_COORD_IMAGES;
00597 } else if (0 == strcmp(k, "vx")) {
00598 data->field[i] = LAMMPS_FIELD_VELX;
00599 #if vmdplugin_ABIVERSION > 10
00600 data->coord_data |= LAMMPS_COORD_VELOCITIES;
00601 data->ts_meta.has_velocities = 1;
00602 #endif
00603 } else if (0 == strcmp(k, "vy")) {
00604 data->field[i] = LAMMPS_FIELD_VELY;
00605 #if vmdplugin_ABIVERSION > 10
00606 data->coord_data |= LAMMPS_COORD_VELOCITIES;
00607 data->ts_meta.has_velocities = 1;
00608 #endif
00609 } else if (0 == strcmp(k, "vz")) {
00610 data->field[i] = LAMMPS_FIELD_VELZ;
00611 #if vmdplugin_ABIVERSION > 10
00612 data->coord_data |= LAMMPS_COORD_VELOCITIES;
00613 data->ts_meta.has_velocities = 1;
00614 #endif
00615 } else if (0 == strcmp(k, "fx")) {
00616 data->field[i] = LAMMPS_FIELD_FORX;
00617 data->coord_data |= LAMMPS_COORD_FORCES;
00618 } else if (0 == strcmp(k, "fy")) {
00619 data->field[i] = LAMMPS_FIELD_FORY;
00620 data->coord_data |= LAMMPS_COORD_FORCES;
00621 } else if (0 == strcmp(k, "fz")) {
00622 data->field[i] = LAMMPS_FIELD_FORZ;
00623 data->coord_data |= LAMMPS_COORD_FORCES;
00624 } else if (0 == strcmp(k, "q")) {
00625 data->field[i] = LAMMPS_FIELD_CHARGE;
00626 *optflags |= MOLFILE_CHARGE;
00627 } else if (0 == strcmp(k, "radius")) {
00628 data->field[i] = LAMMPS_FIELD_RADIUS;
00629 *optflags |= MOLFILE_RADIUS;
00630 } else if (0 == strcmp(k, "diameter")) {
00631 data->field[i] = LAMMPS_FIELD_RADIUS;
00632 *optflags |= MOLFILE_RADIUS;
00633 } else if (0 == strcmp(k, "element")) {
00634 data->field[i] = LAMMPS_FIELD_ELEMENT;
00635 *optflags |= MOLFILE_ATOMICNUMBER;
00636 *optflags |= MOLFILE_MASS;
00637 *optflags |= MOLFILE_RADIUS;
00638 } else if (0 == strcmp(k, "mass")) {
00639 data->field[i] = LAMMPS_FIELD_MASS;
00640 *optflags |= MOLFILE_MASS;
00641 } else if (0 == strcmp(k, "mux")) {
00642 data->field[i] = LAMMPS_FIELD_MUX;
00643 data->coord_data |= LAMMPS_COORD_DIPOLE;
00644 } else if (0 == strcmp(k, "muy")) {
00645 data->field[i] = LAMMPS_FIELD_MUY;
00646 data->coord_data |= LAMMPS_COORD_DIPOLE;
00647 } else if (0 == strcmp(k, "muz")) {
00648 data->field[i] = LAMMPS_FIELD_MUZ;
00649 data->coord_data |= LAMMPS_COORD_DIPOLE;
00650 } else {
00651 data->field[i] = LAMMPS_FIELD_UNKNOWN;
00652 }
00653 ++i;
00654 data->numfields = i;
00655 k = strtok(NULL," \t\n\r");
00656 } while ((k != NULL) && (i < LAMMPS_MAX_NUM_FIELDS));
00657
00658 vmdcon_printf(VMDCON_INFO, "lammpsplugin) New style dump with %d data "
00659 "fields. Coordinate data flags: 0x%02x\n",
00660 data->numfields, data->coord_data);
00661
00662 if ( !(data->coord_data & LAMMPS_COORD_DIPOLE) && (data->dip2atoms >= 0.0f)) {
00663 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) conversion of dipoles to "
00664 "two atoms requested, but no dipole data found\n");
00665 free(idlist);
00666 return MOLFILE_ERROR;
00667 }
00668 }
00669
00670 idlist = (int *)malloc(data->numatoms * sizeof(int));
00671
00672
00673 for(i=0; i<data->numatoms; i++) {
00674 k = myFgets(buffer, LINE_LEN, data->file);
00675
00676 if (k == NULL) {
00677 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Error while reading "
00678 "structure from lammps dump file '%s': atom missing in "
00679 "the first timestep\n", data->file_name);
00680 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) expecting '%d' atoms, "
00681 "found only '%d'\n", data->numatoms, i+1);
00682 free(idlist);
00683 return MOLFILE_ERROR;
00684 }
00685
00686
00687
00688
00689
00690 if (data->coord_data == LAMMPS_COORD_UNKNOWN) {
00691 int ix, iy, iz;
00692 j = sscanf(buffer, "%d%d%f%f%f%d%d%d", &atomid, &atomtype,
00693 &x, &y, &z, &ix, &iy, &iz);
00694 if (j > 4) {
00695 data->coord_data |= LAMMPS_COORD_SCALED;
00696 data->numfields = 5;
00697 data->field[0] = LAMMPS_FIELD_ATOMID;
00698 data->field[1] = LAMMPS_FIELD_TYPE;
00699 data->field[2] = LAMMPS_FIELD_POSXS;
00700 data->field[3] = LAMMPS_FIELD_POSYS;
00701 data->field[4] = LAMMPS_FIELD_POSZS;
00702 } else {
00703 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Error while reading "
00704 "structure from lammps dump file '%s'. Unsupported "
00705 "dump file format.\n", data->file_name);
00706 free(idlist);
00707 return MOLFILE_ERROR;
00708 }
00709 }
00710
00711 atomid = i;
00712
00713
00714 j = 0;
00715 k = strtok(buffer, " \t\n\r");
00716 while ((k != NULL) && (j < data->numfields)) {
00717 switch (data->field[j]) {
00718
00719 case LAMMPS_FIELD_ATOMID:
00720 atomid = atoi(k) - 1;
00721 break;
00722
00723 default:
00724 break;
00725 }
00726 ++j;
00727 k = strtok(NULL, " \t\n\r");
00728 }
00729 if (data->dip2atoms < 0.0f) {
00730 idlist[i] = atomid;
00731 } else {
00732
00733 idlist[i] = 2*atomid;
00734 ++i;
00735 idlist[i] = 2*atomid+1;
00736 }
00737
00738
00739
00740
00741
00742 if ( (data->coord_data & LAMMPS_COORD_UNKNOWN) != 0) {
00743 x=y=z=0.0f;
00744 j = sscanf(buffer, "%*d%*d%f%f%f", &x, &y, &z);
00745 if ((x<-0.1) || (x>1.1) || (y<-0.1) || (y>1.1)
00746 || (z<-0.1) || (x>1.1)) {
00747 data->coord_data &= ~LAMMPS_COORD_UNKNOWN;
00748 if ((data->coord_data & LAMMPS_COORD_IMAGES) != 0) {
00749 data->coord_data |= LAMMPS_COORD_WRAPPED;
00750 data->field[2] = LAMMPS_FIELD_POSX;
00751 data->field[3] = LAMMPS_FIELD_POSY;
00752 data->field[4] = LAMMPS_FIELD_POSZ;
00753 } else {
00754 data->coord_data |= LAMMPS_COORD_UNWRAPPED;
00755 data->field[2] = LAMMPS_FIELD_POSXU;
00756 data->field[3] = LAMMPS_FIELD_POSYU;
00757 data->field[4] = LAMMPS_FIELD_POSZU;
00758 }
00759 }
00760 }
00761 }
00762 data->coord_data &= ~LAMMPS_COORD_UNKNOWN;
00763
00764
00765
00766 if (data->coord_data & LAMMPS_COORD_UNWRAPPED) {
00767 data->coord_data &= ~(LAMMPS_COORD_WRAPPED|LAMMPS_COORD_SCALED
00768 |LAMMPS_COORD_IMAGES);
00769 } else if (data->coord_data & LAMMPS_COORD_WRAPPED) {
00770 data->coord_data &= ~LAMMPS_COORD_SCALED;
00771 } else if (!(data->coord_data & LAMMPS_COORD_SCALED)) {
00772
00773 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) No usable coordinate data "
00774 "found in lammps dump file '%s'.\n", data->file_name);
00775 return MOLFILE_ERROR;
00776 }
00777
00778 if (data->coord_data & LAMMPS_COORD_SCALED) {
00779 vmdcon_printf(VMDCON_INFO, "lammpsplugin) Reconstructing atomic "
00780 "coordinates from fractional coordinates and box vectors.\n");
00781 } else {
00782 vmdcon_printf(VMDCON_INFO, "lammpsplugin) Using absolute atomic "
00783 "coordinates directly.\n");
00784 }
00785 if (data->coord_data & LAMMPS_COORD_DIPOLE) {
00786 vmdcon_printf(VMDCON_INFO, "lammpsplugin) Detected dipole vector data.\n");
00787 }
00788
00789 if (data->coord_data & LAMMPS_COORD_TRICLINIC) {
00790 vmdcon_printf(VMDCON_INFO, "lammpsplugin) Detected triclinic box.\n");
00791 }
00792
00793 #if vmdplugin_ABIVERSION > 10
00794 if (data->coord_data & LAMMPS_COORD_VELOCITIES) {
00795 vmdcon_printf(VMDCON_INFO, "lammpsplugin) Importing atomic velocities.\n");
00796 }
00797 #endif
00798
00799
00800 id_sort(idlist, data->numatoms);
00801 needhash=0;
00802 for (i=0; i < data->numatoms; ++i)
00803 if (idlist[i] != i) needhash=1;
00804
00805
00806 if (needhash) {
00807 vmdcon_printf(VMDCON_INFO, "lammpsplugin) Using hash table to track "
00808 "atom identities.\n");
00809 data->idmap = (inthash_t *)calloc(1, sizeof(inthash_t));
00810 inthash_init(data->idmap, data->numatoms);
00811 for (i=0; i < data->numatoms; ++i) {
00812 if (inthash_insert(data->idmap, idlist[i], i) != HASH_FAIL) {
00813 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Duplicate atomid %d or "
00814 "unsupported dump file format.\n", idlist[i]);
00815 free(idlist);
00816 return MOLFILE_ERROR;
00817 }
00818 }
00819 } else {
00820 data->idmap = NULL;
00821 }
00822 free(idlist);
00823
00824
00825
00826 myRewind(data->file);
00827
00828
00829 fieldlist = find_item_keyword(data->file, KEY_DATA, buffer, LINE_LEN);
00830 if (fieldlist == NULL) {
00831 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Couldn't find data to "
00832 "read structure from file '%s'.\n", data->file_name);
00833 return MOLFILE_ERROR;
00834 }
00835
00836
00837 for(i=0; i<data->numatoms; i++) {
00838 int has_element, has_mass, has_radius;
00839
00840 k = myFgets(buffer, LINE_LEN, data->file);
00841
00842 if (k == NULL) {
00843 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Error while reading "
00844 "structure from lammps dump file '%s': atom missing in "
00845 "the first timestep\n", data->file_name);
00846 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) expecting '%d' atoms, "
00847 "found only '%d'\n", data->numatoms, i+1);
00848 free(idlist);
00849 return MOLFILE_ERROR;
00850 }
00851
00852
00853 memset(&thisatom, 0, sizeof(molfile_atom_t));
00854 thisatom.resid = 0;
00855 strncpy(thisatom.resname, "UNK", 4);
00856 strncpy(thisatom.chain, "",1);
00857 strncpy(thisatom.segid, "",1);
00858 atomid = i;
00859 has_element = has_mass = has_radius = 0;
00860
00861
00862 j = 0;
00863 k = strtok(buffer, " \t\n\r");
00864 while ((k != NULL) && (j < data->numfields)) {
00865 int idx;
00866
00867 switch (data->field[j]) {
00868
00869 case LAMMPS_FIELD_ATOMID:
00870 atomid = atoi(k) - 1;
00871 break;
00872
00873 case LAMMPS_FIELD_ELEMENT:
00874 strncpy(thisatom.name, k, 16);
00875 thisatom.name[15] = '\0';
00876 idx = get_pte_idx(k);
00877 thisatom.atomicnumber = idx;
00878 has_element = 1;
00879 break;
00880
00881 case LAMMPS_FIELD_TYPE:
00882 strncpy(thisatom.type, k, 16);
00883 if (has_element == 0) {
00884
00885 strncpy(thisatom.name, k, 16);
00886 thisatom.type[15] = '\0';
00887 }
00888
00889
00890
00891
00892
00893
00894
00895
00896 break;
00897
00898 case LAMMPS_FIELD_MOLID:
00899 thisatom.resid = atoi(k);
00900 break;
00901
00902 case LAMMPS_FIELD_CHARGE:
00903 thisatom.charge = atof(k);
00904 break;
00905
00906 case LAMMPS_FIELD_MASS:
00907 thisatom.mass = atof(k);
00908 has_mass = 1;
00909 break;
00910
00911 case LAMMPS_FIELD_RADIUS:
00912 thisatom.radius = atof(k);
00913 has_radius = 1;
00914 break;
00915
00916 case LAMMPS_FIELD_DIAMETER:
00917
00918 if (has_radius == 0) {
00919 thisatom.radius = 0.5*atof(k);
00920 has_radius = 1;
00921 }
00922 break;
00923
00924 case LAMMPS_FIELD_UNKNOWN:
00925 default:
00926 break;
00927 }
00928 ++j;
00929 k = strtok(NULL, " \t\n\r");
00930 }
00931
00932
00933 if (has_element) {
00934 int idx = get_pte_idx(thisatom.name);
00935 if (!has_mass) thisatom.mass = get_pte_mass(idx);
00936 if (!has_radius) thisatom.radius = get_pte_vdw_radius(idx);
00937 }
00938
00939
00940 if (data->dip2atoms < 0.0f) {
00941 if (data->idmap != NULL) {
00942 j = inthash_lookup(data->idmap, atomid);
00943 } else {
00944 j = atomid;
00945 }
00946 memcpy(atoms+j, &thisatom, sizeof(molfile_atom_t));
00947 } else {
00948 if (data->idmap != NULL) {
00949 j = inthash_lookup(data->idmap, 2*atomid);
00950 } else {
00951 j = 2*atomid;
00952 }
00953 memcpy(atoms+j, &thisatom, sizeof(molfile_atom_t));
00954
00955 ++i;
00956 if (data->idmap != NULL) {
00957 j = inthash_lookup(data->idmap, 2*atomid+1);
00958 } else {
00959 j = 2*atomid+1;
00960 }
00961 memcpy(atoms+j, &thisatom, sizeof(molfile_atom_t));
00962 }
00963 }
00964
00965 myRewind(data->file);
00966 data->fieldinit = 1;
00967 return MOLFILE_SUCCESS;
00968 }
00969
00970 #if vmdplugin_ABIVERSION > 10
00971
00972 static int read_timestep_metadata(void *mydata,
00973 molfile_timestep_metadata_t *meta) {
00974 lammpsdata *data = (lammpsdata *)mydata;
00975
00976 meta->count = -1;
00977 meta->has_velocities = data->ts_meta.has_velocities;
00978 if (meta->has_velocities && velinfo) {
00979 vmdcon_printf(VMDCON_INFO, "lammpsplugin) Importing velocities from custom LAMMPS dump file.\n");
00980 velinfo = 0;
00981 }
00982 return MOLFILE_SUCCESS;
00983 }
00984 #endif
00985
00986
00987
00988
00989 static float cosangle2deg(double val)
00990 {
00991 if (val < -1.0) val=-1.0;
00992 if (val > 1.0) val= 1.0;
00993 return (float) (90.0 - asin(val)*90.0/M_PI_2);
00994 }
00995
00996 static int read_lammps_timestep(void *mydata, int natoms, molfile_timestep_t *ts) {
00997 int i, j;
00998 char *ptr, buffer[LINE_LEN];
00999 float x, y, z, vx, vy, vz;
01000 int atomid, numres, numatoms;
01001 long timestep;
01002 float xlo, xhi, ylo, yhi, zlo, zhi, xy, xz, yz, ylohi;
01003 float xlo_bound, xhi_bound, ylo_bound, yhi_bound, zlo_bound, zhi_bound;
01004
01005 lammpsdata *data = (lammpsdata *)mydata;
01006
01007
01008 if (data->fieldinit == 0) {
01009 molfile_atom_t *atoms;
01010 atoms = (molfile_atom_t *)malloc(natoms*sizeof(molfile_atom_t));
01011 read_lammps_structure(mydata,&natoms,atoms);
01012 free(atoms);
01013 }
01014
01015
01016
01017
01018 while ((ptr = find_next_item(data->file, buffer, LINE_LEN))) {
01019 if (!ptr) return MOLFILE_ERROR;
01020 char *keyword;
01021 while (isspace(*ptr)) ++ptr;
01022 keyword = ptr;
01023 while (!isspace(*ptr)) ++ptr;
01024 *ptr = '\0';
01025
01026
01027 if (strcmp(keyword, KEY_TSTEP) == 0) break;
01028
01029
01030 if (strcmp(keyword, KEY_TIME) == 0) {
01031
01032
01033 if (!ts) return MOLFILE_SUCCESS;
01034
01035 char *k = myFgets(buffer, LINE_LEN, data->file);
01036 if (k) ts->physical_time = atof(buffer);
01037 }
01038 }
01039
01040
01041 if (!ts) return MOLFILE_SUCCESS;
01042
01043 ptr = myFgets(buffer, LINE_LEN, data->file);
01044 if (!ptr) return MOLFILE_ERROR;
01045 else timestep = atol(ptr);
01046
01047
01048 ptr = find_item_keyword(data->file, KEY_ATOMS, buffer, LINE_LEN);
01049 if (!ptr) {
01050 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Unable to find item: %s for "
01051 "timestep %ld in file %s.\n", KEY_ATOMS, timestep, data->file_name);
01052 return MOLFILE_ERROR;
01053 }
01054
01055 if (!myFgets(buffer, LINE_LEN, data->file)) {
01056 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Premature EOF for %s.\n", data->file_name);
01057 return MOLFILE_ERROR;
01058 }
01059
01060
01061 numatoms = atoi(buffer);
01062 data->numatoms = numatoms;
01063 if (data->dip2atoms < 0.0f) {
01064 if (natoms < numatoms) {
01065 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Too many atoms in timestep %ld."
01066 " %d vs. %d\n", timestep, numatoms, natoms);
01067 return MOLFILE_ERROR;
01068 }
01069 } else {
01070 if (natoms/2 < numatoms) {
01071 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Too many atoms in timestep %ld."
01072 " %d vs. %d\n", timestep, numatoms, natoms/2);
01073 return MOLFILE_ERROR;
01074 }
01075 }
01076
01077
01078 if (NULL == find_item_keyword(data->file, KEY_BOX, buffer, LINE_LEN)) {
01079 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Could not find box boundaries in timestep.\n");
01080 return MOLFILE_ERROR;
01081 }
01082
01083 if (NULL == myFgets(buffer, LINE_LEN, data->file)) return MOLFILE_ERROR;
01084 numres = sscanf(buffer,"%f%f%f", &xlo_bound, &xhi_bound, &xy);
01085
01086 if (NULL == myFgets(buffer, LINE_LEN, data->file)) return MOLFILE_ERROR;
01087 numres += sscanf(buffer,"%f%f%f", &ylo_bound, &yhi_bound, &xz);
01088
01089 if (NULL == myFgets(buffer, LINE_LEN, data->file)) return MOLFILE_ERROR;
01090 numres += sscanf(buffer,"%f%f%f", &zlo_bound, &zhi_bound, &yz);
01091
01092 xlo = xlo_bound;
01093 xhi = xhi_bound;
01094 ylo = ylo_bound;
01095 yhi = yhi_bound;
01096 zlo = zlo_bound;
01097 zhi = zhi_bound;
01098
01099 if (data->coord_data & LAMMPS_COORD_TRICLINIC) {
01100 float xdelta;
01101
01102
01103
01104
01105
01106 if (numres != 9) {
01107 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Inconsistent triclinic box specifications.\n");
01108 return MOLFILE_ERROR;
01109 }
01110
01111
01112 xdelta = MIN(0.0f,xy);
01113 xdelta = MIN(xdelta,xz);
01114 xdelta = MIN(xdelta,xy+xz);
01115 xlo -= xdelta;
01116
01117 xdelta = MAX(0.0f,xy);
01118 xdelta = MAX(xdelta,xz);
01119 xdelta = MAX(xdelta,xy+xz);
01120 xhi -= xdelta;
01121
01122 ylo -= MIN(0.0f,yz);
01123 yhi -= MAX(0.0f,yz);
01124
01125 } else {
01126 if (numres != 6) {
01127 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Inconsistent orthorhombic box specifications.\n");
01128 return MOLFILE_ERROR;
01129 }
01130 xy = 0.0f;
01131 xz = 0.0f;
01132 yz = 0.0f;
01133 }
01134
01135
01136 ts->A = xhi-xlo;
01137 ylohi = yhi-ylo;
01138 ts->B = sqrt(ylohi*ylohi + xy*xy);
01139 ts->C = sqrt((zhi-zlo)*(zhi-zlo) + xz*xz + yz*yz);
01140
01141
01142 ts->alpha = cosangle2deg((xy*xz + ylohi*yz)/(ts->B * ts->C));
01143 ts->beta = cosangle2deg(xz/ts->C);
01144 ts->gamma = cosangle2deg(xy/ts->B);
01145
01146
01147 if (NULL == find_item_keyword(data->file, KEY_DATA, buffer, LINE_LEN)) {
01148 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) could not find atom data for timestep.\n");
01149 return MOLFILE_ERROR;
01150 }
01151
01152
01153 for (i=0; i<natoms; i++) {
01154 ts->coords[3*i+0] = data->dumx;
01155 ts->coords[3*i+1] = data->dumy;
01156 ts->coords[3*i+2] = data->dumz;
01157 }
01158
01159 #if vmdplugin_ABIVERSION > 10
01160
01161 if (ts->velocities != NULL) memset(ts->velocities,0,3*natoms*sizeof(float));
01162 #endif
01163
01164 for (i=0; i<numatoms; i++) {
01165 float ix, iy, iz, mux, muy, muz;
01166 char *k;
01167
01168 k = myFgets(buffer, LINE_LEN, data->file);
01169
01170 if (k == NULL) {
01171 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) Error while reading "
01172 "data from lammps dump file '%s'.\n", data->file_name);
01173 vmdcon_printf(VMDCON_ERROR, "lammpsplugin) expecting '%d' atoms, "
01174 "found only '%d'\n", numatoms, i+1);
01175 return MOLFILE_ERROR;
01176 }
01177
01178 x=y=z=ix=iy=iz=vx=vy=vz=mux=muy=muz=0.0f;
01179 atomid=i;
01180
01181
01182 j = 0;
01183 k = strtok(buffer, " \t\n\r");
01184 while ((k != NULL) && (j < data->numfields)) {
01185 switch (data->field[j]) {
01186
01187 case LAMMPS_FIELD_ATOMID:
01188 atomid = atoi(k) - 1;
01189 break;
01190
01191 case LAMMPS_FIELD_POSX:
01192 if (data->coord_data & LAMMPS_COORD_WRAPPED)
01193 x = atof(k);
01194 break;
01195
01196 case LAMMPS_FIELD_POSY:
01197 if (data->coord_data & LAMMPS_COORD_WRAPPED)
01198 y = atof(k);
01199 break;
01200
01201 case LAMMPS_FIELD_POSZ:
01202 if (data->coord_data & LAMMPS_COORD_WRAPPED)
01203 z = atof(k);
01204 break;
01205
01206 case LAMMPS_FIELD_POSXU:
01207 if (data->coord_data & LAMMPS_COORD_UNWRAPPED)
01208 x = atof(k);
01209 break;
01210
01211 case LAMMPS_FIELD_POSYU:
01212 if (data->coord_data & LAMMPS_COORD_UNWRAPPED)
01213 y = atof(k);
01214 break;
01215
01216 case LAMMPS_FIELD_POSZU:
01217 if (data->coord_data & LAMMPS_COORD_UNWRAPPED)
01218 z = atof(k);
01219 break;
01220
01221 case LAMMPS_FIELD_POSXS:
01222 if (data->coord_data & LAMMPS_COORD_SCALED)
01223 x = atof(k);
01224 break;
01225
01226 case LAMMPS_FIELD_POSYS:
01227 if (data->coord_data & LAMMPS_COORD_SCALED)
01228 y = atof(k);
01229 break;
01230
01231 case LAMMPS_FIELD_POSZS:
01232 if (data->coord_data & LAMMPS_COORD_SCALED)
01233 z = atof(k);
01234 break;
01235
01236 case LAMMPS_FIELD_IMGX:
01237 if (data->coord_data & LAMMPS_COORD_IMAGES)
01238 ix = atof(k);
01239 break;
01240
01241 case LAMMPS_FIELD_IMGY:
01242 if (data->coord_data & LAMMPS_COORD_IMAGES)
01243 iy = atof(k);
01244 break;
01245
01246 case LAMMPS_FIELD_IMGZ:
01247 if (data->coord_data & LAMMPS_COORD_IMAGES)
01248 iz = atof(k);
01249 break;
01250
01251 case LAMMPS_FIELD_MUX:
01252 if (data->coord_data & LAMMPS_COORD_DIPOLE)
01253 mux = atof(k);
01254 break;
01255
01256 case LAMMPS_FIELD_MUY:
01257 if (data->coord_data & LAMMPS_COORD_DIPOLE)
01258 muy = atof(k);
01259 break;
01260
01261 case LAMMPS_FIELD_MUZ:
01262 if (data->coord_data & LAMMPS_COORD_DIPOLE)
01263 muz = atof(k);
01264 break;
01265
01266 #if vmdplugin_ABIVERSION > 10
01267 case LAMMPS_FIELD_VELX:
01268 vx = atof(k);
01269 break;
01270
01271 case LAMMPS_FIELD_VELY:
01272 vy = atof(k);
01273 break;
01274
01275 case LAMMPS_FIELD_VELZ:
01276 vz = atof(k);
01277 break;
01278 #endif
01279
01280 default:
01281 break;
01282 }
01283
01284 ++j;
01285 k = strtok(NULL, " \t\n\r");
01286 }
01287
01288 if (data->dip2atoms < 0.0f) {
01289 if (data->idmap != NULL) {
01290 j = inthash_lookup(data->idmap, atomid);
01291 } else {
01292 j = atomid;
01293 }
01294 } else {
01295 if (data->idmap != NULL) {
01296 j = inthash_lookup(data->idmap, 2*atomid);
01297 } else {
01298 j = 2*atomid;
01299 }
01300 }
01301
01302 if (data->idmap && (j == HASH_FAIL)) {
01303
01304 if (inthash_entries(data->idmap) < data->maxatoms) {
01305 if (data->dip2atoms < 0.0f) {
01306 inthash_insert(data->idmap,atomid,i);
01307 j = inthash_lookup(data->idmap,atomid);
01308 } else {
01309 inthash_insert(data->idmap,2*atomid,2*i);
01310 inthash_insert(data->idmap,2*atomid+1,2*i+1);
01311 j = inthash_lookup(data->idmap, 2*atomid);
01312 }
01313 } else j = -1;
01314 }
01315
01316 if ((j < 0) || (j >= data->maxatoms)) {
01317 vmdcon_printf(VMDCON_WARN, "lammpsplugin) ignoring out of range "
01318 "atom #%d with id %d\n", i, atomid);
01319 } else {
01320
01321
01322
01323
01324
01325
01326
01327 int addr = 3 * j;
01328 if (data->coord_data & LAMMPS_COORD_TRICLINIC) {
01329 if (data->coord_data & LAMMPS_COORD_SCALED) {
01330
01331
01332 ts->coords[addr ] = xlo + x * ts->A + y * xy + z * xz;
01333 ts->coords[addr + 1] = ylo + y * ylohi + z * yz;
01334 ts->coords[addr + 2] = zlo + z * (zhi-zlo);
01335 } else {
01336
01337 ts->coords[addr ] = x;
01338 ts->coords[addr + 1] = y;
01339 ts->coords[addr + 2] = z;
01340 }
01341 if (data->coord_data & LAMMPS_COORD_IMAGES) {
01342
01343 ts->coords[addr ] += ix * ts->A + iy * xy + iz * xz;
01344 ts->coords[addr + 1] += iy * ylohi + iz * yz;
01345 ts->coords[addr + 2] += iz * (zhi-zlo);
01346 }
01347 } else {
01348 if (data->coord_data & LAMMPS_COORD_SCALED) {
01349
01350
01351 ts->coords[addr ] = xlo + x * ts->A;
01352 ts->coords[addr + 1] = ylo + y * ts->B;
01353 ts->coords[addr + 2] = zlo + z * ts->C;
01354 } else {
01355
01356 ts->coords[addr ] = x;
01357 ts->coords[addr + 1] = y;
01358 ts->coords[addr + 2] = z;
01359 }
01360 if (data->coord_data & LAMMPS_COORD_IMAGES) {
01361
01362 ts->coords[addr ] += ix * ts->A;
01363 ts->coords[addr + 1] += iy * ts->B;
01364 ts->coords[addr + 2] += iz * ts->C;
01365 }
01366 }
01367
01368 #if vmdplugin_ABIVERSION > 10
01369 if (ts->velocities != NULL) {
01370 ts->velocities[addr ] = vx;
01371 ts->velocities[addr + 1] = vy;
01372 ts->velocities[addr + 2] = vz;
01373 }
01374 #endif
01375
01376
01377 if (data->dip2atoms >= 0.0f) {
01378 const float sf = data->dip2atoms;
01379
01380 x = ts->coords[addr ];
01381 y = ts->coords[addr + 1];
01382 z = ts->coords[addr + 2];
01383 ts->coords[addr ] = x + sf*mux;
01384 ts->coords[addr + 1] = y + sf*muy;
01385 ts->coords[addr + 2] = z + sf*muz;
01386
01387 if (data->idmap != NULL) {
01388 j = inthash_lookup(data->idmap, 2*atomid + 1);
01389 } else {
01390 j = 2*atomid + 1;
01391 }
01392 addr = 3*j;
01393 ts->coords[addr ] = x - sf*mux;
01394 ts->coords[addr + 1] = y - sf*muy;
01395 ts->coords[addr + 2] = z - sf*muz;
01396 #if vmdplugin_ABIVERSION > 10
01397 if (ts->velocities != NULL) {
01398 ts->velocities[addr ] = vx;
01399 ts->velocities[addr + 1] = vy;
01400 ts->velocities[addr + 2] = vz;
01401 }
01402 #endif
01403 }
01404 }
01405 }
01406
01407 return MOLFILE_SUCCESS;
01408 }
01409
01410 static void close_lammps_read(void *mydata) {
01411 lammpsdata *data = (lammpsdata *)mydata;
01412 myFclose(data->file);
01413 free(data->file_name);
01414 #if LAMMPS_DEBUG
01415 if (data->idmap != NULL)
01416 fprintf(stderr, "inthash stats: %s\n", inthash_stats(data->idmap));
01417 #endif
01418 if (data->idmap != NULL) {
01419 inthash_destroy(data->idmap);
01420 free(data->idmap);
01421 }
01422 free(data);
01423 }
01424
01425 static void *open_lammps_write(const char *filename, const char *filetype,
01426 int natoms) {
01427 FILE *fp;
01428 lammpsdata *data;
01429
01430 fp = fopen(filename, "w");
01431 if (!fp) {
01432 vmdcon_printf(VMDCON_ERROR, "Error) Unable to open lammpstrj file %s for writing\n",
01433 filename);
01434 return NULL;
01435 }
01436
01437 data = (lammpsdata *)malloc(sizeof(lammpsdata));
01438 data->numatoms = natoms;
01439 data->fp = fp;
01440 data->file_name = strdup(filename);
01441 data->nstep = 0;
01442 return data;
01443 }
01444
01445 static int write_lammps_structure(void *mydata, int optflags,
01446 const molfile_atom_t *atoms) {
01447 lammpsdata *data = (lammpsdata *)mydata;
01448 int i, j;
01449 hash_t atomtypehash;
01450
01451 hash_init(&atomtypehash,128);
01452
01453
01454 for (i=0, j=1; i < data->numatoms; i++)
01455 if (hash_insert(&atomtypehash, atoms[i].type, j) == HASH_FAIL)
01456 j++;
01457
01458 data->atomtypes = (int *) malloc(data->numatoms * sizeof(int));
01459
01460 for (i=0; i < data->numatoms ; i++)
01461 data->atomtypes[i] = hash_lookup(&atomtypehash, atoms[i].type);
01462
01463 hash_destroy(&atomtypehash);
01464
01465 return MOLFILE_SUCCESS;
01466 }
01467
01468 static int write_lammps_timestep(void *mydata, const molfile_timestep_t *ts) {
01469 lammpsdata *data = (lammpsdata *)mydata;
01470 const float *pos;
01471 float xmin[3], xmax[3], xcen[3];
01472 int i, tric, pbcx, pbcy, pbcz;
01473
01474 fprintf(data->fp, "ITEM: TIMESTEP\n");
01475 fprintf(data->fp, "%d\n", data->nstep);
01476 fprintf(data->fp, "ITEM: NUMBER OF ATOMS\n");
01477 fprintf(data->fp, "%d\n", data->numatoms);
01478
01479 pos = ts->coords;
01480
01481 xmax[0] = xmax[1] = xmax[2] = -1.0e30f;
01482 xmin[0] = xmin[1] = xmin[2] = 1.0e30f;
01483 tric = pbcx = pbcy = pbcz = 0;
01484
01485 #if defined(_MSC_VER)
01486 if ((fabs(ts->alpha - 90.0f) > SMALL) ||
01487 (fabs(ts->beta - 90.0f) > SMALL) ||
01488 (fabs(ts->gamma - 90.0f) > SMALL)) tric = 1;
01489 if (fabs(ts->A) > SMALL) pbcx = 1;
01490 if (fabs(ts->B) > SMALL) pbcy = 1;
01491 if (fabs(ts->C) > SMALL) pbcz = 1;
01492 #else
01493 if ((fabsf(ts->alpha - 90.0f) > SMALL) ||
01494 (fabsf(ts->beta - 90.0f) > SMALL) ||
01495 (fabsf(ts->gamma - 90.0f) > SMALL)) tric = 1;
01496 if (fabsf(ts->A) > SMALL) pbcx = 1;
01497 if (fabsf(ts->B) > SMALL) pbcy = 1;
01498 if (fabsf(ts->C) > SMALL) pbcz = 1;
01499 #endif
01500
01501
01502 for (i = 0; i < data->numatoms; ++i) {
01503 xmax[0] = (pos[0] > xmax[0]) ? pos[0] : xmax[0];
01504 xmax[1] = (pos[1] > xmax[1]) ? pos[1] : xmax[1];
01505 xmax[2] = (pos[2] > xmax[2]) ? pos[2] : xmax[2];
01506 xmin[0] = (pos[0] < xmin[0]) ? pos[0] : xmin[0];
01507 xmin[1] = (pos[1] < xmin[1]) ? pos[1] : xmin[1];
01508 xmin[2] = (pos[2] < xmin[2]) ? pos[2] : xmin[2];
01509 pos += 3;
01510 }
01511 xcen[0] = 0.5f * (xmax[0] + xmin[0]);
01512 xcen[1] = 0.5f * (xmax[1] + xmin[1]);
01513 xcen[2] = 0.5f * (xmax[2] + xmin[2]);
01514
01515 pos = ts->coords;
01516
01517 if (tric == 0 ) {
01518
01519 if (pbcx) xmax[0] = xcen[0] + 0.5f*ts->A;
01520 if (pbcx) xmin[0] = xcen[0] - 0.5f*ts->A;
01521 if (pbcy) xmax[1] = xcen[1] + 0.5f*ts->B;
01522 if (pbcy) xmin[1] = xcen[1] - 0.5f*ts->B;
01523 if (pbcz) xmax[2] = xcen[2] + 0.5f*ts->C;
01524 if (pbcz) xmin[2] = xcen[2] - 0.5f*ts->C;
01525
01526
01527 fprintf(data->fp, "ITEM: BOX BOUNDS %s %s %s\n", pbcx ? "pp" : "ss",
01528 pbcy ? "pp" : "ss", pbcz ? "pp" : "ss");
01529 fprintf(data->fp, "%g %g\n", xmin[0], xmax[0]);
01530 fprintf(data->fp, "%g %g\n", xmin[1], xmax[1] );
01531 fprintf(data->fp, "%g %g\n", xmin[2], xmax[2] );
01532
01533 } else {
01534
01535 double lx, ly, lz, xy, xz, yz, xbnd;
01536
01537 lx = ts->A;
01538 xy = ts->B * cos(ts->gamma/90.0*M_PI_2);
01539 xz = ts->C * cos(ts->beta/90.0*M_PI_2);
01540 ly = sqrt(ts->B*ts->B - xy*xy);
01541 if (fabs(ly) > SMALL)
01542 yz = (ts->B*ts->C*cos(ts->alpha/90.0*M_PI_2) - xy*xz) / ly;
01543 else
01544 yz = 0.0;
01545 lz = sqrt(ts->C*ts->C - xz*xz - yz*yz);
01546
01547 if (pbcx) xmax[0] = xcen[0] + 0.5f*lx;
01548 if (pbcx) xmin[0] = xcen[0] - 0.5f*lx;
01549 if (pbcy) xmax[1] = xcen[1] + 0.5f*ly;
01550 if (pbcy) xmin[1] = xcen[1] - 0.5f*ly;
01551 if (pbcz) xmax[2] = xcen[2] + 0.5f*lz;
01552 if (pbcz) xmin[2] = xcen[2] - 0.5f*lz;
01553
01554
01555
01556 xbnd = 0.0;
01557 xbnd = (xy > xbnd) ? xy : xbnd;
01558 xbnd = (xz > xbnd) ? xz : xbnd;
01559 xbnd = (xy+xz > xbnd) ? (xy + xz) : xbnd;
01560 xmax[0] += xbnd;
01561
01562 xbnd = 0.0;
01563 xbnd = (xy < xbnd) ? xy : xbnd;
01564 xbnd = (xz < xbnd) ? xz : xbnd;
01565 xbnd = (xy+xz < xbnd) ? (xy + xz) : xbnd;
01566 xmin[0] += xbnd;
01567
01568 xbnd = 0.0;
01569 xbnd = (yz > xbnd) ? yz : xbnd;
01570 xmax[1] += xbnd;
01571
01572 xbnd = 0.0;
01573 xbnd = (yz < xbnd) ? yz : xbnd;
01574 xmin[1] += xbnd;
01575
01576
01577 fprintf(data->fp, "ITEM: BOX BOUNDS %s %s %s xy xz yz\n", pbcx ? "pp" : "ss",
01578 pbcy ? "pp" : "ss", pbcz ? "pp" : "ss");
01579 fprintf(data->fp, "%g %g %g\n", xmin[0], xmax[0], xy);
01580 fprintf(data->fp, "%g %g %g\n", xmin[1], xmax[1], xz);
01581 fprintf(data->fp, "%g %g %g\n", xmin[2], xmax[2], yz);
01582 }
01583
01584
01585 fprintf(data->fp, "ITEM: ATOMS id type xu yu zu\n");
01586 for (i = 0; i < data->numatoms; ++i) {
01587 fprintf(data->fp, " %d %d %g %g %g\n",
01588 i+1, data->atomtypes[i], pos[0], pos[1], pos[2]);
01589 pos += 3;
01590 }
01591
01592 data->nstep ++;
01593 return MOLFILE_SUCCESS;
01594 }
01595
01596
01597 static void close_lammps_write(void *mydata) {
01598 lammpsdata *data = (lammpsdata *)mydata;
01599
01600 fclose(data->fp);
01601 free(data->atomtypes);
01602 free(data->file_name);
01603 free(data);
01604 }
01605
01606
01607
01608 static molfile_plugin_t plugin;
01609
01610 VMDPLUGIN_API int VMDPLUGIN_init() {
01611 memset(&plugin, 0, sizeof(molfile_plugin_t));
01612 plugin.abiversion = vmdplugin_ABIVERSION;
01613 plugin.type = MOLFILE_PLUGIN_TYPE;
01614 plugin.name = "lammpstrj";
01615 plugin.prettyname = "LAMMPS Trajectory";
01616 plugin.author = "Marco Kalweit, Axel Kohlmeyer, Lutz Maibaum, John Stone";
01617 plugin.majorv = 0;
01618 plugin.minorv = 23;
01619 plugin.is_reentrant = VMDPLUGIN_THREADUNSAFE;
01620 #ifdef _USE_ZLIB
01621 plugin.filename_extension = "lammpstrj,lammpstrj.gz,dump,dump.gz";
01622 #else
01623 plugin.filename_extension = "lammpstrj,dump";
01624 #endif
01625 plugin.open_file_read = open_lammps_read;
01626 plugin.read_structure = read_lammps_structure;
01627 plugin.read_next_timestep = read_lammps_timestep;
01628 #if vmdplugin_ABIVERSION > 10
01629 plugin.read_timestep_metadata = read_timestep_metadata;
01630 #endif
01631 plugin.close_file_read = close_lammps_read;
01632 plugin.open_file_write = open_lammps_write;
01633 plugin.write_structure = write_lammps_structure;
01634 plugin.write_timestep = write_lammps_timestep;
01635 plugin.close_file_write = close_lammps_write;
01636
01637 return VMDPLUGIN_SUCCESS;
01638 }
01639
01640 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
01641 (*cb)(v, (vmdplugin_t *)&plugin);
01642 return VMDPLUGIN_SUCCESS;
01643 }
01644
01645 VMDPLUGIN_API int VMDPLUGIN_fini() {
01646 return VMDPLUGIN_SUCCESS;
01647 }
01648
01649 #ifdef TEST_PLUGIN
01650
01651 int main(int argc, char *argv[]) {
01652 molfile_timestep_t timestep;
01653 molfile_atom_t *atoms = NULL;
01654 void *v;
01655 int natoms;
01656 int i, j, opts;
01657 #if vmdplugin_ABIVERSION > 10
01658 molfile_timestep_metadata_t ts_meta;
01659 #endif
01660
01661 while (--argc >0) {
01662 ++argv;
01663 v = open_lammps_read(*argv, "lammpstrj", &natoms);
01664 if (!v) {
01665 fprintf(stderr, "open_lammps_read failed for file %s\n", *argv);
01666 return 1;
01667 }
01668 fprintf(stderr, "open_lammps_read succeeded for file %s\n", *argv);
01669 fprintf(stderr, "number of atoms: %d\n", natoms);
01670
01671 timestep.coords = (float *)malloc(3*sizeof(float)*natoms);
01672 atoms = (molfile_atom_t *)malloc(sizeof(molfile_atom_t)*natoms);
01673 if (read_lammps_structure(v, &opts, atoms) == MOLFILE_ERROR) {
01674 close_lammps_read(v);
01675 continue;
01676 }
01677
01678 fprintf(stderr, "read_lammps_structure: options=0x%08x\n", opts);
01679 #if 0
01680 for (i=0; i<natoms; ++i) {
01681 fprintf(stderr, "atom %09d: name=%s, type=%s, resname=%s, resid=%d, segid=%s, chain=%s\n",
01682 i, atoms[i].name, atoms[i].type, atoms[i].resname, atoms[i].resid,
01683 atoms[i].segid, atoms[i].chain);
01684 }
01685 #endif
01686 #if vmdplugin_ABIVERSION > 10
01687 read_timestep_metadata(v,&ts_meta);
01688 if (ts_meta.has_velocities) {
01689 fprintf(stderr, "found timestep velocities metadata.\n");
01690 }
01691 timestep.velocities = (float *) malloc(3*natoms*sizeof(float));
01692 #endif
01693 j = 0;
01694 while (!read_lammps_timestep(v, natoms, ×tep)) {
01695 for (i=0; i<10; ++i) {
01696 fprintf(stderr, "atom %09d: type=%s, resid=%d, time=%f "
01697 "x/y/z = %.3f %.3f %.3f "
01698 #if vmdplugin_ABIVERSION > 10
01699 "vx/vy/vz = %.3f %.3f %.3f "
01700 #endif
01701 "\n",
01702 i, atoms[i].type, atoms[i].resid, timestep.physical_time,
01703 timestep.coords[3*i], timestep.coords[3*i+1],
01704 timestep.coords[3*i+2]
01705 #if vmdplugin_ABIVERSION > 10
01706 ,timestep.velocities[3*i], timestep.velocities[3*i+1],
01707 timestep.velocities[3*i+2]
01708 #endif
01709 );
01710 }
01711 j++;
01712 }
01713 fprintf(stderr, "ended read_next_timestep on frame %d\n", j);
01714
01715 close_lammps_read(v);
01716 }
01717 #if vmdplugin_ABIVERSION > 10
01718 free(timestep.velocities);
01719 #endif
01720 free(timestep.coords);
01721 free(atoms);
01722 return 0;
01723 }
01724
01725 #endif