#include <stddef.h>
#include <ctype.h>
#include <math.h>
+#include <float.h>
#include "Missing.h"
#include "Dcd.h"
Int gSizeOfAtomRecord = sizeof(Atom);
+/* These are the pasteboard data type. Since the internal representation of the
+ pasteboard data includes binary data that may be dependent on the software version,
+ the revision number is appended to these strings on startup (See MyApp::OnInit()) */
+char *gMoleculePasteboardType = "Molecule";
+char *gParameterPasteboardType = "Parameter";
+
#pragma mark ====== Utility function ======
int
dst->nframes = 0;
}
}
- if (src->nconnects > ATOM_CONNECTS_LIMIT) {
- dst->connects.ptr = NULL;
- dst->nconnects = 0;
- NewArray(&(dst->connects.ptr), &(dst->nconnects), sizeof(Int), src->nconnects);
- memmove(dst->connects.ptr, src->connects.ptr, sizeof(Int) * src->nconnects);
+ if (src->connect.count > ATOM_CONNECT_LIMIT) {
+ dst->connect.u.ptr = NULL;
+ dst->connect.count = 0;
+ NewArray(&(dst->connect.u.ptr), &(dst->connect.count), sizeof(Int), src->connect.count);
+ memmove(dst->connect.u.ptr, src->connect.u.ptr, sizeof(Int) * src->connect.count);
+ }
+ if (src->anchor != NULL) {
+ dst->anchor = (PiAnchor *)malloc(sizeof(PiAnchor));
+ if (dst->anchor != NULL)
+ memmove(dst->anchor, src->anchor, sizeof(PiAnchor));
+ if (dst->anchor->connect.count > ATOM_CONNECT_LIMIT) {
+ dst->anchor->connect.u.ptr = NULL;
+ dst->anchor->connect.count = 0;
+ NewArray(&(dst->anchor->connect.u.ptr), &(dst->anchor->connect.count), sizeof(Int), src->anchor->connect.count);
+ memmove(dst->anchor->connect.u.ptr, src->anchor->connect.u.ptr, sizeof(Int) * src->anchor->connect.count);
+ }
+ if (dst->anchor->ncoeffs > 0) {
+ NewArray(&(dst->anchor->coeffs), &(dst->anchor->ncoeffs), sizeof(Double), src->anchor->ncoeffs);
+ memmove(dst->anchor->coeffs, src->anchor->coeffs, sizeof(Double) * src->anchor->ncoeffs);
+ }
}
return dst;
}
ap->frames = NULL;
ap->nframes = 0;
}
+ if (ap->connect.count > ATOM_CONNECT_LIMIT) {
+ ap->connect.count = 0;
+ free(ap->connect.u.ptr);
+ ap->connect.u.ptr = NULL;
+ }
}
void
free(bset->moenergies);
if (bset->scfdensities != NULL)
free(bset->scfdensities);
- if (bset->pos != NULL)
- free(bset->pos);
+/* if (bset->pos != NULL)
+ free(bset->pos); */
if (bset->nuccharges != NULL)
free(bset->nuccharges);
if (bset->cubes != NULL) {
free(bset);
}
-#define ATOM_CONNECTS_PTR(ap) ((ap)->nconnects > ATOM_CONNECTS_LIMIT ? (ap)->connects.ptr : (ap)->connects.data)
-
Int *
-AtomConnects(Atom *ap)
+AtomConnectData(AtomConnect *ac)
{
- if (ap == NULL)
+ if (ac == NULL)
return NULL;
- return ATOM_CONNECTS_PTR(ap);
-}
-
-Int
-AtomConnectEntryAtIndex(Atom *ap, Int idx)
-{
- if (ap != NULL)
- return -1;
- if (idx < 0 || idx >= ap->nconnects)
- return -1;
- return ATOM_CONNECTS_PTR(ap)[idx];
+ return ATOM_CONNECT_PTR(ac);
}
void
-AtomResizeConnects(Atom *ap, Int nconnects)
+AtomConnectResize(AtomConnect *ac, Int nconnects)
{
Int *p;
- if (ap == NULL)
+ if (ac == NULL)
return;
- if (nconnects <= ATOM_CONNECTS_LIMIT) {
- if (ap->nconnects > ATOM_CONNECTS_LIMIT) {
- p = ap->connects.ptr;
- memmove(ap->connects.data, p, sizeof(Int) * nconnects);
+ if (nconnects <= ATOM_CONNECT_LIMIT) {
+ if (ac->count > ATOM_CONNECT_LIMIT) {
+ p = ac->u.ptr;
+ memmove(ac->u.data, p, sizeof(Int) * nconnects);
free(p);
}
} else {
- if (ap->nconnects <= ATOM_CONNECTS_LIMIT) {
+ if (ac->count <= ATOM_CONNECT_LIMIT) {
p = NULL;
- ap->nconnects = 0;
- NewArray(&p, &(ap->nconnects), sizeof(Int), nconnects);
- memmove(p, ap->connects.data, sizeof(Int) * ap->nconnects);
- ap->connects.ptr = p;
- } else if (ap->nconnects < nconnects) {
+ ac->count = 0;
+ NewArray(&p, &(ac->count), sizeof(Int), nconnects);
+ memmove(p, ac->u.data, sizeof(Int) * ac->count);
+ ac->u.ptr = p;
+ } else if (ac->count < nconnects) {
/* Reallocate */
- AssignArray(&(ap->connects.ptr), &(ap->nconnects), sizeof(Int), nconnects - 1, NULL);
+ AssignArray(&(ac->u.ptr), &(ac->count), sizeof(Int), nconnects - 1, NULL);
}
}
- ap->nconnects = nconnects;
-}
-
-void
-AtomSetConnectEntry(Atom *ap, Int idx, Int connect)
-{
- if (ap == NULL)
- return;
- if (idx >= ap->nconnects) {
- /* Insert a new entry at the last */
- AtomResizeConnects(ap, idx + 1);
- }
- ATOM_CONNECTS_PTR(ap)[idx] = connect;
+ ac->count = nconnects;
}
void
-AtomInsertConnectEntry(Atom *ap, Int idx, Int connect)
+AtomConnectInsertEntry(AtomConnect *ac, Int idx, Int connect)
{
Int n, *p;
- if (ap == NULL)
+ if (ac == NULL)
return;
- if (idx < 0 || idx >= ap->nconnects)
- idx = ap->nconnects;
- AtomResizeConnects(ap, ap->nconnects + 1);
- n = ap->nconnects - idx - 1; /* Number of entries to be moved towards the bottom */
- p = ATOM_CONNECTS_PTR(ap);
+ if (idx > ac->count)
+ idx = ac->count;
+ else if (idx < 0) {
+ /* Insert after the last component that is smaller than connect
+ (i.e. keep them sorted) */
+ p = ATOM_CONNECT_PTR(ac);
+ for (idx = 0; idx < ac->count; idx++) {
+ if (p[idx] >= connect)
+ break;
+ }
+ }
+ AtomConnectResize(ac, ac->count + 1);
+ n = ac->count - idx - 1; /* Number of entries to be moved towards the end */
+ p = ATOM_CONNECT_PTR(ac);
if (n > 0) {
memmove(p + idx + 1, p + idx, sizeof(Int) * n);
}
}
void
-AtomDeleteConnectEntry(Atom *ap, Int idx)
+AtomConnectDeleteEntry(AtomConnect *ac, Int idx)
{
Int n, *p;
- if (ap == NULL)
+ if (ac == NULL)
return;
- if (idx < 0 || idx >= ap->nconnects)
+ if (idx < 0 || idx >= ac->count)
return;
- n = ap->nconnects - idx - 1; /* Number of entries to be moved towards the top */
- p = ATOM_CONNECTS_PTR(ap);
+ n = ac->count - idx - 1; /* Number of entries to be moved towards the top */
+ p = ATOM_CONNECT_PTR(ac);
if (n > 0) {
memmove(p + idx, p + idx + 1, sizeof(Int) * n);
}
- AtomResizeConnects(ap, ap->nconnects - 1);
+ AtomConnectResize(ac, ac->count - 1);
+}
+
+int
+AtomConnectHasEntry(AtomConnect *ac, Int ent)
+{
+ Int n, *p;
+ if (ac == NULL)
+ return 0;
+ p = ATOM_CONNECT_PTR(ac);
+ for (n = 0; n < ac->count; n++) {
+ if (ent == p[n])
+ return 1;
+ }
+ return 0;
}
#pragma mark ====== Accessor types ======
Panic("Cannot allocate new molecule record");
snprintf(name, sizeof name, "Untitled %d", sMoleculeUntitledCount++);
ObjectInit((Object *)mp, (Object **)&sMoleculeRoot, name);
+ mp->mview = MainView_new();
+ mp->mview->mol = mp;
return mp;
}
}
Molecule *
-MoleculeInitWithMolecule(Molecule *mp2, const Molecule *mp)
+MoleculeInitWithMolecule(Molecule *mp2, Molecule *mp)
{
+ int i, n;
+ MoleculeFlushFrames(mp);
MoleculeInitWithAtoms(mp2, mp->atoms, mp->natoms);
if (mp->nbonds > 0) {
if (NewArray(&mp2->bonds, &mp2->nbonds, sizeof(Int)*2, mp->nbonds) == NULL)
memmove(mp2->cell, mp->cell, sizeof(XtalCell));
}
if (mp->nsyms > 0) {
- mp2->nsyms = mp->nsyms;
- mp2->syms = (Transform *)calloc(sizeof(Transform), mp2->nsyms);
+ NewArray(&(mp2->syms), &(mp2->nsyms), sizeof(Transform), mp->nsyms);
memmove(mp2->syms, mp->syms, sizeof(Transform) * mp2->nsyms);
}
+
+ /* mp2->useFlexibleCell = mp->useFlexibleCell; */
+ if (mp->nframe_cells > 0) {
+ if (NewArray(&mp2->frame_cells, &mp2->nframe_cells, sizeof(Vector) * 4, mp->nframe_cells) == NULL)
+ goto error;
+ memmove(mp2->frame_cells, mp->frame_cells, sizeof(Vector) * 4 * mp->nframe_cells);
+ }
+
+ if (mp->nmolprops > 0) {
+ if (NewArray(&mp2->molprops, &mp2->nmolprops, sizeof(MolProp), mp->nmolprops) == NULL)
+ goto error;
+ n = MoleculeGetNumberOfFrames(mp);
+ for (i = 0; i < mp2->nmolprops; i++) {
+ mp2->molprops[i].propname = strdup(mp->molprops[i].propname);
+ mp2->molprops[i].propvals = (Double *)malloc(sizeof(Double) * n);
+ memcpy(mp2->molprops[i].propvals, mp->molprops[i].propvals, sizeof(Double) * n);
+ }
+ }
+
+ /* FIXME: should bset (basis set info) and elpot be duplicated or not? */
+
if (mp->par != NULL)
mp2->par = ParameterDuplicate(mp->par);
if (mp->arena != NULL) {
MoleculeRetain(Molecule *mp)
{
ObjectIncrRefCount((Object *)mp);
+ MoleculeRetainExternalObj(mp);
return mp;
}
void
MoleculeClear(Molecule *mp)
{
+ int i;
if (mp == NULL)
return;
if (mp->arena != NULL) {
ParameterRelease(mp->par);
mp->par = NULL;
}
- if (mp->bset != NULL) {
- BasisSetRelease(mp->bset);
- mp->bset = NULL;
- }
if (mp->atoms != NULL) {
- int i;
for (i = 0; i < mp->natoms; i++)
AtomClean(mp->atoms + i);
free(mp->atoms);
mp->residues = NULL;
mp->nresidues = 0;
}
+ if (mp->cell != NULL) {
+ free(mp->cell);
+ mp->cell = NULL;
+ }
+ if (mp->syms != NULL) {
+ free(mp->syms);
+ mp->syms = NULL;
+ mp->nsyms = 0;
+ }
+ if (mp->selection != NULL) {
+ IntGroupRelease(mp->selection);
+ mp->selection = NULL;
+ }
+ if (mp->frame_cells != NULL) {
+ free(mp->frame_cells);
+ mp->frame_cells = NULL;
+ mp->nframe_cells = 0;
+ }
+ if (mp->bset != NULL) {
+ BasisSetRelease(mp->bset);
+ mp->bset = NULL;
+ }
+ if (mp->mcube != NULL) {
+ MoleculeDeallocateMCube(mp->mcube);
+ mp->mcube = NULL;
+ }
+ if (mp->molprops != NULL) {
+ for (i = 0; i < mp->nmolprops; i++) {
+ free(mp->molprops[i].propname);
+ free(mp->molprops[i].propvals);
+ }
+ free(mp->molprops);
+ mp->molprops = NULL;
+ mp->nmolprops = 0;
+ }
+ if (mp->par != NULL) {
+ ParameterRelease(mp->par);
+ mp->par = NULL;
+ }
if (mp->elpots != NULL) {
free(mp->elpots);
mp->elpots = NULL;
{
if (mp == NULL)
return;
- if (mp->exmolobj != NULL)
- MoleculeReleaseExternalHook(mp);
+ MoleculeReleaseExternalObj(mp);
if (ObjectDecrRefCount((Object *)mp) == 0) {
MoleculeClear(mp);
+ mp->mview->mol = NULL;
+ MainView_release(mp->mview);
ObjectDealloc((Object *)mp, (Object **)&sMoleculeRoot);
}
}
return ReadLine(buf, size, stream, lineNumber);
}
+static int
+s_append_asprintf(char **buf, const char *fmt, ...)
+{
+ int len;
+ char *s;
+ va_list va;
+ va_start(va, fmt);
+ vasprintf(&s, fmt, va);
+ len = (*buf == NULL ? 0 : strlen(*buf));
+ if (s == NULL)
+ return len;
+ len += strlen(s);
+ if (*buf == NULL) {
+ *buf = malloc(len + 1);
+ **buf = 0;
+ } else {
+ *buf = realloc(*buf, len + 1);
+ }
+ strcat(*buf, s);
+ free(s);
+ return len;
+}
+
int
-MoleculeLoadFile(Molecule *mp, const char *fname, const char *ftype, char *errbuf, int errbufsize)
+MoleculeLoadFile(Molecule *mp, const char *fname, const char *ftype, char **errbuf)
{
int retval;
if (ftype == NULL || *ftype == 0) {
}
}
if (strcasecmp(ftype, "psf") == 0) {
- retval = MoleculeLoadPsfFile(mp, fname, errbuf, errbufsize);
+ retval = MoleculeLoadPsfFile(mp, fname, errbuf);
} else if (strcasecmp(ftype, "pdb") == 0) {
- retval = MoleculeReadCoordinatesFromPdbFile(mp, fname, errbuf, errbufsize);
+ retval = MoleculeReadCoordinatesFromPdbFile(mp, fname, errbuf);
} else if (strcasecmp(ftype, "tep") == 0) {
- retval = MoleculeLoadTepFile(mp, fname, errbuf, errbufsize);
+ retval = MoleculeLoadTepFile(mp, fname, errbuf);
} else if (strcasecmp(ftype, "res") == 0 || strcasecmp(ftype, "ins") == 0) {
- retval = MoleculeLoadShelxFile(mp, fname, errbuf, errbufsize);
+ retval = MoleculeLoadShelxFile(mp, fname, errbuf);
} else if (strcasecmp(ftype, "fchk") == 0 || strcasecmp(ftype, "fch") == 0) {
- retval = MoleculeLoadGaussianFchkFile(mp, fname, errbuf, errbufsize);
+ retval = MoleculeLoadGaussianFchkFile(mp, fname, errbuf);
} else {
- snprintf(errbuf, errbufsize, "Unknown format %s", ftype);
+ s_append_asprintf(errbuf, "Unknown format %s", ftype);
return 1;
}
/* if (retval != 0) {
}
int
-MoleculeLoadMbsfFile(Molecule *mp, const char *fname, char *errbuf, int errbufsize)
+MoleculeLoadMbsfFile(Molecule *mp, const char *fname, char **errbuf)
{
FILE *fp;
char buf[1024];
- int i, j, k, n, err, fn, nframes;
+ int i, j, k, err, fn, nframes, nwarnings;
int lineNumber;
int ibuf[12];
Int iibuf[4];
double dbuf[12];
- int mview_ibuf[16];
- float mview_fbuf[8];
+ int mview_ibuf[18];
+ double mview_dbuf[10];
char cbuf[12][8];
const char **pp;
char *bufp, *valp, *comp;
Atom *ap;
const int kUndefined = -10000000;
err = 0;
- if (errbuf == NULL) {
- errbuf = buf;
- errbufsize = 1024;
- }
- errbuf[0] = 0;
+ *errbuf = NULL;
+ nwarnings = 0;
if (mp->natoms != 0 || mp->par != NULL || mp->arena != NULL) {
- snprintf(errbuf, errbufsize, "The molecule must be empty");
+ s_append_asprintf(errbuf, "The molecule must be empty");
return 1;
}
fp = fopen(fname, "rb");
if (fp == NULL) {
- snprintf(errbuf, errbufsize, "Cannot open file");
+ s_append_asprintf(errbuf, "Cannot open file");
return 1;
}
- for (i = 0; i < 8; i++)
- mview_fbuf[i] = kUndefined;
- for (i = 0; i < 16; i++)
+ for (i = 0; i < 10; i++)
+ mview_dbuf[i] = kUndefined;
+ for (i = 0; i < 18; i++)
mview_ibuf[i] = kUndefined;
/* flockfile(fp); */
lineNumber = 0;
break;
/* idx seg_name res_seq res_name name type charge weight element atomic_number occupancy temp_factor int_charge */
if (sscanf(buf, "%d %6s %d %6s %6s %6s %lf %lf %6s %d %lf %lf %d", &ibuf[0], cbuf[0], &ibuf[1], cbuf[1], cbuf[2], cbuf[3], &dbuf[0], &dbuf[1], cbuf[4], &ibuf[2], &dbuf[2], &dbuf[3], &ibuf[3]) < 13) {
- snprintf(errbuf, errbufsize, "line %d: coordinates cannot be read for atom %d", lineNumber, mp->natoms + 1);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: coordinates cannot be read for atom %d", lineNumber, mp->natoms + 1);
+ goto err_exit;
}
ap = AssignArray(&mp->atoms, &mp->natoms, gSizeOfAtomRecord, mp->natoms, NULL);
strncpy(ap->segName, cbuf[0], 4);
break;
/* idx symop symbase */
if (sscanf(buf, "%d %d %d", &ibuf[0], &ibuf[1], &ibuf[2]) < 3) {
- snprintf(errbuf, errbufsize, "line %d: symmetry operations cannot be read for atom %d", lineNumber, i + 1);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: symmetry operations cannot be read for atom %d", lineNumber, i + 1);
+ goto err_exit;
}
if (i >= mp->natoms) {
- snprintf(errbuf, errbufsize, "line %d: too many atomic symmetry info\n", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: too many atomic symmetry info\n", lineNumber);
+ goto err_exit;
}
ap = ATOM_AT_INDEX(mp->atoms, i);
ap->symop.sym = ibuf[1] / 1000000;
break;
/* idx fix_force fix_pos */
if (sscanf(buf, "%d %lf %lf %lf %lf", &ibuf[0], &dbuf[0], &dbuf[1], &dbuf[2], &dbuf[3]) < 5) {
- snprintf(errbuf, errbufsize, "line %d: fix atom info cannot be read for atom %d", lineNumber, i + 1);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: fix atom info cannot be read for atom %d", lineNumber, i + 1);
+ goto err_exit;
}
if (i >= mp->natoms) {
- snprintf(errbuf, errbufsize, "line %d: too many fix atom info\n", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: too many fix atom info\n", lineNumber);
+ goto err_exit;
}
ap = ATOM_AT_INDEX(mp->atoms, i);
ap->fix_force = dbuf[0];
i++;
}
continue;
+ } else if (strcmp(buf, "!:uff_types") == 0) {
+ i = 0;
+ while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
+ if (buf[0] == '!')
+ continue;
+ if (buf[0] == '\n')
+ break;
+ /* idx uff_type */
+ if (sscanf(buf, "%d %6s", &ibuf[0], cbuf[0]) < 2) {
+ s_append_asprintf(errbuf, "line %d: uff type info cannot be read for atom %d", lineNumber, i + 1);
+ goto err_exit;
+ }
+ if (i >= mp->natoms) {
+ s_append_asprintf(errbuf, "line %d: too many uff type info\n", lineNumber);
+ goto err_exit;
+ }
+ ap = ATOM_AT_INDEX(mp->atoms, i);
+ strncpy(ap->uff_type, cbuf[0], 5);
+ ap->uff_type[5] = 0;
+ i++;
+ }
} else if (strcmp(buf, "!:mm_exclude") == 0) {
i = 0;
while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
break;
/* idx mm_exclude periodic_exclude */
if (sscanf(buf, "%d %d %d", &ibuf[0], &ibuf[1], &ibuf[2]) < 3) {
- snprintf(errbuf, errbufsize, "line %d: mm_exclude flags cannot be read for atom %d", lineNumber, i + 1);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: mm_exclude flags cannot be read for atom %d", lineNumber, i + 1);
+ goto err_exit;
}
if (i >= mp->natoms) {
- snprintf(errbuf, errbufsize, "line %d: too many mm_exclude flags\n", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: too many mm_exclude flags\n", lineNumber);
+ goto err_exit;
}
ap = ATOM_AT_INDEX(mp->atoms, i);
ap->mm_exclude = (ibuf[1] != 0);
i++;
}
continue;
+ } else if (strcmp(buf, "!:pi_anchor") == 0) {
+ while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
+ if (buf[0] == '!')
+ continue;
+ if (buf[0] == '\n')
+ break;
+ /* idx count */
+ if ((j = sscanf(buf, "%d %d", &ibuf[0], &ibuf[1])) < 2) {
+ s_append_asprintf(errbuf, "line %d: bad format for pi_anchor", lineNumber);
+ goto err_exit;
+ }
+ i = ibuf[0];
+ ap = ATOM_AT_INDEX(mp->atoms, i);
+ if (ap->anchor != NULL) {
+ s_append_asprintf(errbuf, "line %d: warning: duplicate pi_anchor entry", lineNumber);
+ AtomConnectResize(&ap->anchor->connect, 0);
+ free(ap->anchor->coeffs);
+ free(ap->anchor);
+ }
+ ap->anchor = (PiAnchor *)calloc(sizeof(PiAnchor), 1);
+ if (ibuf[1] < 2 || ibuf[1] >= mp->natoms) {
+ s_append_asprintf(errbuf, "line %d: bad number of components for pi_anchor", lineNumber);
+ goto err_exit;
+ }
+ AtomConnectResize(&ap->anchor->connect, ibuf[1]);
+ ip = AtomConnectData(&ap->anchor->connect);
+ NewArray(&ap->anchor->coeffs, &ap->anchor->ncoeffs, sizeof(Double), ibuf[1]);
+ j = ibuf[1];
+ for (i = 0; i < j; i++) {
+ if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0) {
+ s_append_asprintf(errbuf, "line %d: unexpected end of file while reading pi_anchors", lineNumber);
+ goto err_exit;
+ }
+ if (sscanf(buf, "%d %lf", &ibuf[0], &dbuf[0]) < 2) {
+ s_append_asprintf(errbuf, "line %d: bad format for pi_anchor", lineNumber);
+ goto err_exit;
+ }
+ if (ibuf[0] < 0 || ibuf[0] >= mp->natoms) {
+ s_append_asprintf(errbuf, "line %d: atom index out of range", lineNumber);
+ goto err_exit;
+ }
+ if (dbuf[0] <= 0.0) {
+ s_append_asprintf(errbuf, "line %d: the pi anchor weights should be positive", lineNumber);
+ goto err_exit;
+ }
+ ip[i] = ibuf[0];
+ ap->anchor->coeffs[i] = dbuf[0];
+ }
+ }
+ continue;
} else if (strcmp(buf, "!:positions") == 0) {
i = 0;
while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
break;
/* idx x y z */
if ((j = sscanf(buf, "%d %lf %lf %lf %lf %lf %lf", &ibuf[0], &dbuf[0], &dbuf[1], &dbuf[2], &dbuf[3], &dbuf[4], &dbuf[5])) < 4) {
- snprintf(errbuf, errbufsize, "line %d: atom position cannot be read for atom %d frame %d", lineNumber, i + 1, nframes);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: atom position cannot be read for atom %d frame %d", lineNumber, i + 1, nframes);
+ goto err_exit;
}
if (j > 4 && nframes != 0) {
- snprintf(errbuf, errbufsize, "line %d: atom position sigma can only be given for frame 0", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: atom position sigma can only be given for frame 0", lineNumber);
+ goto err_exit;
}
if (j > 4 && j != 7) {
- snprintf(errbuf, errbufsize, "line %d: atom position sigma cannot be read for atom %d frame %d", lineNumber, i + 1, nframes);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: atom position sigma cannot be read for atom %d frame %d", lineNumber, i + 1, nframes);
+ goto err_exit;
}
if (i >= mp->natoms) {
- snprintf(errbuf, errbufsize, "line %d: too many atom position records\n", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: too many atom position records\n", lineNumber);
+ goto err_exit;
}
v.x = dbuf[0];
v.y = dbuf[1];
/* from1 to1 from2 to2 from3 to3 from4 to4 */
i = sscanf(buf, "%d %d %d %d %d %d %d %d", &ibuf[0], &ibuf[1], &ibuf[2], &ibuf[3], &ibuf[4], &ibuf[5], &ibuf[6], &ibuf[7]);
if (i < 2 || i % 2 != 0) {
- snprintf(errbuf, errbufsize, "line %d: bad bond format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: bad bond format", lineNumber);
+ goto err_exit;
}
for (j = 0; j < i; j += 2) {
iibuf[0] = ibuf[j];
iibuf[1] = ibuf[j + 1];
if (iibuf[0] < 0 || iibuf[0] >= mp->natoms || iibuf[1] < 0 || iibuf[1] >= mp->natoms || iibuf[0] == iibuf[1]) {
- snprintf(errbuf, errbufsize, "line %d: bad bond format", lineNumber);
- goto exit;
- }
- AssignArray(&mp->bonds, &mp->nbonds, sizeof(Int) * 2, mp->nbonds, iibuf);
- for (k = 0; k < 2; k++) {
- const Int *cp;
- ap = ATOM_AT_INDEX(mp->atoms, iibuf[k]);
- cp = AtomConnects(ap);
- for (n = 0; n < ap->nconnects; n++, cp++) {
- if (*cp == iibuf[1 - k])
- break;
- }
- if (n >= ap->nconnects) {
- /* if (ap->nconnects >= ATOMS_MAX_CONNECTS - 1) {
- snprintf(errbuf, errbufsize, "line %d: too many bonds on atom %d", lineNumber, iibuf[k]);
- goto exit;
- } */
- AtomInsertConnectEntry(ap, ap->nconnects, iibuf[1 - k]);
- }
+ s_append_asprintf(errbuf, "line %d: warning: bad bond specification (%d-%d) - skipped\n", lineNumber, iibuf[0], iibuf[1]);
+ nwarnings++;
+ } else if (AtomConnectHasEntry(&(ATOM_AT_INDEX(mp->atoms, iibuf[0])->connect), iibuf[1])) {
+ s_append_asprintf(errbuf, "line %d: warning: bond %d-%d is already present - skipped\n", lineNumber, iibuf[0], iibuf[1]);
+ nwarnings++;
+ } else {
+ AssignArray(&mp->bonds, &mp->nbonds, sizeof(Int) * 2, mp->nbonds, iibuf);
+ AtomConnectInsertEntry(&(ATOM_AT_INDEX(mp->atoms, iibuf[0])->connect), -1, iibuf[1]);
+ AtomConnectInsertEntry(&(ATOM_AT_INDEX(mp->atoms, iibuf[1])->connect), -1, iibuf[0]);
}
}
}
continue;
+ } else if (strcmp(buf, "!:bond_orders") == 0) {
+ while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
+ if (buf[0] == '!')
+ continue;
+ if (buf[0] == '\n')
+ break;
+ /* b1 b2 b3 b4 */
+ i = sscanf(buf, "%lf %lf %lf %lf", &dbuf[0], &dbuf[1], &dbuf[2], &dbuf[3]);
+ if (i == 0) {
+ s_append_asprintf(errbuf, "line %d: bad bond order format", lineNumber);
+ goto err_exit;
+ }
+ for (j = 0; j < i; j++) {
+ AssignArray(&mp->bondOrders, &mp->nbondOrders, sizeof(Double), mp->nbondOrders, &dbuf[j]);
+ }
+ }
+ if (mp->nbondOrders > mp->nbonds) {
+ s_append_asprintf(errbuf, "line %d: warning: the number of bond order info (%d) exceeds number of bonds (%d) - ignoring excess info\n", lineNumber, mp->nbondOrders, mp->nbonds);
+ nwarnings++;
+ mp->nbondOrders = mp->nbonds;
+ } else if (mp->nbondOrders < mp->nbonds) {
+ s_append_asprintf(errbuf, "line %d: warning: the number of bond order info (%d) is less than number of bonds (%d)\n", lineNumber, mp->nbondOrders, mp->nbonds);
+ nwarnings++;
+ j = mp->nbondOrders;
+ AssignArray(&mp->bondOrders, &mp->nbondOrders, sizeof(Double), mp->nbonds - 1, NULL);
+ for (i = j; i < mp->nbonds; i++)
+ mp->bondOrders[i] = 0.0;
+ }
+ continue;
+
} else if (strcmp(buf, "!:angles") == 0) {
while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
if (buf[0] == '!')
/* a1 b1 c1 a2 b2 c2 a3 b3 c3 */
i = sscanf(buf, "%d %d %d %d %d %d %d %d %d", &ibuf[0], &ibuf[1], &ibuf[2], &ibuf[3], &ibuf[4], &ibuf[5], &ibuf[6], &ibuf[7], &ibuf[8]);
if (i == 0 || i % 3 != 0) {
- snprintf(errbuf, errbufsize, "line %d: bad angle format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: bad angle format", lineNumber);
+ goto err_exit;
}
for (j = 0; j < i; j += 3) {
iibuf[0] = ibuf[j];
iibuf[1] = ibuf[j + 1];
iibuf[2] = ibuf[j + 2];
if (iibuf[0] < 0 || iibuf[0] >= mp->natoms || iibuf[1] < 0 || iibuf[1] >= mp->natoms || iibuf[2] < 0 || iibuf[2] >= mp->natoms || iibuf[0] == iibuf[1] || iibuf[1] == iibuf[2]) {
- snprintf(errbuf, errbufsize, "line %d: bad angle format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: warning: bad angle specification (%d-%d-%d) - skipped\n", lineNumber, iibuf[0], iibuf[1], iibuf[2]);
+ nwarnings++;
+ } else if (MoleculeAreAtomsConnected(mp, iibuf[1], iibuf[0]) == 0 || MoleculeAreAtomsConnected(mp, iibuf[1], iibuf[2]) == 0) {
+ s_append_asprintf(errbuf, "line %d: warning: angle with non-bonded atoms (%d-%d-%d) - skipped\n", lineNumber, iibuf[0], iibuf[1], iibuf[2]);
+ nwarnings++;
+ } else if (MoleculeLookupAngle(mp, iibuf[0], iibuf[1], iibuf[2]) >= 0) {
+ s_append_asprintf(errbuf, "line %d: warning: angle %d-%d-%d is already present - skipped\n", lineNumber, iibuf[0], iibuf[1], iibuf[2]);
+ nwarnings++;
+ } else {
+ AssignArray(&mp->angles, &mp->nangles, sizeof(Int) * 3, mp->nangles, iibuf);
}
- AssignArray(&mp->angles, &mp->nangles, sizeof(Int) * 3, mp->nangles, iibuf);
}
}
continue;
/* a1 b1 c1 d1 a2 b2 c2 d2 */
i = sscanf(buf, "%d %d %d %d %d %d %d %d", &ibuf[0], &ibuf[1], &ibuf[2], &ibuf[3], &ibuf[4], &ibuf[5], &ibuf[6], &ibuf[7]);
if (i == 0 || i % 4 != 0) {
- snprintf(errbuf, errbufsize, "line %d: bad dihedral format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: bad dihedral format", lineNumber);
+ goto err_exit;
}
for (j = 0; j < i; j += 4) {
iibuf[0] = ibuf[j];
iibuf[2] = ibuf[j + 2];
iibuf[3] = ibuf[j + 3];
if (iibuf[0] < 0 || iibuf[0] >= mp->natoms || iibuf[1] < 0 || iibuf[1] >= mp->natoms || iibuf[2] < 0 || iibuf[2] >= mp->natoms || iibuf[3] < 0 || iibuf[3] >= mp->natoms || iibuf[0] == iibuf[1] || iibuf[1] == iibuf[2] || iibuf[2] == iibuf[3] || iibuf[0] == iibuf[2] || iibuf[1] == iibuf[3] || iibuf[0] == iibuf[3]) {
- snprintf(errbuf, errbufsize, "line %d: bad dihedral format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: warning: bad dihedral specification (%d-%d-%d-%d) - skipped\n", lineNumber, iibuf[0], iibuf[1], iibuf[2], iibuf[3]);
+ nwarnings++;
+ } else if (MoleculeAreAtomsConnected(mp, iibuf[1], iibuf[0]) == 0 || MoleculeAreAtomsConnected(mp, iibuf[1], iibuf[2]) == 0 || MoleculeAreAtomsConnected(mp, iibuf[2], iibuf[3]) == 0) {
+ s_append_asprintf(errbuf, "line %d: warning: dihedral with non-bonded atoms (%d-%d-%d-%d) - skipped\n", lineNumber, iibuf[0], iibuf[1], iibuf[2], iibuf[3]);
+ nwarnings++;
+ } else if (MoleculeLookupDihedral(mp, iibuf[0], iibuf[1], iibuf[2], iibuf[3]) >= 0) {
+ s_append_asprintf(errbuf, "line %d: warning: dihedral %d-%d-%d-%d is already present - skipped\n", lineNumber, iibuf[0], iibuf[1], iibuf[2], iibuf[3]);
+ nwarnings++;
+ } else {
+ AssignArray(&mp->dihedrals, &mp->ndihedrals, sizeof(Int) * 4, mp->ndihedrals, iibuf);
}
- AssignArray(&mp->dihedrals, &mp->ndihedrals, sizeof(Int) * 4, mp->ndihedrals, iibuf);
}
}
continue;
/* a1 b1 c1 d1 a2 b2 c2 d2 */
i = sscanf(buf, "%d %d %d %d %d %d %d %d", &ibuf[0], &ibuf[1], &ibuf[2], &ibuf[3], &ibuf[4], &ibuf[5], &ibuf[6], &ibuf[7]);
if (i == 0 || i % 4 != 0) {
- snprintf(errbuf, errbufsize, "line %d: bad improper format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: bad improper format", lineNumber);
+ goto err_exit;
}
for (j = 0; j < i; j += 4) {
iibuf[0] = ibuf[j];
iibuf[2] = ibuf[j + 2];
iibuf[3] = ibuf[j + 3];
if (iibuf[0] < 0 || iibuf[0] >= mp->natoms || iibuf[1] < 0 || iibuf[1] >= mp->natoms || iibuf[2] < 0 || iibuf[2] >= mp->natoms || iibuf[3] < 0 || iibuf[3] >= mp->natoms || iibuf[0] == iibuf[1] || iibuf[1] == iibuf[2] || iibuf[2] == iibuf[3] || iibuf[0] == iibuf[2] || iibuf[1] == iibuf[3] || iibuf[0] == iibuf[3]) {
- snprintf(errbuf, errbufsize, "line %d: bad improper format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: warning: bad improper specification (%d-%d-%d-%d) - skipped\n", lineNumber, iibuf[0], iibuf[1], iibuf[2], iibuf[3]);
+ nwarnings++;
+ } else if (MoleculeAreAtomsConnected(mp, iibuf[2], iibuf[0]) == 0 || MoleculeAreAtomsConnected(mp, iibuf[2], iibuf[1]) == 0 || MoleculeAreAtomsConnected(mp, iibuf[2], iibuf[3]) == 0) {
+ s_append_asprintf(errbuf, "line %d: warning: improper with non-bonded atoms (%d-%d-%d-%d) - skipped\n", lineNumber, iibuf[0], iibuf[1], iibuf[2], iibuf[3]);
+ nwarnings++;
+ } else if (MoleculeLookupImproper(mp, iibuf[0], iibuf[1], iibuf[2], iibuf[3]) >= 0) {
+ s_append_asprintf(errbuf, "line %d: warning: improper %d-%d-%d-%d is already present - skipped\n", lineNumber, iibuf[0], iibuf[1], iibuf[2], iibuf[3]);
+ nwarnings++;
+ } else {
+ AssignArray(&mp->impropers, &mp->nimpropers, sizeof(Int) * 4, mp->nimpropers, iibuf);
}
- AssignArray(&mp->impropers, &mp->nimpropers, sizeof(Int) * 4, mp->nimpropers, iibuf);
}
}
continue;
break;
/* a b c alpha beta gamma [sigmaflag] */
if ((j = sscanf(buf, "%lf %lf %lf %lf %lf %lf %d", &dbuf[0], &dbuf[1], &dbuf[2], &dbuf[3], &dbuf[4], &dbuf[5], &ibuf[0])) < 6) {
- snprintf(errbuf, errbufsize, "line %d: bad xtalcell format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: bad xtalcell format", lineNumber);
+ goto err_exit;
}
MoleculeSetCell(mp, dbuf[0], dbuf[1], dbuf[2], dbuf[3], dbuf[4], dbuf[5], 0);
if (j == 7 && ibuf[0] != 0) {
if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0) {
- snprintf(errbuf, errbufsize, "line %d: sigma for xtalcell are missing", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: sigma for xtalcell are missing", lineNumber);
+ goto err_exit;
}
if (sscanf(buf, "%lf %lf %lf %lf %lf %lf", &dbuf[0], &dbuf[1], &dbuf[2], &dbuf[3], &dbuf[4], &dbuf[5]) < 6) {
- snprintf(errbuf, errbufsize, "line %d: bad xtalcell sigma format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf,"line %d: bad xtalcell sigma format", lineNumber);
+ goto err_exit;
}
if (mp->cell != NULL) {
mp->cell->has_sigma = 1;
mp->cell->cellsigma[i] = dbuf[i];
}
} else {
- snprintf(errbuf, errbufsize, "line %d: cell sigma are given while cell is not given", lineNumber);
+ s_append_asprintf(errbuf, "line %d: cell sigma are given while cell is not given", lineNumber);
}
}
}
break;
/* a11 a12 a13; a21 a22 a23; a31 a32 a33; t1 t2 t3 */
if (sscanf(buf, "%lf %lf %lf", &dbuf[0], &dbuf[1], &dbuf[2]) < 3) {
- snprintf(errbuf, errbufsize, "line %d: bad symmetry_operation format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: bad symmetry_operation format", lineNumber);
+ goto err_exit;
}
if (i < 3) {
tr[i] = dbuf[0];
break;
/* b11 b22 b33 b12 b13 b23 [has_sigma] */
if ((j = sscanf(buf, "%lf %lf %lf %lf %lf %lf %d", &dbuf[0], &dbuf[1], &dbuf[2], &dbuf[3], &dbuf[4], &dbuf[5], &ibuf[0])) < 6) {
- snprintf(errbuf, errbufsize, "line %d: anisotropic thermal parameters cannot be read for atom %d", lineNumber, i + 1);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: anisotropic thermal parameters cannot be read for atom %d", lineNumber, i + 1);
+ goto err_exit;
}
if (i >= mp->natoms) {
- snprintf(errbuf, errbufsize, "line %d: too many anisotropic thermal parameters\n", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: too many anisotropic thermal parameters\n", lineNumber);
+ goto err_exit;
}
if (dbuf[0] == 0.0 && dbuf[1] == 0.0 && dbuf[2] == 0.0 && dbuf[3] == 0.0 && dbuf[4] == 0.0 && dbuf[5] == 0.0) {
/* Skip it */
}
if (j == 7 && ibuf[0] != 0) {
if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0) {
- snprintf(errbuf, errbufsize, "line %d: anisotropic thermal parameters sigma missing", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: anisotropic thermal parameters sigma missing", lineNumber);
+ goto err_exit;
}
if (sscanf(buf, "%lf %lf %lf %lf %lf %lf", &dbuf[0], &dbuf[1], &dbuf[2], &dbuf[3], &dbuf[4], &dbuf[5]) < 6) {
- snprintf(errbuf, errbufsize, "line %d: anisotropic thermal parameters sigma cannot be read for atom %d", lineNumber, i + 1);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: anisotropic thermal parameters sigma cannot be read for atom %d", lineNumber, i + 1);
+ goto err_exit;
}
ap = ATOM_AT_INDEX(mp->atoms, i);
if (ap->aniso == NULL) {
- snprintf(errbuf, errbufsize, "line %d: anisotropic thermal parameters sigma are given while the parameters are not given", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: anisotropic thermal parameters sigma are given while the parameters are not given", lineNumber);
+ goto err_exit;
}
ap->aniso->has_bsig = 1;
for (j = 0; j < 6; j++)
/* ax ay az; bx by bz; cx cy cz; ox oy oz; fx fy fz [sigma; sa sb sc s_alpha s_beta s_gamma] */
if (i < 4) {
if (sscanf(buf, "%lf %lf %lf", &dbuf[0], &dbuf[1], &dbuf[2]) < 3) {
- snprintf(errbuf, errbufsize, "line %d: bad periodic_box format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: bad periodic_box format", lineNumber);
+ goto err_exit;
}
vs[i].x = dbuf[0];
vs[i].y = dbuf[1];
continue;
}
if ((j = sscanf(buf, "%d %d %d %d", &ibuf[0], &ibuf[1], &ibuf[2], &ibuf[3])) < 3) {
- snprintf(errbuf, errbufsize, "line %d: bad periodic_box format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: bad periodic_box format", lineNumber);
+ goto err_exit;
}
if (j == 4 && ibuf[3] != 0)
has_sigma = 1;
cbuf[0][0] = ibuf[0];
cbuf[0][1] = ibuf[1];
cbuf[0][2] = ibuf[2];
- MoleculeSetPeriodicBox(mp, vs, vs + 1, vs + 2, vs + 3, cbuf[0]);
+ MoleculeSetPeriodicBox(mp, vs, vs + 1, vs + 2, vs + 3, cbuf[0], 0);
if (has_sigma) {
if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0) {
- snprintf(errbuf, errbufsize, "line %d: sigma for cell parameters are missing", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: sigma for cell parameters are missing", lineNumber);
+ goto err_exit;
}
if (sscanf(buf, "%lf %lf %lf %lf %lf %lf", &dbuf[0], &dbuf[1], &dbuf[2], &dbuf[3], &dbuf[4], &dbuf[5]) < 6) {
- snprintf(errbuf, errbufsize, "line %d: bad periodic_box sigma format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: bad periodic_box sigma format", lineNumber);
+ goto err_exit;
}
if (mp->cell != NULL) {
mp->cell->has_sigma = 1;
mp->cell->cellsigma[i] = dbuf[i];
}
} else {
- snprintf(errbuf, errbufsize, "line %d: cell sigma are given while cell is not given", lineNumber);
+ s_append_asprintf(errbuf, "line %d: cell sigma are given while cell is not given", lineNumber);
}
}
break;
} else if (strcmp(buf, "!:frame_periodic_boxes") == 0) {
Vector vs[5];
i = 0;
+ /* mp->useFlexibleCell = 1; *//* The presence of this block causes asserting this flag */
while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
if (buf[0] == '!')
continue;
if (buf[0] == '\n')
break;
- if (sscanf(buf, "%lf %lf %f", &dbuf[0], &dbuf[1], &dbuf[2]) < 3) {
- snprintf(errbuf, errbufsize, "line %d: bad frame_periodic_box format", lineNumber);
- goto exit;
+ if (sscanf(buf, "%lf %lf %lf", &dbuf[0], &dbuf[1], &dbuf[2]) < 3) {
+ s_append_asprintf(errbuf, "line %d: bad frame_periodic_box format", lineNumber);
+ goto err_exit;
}
vs[i].x = dbuf[0];
vs[i].y = dbuf[1];
i = 0;
}
}
+ if (mp->cframe < mp->nframe_cells) {
+ /* mp->cframe should already have been set when positions are read */
+ Vector *vp = &mp->frame_cells[mp->cframe * 4];
+ static char defaultFlags[] = {1, 1, 1};
+ char *flags = (mp->cell != NULL ? mp->cell->flags : defaultFlags);
+ MoleculeSetPeriodicBox(mp, vp, vp + 1, vp + 2, vp + 3, flags, 0);
+ }
continue;
} else if (strcmp(buf, "!:md_parameters") == 0) {
MDArena *arena;
while ((k = fgetc(fp)) >= 0) {
ungetc(k, fp);
if (k < '0' || k > '9') {
- snprintf(errbuf, errbufsize, "line %d: too few flags in alchem_flags block", lineNumber + 1);
+ s_append_asprintf(errbuf, "line %d: too few flags in alchem_flags block", lineNumber + 1);
free(valp);
- goto exit;
+ goto err_exit;
}
ReadLine(buf, sizeof buf, fp, &lineNumber);
bufp = buf;
while (*bufp != 0) {
if (*bufp >= '0' && *bufp <= '2') {
if (i >= j) {
- snprintf(errbuf, errbufsize, "line %d: too many flags in alchem_flags block", lineNumber);
+ s_append_asprintf(errbuf, "line %d: too many flags in alchem_flags block", lineNumber);
free(valp);
- goto exit;
+ goto err_exit;
}
valp[i++] = *bufp - '0';
} else if (*bufp != ' ' && *bufp != '\t' && *bufp != '\n') {
- snprintf(errbuf, errbufsize, "line %d: strange character (0x%02x) in alchem_flags block", lineNumber, (int)*bufp);
+ s_append_asprintf(errbuf, "line %d: strange character (0x%02x) in alchem_flags block", lineNumber, (int)*bufp);
free(valp);
- goto exit;
+ goto err_exit;
}
bufp++;
}
|| (strcmp(comp, "cutoff") == 0 && (dp = &arena->cutoff) != NULL)
|| (strcmp(comp, "electro_cutoff") == 0 && (dp = &arena->electro_cutoff) != NULL)
|| (strcmp(comp, "pairlist_distance") == 0 && (dp = &arena->pairlist_distance) != NULL)
+ || (strcmp(comp, "switch_distance") == 0 && (dp = &arena->switch_distance) != NULL)
|| (strcmp(comp, "temperature") == 0 && (dp = &arena->temperature) != NULL)
|| (strcmp(comp, "andersen_coupling") == 0 && (dp = &arena->andersen_thermo_coupling) != NULL)
|| (strcmp(comp, "dielectric") == 0 && (dp = &arena->dielectric) != NULL)
} else valp = NULL;
if (strcmp(comp, "pressure") == 0) {
if (sscanf(valp, "%lf %lf %lf %lf %lf %lf %lf %lf %lf", &dbuf[0], &dbuf[1], &dbuf[2], &dbuf[3], &dbuf[4], &dbuf[5], &dbuf[6], &dbuf[7], &dbuf[8]) < 9) {
- snprintf(errbuf, errbufsize, "line %d: bad format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: bad format", lineNumber);
+ goto err_exit;
}
for (i = 0; i < 9; i++)
pressure->apply[i] = dbuf[i];
} else if (strcmp(comp, "pressure_cell_flexibility") == 0) {
if (sscanf(valp, "%lf %lf %lf %lf %lf %lf %lf %lf", &dbuf[0], &dbuf[1], &dbuf[2], &dbuf[3], &dbuf[4], &dbuf[5], &dbuf[6], &dbuf[7]) < 8) {
- snprintf(errbuf, errbufsize, "line %d: bad format", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: bad format", lineNumber);
+ goto err_exit;
}
for (i = 0; i < 8; i++)
pressure->cell_flexibility[i] = dbuf[i];
break;
/* idx vx vy vz */
if (sscanf(buf, "%d %lf %lf %lf", &ibuf[0], &dbuf[0], &dbuf[1], &dbuf[2]) < 4) {
- snprintf(errbuf, errbufsize, "line %d: atom velocity cannot be read for atom %d", lineNumber, i + 1);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: atom velocity cannot be read for atom %d", lineNumber, i + 1);
+ goto err_exit;
}
if (i >= mp->natoms) {
- snprintf(errbuf, errbufsize, "line %d: too many atom velocity records\n", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: too many atom velocity records\n", lineNumber);
+ goto err_exit;
}
ap = ATOM_AT_INDEX(mp->atoms, i);
ap->v.x = dbuf[0];
break;
/* idx fx fy fz */
if (sscanf(buf, "%d %lf %lf %lf", &ibuf[0], &dbuf[0], &dbuf[1], &dbuf[2]) < 4) {
- snprintf(errbuf, errbufsize, "line %d: atom force cannot be read for atom %d", lineNumber, i + 1);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: atom force cannot be read for atom %d", lineNumber, i + 1);
+ goto err_exit;
}
if (i >= mp->natoms) {
- snprintf(errbuf, errbufsize, "line %d: too many atom force records\n", lineNumber);
- goto exit;
+ s_append_asprintf(errbuf, "line %d: too many atom force records\n", lineNumber);
+ goto err_exit;
}
ap = ATOM_AT_INDEX(mp->atoms, i);
ap->f.x = dbuf[0];
break;
j = ParameterReadFromString(par, buf, &bufp, fname, lineNumber, 0);
if (j < 0) {
- snprintf(errbuf, errbufsize, "%s", bufp);
- goto exit;
+ s_append_asprintf(errbuf, "%s", bufp);
+ free(bufp);
+ goto err_exit;
}
i += j;
}
if (bufp != NULL) {
- MyAppCallback_setConsoleColor(1);
- MyAppCallback_showScriptMessage("%s", bufp);
- MyAppCallback_setConsoleColor(0);
+ s_append_asprintf(errbuf, "%s", bufp);
free(bufp);
}
continue;
continue;
if (buf[0] == '\n')
break;
+ if (mp->mview == NULL || mp->mview->track == NULL)
+ continue; /* Skip (this should not happen though) */
/* scale; trx try trz; theta_deg x y z */
- if ((i == 0 && sscanf(buf, "%f", &mview_fbuf[0]) < 1)
- || (i == 1 && sscanf(buf, "%f %f %f",
- &mview_fbuf[1], &mview_fbuf[2], &mview_fbuf[3]) < 3)
- || (i == 2 && sscanf(buf, "%f %f %f %f",
- &mview_fbuf[4], &mview_fbuf[5], &mview_fbuf[6], &mview_fbuf[7]) < 4)) {
- snprintf(errbuf, errbufsize, "line %d: bad trackball format", lineNumber);
- goto exit;
+ if ((i == 0 && sscanf(buf, "%lf", &dbuf[0]) < 1)
+ || (i == 1 && sscanf(buf, "%lf %lf %lf",
+ &dbuf[1], &dbuf[2], &dbuf[3]) < 3)
+ || (i == 2 && sscanf(buf, "%lf %lf %lf %lf",
+ &dbuf[4], &dbuf[5], &dbuf[6], &dbuf[7]) < 4)) {
+ s_append_asprintf(errbuf, "line %d: bad trackball format", lineNumber);
+ goto err_exit;
}
+ if (i == 0)
+ TrackballSetScale(mp->mview->track, dbuf[0]);
+ else if (i == 1)
+ TrackballSetTranslate(mp->mview->track, dbuf + 1);
+ else if (i == 2)
+ TrackballSetRotate(mp->mview->track, dbuf + 4);
i++;
}
continue;
continue;
if (buf[0] == '\n')
break;
+ if (mp->mview == NULL)
+ continue; /* Skip (this should not happen, though) */
bufp = buf;
comp = strsep(&bufp, " \t");
if (bufp != NULL) {
bufp++;
valp = strsep(&bufp, "\n");
} else valp = NULL;
- /* In the following, the redundant "!= NULL" is to suppress suprious warning */
- if ((strcmp(comp, "show_unit_cell") == 0 && (i = 1))
- || (strcmp(comp, "show_periodic_box") == 0 && (i = 2))
- || (strcmp(comp, "show_expanded_atoms") == 0 && (i = 3))
- || (strcmp(comp, "show_ellipsoids") == 0 && (i = 4))
- || (strcmp(comp, "show_hydrogens") == 0 && (i = 5))
- || (strcmp(comp, "show_dummy_atoms") == 0 && (i = 6))
- || (strcmp(comp, "show_rotation_center") == 0 && (i = 7))
- || (strcmp(comp, "show_graphite_flag") == 0 && (i = 8))
- || (strcmp(comp, "show_periodic_image_flag") == 0 && (i = 9))
- || (strcmp(comp, "show_graphite") == 0 && (i = 10))) {
- mview_ibuf[i - 1] = atoi(valp);
- } else if (strcmp(comp, "show_periodic_image") == 0) {
- sscanf(valp, "%d %d %d %d %d %d",
- &mview_ibuf[10], &mview_ibuf[11], &mview_ibuf[12],
- &mview_ibuf[13], &mview_ibuf[14], &mview_ibuf[15]);
+ if (strcmp(comp, "show_unit_cell") == 0)
+ mp->mview->showUnitCell = atoi(valp);
+ else if (strcmp(comp, "show_periodic_box") == 0)
+ mp->mview->showPeriodicBox = atoi(valp);
+ else if (strcmp(comp, "show_expanded_atoms") == 0)
+ mp->mview->showExpandedAtoms = atoi(valp);
+ else if (strcmp(comp, "show_ellipsoids") == 0)
+ mp->mview->showEllipsoids = atoi(valp);
+ else if (strcmp(comp, "show_hydrogens") == 0)
+ mp->mview->showHydrogens = atoi(valp);
+ else if (strcmp(comp, "show_dummy_atoms") == 0)
+ mp->mview->showDummyAtoms = atoi(valp);
+ else if (strcmp(comp, "show_rotation_center") == 0)
+ mp->mview->showRotationCenter = atoi(valp);
+ else if (strcmp(comp, "show_graphite_flag") == 0)
+ mp->mview->showGraphiteFlag = atoi(valp);
+ else if (strcmp(comp, "show_periodic_image_flag") == 0)
+ mp->mview->showPeriodicImageFlag = atoi(valp);
+ else if (strcmp(comp, "show_graphite") == 0)
+ mp->mview->showGraphite = atoi(valp);
+ else if (strcmp(comp, "show_expanded_atoms") == 0)
+ mp->mview->showExpandedAtoms = atoi(valp);
+ else if (strcmp(comp, "atom_resolution") == 0 && (i = atoi(valp)) >= 6)
+ mp->mview->atomResolution = i;
+ else if (strcmp(comp, "bond_resolution") == 0 && (i = atoi(valp)) >= 4)
+ mp->mview->bondResolution = i;
+ else if (strcmp(comp, "atom_radius") == 0)
+ mp->mview->atomRadius = strtod(valp, NULL);
+ else if (strcmp(comp, "bond_radius") == 0)
+ mp->mview->bondRadius = strtod(valp, NULL);
+ else if (strcmp(comp, "show_periodic_image") == 0) {
+ sscanf(valp, "%d %d %d %d %d %d", &ibuf[0], &ibuf[1], &ibuf[2], &ibuf[3], &ibuf[4], &ibuf[5]);
+ for (i = 0; i < 6; i++)
+ mp->mview->showPeriodicImage[i] = ibuf[i];
}
}
continue;
- }
- /* Unknown sections are silently ignored */
- }
-
- MoleculeCleanUpResidueTable(mp);
- if (mp->arena != NULL)
- md_arena_set_molecule(mp->arena, mp);
-
-exit:
- fclose(fp);
- if (errbuf[0] != 0) {
- /* The content of mp may be broken, so make it empty */
- MoleculeClear(mp);
- return -1;
- } else {
- MainView *mview = mp->mview;
- if (mview != NULL) {
- if (mview_ibuf[0] != kUndefined)
- mview->showUnitCell = mview_ibuf[0];
- if (mview_ibuf[1] != kUndefined)
- mview->showPeriodicBox = mview_ibuf[1];
- if (mview_ibuf[2] != kUndefined)
- mview->showExpandedAtoms = mview_ibuf[2];
- if (mview_ibuf[3] != kUndefined)
- mview->showEllipsoids = mview_ibuf[3];
- if (mview_ibuf[4] != kUndefined)
- mview->showHydrogens = mview_ibuf[4];
- if (mview_ibuf[5] != kUndefined)
- mview->showDummyAtoms = mview_ibuf[5];
- if (mview_ibuf[6] != kUndefined)
- mview->showRotationCenter = mview_ibuf[6];
- if (mview_ibuf[7] != kUndefined)
- mview->showGraphiteFlag = mview_ibuf[7];
- if (mview_ibuf[8] != kUndefined)
- mview->showPeriodicImageFlag = mview_ibuf[8];
- if (mview_ibuf[9] != kUndefined)
- mview->showGraphite = mview_ibuf[9];
- for (i = 0; i < 6; i++) {
- if (mview_ibuf[10 + i] != kUndefined)
- mview->showPeriodicImage[i] = mview_ibuf[10 + i];
- }
- if (mview->track != NULL) {
- if (mview_fbuf[0] != kUndefined)
- TrackballSetScale(mview->track, mview_fbuf[0]);
- if (mview_fbuf[1] != kUndefined)
- TrackballSetTranslate(mview->track, mview_fbuf + 1);
- if (mview_fbuf[4] != kUndefined)
- TrackballSetRotate(mview->track, mview_fbuf + 4);
+ } else if (strcmp(buf, "!:property") == 0) {
+ char dec[1024];
+ i = 0;
+ bufp = buf + 13;
+ while (*bufp != 0 && *bufp != '\n' && bufp < (buf + sizeof buf - 3)) {
+ if (*bufp == '%') {
+ dec[i] = bufp[1];
+ dec[i + 1] = bufp[2];
+ dec[i + 2] = 0;
+ dec[i++] = strtol(dec, NULL, 16);
+ bufp += 3;
+ } else {
+ dec[i++] = *bufp++;
+ }
+ if (i >= 1000)
+ break;
}
- }
- }
- return 0;
-}
-
-int
-MoleculeLoadPsfFile(Molecule *mp, const char *fname, char *errbuf, int errbufsize)
-{
- FILE *fp;
- char buf[1024];
- char *p;
- int section = -1;
- int i, j, err, fn;
- int lineNumber;
- Int ibuf[12];
- Vector *frames = NULL;
- Atom *ap;
- err = 0;
- if (errbuf == NULL) {
- errbuf = buf;
- errbufsize = 1024;
- }
- errbuf[0] = 0;
- if (mp == NULL)
- mp = MoleculeNew();
- fp = fopen(fname, "rb");
- if (fp == NULL) {
- snprintf(errbuf, errbufsize, "Cannot open file");
- return 1;
- }
-/* flockfile(fp); */
- lineNumber = 0;
- fn = 0;
- while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
- if (strncmp(buf, "PSF", 3) == 0) {
- section = 0;
- continue;
- } else {
- for (p = buf; *p != 0 && isspace(*p); p++) {}
- if (*p == 0) {
- section++;
+ if (i == 0)
+ continue;
+ dec[i] = 0;
+ i = MoleculeCreateProperty(mp, dec);
+ if (i < 0) {
+ s_append_asprintf(errbuf, "line %d: warning: duplicate molecular property %s - ignored\n", lineNumber, dec);
+ nwarnings++;
continue;
}
- }
- if (strstr(buf, "!COORD") != NULL) {
- /* Extended psf file with coordinates */
- if (fn > 0) {
- /* Allocate a temporary storage for frames */
- size_t size = sizeof(Vector) * mp->natoms * fn;
- if (frames == NULL)
- frames = (Vector *)malloc(size);
- else
- frames = (Vector *)realloc(frames, size);
- if (frames == NULL)
- goto panic;
- #if 0
- if (fn == 1) {
- /* Copy the coordinates of the first frame */
- for (i = 0; i < mp->natoms; i++) {
- ap = ATOM_AT_INDEX(mp->atoms, i);
- frames[i] = ap->r;
- }
+ j = 0;
+ while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
+ if (buf[0] == '!')
+ continue;
+ if (buf[0] == '\n')
+ break;
+ if (j >= nframes) {
+ s_append_asprintf(errbuf, "line %d: warning: too many molecular property %s - ignored\n", lineNumber, dec);
+ nwarnings++;
+ break;
}
- /* Copy the coordinates of the last frame to the newly created frame */
- memmove(frames + sizeof(Vector) * mp->natoms * fn, frames + sizeof(Vector) * mp->natoms * (fn - 1), sizeof(Vector) * mp->natoms);
- #endif
+ dbuf[0] = strtod(buf, NULL);
+ mp->molprops[i].propvals[j] = dbuf[0];
+ j++;
}
- /* Read coordinates */
- for (i = 0; i < mp->natoms; i++) {
- double dval[3];
- Vector r;
- if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0) {
- err = 1;
- snprintf(errbuf, errbufsize, "line %d: premature end of file while reading coordinates (frame %d)", lineNumber, fn);
- goto exit;
+ continue;
+ } else if (strcmp(buf, "!:gaussian_primitives") == 0) {
+ while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
+ if (buf[0] == '!')
+ continue;
+ if (buf[0] == '\n')
+ break;
+ /* sym nprims a_idx */
+ if (sscanf(buf, "%6s %d %d", cbuf[0], &ibuf[0], &ibuf[1]) < 3) {
+ s_append_asprintf(errbuf, "line %d: the gaussian primitive info cannot be read", lineNumber);
+ goto err_exit;
+ }
+ if (strcasecmp(cbuf[0], "S") == 0) {
+ ibuf[2] = 0;
+ } else if (strcasecmp(cbuf[0], "P") == 0) {
+ ibuf[2] = 1;
+ } else if (strcasecmp(cbuf[0], "SP") == 0) {
+ ibuf[2] = -1;
+ } else if (strcasecmp(cbuf[0], "D") == 0) {
+ ibuf[2] = 2;
+ } else if (strcasecmp(cbuf[0], "D5") == 0) {
+ ibuf[2] = -2;
+ } else if (strcasecmp(cbuf[0], "F") == 0) {
+ ibuf[2] = 3;
+ } else if (strcasecmp(cbuf[0], "F7") == 0) {
+ ibuf[2] = -3;
+ } else if (strcasecmp(cbuf[0], "G") == 0) {
+ ibuf[2] = 4;
+ } else if (strcasecmp(cbuf[0], "G9") == 0) {
+ ibuf[2] = -4;
+ } else {
+ s_append_asprintf(errbuf, "line %d: the gaussian primitive type %s is unknown", lineNumber, cbuf[0]);
+ goto err_exit;
+ }
+ if (ibuf[0] <= 0) {
+ s_append_asprintf(errbuf, "line %d: the number of primitive (%d) must be positive", lineNumber, ibuf[0]);
+ goto err_exit;
+ }
+ if (ibuf[1] < 0 || ibuf[1] >= mp->natoms) {
+ s_append_asprintf(errbuf, "line %d: the atom index (%d) is out of range", lineNumber, ibuf[1]);
+ goto err_exit;
+ }
+ MoleculeAddGaussianOrbitalShell(mp, ibuf[1], ibuf[2], ibuf[0], 0);
+ i = ibuf[0];
+ while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
+ if (buf[0] == '!')
+ continue;
+ if (buf[0] == '\n')
+ break;
+ if (sscanf(buf, "%lf %lf %lf", &dbuf[0], &dbuf[1], &dbuf[2]) < 3) {
+ s_append_asprintf(errbuf, "line %d: cannot read gaussian primitive coefficients", lineNumber);
+ goto err_exit;
+ }
+ MoleculeAddGaussianPrimitiveCoefficients(mp, dbuf[0], dbuf[1], dbuf[2]);
+ if (--i == 0)
+ break;
+ }
+ if (buf[0] == '\n')
+ break;
+ }
+ continue;
+ } else if (strcmp(buf, "!:mo_info") == 0) {
+ while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
+ if (buf[0] == '!')
+ continue;
+ if (buf[0] == '\n')
+ break;
+ if (sscanf(buf, "%6s %d %d", cbuf[0], &ibuf[0], &ibuf[1]) < 3) {
+ s_append_asprintf(errbuf, "line %d: the MO info cannot be correctly read", lineNumber);
+ goto err_exit;
+ }
+ if (strcasecmp(cbuf[0], "RHF") == 0) {
+ ibuf[2] = 1;
+ } else if (strcasecmp(cbuf[0], "ROHF") == 0) {
+ ibuf[2] = 2;
+ } else if (strcasecmp(cbuf[0], "UHF") == 0) {
+ ibuf[2] = 0;
+ } else {
+ s_append_asprintf(errbuf, "line %d: unknown HF type: %s", lineNumber, cbuf[0]);
+ goto err_exit;
+ }
+ if (ibuf[0] < 0 || ibuf[1] < 0) {
+ s_append_asprintf(errbuf, "line %d: incorrect number of electrons", lineNumber);
+ goto err_exit;
+ }
+ MoleculeSetMOInfo(mp, ibuf[2], ibuf[0], ibuf[1]);
+ }
+ continue;
+ } else if (strcmp(buf, "!:mo_coefficients") == 0) {
+ if (mp->bset == NULL || mp->bset->nshells == 0) {
+ s_append_asprintf(errbuf, "line %d: the :gaussian_primitive section must come before :mo_coefficients", lineNumber);
+ goto err_exit;
+ }
+ /* Count the number of components */
+ dp = (Double *)malloc(sizeof(Double) * mp->bset->ncomps);
+ i = 1;
+ while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
+ if (buf[0] == '!')
+ continue;
+ if (buf[0] == '\n')
+ break;
+ if (sscanf(buf, "MO %d %lf", &ibuf[0], &dbuf[6]) < 2) {
+ s_append_asprintf(errbuf, "line %d: cannot read the MO index or energy", lineNumber);
+ goto err_exit;
+ }
+ if (ibuf[0] != i) {
+ s_append_asprintf(errbuf, "line %d: the MO index (%d) must be in ascending order", lineNumber, ibuf[0]);
+ goto err_exit;
+ }
+ i = 0;
+ while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
+ j = sscanf(buf, "%lf %lf %lf %lf %lf %lf", &dbuf[0], &dbuf[1], &dbuf[2], &dbuf[3], &dbuf[4], &dbuf[5]);
+ if (j == 0) {
+ s_append_asprintf(errbuf, "line %d: cannot read the MO coefficients", lineNumber);
+ goto err_exit;
+ }
+ for (k = 0; k < j; k++, i++) {
+ if (i >= mp->bset->ncomps) {
+ s_append_asprintf(errbuf, "line %d: too many MO coefficients", lineNumber);
+ goto err_exit;
+ }
+ dp[i] = dbuf[k];
+ }
+ if (i >= mp->bset->ncomps)
+ break;
+ }
+ i = MoleculeSetMOCoefficients(mp, ibuf[0], dbuf[6], mp->bset->ncomps, dp);
+ if (i != 0) {
+ s_append_asprintf(errbuf, "line %d: cannot set MO coefficients", lineNumber);
+ goto err_exit;
+ }
+ i = ibuf[0] + 1; /* For next entry */
+ }
+ continue;
+ } else if (strcmp(buf, "!:graphics") == 0) {
+ while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
+ MainViewGraphic *gp = NULL;
+ if (buf[0] == '!')
+ continue;
+ if (buf[0] == '\n')
+ break;
+ if (mp->mview == NULL)
+ continue; /* Skip */
+ redo:
+ if (strcmp(buf, "line\n") == 0) {
+ ibuf[0] = kMainViewGraphicLine;
+ } else if (strcmp(buf, "poly\n") == 0) {
+ ibuf[0] = kMainViewGraphicPoly;
+ } else if (strcmp(buf, "cylinder\n") == 0) {
+ ibuf[0] = kMainViewGraphicCylinder;
+ } else if (strcmp(buf, "cone\n") == 0) {
+ ibuf[0] = kMainViewGraphicCone;
+ } else if (strcmp(buf, "ellipsoid\n") == 0) {
+ ibuf[0] = kMainViewGraphicEllipsoid;
+ } else {
+ continue; /* Skip */
+ }
+ gp = (MainViewGraphic *)calloc(sizeof(MainViewGraphic), 1);
+ gp->kind = ibuf[0];
+ i = 0;
+ while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
+ if (buf[0] == '!')
+ continue;
+ if (buf[0] == '\n')
+ break;
+ if (i == 0) {
+ if (sscanf(buf, "%d %d", &ibuf[0], &ibuf[1]) < 2) {
+ s_append_asprintf(errbuf, "line %d: the closed/visible flags cannot be read for graphic object", lineNumber);
+ goto err_exit;
+ }
+ gp->closed = ibuf[0];
+ gp->visible = ibuf[1];
+ } else if (i == 1) {
+ if (sscanf(buf, "%lf %lf %lf %lf", &dbuf[0], &dbuf[1], &dbuf[2], &dbuf[3]) < 4) {
+ s_append_asprintf(errbuf, "line %d: the color cannot be read for graphic object", lineNumber);
+ goto err_exit;
+ }
+ for (j = 0; j < 4; j++)
+ gp->rgba[j] = dbuf[j];
+ } else if (i == 2) {
+ j = atoi(buf);
+ if (j < 0) {
+ s_append_asprintf(errbuf, "line %d: the number of control points must be non-negative", lineNumber);
+ goto err_exit;
+ }
+ if (j > 0)
+ NewArray(&gp->points, &gp->npoints, sizeof(GLfloat) * 3, j);
+ } else if (i >= 3 && i < gp->npoints + 3) {
+ if (sscanf(buf, "%lf %lf %lf", &dbuf[0], &dbuf[1], &dbuf[2]) < 3) {
+ s_append_asprintf(errbuf, "line %d: the control point cannot be read for graphic object", lineNumber);
+ goto err_exit;
+ }
+ j = (i - 3) * 3;
+ gp->points[j++] = dbuf[0];
+ gp->points[j++] = dbuf[1];
+ gp->points[j] = dbuf[2];
+ } else if (i == gp->npoints + 3) {
+ j = atoi(buf);
+ if (j < 0) {
+ s_append_asprintf(errbuf, "line %d: the number of normals must be non-negative", lineNumber);
+ goto err_exit;
+ }
+ if (j > 0)
+ NewArray(&gp->normals, &gp->nnormals, sizeof(GLfloat) * 3, j);
+ } else if (i >= gp->npoints + 4 && i < gp->npoints + gp->nnormals + 4) {
+ if (sscanf(buf, "%lf %lf %lf", &dbuf[0], &dbuf[1], &dbuf[2]) < 3) {
+ s_append_asprintf(errbuf, "line %d: the normal vector cannot be read for graphic object", lineNumber);
+ goto err_exit;
+ }
+ j = (i - gp->npoints - 4) * 3;
+ gp->normals[j++] = dbuf[0];
+ gp->normals[j++] = dbuf[1];
+ gp->normals[j] = dbuf[2];
+ } else break;
+ i++;
+ }
+ MainView_insertGraphic(mp->mview, -1, gp);
+ free(gp);
+ if (buf[0] == '\n' || buf[0] == 0)
+ break;
+ goto redo;
+ }
+ continue;
+ } else if (strncmp(buf, "!:@", 3) == 0) {
+ /* Plug-in implemented in the ruby world */
+ Int stringLen;
+ char *stringBuf, *returnString;
+ i = strlen(buf);
+ NewArray(&stringBuf, &stringLen, sizeof(char), i + 1);
+ strcpy(stringBuf, buf);
+ k = lineNumber;
+ while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
+ /* The comment lines are _not_ skipped */
+ if (buf[0] == '\n')
+ break;
+ j = strlen(buf);
+ AssignArray(&stringBuf, &stringLen, sizeof(char), i + j, NULL);
+ strncpy(stringBuf + i, buf, j);
+ i += j;
+ }
+ if (MolActionCreateAndPerform(mp, SCRIPT_ACTION("si;s"),
+ "proc { |i| loadmbsf_plugin(i) rescue \"line #{i}: #{$i.to_s}\" }",
+ stringBuf, k, &returnString) != 0) {
+ s_append_asprintf(errbuf, "line %d: cannot invoke Ruby plugin", lineNumber);
+ goto err_exit;
+ } else if (returnString[0] != 0) {
+ s_append_asprintf(errbuf, "%s", returnString);
+ goto err_exit;
+ }
+ free(stringBuf);
+ continue;
+ }
+ /* Unknown sections are silently ignored */
+ }
+
+ MoleculeCleanUpResidueTable(mp);
+ if (mp->arena != NULL)
+ md_arena_set_molecule(mp->arena, mp);
+
+ fclose(fp);
+
+/* if (mp->mview != NULL) {
+ if (mview_ibuf[0] != kUndefined)
+ mp->mview->showUnitCell = mview_ibuf[0];
+ if (mview_ibuf[1] != kUndefined)
+ mp->mview->showPeriodicBox = mview_ibuf[1];
+ if (mview_ibuf[2] != kUndefined)
+ mp->mview->showExpandedAtoms = mview_ibuf[2];
+ if (mview_ibuf[3] != kUndefined)
+ mp->mview->showEllipsoids = mview_ibuf[3];
+ if (mview_ibuf[4] != kUndefined)
+ mp->mview->showHydrogens = mview_ibuf[4];
+ if (mview_ibuf[5] != kUndefined)
+ mp->mview->showDummyAtoms = mview_ibuf[5];
+ if (mview_ibuf[6] != kUndefined)
+ mp->mview->showRotationCenter = mview_ibuf[6];
+ if (mview_ibuf[7] != kUndefined)
+ mp->mview->showGraphiteFlag = mview_ibuf[7];
+ if (mview_ibuf[8] != kUndefined)
+ mp->mview->showPeriodicImageFlag = mview_ibuf[8];
+ if (mview_ibuf[9] != kUndefined)
+ mp->mview->showGraphite = mview_ibuf[9];
+ if (mview_ibuf[10] != kUndefined && mview_ibuf[10] >= 6)
+ mp->mview->atomResolution = mview_ibuf[10];
+ if (mview_ibuf[11] != kUndefined && mview_ibuf[11] >= 4)
+ mp->mview->bondResolution = mview_ibuf[11];
+ for (i = 0; i < 6; i++) {
+ if (mview_ibuf[12 + i] != kUndefined)
+ mp->mview->showPeriodicImage[i] = mview_ibuf[12 + i];
+ }
+ if (mview_dbuf[8] != kUndefined)
+ mp->mview->atomRadius = mview_dbuf[8];
+ if (mview_dbuf[9] != kUndefined)
+ mp->mview->bondRadius = mview_dbuf[9];
+ if (mp->mview->track != NULL) {
+ if (mview_dbuf[0] != kUndefined)
+ TrackballSetScale(mp->mview->track, mview_dbuf[0]);
+ if (mview_dbuf[1] != kUndefined)
+ TrackballSetTranslate(mp->mview->track, mview_dbuf + 1);
+ if (mview_dbuf[4] != kUndefined)
+ TrackballSetRotate(mp->mview->track, mview_dbuf + 4);
+ }
+ }
+*/
+
+ return 0;
+
+err_exit:
+ fclose(fp);
+ /* The content of mp may be broken, so make it empty */
+ MoleculeClear(mp);
+ return -1;
+}
+
+int
+MoleculeLoadPsfFile(Molecule *mp, const char *fname, char **errbuf)
+{
+ FILE *fp;
+ char buf[1024];
+ char *p;
+ int section = -1;
+ int i, j, err, fn;
+ int lineNumber;
+ Int ibuf[12];
+ Vector *frames = NULL;
+ Atom *ap;
+ err = 0;
+ *errbuf = NULL;
+ if (mp == NULL)
+ mp = MoleculeNew();
+ else MoleculeClear(mp);
+ fp = fopen(fname, "rb");
+ if (fp == NULL) {
+ s_append_asprintf(errbuf, "Cannot open file");
+ return 1;
+ }
+/* flockfile(fp); */
+ lineNumber = 0;
+ fn = 0;
+ while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
+ if (strncmp(buf, "PSF", 3) == 0) {
+ section = 0;
+ continue;
+ } else {
+ for (p = buf; *p != 0 && isspace(*p); p++) {}
+ if (*p == 0) {
+ section++;
+ continue;
+ }
+ }
+ if (strstr(buf, "!COORD") != NULL) {
+ /* Extended psf file with coordinates */
+ if (fn > 0) {
+ /* Allocate a temporary storage for frames */
+ size_t size = sizeof(Vector) * mp->natoms * fn;
+ if (frames == NULL)
+ frames = (Vector *)malloc(size);
+ else
+ frames = (Vector *)realloc(frames, size);
+ if (frames == NULL)
+ goto panic;
+ }
+ /* Read coordinates */
+ for (i = 0; i < mp->natoms; i++) {
+ double dval[3];
+ Vector r;
+ if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0) {
+ err = 1;
+ s_append_asprintf(errbuf, "line %d: premature end of file while reading coordinates (frame %d)", lineNumber, fn);
+ goto exit;
}
if (sscanf(buf, "%lg %lg %lg", dval, dval + 1, dval + 2) != 3) {
err = 1;
- snprintf(errbuf, errbufsize, "line %d: coordinates cannot be read for atom %d", lineNumber, i + 1);
+ s_append_asprintf(errbuf, "line %d: coordinates cannot be read for atom %d", lineNumber, i + 1);
goto exit;
}
r.x = dval[0];
/* Atoms */
Int natoms;
ReadFormat(buf, "I8", &natoms);
- if (mp->atoms != NULL)
- free(mp->atoms);
+ if (natoms == 0)
+ continue;
if (NewArray(&mp->atoms, &mp->natoms, gSizeOfAtomRecord, natoms) == NULL)
goto panic;
mp->nresidues = 0;
ap = ATOM_AT_INDEX(mp->atoms, i);
if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0) {
err = 1;
- snprintf(errbuf, errbufsize, "line %d: premature end of file while reading atoms", lineNumber);
+ s_append_asprintf(errbuf, "line %d: premature end of file while reading atoms", lineNumber);
goto exit;
}
ReadFormat(buf, "I8 x1 S4 I5 x1 S3 x2 S4 x1 S4 F16 F10",
Int nbonds;
Int *bp;
ReadFormat(buf, "I8", &nbonds);
- if (mp->bonds != NULL)
- free(mp->bonds);
+ if (nbonds == 0)
+ continue;
if (NewArray(&mp->bonds, &mp->nbonds, sizeof(Int) * 2, nbonds) == NULL)
goto panic;
bp = mp->bonds;
for (i = 0; i < nbonds; i += 4) {
if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0) {
- snprintf(errbuf, errbufsize, "line %d: premature end of file while reading bonds", lineNumber);
+ s_append_asprintf(errbuf, "line %d: premature end of file while reading bonds", lineNumber);
err = 1;
goto exit;
}
b1 = ibuf[j * 2] - 1; /* Internal atom number is 0-based */
b2 = ibuf[j * 2 + 1] - 1;
if (b1 < 0 || b1 >= mp->natoms || b2 < 0 || b2 >= mp->natoms) {
- snprintf(errbuf, errbufsize, "line %d: The bond %d-%d includes non-existent atom", lineNumber, b1+1, b2+1);
+ s_append_asprintf(errbuf, "line %d: The bond %d-%d includes non-existent atom", lineNumber, b1+1, b2+1);
err = 1;
goto exit;
}
*bp++ = b1;
*bp++ = b2;
ap = ATOM_AT_INDEX(mp->atoms, b1);
- AtomInsertConnectEntry(ap, ap->nconnects, b2);
- /* if (ap->nconnects < ATOMS_MAX_CONNECTS)
- ap->connects[ap->nconnects++] = b2;
- else {
- snprintf(errbuf, errbufsize, "line %d: The atom %d has more than %d bonds", lineNumber, b1+1, ATOMS_MAX_CONNECTS);
- err = 1;
- goto exit;
- } */
+ AtomConnectInsertEntry(&ap->connect, -1, b2);
ap = ATOM_AT_INDEX(mp->atoms, b2);
- AtomInsertConnectEntry(ap, ap->nconnects, b1);
- /* if (ap->nconnects < ATOMS_MAX_CONNECTS)
- ap->connects[ap->nconnects++] = b1;
- else {
- snprintf(errbuf, errbufsize, "line %d: The atom %d has more than %d bonds", lineNumber, b2+1, ATOMS_MAX_CONNECTS);
- err = 1;
- goto exit;
- } */
+ AtomConnectInsertEntry(&ap->connect, -1, b1);
}
}
continue;
Int nangles;
Int *gp;
ReadFormat(buf, "I8", &nangles);
- if (mp->angles != NULL)
- free(mp->angles);
+ if (nangles == 0)
+ continue;
if (NewArray(&mp->angles, &mp->nangles, sizeof(Int) * 3, nangles) == NULL)
goto panic;
gp = mp->angles;
for (i = 0; i < nangles; i += 3) {
if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0) {
- snprintf(errbuf, errbufsize, "line %d: premature end of file while reading angles", lineNumber);
+ s_append_asprintf(errbuf, "line %d: premature end of file while reading angles", lineNumber);
err = 1;
goto exit;
}
a2 = ibuf[j * 3 + 1] - 1;
a3 = ibuf[j * 3 + 2] - 1;
if (a1 < 0 || a1 >= mp->natoms || a2 < 0 || a2 >= mp->natoms || a3 < 0 || a3 >= mp->natoms) {
- snprintf(errbuf, errbufsize, "line %d: The angle %d-%d-%d includes non-existent atom", lineNumber, a1+1, a2+1, a3+1);
+ s_append_asprintf(errbuf, "line %d: The angle %d-%d-%d includes non-existent atom", lineNumber, a1+1, a2+1, a3+1);
err = 1;
goto exit;
}
Int ndihedrals;
Int *dp;
ReadFormat(buf, "I8", &ndihedrals);
+ if (ndihedrals == 0)
+ continue;
if (section == 5) {
if (NewArray(&mp->dihedrals, &mp->ndihedrals, sizeof(Int) * 4, ndihedrals) == NULL)
goto panic;
for (i = 0; i < ndihedrals; i += 2) {
if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0) {
fclose(fp);
- snprintf(errbuf, errbufsize, "line %d: premature end of file while reading %s", lineNumber, (section == 5 ? "dihedral" : "improper"));
+ s_append_asprintf(errbuf, "line %d: premature end of file while reading %s", lineNumber, (section == 5 ? "dihedral" : "improper"));
err = 1;
goto exit;
}
d3 = ibuf[j * 4 + 2] - 1;
d4 = ibuf[j * 4 + 3] - 1;
if (d1 < 0 || d1 >= mp->natoms || d2 < 0 || d2 >= mp->natoms || d3 < 0 || d3 >= mp->natoms || d4 < 0 || d4 >= mp->natoms) {
- snprintf(errbuf, errbufsize, "line %d: The %s %d-%d-%d-%d angle includes non-existent atom", lineNumber, (section == 5 ? "dihedral" : "improper"), d1+1, d2+1, d3+1, d4+1);
+ s_append_asprintf(errbuf, "line %d: The %s %d-%d-%d-%d angle includes non-existent atom", lineNumber, (section == 5 ? "dihedral" : "improper"), d1+1, d2+1, d3+1, d4+1);
err = 1;
goto exit;
}
if (fn > 1) {
for (i = 0; i < mp->natoms; i++) {
ap = ATOM_AT_INDEX(mp->atoms, i);
- ap->frames = (Vector *)malloc(sizeof(Vector) * fn);
+ NewArray(&ap->frames, &ap->nframes, sizeof(Vector), fn);
if (ap->frames == NULL)
goto panic;
- ap->nframes = fn;
for (j = 0; j < fn; j++)
ap->frames[j] = frames[mp->natoms * j + i];
}
}
int
-MoleculeLoadTepFile(Molecule *mp, const char *fname, char *errbuf, int errbufsize)
+MoleculeLoadTepFile(Molecule *mp, const char *fname, char **errbuf)
{
FILE *fp;
char buf[1024];
Int ibuf[12];
Double fbuf[12];
Int *bonds, nbonds;
- if (errbuf == NULL) {
- errbuf = buf;
- errbufsize = 1024;
- }
- errbuf[0] = 0;
+ *errbuf = NULL;
if (mp == NULL)
mp = MoleculeNew();
fp = fopen(fname, "rb");
if (fp == NULL) {
- snprintf(errbuf, errbufsize, "Cannot open file");
+ s_append_asprintf(errbuf, "Cannot open file");
return 1;
}
lineNumber = 0;
symops[1] = strtok_r(NULL, ", ", &brks);
symops[2] = strtok_r(NULL, ", ", &brks);
if (sMoleculeSymopStringsToTransform(symops, tr)) {
- snprintf(errbuf, errbufsize, "line %d: bad symmetry specification", lineNumber);
+ s_append_asprintf(errbuf, "line %d: bad symmetry specification", lineNumber);
return 1;
}
}
guessElement(ap);
atomType = fbuf[3];
if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0) {
- snprintf(errbuf, errbufsize, "unexpected end of file");
+ s_append_asprintf(errbuf, "unexpected end of file");
return 1;
}
ReadFormat(buf, "I1F8F9F9F9F9F9F9", ibuf, fbuf, fbuf+1, fbuf+2, fbuf+3, fbuf+4, fbuf+5, fbuf+6);
}
}
fclose(fp);
- MoleculeGuessBonds(mp, 1.2, &nbonds, &bonds);
+ MoleculeGuessBonds(mp, 0.0, &nbonds, &bonds);
if (nbonds > 0) {
- MoleculeAddBonds(mp, nbonds, bonds);
+ MoleculeAddBonds(mp, nbonds, bonds, NULL, 1);
free(bonds);
}
mp->nframes = -1; /* Should be recalculated later */
}
int
-MoleculeLoadShelxFile(Molecule *mp, const char *fname, char *errbuf, int errbufsize)
+MoleculeLoadShelxFile(Molecule *mp, const char *fname, char **errbuf)
{
FILE *fp;
char buf[1024];
Int nbonds, *bonds;
char (*sfacs)[4] = NULL;
- if (errbuf == NULL) {
- errbuf = buf;
- errbufsize = 1024;
- }
- errbuf[0] = 0;
+ *errbuf = NULL;
if (mp == NULL)
mp = MoleculeNew();
currentResName[0] = 0;
fp = fopen(fname, "rb");
if (fp == NULL) {
- snprintf(errbuf, errbufsize, "Cannot open file");
+ s_append_asprintf(errbuf, "Cannot open file");
return 1;
}
lineNumber = 0;
symops[1] = strtok_r(NULL, ",", &brks);
symops[2] = strtok_r(NULL, ",", &brks);
if (sMoleculeSymopStringsToTransform(symops, tr)) {
- snprintf(errbuf, errbufsize, "line %d: bad symmetry specification", lineNumber);
+ s_append_asprintf(errbuf, "line %d: bad symmetry specification", lineNumber);
return 1;
}
if (AssignArray(&mp->syms, &mp->nsyms, sizeof(Transform), mp->nsyms, tr) == 0)
n = sscanf(p1, " %d %f %f %f %f %f %f %2s", ibuf, fbuf, fbuf+1, fbuf+2, fbuf+3, fbuf+4, fbuf+5, cont);
if (n == 8 && strcmp(cont, "=") == 0) {
if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0) {
- snprintf(errbuf, errbufsize, "line %d: unexpected end of file within the atom cards", lineNumber);
+ s_append_asprintf(errbuf, "line %d: unexpected end of file within the atom cards", lineNumber);
return 1;
}
sscanf(buf, " %f %f %f %f", fbuf+6, fbuf+7, fbuf+8, fbuf+9);
sMoleculeGenerateSymopWithTransform(mp, tr_inv, 0);
}
- MoleculeGuessBonds(mp, 1.2, &nbonds, &bonds);
+ MoleculeGuessBonds(mp, 0.0, &nbonds, &bonds);
if (nbonds > 0) {
- MoleculeAddBonds(mp, nbonds, bonds);
+ MoleculeAddBonds(mp, nbonds, bonds, NULL, 1);
free(bonds);
}
mp->nframes = -1; /* Should be recalculated later */
/* Add one gaussian orbital shell information (not undoable) */
int
-MoleculeAddGaussianOrbitalShell(Molecule *mol, Int sym, Int nprims, Int a_idx)
+MoleculeAddGaussianOrbitalShell(Molecule *mol, Int a_idx, Int sym, Int nprims, Int add_exp)
{
BasisSet *bset;
ShellInfo *shellp;
case -1: shellp->sym = kGTOType_SP; shellp->ncomp = 4; break;
case 2: shellp->sym = kGTOType_D; shellp->ncomp = 6; break;
case -2: shellp->sym = kGTOType_D5; shellp->ncomp = 5; break;
- /* TODO: Support F/F7 type orbitals */
- /* case 3: sp->sym = kGTOtype_F; sp->ncomp = 10; break;
- case -3: sp->sym = kGTOType_F7; sp->ncomp = 7; break; */
+ case 3: shellp->sym = kGTOType_F; shellp->ncomp = 10; break;
+ case -3: shellp->sym = kGTOType_F7; shellp->ncomp = 7; break;
+ case 4: shellp->sym = kGTOType_G; shellp->ncomp = 15; break;
+ case -4: shellp->sym = kGTOType_G9; shellp->ncomp = 9; break;
default:
return -3; /* Unsupported shell type */
}
shellp->m_idx = 0;
shellp->p_idx = 0;
}
+ shellp->add_exp = add_exp;
+ /* Update the number of components (if not yet determined) */
+ if (bset->ncomps < shellp->m_idx + shellp->ncomp)
+ bset->ncomps = shellp->m_idx + shellp->ncomp;
return 0;
}
return 0;
}
-/* Set MO coefficients for idx-th MO */
+/* Get the shell information from the component index */
+/* The outLabel must have space for at least 23 non-Null characters */
+int
+MoleculeGetGaussianComponentInfo(Molecule *mol, Int comp_idx, Int *outAtomIdx, char *outLabel, Int *outShellIdx)
+{
+ BasisSet *bset;
+ ShellInfo *shellp;
+ int si;
+ if (mol == NULL || (bset = mol->bset) == NULL)
+ return -1; /* No basis set info */
+ if (comp_idx < 0 || comp_idx >= bset->ncomps)
+ return -2; /* Component index out of range */
+ for (si = 0, shellp = bset->shells; si < bset->nshells; si++, shellp++) {
+ if (comp_idx >= shellp->ncomp) {
+ comp_idx -= shellp->ncomp;
+ continue;
+ } else {
+ static const char *type_p = "xyz";
+ static const char *type_d = "xxyyzzxyxzyz";
+ static const char *type_d5[] = {"xy","yz","zz", "xz", "xx-yy"};
+ static const char *type_f = "xxxyyyzzzxxyxxzxyyyyzxzzyzzxyz";
+ static const char *type_f7[] = {"x3-3xy2", "x2z-y2z", "x(5z2-r2)", "z(5z2-3r2)", "y(5z2-r2)", "xyz", "3x2y-y3"};
+ static const char *type_g[] = {"x4", "y4", "z4", "x3y", "x3z", "xy3", "y3z", "xz3", "yz3", "x2y2", "x2z2", "y2z2", "x2yz", "x2yz", "xyz2"};
+ static const char *type_g9[] = {"x4+y4-6x2y2", "xz(x2-3y2)", "(x2-y2)(7z2-r2)", "xz(7z2-3r2)", "35z4-30z2r2+3r4", "yz(7z2-3r2)", "xy(7z2-r2)", "yz(3x2-y2)", "xy(x2-y2)"};
+ *outAtomIdx = shellp->a_idx;
+ *outShellIdx = si;
+ switch (shellp->sym) {
+ case kGTOType_S:
+ strcpy(outLabel, "S");
+ break;
+ case kGTOType_P:
+ outLabel[0] = 'P';
+ outLabel[1] = type_p[comp_idx];
+ outLabel[2] = 0;
+ break;
+ case kGTOType_SP:
+ if (comp_idx == 0)
+ strcpy(outLabel, "S");
+ else {
+ outLabel[0] = 'P';
+ outLabel[1] = type_p[comp_idx - 1];
+ outLabel[2] = 0;
+ }
+ break;
+ case kGTOType_D:
+ outLabel[0] = 'D';
+ strncpy(outLabel + 1, type_d + comp_idx * 2, 2);
+ outLabel[3] = 0;
+ break;
+ case kGTOType_D5:
+ outLabel[0] = 'D';
+ strcpy(outLabel + 1, type_d5[comp_idx]);
+ break;
+ case kGTOType_F:
+ outLabel[0] = 'F';
+ strncpy(outLabel + 1, type_f + comp_idx * 3, 3);
+ outLabel[4] = 0;
+ break;
+ case kGTOType_F7:
+ outLabel[0] = 'F';
+ strcpy(outLabel + 1, type_f7[comp_idx]);
+ break;
+ case kGTOType_G:
+ outLabel[0] = 'G';
+ strcpy(outLabel + 1, type_g[comp_idx]);
+ break;
+ case kGTOType_G9:
+ outLabel[0] = 'G';
+ strcpy(outLabel + 1, type_g9[comp_idx]);
+ break;
+ default:
+ return -3; /* Unsupported orbital type (internal error) */
+ }
+ return 0;
+ }
+ }
+ return -4; /* comp_idx out of range? (internal error) */
+}
+
+/* Set MO coefficients for idx-th MO (1-based) */
int
MoleculeSetMOCoefficients(Molecule *mol, Int idx, Double energy, Int ncomps, Double *coeffs)
{
bset->nmos = bset->ncomps;
if (bset->nmos <= 0)
return -3; /* Bad or inconsistent number of MOs */
- bset->mo = (Double *)calloc(sizeof(Double), bset->nmos * bset->ncomps);
- bset->moenergies = (Double *)calloc(sizeof(Double), bset->nmos);
+ bset->mo = (Double *)calloc(sizeof(Double), (bset->nmos + 1) * bset->ncomps);
+ bset->moenergies = (Double *)calloc(sizeof(Double), bset->nmos + 1);
if (bset->mo == NULL || bset->moenergies == NULL) {
if (bset->mo != NULL)
free(bset->mo);
return -2; /* Low memory */
}
}
- if (idx < 0 || idx >= bset->nmos)
+ if (idx < 0)
+ idx = -idx + bset->ncomps;
+ if (idx < 0 || idx > bset->nmos)
return -4; /* Bad MO index */
+ if (idx == 0)
+ idx = bset->nmos; /* Arbitrary vector */
+ else
+ idx--;
if (energy != -1000000)
bset->moenergies[idx] = energy;
if (ncomps < bset->ncomps)
return 0;
}
-/* Allocate BasisSet record. rflag: UHF, 0; RHF, 1; ROHF, 2
- ne_alpha: number of alpha electrons, ne_beta: number of beta electrons
- The natoms and pos are copied from mol. */
+/* Get MO coefficients for idx-th MO (1-based) */
+/* Caution: *ncoeffs and *coeffs should be valid _before_ calling this function, i.e. */
+/* *ncoeffs = 0 && *coeffs = NULL or *coeffs is a valid memory pointer and *ncoeffs */
+/* properly designates the memory size as an array of Doubles. */
int
-MoleculeAllocateBasisSetRecord(Molecule *mol, Int rflag, Int ne_alpha, Int ne_beta)
+MoleculeGetMOCoefficients(Molecule *mol, Int idx, Double *energy, Int *ncoeffs, Double **coeffs)
+{
+ BasisSet *bset;
+ if (mol == NULL)
+ return -1; /* Molecule is empty */
+ bset = mol->bset;
+ if (bset == NULL || bset->ncomps <= 0)
+ return -2; /* No basis set info */
+ if (idx < 0)
+ idx = -idx + bset->ncomps;
+ if (idx < 0 || idx > bset->nmos)
+ return -3; /* MO index out of range */
+ if (idx == 0)
+ idx = bset->nmos; /* Arbitrary vector */
+ else
+ idx--;
+ if (energy != NULL)
+ *energy = bset->moenergies[idx];
+ if (ncoeffs != NULL && coeffs != NULL) {
+ if (*ncoeffs < bset->ncomps || *coeffs == NULL) {
+ if (*coeffs != NULL)
+ free(*coeffs); /* Caution: possible cause of SIGBUS if *coeff is not initialized properly */
+ *coeffs = (Double *)calloc(sizeof(Double), bset->ncomps);
+ *ncoeffs = bset->ncomps;
+ }
+ memmove(*coeffs, bset->mo + (idx * bset->ncomps), sizeof(Double) * bset->ncomps);
+ }
+ return 0;
+}
+
+/* Set Basic MO Info. rflag: 0, UHF; 1, RHF; 2, ROHF; -1, clear
+ ne_alpha: number of alpha electrons, ne_beta: number of beta electrons */
+int
+MoleculeSetMOInfo(Molecule *mol, Int rflag, Int ne_alpha, Int ne_beta)
{
BasisSet *bset;
- int i;
- Atom *ap;
if (mol == NULL || mol->natoms == 0)
return -1; /* Molecule is empty */
+ if (rflag < 0) {
+ if (mol->bset != NULL) {
+ BasisSetRelease(mol->bset);
+ mol->bset = NULL;
+ }
+ return 0;
+ }
bset = mol->bset;
if (bset == NULL) {
bset = mol->bset = (BasisSet *)calloc(sizeof(BasisSet), 1);
if (bset == NULL)
return -2; /* Low memory */
}
- if (bset->pos != NULL) {
- free(bset->pos);
- bset->pos = NULL;
- }
- bset->natoms = mol->natoms;
- bset->pos = (Vector *)calloc(sizeof(Vector), bset->natoms);
- if (bset->pos == NULL)
- return -2; /* Low memory */
- for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
- bset->pos[i].x = ap->r.x * kAngstrom2Bohr;
- bset->pos[i].y = ap->r.y * kAngstrom2Bohr;
- bset->pos[i].z = ap->r.z * kAngstrom2Bohr;
- }
+ bset->natoms_bs = mol->natoms;
bset->ne_alpha = ne_alpha;
bset->ne_beta = ne_beta;
bset->rflag = rflag;
return 3; /* Unexpected EOF */
}
+// Normalization constant for one gaussian component
+// 1/sqrt(Integral((Y(lm)*(r^n)*exp(-a*r*r))^2, for all r = (x, y, z)))
+// where Y(lm) is a spherical harmonic function, r^n is an "additional exponent"
+// required in expanded Molden file generated by JANPA, and a is the exponent
+// of the gaussian component.
+// The function Y(lm) is assumed so that its norm equals sqrt(4*pi/(2l+1))
+// for each m in [-l..l].
+static double
+sGaussianNormalizationConstant(int l, double a, int n)
+{
+ return 1.0/(sqrt(4 * PI / (2 * l + 1.0)) * sqrt(tgamma(l + n + 1.5) / (2.0 * pow(2.0 * a, l + n + 1.5))));
+}
+
static int
sSetupGaussianCoefficients(BasisSet *bset)
{
ShellInfo *sp;
PrimInfo *pp;
- int i, j, k;
+ int i, j, k, n;
Double *dp, d;
/* Cache the contraction coefficients for efficient calculation */
dp = bset->cns;
for (i = 0, sp = bset->shells; i < bset->nshells; i++, sp++) {
for (j = 0, pp = bset->priminfos + sp->p_idx; j < sp->nprim; j++, pp++) {
+ n = sp->add_exp;
switch (sp->sym) {
case kGTOType_S:
+ // GNC(0,a,n) * r^n * exp(-a*r^2)
+ d = pp->C * sGaussianNormalizationConstant(0, pp->A, n);
+ *dp++ = d;
+ //{ printf("type_S: %g %g\n", d, pp->C * pow(pp->A, 0.75) * 0.71270547); }
// (8 alpha^3/pi^3)^0.25 exp(-alpha r^2)
- *dp++ = pp->C * pow(pp->A, 0.75) * 0.71270547;
+ //*dp++ = pp->C * pow(pp->A, 0.75) * 0.71270547;
break;
case kGTOType_P:
- // (128 alpha^5/pi^3)^0.25 [x|y|z]exp(-alpha r^2)
- d = pp->C * pow(pp->A, 1.25) * 1.425410941;
+ // GNC(1,a,n) * [x|y|z] * r^n * exp(-a*r^2)
+ d = pp->C * sGaussianNormalizationConstant(1, pp->A, n);
+ //{ printf("type_P: %g %g\n", d, pp->C * pow(pp->A, 1.25) * 1.425410941); }
+ // (128 alpha^5/pi^3)^0.25 [x|y|z]exp(-alpha r^2)
+ // d = pp->C * pow(pp->A, 1.25) * 1.425410941;
*dp++ = d;
*dp++ = d;
*dp++ = d;
break;
case kGTOType_SP:
- *dp++ = pp->C * pow(pp->A, 0.75) * 0.71270547;
- d = pp->Csp * pow(pp->A, 1.25) * 1.425410941;
+ // GNC(0,a,n) * r^n * exp(-a*r^2)
+ *dp++ = d = pp->C * sGaussianNormalizationConstant(0, pp->A, n);
+ //{ printf("type_SP(s): %g %g\n", d, pp->C * pow(pp->A, 0.75) * 0.71270547); }
+ // GNC(1,a,n) * [x|y|z] * r^n * exp(-a*r^2)
+ d = pp->Csp * sGaussianNormalizationConstant(1, pp->A, n);
+ //{ printf("type_SP(p): %g %g\n", d, pp->Csp * pow(pp->A, 1.25) * 1.425410941); }
+ //*dp++ = pp->C * pow(pp->A, 0.75) * 0.71270547;
+ //d = pp->Csp * pow(pp->A, 1.25) * 1.425410941;
*dp++ = d;
*dp++ = d;
*dp++ = d;
break;
case kGTOType_D:
+ // GNC(2,a,n) * [xx|yy|zz] * r^n * exp(-a*r^2)
+ // GNC(2,a,n) * sqrt(3) * [xy|yz|zx] * r^n * exp(-a*r^2)
+ d = pp->C * sGaussianNormalizationConstant(2, pp->A, n);
+ //{ printf("type_D[0-2]: %g %g\n", d, pp->C * pow(pp->A, 1.75) * 1.645922781); }
+ //{ printf("type_D[3-5]: %g %g\n", d * sqrt(3), pp->C * pow(pp->A, 1.75) * 2.850821881); }
+ dp[0] = dp[1] = dp[2] = d;
+ dp[3] = dp[4] = dp[5] = d * sqrt(3);
// xx|yy|zz: (2048 alpha^7/9pi^3)^0.25 [xx|yy|zz]exp(-alpha r^2)
// xy|yz|zx: (2048 alpha^7/pi^3)^0.25 [xy|xz|yz]exp(-alpha r^2)
- d = pp->C * pow(pp->A, 1.75);
- dp[0] = dp[1] = dp[2] = d * 1.645922781;
- dp[3] = dp[4] = dp[5] = d * 2.850821881;
+ // d = pp->C * pow(pp->A, 1.75);
+ //dp[0] = dp[1] = dp[2] = d * 1.645922781;
+ //dp[3] = dp[4] = dp[5] = d * 2.850821881;
dp += 6;
break;
case kGTOType_D5:
+ // D(0): GNC(2,a,n) * (1/2) * (3zz-rr) * r^n * exp(-a*r^2)
+ // D(+1): GNC(2,a,n) * sqrt(3) * xz * r^n * exp(-a*r^2)
+ // D(-1): GNC(2,a,n) * sqrt(3) * yz * r^n * exp(-a*r^2)
+ // D(+2): GNC(2,a,n) * (sqrt(3)/2) * (xx-yy) * r^n * exp(-a*r^2)
+ // D(-2): GNC(2,a,n) * sqrt(3) * xy * r^n * exp(-a*r^2)
+ d = pp->C * sGaussianNormalizationConstant(2, pp->A, n);
+ //{ printf("type_D5[0]: %g %g\n", d * 0.5, pp->C * pow(pp->A, 1.75) * 0.822961390); }
+ //{ printf("type_D5[1,2,4]: %g %g\n", d * sqrt(3), pp->C * pow(pp->A, 1.75) * 2.850821881); }
+ //{ printf("type_D5[3]: %g %g\n", d * sqrt(3) * 0.5, pp->C * pow(pp->A, 1.75) * 1.425410941); }
+ dp[0] = d * 0.5;
+ dp[1] = dp[2] = dp[4] = d * sqrt(3);
+ dp[3] = d * sqrt(3) * 0.5;
// 3zz-rr: (128 alpha^7/9pi^3)^0.25 (3zz-rr)exp(-alpha r^2)
// xy|yz|zx: (2048 alpha^7/pi^3)^0.25 [xy|xz|yz]exp(-alpha r^2)
// xx-yy: (128 alpha^7/pi^3)^0.25 (xx-yy)exp(-alpha r^2)
- d = pp->C * pow(pp->A, 1.75);
- dp[0] = d * 0.822961390;
- dp[1] = dp[2] = dp[4] = d * 2.850821881;
- dp[3] = d * 1.425410941;
+ //d = pp->C * pow(pp->A, 1.75);
+ //dp[0] = d * 0.822961390;
+ //dp[1] = dp[2] = dp[4] = d * 2.850821881;
+ //dp[3] = d * 1.425410941;
dp += 5;
break;
+ case kGTOType_F:
+ // GNC(3,a,n) * [xxx|yyy|zzz] * r^n * exp(-a*r^2)
+ // GNC(3,a,n) * sqrt(5) * [xyy|xxy|xxz|xzz|yzz|yyz] * r^n * exp(-a*r^2)
+ // GNC(3,a,n) * sqrt(15) * xyz * r^n * exp(-a*r^2)
+ d = pp->C * sGaussianNormalizationConstant(3, pp->A, n);
+ dp[0] = dp[1] = dp[2] = d;
+ dp[3] = dp[4] = dp[5] = dp[6] = dp[7] = dp[8] = d * sqrt(5);
+ dp[9] = d * sqrt(15);
+ dp += 10;
+ break;
+ case kGTOType_F7:
+ // F(0): GNC(3,a,n) * (1/2) * (5zzz-3zrr) * r^n * exp(-a*r^2)
+ // F(+1): GNC(3,a,n) * sqrt(3/8) * (5xzz-xrr) * r^n * exp(-a*r^2)
+ // F(-1): GNC(3,a,n) * sqrt(3/8) * (5yzz-yrr) * r^n * exp(-a*r^2)
+ // F(+2): GNC(3,a,n) * sqrt(15/4) * (xxz-yyz) * r^n * exp(-a*r^2)
+ // F(-2): GNC(3,a,n) * sqrt(15) * xyz * r^n * exp(-a*r^2)
+ // F(+3): GNC(3,a,n) * sqrt(5/8) * (xxx-3xyy) * r^n * exp(-a*r^2)
+ // F(-3): GNC(3,a,n) * sqrt(5/8) * (3xxy-yyy) * r^n * exp(-a*r^2)
+ d = pp->C * sGaussianNormalizationConstant(3, pp->A, n);
+ dp[0] = d * 0.5;
+ dp[1] = dp[2] = d * sqrt(3/8.0);
+ dp[3] = d * sqrt(15/4.0);
+ dp[4] = d * sqrt(15);
+ dp[5] = dp[6] = d * sqrt(5/8.0);
+ dp += 7;
+ break;
+ case kGTOType_G:
+ // GNC(4,a,n) * [xxxx|yyyy|zzzz] * exp(-a*r^2)
+ // GNC(4,a,n) * sqrt(7) * [xxxy|xxxz|yyyx|yyyz|zzzx|zzzy] * exp(-a*r^2)
+ // GNC(4,a,n) * sqrt(35/3) * [xxyy|xxzz|yyzz] * exp(-a*r^2)
+ // GNC(4,a,n) * sqrt(35) * [xxyz|yyzx|zzxy] * exp(-a*r^2)
+ d = pp->C * sGaussianNormalizationConstant(4, pp->A, n);
+ dp[0] = dp[1] = dp[2] = d;
+ dp[3] = dp[4] = dp[5] = dp[6] = dp[7] = dp[8] = d * sqrt(7);
+ dp[9] = dp[10] = dp[11] = d * sqrt(35/3.0);
+ dp[12] = dp[13] = dp[14] = d * sqrt(35);
+ dp += 15;
+ break;
+ case kGTOType_G9:
+ // G(0): GNC(4,a,n) * (1/8) * (35zzzz-30zzrr+3rrrr) * exp(-a*r^2)
+ // G(+1): GNC(4,a,n) * sqrt(5/8) * (7xzzz-3xzrr) * exp(-a*r^2)
+ // G(-1): GNC(4,a,n) * sqrt(5/8) * (7yzzz-3yzrr) * exp(-a*r^2)
+ // G(+2): GNC(4,a,n) * sqrt(5/16) * (xx-yy)(7zz-rr) * exp(-a*r^2)
+ // G(-2): GNC(4,a,n) * sqrt(5/4) * (7xyzz-xyrr) * exp(-a*r^2)
+ // G(+3): GNC(4,a,n) * sqrt(35/8) * (xxxz-3xyyz) * exp(-a*r^2)
+ // G(-3): GNC(4,a,n) * sqrt(35/8) * (3xxyz-yyyz) * exp(-a*r^2)
+ // G(+4): GNC(4,a,n) * sqrt(35/64) * (xxxx-6xxyy+yyyy) * exp(-a*r^2)
+ // G(-4): GNC(4,a,n) * sqrt(35/4) * (xxxy-xyyy) * exp(-a*r^2)
+ d = pp->C * sGaussianNormalizationConstant(4, pp->A, n);
+ dp[0] = d * 0.125;
+ dp[1] = dp[2] = d * sqrt(5/8.0);
+ dp[3] = d * sqrt(5/16.0);
+ dp[4] = d * sqrt(5/4.0);
+ dp[5] = dp[6] = d * sqrt(35/8.0);
+ dp[7] = d * sqrt(35/64.0);
+ dp[8] = d * sqrt(35/4.0);
+ dp += 9;
+ break;
}
}
}
}
int
-MoleculeLoadGaussianFchkFile(Molecule *mp, const char *fname, char *errbuf, int errbufsize)
+MoleculeLoadGaussianFchkFile(Molecule *mp, const char *fname, char **errbuf)
{
FILE *fp;
char buf[1024];
Int *iary;
Double *dary;
Atom *ap;
- Vector *vp;
+/* Vector *vp; */
Double w;
- if (errbuf == NULL) {
- errbuf = buf;
- errbufsize = 1024;
- }
- errbuf[0] = 0;
+ *errbuf = NULL;
if (mp == NULL)
mp = MoleculeNew();
bset = (BasisSet *)calloc(sizeof(BasisSet), 1);
mp->bset = bset;
fp = fopen(fname, "rb");
if (fp == NULL) {
- snprintf(errbuf, errbufsize, "Cannot open file");
+ s_append_asprintf(errbuf, "Cannot open file");
return 1;
}
lineNumber = 0;
sSeparateTokens(buf + 42, tokens, 16);
if (strcmp(buf, "Number of atoms") == 0) {
if (tokens[1] == NULL || (natoms = atoi(tokens[1])) <= 0) {
- snprintf(errbuf, errbufsize, "Line %d: strange number of atoms: %s", lineNumber, tokens[1]);
+ s_append_asprintf(errbuf, "Line %d: strange number of atoms: %s", lineNumber, tokens[1]);
retval = 2;
goto cleanup;
}
+ bset->natoms_bs = natoms;
/* Allocate atom records (all are empty for now) */
AssignArray(&mp->atoms, &mp->natoms, gSizeOfAtomRecord, natoms - 1, NULL);
/* Also allocate atom position array for MO calculations */
- AssignArray(&bset->pos, &bset->natoms, sizeof(Vector), natoms - 1, NULL);
+ /* AssignArray(&bset->pos, &bset->natoms, sizeof(Vector), natoms - 1, NULL); */
/* Also allocate nuclear charge array */
bset->nuccharges = (Double *)calloc(sizeof(Double), natoms);
} else if (strcmp(buf, "Number of electrons") == 0) {
if (tokens[1] == NULL || (i = atoi(tokens[1])) < 0) {
- snprintf(errbuf, errbufsize, "Line %d: strange number of electrons: %s", lineNumber, tokens[1]);
+ s_append_asprintf(errbuf, "Line %d: strange number of electrons: %s", lineNumber, tokens[1]);
retval = 2;
goto cleanup;
}
nelec = i;
} else if (strcmp(buf, "Number of alpha electrons") == 0) {
if (tokens[1] == NULL || (i = atoi(tokens[1])) < 0) {
- snprintf(errbuf, errbufsize, "Line %d: strange number of alpha electrons: %s", lineNumber, tokens[1]);
+ s_append_asprintf(errbuf, "Line %d: strange number of alpha electrons: %s", lineNumber, tokens[1]);
retval = 2;
goto cleanup;
}
bset->ne_alpha = i;
} else if (strcmp(buf, "Number of beta electrons") == 0) {
if (tokens[1] == NULL || (i = atoi(tokens[1])) < 0) {
- snprintf(errbuf, errbufsize, "Line %d: strange number of beta electrons: %s", lineNumber, tokens[1]);
+ s_append_asprintf(errbuf, "Line %d: strange number of beta electrons: %s", lineNumber, tokens[1]);
retval = 2;
goto cleanup;
}
bset->ne_beta = i;
if (bset->ne_alpha + bset->ne_beta != nelec) {
- snprintf(errbuf, errbufsize, "Line %d: sum of alpha (%d) and beta (%d) electrons does not match the number of electrons (%d)", lineNumber, (int)bset->ne_alpha, (int)bset->ne_beta, (int)nelec);
+ s_append_asprintf(errbuf, "Line %d: sum of alpha (%d) and beta (%d) electrons does not match the number of electrons (%d)", lineNumber, (int)bset->ne_alpha, (int)bset->ne_beta, (int)nelec);
retval = 2;
goto cleanup;
}
} else if (strcmp(buf, "Number of basis functions") == 0) {
if (tokens[1] == NULL || (nbasis = atoi(tokens[1])) <= 0) {
- snprintf(errbuf, errbufsize, "Line %d: strange number of basis functions: %s", lineNumber, tokens[1]);
+ s_append_asprintf(errbuf, "Line %d: strange number of basis functions: %s", lineNumber, tokens[1]);
retval = 2;
goto cleanup;
}
} else if (strcmp(buf, "Atomic numbers") == 0) {
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0 || i != natoms) {
- snprintf(errbuf, errbufsize, "Line %d: wrong or inconsistent number of atoms: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong or inconsistent number of atoms: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&iary, &nary, sizeof(Int), natoms, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read atomic numbers", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read atomic numbers", lineNumber);
retval = 2;
goto cleanup;
}
iary = NULL;
} else if (strcmp(buf, "Nuclear charges") == 0) {
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0 || i != natoms) {
- snprintf(errbuf, errbufsize, "Line %d: wrong or inconsistent number of atoms: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong or inconsistent number of atoms: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&dary, &nary, sizeof(Double), natoms, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read nuclear charges", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read nuclear charges", lineNumber);
retval = 2;
goto cleanup;
}
iary = NULL;
} else if (strcmp(buf, "Current cartesian coordinates") == 0) {
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0 || i != natoms * 3) {
- snprintf(errbuf, errbufsize, "Line %d: wrong or inconsistent number of cartesian coordinates: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong or inconsistent number of cartesian coordinates: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&dary, &nary, sizeof(Double), natoms * 3, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read cartesian coordinates", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read cartesian coordinates", lineNumber);
retval = 2;
goto cleanup;
}
- for (i = 0, ap = mp->atoms, vp = bset->pos; i < natoms; i++, ap = ATOM_NEXT(ap), vp++) {
- vp->x = dary[i * 3];
- vp->y = dary[i * 3 + 1];
- vp->z = dary[i * 3 + 2];
- ap->r.x = vp->x * kBohr2Angstrom;
- ap->r.y = vp->y * kBohr2Angstrom;
- ap->r.z = vp->z * kBohr2Angstrom;
+ for (i = 0, ap = mp->atoms; i < natoms; i++, ap = ATOM_NEXT(ap)) {
+ ap->r.x = dary[i * 3] * kBohr2Angstrom;
+ ap->r.y = dary[i * 3 + 1] * kBohr2Angstrom;
+ ap->r.z = dary[i * 3 + 2] * kBohr2Angstrom;
}
free(dary);
dary = NULL;
} else if (strcmp(buf, "MxBond") == 0) {
if (tokens[1] == NULL || (mxbond = atoi(tokens[1])) <= 0) {
- snprintf(errbuf, errbufsize, "Line %d: strange number of bonds per atom: %s", lineNumber, tokens[1]);
+ s_append_asprintf(errbuf, "Line %d: strange number of bonds per atom: %s", lineNumber, tokens[1]);
retval = 2;
goto cleanup;
}
} else if (strcmp(buf, "IBond") == 0) {
Int *bonds;
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0 || i != natoms * mxbond) {
- snprintf(errbuf, errbufsize, "Line %d: wrong or inconsistent number of bonds: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong or inconsistent number of bonds: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&iary, &nary, sizeof(Int), natoms * mxbond, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read bond information", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read bond information", lineNumber);
retval = 2;
goto cleanup;
}
}
if (k > 0) {
bonds[k] = kInvalidIndex;
- MoleculeAddBonds(mp, k / 2, bonds);
+ MoleculeAddBonds(mp, k / 2, bonds, NULL, 1);
}
}
free(iary);
iary = NULL;
} else if (strcmp(buf, "Shell types") == 0) {
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0) {
- snprintf(errbuf, errbufsize, "Line %d: wrong number of shell types: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong number of shell types: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&iary, &nary, sizeof(Int), i, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read shell types", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read shell types", lineNumber);
retval = 2;
goto cleanup;
}
case -1: sp->sym = kGTOType_SP; sp->ncomp = 4; break;
case 2: sp->sym = kGTOType_D; sp->ncomp = 6; break;
case -2: sp->sym = kGTOType_D5; sp->ncomp = 5; break;
- /* TODO: Support F/F7 type orbitals */
- /* case 3: sp->sym = kGTOtype_F; sp->ncomp = 10; break;
- case -3: sp->sym = kGTOType_F7; sp->ncomp = 7; break; */
+ case 3: sp->sym = kGTOType_F; sp->ncomp = 10; break;
+ case -3: sp->sym = kGTOType_F7; sp->ncomp = 7; break;
+ case 4: sp->sym = kGTOType_G; sp->ncomp = 15; break;
+ case -4: sp->sym = kGTOType_G9; sp->ncomp = 9; break;
default:
- snprintf(errbuf, errbufsize, "Line %d: unsupported shell type %d", lineNumber, iary[i]);
+ s_append_asprintf(errbuf, "Line %d: unsupported shell type %d", lineNumber, iary[i]);
retval = 2;
goto cleanup;
}
iary = NULL;
} else if (strcmp(buf, "Number of primitives per shell") == 0) {
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0 || i != bset->nshells) {
- snprintf(errbuf, errbufsize, "Line %d: wrong size of the primitive table: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong size of the primitive table: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&iary, &nary, sizeof(Int), i, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read primitive table", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read primitive table", lineNumber);
retval = 2;
goto cleanup;
}
iary = NULL;
} else if (strcmp(buf, "Shell to atom map") == 0) {
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0 || i != bset->nshells) {
- snprintf(errbuf, errbufsize, "Line %d: wrong size of the shell-to-atom map: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong size of the shell-to-atom map: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&iary, &nary, sizeof(Int), i, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read shell-to-atom table", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read shell-to-atom table", lineNumber);
retval = 2;
goto cleanup;
}
iary = NULL;
} else if (strcmp(buf, "Primitive exponents") == 0) {
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0 || i != nprims) {
- snprintf(errbuf, errbufsize, "Line %d: wrong number of primitive exponents: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong number of primitive exponents: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&dary, &nary, sizeof(Double), i, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read primitive exponents", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read primitive exponents", lineNumber);
retval = 2;
goto cleanup;
}
dary = NULL;
} else if (strcmp(buf, "Contraction coefficients") == 0) {
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0 || i != bset->npriminfos) {
- snprintf(errbuf, errbufsize, "Line %d: wrong number of contraction coefficients: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong number of contraction coefficients: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&dary, &nary, sizeof(Double), i, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read contraction coefficients", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read contraction coefficients", lineNumber);
retval = 2;
goto cleanup;
}
dary = NULL;
} else if (strcmp(buf, "P(S=P) Contraction coefficients") == 0) {
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0 || i != bset->npriminfos) {
- snprintf(errbuf, errbufsize, "Line %d: wrong number of P(S=P) contraction coefficients: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong number of P(S=P) contraction coefficients: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&dary, &nary, sizeof(Double), i, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read P(S=P) contraction coefficients", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read P(S=P) contraction coefficients", lineNumber);
retval = 2;
goto cleanup;
}
dary = NULL;
} else if (strcmp(buf, "Alpha Orbital Energies") == 0) {
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0 || i != ncomps) {
- snprintf(errbuf, errbufsize, "Line %d: wrong or inconsistent number of alpha orbitals: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong or inconsistent number of alpha orbitals: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&bset->moenergies, &bset->nmos, sizeof(Double), i, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read alpha orbital energies", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read alpha orbital energies", lineNumber);
retval = 2;
goto cleanup;
}
} else if (strcmp(buf, "Alpha MO coefficients") == 0) {
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0 || i != ncomps * ncomps) {
- snprintf(errbuf, errbufsize, "Line %d: wrong or inconsistent number of alpha MO coefficients: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong or inconsistent number of alpha MO coefficients: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&bset->mo, &nary, sizeof(Double), i, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read MO coefficients", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read MO coefficients", lineNumber);
retval = 2;
goto cleanup;
}
} else if (strcmp(buf, "Beta Orbital Energies") == 0) {
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0 || i != ncomps) {
- snprintf(errbuf, errbufsize, "Line %d: wrong or inconsistent number of beta orbitals: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong or inconsistent number of beta orbitals: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&dary, &nary, sizeof(Double), i, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read beta orbital energies", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read beta orbital energies", lineNumber);
retval = 2;
goto cleanup;
}
dary = NULL;
} else if (strcmp(buf, "Beta MO coefficients") == 0) {
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0 || i != ncomps * ncomps) {
- snprintf(errbuf, errbufsize, "Line %d: wrong or inconsistent number of beta MO coefficients: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong or inconsistent number of beta MO coefficients: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&dary, &nary, sizeof(Double), i, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read alpha MO coefficients", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read alpha MO coefficients", lineNumber);
retval = 2;
goto cleanup;
}
dary = NULL;
} else if (strcmp(buf, "Total SCF Density") == 0) {
if (tokens[2] == NULL || (i = atoi(tokens[2])) <= 0 || i != ncomps * (ncomps + 1) / 2) {
- snprintf(errbuf, errbufsize, "Line %d: wrong or inconsistent number of SCF densities: %s", lineNumber, tokens[2]);
+ s_append_asprintf(errbuf, "Line %d: wrong or inconsistent number of SCF densities: %s", lineNumber, tokens[2]);
retval = 2;
goto cleanup;
}
if (sReadNumberArray(&bset->scfdensities, &nary, sizeof(Double), i, fp, &lineNumber) != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot read SCF densities", lineNumber);
+ s_append_asprintf(errbuf, "Line %d: cannot read SCF densities", lineNumber);
retval = 2;
goto cleanup;
}
}
}
if (mp->natoms == 0) {
- snprintf(errbuf, errbufsize, "Atom information is missing");
+ s_append_asprintf(errbuf, "Atom information is missing");
retval = 2;
goto cleanup;
}
if (bset->shells == NULL || bset->priminfos == NULL) {
- snprintf(errbuf, errbufsize, "Gaussian primitive information is missing");
+ s_append_asprintf(errbuf, "Gaussian primitive information is missing");
retval = 2;
goto cleanup;
}
if (bset->mo == NULL) {
- snprintf(errbuf, errbufsize, "MO coefficients were not found");
+ s_append_asprintf(errbuf, "MO coefficients were not found");
retval = 2;
goto cleanup;
}
if (sSetupGaussianCoefficients(bset) != 0) {
- snprintf(errbuf, errbufsize, "Internal error during setup MO calculation");
+ s_append_asprintf(errbuf, "Internal error during setup MO calculation");
retval = 2;
goto cleanup;
}
}
int
-MoleculeLoadGamessDatFile(Molecule *mol, const char *fname, char *errbuf, int errbufsize)
+MoleculeLoadGamessDatFile(Molecule *mol, const char *fname, char **errbuf)
{
FILE *fp;
int newmol = 0;
int lineNumber, i, j, k, len, natoms = 0;
int nframes = 0;
int n1;
+ int retval = 0;
int ival[8];
double dval[8];
char sval[16];
Vector *vbuf = NULL;
IntGroup *ig;
int optimizing = 0, status = 0;
-
- if (errbuf == NULL) {
- errbuf = buf;
- errbufsize = 1024;
- }
- errbuf[0] = 0;
+
+ *errbuf = NULL;
if (mol == NULL) {
mol = MoleculeNew();
}
fp = fopen(fname, "rb");
if (fp == NULL) {
- snprintf(errbuf, errbufsize, "Cannot open file");
+ s_append_asprintf(errbuf, "Cannot open file");
return 1;
}
if (strncmp(buf, " $END", 5) == 0)
break;
if (sscanf(buf, "%12s %lf %lf %lf %lf", sval, &dval[0], &dval[1], &dval[2], &dval[3]) < 5) {
- snprintf(errbuf, errbufsize, "Line %d: bad format in $DATA section", lineNumber);
- return 2;
+ s_append_asprintf(errbuf, "Line %d: bad format in $DATA section", lineNumber);
+ retval = 2;
+ goto exit_loop;
}
if (newmol) {
Atom a;
} else {
Atom *ap;
if (i >= mol->natoms) {
- snprintf(errbuf, errbufsize, "Line %d: too many atoms", lineNumber);
- return 3;
+ s_append_asprintf(errbuf, "Line %d: too many atoms", lineNumber);
+ retval = 3;
+ goto exit_loop;
}
if ((ap = ATOM_AT_INDEX(mol->atoms, i))->atomicNumber != dval[0]) {
- snprintf(errbuf, errbufsize, "Line %d: atomic number does not match", lineNumber);
- return 4;
+ s_append_asprintf(errbuf, "Line %d: atomic number does not match", lineNumber);
+ retval = 4;
+ goto exit_loop;
}
vbuf[i].x = dval[1];
vbuf[i].y = dval[2];
vbuf[i].z = dval[3];
}
/* Skip until a blank line is found */
+ /* 2013.6.11. Line including "PM3" is also recognized as the end of atom */
while ((status = sReadLineWithInterrupt(buf, sizeof buf, fp, &lineNumber)) > 0) {
for (j = 0; buf[j] == ' '; j++);
- if (buf[j] == '\n')
+ if (buf[j] == '\n' || strncmp(buf + j, "PM3", 3) == 0)
break;
}
i++;
/* Set atom positions */
IntGroup *ig;
if (natoms < mol->natoms) {
- snprintf(errbuf, errbufsize, "Line %d: too few atoms", lineNumber);
- return 5;
+ s_append_asprintf(errbuf, "Line %d: too few atoms", lineNumber);
+ retval = 5;
+ goto exit_loop;
}
ig = IntGroupNewWithPoints(0, natoms, -1);
MolActionCreateAndPerform(mol, gMolActionSetAtomPositions, ig, natoms, vbuf);
i = 0;
do {
if (i++ >= 4) {
- snprintf(errbuf, errbufsize, "Line %d: the separator line at the top of the coordinates is not found: bad format?", lineNumber);
- return 6;
+ s_append_asprintf(errbuf, "Line %d: the separator line at the top of the coordinates is not found: bad format?", lineNumber);
+ retval = 6;
+ goto exit_loop;
}
ReadLine(buf, sizeof buf, fp, &lineNumber);
} while (strstr(buf, "----------------------------") == NULL);
for (i = 0; i < natoms; i++) {
if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0) {
- snprintf(errbuf, errbufsize, "Unexpected end of file in reading NSERCH data");
- return 6;
+ s_append_asprintf(errbuf, "Unexpected end of file in reading NSERCH data");
+ retval = 6;
+ goto exit_loop;
}
if (sscanf(buf, "%12s %lf %lf %lf %lf", sval, &dval[0], &dval[1], &dval[2], &dval[3]) < 5) {
- snprintf(errbuf, errbufsize, "Line %d: bad format in NSERCH coordinate data", lineNumber);
- return 7;
+ s_append_asprintf(errbuf, "Line %d: bad format in NSERCH coordinate data", lineNumber);
+ retval = 6;
+ goto exit_loop;
}
vbuf[i].x = dval[1];
vbuf[i].y = dval[2];
continue;
} else if (strstr(buf, "E(UHF)") != NULL || (strstr(buf, "E(RHF)") != NULL && (n1 = 1)) || (strstr(buf, "E(ROHF)") != NULL && (n1 = 2))) {
if (mol->bset == NULL) {
- i = MoleculeAllocateBasisSetRecord(mol, n1, 0, 0);
+ i = MoleculeSetMOInfo(mol, n1, 0, 0);
if (i != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot allocate basis set internal buffer", lineNumber);
- return 8;
+ s_append_asprintf(errbuf, "Line %d: cannot allocate basis set internal buffer", lineNumber);
+ retval = 8;
+ goto exit_loop;
}
}
} else if (strncmp(buf, " $VEC", 5) == 0) {
continue; /* Ignore VEC group during optimization */
coeffs = (Double *)calloc(sizeof(Double), mol->bset->ncomps);
if (coeffs == NULL) {
- snprintf(errbuf, errbufsize, "Line %d: low memory during $VEC", lineNumber);
- return 9;
+ s_append_asprintf(errbuf, "Line %d: low memory during $VEC", lineNumber);
+ retval = 9;
+ goto exit_loop;
}
i = k = 0;
while ((status = sReadLineWithInterrupt(buf, sizeof buf, fp, &lineNumber)) > 0) {
}
if (k < mol->bset->ncomps)
continue;
- j = MoleculeSetMOCoefficients(mol, i, -1000000, k, coeffs);
+ j = MoleculeSetMOCoefficients(mol, i + 1, -1000000, k, coeffs);
if (j != 0) {
- snprintf(errbuf, errbufsize, "Line %d: cannot set coefficients for MO %d", lineNumber, i + 1);
+ s_append_asprintf(errbuf, "Line %d: cannot set coefficients for MO %d", lineNumber, i + 1);
free(coeffs);
- return 10;
+ retval = 10;
+ goto exit_loop;
}
i++;
k = 0;
} /* TODO: read MOLPLT info if present */
}
if (status < 0) {
- snprintf(errbuf, errbufsize, "User interrupt at line %d", lineNumber);
- return 11;
+ s_append_asprintf(errbuf, "User interrupt at line %d", lineNumber);
+ retval = 11;
}
+exit_loop:
if (vbuf != NULL)
free(vbuf);
+ if (mol->natoms > 0)
+ retval = 0; /* Return the partially constructed molecule */
if (newmol && mol->nbonds == 0) {
/* Guess bonds */
Int nbonds, *bonds;
- MoleculeGuessBonds(mol, 1.2, &nbonds, &bonds);
+ MoleculeGuessBonds(mol, 0.0, &nbonds, &bonds);
if (nbonds > 0) {
- MolActionCreateAndPerform(mol, gMolActionAddBonds, nbonds * 2, bonds);
+ MolActionCreateAndPerform(mol, gMolActionAddBonds, nbonds * 2, bonds, NULL);
free(bonds);
}
}
}
int
-MoleculeReadCoordinatesFromFile(Molecule *mp, const char *fname, const char *ftype, char *errbuf, int errbufsize)
+MoleculeReadCoordinatesFromFile(Molecule *mp, const char *fname, const char *ftype, char **errbuf)
{
int retval;
if (ftype == NULL || *ftype == 0) {
}
}
if (strcasecmp(ftype, "pdb") == 0) {
- retval = MoleculeReadCoordinatesFromPdbFile(mp, fname, errbuf, errbufsize);
+ retval = MoleculeReadCoordinatesFromPdbFile(mp, fname, errbuf);
}
if (retval != 0) {
/* Try all formats once again */
- retval = MoleculeReadCoordinatesFromPdbFile(mp, fname, errbuf, errbufsize);
+ retval = MoleculeReadCoordinatesFromPdbFile(mp, fname, errbuf);
}
return retval;
}
int
-MoleculeReadCoordinatesFromPdbFile(Molecule *mp, const char *fname, char *errbuf, int errbufsize)
+MoleculeReadCoordinatesFromPdbFile(Molecule *mp, const char *fname, char **errbuf)
{
FILE *fp;
char buf[1024];
Int ibuf[12];
Int entries = 0;
retval = 0;
- if (errbuf == NULL) {
- errbuf = buf;
- errbufsize = 1024;
- }
- errbuf[0] = 0;
+ *errbuf = NULL;
fp = fopen(fname, "rb");
if (fp == NULL) {
- snprintf(errbuf, errbufsize, "Cannot open file");
+ s_append_asprintf(errbuf, "Cannot open file");
return -1;
}
/* flockfile(fp); */
else
w.occ = atof(w.occStr);
if (w.serial <= 0) {
- snprintf(errbuf, errbufsize, "line %d: non-positive atom number %d", lineNumber, w.serial);
+ s_append_asprintf(errbuf, "line %d: non-positive atom number %d", lineNumber, w.serial);
retval = 1;
goto abort;
}
/* Create a new atom entry */
ap = AssignArray(&mp->atoms, &mp->natoms, gSizeOfAtomRecord, w.serial, NULL);
} else {
- snprintf(errbuf, errbufsize, "line %d: the atom number %d does not exist in the structure file", lineNumber, w.serial+1);
+ s_append_asprintf(errbuf, "line %d: the atom number %d does not exist in the structure file", lineNumber, w.serial+1);
retval = 1;
goto abort;
}
strncpy(ap->resName, w.resName, 4);
strncpy(ap->aname, w.atomName, 4);
strncpy(ap->element, w.element, 2);
+ ap->element[2] = 0;
+ ap->atomicNumber = ElementToInt(ap->element);
+ ap->type = AtomTypeEncodeToUInt(ap->element);
+ ap->weight = WeightForAtomicNumber(ap->atomicNumber);
ap->intCharge = w.intCharge;
if (ap->resSeq > 0) {
if (ap->resSeq < mp->nresidues) {
int bi;
for (j = 0; j < i; j++) {
if (ibuf[j] < 0 || ibuf[j] > mp->natoms) {
- snprintf(errbuf, errbufsize, "line %d: The CONECT record contains non-existent atom %d", lineNumber, ibuf[j]);
+ s_append_asprintf(errbuf, "line %d: The CONECT record contains non-existent atom %d", lineNumber, ibuf[j]);
retval = 1;
goto abort;
} else if (ibuf[j] == 0)
continue;
for (j = 1, bi = 0; j < i; j++) {
if (ibuf[0] < ibuf[j]) {
- bbuf[bi * 2] = ibuf[0] - 1;
- bbuf[bi * 2 + 1] = ibuf[j] - 1;
- bi++;
+ if (MoleculeLookupBond(mp, ibuf[0], ibuf[j]) >= 0) {
+ s_append_asprintf(errbuf, "line %d: warning: duplicate bond %d-%d\n", lineNumber, ibuf[0], ibuf[j]);
+ } else {
+ bbuf[bi * 2] = ibuf[0] - 1;
+ bbuf[bi * 2 + 1] = ibuf[j] - 1;
+ bi++;
+ }
}
}
if (bi == 0)
continue;
bbuf[bi * 2] = -1;
- retval = MoleculeAddBonds(mp, bi, bbuf);
+ retval = MoleculeAddBonds(mp, bi, bbuf, NULL, 1);
if (retval < 0) {
- snprintf(errbuf, errbufsize, "line %d: bad bond specification", lineNumber);
+ s_append_asprintf(errbuf, "line %d: bad bond specification", lineNumber);
retval = 1;
goto abort;
}
int *old2new, oldidx, newidx;
old2new = (int *)calloc(sizeof(int), mp->natoms);
if (old2new == NULL) {
- snprintf(errbuf, errbufsize, "Out of memory");
+ s_append_asprintf(errbuf, "Out of memory");
retval = 1;
goto abort;
}
Int *cp;
for (i = 0; i < mp->natoms; i++) {
ap = ATOM_AT_INDEX(mp->atoms, i);
- cp = AtomConnects(ap);
- for (j = 0; j < ap->nconnects; j++) {
+ cp = AtomConnectData(&ap->connect);
+ for (j = 0; j < ap->connect.count; j++) {
cp[j] = old2new[cp[j]];
}
}
retval = MoleculeRebuildTablesFromConnects(mp);
if (retval != 0) {
/* This error may not happen */
- snprintf(errbuf, errbufsize, "Cannot build angle/dihedral/improper tables");
+ s_append_asprintf(errbuf, "Cannot build angle/dihedral/improper tables");
retval = 1;
goto abort;
}
}
int
-MoleculeReadCoordinatesFromDcdFile(Molecule *mp, const char *fname, char *errbuf, int errbufsize)
+MoleculeReadCoordinatesFromDcdFile(Molecule *mp, const char *fname, char **errbuf)
{
DcdRecord dcd;
SFloat32 *xp, *yp, *zp;
Vector *vp, *cp;
IntGroup *ig;
- int n;
- errbuf[0] = 0;
+ int n, errcount = 0;
+ *errbuf = NULL;
if (mp == NULL || mp->natoms == 0) {
- snprintf(errbuf, errbufsize, "Molecule is empty");
+ s_append_asprintf(errbuf, "Molecule is empty");
return 1;
}
n = DcdOpen(fname, &dcd);
if (n != 0) {
switch (n) {
- case -2: snprintf(errbuf, errbufsize, "Cannot open file"); break;
- case 1: snprintf(errbuf, errbufsize, "Premature EOF encountered"); break;
- case 2: snprintf(errbuf, errbufsize, "Bad block length of the first section"); break;
- case 3: snprintf(errbuf, errbufsize, "\"CORD\" signature is missing"); break;
- case 4: snprintf(errbuf, errbufsize, "Bad termination of the first section"); break;
- case 5: snprintf(errbuf, errbufsize, "The title section is not correct"); break;
- case 6: snprintf(errbuf, errbufsize, "The atom number section is not correct"); break;
- default: snprintf(errbuf, errbufsize, "Read error in dcd file"); break;
- }
+ case -2: s_append_asprintf(errbuf, "Cannot open file"); break;
+ case 1: s_append_asprintf(errbuf, "Premature EOF encountered"); break;
+ case 2: s_append_asprintf(errbuf, "Bad block length of the first section"); break;
+ case 3: s_append_asprintf(errbuf, "\"CORD\" signature is missing"); break;
+ case 4: s_append_asprintf(errbuf, "Bad termination of the first section"); break;
+ case 5: s_append_asprintf(errbuf, "The title section is not correct"); break;
+ case 6: s_append_asprintf(errbuf, "The atom number section is not correct"); break;
+ default: s_append_asprintf(errbuf, "Read error in dcd file"); break;
+ }
+ errcount++;
} else {
- if (dcd.natoms == 0)
- snprintf(errbuf, errbufsize, "No atoms were found in the dcd file");
- else if (dcd.nframes == 0)
- snprintf(errbuf, errbufsize, "No frames were found in the dcd file");
+ if (dcd.natoms == 0) {
+ s_append_asprintf(errbuf, "No atoms were found in the dcd file");
+ errcount++;
+ } else if (dcd.nframes == 0) {
+ s_append_asprintf(errbuf, "No frames were found in the dcd file");
+ errcount++;
+ }
}
- if (errbuf[0] != 0) {
+ if (errcount > 0) {
if (n == 0)
DcdClose(&dcd);
return 1;
zp = (SFloat32 *)malloc(sizeof(SFloat32) * dcd.natoms);
ig = IntGroupNewWithPoints(MoleculeGetNumberOfFrames(mp), dcd.nframes, -1);
if (vp == NULL || xp == NULL || yp == NULL || zp == NULL || ig == NULL) {
- snprintf(errbuf, errbufsize, "Cannot allocate memory");
+ s_append_asprintf(errbuf, "Cannot allocate memory");
if (vp) free(vp);
if (cp) free(cp);
if (xp) free(xp);
Vector *vpp;
SFloat32 dcdcell[6];
if (DcdReadFrame(&dcd, n, xp, yp, zp, dcdcell)) {
- snprintf(errbuf, errbufsize, "Read error in dcd file");
+ s_append_asprintf(errbuf, "Read error in dcd file");
goto exit;
}
for (i = 0, vpp = &vp[n * mp->natoms]; i < dcd.natoms && i < mp->natoms; i++, vpp++) {
vpp[3].x = vpp[3].y = vpp[3].z = 0.0;
if (mp->cell == NULL) {
/* Create periodicity if not present */
- MolActionCreateAndPerform(mp, gMolActionSetBox, &vpp[0], &vpp[1], &vpp[2], &vpp[3], 7);
+ MolActionCreateAndPerform(mp, gMolActionSetBox, &vpp[0], &vpp[1], &vpp[2], &vpp[3], 7, 0);
}
}
}
if (MolActionCreateAndPerform(mp, gMolActionInsertFrames, ig, mp->natoms * dcd.nframes, vp, (cp == NULL ? 0 : dcd.nframes * 4), cp) != 0)
- snprintf(errbuf, errbufsize, "Cannot insert frames");
+ s_append_asprintf(errbuf, "Cannot insert frames");
mp->startStep = dcd.nstart;
mp->stepsPerFrame = dcd.ninterval;
mp->psPerStep = dcd.delta;
free(yp);
free(zp);
IntGroupRelease(ig);
- if (errbuf[0] == 0)
+ if (errcount == 0)
return 0;
else return 1;
}
int
-MoleculeReadExtendedInfo(Molecule *mp, const char *fname, char *errbuf, int errbufsize)
+MoleculeReadExtendedInfo(Molecule *mp, const char *fname, char **errbuf)
{
FILE *fp;
char buf[1024];
double d[3];
int n, flag;
char flags[3];
+ *errbuf = NULL;
fp = fopen(fname, "rb");
if (fp == NULL) {
- snprintf(errbuf, errbufsize, "Cannot open file");
+ s_append_asprintf(errbuf, "Cannot open file");
return -1;
}
errbuf[0] = 0;
if (strncmp(buf, "Bounding box:", 13) == 0) {
for (i = 0; i < 3; i++) {
if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0) {
- snprintf(errbuf, errbufsize, "line %d: missing %d component of the bounding box", lineNumber, i + 1);
+ s_append_asprintf(errbuf, "line %d: missing %d component of the bounding box", lineNumber, i + 1);
retval = 1;
goto abort;
}
vv = mp->cell->origin;
else
vv.x = vv.y = vv.z = 0.0;
- MoleculeSetPeriodicBox(mp, &v[0], &v[1], &v[2], &vv, flags);
+ MoleculeSetPeriodicBox(mp, &v[0], &v[1], &v[2], &vv, flags, 0);
} else if (strncmp(buf, "Bounding box origin:", 20) == 0) {
if (mp->cell != NULL) {
v[0] = mp->cell->axes[0];
flags[0] = flags[1] = flags[2] = 1.0;
}
if (ReadLine(buf, sizeof buf, fp, &lineNumber) <= 0 || (n = sscanf(buf, "%lf %lf %lf", &d[0], &d[1], &d[2]) < 3)) {
- snprintf(errbuf, errbufsize, "line %d: wrong format for the bounding box origin", lineNumber);
+ s_append_asprintf(errbuf, "line %d: wrong format for the bounding box origin", lineNumber);
retval = 1;
goto abort;
}
vv.x = d[0];
vv.y = d[1];
vv.z = d[2];
- MoleculeSetPeriodicBox(mp, &v[0], &v[1], &v[2], &vv, flags);
+ MoleculeSetPeriodicBox(mp, &v[0], &v[1], &v[2], &vv, flags, 0);
}
}
fclose(fp);
}
int
-MoleculeWriteToFile(Molecule *mp, const char *fname, const char *ftype, char *errbuf, int errbufsize)
+MoleculeWriteToFile(Molecule *mp, const char *fname, const char *ftype, char **errbuf)
{
int retval;
+ *errbuf = NULL;
if (ftype == NULL || *ftype == 0) {
const char *cp;
cp = strrchr(fname, '.');
}
}
if (strcasecmp(ftype, "psf") == 0) {
- retval = MoleculeWriteToPsfFile(mp, fname, errbuf, errbufsize);
+ retval = MoleculeWriteToPsfFile(mp, fname, errbuf);
} else if (strcasecmp(ftype, "pdb") == 0) {
- retval = MoleculeWriteToPdbFile(mp, fname, errbuf, errbufsize);
+ retval = MoleculeWriteToPdbFile(mp, fname, errbuf);
} else if (strcasecmp(ftype, "tep") == 0) {
- retval = MoleculeWriteToTepFile(mp, fname, errbuf, errbufsize);
+ retval = MoleculeWriteToTepFile(mp, fname, errbuf);
} else {
- snprintf(errbuf, errbufsize, "The file format should be specified");
+ s_append_asprintf(errbuf, "The file format should be specified");
retval = 1;
}
if (retval == 0)
}
int
-MoleculeWriteToMbsfFile(Molecule *mp, const char *fname, char *errbuf, int errbufsize)
+MoleculeWriteToMbsfFile(Molecule *mp, const char *fname, char **errbuf)
{
FILE *fp;
- int i, j, k, n1, n2, n3, n_aniso;
+ Int i, j, k, n1, n2, n3, n_aniso, nframes, nanchors, n_uff;
Atom *ap;
+ char *p;
char bufs[6][8];
+ *errbuf = NULL;
fp = fopen(fname, "wb");
if (fp == NULL) {
- snprintf(errbuf, errbufsize, "Cannot write to file %s", fname);
+ s_append_asprintf(errbuf, "Cannot write to file %s", fname);
return 1;
}
errbuf[0] = 0;
+ nframes = MoleculeFlushFrames(mp);
+
fprintf(fp, "!:atoms\n");
fprintf(fp, "! idx seg_name res_seq res_name name type charge weight element atomic_number occupancy temp_factor int_charge\n");
- n1 = n2 = n3 = n_aniso = 0;
+ n1 = n2 = n3 = n_aniso = nanchors = n_uff = 0;
for (i = 0, ap = mp->atoms; i < mp->natoms; i++, ap = ATOM_NEXT(ap)) {
strncpy(bufs[0], ap->segName, 4);
bufs[0][4] = 0;
n3++;
if (ap->aniso != NULL)
n_aniso++;
+ if (ap->anchor != NULL)
+ nanchors++;
+ if (ap->uff_type[0] != 0)
+ n_uff++;
fprintf(fp, "%d %s %d %s %s %s %.5f %.5f %s %d %f %f %d\n", i, bufs[0], ap->resSeq, bufs[1], bufs[2], bufs[3], ap->charge, ap->weight, bufs[4], ap->atomicNumber, ap->occupancy, ap->tempFactor, ap->intCharge);
}
fprintf(fp, "\n");
+ if (n_uff > 0) {
+ fprintf(fp, "!:uff_type\n");
+ fprintf(fp, "! idx uff_type\n");
+ for (i = 0, ap = mp->atoms; i < mp->natoms; i++, ap = ATOM_NEXT(ap)) {
+ fprintf(fp, "%d %.5s\n", i, ap->uff_type);
+ }
+ fprintf(fp, "\n");
+ }
+
if (n1 > 0) {
fprintf(fp, "!:atoms_symop\n");
fprintf(fp, "! idx symop symbase\n");
fprintf(fp, "\n");
}
- if ((n1 = MoleculeGetNumberOfFrames(mp)) > 0)
+ if (nanchors > 0) {
+ fprintf(fp, "!:pi_anchor\n");
+ fprintf(fp, "! idx count; n1 weight1; n2 weight2; ...; nN weightN\n");
+ for (i = 0, ap = mp->atoms; i < mp->natoms; i++, ap = ATOM_NEXT(ap)) {
+ Int *ip;
+ if (ap->anchor == NULL)
+ continue;
+ k = ap->anchor->connect.count;
+ ip = AtomConnectData(&ap->anchor->connect);
+ fprintf(fp, "%d %d\n", i, k);
+ for (j = 0; j < k; j++) {
+ fprintf(fp, "%d %f\n", ip[j], ap->anchor->coeffs[j]);
+ }
+ }
+ fprintf(fp, "\n");
+ }
+
+ n1 = nframes;
+ if (n1 > 0)
n2 = mp->cframe;
else
n2 = 0;
}
fprintf(fp, "\n");
}
+
+ if (mp->nbondOrders > 0) {
+ fprintf(fp, "!:bond_orders\n");
+ fprintf(fp, "! order1 order2 order3 order4\n");
+ for (i = 0; i < mp->nbondOrders; i++) {
+ fprintf(fp, "%.6f%c", mp->bondOrders[i], (i % 4 == 3 || i == mp->nbondOrders - 1 ? '\n' : ' '));
+ }
+ fprintf(fp, "\n");
+ }
if (mp->nangles > 0) {
fprintf(fp, "!:angles\n");
fprintf(fp, "\n");
}
- if (mp->frame_cells != NULL) {
+ if (mp->nframe_cells > 0) {
fprintf(fp, "!:frame_periodic_boxes\n");
fprintf(fp, "! ax ay az; bx by bz; cx cy cz; ox oy oz\n");
for (i = 0; i < mp->nframe_cells * 4; i++) {
fprintf(fp, "cutoff %g\n", arena->cutoff);
fprintf(fp, "electro_cutoff %g\n", arena->electro_cutoff);
fprintf(fp, "pairlist_distance %g\n", arena->pairlist_distance);
+ fprintf(fp, "switch_distance %g\n", arena->switch_distance);
fprintf(fp, "temperature %g\n", arena->temperature);
fprintf(fp, "andersen_freq %d\n", arena->andersen_thermo_freq);
fprintf(fp, "andersen_coupling %g\n", arena->andersen_thermo_coupling);
}
if (mp->mview != NULL) {
- float f[4];
+ double f[4];
if (mp->mview->track != NULL) {
fprintf(fp, "!:trackball\n");
fprintf(fp, "! scale; trx try trz; theta_deg x y z\n");
mp->mview->showPeriodicImage[0], mp->mview->showPeriodicImage[1],
mp->mview->showPeriodicImage[2], mp->mview->showPeriodicImage[3],
mp->mview->showPeriodicImage[4], mp->mview->showPeriodicImage[5]);
+ if (mp->mview->atomRadius != 0.2)
+ fprintf(fp, "atom_radius %f\n", mp->mview->atomRadius);
+ if (mp->mview->bondRadius != 0.1)
+ fprintf(fp, "bond_radius %f\n", mp->mview->bondRadius);
+ if (mp->mview->atomResolution != 12)
+ fprintf(fp, "atom_resolution %d\n", mp->mview->atomResolution);
+ if (mp->mview->bondResolution != 8)
+ fprintf(fp, "bond_resolution %d\n", mp->mview->bondResolution);
fprintf(fp, "\n");
}
- fclose(fp);
- return 0;
-}
-
-int
-MoleculeWriteToPsfFile(Molecule *mp, const char *fname, char *errbuf, int errbufsize)
-{
- FILE *fp;
- int i;
- Atom *ap;
- fp = fopen(fname, "wb");
- if (fp == NULL) {
- snprintf(errbuf, errbufsize, "Cannot write to file %s", fname);
- return 1;
- }
- errbuf[0] = 0;
- fprintf(fp, "PSF\n\n");
- fprintf(fp, " 1 !NTITLE\n");
+ if (mp->nmolprops > 0) {
+ MolProp *prp;
+ for (i = 0, prp = mp->molprops; i < mp->nmolprops; i++, prp++) {
+ /* Encode the property name if necessary */
+ char enc[1024];
+ n1 = n2 = 0;
+ for (p = prp->propname; *p != 0 && n1 < 900; p++) {
+ if (*p > ' ' && *p != '%' && *p < 0x7f) {
+ enc[n1++] = *p;
+ n2 = n1;
+ } else {
+ sprintf(enc + n1, "%%%02x", *p);
+ n1 += 3;
+ }
+ }
+ if (*p == 0)
+ enc[n1] = 0;
+ else {
+ enc[n2] = 0; /* Truncate after last ASCII character */
+ n1 = n2;
+ }
+ if (n1 == 0) {
+ sprintf(enc, "prop_%d", i + 1);
+ n1 = strlen(enc);
+ }
+ fprintf(fp, "!:property ; %s\n", enc);
+ for (j = 0; j < nframes; j++) {
+ fprintf(fp, "%.18g\n", prp->propvals[j]);
+ }
+ fprintf(fp, "\n");
+ }
+ }
+
+ if (mp->bset != NULL) {
+ /* Gaussian primitive info */
+ ShellInfo *sp;
+ PrimInfo *pp;
+ fprintf(fp, "!:gaussian_primitives\n");
+ fprintf(fp, "! sym nprims a_idx; A C Csp\n");
+ for (i = 0, sp = mp->bset->shells; i < mp->bset->nshells; i++, sp++) {
+ switch (sp->sym) {
+ case kGTOType_S: p = "S"; break;
+ case kGTOType_P: p = "P"; break;
+ case kGTOType_SP: p = "SP"; break;
+ case kGTOType_D: p = "D"; break;
+ case kGTOType_D5: p = "D5"; break;
+ case kGTOType_F: p = "F"; break;
+ case kGTOType_F7: p = "F7"; break;
+ case kGTOType_G: p = "G"; break;
+ case kGTOType_G9: p = "G9"; break;
+ default: snprintf(bufs[0], 8, "X%d", sp->sym); p = bufs[0]; break;
+ }
+ fprintf(fp, "%s %d %d\n", p, sp->nprim, sp->a_idx);
+ pp = mp->bset->priminfos + sp->p_idx;
+ for (j = 0; j < sp->nprim; j++, pp++) {
+ fprintf(fp, "%.18g %.18g %.18g\n", pp->A, pp->C, pp->Csp);
+ }
+ }
+ fprintf(fp, "\n");
+
+ /* MO info */
+ fprintf(fp, "!:mo_info\n");
+ fprintf(fp, "! uhf|rhf|rohf ne_alpha ne_beta\n");
+ switch (mp->bset->rflag) {
+ case 0: p = "UHF"; break;
+ case 1: p = "RHF"; break;
+ case 2: p = "ROHF"; break;
+ default: p = "(unknown)"; break;
+ }
+ fprintf(fp, "%s %d %d\n", p, mp->bset->ne_alpha, mp->bset->ne_beta);
+ fprintf(fp, "\n");
+
+ /* MO coefficients */
+ fprintf(fp, "!:mo_coefficients\n");
+ for (i = 0; i < mp->bset->nmos; i++) {
+ fprintf(fp, "MO %d %.18g\n", i + 1, mp->bset->moenergies[i]);
+ for (j = 0; j < mp->bset->ncomps; j++) {
+ fprintf(fp, "%.18g%c", mp->bset->mo[i * mp->bset->ncomps + j], (j % 6 == 5 || j == mp->bset->ncomps - 1 ? '\n' : ' '));
+ }
+ }
+ fprintf(fp, "\n");
+ }
+
+ if (mp->mview != NULL && mp->mview->ngraphics > 0) {
+ MainViewGraphic *gp;
+ fprintf(fp, "!:graphics\n");
+ for (i = 0; i < mp->mview->ngraphics; i++) {
+ gp = mp->mview->graphics + i;
+ switch (gp->kind) {
+ case kMainViewGraphicLine: fprintf(fp, "line\n"); break;
+ case kMainViewGraphicPoly: fprintf(fp, "poly\n"); break;
+ case kMainViewGraphicCylinder: fprintf(fp, "cylinder\n"); break;
+ case kMainViewGraphicCone: fprintf(fp, "cone\n"); break;
+ case kMainViewGraphicEllipsoid: fprintf(fp, "ellipsoid\n"); break;
+ default: fprintf(fp, "unknown\n"); break;
+ }
+ fprintf(fp, "%d %d\n", gp->closed, gp->visible);
+ fprintf(fp, "%.4f %.4f %.4f %.4f\n", gp->rgba[0], gp->rgba[1], gp->rgba[2], gp->rgba[3]);
+ fprintf(fp, "%d\n", gp->npoints);
+ for (j = 0; j < gp->npoints; j++)
+ fprintf(fp, "%.6f %.6f %.6f\n", gp->points[j * 3], gp->points[j * 3 + 1], gp->points[j * 3 + 2]);
+ fprintf(fp, "%d\n", gp->nnormals);
+ for (j = 0; j < gp->nnormals; j++)
+ fprintf(fp, "%.6f %.6f %.6f\n", gp->normals[j * 3], gp->normals[j * 3 + 1], gp->normals[j * 3 + 2]);
+ }
+ fprintf(fp, "\n");
+ }
+
+ /* Plug-in in the Ruby world */
+ {
+ char *outMessage;
+ if (MolActionCreateAndPerform(mp, SCRIPT_ACTION(";s"),
+ "proc { savembsf_plugin rescue \"Plug-in error: #{$!.to_s}\" }", &outMessage) == 0) {
+ if (outMessage[0] != 0) {
+ if (strncmp(outMessage, "Plug-in", 7) == 0) {
+ s_append_asprintf(errbuf, "%s", outMessage);
+ } else {
+ fprintf(fp, "%s\n", outMessage);
+ }
+ }
+ free(outMessage);
+ }
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+int
+MoleculeWriteToPsfFile(Molecule *mp, const char *fname, char **errbuf)
+{
+ FILE *fp;
+ int i;
+ Atom *ap;
+ *errbuf = NULL;
+ fp = fopen(fname, "wb");
+ if (fp == NULL) {
+ s_append_asprintf(errbuf, "Cannot write to file %s", fname);
+ return 1;
+ }
+ fprintf(fp, "PSF\n\n");
+ fprintf(fp, " 1 !NTITLE\n");
fprintf(fp, " REMARKS FILENAME=\n");
fprintf(fp, "\n");
fprintf(fp, " %.8g %.8g %.8g ! %d,%.4s\n", r.x, r.y, r.z, i + 1, ap->aname);
}
fprintf(fp, "\n");
-#if 0
- if (mp->nframes > 0) {
- int fn; /* Frame number */
- for (fn = 0; fn < ap->nframes; fn++) {
- fprintf(fp, "%8d !COORD: coordinates for frame %d\n", mp->natoms, fn);
- for (i = 0; i < mp->natoms; i++) {
- Vector r;
- ap = ATOM_AT_INDEX(mp->atoms, i);
- if (ap->frames == NULL || fn >= ap->nframes)
- r = ap->r;
- else
- r = ap->frames[fn];
- fprintf(fp, " %.8g %.8g %.8g ! %d,%.4s\n", r.x, r.y, r.z, i + 1, ap->name);
- }
- fprintf(fp, "\n");
- }
- }
-#endif
}
fclose(fp);
}
int
-MoleculeWriteToPdbFile(Molecule *mp, const char *fname, char *errbuf, int errbufsize)
+MoleculeWriteToPdbFile(Molecule *mp, const char *fname, char **errbuf)
{
FILE *fp;
int i, j;
Atom *ap;
+ *errbuf = NULL;
fp = fopen(fname, "wb");
if (fp == NULL) {
- snprintf(errbuf, errbufsize, "Cannot write to file %s", fname);
+ s_append_asprintf(errbuf, "Cannot write to file %s", fname);
return 1;
}
- errbuf[0] = 0;
for (i = 0; i < mp->natoms; i++) {
char buf[6];
ap = ATOM_AT_INDEX(mp->atoms, i);
for (i = 0; i < mp->natoms; i++) {
Int *cp;
ap = ATOM_AT_INDEX(mp->atoms, i);
- cp = AtomConnects(ap);
- for (j = 0; j < ap->nconnects; j++) {
+ cp = AtomConnectData(&ap->connect);
+ for (j = 0; j < ap->connect.count; j++) {
if (j % 4 == 0) {
if (j > 0)
fprintf(fp, "\n");
}
int
-MoleculeWriteToDcdFile(Molecule *mp, const char *fname, char *errbuf, int errbufsize)
+MoleculeWriteToDcdFile(Molecule *mp, const char *fname, char **errbuf)
{
DcdRecord dcd;
SFloat32 *xp, *yp, *zp;
int n;
- errbuf[0] = 0;
+ *errbuf = NULL;
if (mp == NULL || mp->natoms == 0) {
- snprintf(errbuf, errbufsize, "Molecule is empty");
+ s_append_asprintf(errbuf, "Molecule is empty");
return 1;
}
memset(&dcd, 0, sizeof(dcd));
dcd.natoms = mp->natoms;
dcd.nframes = MoleculeGetNumberOfFrames(mp);
if (dcd.nframes == 0) {
- snprintf(errbuf, errbufsize, "no frame is present");
+ s_append_asprintf(errbuf, "no frame is present");
return 1;
}
dcd.nstart = mp->startStep;
n = DcdCreate(fname, &dcd);
if (n != 0) {
if (n < 0)
- snprintf(errbuf, errbufsize, "Cannot create dcd file");
+ s_append_asprintf(errbuf, "Cannot create dcd file");
else
- snprintf(errbuf, errbufsize, "Cannot write dcd header");
+ s_append_asprintf(errbuf, "Cannot write dcd header");
DcdClose(&dcd);
return 1;
}
yp = (SFloat32 *)malloc(sizeof(SFloat32) * dcd.natoms);
zp = (SFloat32 *)malloc(sizeof(SFloat32) * dcd.natoms);
if (xp == NULL || yp == NULL || zp == NULL) {
- snprintf(errbuf, errbufsize, "Cannot allocate memory");
+ s_append_asprintf(errbuf, "Cannot allocate memory");
if (xp) free(xp);
if (yp) free(yp);
if (zp) free(zp);
dcd.globalcell[4] = VecDot(cp[1], cp[2]) / (dcd.globalcell[2] * dcd.globalcell[5]);
}
if (DcdWriteFrame(&dcd, n, xp, yp, zp, dcd.globalcell)) {
- snprintf(errbuf, errbufsize, "Write error in dcd file");
+ s_append_asprintf(errbuf, "Write error in dcd file");
goto exit;
}
}
}
int
-MoleculeWriteExtendedInfo(Molecule *mp, const char *fname, char *errbuf, int errbufsize)
+MoleculeWriteExtendedInfo(Molecule *mp, const char *fname, char **errbuf)
{
FILE *fp;
int i;
Vector v;
- errbuf[0] = 0;
+ *errbuf = NULL;
fp = fopen(fname, "wb");
if (fp == NULL) {
- snprintf(errbuf, errbufsize, "Cannot write to file %s", fname);
+ s_append_asprintf(errbuf, "Cannot write to file %s", fname);
return 1;
}
if (mp->cell != NULL) {
continue;
VecSub(dr, ap->r, ap2->r);
d = VecLength(dr);
- cp = AtomConnects(ap);
- for (k = ap->nconnects - 1; k >= 0; k--) {
+ cp = AtomConnectData(&ap->connect);
+ for (k = ap->connect.count - 1; k >= 0; k--) {
if (cp[k] == n2)
break;
}
max_bond = min_nonbond - 0.002;
/* Some bonds may be omitted, so scan all bonds again */
for (n1 = n[i], ap = ATOM_AT_INDEX(atoms, n1); n1 < n[i + 1]; n1++, ap = ATOM_NEXT(ap)) {
- cp = AtomConnects(ap);
- for (k = ap->nconnects - 1; k >= 0; k--) {
+ cp = AtomConnectData(&ap->connect);
+ for (k = ap->connect.count - 1; k >= 0; k--) {
n2 = cp[k];
if (n2 < n[j] || n2 >= n[j + 1])
continue;
free(exbonds);
}
}
-
-#if 0
-{
- /* Explicit bond table, sorted by bond type */
- for (i = j = 0; i < mp->nbonds; i++) {
- n1 = mp->bonds[i * 2];
- n2 = mp->bonds[i * 2 + 1];
- ap1 = ATOM_AT_INDEX(mp->atoms, n1);
- ap2 = ATOM_AT_INDEX(mp->atoms, n2);
- if ((ap1->exflags & kAtomHiddenFlag) || (ap2->exflags & kAtomHiddenFlag))
- continue;
- if (ap1->atomicNumber > 18 || ap2->atomicNumber > 18) {
- type = 3;
- } else if (ap1->atomicNumber > 1 && ap1->atomicNumber > 1) {
- type = 2;
- } else {
- type = 1;
- }
- ip[j * 3] = type;
- ip[j * 3 + 1] = sMakeAdc(n1, ap1->symbase, ap1->symop);
- ip[j * 3 + 2] = sMakeAdc(n2, ap2->symbase, ap2->symop);
- j++;
- }
- mergesort(ip, j, sizeof(int) * 3, sCompareBondType);
-
- /* Output instruction cards */
- strcpy(buf, " 1 811");
- for (i = n1 = 0; i < j; i++) {
- n2 = (n1 % 3) * 18 + 9;
- snprintf(buf + n2, 80 - n2, "%9d%9d\n", ip[i * 3 + 1], ip[i * 3 + 2]);
- if (i == j - 1 || n1 >= 29 || ip[i * 3] != ip[i * 3 + 3]) {
- /* End of this instruction */
- buf[2] = '2';
- fputs(buf, fp);
- switch (ip[i * 3]) {
- case 3: rad = 0.06; nshades = 5; break;
- case 2: rad = 0.06; nshades = 1; break;
- default: rad = 0.04; nshades = 1; break;
- }
- fprintf(fp, " %3d %6.3f\n", nshades, rad);
- strcpy(buf, " 1 811");
- n1 = 0;
- continue;
- } else if (n1 % 3 == 2) {
- fputs(buf, fp);
- strcpy(buf, " 1 ");
- }
- n1++;
- }
- free(ip);
-}
-#endif
int
-MoleculeWriteToTepFile(Molecule *mp, const char *fname, char *errbuf, int errbufsize)
+MoleculeWriteToTepFile(Molecule *mp, const char *fname, char **errbuf)
{
FILE *fp;
int i, j, natoms, *ip;
Double *dp;
static Double sUnit[] = {1, 1, 1, 90, 90, 90};
- errbuf[0] = 0;
+ *errbuf = NULL;
/* Create sorted array of atoms */
natoms = mp->natoms;
app = (Atom **)calloc(sizeof(Atom *), natoms);
ip = (int *)calloc(sizeof(int), natoms);
if (atoms == NULL || app == NULL || ip == NULL) {
- snprintf(errbuf, errbufsize, "Cannot allocate memory");
+ s_append_asprintf(errbuf, "Cannot allocate memory");
return 1;
}
/* Sort the atom pointer by atomic number */
AtomDuplicateNoFrame(ap, app[i]);
/* memmove(ap, app[i], gSizeOfAtomRecord); */
MoleculeCartesianToXtal(mp, &(ap->v), &(ap->r));
- cp = AtomConnects(ap);
- for (j = ap->nconnects - 1; j >= 0; j--) {
+ cp = AtomConnectData(&ap->connect);
+ for (j = ap->connect.count - 1; j >= 0; j--) {
cp[j] = ip[cp[j]];
}
if (SYMOP_ALIVE(ap->symop))
fp = fopen(fname, "wb");
if (fp == NULL) {
- snprintf(errbuf, errbufsize, "Cannot write to file %s", fname);
+ s_append_asprintf(errbuf, "Cannot write to file %s", fname);
return 1;
}
- errbuf[0] = 0;
/* Title line */
fprintf(fp, "Generated by Molby\n");
ap = ATOM_AT_INDEX(mol->atoms, i);
snprintf(buf1, sizeof buf1, "%3.4s.%d", ap->resName, ap->resSeq);
fprintf(stderr, "%4d %-7s %-4.6s %-4.6s %-2.2s %7.3f %7.3f %7.3f %6.3f [", i, buf1, ap->aname, AtomTypeDecodeToString(ap->type, NULL), ap->element, ap->r.x, ap->r.y, ap->r.z, ap->charge);
- cp = AtomConnects(ap);
- for (j = 0; j < ap->nconnects; j++) {
+ cp = AtomConnectData(&ap->connect);
+ for (j = 0; j < ap->connect.count; j++) {
fprintf(stderr, "%s%d", (j > 0 ? "," : ""), cp[j]);
}
fprintf(stderr, "]\n");
IntGroupRelease(ig3);
}
+ {
+ /* Update the path information of the molecule before MD setup */
+ char *buf = (char *)malloc(4096);
+ MoleculeCallback_pathName(mol, buf, sizeof buf);
+ MoleculeSetPath(mol, buf);
+ free(buf);
+ }
+
/* Prepare parameters and internal information */
msg = md_prepare(arena, check_only);
{
Molecule *mp;
Parameter *par;
+ Atom *ap;
/* int result; */
mp = MoleculeNew();
NewArray(&mp->atoms, &mp->natoms, gSizeOfAtomRecord, n);
memmove(mp->atoms, ptr, len);
} else if (strcmp(data, "ANISO") == 0) {
- Atom *ap;
n = len / (sizeof(Int) + sizeof(Aniso));
for (i = 0; i < n; i++) {
j = *((const Int *)ptr);
ptr += sizeof(Int) + sizeof(Aniso);
}
} else if (strcmp(data, "FRAME") == 0) {
- Atom *ap;
for (i = 0, ap = mp->atoms; i < mp->natoms; i++, ap = ATOM_NEXT(ap)) {
if (ap->nframes == 0)
continue;
- ap->frames = (Vector *)malloc(sizeof(Vector) * ap->nframes);
+ n = ap->nframes;
+ ap->frames = NULL;
+ ap->nframes = 0;
+ NewArray(&ap->frames, &ap->nframes, sizeof(Vector), n);
if (ap->frames == NULL)
goto out_of_memory;
memmove(ap->frames, ptr, sizeof(Vector) * ap->nframes);
ptr += sizeof(Vector) * ap->nframes;
}
+ } else if (strcmp(data, "EXTCON") == 0) {
+ for (i = 0, ap = mp->atoms; i < mp->natoms; i++, ap = ATOM_NEXT(ap)) {
+ if (ap->connect.count <= ATOM_CONNECT_LIMIT)
+ continue;
+ n = ap->connect.count;
+ ap->connect.count = 0;
+ ap->connect.u.ptr = NULL;
+ NewArray(&(ap->connect.u.ptr), &(ap->connect.count), sizeof(Int), n);
+ memmove(ap->connect.u.ptr, ptr, sizeof(Int) * n);
+ ptr += sizeof(Int) * n;
+ }
} else if (strcmp(data, "BOND") == 0) {
n = len / (sizeof(Int) * 2);
NewArray(&mp->bonds, &mp->nbonds, sizeof(Int) * 2, n);
n = len / sizeof(Transform);
NewArray(&mp->syms, &mp->nsyms, sizeof(Transform), n);
memmove(mp->syms, ptr, len);
- } else if (strcmp(data, "EXATOM") == 0) {
- n = len / sizeof(ExAtom);
- NewArray(&mp->exatoms, &mp->nexatoms, sizeof(ExAtom), n);
- memmove(mp->exatoms, ptr, len);
- } else if (strcmp(data, "EXBOND") == 0) {
- n = len / (sizeof(Int) * 2);
- NewArray(&mp->exbonds, &mp->nexbonds, sizeof(Int) * 2, n);
- memmove(mp->exbonds, ptr, len);
+ } else if (strcmp(data, "ANCHOR") == 0) {
+ const char *ptr2 = ptr + len;
+ while (ptr < ptr2) {
+ PiAnchor an;
+ memset(&an, 0, sizeof(an));
+ i = *((Int *)ptr);
+ if (i >= 0 && i < mp->natoms) {
+ n = *((Int *)(ptr + sizeof(Int)));
+ AtomConnectResize(&(an.connect), n);
+ memmove(AtomConnectData(&(an.connect)), ptr + sizeof(Int) * 2, sizeof(Int) * n);
+ NewArray(&an.coeffs, &an.ncoeffs, sizeof(Double), n);
+ memmove(an.coeffs, ptr + sizeof(Int) * (2 + n), sizeof(Double) * n);
+ ap = ATOM_AT_INDEX(mp->atoms, i);
+ ap->anchor = (PiAnchor *)malloc(sizeof(PiAnchor));
+ memmove(ap->anchor, &an, sizeof(PiAnchor));
+ }
+ ptr += sizeof(Int) * (2 + n) + sizeof(Double) * n;
+ }
} else if (strcmp(data, "TIME") == 0) {
if (timep != NULL)
*timep = *((Int *)ptr);
MoleculeSerialize(Molecule *mp, Int *outLength, Int *timep)
{
char *ptr, *p;
- int len, len_all, i, naniso, nframes;
+ int len, len_all, i, naniso, nframes, nconnects, nanchors;
+ Atom *ap;
/* Array of atoms */
len = 8 + sizeof(Int) + gSizeOfAtomRecord * mp->natoms;
*((Int *)(ptr + 8)) = gSizeOfAtomRecord * mp->natoms;
p = ptr + 8 + sizeof(Int);
memmove(p, mp->atoms, gSizeOfAtomRecord * mp->natoms);
- naniso = nframes = 0;
+ naniso = nframes = nconnects = nanchors = 0;
for (i = 0; i < mp->natoms; i++) {
- Atom *ap = ATOM_AT_INDEX(p, i);
+ ap = ATOM_AT_INDEX(p, i);
if (ap->aniso != NULL) {
naniso++;
ap->aniso = NULL;
nframes += ap->nframes;
ap->frames = NULL;
}
+ if (ap->connect.count > ATOM_CONNECT_LIMIT) {
+ nconnects += ap->connect.count;
+ ap->connect.u.ptr = NULL;
+ }
+ if (ap->anchor != NULL) {
+ nanchors++;
+ ap->anchor = NULL;
+ }
}
len_all = len;
*((Int *)(p + 8)) = (sizeof(Int) + sizeof(Aniso)) * naniso;
p += 8 + sizeof(Int);
for (i = 0; i < mp->natoms; i++) {
- Atom *ap = ATOM_AT_INDEX(mp->atoms, i);
+ ap = ATOM_AT_INDEX(mp->atoms, i);
if (ap->aniso != NULL) {
*((Int *)p) = i;
*((Aniso *)(p + sizeof(Int))) = *(ap->aniso);
*((Int *)(p + 8)) = sizeof(Vector) * nframes;
p += 8 + sizeof(Int);
for (i = 0; i < mp->natoms; i++) {
- Atom *ap = ATOM_AT_INDEX(mp->atoms, i);
+ ap = ATOM_AT_INDEX(mp->atoms, i);
if (ap->frames != NULL) {
memmove(p, ap->frames, sizeof(Vector) * ap->nframes);
p += sizeof(Vector) * ap->nframes;
len_all += len;
}
+ /* Array of connects */
+ if (nconnects > 0) {
+ len = 8 + sizeof(Int) + sizeof(Int) * nconnects;
+ ptr = (char *)realloc(ptr, len_all + len);
+ if (ptr == NULL)
+ goto out_of_memory;
+ p = ptr + len_all;
+ memmove(p, "EXTCON\0\0", 8);
+ *((Int *)(p + 8)) = sizeof(Int) * nconnects;
+ p += 8 + sizeof(Int);
+ for (i = 0; i < mp->natoms; i++) {
+ ap = ATOM_AT_INDEX(mp->atoms, i);
+ if (ap->connect.count > ATOM_CONNECT_LIMIT) {
+ memmove(p, ap->connect.u.ptr, sizeof(Int) * ap->connect.count);
+ p += sizeof(Int) * ap->connect.count;
+ }
+ }
+ len_all += len;
+ }
+
/* Bonds, angles, dihedrals, impropers */
if (mp->nbonds > 0) {
len = 8 + sizeof(Int) + sizeof(Int) * 2 * mp->nbonds;
len_all += len;
}
- /* Expanded atoms */
- if (mp->nexatoms > 0) {
- len = 8 + sizeof(Int) + sizeof(ExAtom) * mp->nexatoms;
- ptr = (char *)realloc(ptr, len_all + len);
- if (ptr == NULL)
- goto out_of_memory;
- p = ptr + len_all;
- memmove(p, "EXATOM\0\0", 8);
- *((Int *)(p + 8)) = sizeof(ExAtom) * mp->nexatoms;
- p += 8 + sizeof(Int);
- memmove(p, mp->exatoms, sizeof(ExAtom) * mp->nexatoms);
- for (i = 0; i < mp->nexatoms; i++) {
- /* Clear label id */
- ((ExAtom *)p)[i].labelid = 0;
+ /* Pi-anchors */
+ if (nanchors > 0) {
+ /* Estimate the necessary storage first */
+ /* One entry consists of { atom_index (Int), number_of_connects (Int), connects (Int's), weights (Double's) } */
+ len = 8 + sizeof(Int);
+ for (i = 0; i < mp->natoms; i++) {
+ ap = ATOM_AT_INDEX(mp->atoms, i);
+ if (ap->anchor != NULL)
+ len += sizeof(Int) * 2 + (sizeof(Int) + sizeof(Double)) * ap->anchor->connect.count;
}
- len_all += len;
- }
-
- /* Expanded bonds */
- if (mp->nexbonds > 0) {
- len = 8 + sizeof(Int) + sizeof(Int) * 2 * mp->nexbonds;
ptr = (char *)realloc(ptr, len_all + len);
if (ptr == NULL)
goto out_of_memory;
p = ptr + len_all;
- memmove(p, "EXBOND\0\0", 8);
- *((Int *)(p + 8)) = sizeof(Int) * 2 * mp->nexbonds;
+ memmove(p, "ANCHOR\0\0", 8);
+ *((Int *)(p + 8)) = len - (8 + sizeof(Int));
p += 8 + sizeof(Int);
- memmove(p, mp->exbonds, sizeof(Int) * 2 * mp->nexbonds);
+ for (i = 0; i < mp->natoms; i++) {
+ Int count, *ip;
+ ap = ATOM_AT_INDEX(mp->atoms, i);
+ if (ap->anchor != NULL) {
+ count = ap->anchor->connect.count;
+ *((Int *)p) = i;
+ *((Int *)(p + sizeof(Int))) = count;
+ p += sizeof(Int) * 2;
+ ip = AtomConnectData(&(ap->anchor->connect));
+ memmove(p, ip, sizeof(Int) * count);
+ p += sizeof(Int) * count;
+ memmove(p, ap->anchor->coeffs, sizeof(Double) * count);
+ p += sizeof(Double) * count;
+ }
+ }
len_all += len;
}
return sMoleculeSearchAcrossAtomGroup(mp->nimpropers, mp->impropers, 4, atomgroup, "impropers");
}
-/* Subroutine for MoleculeGuessBonds. It can be also used independently, but make sure that *outNbonds/*outBonds
+/* Subroutine for MoleculeGuessBonds. It can be also used independently, but make sure that *outNbonds / *outBonds
_correctly_ represents an array of two integers (as in mp->nbonds/mp->bonds). */
-/* Find atoms within the given "distance" from the given atom. */
+/* Find atoms within the given "distance" from the given position. */
/* If limit is negative, its absolute value denotes the threshold distance in angstrom; otherwise,
- the threshold distance is given by the sum of van der Waals radii times limit. */
-/* If triangle is non-zero, then only atoms with lower indexes than index are looked for. */
+ the threshold distance is given by the sum of van der Waals radii times limit, and radius is
+ the van der Waals radius of the atom at the given position. */
+/* Index is the atom index of the given atom; it is only used in returning the "bond" array
+ to the caller. If index is negative, then (-index) is the real atom index, and
+ only atoms with lower indices than (-index) are looked for. */
int
-MoleculeFindCloseAtoms(Molecule *mp, Int index, Double limit, Int *outNbonds, Int **outBonds, Int triangle)
-{
- Int n1, n2, j, nlim, newbond[2];
- Double a1, a2, alim;
- Vector dr, r1, r2;
- Atom *ap = ATOM_AT_INDEX(mp->atoms, index);
- n1 = ap->atomicNumber;
- if (n1 >= 0 && n1 < gCountElementParameters)
- a1 = gElementParameters[n1].radius;
- else a1 = gElementParameters[6].radius;
- r1 = ap->r;
- nlim = (triangle ? index : mp->natoms);
+MoleculeFindCloseAtoms(Molecule *mp, const Vector *vp, Double radius, Double limit, Int *outNbonds, Int **outBonds, Int index)
+{
+ Int n2, j, nlim, newbond[2];
+ Double a2, alim;
+ Vector dr, r2;
+ if (index < 0) {
+ nlim = index = -index;
+ } else {
+ nlim = mp->natoms;
+ }
for (j = 0; j < nlim; j++) {
Atom *bp = ATOM_AT_INDEX(mp->atoms, j);
if (index == j)
a2 = gElementParameters[n2].radius;
else a2 = gElementParameters[6].radius;
r2 = bp->r;
- VecSub(dr, r1, r2);
+ VecSub(dr, *vp, r2);
if (limit < 0)
alim = -limit;
else
- alim = limit * (a1 + a2);
+ alim = limit * (radius + a2);
if (VecLength2(dr) < alim * alim) {
newbond[0] = index;
newbond[1] = j;
MoleculeGuessBonds(Molecule *mp, Double limit, Int *outNbonds, Int **outBonds)
{
Int nbonds, *bonds, i, newbond[2];
-/* int i, j, n1, n2;
- Atom *ap, *bp;
- Vector r1, r2, dr;
- Double a1, a2, alim;
- Int newbond[2];
- ElementPar *p = gElementParameters; */
+ Atom *ap;
nbonds = 0;
bonds = NULL;
- for (i = 0; i < mp->natoms; i++) {
- MoleculeFindCloseAtoms(mp, i, limit, &nbonds, &bonds, 1);
- /*
- ap = ATOM_AT_INDEX(mp->atoms, i);
- n1 = ap->atomicNumber;
- if (n1 >= 0 && n1 < gCountElementParameters)
- a1 = p[n1].radius;
- else a1 = p[6].radius;
- r1 = ap->r;
- for (j = 0; j < i; j++) {
- bp = ATOM_AT_INDEX(mp->atoms, j);
- n2 = bp->atomicNumber;
- if (n2 >= 0 && n2 < gCountElementParameters)
- a2 = p[n2].radius;
- else a2 = p[6].radius;
- r2 = bp->r;
- VecSub(dr, r1, r2);
- if (limit < 0)
- alim = -limit;
- else
- alim = limit * (a1 + a2);
- if (VecLength2(dr) < alim * alim) {
- newbond[0] = i;
- newbond[1] = j;
- AssignArray(&bonds, &nbonds, sizeof(Int) * 2, nbonds, newbond);
- }
- }
- */
+ if (limit == 0.0)
+ limit = 1.2;
+ for (i = 1, ap = ATOM_NEXT(mp->atoms); i < mp->natoms; i++, ap = ATOM_NEXT(ap)) {
+ Vector r = ap->r;
+ Int an = ap->atomicNumber;
+ Double rad;
+ if (an >= 0 && an < gCountElementParameters)
+ rad = gElementParameters[an].radius;
+ else rad = gElementParameters[6].radius;
+ MoleculeFindCloseAtoms(mp, &r, rad, limit, &nbonds, &bonds, -i);
}
if (nbonds > 0) {
newbond[0] = kInvalidIndex;
if (mp->nbonds == 0) {
for (i = 0; i < mp->natoms; i++) {
ap = ATOM_AT_INDEX(mp->atoms, i);
- cp = AtomConnects(ap);
- for (j = 0; j < ap->nconnects; j++) {
+ cp = AtomConnectData(&ap->connect);
+ for (j = 0; j < ap->connect.count; j++) {
k = cp[j];
if (i >= k)
continue;
if (mp->nangles == 0) {
for (i = 0; i < mp->natoms; i++) {
ap = ATOM_AT_INDEX(mp->atoms, i);
- cp = AtomConnects(ap);
- for (j = 0; j < ap->nconnects; j++) {
- for (k = j + 1; k < ap->nconnects; k++) {
+ cp = AtomConnectData(&ap->connect);
+ for (j = 0; j < ap->connect.count; j++) {
+ for (k = j + 1; k < ap->connect.count; k++) {
ibuf[0] = cp[j];
ibuf[1] = i;
ibuf[2] = cp[k];
if (mp->ndihedrals == 0) {
for (i = 0; i < mp->natoms; i++) {
ap = ATOM_AT_INDEX(mp->atoms, i);
- cp = AtomConnects(ap);
- for (j = 0; j < ap->nconnects; j++) {
+ cp = AtomConnectData(&ap->connect);
+ for (j = 0; j < ap->connect.count; j++) {
int jj, kk, mm, m;
Atom *apjj;
Int *cpjj;
if (i >= jj)
continue;
apjj = ATOM_AT_INDEX(mp->atoms, jj);
- cpjj = AtomConnects(apjj);
- for (k = 0; k < ap->nconnects; k++) {
+ cpjj = AtomConnectData(&apjj->connect);
+ for (k = 0; k < ap->connect.count; k++) {
if (k == j)
continue;
kk = cp[k];
- for (m = 0; m < apjj->nconnects; m++) {
+ for (m = 0; m < apjj->connect.count; m++) {
mm = cpjj[m];
if (mm == i || mm == kk)
continue;
for (i = 0; i < mp->natoms; i++) {
int i1, i2, i4, n1, n2, n4;
ap = ATOM_AT_INDEX(mp->atoms, i);
- cp = AtomConnects(ap);
- for (i1 = 0; i1 < ap->nconnects; i1++) {
+ cp = AtomConnectData(&ap->connect);
+ for (i1 = 0; i1 < ap->connect.count; i1++) {
n1 = cp[i1];
- for (i2 = i1 + 1; i2 < ap->nconnects; i2++) {
+ for (i2 = i1 + 1; i2 < ap->connect.count; i2++) {
n2 = cp[i2];
- for (i4 = i2 + 1; i4 < ap->nconnects; i4++) {
+ for (i4 = i2 + 1; i4 < ap->connect.count; i4++) {
n4 = cp[i4];
ibuf[0] = n1;
ibuf[1] = n2;
return retval;
}
+int
+MoleculeAreAtomsConnected(Molecule *mol, int idx1, int idx2)
+{
+ Atom *ap1 = ATOM_AT_INDEX(mol->atoms, idx1);
+ if (AtomConnectHasEntry(&ap1->connect, idx2))
+ return 1;
+ else if (ap1->anchor != NULL && AtomConnectHasEntry(&(ap1->anchor->connect), idx2))
+ return 2;
+ else return 0;
+}
+
#pragma mark ====== Atom names ======
/* Look for the n1-th atom in resno-th residue (n1 is 0-based) */
return -1; /* Not found */
}
-int
-MoleculeAreAtomsConnected(Molecule *mp, int n1, int n2)
-{
- Atom *ap;
- Int i, *cp;
- if (mp == NULL || n1 < 0 || n1 >= mp->natoms || n2 < 0 || n2 >= mp->natoms)
- return 0;
- ap = ATOM_AT_INDEX(mp->atoms, n1);
- cp = AtomConnects(ap);
- for (i = 0; i < ap->nconnects; i++)
- if (cp[i] == n2)
- return 1;
- return 0;
-}
-
-
void
MoleculeGetAtomName(Molecule *mp, int index, char *buf, int bufsize)
{
list1->next = list;
if (i == j || (db[i] != NULL && db[i] == db[j]))
return list1;
- cpi = AtomConnects(api);
- cpj = AtomConnects(apj);
- for (ni = 0; ni < api->nconnects; ni++) {
+ cpi = AtomConnectData(&api->connect);
+ cpj = AtomConnectData(&apj->connect);
+ for (ni = 0; ni < api->connect.count; ni++) {
ii = cpi[ni];
if (ig != NULL && IntGroupLookupPoint(ig, ii) < 0)
continue;
if (sExistInEqList(ii, 0, list1))
continue;
list2 = NULL;
- for (nj = 0; nj < apj->nconnects; nj++) {
+ for (nj = 0; nj < apj->connect.count; nj++) {
jj = cpj[nj];
if (ig != NULL && IntGroupLookupPoint(ig, jj) < 0)
continue;
/* Find the equivalent univalent atoms */
for (i = 0, api = mol->atoms; i < mol->natoms; i++, api = ATOM_NEXT(api)) {
- if (api->nconnects < 2)
+ if (api->connect.count < 2)
continue;
- cpi = AtomConnects(api);
- for (j = 0; j < api->nconnects; j++) {
+ cpi = AtomConnectData(&api->connect);
+ for (j = 0; j < api->connect.count; j++) {
Int n;
n = 0;
jj = cpi[j];
AssignArray(&ibuf, &nibuf, sizeof(Int), n, &jj);
n++;
apj = ATOM_AT_INDEX(mol->atoms, jj);
- if (apj->nconnects != 1 || db[jj] != NULL)
+ if (apj->connect.count != 1 || db[jj] != NULL)
continue;
- cpj = AtomConnects(apj);
- for (k = j + 1; k < api->nconnects; k++) {
+ cpj = AtomConnectData(&apj->connect);
+ for (k = j + 1; k < api->connect.count; k++) {
kk = cpj[k];
if (ig != NULL && IntGroupLookupPoint(ig, kk) < 0)
continue;
apk = ATOM_AT_INDEX(mol->atoms, kk);
- if (apk->nconnects != 1 || db[kk] != NULL)
+ if (apk->connect.count != 1 || db[kk] != NULL)
continue;
if (apj->atomicNumber == apk->atomicNumber) {
AssignArray(&ibuf, &nibuf, sizeof(Int), n, &kk);
Transform t;
if (mp == NULL || mp->cell == NULL)
return -1;
- if (symop.sym >= mp->nsyms)
+ if (symop.sym >= mp->nsyms && symop.sym != 0)
return -2;
- memmove(*tf, mp->syms[symop.sym], sizeof(Transform));
+ memmove(*tf, SYMMETRY_AT_INDEX(mp->syms, symop.sym), sizeof(Transform));
(*tf)[9] += symop.dx;
(*tf)[10] += symop.dy;
(*tf)[11] += symop.dz;
int i, j, n[3];
if (mp == NULL || mp->cell == NULL)
return -1;
- if (mp->nsyms == 0)
- return -2;
if (is_cartesian) {
TransformMul(t, tf, mp->cell->tr);
TransformMul(t, mp->cell->rtr, t);
} else {
memmove(t, tf, sizeof(Transform));
}
- for (i = 0; i < mp->nsyms; i++) {
- Transform *tp = mp->syms + i;
+ for (i = 0; i < mp->nsyms || i == 0; i++) {
+ Transform *tp = &(SYMMETRY_AT_INDEX(mp->syms, i));
for (j = 0; j < 9; j++) {
if (fabs((*tp)[j] - t[j]) > 1e-4)
break;
{
if (mp == NULL)
return 1;
- if (symop.sym >= mp->nsyms)
+ if (symop.sym >= mp->nsyms && symop.sym != 0)
return 2;
if (mp->cell != NULL /* && !mp->is_xtal_coord */) {
TransformVec(vpout, mp->cell->rtr, vpin);
- TransformVec(vpout, mp->syms[symop.sym], vpout);
+ TransformVec(vpout, SYMMETRY_AT_INDEX(mp->syms, symop.sym), vpout);
vpout->x += symop.dx;
vpout->y += symop.dy;
vpout->z += symop.dz;
TransformVec(vpout, mp->cell->tr, vpout);
} else {
- TransformVec(vpout, mp->syms[symop.sym], vpin);
+ TransformVec(vpout, SYMMETRY_AT_INDEX(mp->syms, symop.sym), vpin);
vpout->x += symop.dx;
vpout->y += symop.dy;
vpout->z += symop.dz;
If indices is non-NULL, it should be an array of Int with at least
IntGroupGetCount(group) entries, and on return it contains the
indices of the expanded atoms (may be existing atoms if the expanded
- atoms are already present) */
+ atoms are already present)
+ If allowOverlap is non-zero, then the new atom is created even when the
+ coordinates coincide with the some other atom (special position) of the
+ same element; otherwise, such atom will not be created and the existing
+ atom is returned in indices[]. */
int
-MoleculeAddExpandedAtoms(Molecule *mp, Symop symop, IntGroup *group, Int *indices)
+MoleculeAddExpandedAtoms(Molecule *mp, Symop symop, IntGroup *group, Int *indices, Int allowOverlap)
{
- int i, n, n0, n1, count, *table;
+ int i, n, n0, n1, n2, base, count, *table;
Atom *ap;
IntGroupIterator iter;
- Transform tr;
-
+ Transform tr, t1;
+ Symop symop1;
+ Atom *ap2;
+ Vector nr, dr;
+
if (mp == NULL || mp->natoms == 0 || group == NULL || (count = IntGroupGetCount(group)) == 0)
return -1;
- if (symop.sym >= mp->nsyms)
+ if (symop.sym != 0 && symop.sym >= mp->nsyms)
return -2;
/* Create atoms, with avoiding duplicates */
MoleculeGetTransformForSymop(mp, symop, &tr, 0);
__MoleculeLock(mp);
for (i = 0; i < count; i++) {
- int n2, base;
- Symop symop1;
- Atom *ap2;
- Vector nr, dr;
n = IntGroupIteratorNext(&iter);
ap = ATOM_AT_INDEX(mp->atoms, n);
if (SYMOP_ALIVE(ap->symop)) {
/* Calculate the cumulative symop */
- Transform t1;
+ Transform tr2;
MoleculeGetTransformForSymop(mp, ap->symop, &t1, 0);
- TransformMul(t1, tr, t1);
- if (MoleculeGetSymopForTransform(mp, t1, &symop1, 0) != 0) {
+ TransformMul(tr2, tr, t1);
+ if (MoleculeGetSymopForTransform(mp, tr2, &symop1, 0) != 0) {
if (indices != NULL)
indices[i] = -1;
continue; /* Skip this atom */
symop1 = symop;
base = n;
}
+
+ /* Calculate the expande position */
+ MoleculeTransformBySymop(mp, &(ap->r), &nr, symop);
+
/* Is this expansion already present? */
for (n2 = 0, ap2 = mp->atoms; n2 < n0; n2++, ap2 = ATOM_NEXT(ap2)) {
+ /* Symmetry operation and the base atom are the same */
if (ap2->symbase == base && SYMOP_EQUAL(symop1, ap2->symop))
break;
+ /* Atomic number and the position are the same */
+ if (ap2->atomicNumber == ap->atomicNumber && allowOverlap == 0) {
+ VecSub(dr, ap2->r, nr);
+ if (VecLength2(dr) < 1e-6)
+ break;
+ }
}
if (n2 < n0) {
/* If yes, then skip it */
if (indices != NULL)
indices[i] = n2;
continue;
- }
- /* Is the expanded position coincides with itself? */
- MoleculeTransformBySymop(mp, &(ap->r), &nr, symop);
- VecSub(dr, ap->r, nr);
- if (VecLength2(dr) < 1e-6) {
- /* If yes, then this atom is included but no new atom is created */
- table[n] = n;
- if (indices != NULL)
- indices[i] = n;
} else {
/* Create a new atom */
Atom newAtom;
AtomClean(&newAtom);
ap2 = ATOM_AT_INDEX(mp->atoms, mp->natoms - 1);
ap2->r = nr;
- ap2->symbase = n;
- ap2->symop = symop;
- ap2->symop.alive = (symop.dx != 0 || symop.dy != 0 || symop.dz != 0 || symop.sym != 0);
+ ap2->symbase = base;
+ ap2->symop = symop1;
+ ap2->symop.alive = (symop1.dx != 0 || symop1.dy != 0 || symop1.dz != 0 || symop1.sym != 0);
table[n] = n1; /* The index of the new atom */
+ MoleculeSetAnisoBySymop(mp, n1); /* Recalculate anisotropic parameters according to symop */
if (indices != NULL)
indices[i] = n1;
n1++;
IntGroupIteratorRelease(&iter);
/* Create bonds */
- for (i = 0; i < n0; i++) {
- int b[2];
- Int *cp;
- b[0] = table[i];
- if (b[0] < 0 || b[0] == i)
- continue;
+ for (i = n0; i < n1; i++) {
+ Int b[2], j;
ap = ATOM_AT_INDEX(mp->atoms, i);
- cp = AtomConnects(ap);
- for (n = 0; n < ap->nconnects; n++) {
- b[1] = table[cp[n]];
- if (b[1] < 0)
- continue;
- if (b[1] > n0 && b[0] > b[1])
- continue;
- MoleculeAddBonds(mp, 1, b);
+ if (SYMOP_ALIVE(ap->symop) && MoleculeGetTransformForSymop(mp, ap->symop, &tr, 1) == 0) {
+ /* For each connected atom, look for the transformed atom */
+ Int *cp;
+ ap2 = ATOM_AT_INDEX(mp->atoms, ap->symbase);
+ cp = AtomConnectData(&ap2->connect);
+ n2 = ap2->connect.count;
+ for (n = 0; n < n2; n++) {
+ Atom *apn = ATOM_AT_INDEX(mp->atoms, cp[n]);
+ nr = apn->r;
+ TransformVec(&nr, tr, &nr);
+ /* Look for the bonded atom transformed by ap->symop */
+ for (j = 0, ap2 = mp->atoms; j < mp->natoms; j++, ap2 = ATOM_NEXT(ap2)) {
+ if (ap2->symbase == cp[n] && SYMOP_EQUAL(ap->symop, ap2->symop))
+ break;
+ VecSub(dr, nr, ap2->r);
+ if (ap2->atomicNumber == apn->atomicNumber && VecLength2(dr) < 1e-6)
+ break;
+ }
+ if (j < mp->natoms) {
+ /* Bond i-j is created */
+ b[0] = i;
+ b[1] = j;
+ if (MoleculeLookupBond(mp, b[0], b[1]) < 0)
+ MoleculeAddBonds(mp, 1, b, NULL, 1);
+ }
+ }
}
}
mp->needsMDRebuild = 1;
}
/* Recalculate the coordinates of symmetry expanded atoms.
+ (Also recalculate the positions of pi-anchor atoms)
Returns the number of affected atoms.
If group is non-NULL, only the expanded atoms whose base atoms are in the
given group are considered.
{
int i, count;
Atom *ap, *bp;
- if (mp == NULL || mp->natoms == 0 || mp->nsyms == 0)
- return 0;
- if (groupout != NULL && vpout != NULL) {
- *groupout = IntGroupNew();
- if (*groupout == NULL)
- return -1;
- *vpout = (Vector *)malloc(sizeof(Vector) * mp->natoms);
- if (*vpout == NULL) {
- IntGroupRelease(*groupout);
- return -1;
- }
- } else groupout = NULL; /* To simplify test for validity of groupout/vpout */
+ Vector nr, dr;
+ IntGroup *ig = NULL;
+ Vector *vp = NULL;
+ if (mp == NULL || mp->natoms == 0)
+ return 0;
+
__MoleculeLock(mp);
count = 0;
+ if (mp->nsyms != 0) {
+ for (i = 0, ap = mp->atoms; i < mp->natoms; i++, ap = ATOM_NEXT(ap)) {
+ if (!SYMOP_ALIVE(ap->symop))
+ continue;
+ if (group != NULL && IntGroupLookup(group, ap->symbase, NULL) == 0)
+ continue;
+ bp = ATOM_AT_INDEX(mp->atoms, ap->symbase);
+ MoleculeTransformBySymop(mp, &(bp->r), &nr, ap->symop);
+ VecSub(dr, nr, ap->r);
+ if (VecLength2(dr) < 1e-20)
+ continue;
+ if (groupout != NULL) {
+ if (ig == NULL) {
+ ig = IntGroupNew();
+ vp = (Vector *)calloc(sizeof(Vector), mp->natoms);
+ }
+ vp[count] = ap->r;
+ IntGroupAdd(ig, i, 1);
+ }
+ ap->r = nr;
+ count++;
+ }
+ }
for (i = 0, ap = mp->atoms; i < mp->natoms; i++, ap = ATOM_NEXT(ap)) {
- Vector nr, dr;
- if (!SYMOP_ALIVE(ap->symop))
- continue;
- if (group != NULL && IntGroupLookup(group, ap->symbase, NULL) == 0)
+ Int *ip, j, n;
+ if (ap->anchor == NULL)
continue;
- bp = ATOM_AT_INDEX(mp->atoms, ap->symbase);
- MoleculeTransformBySymop(mp, &(bp->r), &nr, ap->symop);
+ if (group != NULL) {
+ if (IntGroupLookup(group, i, NULL) == 0) {
+ n = ap->anchor->connect.count;
+ ip = AtomConnectData(&(ap->anchor->connect));
+ for (j = 0; j < n; j++) {
+ if (IntGroupLookup(group, ip[j], NULL) != 0)
+ break;
+ }
+ if (j == n)
+ continue; /* This pi-anchor should not be modified */
+ }
+ }
+ nr = ap->r;
+ MoleculeCalculatePiAnchorPosition(mp, i);
VecSub(dr, nr, ap->r);
- if (VecLength2(dr) < 1e-20)
+ if (VecLength2(dr) < 1e-20) {
+ ap->r = nr; /* No change */
continue;
+ }
if (groupout != NULL) {
- (*vpout)[count] = ap->r;
- IntGroupAdd(*groupout, i, 1);
+ if (ig == NULL) {
+ ig = IntGroupNew();
+ vp = (Vector *)calloc(sizeof(Vector), mp->natoms);
+ }
+ vp[count] = nr;
+ IntGroupAdd(ig, i, 1);
}
- ap->r = nr;
count++;
}
mp->needsMDCopyCoordinates = 1;
__MoleculeUnlock(mp);
- if (groupout != NULL) {
- if (count == 0) {
- free(*vpout);
- *vpout = NULL;
- IntGroupRelease(*groupout);
- *groupout = NULL;
+
+ if (count > 0) {
+ if (groupout != NULL && vpout != NULL) {
+ *groupout = ig;
+ *vpout = (Vector *)realloc(vp, sizeof(Vector) * count);
} else {
- *vpout = (Vector *)realloc(*vpout, sizeof(Vector) * count);
+ IntGroupRelease(ig);
+ free(vp);
+ }
+ } else {
+ if (groupout != NULL && vpout != NULL) {
+ *groupout = NULL;
+ *vpout = NULL;
}
}
return count;
sRemoveElementsFromArrayAtPositions(void *objs, int nobjs, void *clip, size_t size, IntGroup *where)
{
int n1, n2, n3, start, end, i;
- if (objs == NULL || where == NULL)
+ if (where == NULL || IntGroupGetCount(where) == 0)
+ return 0; /* No operation */
+ if (objs == NULL || nobjs == 0)
return 1; /* Bad argument */
n1 = 0; /* Position to move remaining elements to */
n2 = 0; /* Position to move remaining elements from */
mp->natoms--;
goto error;
}
- ap1->nconnects = 0;
+ ap1->connect.count = 0;
if (ap1->resSeq >= mp->nresidues)
AssignArray(&mp->residues, &mp->nresidues, 4, ap1->resSeq, ap1->resName);
if (ap1->resName[0] == 0)
for (i = 0, api = ATOM_AT_INDEX(mp->atoms, i); i < mp->natoms; i++, api = ATOM_NEXT(api)) {
int j;
Int *cp;
- for (j = 0; j < api->nconnects; j++) {
- cp = AtomConnects(api);
+ cp = AtomConnectData(&api->connect);
+ for (j = 0; j < api->connect.count; j++) {
if (cp[j] >= pos)
cp[j]++;
}
+ if (api->anchor != NULL) {
+ cp = AtomConnectData(&api->anchor->connect);
+ for (j = 0; j < api->anchor->connect.count; j++) {
+ if (cp[j] >= pos)
+ cp[j]++;
+ }
+ }
}
for (i = 0; i < mp->nbonds * 2; i++) {
if (mp->bonds[i] >= pos)
return -1;
}
+#if defined(DEBUG)
+
+static int s_error_count;
+
+static int
+s_fprintf(FILE *fp, const char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ s_error_count++;
+ return vfprintf(fp, fmt, va);
+}
+
+int
+MoleculeCheckSanity(Molecule *mol)
+{
+ const char *fail = "Sanity check failure";
+ Int i, j, *ip, c[4];
+ Atom *ap;
+ s_error_count = 0;
+ for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
+ if (ap->resSeq >= mol->nresidues)
+ s_fprintf(stderr, "%s: atom %d residue %d but nresidues %d\n", fail, i, ap->resSeq, mol->nresidues);
+ if (ap->type != 0 && ap->type < kAtomTypeMinimum)
+ s_fprintf(stderr, "%s: atom %d atom type %d less than minimum\n", fail, i, ap->type);
+ if (ap->atomicNumber < 0 || ap->atomicNumber > 113)
+ s_fprintf(stderr, "%s: atom %d atomic number %d\n", fail, i, ap->atomicNumber);
+ ip = AtomConnectData(&ap->connect);
+ for (j = 0; j < ap->connect.count; j++) {
+ if (ip[j] < 0 || ip[j] >= mol->natoms)
+ s_fprintf(stderr, "%s: atom %d connect[%d] = %d out of range\n", fail, i, j, ip[j]);
+ if (AtomConnectHasEntry(&(ATOM_AT_INDEX(mol->atoms, ip[j])->connect), i) == 0)
+ s_fprintf(stderr, "%s: atom %d has connect %d but atom %d has no connect %d\n", fail, i, ip[j], ip[j], i);
+ }
+ }
+ for (i = 0, ip = mol->bonds; i < mol->nbonds; i++, ip += 2) {
+ if (ip[0] < 0 || ip[0] >= mol->natoms || ip[1] < 0 || ip[1] >= mol->natoms)
+ s_fprintf(stderr, "%s: bond %d %d-%d out of range\n", fail, i, ip[0], ip[1]);
+ if (AtomConnectHasEntry(&(ATOM_AT_INDEX(mol->atoms, ip[0])->connect), ip[1]) == 0)
+ s_fprintf(stderr, "%s: bond %d %d-%d but atom %d has no connect %d\n", fail, i, ip[0], ip[1], ip[0], ip[1]);
+ }
+ for (i = 0, ip = mol->angles; i < mol->nangles; i++, ip += 3) {
+ if (ip[0] < 0 || ip[0] >= mol->natoms || ip[1] < 0 || ip[1] >= mol->natoms || ip[2] < 0 || ip[2] >= mol->natoms)
+ s_fprintf(stderr, "%s: angle %d %d-%d-%d out of range\n", fail, i, ip[0], ip[1], ip[2]);
+ c[0] = MoleculeAreAtomsConnected(mol, ip[1], ip[0]);
+ if (c[0] == 0)
+ s_fprintf(stderr, "%s: angle %d %d-%d-%d but atom %d has no connect %d\n", fail, i, ip[0], ip[1], ip[2], ip[1], ip[0]);
+ c[1] = MoleculeAreAtomsConnected(mol, ip[1], ip[2]);
+ if (c[1] == 0)
+ s_fprintf(stderr, "%s: angle %d %d-%d-%d but atom %d has no connect %d\n", fail, i, ip[0], ip[1], ip[2], ip[1], ip[2]);
+ if (c[0] == 2 && c[1] == 2)
+ s_fprintf(stderr, "%s: angle %d %d-%d-%d but bonds %d-%d and %d-%d are both virtual\n", fail, i, ip[0], ip[1], ip[2], ip[1], ip[0], ip[1], ip[2]);
+ }
+ for (i = 0, ip = mol->dihedrals; i < mol->ndihedrals; i++, ip += 4) {
+ if (ip[0] < 0 || ip[0] >= mol->natoms || ip[1] < 0 || ip[1] >= mol->natoms || ip[2] < 0 || ip[2] >= mol->natoms || ip[3] < 0 || ip[3] >= mol->natoms)
+ s_fprintf(stderr, "%s: dihedral %d %d-%d-%d%d out of range\n", fail, i, ip[0], ip[1], ip[2], ip[3]);
+ c[0] = MoleculeAreAtomsConnected(mol, ip[1], ip[0]);
+ c[1] = MoleculeAreAtomsConnected(mol, ip[1], ip[2]);
+ c[2] = MoleculeAreAtomsConnected(mol, ip[2], ip[3]);
+ if (c[0] == 0)
+ s_fprintf(stderr, "%s: dihedral %d %d-%d-%d-%d but atom %d has no connect %d\n", fail, i, ip[0], ip[1], ip[2], ip[3], ip[1], ip[0]);
+ if (c[1] == 0)
+ s_fprintf(stderr, "%s: dihedral %d %d-%d-%d-%d but atom %d has no connect %d\n", fail, i, ip[0], ip[1], ip[2], ip[3], ip[1], ip[2]);
+ if (c[2] == 0)
+ s_fprintf(stderr, "%s: dihedral %d %d-%d-%d-%d but atom %d has no connect %d\n", fail, i, ip[0], ip[1], ip[2], ip[3], ip[2], ip[3]);
+ }
+ for (i = 0, ip = mol->impropers; i < mol->nimpropers; i++, ip += 4) {
+ if (ip[0] < 0 || ip[0] >= mol->natoms || ip[1] < 0 || ip[1] >= mol->natoms || ip[2] < 0 || ip[2] >= mol->natoms || ip[3] < 0 || ip[3] >= mol->natoms)
+ s_fprintf(stderr, "%s: improper %d %d-%d-%d%d out of range\n", fail, i, ip[0], ip[1], ip[2], ip[3]);
+ c[0] = MoleculeAreAtomsConnected(mol, ip[2], ip[0]);
+ c[1] = MoleculeAreAtomsConnected(mol, ip[2], ip[1]);
+ c[2] = MoleculeAreAtomsConnected(mol, ip[2], ip[3]);
+ if (c[0] == 0)
+ s_fprintf(stderr, "%s: improper %d %d-%d-%d-%d but atom %d has no connect %d\n", fail, i, ip[0], ip[1], ip[2], ip[3], ip[2], ip[0]);
+ if (c[1] == 0)
+ s_fprintf(stderr, "%s: improper %d %d-%d-%d-%d but atom %d has no connect %d\n", fail, i, ip[0], ip[1], ip[2], ip[3], ip[2], ip[1]);
+ if (c[2] == 0)
+ s_fprintf(stderr, "%s: improper %d %d-%d-%d-%d but atom %d has no connect %d\n", fail, i, ip[0], ip[1], ip[2], ip[3], ip[2], ip[3]);
+ }
+ return s_error_count;
+}
+#endif
+
/* Merge two molecules. We use this procedure for all add-atom operations. */
/* resSeqOffset is an offset to add to the (non-zero) residue numbers in src. */
+/* If nactions and actions are non-NULL, then the corresponding undo actions are created and returned. */
+/* If forUndo is non-zero, then only the atoms are inserted; other information should be inserted
+ separately by other undo actions. */
int
-MoleculeMerge(Molecule *dst, Molecule *src, IntGroup *where, int resSeqOffset)
+MoleculeMerge(Molecule *dst, Molecule *src, IntGroup *where, Int resSeqOffset, Int *nactions, MolAction ***actions, Int forUndo)
{
Int nsrc, ndst;
Int i, j, n1, n2, n3, n4, *cp;
Int *new2old, *old2new;
+ IntGroup *ig;
Atom *ap;
+ MolAction *act;
+
if (dst == NULL || src == NULL || src->natoms == 0 || (where != NULL && IntGroupGetIntervalCount(where) == 0))
return 0; /* Do nothing */
if (where != NULL && IntGroupGetCount(where) != src->natoms)
return 1; /* Bad parameter */
+ if (nactions != NULL)
+ *nactions = 0;
+ if (actions != NULL)
+ *actions = NULL;
+ act = NULL;
+
__MoleculeLock(dst);
+
nsrc = src->natoms;
ndst = dst->natoms;
if (resSeqOffset < 0)
if (where == NULL) {
/* Duplicate atoms to the end of the destination array */
for (i = 0; i < nsrc; i++) {
- if (AtomDuplicate(ATOM_AT_INDEX(dst->atoms, ndst + i), ATOM_AT_INDEX(src->atoms, i)) == NULL)
+ ap = ATOM_AT_INDEX(dst->atoms, ndst + i);
+ if (AtomDuplicate(ap, ATOM_AT_INDEX(src->atoms, i)) == NULL)
goto panic;
+ if (forUndo) /* For undo action, all bonds come from another undo action, so connection info are cleared */
+ AtomConnectResize(&ap->connect, 0);
}
- // memmove(ATOM_AT_INDEX(dst->atoms, ndst), src->atoms, gSizeOfAtomRecord * nsrc);
} else {
/* Duplicate to a temporary storage and then insert */
Atom *tempatoms = (Atom *)malloc(gSizeOfAtomRecord * nsrc);
if (tempatoms == NULL)
goto panic;
for (i = 0; i < nsrc; i++) {
- if (AtomDuplicate(ATOM_AT_INDEX(tempatoms, i), ATOM_AT_INDEX(src->atoms, i)) == NULL)
+ ap = ATOM_AT_INDEX(tempatoms, i);
+ if (AtomDuplicate(ap, ATOM_AT_INDEX(src->atoms, i)) == NULL)
goto panic;
+ if (forUndo) /* See above */
+ AtomConnectResize(&ap->connect, 0);
}
if (sInsertElementsToArrayAtPositions(dst->atoms, ndst, tempatoms, nsrc, gSizeOfAtomRecord, where) != 0)
goto panic;
if (ap->resSeq != 0)
ap->resSeq += resSeqOffset; /* Modify residue number */
}
- cp = AtomConnects(ap);
- for (j = 0; j < ap->nconnects; j++)
+ cp = AtomConnectData(&ap->connect);
+ for (j = 0; j < ap->connect.count; j++)
cp[j] = old2new[cp[j] + n1];
if (SYMOP_ALIVE(ap->symop))
ap->symbase = old2new[ap->symbase + n1];
+ if (ap->anchor != NULL) {
+ cp = AtomConnectData(&ap->anchor->connect);
+ for (j = 0; j < ap->anchor->connect.count; j++)
+ cp[j] = old2new[cp[j] + n1];
+ }
}
/* Move the bonds, angles, dihedrals, impropers */
}
nitems_src = (Int *)((char *)src + ((char *)nitems - (char *)dst));
items_src = (Int **)((char *)src + ((char *)items - (char *)dst));
- /* Keep the old number of entries in dst, because it is updated by AssignArray() */
- n1 = *nitems;
- /* Also keep the old number of entries in src, in case src and dst point the same molecule */
- n2 = *nitems_src;
- /* Expand the array */
- if (AssignArray(items, nitems, sizeof(Int) * nsize, *nitems + *nitems_src - 1, NULL) == NULL)
- goto panic;
- /* Copy the items */
- memmove(*items + n1 * nsize, *items_src, sizeof(Int) * nsize * n2);
+ if (forUndo) {
+ /* During undo, no bonds etc. are copied from src; they will be taken care later
+ by undo actions */
+ n1 = *nitems;
+ n2 = 0;
+ } else {
+ /* Keep the old number of entries in dst, because it is updated by AssignArray() */
+ n1 = *nitems;
+ /* Also keep the old number of entries in src, in case src and dst point the same molecule */
+ n2 = *nitems_src;
+ /* Expand the array */
+ if (AssignArray(items, nitems, sizeof(Int) * nsize, *nitems + *nitems_src - 1, NULL) == NULL)
+ goto panic;
+ /* Copy the items */
+ memmove(*items + n1 * nsize, *items_src, sizeof(Int) * nsize * n2);
+ if (i == 0) {
+ /* Copy the bond order info if present */
+ Int nn1 = dst->nbondOrders;
+ if (dst->bondOrders != NULL || src->bondOrders != NULL) {
+ if (AssignArray(&dst->bondOrders, &dst->nbondOrders, sizeof(Double), dst->nbonds - 1, NULL) == NULL)
+ goto panic;
+ memset(dst->bondOrders + nn1, 0, sizeof(Double) * (dst->nbonds - nn1));
+ if (src->bondOrders != NULL)
+ memmove(dst->bondOrders + n1, src->bondOrders, sizeof(Double) * n2);
+ }
+ }
+ }
/* Renumber */
for (j = 0; j < n1 * nsize; j++)
(*items)[j] = old2new[(*items)[j]];
for (j = n1 * nsize; j < (n1 + n2) * nsize; j++)
(*items)[j] = old2new[(*items)[j] + ndst];
+ if (forUndo == 0 && actions != NULL) {
+ ig = IntGroupNewWithPoints(n1, n2, -1);
+ switch (i) {
+ case 0: act = MolActionNew(gMolActionDeleteBonds, ig); break;
+ case 1: act = MolActionNew(gMolActionDeleteAngles, ig); break;
+ case 2: act = MolActionNew(gMolActionDeleteDihedrals, ig); break;
+ case 3: act = MolActionNew(gMolActionDeleteImpropers, ig); break;
+ }
+ IntGroupRelease(ig);
+ AssignArray(actions, nactions, sizeof(MolAction *), *nactions, &act);
+ act = NULL;
+ }
}
- /* Merge parameters */
- if (src->par != NULL) {
+ /* Renumber existing parameters */
+ if (dst->par != NULL) {
+ int type;
+ for (type = kFirstParType; type <= kLastParType; type++) {
+ UnionPar *up1;
+ n1 = ParameterGetCountForType(dst->par, type);
+ for (i = 0; i < n1; i++) {
+ up1 = ParameterGetUnionParFromTypeAndIndex(dst->par, type, i);
+ ParameterRenumberAtoms(type, up1, ndst, old2new);
+ }
+ }
+ }
+
+ /* Merge parameters from src */
+ if (src->par != NULL && forUndo == 0) {
UnionPar *up1, *up2;
int type;
- IntGroup *ig;
if (dst->par == NULL)
dst->par = ParameterNew();
else {
if (up1 == NULL)
goto panic;
/* Copy parameters and renumber indices if necessary */
- for (i = 0; i < n1; i++) {
+ for (i = j = 0; i < n1; i++) {
up2 = ParameterGetUnionParFromTypeAndIndex(src->par, type, IntGroupGetNthPoint(ig, i));
if (up2 == NULL)
continue;
- up1[i] = *up2;
- ParameterRenumberAtoms(type, up1 + i, nsrc, old2new + ndst);
+ up1[j] = *up2;
+ ParameterRenumberAtoms(type, up1 + j, nsrc, old2new + ndst);
+ j++;
}
/* Merge parameters */
IntGroupClear(ig);
- IntGroupAdd(ig, n2, n1);
- if (ParameterInsert(dst->par, type, up1, ig) < n1)
+ IntGroupAdd(ig, n2, j);
+ if (ParameterInsert(dst->par, type, up1, ig) < j)
goto panic;
+ if (actions != NULL) {
+ act = MolActionNew(gMolActionDeleteParameters, type, ig);
+ AssignArray(actions, nactions, sizeof(MolAction *), *nactions, &act);
+ act = NULL;
+ }
IntGroupClear(ig);
free(up1);
}
/* src[1..src->nresidues-1] should become dst[1+resSeqOffset..src->nresidues+resSeqOffset-1];
However, 1+resSeqOffset should not overwrite the existing residue in dst;
i.e. if 1+resSeqOffset is less than dst->nresidues, copy should start from src[dst->nresidues-resSeqOffset] instead of src[1]. */
- n1 = dst->nresidues;
- if (1 + resSeqOffset < n1) {
- n2 = n1;
- } else n2 = 1 + resSeqOffset; /* n2 is the start index of residues from src[] */
- if (src->nresidues > 1 && n1 < src->nresidues + resSeqOffset) {
- if (AssignArray(&dst->residues, &dst->nresidues, sizeof(dst->residues[0]), src->nresidues + resSeqOffset - 1, NULL) == NULL)
- goto panic;
- memmove(dst->residues + n2, src->residues + n2 - resSeqOffset, sizeof(dst->residues[0]) * (src->nresidues - (n2 - resSeqOffset)));
+ if (forUndo == 0) {
+ n1 = dst->nresidues;
+ if (1 + resSeqOffset < n1) {
+ n2 = n1;
+ } else n2 = 1 + resSeqOffset; /* n2 is the start index of residues from src[] */
+ if (src->nresidues > 1 && n1 < src->nresidues + resSeqOffset) {
+ if (AssignArray(&dst->residues, &dst->nresidues, sizeof(dst->residues[0]), src->nresidues + resSeqOffset - 1, NULL) == NULL)
+ goto panic;
+ memmove(dst->residues + n2, src->residues + n2 - resSeqOffset, sizeof(dst->residues[0]) * (src->nresidues - (n2 - resSeqOffset)));
+ if (nactions != NULL) {
+ act = MolActionNew(gMolActionChangeNumberOfResidues, n1);
+ AssignArray(actions, nactions, sizeof(MolAction *), *nactions, &act);
+ act = NULL;
+ }
+ }
}
MoleculeCleanUpResidueTable(dst);
return 1; /* Not reached */
}
+/* Unmerge the molecule. If necessary, the undo actions are stored in nactions/actions array.
+ (The nactions/actions array must be initialized by the caller) */
static int
-sMoleculeUnmergeSub(Molecule *src, Molecule **dstp, IntGroup *where, int resSeqOffset, int moveFlag)
+sMoleculeUnmergeSub(Molecule *src, Molecule **dstp, IntGroup *where, int resSeqOffset, int moveFlag, Int *nactions, MolAction ***actions, Int forUndo)
{
Int nsrc, ndst, nsrcnew;
Int i, j, n1, n2, n3, n4, *cp;
Molecule *dst;
Atom *ap, *dst_ap;
UnionPar *up;
-
+ MolAction *act;
+
if (src == NULL || src->natoms == 0 || where == NULL || IntGroupGetIntervalCount(where) == 0) {
/* Do nothing */
if (dstp != NULL)
__MoleculeLock(src);
+ act = NULL;
+
nsrc = src->natoms;
nsrcnew = nsrc - ndst;
if (resSeqOffset < 0)
}
}
} else dst_par_g = remove_par_g = NULL;
-
+
+ /* Pi anchors should be modified if the anchor and its component atoms become separated between
+ src anc dst */
+ if (moveFlag) {
+ Int ibufsize, *ibuf, flag_i, flag_j;
+ ibufsize = 8;
+ ibuf = (Int *)malloc(sizeof(Int) * ibufsize);
+ for (i = 0, ap = src->atoms; i < src->natoms; i++, ap = ATOM_NEXT(ap)) {
+ if (ap->anchor == NULL)
+ continue;
+ flag_i = (old2new[i] < nsrcnew);
+ cp = AtomConnectData(&ap->anchor->connect);
+ for (j = n1 = 0; j < ap->anchor->connect.count; j++) {
+ flag_j = (old2new[cp[j]] < nsrcnew);
+ if (flag_i == flag_j) {
+ if (n1 >= ibufsize) {
+ ibufsize += 8;
+ ibuf = (Int *)realloc(ibuf, sizeof(Int) * ibufsize);
+ }
+ ibuf[n1++] = cp[j];
+ }
+ }
+ if (n1 < j) {
+ /* Need to modify the pi anchor list */
+ if (n1 <= 1)
+ n1 = 0;
+ MolActionCreateAndPerform(src, SCRIPT_ACTION("isI"), "set_atom_attr", i, "anchor_list", n1, ibuf);
+ }
+ }
+ }
+
/* Make a new molecule */
if (dstp != NULL) {
dst = MoleculeNew();
dst_ap = NULL;
}
- /* Renumber the atom indices in connect[] */
+ /* Renumber the atom indices in connect[] (src) */
if (moveFlag) {
for (i = 0, ap = src->atoms; i < src->natoms; i++, ap = ATOM_NEXT(ap)) {
- cp = AtomConnects(ap);
- for (j = n1 = 0; j < ap->nconnects; j++) {
+ cp = AtomConnectData(&ap->connect);
+ for (j = n1 = 0; j < ap->connect.count; j++) {
n2 = old2new[cp[j]];
if (n2 < nsrcnew)
cp[n1++] = n2;
}
- AtomResizeConnects(ap, n1);
+ AtomConnectResize(&ap->connect, n1);
+ if (ap->anchor != NULL) {
+ cp = AtomConnectData(&ap->anchor->connect);
+ for (j = n1 = 0; j < ap->anchor->connect.count; j++) {
+ n2 = old2new[cp[j]];
+ if (n2 < nsrcnew)
+ cp[n1++] = n2;
+ }
+ if (n1 != ap->anchor->connect.count) {
+ /* This should not happen!! */
+ AtomConnectResize(&ap->anchor->connect, n1);
+ fprintf(stderr, "Internal error in sMoleculeUnmergeSub (line %d)\n", __LINE__);
+ if (n1 == 0) {
+ free(ap->anchor->coeffs);
+ free(ap->anchor);
+ ap->anchor = NULL;
+ }
+ }
+ }
}
}
- /* Renumber the atom indices in connect[] and the residue indices */
+ /* Renumber the atom indices in connect[] (dst) */
if (dst != NULL) {
for (i = 0, ap = dst->atoms; i < dst->natoms; i++, ap = ATOM_NEXT(ap)) {
if (ap->resSeq != 0 && ap->resSeq - resSeqOffset >= 0)
ap->resSeq -= resSeqOffset;
else ap->resSeq = 0;
- cp = AtomConnects(ap);
- for (j = n1 = 0; j < ap->nconnects; j++) {
+ cp = AtomConnectData(&ap->connect);
+ for (j = n1 = 0; j < ap->connect.count; j++) {
n2 = old2new[cp[j]] - nsrcnew;
if (n2 >= 0)
cp[n1++] = n2;
}
- AtomResizeConnects(ap, n1);
+ AtomConnectResize(&ap->connect, n1);
+ if (ap->anchor != NULL) {
+ cp = AtomConnectData(&ap->anchor->connect);
+ for (j = n1 = 0; j < ap->anchor->connect.count; j++) {
+ n2 = old2new[cp[j]] - nsrcnew;
+ if (n2 >= 0)
+ cp[n1++] = n2;
+ }
+ if (n1 != ap->anchor->connect.count) {
+ /* This can happen, and the anchor info is silently modified */
+ if (n1 <= 1) {
+ AtomConnectResize(&ap->anchor->connect, 0);
+ free(ap->anchor->coeffs);
+ free(ap->anchor);
+ ap->anchor = NULL;
+ } else {
+ Double d;
+ AtomConnectResize(&ap->anchor->connect, n1);
+ d = 0.0;
+ for (j = 0; j < n1; j++)
+ d += ap->anchor->coeffs[j];
+ for (j = 0; j < n1; j++)
+ ap->anchor->coeffs[j] /= d;
+ MoleculeCalculatePiAnchorPosition(dst, i);
+ }
+ }
+ }
}
}
/* Separate the bonds, angles, dihedrals, impropers */
/* TODO: Improper torsions should also be copied! */
move_g = IntGroupNew();
- del_g = IntGroupNew();
- if (move_g == NULL || del_g == NULL)
+ if (move_g == NULL)
goto panic;
- for (i = 0; i < 4; i++) {
+ for (i = 3; i >= 0; i--) {
Int *nitems, *nitems_dst;
Int **items, **items_dst;
Int nsize; /* Number of Ints in one element */
unsigned char *counts;
+ del_g = IntGroupNew();
switch (i) {
case 0:
nitems = &src->nbonds; items = &src->bonds; nsize = 2; break;
n1 = old2new[(*items)[j]];
if (n1 >= nsrcnew)
counts[j / nsize]++; /* Count the atom belonging to dst */
- /* if (n1 >= nsrcnew) {
- n1 -= nsrcnew;
- if (j % nsize == 0) {
- if (IntGroupAdd(sep, j / nsize, 1) != 0)
- goto panic;
- n2++;
- }
- }
- (*items)[j] = n1; */
}
for (j = n2 = n3 = 0; j < *nitems; j++) {
if (counts[j] > 0) {
goto panic;
if (sCopyElementsFromArrayAtPositions(*items, *nitems, *items_dst, sizeof(Int) * nsize, move_g) != 0)
goto panic;
+ if (i == 0 && src->bondOrders != NULL) {
+ if (AssignArray(&dst->bondOrders, &dst->nbondOrders, sizeof(Double), n3 - 1, NULL) == NULL)
+ goto panic;
+ if (sCopyElementsFromArrayAtPositions(src->bondOrders, src->nbondOrders, dst->bondOrders, sizeof(Double), move_g) != 0)
+ goto panic;
+ }
}
/* Remove from src */
- if (moveFlag) {
+ if (moveFlag && forUndo == 0) {
+ if (nactions != NULL) {
+ Int k, *ip;
+ Double *dp;
+ ip = (Int *)malloc(sizeof(Int) * nsize * n2);
+ for (j = 0; (k = IntGroupGetNthPoint(del_g, j)) >= 0; j++)
+ memmove(ip + j * nsize, *items + k * nsize, sizeof(Int) * nsize);
+ if (i == 0 && src->bondOrders != NULL) {
+ dp = (Double *)malloc(sizeof(Double) * n2);
+ for (j = 0; (k = IntGroupGetNthPoint(del_g, j)) >= 0; j++)
+ dp[j] = src->bondOrders[k];
+ } else dp = NULL;
+ switch (i) {
+ case 0:
+ act = MolActionNew(gMolActionAddBondsForUndo, n2 * nsize, ip, del_g); break;
+ case 1:
+ act = MolActionNew(gMolActionAddAngles, n2 * nsize, ip, del_g); break;
+ case 2:
+ act = MolActionNew(gMolActionAddDihedrals, n2 * nsize, ip, del_g); break;
+ case 3:
+ act = MolActionNew(gMolActionAddImpropers, n2 * nsize, ip, del_g); break;
+ }
+ if (act != NULL) {
+ AssignArray(actions, nactions, sizeof(MolAction *), *nactions, &act);
+ act = NULL;
+ }
+ free(ip);
+ if (dp != NULL) {
+ act = MolActionNew(gMolActionAssignBondOrders, n2, dp, del_g);
+ AssignArray(actions, nactions, sizeof(MolAction *), *nactions, &act);
+ act = NULL;
+ free(dp);
+ }
+ }
if (sRemoveElementsFromArrayAtPositions(*items, *nitems, NULL, sizeof(Int) * nsize, del_g) != 0)
goto panic;
(*nitems) -= n2;
}
free(counts);
IntGroupClear(move_g);
- IntGroupClear(del_g);
+ IntGroupRelease(del_g);
}
IntGroupRelease(move_g);
- IntGroupRelease(del_g);
/* Copy the residues */
if (dst != NULL) {
free(up);
IntGroupRelease(dst_new_g);
}
-
+ IntGroupRelease(dst_par_g);
+
/* Remove the unused parameter. Note: the parameters that are in remove_par_g and not in
dst_par_g will disappear. To support undo, these parameters should be taken care separately. */
- if (remove_par_g != NULL && (n2 = IntGroupGetCount(remove_par_g)) > 0) {
- ParameterDelete(src->par, kFirstParType, NULL, remove_par_g);
+ if (forUndo == 0 && remove_par_g != NULL && (n2 = IntGroupGetCount(remove_par_g)) > 0) {
+ UnionPar *up = (UnionPar *)malloc(sizeof(UnionPar) * n2);
+ ParameterDelete(src->par, kFirstParType, up, remove_par_g);
+ if (nactions != NULL) {
+ act = MolActionNew(gMolActionAddParameters, kFirstParType, remove_par_g, n2, up);
+ AssignArray(actions, nactions, sizeof(MolAction *), *nactions, &act);
+ act = NULL;
+ }
+ free(up);
}
+ IntGroupRelease(remove_par_g);
/* Renumber the parameter records remaining in the src */
if (moveFlag) {
}
}
}
-
+
/* Clean up */
+ IntGroupRelease(remain_g);
MoleculeCleanUpResidueTable(src);
if (dst != NULL)
MoleculeCleanUpResidueTable(dst);
from src to a new molecule, which is returned as *dstp. Dstp can be NULL,
in which case the moved atoms are discarded. */
int
-MoleculeUnmerge(Molecule *src, Molecule **dstp, IntGroup *where, int resSeqOffset)
+MoleculeUnmerge(Molecule *src, Molecule **dstp, IntGroup *where, int resSeqOffset, Int *nactions, MolAction ***actions, Int forUndo)
{
- return sMoleculeUnmergeSub(src, dstp, where, resSeqOffset, 1);
+ return sMoleculeUnmergeSub(src, dstp, where, resSeqOffset, 1, nactions, actions, forUndo);
}
/* Extract atoms from a given molecule into two parts. The atoms specified by
int retval;
/* Extract the fragment */
- retval = sMoleculeUnmergeSub(src, dstp, where, 0, 0);
+ retval = sMoleculeUnmergeSub(src, dstp, where, 0, 0, NULL, NULL, 0);
if (retval != 0)
return retval;
nn[1] = MoleculeCreateAnAtom(*dstp, &a, -1);
/* Connect nn1 and nn2 */
nn[2] = kInvalidIndex;
- MoleculeAddBonds(*dstp, 1, nn);
+ MoleculeAddBonds(*dstp, 1, nn, NULL, 1);
}
IntGroupIteratorRelease(&iter);
IntGroupRelease(ig);
}
int
-MoleculeAddBonds(Molecule *mp, Int nbonds, const Int *bonds)
-{
- int i, j, n1, n2, n;
- Atom *ap;
- Int *bonds_tmp, *cp;
-
+MoleculeAddBonds(Molecule *mp, Int nbonds, const Int *bonds, IntGroup *where, Int autoGenerate)
+{
+ Int nangles, ndihedrals;
+ Int *angles, *dihedrals;
+ Int i, j, k, kk, n1, n2, cn1, cn2;
+ Int *cp1, *cp2;
+ Int temp[4];
+ Atom *ap1, *ap2, *ap3;
+
if (mp == NULL || bonds == NULL || nbonds <= 0)
return 0;
if (mp->noModifyTopology)
return -4; /* Prohibited operation */
- /* Check the bonds */
- bonds_tmp = (Int *)malloc(sizeof(Int) * nbonds * 2);
- if (bonds_tmp == NULL)
+ /* Note: Duplicates and validity are not checked (the caller must do that) */
+
+ __MoleculeLock(mp);
+
+ n1 = mp->nbonds;
+ if (AssignArray(&(mp->bonds), &(mp->nbonds), sizeof(Int) * 2, n1 + nbonds - 1, NULL) == NULL
+ || sInsertElementsToArrayAtPositions(mp->bonds, n1, bonds, nbonds, sizeof(Int) * 2, where) != 0) {
+ __MoleculeUnlock(mp);
return -4; /* Out of memory */
- n = 0;
- for (i = 0; i < nbonds; i++) {
- n1 = bonds[i * 2];
- n2 = bonds[i * 2 + 1];
- if (n1 < 0 || n1 >= mp->natoms || n2 < 0 || n2 >= mp->natoms)
- return -1; /* Bad bond specification */
- if (n1 == n2)
- return -5;
- ap = ATOM_AT_INDEX(mp->atoms, n1);
- /* if (ap->nconnects >= ATOMS_MAX_CONNECTS - 1 || ATOM_AT_INDEX(mp->atoms, n2)->nconnects >= ATOMS_MAX_CONNECTS - 1)
- return -2; *//* Too many bonds */
- /* Check duplicates */
- cp = AtomConnects(ap);
- for (j = 0; j < ap->nconnects; j++) {
- if (cp[j] == n2)
- break;
- }
- if (j == ap->nconnects) {
- bonds_tmp[n * 2] = n1;
- bonds_tmp[n * 2 + 1] = n2;
- n++;
- }
}
- if (n == 0) {
- /* No bonds to add */
- free(bonds_tmp);
- return 0;
+ if (mp->bondOrders != NULL) {
+ /* Expand the bond order info (all new entries are zero) */
+ Double *dp = (Double *)calloc(sizeof(Double), nbonds);
+ if (dp == NULL)
+ return -4;
+ if (AssignArray(&(mp->bondOrders), &(mp->nbondOrders), sizeof(Double), n1 + nbonds - 1, NULL) == NULL
+ || sInsertElementsToArrayAtPositions(mp->bondOrders, n1, dp, nbonds, sizeof(Double), where) != 0) {
+ __MoleculeUnlock(mp);
+ free(dp);
+ return -4;
+ }
+ free(dp);
}
- __MoleculeLock(mp);
-
- /* Add connects[] */
- for (i = 0; i < n; i++) {
- n1 = bonds_tmp[i * 2];
- n2 = bonds_tmp[i * 2 + 1];
- ap = ATOM_AT_INDEX(mp->atoms, n1);
- AtomInsertConnectEntry(ap, ap->nconnects, n2);
- ap = ATOM_AT_INDEX(mp->atoms, n2);
- AtomInsertConnectEntry(ap, ap->nconnects, n1);
- }
+ angles = dihedrals = NULL;
+ nangles = ndihedrals = 0;
- /* Expand the array and insert */
- n1 = mp->nbonds;
-/* if (AssignArray(&(mp->bonds), &(mp->nbonds), sizeof(Int) * 2, mp->nbonds + nb - 1, NULL) == NULL
- || sInsertElementsToArrayAtPositions(mp->bonds, n1, bonds, nb, sizeof(Int) * 2, where) != 0) */
- if (AssignArray(&(mp->bonds), &(mp->nbonds), sizeof(Int) * 2, mp->nbonds + n - 1, NULL) == NULL)
- goto panic;
- memmove(mp->bonds + n1 * 2, bonds_tmp, sizeof(Int) * 2 * n);
-
- /* Add angles, dihedrals, impropers */
- {
- Int nangles, ndihedrals, nimpropers;
- Int *angles, *dihedrals, *impropers;
- Int k, n3, n4;
- Int *ip, *cp1, *cp2;
- Int temp[4];
- Atom *ap1, *ap2;
-
- angles = dihedrals = impropers = NULL;
- nangles = ndihedrals = nimpropers = 0;
-
- for (i = 0; i < n; i++) {
- n1 = bonds_tmp[i * 2];
- n2 = bonds_tmp[i * 2 + 1];
- ap1 = ATOM_AT_INDEX(mp->atoms, n1);
- ap2 = ATOM_AT_INDEX(mp->atoms, n2);
- cp1 = AtomConnects(ap1);
- cp2 = AtomConnects(ap2);
- /* Angles X-n1-n2 */
- for (j = 0; j < ap1->nconnects; j++) {
- n3 = cp1[j];
- if (n3 == n2)
- continue;
- temp[0] = n3;
- temp[1] = n1;
- temp[2] = n2;
- for (k = 0; k < nangles; k++) {
- ip = angles + k * 3;
- if (ip[1] == n1 && ((ip[0] == n3 && ip[2] == n2) || (ip[0] == n2 && ip[2] == n3)))
- break;
- }
- if (k == nangles) {
- if (AssignArray(&angles, &nangles, sizeof(Int) * 3, nangles, temp) == NULL)
- goto panic;
- }
- /* Dihedrals X-n1-n2-X */
- for (k = 0; k < ap2->nconnects; k++) {
- n4 = cp2[k];
- if (n4 == n1 || n4 == n3)
- continue;
- temp[3] = n4;
- if (AssignArray(&dihedrals, &ndihedrals, sizeof(Int) * 4, ndihedrals, temp) == NULL)
- goto panic;
+ /* Add connects[], and angles/dihedrals (if autoGenerate is true) */
+ for (i = 0; i < nbonds; i++) {
+
+ /* One entry at time */
+ /* (Otherwise, duplicate entries of angles and dihedrals result) */
+ n1 = bonds[i * 2];
+ n2 = bonds[i * 2 + 1];
+
+ ap1 = ATOM_AT_INDEX(mp->atoms, n1);
+ AtomConnectInsertEntry(&ap1->connect, -1, n2);
+ ap2 = ATOM_AT_INDEX(mp->atoms, n2);
+ AtomConnectInsertEntry(&ap2->connect, -1, n1);
+
+ /* Add angles and dihedrals */
+ if (autoGenerate) {
+ AtomConnect *ac1, *ac2;
+ if (ap1->anchor == NULL || ap2->anchor == NULL) {
+ /* N1-N2-{XY} or N2-N1-{XY} angles (X: connected atom, Y: constitute atom of pi-anchor) */
+ for (j = 0; j < 4; j++) {
+ switch (j) {
+ case 0: temp[0] = n1; temp[1] = n2; ac1 = &ap2->connect; break; /* N1-N2-X */
+ case 1: if (ap2->anchor == NULL) continue; else ac1 = &ap2->anchor->connect; break; /* N1-N2-Y */
+ case 2: temp[0] = n2; temp[1] = n1; ac1 = &ap1->connect; break; /* N2-N1-X */
+ case 3: if (ap1->anchor == NULL) continue; else ac1 = &ap1->anchor->connect; break; /* N2-N1-Y */
+ }
+ cp1 = AtomConnectData(ac1);
+ cn1 = ac1->count;
+ for (k = 0; k < cn1; k++) {
+ temp[2] = cp1[k];
+ if (temp[2] == temp[0])
+ continue;
+ ap3 = ATOM_AT_INDEX(mp->atoms, temp[2]);
+ if (ap3->anchor != NULL) {
+ /* Avoid X-anchor-anchor angle (anchor-X-anchor is allowed) */
+ if ((j < 2 && ap2->anchor != NULL) || (j >= 2 && ap1->anchor != NULL))
+ continue;
+ }
+ if (AssignArray(&angles, &nangles, sizeof(Int) * 3, nangles, temp) == NULL)
+ goto panic;
+ /* Dihedrals N1-N2-X-{XY} or N2-N1-X-{XY} */
+ if (j == 1 || j == 3)
+ continue;
+ cp2 = AtomConnectData(&ap3->connect);
+ for (kk = 0; kk < ap3->connect.count; kk++) {
+ temp[3] = cp2[kk];
+ if (temp[3] == temp[0] || temp[3] == temp[1])
+ continue;
+ if (AssignArray(&dihedrals, &ndihedrals, sizeof(Int) * 4, ndihedrals, temp) == NULL)
+ goto panic;
+ }
+ if (ap3->anchor != NULL) {
+ /* N1-N2-X-Y or N2-N1-X-Y */
+ /* for Y, only the first constitute atom is considered */
+ cp2 = AtomConnectData(&ap3->anchor->connect);
+ temp[3] = cp2[0];
+ if (temp[3] == temp[0] || temp[3] == temp[1])
+ continue;
+ if (AssignArray(&dihedrals, &ndihedrals, sizeof(Int) * 4, ndihedrals, temp) == NULL)
+ goto panic;
+ }
+ }
}
- /* Impropers X-n2-n1-X */
- /* temp[1] = n2;
- temp[2] = n1;
- for (k = 0; k < ap1->nconnects; k++) {
- n4 = ap1->connects[k];
- if (n4 == n2 || n4 <= n3)
- continue;
- temp[3] = n4;
- if (AssignArray(&impropers, &nimpropers, sizeof(Int) * 4, nimpropers, temp) == NULL)
- goto panic;
- } */
}
- /* Angles X-n2-n1 */
- for (j = 0; j < ap2->nconnects; j++) {
- n3 = cp2[j];
- if (n3 == n1)
+ /* X-N1-N2-X dihedrals */
+ /* Y-N1-N2-anchor is allowed, but the force may be zero if the angle N1-N2-anchor is */
+ /* close to 180 deg (e.g. in ferrocene, C-anchor-Fe-anchor dihedral should be k=0) */
+ if (ap1->anchor == NULL) {
+ ac1 = &ap1->connect;
+ cn1 = ac1->count;
+ } else {
+ ac1 = &ap1->anchor->connect;
+ cn1 = 1; /* Only the first constitute atom of pi-anchor is considered */
+ }
+ if (ap2->anchor == NULL) {
+ ac2 = &ap2->connect;
+ cn2 = ac2->count;
+ } else {
+ ac2 = &ap2->anchor->connect;
+ cn2 = 1; /* Only the first constitute atom of pi-anchor is considered */
+ }
+ temp[1] = n1;
+ temp[2] = n2;
+ cp1 = AtomConnectData(ac1);
+ cp2 = AtomConnectData(ac2);
+ for (j = 0; j < cn1; j++) {
+ temp[0] = cp1[j];
+ if (temp[0] == temp[2])
continue;
- temp[0] = n1;
- temp[1] = n2;
- temp[2] = n3;
- for (k = 0; k < nangles; k++) {
- ip = angles + k * 3;
- if (ip[1] == n2 && ((ip[0] == n3 && ip[2] == n1) || (ip[0] == n1 && ip[2] == n3)))
- break;
- }
- if (k == nangles) {
- if (AssignArray(&angles, &nangles, sizeof(Int) * 3, nangles, temp) == NULL)
+ for (k = 0; k < cn2; k++) {
+ temp[3] = cp2[k];
+ if (temp[3] == temp[0] || temp[3] == temp[1])
+ continue;
+ if (AssignArray(&dihedrals, &ndihedrals, sizeof(Int) * 4, ndihedrals, temp) == NULL)
goto panic;
}
}
}
+ }
+
+ if (angles != NULL) {
temp[0] = kInvalidIndex;
if (AssignArray(&angles, &nangles, sizeof(Int) * 3, nangles, temp) == NULL)
goto panic;
+ MoleculeAddAngles(mp, angles, NULL);
+ free(angles);
+ }
+ if (dihedrals != NULL) {
+ temp[0] = kInvalidIndex;
if (AssignArray(&dihedrals, &ndihedrals, sizeof(Int) * 4, ndihedrals, temp) == NULL)
goto panic;
- if (AssignArray(&impropers, &nimpropers, sizeof(Int) * 4, nimpropers, temp) == NULL)
- goto panic;
- MoleculeAddAngles(mp, angles, NULL);
MoleculeAddDihedrals(mp, dihedrals, NULL);
- MoleculeAddImpropers(mp, impropers, NULL);
- if (angles != NULL)
- free(angles);
- if (dihedrals != NULL)
- free(dihedrals);
- if (impropers != NULL)
- free(impropers);
+ free(dihedrals);
}
-
+
MoleculeIncrementModifyCount(mp);
mp->needsMDRebuild = 1;
__MoleculeUnlock(mp);
- free(bonds_tmp);
- return n;
+ return nbonds;
panic:
__MoleculeUnlock(mp);
return -1; /* Not reached */
}
+/* Delete bonds */
+/* The deleted angles and dihedrals are stored in outRemoval. */
+/* (*outRemoval) is an array of integers, containing:
+ [0..na*3-1]: the angle indices
+ [na*3..na*3+nd*4-1]: the dihedral indices
+ [na*3+nd*4..na*3+nd*4+ni*4-1]: the improper indices
+ *outRemovedPos is an intgroup denoting the positions of the removed angles/dihedrals/impropers.
+ the angle indices are included as they are,
+ the dihedral indices are offset by ATOMS_MAX_NUMBER,
+ the improper indices are offset by ATOMS_MAX_NUMBER*2.
+ Note: the removed bond indices are not returned, because the caller should already know them. */
int
-MoleculeDeleteBonds(Molecule *mp, Int nbonds, const Int *bonds)
+MoleculeDeleteBonds(Molecule *mp, Int *bonds, IntGroup *where, Int **outRemoved, IntGroup **outRemovedPos)
{
- Int i, j, n1, n2, *cp;
+ Int i, j, n1, n2, nw;
+ Int *ip, *jp, na, nd, ni;
+ IntGroup *ag, *dg, *ig;
Atom *ap;
+ IntGroupIterator iter;
- if (mp == NULL || nbonds <= 0)
+ if (mp == NULL)
return 0;
if (mp->noModifyTopology)
return -4; /* Prohibited operation */
__MoleculeLock(mp);
/* Update connects[] */
- for (i = 0; i < nbonds; i++) {
- n1 = bonds[i * 2];
- n2 = bonds[i * 2 + 1];
+ IntGroupIteratorInit(where, &iter);
+ while ((i = IntGroupIteratorNext(&iter)) >= 0) {
+ n1 = mp->bonds[i * 2];
+ n2 = mp->bonds[i * 2 + 1];
ap = ATOM_AT_INDEX(mp->atoms, n1);
- cp = AtomConnects(ap);
- for (j = 0; j < ap->nconnects; j++) {
- if (cp[j] == n2) {
- /* memmove(&ap->connects[j], &ap->connects[j + 1], sizeof(Int) * (ap->nconnects - j - 1));
- ap->nconnects--; */
- AtomDeleteConnectEntry(ap, j);
+ ip = AtomConnectData(&ap->connect);
+ for (j = 0; j < ap->connect.count; j++) {
+ if (ip[j] == n2) {
+ AtomConnectDeleteEntry(&ap->connect, j);
break;
}
}
ap = ATOM_AT_INDEX(mp->atoms, n2);
- cp = AtomConnects(ap);
- for (j = 0; j < ap->nconnects; j++) {
- if (cp[j] == n1) {
- /* memmove(&ap->connects[j], &ap->connects[j + 1], sizeof(Int) * (ap->nconnects - j - 1));
- ap->nconnects--; */
- AtomDeleteConnectEntry(ap, j);
+ ip = AtomConnectData(&ap->connect);
+ for (j = 0; j < ap->connect.count; j++) {
+ if (ip[j] == n1) {
+ AtomConnectDeleteEntry(&ap->connect, j);
break;
}
}
}
+
+ /* Remove bonds, angles, dihedrals, impropers */
+ ag = IntGroupNew();
+ dg = ig = NULL;
+ na = nd = ni = 0;
+
+ nw = IntGroupGetCount(where);
+ jp = (Int *)malloc(sizeof(Int) * nw * 2);
+ j = 0;
+ IntGroupIteratorReset(&iter);
+ while ((i = IntGroupIteratorNext(&iter)) >= 0) {
+ jp[j++] = mp->bonds[i * 2];
+ jp[j++] = mp->bonds[i * 2 + 1];
+ }
+ IntGroupIteratorRelease(&iter);
- /* Remove bonds, angles, dihedrals, impropers */
- {
- IntGroup *bg, *ag, *dg, *ig;
- Int *ip;
-
- bg = IntGroupNew();
- ag = IntGroupNew();
- dg = IntGroupNew();
- ig = IntGroupNew();
- if (bg == NULL || ag == NULL || dg == NULL || ig == NULL)
- goto panic;
- for (i = 0; i < nbonds; i++) {
- n1 = bonds[i * 2];
- n2 = bonds[i * 2 + 1];
- for (j = 0; j < mp->nbonds; j++) {
- ip = mp->bonds + j * 2;
- if ((ip[0] == n1 && ip[1] == n2)
- || (ip[1] == n1 && ip[0] == n2)) {
- if (IntGroupAdd(bg, j, 1) != 0)
- goto panic;
- }
- }
- for (j = 0; j < mp->nangles; j++) {
- ip = mp->angles + j * 3;
- if ((ip[0] == n1 && ip[1] == n2)
- || (ip[1] == n1 && ip[0] == n2)
- || (ip[1] == n1 && ip[2] == n2)
- || (ip[2] == n1 && ip[1] == n2)) {
- if (IntGroupAdd(ag, j, 1) != 0)
- goto panic;
- }
+ for (i = 0, ip = mp->angles; i < mp->nangles; i++, ip += 3) {
+ for (j = 0; j < nw; j++) {
+ n1 = jp[j * 2];
+ n2 = jp[j * 2 + 1];
+ if ((ip[0] == n1 && ip[1] == n2)
+ || (ip[1] == n1 && ip[0] == n2)
+ || (ip[1] == n1 && ip[2] == n2)
+ || (ip[2] == n1 && ip[1] == n2)) {
+ if (IntGroupAdd(ag, i, 1) != 0)
+ goto panic;
+ na++;
+ break;
}
- for (j = 0; j < mp->ndihedrals; j++) {
- ip = mp->dihedrals + j * 4;
- if ((ip[1] == n1 && ip[2] == n2)
- || (ip[2] == n1 && ip[1] == n2)) {
- if (IntGroupAdd(dg, j, 1) != 0)
- goto panic;
- }
+ }
+ }
+ for (i = 0, ip = mp->dihedrals; i < mp->ndihedrals; i++, ip += 4) {
+ for (j = 0; j < nw; j++) {
+ n1 = jp[j * 2];
+ n2 = jp[j * 2 + 1];
+ if ((ip[0] == n1 && ip[1] == n2)
+ || (ip[1] == n1 && ip[0] == n2)
+ || (ip[1] == n1 && ip[2] == n2)
+ || (ip[2] == n1 && ip[1] == n2)
+ || (ip[2] == n1 && ip[3] == n2)
+ || (ip[3] == n1 && ip[2] == n2)) {
+ if (dg == NULL)
+ dg = IntGroupNew();
+ if (IntGroupAdd(dg, i, 1) != 0)
+ goto panic;
+ nd++;
+ break;
}
- for (j = 0; j < mp->nimpropers; j++) {
- ip = mp->impropers + j * 4;
- if ((ip[0] == n1 && ip[2] == n2)
- || (ip[1] == n1 && ip[2] == n2)
- || (ip[3] == n1 && ip[2] == n2)
- || (ip[0] == n2 && ip[2] == n1)
- || (ip[1] == n2 && ip[2] == n1)
- || (ip[3] == n2 && ip[2] == n1)) {
- if (IntGroupAdd(ig, j, 1) != 0)
- goto panic;
- }
+ }
+ }
+ for (i = 0, ip = mp->impropers; i < mp->nimpropers; i++, ip += 4) {
+ for (j = 0; j < nw; j++) {
+ n1 = jp[j * 2];
+ n2 = jp[j * 2 + 1];
+ if ((ip[0] == n1 && ip[2] == n2)
+ || (ip[1] == n1 && ip[2] == n2)
+ || (ip[3] == n1 && ip[2] == n2)
+ || (ip[0] == n2 && ip[2] == n1)
+ || (ip[1] == n2 && ip[2] == n1)
+ || (ip[3] == n2 && ip[2] == n1)) {
+ if (ig == NULL)
+ ig = IntGroupNew();
+ if (IntGroupAdd(ig, i, 1) != 0)
+ goto panic;
+ ni++;
+ break;
}
}
- if (sRemoveElementsFromArrayAtPositions(mp->bonds, mp->nbonds, NULL, sizeof(Int) * 2, bg) != 0)
+ }
+ free(jp);
+
+ if (sRemoveElementsFromArrayAtPositions(mp->bonds, mp->nbonds, bonds, sizeof(Int) * 2, where) != 0)
+ goto panic;
+ mp->nbonds -= IntGroupGetCount(where);
+ if (mp->nbonds == 0) {
+ free(mp->bonds);
+ mp->bonds = NULL;
+ }
+ if (mp->bondOrders != NULL) {
+ if (sRemoveElementsFromArrayAtPositions(mp->bondOrders, mp->nbondOrders, NULL, sizeof(Double), where) != 0)
goto panic;
- mp->nbonds -= IntGroupGetCount(bg);
-
- if (IntGroupGetCount(ag) > 0)
- MoleculeDeleteAngles(mp, NULL, ag);
- if (IntGroupGetCount(dg) > 0)
- MoleculeDeleteDihedrals(mp, NULL, dg);
- if (IntGroupGetCount(ig) > 0)
- MoleculeDeleteImpropers(mp, NULL, ig);
- IntGroupRelease(bg);
- IntGroupRelease(ag);
+ mp->nbondOrders -= IntGroupGetCount(where);
+ if (mp->nbondOrders == 0) {
+ free(mp->bondOrders);
+ mp->bondOrders = NULL;
+ }
+ }
+ if (na == 0 && nd == 0 && ni == 0)
+ ip = NULL;
+ else
+ ip = (Int *)malloc(sizeof(Int) * (na * 3 + nd * 4 + ni * 4));
+ if (na > 0)
+ MoleculeDeleteAngles(mp, ip, ag);
+ if (nd > 0)
+ MoleculeDeleteDihedrals(mp, ip + na * 3, dg);
+ if (ni > 0)
+ MoleculeDeleteImpropers(mp, ip + na * 3 + nd * 4, ig);
+ if (ip != NULL) {
+ IntGroupOffset(dg, ATOMS_MAX_NUMBER);
+ IntGroupOffset(ig, ATOMS_MAX_NUMBER * 2);
+ IntGroupAddIntGroup(ag, dg);
+ IntGroupAddIntGroup(ag, ig);
IntGroupRelease(dg);
IntGroupRelease(ig);
}
+ if (IntGroupGetCount(ag) == 0) {
+ IntGroupRelease(ag);
+ ag = NULL;
+ }
+
+ *outRemoved = ip;
+ *outRemovedPos = ag;
+
MoleculeIncrementModifyCount(mp);
mp->needsMDRebuild = 1;
__MoleculeUnlock(mp);
- return nbonds;
+ return na * 3 + nd * 4 + ni * 4;
panic:
__MoleculeUnlock(mp);
}
int
+MoleculeAssignBondOrders(Molecule *mp, const Double *orders, IntGroup *where)
+{
+ Int i, j;
+ IntGroupIterator iter;
+ if (mp == NULL || orders == NULL || mp->nbonds == 0)
+ return 0;
+ if (mp->noModifyTopology)
+ return -4; /* Prohibited operation */
+ if (mp->bondOrders == NULL) {
+ AssignArray(&mp->bondOrders, &mp->nbondOrders, sizeof(Double), mp->nbonds - 1, NULL);
+ memset(mp->bondOrders, 0, sizeof(Double) * mp->nbondOrders);
+ }
+ IntGroupIteratorInit(where, &iter);
+ j = 0;
+ while ((i = IntGroupIteratorNext(&iter)) >= 0) {
+ if (i >= mp->nbondOrders)
+ break;
+ mp->bondOrders[i] = orders[j++];
+ }
+ IntGroupIteratorRelease(&iter);
+ return 0;
+}
+
+int
+MoleculeGetBondOrders(Molecule *mp, Double *outOrders, IntGroup *where)
+{
+ Int i, j;
+ IntGroupIterator iter;
+ if (mp == NULL || mp->nbonds == 0)
+ return 0;
+ if (mp->bondOrders == NULL) {
+ /* Returns all zero */
+ i = IntGroupGetCount(where);
+ for (j = 0; j < i; j++)
+ outOrders[j] = 0.0;
+ } else {
+ IntGroupIteratorInit(where, &iter);
+ j = 0;
+ while ((i = IntGroupIteratorNext(&iter)) >= 0) {
+ if (i < mp->nbondOrders)
+ outOrders[j] = mp->bondOrders[i];
+ else outOrders[j] = 0.0;
+ j++;
+ }
+ }
+ return 0;
+}
+
+int
MoleculeAddAngles(Molecule *mp, const Int *angles, IntGroup *where)
{
int n1, nc;
__MoleculeLock(mp);
if (sRemoveElementsFromArrayAtPositions(mp->angles, mp->nangles, angles, sizeof(Int) * 3, where) != 0) {
__MoleculeUnlock(mp);
- Panic("Low memory while adding angles");
+ Panic("Bad argument while deleting angles");
}
mp->nangles -= (nc = IntGroupGetCount(where));
+ if (mp->nangles == 0) {
+ free(mp->angles);
+ mp->angles = NULL;
+ }
mp->needsMDRebuild = 1;
__MoleculeUnlock(mp);
return nc;
__MoleculeLock(mp);
if (sRemoveElementsFromArrayAtPositions(mp->dihedrals, mp->ndihedrals, dihedrals, sizeof(Int) * 4, where) != 0) {
__MoleculeUnlock(mp);
- Panic("Low memory while adding dihedrals");
+ Panic("Internal error: bad argument while deleting dihedrals");
}
mp->ndihedrals -= (nc = IntGroupGetCount(where));
+ if (mp->ndihedrals == 0) {
+ free(mp->dihedrals);
+ mp->dihedrals = NULL;
+ }
mp->needsMDRebuild = 1;
__MoleculeUnlock(mp);
return nc;
__MoleculeLock(mp);
if (sRemoveElementsFromArrayAtPositions(mp->impropers, mp->nimpropers, impropers, sizeof(Int) * 4, where) != 0) {
__MoleculeUnlock(mp);
- Panic("Low memory while adding impropers");
+ Panic("Internal error: bad argument while deleting impropers");
}
mp->nimpropers -= (nc = IntGroupGetCount(where));
+ if (mp->impropers == NULL) {
+ free(mp->impropers);
+ mp->impropers = NULL;
+ }
__MoleculeUnlock(mp);
return nc;
}
Atom *rootp[2];
Atom na[2], *nap;
int i, natoms;
+ IntGroup *ig;
if (mp == NULL || mp->noModifyTopology)
return 0;
if (bondIndex < 0 || bondIndex >= mp->nbonds)
nap->type = 0;
nap->charge = nap->weight = 0.0;
nap->atomicNumber = 0;
- nap->nconnects = 0;
+ nap->connect.count = 0;
w = (i == 0 ? 0.4 : -0.4);
VecScaleInc(nap->r, dr, w);
VecZero(nap->v);
dummyIndices[1] = natoms + 1;
/* Remove the old bond and create new bonds */
-/* ig = IntGroupNewWithPoints(bondIndex, 1, -1);
+ ig = IntGroupNewWithPoints(bondIndex, 1, -1);
if (ig == NULL)
goto panic;
- MoleculeDeleteBonds(mp, NULL, ig);
- IntGroupRelease(ig); */
- MoleculeDeleteBonds(mp, 1, roots);
+ MoleculeDeleteBonds(mp, NULL, ig, NULL, NULL);
+ IntGroupRelease(ig);
newBonds[0] = roots[0];
newBonds[1] = dummyIndices[0];
newBonds[2] = roots[1];
newBonds[3] = dummyIndices[1];
newBonds[4] = kInvalidIndex;
- i = (MoleculeAddBonds(mp, 2, newBonds) < 0 ? -1 : 0);
+ i = (MoleculeAddBonds(mp, 2, newBonds, NULL, 1) < 0 ? -1 : 0);
mp->needsMDRebuild = 1;
__MoleculeUnlock(mp);
return i;
nangles = 0;
angles = NULL;
for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
- Int *cp = AtomConnects(ap);
- for (j = 0; j < ap->nconnects; j++) {
+ Int *cp = AtomConnectData(&ap->connect);
+ if (ap->anchor != NULL)
+ continue;
+ for (j = 0; j < ap->connect.count; j++) {
Int j0 = cp[j];
- for (k = j + 1; k < ap->nconnects; k++) {
+ if (ATOM_AT_INDEX(mol->atoms, j0)->anchor != NULL)
+ continue;
+ for (k = j + 1; k < ap->connect.count; k++) {
Int k0 = cp[k];
+ if (ATOM_AT_INDEX(mol->atoms, k0)->anchor != NULL)
+ continue;
if (MoleculeLookupAngle(mol, j0, i, k0) < 0) {
ip = (Int *)AssignArray(&angles, &nangles, sizeof(Int) * 3, nangles, NULL);
ip[0] = j0;
dihedrals = NULL;
for (n2 = 0, ap2 = mol->atoms; n2 < mol->natoms; n2++, ap2 = ATOM_NEXT(ap2)) {
Int i1, i3, i4, *ip;
- cp2 = AtomConnects(ap2);
- for (i3 = 0; i3 < ap2->nconnects; i3++) {
+ if (ap2->anchor != NULL)
+ continue;
+ cp2 = AtomConnectData(&ap2->connect);
+ for (i3 = 0; i3 < ap2->connect.count; i3++) {
n3 = cp2[i3];
if (n2 > n3)
continue;
ap3 = ATOM_AT_INDEX(mol->atoms, n3);
- cp3 = AtomConnects(ap3);
- for (i1 = 0; i1 < ap2->nconnects; i1++) {
+ if (ap3->anchor != NULL)
+ continue;
+ cp3 = AtomConnectData(&ap3->connect);
+ for (i1 = 0; i1 < ap2->connect.count; i1++) {
n1 = cp2[i1];
if (n1 == n3)
continue;
- for (i4 = 0; i4 < ap3->nconnects; i4++) {
+ if (ATOM_AT_INDEX(mol->atoms, n1)->anchor != NULL)
+ continue;
+ for (i4 = 0; i4 < ap3->connect.count; i4++) {
n4 = cp3[i4];
if (n2 == n4 || n1 == n4)
continue;
+ if (ATOM_AT_INDEX(mol->atoms, n4)->anchor != NULL)
+ continue;
if (MoleculeLookupDihedral(mol, n1, n2, n3, n4) < 0) {
ip = (Int *)AssignArray(&dihedrals, &ndihedrals, sizeof(Int) * 4, ndihedrals, NULL);
ip[0] = n1;
for (n3 = 0, ap3 = ap; n3 < mol->natoms; n3++, ap3 = ATOM_NEXT(ap3)) {
Int i1, i2, i4, found, *ip;
t3 = ap3->type;
- cp = AtomConnects(ap3);
- for (i1 = 0; i1 < ap3->nconnects; i1++) {
+ cp = AtomConnectData(&ap3->connect);
+ for (i1 = 0; i1 < ap3->connect.count; i1++) {
n1 = cp[i1];
t1 = ATOM_AT_INDEX(ap, n1)->type;
- for (i2 = i1 + 1; i2 < ap3->nconnects; i2++) {
+ for (i2 = i1 + 1; i2 < ap3->connect.count; i2++) {
n2 = cp[i2];
t2 = ATOM_AT_INDEX(ap, n2)->type;
- for (i4 = i2 + 1; i4 < ap3->nconnects; i4++) {
+ for (i4 = i2 + 1; i4 < ap3->connect.count; i4++) {
n4 = cp[i4];
t4 = ATOM_AT_INDEX(ap, n4)->type;
found = 0;
Atom *ap;
/* If LSB of resSeqs is 1, then a constant value is used for all specified atoms */
- if (((int)resSeqs & 1) == 0) {
+ if (((uintptr_t)resSeqs & 1) == 0) {
withArray = 1;
resSeq = 0;
} else {
withArray = 0;
- resSeq = ((int)resSeqs - 1) / 2;
+ resSeq = ((uintptr_t)resSeqs - 1) / 2;
}
IntGroupIteratorInit(group, &iter);
int
MoleculeChangeResidueNumber(Molecule *mp, IntGroup *group, int resSeq)
{
- return MoleculeChangeResidueNumberWithArray(mp, group, (Int *)(resSeq * 2 + 1));
+ return MoleculeChangeResidueNumberWithArray(mp, group, (Int *)(intptr_t)(resSeq * 2 + 1));
}
/* Offset the residue numbers by a certain amount. The argument nresidues, if non-negative,
}
for (i = 0; i < mp->natoms; i++) {
Int *ip, j;
- ip = AtomConnects(apArray[i]);
- for (j = 0; j < apArray[i]->nconnects; j++, ip++)
+ ip = AtomConnectData(&(apArray[i]->connect));
+ for (j = 0; j < apArray[i]->connect.count; j++, ip++)
*ip = old2new[*ip];
}
free(newAtoms);
free(old2new);
free(apArray);
-
}
/* Renumber atoms */
for (i = 0; i < mp->nimpropers * 4; i++) {
mp->impropers[i] = old2new[mp->impropers[i]];
}
+ /* Renumber the connection table and pi anchor table */
for (i = 0; i < mp->natoms; i++) {
Atom *ap = ATOM_AT_INDEX(saveAtoms, i);
- Int *ip = AtomConnects(ap);
- for (j = 0; j < ap->nconnects; j++, ip++)
+ Int *ip = AtomConnectData(&ap->connect);
+ for (j = 0; j < ap->connect.count; j++, ip++)
*ip = old2new[*ip];
+ if (ap->anchor != NULL) {
+ ip = AtomConnectData(&ap->anchor->connect);
+ for (j = 0; j < ap->anchor->connect.count; j++, ip++)
+ *ip = old2new[*ip];
+ }
}
+
if (mp->par != NULL) {
/* Renumber the parameters */
int n;
for (i = 0; i < mp->natoms; i++)
memmove(ATOM_AT_INDEX(mp->atoms, old2new[i]), ATOM_AT_INDEX(saveAtoms, i), gSizeOfAtomRecord);
retval = 0;
-
+
MoleculeIncrementModifyCount(mp);
mp->needsMDRebuild = 1;
return -1; /* Non-regular transform */
/* Calculate the reciprocal cell parameters */
- cp->rcell[0] = sqrt(cp->rtr[0] * cp->rtr[0] + cp->rtr[1] * cp->rtr[1] + cp->rtr[2] * cp->rtr[2]);
- cp->rcell[1] = sqrt(cp->rtr[3] * cp->rtr[3] + cp->rtr[4] * cp->rtr[4] + cp->rtr[5] * cp->rtr[5]);
- cp->rcell[2] = sqrt(cp->rtr[6] * cp->rtr[6] + cp->rtr[7] * cp->rtr[7] + cp->rtr[8] * cp->rtr[8]);
- cp->rcell[3] = acos((cp->rtr[3] * cp->rtr[6] + cp->rtr[4] * cp->rtr[7] + cp->rtr[5] * cp->rtr[8]) / (cp->rcell[1] * cp->rcell[2])) * kRad2Deg;
- cp->rcell[4] = acos((cp->rtr[6] * cp->rtr[0] + cp->rtr[7] * cp->rtr[1] + cp->rtr[8] * cp->rtr[2]) / (cp->rcell[2] * cp->rcell[0])) * kRad2Deg;
- cp->rcell[5] = acos((cp->rtr[0] * cp->rtr[3] + cp->rtr[1] * cp->rtr[4] + cp->rtr[2] * cp->rtr[5]) / (cp->rcell[0] * cp->rcell[1])) * kRad2Deg;
+ cp->rcell[0] = sqrt(cp->rtr[0] * cp->rtr[0] + cp->rtr[3] * cp->rtr[3] + cp->rtr[6] * cp->rtr[6]);
+ cp->rcell[1] = sqrt(cp->rtr[1] * cp->rtr[1] + cp->rtr[4] * cp->rtr[4] + cp->rtr[7] * cp->rtr[7]);
+ cp->rcell[2] = sqrt(cp->rtr[2] * cp->rtr[2] + cp->rtr[5] * cp->rtr[5] + cp->rtr[8] * cp->rtr[8]);
+ cp->rcell[3] = acos((cp->rtr[1] * cp->rtr[2] + cp->rtr[4] * cp->rtr[5] + cp->rtr[7] * cp->rtr[8]) / (cp->rcell[1] * cp->rcell[2])) * kRad2Deg;
+ cp->rcell[4] = acos((cp->rtr[2] * cp->rtr[0] + cp->rtr[5] * cp->rtr[3] + cp->rtr[8] * cp->rtr[6]) / (cp->rcell[2] * cp->rcell[0])) * kRad2Deg;
+ cp->rcell[5] = acos((cp->rtr[0] * cp->rtr[1] + cp->rtr[3] * cp->rtr[4] + cp->rtr[6] * cp->rtr[7]) / (cp->rcell[0] * cp->rcell[1])) * kRad2Deg;
if (calc_abc) {
/* Calculate a, b, c, alpha, beta, gamma */
cp->cell[4] = acos((cp->tr[6] * cp->tr[0] + cp->tr[7] * cp->tr[1] + cp->tr[8] * cp->tr[2]) / (cp->cell[2] * cp->cell[0])) * kRad2Deg;
cp->cell[5] = acos((cp->tr[0] * cp->tr[3] + cp->tr[1] * cp->tr[4] + cp->tr[2] * cp->tr[5]) / (cp->cell[0] * cp->cell[1])) * kRad2Deg;
}
-
return 0;
}
return;
__MoleculeLock(mp);
memset(&cmat, 0, sizeof(Transform));
+ if (mp->cell != NULL)
+ memmove(&cmat, &(mp->cell->rtr), sizeof(Transform));
+ else
+ memmove(&cmat, &gIdentityTransform, sizeof(Transform));
if (a == 0.0) {
if (mp->cell != NULL) {
- memmove(&cmat, &(mp->cell->tr), sizeof(Transform));
free(mp->cell);
- } else {
- cmat[0] = cmat[4] = cmat[8] = 1.0;
+ mp->needsMDRebuild = 1;
}
mp->cell = NULL;
- /* mp->is_xtal_coord = 0; */
} else {
cp = mp->cell;
if (cp == NULL) {
if (cp == NULL)
Panic("Low memory during setting cell parameters");
mp->cell = cp;
- cmat[0] = cmat[4] = cmat[8] = 1.0;
- } else {
- /* if (mp->is_xtal_coord)
- memmove(&cmat, &(cp->tr), sizeof(Transform)); */
+ mp->needsMDRebuild = 1;
}
- /* mp->is_xtal_coord = 1; */
/* alpha, beta, gamma are in degree */
cp->cell[0] = a;
cp->cell[1] = b;
cp->origin.x = cp->origin.y = cp->origin.z = 0.0;
cp->flags[0] = cp->flags[1] = cp->flags[2] = 1;
MoleculeCalculateCellFromAxes(cp, 0);
- TransformMul(cmat, cp->rtr, cmat);
+ TransformMul(cmat, cp->tr, cmat);
}
/* Update the coordinates (if requested) */
}
MatrixSymDiagonalize(m1, val, axis);
for (u = 0; u < 3; u++) {
+ anp->eigval[u] = val[u];
if (val[u] < 0) {
fprintf(stderr, "Non-positive definite thermal parameters for atom %.4s\n", mp->atoms[n1].aname);
val[u] = 0.001;
__MoleculeUnlock(mp);
}
+/* Set the anisotropic parameter for atom idx according to the symop. If symop is not alive, nothing is done. */
+void
+MoleculeSetAnisoBySymop(Molecule *mp, int idx)
+{
+ Atom *ap, *ap2;
+ Transform t1, t2;
+ if (mp == NULL || idx < 0 || idx >= mp->natoms)
+ return;
+ ap = ATOM_AT_INDEX(mp->atoms, idx);
+ if (!SYMOP_ALIVE(ap->symop))
+ return;
+ ap2 = ATOM_AT_INDEX(mp->atoms, ap->symbase);
+ if (ap2->aniso == NULL) {
+ if (ap->aniso != NULL) {
+ free(ap->aniso);
+ ap->aniso = NULL;
+ }
+ return;
+ }
+ if (ap->aniso == NULL)
+ ap->aniso = (Aniso *)calloc(sizeof(Aniso), 1);
+ if (ap->symop.sym == 0 || ap->symop.sym >= mp->nsyms) {
+ /* Just copy the aniso parameters */
+ memmove(ap->aniso, ap2->aniso, sizeof(Aniso));
+ return;
+ }
+ memmove(t1, SYMMETRY_AT_INDEX(mp->syms, ap->symop.sym), sizeof(Transform));
+ t1[9] = t1[10] = t1[11] = 0.0;
+ memset(t2, 0, sizeof(Transform));
+ t2[0] = ap2->aniso->bij[0];
+ t2[4] = ap2->aniso->bij[1];
+ t2[8] = ap2->aniso->bij[2];
+ t2[1] = t2[3] = ap2->aniso->bij[3];
+ t2[2] = t2[6] = ap2->aniso->bij[4];
+ t2[5] = t2[7] = ap2->aniso->bij[5];
+ TransformMul(t2, t1, t2);
+ TransformInvert(t1, t1);
+ TransformMul(t2, t2, t1);
+ MoleculeSetAniso(mp, idx, 0, t2[0], t2[4], t2[8], t2[1], t2[2], t2[5], (ap2->aniso->has_bsig ? ap2->aniso->bsig : NULL));
+}
+
int
-MoleculeSetPeriodicBox(Molecule *mp, const Vector *ax, const Vector *ay, const Vector *az, const Vector *ao, const char *periodic)
+MoleculeSetPeriodicBox(Molecule *mp, const Vector *ax, const Vector *ay, const Vector *az, const Vector *ao, const char *periodic, int convertCoordinates)
{
static Vector zeroVec = {0, 0, 0};
-/* static Transform identityTransform = {1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}; */
XtalCell b;
- int n;
+ Transform cmat;
+ int i, n;
+ Atom *ap;
if (mp == NULL)
return 0;
+ if (mp->cell != NULL)
+ memmove(&cmat, &(mp->cell->rtr), sizeof(Transform));
+ else
+ memmove(&cmat, &gIdentityTransform, sizeof(Transform));
if (ax == NULL) {
- if (mp->cell != NULL)
+ if (mp->cell != NULL) {
free(mp->cell);
+ mp->needsMDRebuild = 1;
+ }
mp->cell = NULL;
- /* mp->is_xtal_coord = 0; */
return 0;
- }
+ }
memset(&b, 0, sizeof(b));
b.axes[0] = (ax != NULL ? *ax : zeroVec);
b.axes[1] = (ay != NULL ? *ay : zeroVec);
if (MoleculeCalculateCellFromAxes(&b, 1) < 0)
return -1;
__MoleculeLock(mp);
- if (mp->cell != NULL) {
+ if (mp->cell == NULL) {
+ mp->needsMDRebuild = 1;
+ } else {
if (mp->cell->has_sigma) {
/* Keep the sigma */
b.has_sigma = 1;
memmove(b.cellsigma, mp->cell->cellsigma, sizeof(mp->cell->cellsigma));
}
+ if ((b.flags[0] != mp->cell->flags[0]) || (b.flags[1] != mp->cell->flags[1]) || (b.flags[2] != mp->cell->flags[2])) {
+ mp->needsMDRebuild = 1;
+ }
free(mp->cell);
}
mp->cell = (XtalCell *)calloc(sizeof(XtalCell), 1);
if (mp->cell != NULL) {
memmove(mp->cell, &b, sizeof(XtalCell));
+ TransformMul(cmat, b.tr, cmat);
+ /* Update the coordinates (if requested) */
+ if (convertCoordinates) {
+ for (i = 0, ap = mp->atoms; i < mp->natoms; i++, ap = ATOM_NEXT(ap)) {
+ TransformVec(&(ap->r), cmat, &(ap->r));
+ }
+ }
+
+ /* Update the anisotropic parameters */
+ for (i = 0, ap = mp->atoms; i < mp->natoms; i++, ap = ATOM_NEXT(ap)) {
+ Aniso *anp = ap->aniso;
+ if (anp != NULL) {
+ MoleculeSetAniso(mp, i, 0, anp->bij[0], anp->bij[1], anp->bij[2], anp->bij[3], anp->bij[4], anp->bij[5], anp->bsig);
+ }
+ }
n = 0;
} else n = -2; /* Out of memory */
__MoleculeUnlock(mp);
+ sMoleculeNotifyChangeAppearance(mp);
return n;
}
sMoleculeFragmentSub(Molecule *mp, int idx, IntGroup *result, IntGroup *exatoms)
{
Atom *ap;
- Int i, *cp;
+ Int i, *cp, idx2;
if (exatoms != NULL && IntGroupLookup(exatoms, idx, NULL))
return;
IntGroupAdd(result, idx, 1);
ap = ATOM_AT_INDEX(mp->atoms, idx);
- cp = AtomConnects(ap);
- for (i = 0; i < ap->nconnects; i++) {
- int idx2 = cp[i];
+ cp = AtomConnectData(&ap->connect);
+ for (i = 0; i < ap->connect.count; i++) {
+ idx2 = cp[i];
if (IntGroupLookup(result, idx2, NULL))
continue;
+ if (ap->anchor != NULL && ATOM_AT_INDEX(mp->atoms, idx2)->anchor != NULL)
+ continue; /* bond between two pi_anchors is ignored */
sMoleculeFragmentSub(mp, idx2, result, exatoms);
}
+ if (ap->anchor != NULL) {
+ cp = AtomConnectData(&ap->anchor->connect);
+ for (i = 0; i < ap->anchor->connect.count; i++) {
+ idx2 = cp[i];
+ if (IntGroupLookup(result, idx2, NULL))
+ continue;
+ sMoleculeFragmentSub(mp, idx2, result, exatoms);
+ }
+ }
}
/* The molecular fragment (= interconnected atoms) containing the atom n1 and
if (j < 0 || j >= mp->natoms)
return 0; /* Invalid atom group */
ap = ATOM_AT_INDEX(mp->atoms, j);
- cp = AtomConnects(ap);
- for (k = 0; k < ap->nconnects; k++) {
+ cp = AtomConnectData(&ap->connect);
+ for (k = 0; k < ap->connect.count; k++) {
+ if (ap->anchor != NULL && ATOM_AT_INDEX(mp->atoms, cp[k])->anchor != NULL)
+ continue; /* Ignore bond between two pi_anchors */
if (IntGroupLookup(group, cp[k], NULL) == 0) {
bond_count++;
nval1 = j;
return 0; /* Too many bonds */
}
}
+ if (ap->anchor != NULL) {
+ cp = AtomConnectData(&ap->anchor->connect);
+ for (k = 0; k < ap->anchor->connect.count; k++) {
+ if (IntGroupLookup(group, cp[k], NULL) == 0) {
+ bond_count++;
+ nval1 = j;
+ nval2 = cp[k];
+ if (bond_count > 1)
+ return 0; /* Too many bonds */
+ }
+ }
+ }
}
}
if (bond_count == 1) {
int i, j, count, n_new, n_old, natoms, exframes, last_inserted;
Vector *tempv, *vp;
Atom *ap;
+ MolProp *prp;
+ Double *dp;
+
if (mp == NULL || (natoms = mp->natoms) == 0 || (count = IntGroupGetCount(group)) <= 0)
return -1;
/* Expand ap->frames for all atoms */
for (i = 0, ap = mp->atoms; i < mp->natoms; i++, ap = ATOM_NEXT(ap)) {
- if (ap->frames == NULL)
- vp = (Vector *)calloc(sizeof(Vector), n_new);
- else
- vp = (Vector *)realloc(ap->frames, sizeof(Vector) * n_new);
- if (vp == NULL) {
+ Int n = ap->nframes;
+ AssignArray(&ap->frames, &ap->nframes, sizeof(Vector), n_new - 1, NULL);
+ if (ap->frames == NULL) {
__MoleculeUnlock(mp);
return -1;
}
- for (j = ap->nframes; j < n_new; j++)
- vp[j] = ap->r;
- ap->frames = vp;
+ for (j = n; j < n_new; j++)
+ ap->frames[j] = ap->r;
}
- if (mp->cell != NULL && (mp->frame_cells != NULL || inFrameCell != NULL)) {
- vp = mp->frame_cells;
+ if (mp->cell != NULL) {
+ j = mp->nframe_cells;
AssignArray(&mp->frame_cells, &mp->nframe_cells, sizeof(Vector) * 4, n_new - 1, NULL);
- if (vp == NULL) {
- /* Set the first cell parameters */
- mp->frame_cells[0] = mp->cell->axes[0];
- mp->frame_cells[1] = mp->cell->axes[1];
- mp->frame_cells[2] = mp->cell->axes[2];
- mp->frame_cells[3] = mp->cell->origin;
- }
-/* vp = mp->frame_cells;
- if (mp->frame_cells == NULL) {
- vp = (Vector *)calloc(sizeof(Vector), n_new * 4);
- vp[0] = mp->cell->axes[0];
- vp[1] = mp->cell->axes[1];
- vp[2] = mp->cell->axes[2];
- vp[3] = mp->cell->origin;
- } else
- vp = (Vector *)realloc(mp->frame_cells, sizeof(Vector) * 4 * n_new);
- if (vp == NULL) {
+ for (i = j; i < n_new; i++) {
+ /* Set the current cell parameters to the expanded frames */
+ mp->frame_cells[i * 4] = mp->cell->axes[0];
+ mp->frame_cells[i * 4 + 1] = mp->cell->axes[1];
+ mp->frame_cells[i * 4 + 2] = mp->cell->axes[2];
+ mp->frame_cells[i * 4 + 3] = mp->cell->origin;
+ }
+ }
+
+ /* Expand propvals for all properties */
+ for (i = 0, prp = mp->molprops; i < mp->nmolprops; i++, prp++) {
+ dp = (Double *)realloc(prp->propvals, sizeof(Double) * n_new);
+ if (dp == NULL) {
__MoleculeUnlock(mp);
return -1;
}
- mp->frame_cells = vp; */
+ for (j = n_old; j < n_new; j++)
+ dp[j] = 0.0;
+ prp->propvals = dp;
}
/* group = [n0..n1-1, n2..n3-1, ...] */
...
tempv[nl..n_new-1] <- ap[s..s+(n_new-nl-1)], s += n_new-nl
At last, s will become n_old and t will become count. */
- for (i = 0, ap = mp->atoms; i <= mp->natoms; i++, ap = ATOM_NEXT(ap)) {
+ for (i = 0, ap = mp->atoms, prp = mp->molprops; i <= mp->natoms + mp->nmolprops; i++) {
int s, t, ns, ne, mult;
Vector cr;
ne = s = t = 0;
if (i == mp->natoms) {
if (mp->cell == NULL || mp->frame_cells == NULL)
- break;
+ continue;
vp = mp->frame_cells;
mult = 4;
- } else {
+ } else if (i < mp->natoms) {
cr = ap->r;
vp = ap->frames;
mult = 1;
+ } else {
+ dp = prp->propvals;
}
for (j = 0; (ns = IntGroupGetStartPoint(group, j)) >= 0; j++) {
if (ns > ne) {
- memmove(tempv + ne * mult, vp + s * mult, sizeof(Vector) * mult * (ns - ne));
+ if (i <= mp->natoms)
+ memmove(tempv + ne * mult, vp + s * mult, sizeof(Vector) * mult * (ns - ne));
+ else
+ memmove((Double *)tempv + ne, dp + s, sizeof(Double) * (ns - ne));
s += ns - ne;
}
ne = IntGroupGetEndPoint(group, j);
tempv[ns * 4 + 2] = mp->cell->axes[2];
tempv[ns * 4 + 3] = mp->cell->origin;
}
- } else {
+ } else if (i < mp->natoms) {
if (inFrame != NULL)
tempv[ns] = inFrame[natoms * t + i];
else
tempv[ns] = cr;
+ } else {
+ ((Double *)tempv)[ns] = 0.0;
}
t++;
ns++;
}
}
if (n_new > ne) {
- memmove(tempv + ne * mult, vp + s * mult, sizeof(Vector) * mult * (n_new - ne));
+ if (i <= mp->natoms)
+ memmove(tempv + ne * mult, vp + s * mult, sizeof(Vector) * mult * (n_new - ne));
+ else
+ memmove((Double *)tempv + ne, dp + s, sizeof(Double) * (n_new - ne));
s += n_new - ne;
}
if (i < mp->natoms)
ap->nframes = n_new;
- memmove(vp, tempv, sizeof(Vector) * mult * n_new);
+ if (i <= mp->natoms) {
+ memmove(vp, tempv, sizeof(Vector) * mult * n_new);
+ if (i < mp->natoms) {
+ ap->nframes = n_new;
+ ap = ATOM_NEXT(ap);
+ }
+ } else {
+ memmove(dp, (Double *)tempv, sizeof(Double) * n_new);
+ prp++;
+ }
}
free(tempv);
mp->nframes = n_new;
int i, count, n_new, n_old, natoms, nframes, old_count, new_cframe;
Vector *tempv, *vp;
Atom *ap;
+ MolProp *prp;
IntGroup *group, *group2;
if (mp == NULL || (natoms = mp->natoms) == 0 || (count = IntGroupGetCount(inGroup)) <= 0)
tempv[nl..n_old-1] -> ap[s..s+(n_old-nl-1)], s += n_old-nl
At last, s will become n_new and t will become count. */
nframes = 0;
- for (i = 0, ap = mp->atoms; i <= mp->natoms; i++, ap = ATOM_NEXT(ap)) {
+ for (i = 0, ap = mp->atoms, prp = mp->molprops; i <= mp->natoms + mp->nmolprops; i++) {
int s, t, j, ns, ne;
int mult;
/* if i == mp->natoms, mp->frame_cells is handled */
if (i == mp->natoms) {
if (mp->cell == NULL || mp->frame_cells == NULL)
- break;
- mult = 4;
+ continue;
+ mult = 4 * sizeof(Vector);
vp = mp->frame_cells;
old_count = n_old;
- } else {
- mult = 1;
+ } else if (i < mp->natoms) {
+ mult = sizeof(Vector);
vp = ap->frames;
if (vp == NULL) {
- ap->frames = vp = (Vector *)calloc(sizeof(Vector), n_old);
- if (vp == NULL) {
+ NewArray(&ap->frames, &ap->nframes, sizeof(Vector), n_old);
+ if (ap->frames == NULL) {
__MoleculeUnlock(mp);
return -1;
}
+ vp = ap->frames;
}
old_count = ap->nframes;
+ } else {
+ mult = sizeof(Double);
+ vp = (Vector *)prp->propvals;
+ old_count = n_old;
}
/* Copy vp to tempv */
- memset(tempv, 0, sizeof(Vector) * mult * n_old);
- memmove(tempv, vp, sizeof(Vector) * mult * (old_count > n_old ? n_old : old_count));
+ memset(tempv, 0, mult * n_old);
+ memmove(tempv, vp, mult * (old_count > n_old ? n_old : old_count));
ne = ns = s = t = 0;
for (j = 0; ns < n_old && (ns = IntGroupGetStartPoint(group, j)) >= 0; j++) {
if (ns > n_old)
ns = n_old;
if (ns > ne) {
- memmove(vp + s * mult, tempv + ne * mult, sizeof(Vector) * mult * (ns - ne));
+ memmove((char *)vp + s * mult, (char *)tempv + ne * mult, mult * (ns - ne));
s += ns - ne;
}
ne = IntGroupGetEndPoint(group, j);
while (ns < ne) {
if (i < mp->natoms)
outFrame[natoms * t + i] = tempv[ns];
- else if (outFrameCell != NULL) {
- outFrameCell[t * 4] = tempv[ns * 4];
- outFrameCell[t * 4 + 1] = tempv[ns * 4 + 1];
- outFrameCell[t * 4 + 2] = tempv[ns * 4 + 2];
- outFrameCell[t * 4 + 3] = tempv[ns * 4 + 3];
+ else if (i == mp->natoms) {
+ if (outFrameCell != NULL) {
+ outFrameCell[t * 4] = tempv[ns * 4];
+ outFrameCell[t * 4 + 1] = tempv[ns * 4 + 1];
+ outFrameCell[t * 4 + 2] = tempv[ns * 4 + 2];
+ outFrameCell[t * 4 + 3] = tempv[ns * 4 + 3];
+ }
}
t++;
ns++;
}
}
if (n_old > ne) {
- memmove(vp + s * mult, tempv + ne * mult, sizeof(Vector) * mult * (n_old - ne));
+ memmove((char *)vp + s * mult, (char *)tempv + ne * mult, mult * (n_old - ne));
s += n_old - ne;
}
if (i < mp->natoms)
free(ap->frames);
ap->frames = NULL;
ap->nframes = 0;
- } else {
+ } else if (i == mp->natoms) {
free(mp->frame_cells);
mp->frame_cells = NULL;
+ mp->nframe_cells = 0;
+ } else {
+ prp->propvals = (Double *)realloc(prp->propvals, sizeof(Double));
}
} else {
- if (i < mp->natoms)
- ap->frames = (Vector *)realloc(ap->frames, sizeof(Vector) * s);
- else {
+ if (i < mp->natoms) {
+ AssignArray(&ap->frames, &ap->nframes, sizeof(Vector), s - 1, NULL);
+ ap->nframes = s;
+ } else if (i == mp->natoms) {
AssignArray(&mp->frame_cells, &mp->nframe_cells, sizeof(Vector) * 4, s - 1, NULL);
+ mp->nframe_cells = s;
+ } else {
+ prp->propvals = (Double *)realloc(prp->propvals, sizeof(Double) * s);
}
}
+ if (i < mp->natoms) {
+ ap = ATOM_NEXT(ap);
+ } else if (i > mp->natoms) {
+ prp++;
+ }
}
free(tempv);
mp->nframes = nframes;
int
MoleculeSelectFrame(Molecule *mp, int frame, int copyback)
{
- int i, cframe, ok;
+ int i, cframe, nframes, modified;
Atom *ap;
- if (mp == NULL || mp->natoms == 0)
- return -1;
cframe = mp->cframe;
- ok = 0;
+ nframes = MoleculeGetNumberOfFrames(mp);
+ if (frame == -1)
+ frame = mp->cframe;
+ if (mp == NULL || mp->natoms == 0 || frame < 0 || frame >= nframes)
+ return -1;
+ modified = 0;
__MoleculeLock(mp);
for (i = 0, ap = mp->atoms; i < mp->natoms; i++, ap = ATOM_NEXT(ap)) {
if (copyback && cframe >= 0 && cframe < ap->nframes) {
/* Write the current coordinate back to the frame array */
ap->frames[cframe] = ap->r;
}
- if (frame >= 0 && frame < ap->nframes) {
+ if ((frame != cframe || copyback == 0) && frame >= 0 && frame < ap->nframes) {
/* Read the coordinate from the frame array */
ap->r = ap->frames[frame];
- ok = 1;
+ modified = 1;
}
}
vp[3] = mp->cell->origin;
}
/* Set the cell from the frame array */
- MoleculeSetPeriodicBox(mp, &mp->frame_cells[frame * 4], &mp->frame_cells[frame * 4 + 1], &mp->frame_cells[frame * 4 + 2], &mp->frame_cells[frame * 4 + 3], mp->cell->flags);
+ if ((frame != cframe || copyback == 0) && frame >= 0 && frame < mp->nframe_cells) {
+ MoleculeSetPeriodicBox(mp, &mp->frame_cells[frame * 4], &mp->frame_cells[frame * 4 + 1], &mp->frame_cells[frame * 4 + 2], &mp->frame_cells[frame * 4 + 3], mp->cell->flags, 0);
+ modified = 1;
+ MoleculeAmendBySymmetry(mp, NULL, NULL, NULL);
+ }
}
- mp->needsMDCopyCoordinates = 1;
+ mp->cframe = frame;
+ if (modified)
+ mp->needsMDCopyCoordinates = 1;
__MoleculeUnlock(mp);
- if (ok) {
- mp->cframe = frame;
- sMoleculeNotifyChangeAppearance(mp);
- return frame;
- } else return -1;
+ sMoleculeNotifyChangeAppearance(mp);
+ return frame;
+}
+
+/* If molecule is multi-frame, then flush the current information to the frame buffer.
+ Returns the number of frames. */
+int
+MoleculeFlushFrames(Molecule *mp)
+{
+ int nframes = MoleculeGetNumberOfFrames(mp);
+ if (nframes > 1)
+ MoleculeSelectFrame(mp, mp->cframe, 1);
+ return nframes;
+}
+
+int
+MoleculeReorderFrames(Molecule *mp, const Int *old_idx)
+{
+ Int *ip, i, j, n, nframes;
+ Double *dp;
+ Atom *ap;
+ MolProp *prp;
+ if (mp == NULL || old_idx == NULL)
+ return 0;
+ nframes = MoleculeGetNumberOfFrames(mp);
+ MoleculeFlushFrames(mp);
+ ip = (Int *)malloc(sizeof(Int) * nframes);
+ if (ip == NULL)
+ return -1; /* Out of memory */
+ memset(ip, 0, sizeof(Int) * nframes);
+ /* Check the argument */
+ for (i = 0; i < nframes; i++) {
+ j = old_idx[i];
+ if (j < 0 || j >= nframes || ip[j] != 0) {
+ free(ip);
+ return -2; /* Bad argument */
+ }
+ ip[j] = 1;
+ }
+ free(ip);
+ dp = (Double *)malloc(sizeof(Double) * nframes * 12);
+ for (i = 0, ap = mp->atoms, prp = mp->molprops; i <= mp->natoms + mp->nmolprops; i++) {
+ for (j = 0; j < nframes; j++) {
+ n = old_idx[j];
+ if (i < mp->natoms) {
+ ((Vector *)dp)[j] = (n < ap->nframes ? ap->frames[n] : ap->r);
+ } else if (i == mp->natoms) {
+ if (mp->cell != NULL) {
+ if (n < mp->nframe_cells && mp->frame_cells != NULL)
+ memmove(dp + j * 12, mp->frame_cells + n * 4, sizeof(Vector) * 4);
+ else {
+ ((Vector *)dp)[j * 4] = mp->cell->axes[0];
+ ((Vector *)dp)[j * 4] = mp->cell->axes[1];
+ ((Vector *)dp)[j * 4] = mp->cell->axes[2];
+ ((Vector *)dp)[j * 4] = mp->cell->origin;
+ }
+ }
+ } else {
+ dp[j] = prp->propvals[n];
+ }
+ }
+ for (j = 0; j < nframes; j++) {
+ if (i < mp->natoms) {
+ if (ap->nframes <= j)
+ AssignArray(&ap->frames, &ap->nframes, sizeof(Vector), nframes - 1, NULL);
+ ap->frames[j] = ((Vector *)dp)[j];
+ } else if (i == mp->natoms) {
+ if (mp->cell != NULL) {
+ AssignArray(&mp->frame_cells, &mp->nframe_cells, sizeof(Vector) * 4, nframes - 1, NULL);
+ memmove(mp->frame_cells + j * 4, dp + j * 12, sizeof(Vector) * 4);
+ }
+ } else {
+ prp->propvals[j] = dp[j];
+ }
+ }
+ if (i < mp->natoms)
+ ap = ATOM_NEXT(ap);
+ else if (i > mp->natoms)
+ prp++;
+ }
+ free(dp);
+ MoleculeSelectFrame(mp, mp->cframe, 0);
+ return 0;
+}
+
+#pragma mark ====== Molecule Propeties ======
+
+int
+MoleculeCreateProperty(Molecule *mp, const char *name)
+{
+ int i;
+ MolProp *prp;
+ for (i = 0, prp = mp->molprops; i < mp->nmolprops; i++, prp++) {
+ if (strcmp(prp->propname, name) == 0)
+ return -(i + 1);
+ }
+ prp = (MolProp *)calloc(sizeof(MolProp), 1);
+ if (prp == NULL)
+ return -10000;
+ prp->propname = strdup(name);
+ if (prp->propname == NULL)
+ return -10000;
+ i = MoleculeGetNumberOfFrames(mp);
+ prp->propvals = (Double *)calloc(sizeof(Double), i);
+ if (prp->propvals == NULL)
+ return -10000;
+ AssignArray(&mp->molprops, &mp->nmolprops, sizeof(MolProp), mp->nmolprops, prp);
+ free(prp);
+ return mp->nmolprops - 1;
+}
+
+int
+MoleculeLookUpProperty(Molecule *mp, const char *name)
+{
+ int i;
+ MolProp *prp;
+ for (i = 0, prp = mp->molprops; i < mp->nmolprops; i++, prp++) {
+ if (strcmp(prp->propname, name) == 0)
+ return i;
+ }
+ return -1;
+}
+
+int
+MoleculeDeletePropertyAtIndex(Molecule *mp, int idx)
+{
+ if (idx >= 0 && idx < mp->nmolprops) {
+ free(mp->molprops[idx].propname);
+ free(mp->molprops[idx].propvals);
+ DeleteArray(&mp->molprops, &mp->nmolprops, sizeof(MolProp), idx, 1, NULL);
+ return idx;
+ }
+ return -1;
+}
+
+int
+MoleculeSetProperty(Molecule *mp, int idx, IntGroup *ig, const Double *values)
+{
+ IntGroupIterator iter;
+ int i, n, nframes;
+ if (idx < 0 || idx >= mp->nmolprops)
+ return -1;
+ IntGroupIteratorInit(ig, &iter);
+ nframes = MoleculeGetNumberOfFrames(mp);
+ n = 0;
+ while ((i = IntGroupIteratorNext(&iter)) >= 0) {
+ if (i >= nframes)
+ break;
+ mp->molprops[idx].propvals[i] = values[n];
+ n++;
+ }
+ IntGroupIteratorRelease(&iter);
+ return n;
+}
+
+int
+MoleculeGetProperty(Molecule *mp, int idx, IntGroup *ig, Double *outValues)
+{
+ IntGroupIterator iter;
+ int i, n, nframes;
+ if (idx < 0 || idx >= mp->nmolprops)
+ return -1;
+ IntGroupIteratorInit(ig, &iter);
+ nframes = MoleculeGetNumberOfFrames(mp);
+ n = 0;
+ while ((i = IntGroupIteratorNext(&iter)) >= 0) {
+ if (i >= nframes)
+ break;
+ outValues[n] = mp->molprops[idx].propvals[i];
+ n++;
+ }
+ IntGroupIteratorRelease(&iter);
+ return n;
+}
+
+#pragma mark ====== Pi Atoms ======
+
+static inline void
+sMoleculeCalculatePiAnchorPosition(Atom *ap, Atom *atoms)
+{
+ Int *cp, j, n;
+ Atom *ap2;
+ cp = AtomConnectData(&ap->anchor->connect);
+ n = ap->anchor->connect.count;
+ VecZero(ap->r);
+ for (j = 0; j < n; j++) {
+ Double w = ap->anchor->coeffs[j];
+ ap2 = ATOM_AT_INDEX(atoms, cp[j]);
+ VecScaleInc(ap->r, ap2->r, w);
+ }
+}
+
+void
+MoleculeUpdatePiAnchorPositions(Molecule *mol)
+{
+ Int i;
+ Atom *ap;
+ for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
+ if (ap->anchor == NULL)
+ continue;
+ sMoleculeCalculatePiAnchorPosition(ap, mol->atoms);
+ }
+}
+
+void
+MoleculeCalculatePiAnchorPosition(Molecule *mol, int idx)
+{
+ Atom *ap;
+ if (mol == NULL || idx < 0 || idx >= mol->natoms)
+ return;
+ ap = ATOM_AT_INDEX(mol->atoms, idx);
+ if (ap->anchor == NULL)
+ return;
+ sMoleculeCalculatePiAnchorPosition(ap, mol->atoms);
+}
+
+int
+MoleculeSetPiAnchorList(Molecule *mol, Int idx, Int nentries, Int *entries, Double *weights, Int *nUndoActions, struct MolAction ***undoActions)
+{
+ Atom *ap;
+ Int *ip, i, j, n, *np;
+ Double d;
+ if (mol == NULL || idx < 0 || idx >= mol->natoms || nentries <= 1)
+ return -1; /* Invalid argument */
+ if (weights != NULL) {
+ d = 0.0;
+ for (i = 0; i < nentries; i++) {
+ if (weights[i] <= 0.0) {
+ return 10; /* Weights must be positive */
+ }
+ d += weights[i];
+ }
+ d = 1.0 / d;
+ } else d = 1.0 / nentries;
+ ap = ATOM_AT_INDEX(mol->atoms, idx);
+ if (ap->anchor != NULL) {
+ /* Already an anchor: check if bonds/angles/dihedrals have entries related to this anchor */
+ IntGroup *bg, *ag, *dg, *ig;
+ Int *ibuf, ibufsize;
+ MolAction *act;
+ bg = ag = dg = ig = NULL;
+ ip = AtomConnectData(&ap->anchor->connect);
+ for (i = 0; i < ap->anchor->connect.count; i++) {
+ n = ip[i];
+ for (j = 0; j < nentries; j++) {
+ if (n == entries[j])
+ break;
+ }
+ if (j == nentries) {
+ /* This entry will disappear: if any bond/angle/dihedral has idx-n pair, that should be removed. */
+ for (j = 0, np = mol->bonds; j < mol->nbonds; j++, np += 2) {
+ if ((idx == np[0] && n == np[1]) || (idx == np[1] && n == np[0])) {
+ if (bg == NULL)
+ bg = IntGroupNew();
+ IntGroupAdd(bg, j, 1);
+ }
+ }
+ for (j = 0, np = mol->angles; j < mol->nangles; j++, np += 3) {
+ if ((idx == np[0] && n == np[1]) || (idx == np[1] && n == np[2]) ||
+ (idx == np[1] && n == np[0]) || (idx == np[2] && n == np[1])) {
+ if (ag == NULL)
+ ag = IntGroupNew();
+ IntGroupAdd(ag, j, 1);
+ }
+ }
+ for (j = 0, np = mol->dihedrals; j < mol->ndihedrals; j++, np += 4) {
+ if ((idx == np[0] && n == np[1]) || (idx == np[1] && n == np[2]) || (idx == np[2] && n == np[3]) ||
+ (idx == np[1] && n == np[0]) || (idx == np[2] && n == np[1]) || (idx == np[3] && n == np[2])) {
+ if (dg == NULL)
+ dg = IntGroupNew();
+ IntGroupAdd(dg, j, 1);
+ }
+ }
+ for (j = 0, np = mol->impropers; j < mol->nimpropers; j++, np += 4) {
+ if ((idx == np[0] && n == np[2]) || (idx == np[1] && n == np[2]) || (idx == np[3] && n == np[2]) ||
+ (idx == np[2] && n == np[0]) || (idx == np[2] && n == np[1]) || (idx == np[2] && n == np[3])) {
+ if (ig == NULL)
+ ig = IntGroupNew();
+ IntGroupAdd(ig, j, 1);
+ }
+ }
+ }
+ }
+ ibuf = NULL;
+ ibufsize = 0;
+ if (ig != NULL) {
+ /* Delete impropers (with undo info) */
+ i = IntGroupGetCount(ig);
+ AssignArray(&ibuf, &ibufsize, sizeof(Int), i * 4 - 1, NULL);
+ MoleculeDeleteImpropers(mol, ibuf, ig);
+ if (nUndoActions != NULL && undoActions != NULL) {
+ act = MolActionNew(gMolActionAddImpropers, i * 4, ibuf, ig);
+ AssignArray(undoActions, nUndoActions, sizeof(MolAction *), *nUndoActions, &act);
+ }
+ IntGroupRelease(ig);
+ }
+ if (dg != NULL) {
+ /* Delete dihedrals (with undo info) */
+ i = IntGroupGetCount(dg);
+ AssignArray(&ibuf, &ibufsize, sizeof(Int), i * 4 - 1, NULL);
+ MoleculeDeleteDihedrals(mol, ibuf, dg);
+ if (nUndoActions != NULL && undoActions != NULL) {
+ act = MolActionNew(gMolActionAddDihedrals, i * 4, ibuf, dg);
+ AssignArray(undoActions, nUndoActions, sizeof(MolAction *), *nUndoActions, &act);
+ }
+ IntGroupRelease(dg);
+ }
+ if (ag != NULL) {
+ /* Delete angles (with undo info) */
+ i = IntGroupGetCount(ag);
+ AssignArray(&ibuf, &ibufsize, sizeof(Int), i * 3 - 1, NULL);
+ MoleculeDeleteAngles(mol, ibuf, ag);
+ if (nUndoActions != NULL && undoActions != NULL) {
+ act = MolActionNew(gMolActionAddAngles, i * 3, ibuf, ag);
+ AssignArray(undoActions, nUndoActions, sizeof(MolAction *), *nUndoActions, &act);
+ }
+ IntGroupRelease(ag);
+ }
+ if (bg != NULL) {
+ /* Delete bonds (with undo info) */
+ i = IntGroupGetCount(bg);
+ AssignArray(&ibuf, &ibufsize, sizeof(Int), i * 2 - 1, NULL);
+ MoleculeDeleteBonds(mol, ibuf, bg, NULL, NULL);
+ if (nUndoActions != NULL && undoActions != NULL) {
+ act = MolActionNew(gMolActionAddBondsForUndo, i * 2, ibuf, bg);
+ AssignArray(undoActions, nUndoActions, sizeof(MolAction *), *nUndoActions, &act);
+ }
+ IntGroupRelease(bg);
+ }
+ } else {
+ ap->anchor = (PiAnchor *)calloc(sizeof(PiAnchor), 1);
+ }
+ AtomConnectResize(&ap->anchor->connect, nentries);
+ memmove(AtomConnectData(&ap->anchor->connect), entries, sizeof(Int) * nentries);
+ AssignArray(&ap->anchor->coeffs, &ap->anchor->ncoeffs, sizeof(Double), nentries - 1, NULL);
+ if (weights != NULL) {
+ memmove(ap->anchor->coeffs, weights, sizeof(Double) * nentries);
+ for (i = 0; i < nentries; i++)
+ ap->anchor->coeffs[i] *= d; /* Normalize weight */
+ } else {
+ for (i = 0; i < nentries; i++)
+ ap->anchor->coeffs[i] = d;
+ }
+ MoleculeCalculatePiAnchorPosition(mol, idx);
+ return 0;
}
#pragma mark ====== MO calculation ======
/* Calculate an MO value for a single point. */
-/* Index is the MO number (1-based) */
+/* Index is the MO number (1-based); 0 denotes "arbitrary vector" */
/* tmp is an array of (natoms * 4) atoms, and used to store dr and |dr|^2 for each atom. */
static Double
-sCalcMOPoint(const BasisSet *bset, Int index, const Vector *vp, Double *tmp)
+sCalcMOPoint(Molecule *mp, const BasisSet *bset, Int index, const Vector *vp, Double *tmp)
{
ShellInfo *sp;
PrimInfo *pp;
Double val, tval, *cnp, *tmpp, *mobasep, *mop;
Int i, j;
/* Cache dr and |dr|^2 */
- for (i = 0; i < bset->natoms; i++) {
- Vector r = bset->pos[i];
- tmp[i * 4] = r.x = vp->x - r.x;
- tmp[i * 4 + 1] = r.y = vp->y - r.y;
- tmp[i * 4 + 2] = r.z = vp->z - r.z;
+ if (index == 0)
+ index = bset->nmos + 1;
+ for (i = 0; i < mp->natoms; i++) {
+ Vector r;
+ r = ATOM_AT_INDEX(mp->atoms, i)->r;
+ tmp[i * 4] = r.x = (vp->x - r.x) * kAngstrom2Bohr;
+ tmp[i * 4 + 1] = r.y = (vp->y - r.y) * kAngstrom2Bohr;
+ tmp[i * 4 + 2] = r.z = (vp->z - r.z) * kAngstrom2Bohr;
tmp[i * 4 + 3] = r.x * r.x + r.y * r.y + r.z * r.z;
}
/* Iterate over all shells */
val = 0.0;
mobasep = bset->mo + (index - 1) * bset->ncomps;
for (i = 0, sp = bset->shells; i < bset->nshells; i++, sp++) {
- pp = bset->priminfos + sp->p_idx;
+ Double rn;
+ pp = bset->priminfos + sp->p_idx;
cnp = bset->cns + sp->cn_idx;
+ if (sp->a_idx >= mp->natoms)
+ return 0.0; /* This may happen when molecule is edited after setting up MO info */
tmpp = tmp + sp->a_idx * 4;
mop = mobasep + sp->m_idx;
+ if (sp->add_exp == 0)
+ rn = 1.0;
+ else
+ rn = pow(tmpp[3], sp->add_exp * 0.5);
switch (sp->sym) {
case kGTOType_S: {
tval = 0;
for (j = 0; j < sp->nprim; j++) {
- tval += *cnp++ * exp(-pp->A * tmpp[3]);
+ tval += *cnp++ * rn * exp(-pp->A * tmpp[3]);
pp++;
}
val += mop[0] * tval;
Double x, y, z;
x = y = z = 0;
for (j = 0; j < sp->nprim; j++) {
- tval = exp(-pp->A * tmpp[3]);
+ tval = rn * exp(-pp->A * tmpp[3]);
x += *cnp++ * tval;
y += *cnp++ * tval;
z += *cnp++ * tval;
Double t, x, y, z;
t = x = y = z = 0;
for (j = 0; j < sp->nprim; j++) {
- tval = exp(-pp->A * tmpp[3]);
+ tval = rn * exp(-pp->A * tmpp[3]);
t += *cnp++ * tval;
x += *cnp++ * tval;
y += *cnp++ * tval;
Double xx, yy, zz, xy, xz, yz;
xx = yy = zz = xy = xz = yz = 0;
for (j = 0; j < sp->nprim; j++) {
- tval = exp(-pp->A * tmpp[3]);
+ tval = rn * exp(-pp->A * tmpp[3]);
xx += *cnp++ * tval;
yy += *cnp++ * tval;
zz += *cnp++ * tval;
Double d0, d1p, d1n, d2p, d2n;
d0 = d1p = d1n = d2p = d2n = 0;
for (j = 0; j < sp->nprim; j++) {
- tval = exp(-pp->A * tmpp[3]);
+ tval = rn * exp(-pp->A * tmpp[3]);
d0 += *cnp++ * tval;
d1p += *cnp++ * tval;
d1n += *cnp++ * tval;
val += d0 + d1p + d1n + d2p + d2n;
break;
}
+ case kGTOType_F: {
+ Double xxx, yyy, zzz, xyy, xxy, xxz, xzz, yzz, yyz, xyz;
+ xxx = yyy = zzz = xyy = xxy = xxz = xzz = yzz = yyz = xyz = 0;
+ for (j = 0; j < sp->nprim; j++) {
+ tval = rn * exp(-pp->A * tmpp[3]);
+ xxx += *cnp++ * tval;
+ yyy += *cnp++ * tval;
+ zzz += *cnp++ * tval;
+ xyy += *cnp++ * tval;
+ xxy += *cnp++ * tval;
+ xxz += *cnp++ * tval;
+ xzz += *cnp++ * tval;
+ yzz += *cnp++ * tval;
+ yyz += *cnp++ * tval;
+ xyz += *cnp++ * tval;
+ pp++;
+ }
+ xxx *= mop[0] * tmpp[0] * tmpp[0] * tmpp[0];
+ yyy *= mop[1] * tmpp[1] * tmpp[1] * tmpp[1];
+ zzz *= mop[2] * tmpp[2] * tmpp[2] * tmpp[2];
+ xyy *= mop[3] * tmpp[0] * tmpp[1] * tmpp[1];
+ xxy *= mop[4] * tmpp[0] * tmpp[0] * tmpp[1];
+ xxz *= mop[5] * tmpp[0] * tmpp[0] * tmpp[2];
+ xzz *= mop[6] * tmpp[0] * tmpp[2] * tmpp[2];
+ yzz *= mop[7] * tmpp[1] * tmpp[2] * tmpp[2];
+ yyz *= mop[8] * tmpp[1] * tmpp[1] * tmpp[2];
+ xyz *= mop[9] * tmpp[0] * tmpp[1] * tmpp[2];
+ val += xxx + yyy + zzz + xyy + xxy + xxz + xzz + yzz + yyz + xyz;
+ break;
+ }
+ case kGTOType_F7: {
+ Double f0, f1p, f1n, f2p, f2n, f3p, f3n;
+ f0 = f1p = f1n = f2p = f2n = f3p = f3n = 0;
+ for (j = 0; j < sp->nprim; j++) {
+ tval = rn * exp(-pp->A * tmpp[3]);
+ f0 += *cnp++ * tval;
+ f1p += *cnp++ * tval;
+ f1n += *cnp++ * tval;
+ f2p += *cnp++ * tval;
+ f2n += *cnp++ * tval;
+ f3p += *cnp++ * tval;
+ f3n += *cnp++ * tval;
+ pp++;
+ }
+ // F(0): GNC(3,a,n) * (1/2) * (5zzz-3zrr) * r^n * exp(-a*r^2)
+ // F(+1): GNC(3,a,n) * sqrt(3/8) * (5xzz-xrr) * r^n * exp(-a*r^2)
+ // F(-1): GNC(3,a,n) * sqrt(3/8) * (5yzz-yrr) * r^n * exp(-a*r^2)
+ // F(+2): GNC(3,a,n) * sqrt(15/4) * (xxz-yyz) * r^n * exp(-a*r^2)
+ // F(-2): GNC(3,a,n) * sqrt(15) * xyz * r^n * exp(-a*r^2)
+ // F(+3): GNC(3,a,n) * sqrt(5/8) * (xxx-3xyy) * r^n * exp(-a*r^2)
+ // F(-3): GNC(3,a,n) * sqrt(5/8) * (3xxy-yyy) * r^n * exp(-a*r^2)
+ f0 *= mop[0] * tmpp[2] * (5 * tmpp[2] * tmpp[2] - 3 * tmpp[3]);
+ f1p *= mop[1] * tmpp[0] * (5 * tmpp[2] * tmpp[2] - tmpp[3]);
+ f1n *= mop[2] * tmpp[1] * (5 * tmpp[2] * tmpp[2] - tmpp[3]);
+ f2p *= mop[3] * tmpp[2] * (tmpp[0] * tmpp[0] - tmpp[1] * tmpp[1]);
+ f2n *= mop[4] * tmpp[0] * tmpp[1] * tmpp[2];
+ f3p *= mop[5] * tmpp[0] * (tmpp[0] * tmpp[0] - 3 * tmpp[1] * tmpp[1]);
+ f3n *= mop[6] * tmpp[1] * (3 * tmpp[0] * tmpp[0] - tmpp[2] * tmpp[2]);
+ val += f0 + f1p + f1n + f2p + f2n + f3p + f3n;
+ break;
+ }
+ case kGTOType_G: {
+ Double xxxx, yyyy, zzzz, xxxy, xxxz, yyyx, yyyz, zzzx, zzzy, xxyy, xxzz, yyzz, xxyz, yyxz, zzxy;
+ xxxx = yyyy = zzzz = xxxy = xxxz = yyyx = yyyz = zzzx = zzzy = xxyy = xxzz = yyzz = xxyz = yyxz = zzxy = 0;
+ for (j = 0; j < sp->nprim; j++) {
+ tval = rn * exp(-pp->A * tmpp[3]);
+ xxxx += *cnp++ * tval;
+ yyyy += *cnp++ * tval;
+ zzzz += *cnp++ * tval;
+ xxxy += *cnp++ * tval;
+ xxxz += *cnp++ * tval;
+ yyyx += *cnp++ * tval;
+ yyyz += *cnp++ * tval;
+ zzzx += *cnp++ * tval;
+ zzzy += *cnp++ * tval;
+ xxyy += *cnp++ * tval;
+ xxzz += *cnp++ * tval;
+ yyzz += *cnp++ * tval;
+ xxyz += *cnp++ * tval;
+ yyxz += *cnp++ * tval;
+ zzxy += *cnp++ * tval;
+ pp++;
+ }
+ xxxx *= mop[0] * tmpp[0] * tmpp[0] * tmpp[0] * tmpp[0];
+ yyyy *= mop[1] * tmpp[1] * tmpp[1] * tmpp[1] * tmpp[1];
+ zzzz *= mop[2] * tmpp[2] * tmpp[2] * tmpp[2] * tmpp[2];
+ xxxy *= mop[3] * tmpp[0] * tmpp[0] * tmpp[0] * tmpp[1];
+ xxxz *= mop[4] * tmpp[0] * tmpp[0] * tmpp[0] * tmpp[2];
+ yyyx *= mop[5] * tmpp[1] * tmpp[1] * tmpp[1] * tmpp[0];
+ yyyz *= mop[6] * tmpp[1] * tmpp[1] * tmpp[1] * tmpp[2];
+ zzzx *= mop[7] * tmpp[2] * tmpp[2] * tmpp[2] * tmpp[0];
+ zzzy *= mop[8] * tmpp[2] * tmpp[2] * tmpp[2] * tmpp[1];
+ xxyy *= mop[9] * tmpp[0] * tmpp[0] * tmpp[1] * tmpp[1];
+ xxzz *= mop[10] * tmpp[0] * tmpp[0] * tmpp[2] * tmpp[2];
+ yyzz *= mop[11] * tmpp[1] * tmpp[1] * tmpp[2] * tmpp[2];
+ xxyz *= mop[12] * tmpp[0] * tmpp[0] * tmpp[1] * tmpp[2];
+ yyxz *= mop[13] * tmpp[1] * tmpp[1] * tmpp[0] * tmpp[2];
+ zzxy *= mop[14] * tmpp[2] * tmpp[2] * tmpp[0] * tmpp[1];
+ val += xxxx + yyyy + zzzz + xxxy + xxxz + yyyx + yyyz + zzzx + zzzy + xxyy + xxzz + yyzz + xxyz + yyxz + zzxy;
+ break;
+ }
+ case kGTOType_G9: {
+ Double g0, g1p, g1n, g2p, g2n, g3p, g3n, g4p, g4n;
+ Double xx = tmpp[0] * tmpp[0];
+ Double yy = tmpp[1] * tmpp[1];
+ Double zz = tmpp[2] * tmpp[2];
+ Double rr = tmpp[3];
+ g0 = g1p = g1n = g2p = g2n = g3p = g3n = g4p = g4n = 0;
+ for (j = 0; j < sp->nprim; j++) {
+ tval = rn * exp(-pp->A * tmpp[3]);
+ g0 += *cnp++ * tval;
+ g1p += *cnp++ * tval;
+ g1n += *cnp++ * tval;
+ g2p += *cnp++ * tval;
+ g2n += *cnp++ * tval;
+ g3p += *cnp++ * tval;
+ g3n += *cnp++ * tval;
+ g4p += *cnp++ * tval;
+ g4n += *cnp++ * tval;
+ pp++;
+ }
+ // G(0): GNC(4,a,n) * (1/8) * (35zzzz-30zzrr+3rrrr) * r^n * exp(-a*r^2)
+ // G(+1): GNC(4,a,n) * sqrt(5/8) * (7xzzz-3xzrr) * r^n * exp(-a*r^2)
+ // G(-1): GNC(4,a,n) * sqrt(5/8) * (7yzzz-3yzrr) * r^n * exp(-a*r^2)
+ // G(+2): GNC(4,a,n) * sqrt(5/16) * (xx-yy)(7zz-rr) * r^n * exp(-a*r^2)
+ // G(-2): GNC(4,a,n) * sqrt(5/4) * (7xyzz-xyrr) * r^n * exp(-a*r^2)
+ // G(+3): GNC(4,a,n) * sqrt(35/8) * (xxxz-3xyyz) * r^n * exp(-a*r^2)
+ // G(-3): GNC(4,a,n) * sqrt(35/8) * (3xxyz-yyyz) * r^n * exp(-a*r^2)
+ // G(+4): GNC(4,a,n) * sqrt(35/64) * (xxxx-6xxyy+yyyy) * r^n * exp(-a*r^2)
+ // G(-4): GNC(4,a,n) * sqrt(35/4) * (xxxy-xyyy) * r^n * exp(-a*r^2)
+ g0 *= mop[0] * (35 * zz * zz - 30 * zz * rr + 3 * rr * rr);
+ g1p *= mop[1] * tmpp[0] * tmpp[2] * (7 * zz - 3 * rr);
+ g1n *= mop[2] * tmpp[1] * tmpp[2] * (7 * zz - 3 * rr);
+ g2p *= mop[3] * (xx - yy) * (7 * zz - rr);
+ g2n *= mop[4] * tmpp[0] * tmpp[1] * (7 * zz - rr);
+ g3p *= mop[5] * tmpp[0] * tmpp[2] * (xx - 3 * yy);
+ g3n *= mop[6] * tmpp[1] * tmpp[2] * (3 * xx - yy);
+ g4p *= mop[7] * (xx * xx - 6 * xx * yy + yy * yy);
+ g4n *= mop[8] * tmpp[0] * tmpp[1] * (xx - yy);
+ val += g0 + g1p + g1n + g2p + g2n + g3p + g3n + g4p + g4n;
+ break;
+ }
}
}
return val;
}
-/* Calculate one MO. The input vectors should be in bohr unit (angstrom * 1.889725989 = kAngstrom2Bohr). */
-/* mono is the MO number (1-based) */
+/* Calculate one MO. The input vectors are angstrom unit (changed from bohr unit: 20140520) */
+/* mono is the MO number (1-based); 0 denotes "arbitrary vector" */
int
MoleculeCalcMO(Molecule *mp, Int mono, const Vector *op, const Vector *dxp, const Vector *dyp, const Vector *dzp, Int nx, Int ny, Int nz, int (*callback)(double progress, void *ref), void *ref)
{
if (sSetupGaussianCoefficients(mp->bset) != 0)
return -1;
}
+ if (mp->bset->natoms_bs > mp->natoms)
+ return -3; /* Number of atoms is smaller than expected (internal error) */
+
cp = (Cube *)calloc(sizeof(Cube), 1);
if (cp == NULL) {
return -1;
cp->nz = nz;
/* TODO: use multithread */
- tmp = (Double *)calloc(sizeof(Double), mp->bset->natoms * 4);
+ tmp = (Double *)calloc(sizeof(Double), mp->bset->natoms_bs * 4);
if (tmp == NULL) {
free(cp->dp);
free(cp);
p.x = op->x + dxp->x * ix + dyp->x * iy + dzp->x * iz;
p.y = op->y + dxp->y * ix + dyp->y * iy + dzp->y * iz;
p.z = op->z + dxp->z * ix + dyp->z * iy + dzp->z * iz;
- cp->dp[n++] = sCalcMOPoint(mp->bset, mono, &p, tmp);
+ cp->dp[n++] = sCalcMOPoint(mp, mp->bset, mono, &p, tmp);
}
if (callback != NULL && n - nn > 100) {
nn = n;
return mp->bset->ncubes - 1;
}
+/* Output values are in angstrom unit (changed from bohr unit: 20140520) */
int
MoleculeGetDefaultMOGrid(Molecule *mp, Int npoints, Vector *op, Vector *xp, Vector *yp, Vector *zp, Int *nx, Int *ny, Int *nz)
{
int i;
- Vector rmin, rmax, *vp;
+ Vector rmin, rmax, r;
Double dr, dx, dy, dz;
- if (mp == NULL || mp->bset == NULL || mp->bset->natoms == 0)
+ Atom *ap;
+ if (mp == NULL || mp->bset == NULL)
return -1;
if (npoints <= 0)
npoints = 1000000;
rmin.x = rmin.y = rmin.z = 1e10;
rmax.x = rmax.y = rmax.z = -1e10;
- for (i = 0, vp = mp->bset->pos; i < mp->bset->natoms; i++, vp++) {
- dr = RadiusForAtomicNumber(ATOM_AT_INDEX(mp->atoms, i)->atomicNumber);
+ for (i = 0, ap = mp->atoms; i < mp->natoms; i++, ap = ATOM_NEXT(ap)) {
+ dr = RadiusForAtomicNumber(ap->atomicNumber);
+ r = ap->r;
if (dr == 0.0)
dr = 1.0;
- dr = dr * kAngstrom2Bohr * 3.0 + 2.0;
- if (rmin.x > vp->x - dr)
- rmin.x = vp->x - dr;
- if (rmin.y > vp->y - dr)
- rmin.y = vp->y - dr;
- if (rmin.z > vp->z - dr)
- rmin.z = vp->z - dr;
- if (rmax.x < vp->x + dr)
- rmax.x = vp->x + dr;
- if (rmax.y < vp->y + dr)
- rmax.y = vp->y + dr;
- if (rmax.z < vp->z + dr)
- rmax.z = vp->z + dr;
+ dr = dr * 3.0 + 2.0;
+ if (rmin.x > r.x - dr)
+ rmin.x = r.x - dr;
+ if (rmin.y > r.y - dr)
+ rmin.y = r.y - dr;
+ if (rmin.z > r.z - dr)
+ rmin.z = r.z - dr;
+ if (rmax.x < r.x + dr)
+ rmax.x = r.x + dr;
+ if (rmax.y < r.y + dr)
+ rmax.y = r.y + dr;
+ if (rmax.z < r.z + dr)
+ rmax.z = r.z + dr;
}
dx = rmax.x - rmin.x;
dy = rmax.y - rmin.y;
fprintf(fp, "%s MO=%d\n", comment, cp->idn);
fprintf(fp, " MO coefficients\n");
- fprintf(fp, "%5d %11.6f %11.6f %11.6f\n", -(mp->bset->natoms), cp->origin.x, cp->origin.y, cp->origin.z);
- fprintf(fp, "%5d %11.6f %11.6f %11.6f\n", cp->nx, cp->dx.x, cp->dx.y, cp->dx.z);
- fprintf(fp, "%5d %11.6f %11.6f %11.6f\n", cp->ny, cp->dy.x, cp->dy.y, cp->dy.z);
- fprintf(fp, "%5d %11.6f %11.6f %11.6f\n", cp->nz, cp->dz.x, cp->dz.y, cp->dz.z);
+ fprintf(fp, "%5d %11.6f %11.6f %11.6f\n", -(mp->bset->natoms_bs),
+ cp->origin.x * kAngstrom2Bohr, cp->origin.y * kAngstrom2Bohr, cp->origin.z * kAngstrom2Bohr);
+ fprintf(fp, "%5d %11.6f %11.6f %11.6f\n", cp->nx,
+ cp->dx.x * kAngstrom2Bohr, cp->dx.y * kAngstrom2Bohr, cp->dx.z * kAngstrom2Bohr);
+ fprintf(fp, "%5d %11.6f %11.6f %11.6f\n", cp->ny,
+ cp->dy.x * kAngstrom2Bohr, cp->dy.y * kAngstrom2Bohr, cp->dy.z * kAngstrom2Bohr);
+ fprintf(fp, "%5d %11.6f %11.6f %11.6f\n", cp->nz,
+ cp->dz.x * kAngstrom2Bohr, cp->dz.y * kAngstrom2Bohr, cp->dz.z * kAngstrom2Bohr);
/* Atomic information */
- for (i = 0; i < mp->bset->natoms; i++) {
- Vector *vp = mp->bset->pos + i;
+ for (i = 0; i < mp->natoms; i++) {
Atom *ap = ATOM_AT_INDEX(mp->atoms, i);
/* The second number should actually be the effective charge */
- fprintf(fp, "%5d %11.6f %11.6f %11.6f %11.6f\n", ap->atomicNumber, (double)ap->atomicNumber, vp->x, vp->y, vp->z);
+ fprintf(fp, "%5d %11.6f %11.6f %11.6f %11.6f\n", ap->atomicNumber, (double)ap->atomicNumber,
+ ap->r.x * kAngstrom2Bohr, ap->r.y * kAngstrom2Bohr, ap->r.z * kAngstrom2Bohr);
}
fprintf(fp, "%5d%5d\n", 1, 1);
for (i = n = 0; i < cp->nx; i++) {
for (j = 0; j < cp->ny; j++) {
for (k = 0; k < cp->nz; k++) {
- fprintf(fp, " %12.5e", cp->dp[n++]);
+ /* On Windows, the "%e" format writes the exponent in 3 digits, but
+ this is not standard. So we avoid using %e */
+ Double d = cp->dp[n++];
+ int exponent;
+ Double base;
+ if (d >= -1.0e-90 && d <= 1.0e-90) {
+ exponent = 0;
+ base = 0.0;
+ } else {
+ exponent = (int)floor(log10(fabs(d)));
+ base = d * pow(10, -1.0 * exponent);
+ }
+ fprintf(fp, " %8.5fe%+03d", base, exponent);
+ /* fprintf(fp, " %12.5e", d); */
if (k == cp->nz - 1 || k % 6 == 5)
fprintf(fp, "\n");
}
fclose(fp);
return 0;
}
+
+#pragma mark ====== Marching Cube (for isosurface) ======
+
+MCube *
+MoleculeClearMCube(Molecule *mol, Int nx, Int ny, Int nz, const Vector *origin, Double dx, Double dy, Double dz)
+{
+ MCube *mc = mol->mcube;
+ int i;
+ float rgba[8] = { 1, 1, 1, 0.6, 0, 0, 1, 0.6 };
+ if (mc != NULL) {
+ free(mc->dp);
+ free(mc->radii);
+ free(mc->c[0].fp);
+ free(mc->c[0].cubepoints);
+ free(mc->c[0].triangles);
+ free(mc->c[1].fp);
+ free(mc->c[1].cubepoints);
+ free(mc->c[1].triangles);
+ memmove(rgba, mc->c[0].rgba, sizeof(float) * 4);
+ memmove(rgba + 4, mc->c[1].rgba, sizeof(float) * 4);
+ free(mc);
+ mol->mcube = NULL;
+ }
+ if (nx > 0 && ny > 0 && nz > 0) {
+ mc = (MCube *)calloc(sizeof(MCube), 1);
+ mc->idn = -1;
+ /* round up to nearest 4N+1 integer */
+ dx *= nx;
+ dy *= ny;
+ dz *= nz;
+ mc->nx = (nx + 2) / 4 * 4 + 1;
+ mc->ny = (ny + 2) / 4 * 4 + 1;
+ mc->nz = (nz + 2) / 4 * 4 + 1;
+ mc->dx = dx / mc->nx;
+ mc->dy = dy / mc->ny;
+ mc->dz = dz / mc->nz;
+ mc->origin = *origin;
+ mc->dp = (Double *)malloc(sizeof(Double) * mc->nx * mc->ny * mc->nz);
+ if (mc->dp == NULL) {
+ free(mc);
+ return NULL;
+ }
+ mc->radii = (Double *)calloc(sizeof(Double), mol->natoms);
+ if (mc->radii == NULL) {
+ free(mc->dp);
+ free(mc);
+ return NULL;
+ }
+ mc->nradii = mol->natoms;
+ mc->c[0].fp = (unsigned char *)calloc(sizeof(unsigned char), mc->nx * mc->ny * mc->nz);
+ mc->c[1].fp = (unsigned char *)calloc(sizeof(unsigned char), mc->nx * mc->ny * mc->nz);
+ if (mc->c[0].fp == NULL || mc->c[1].fp == NULL) {
+ free(mc->c[0].fp);
+ free(mc->c[1].fp);
+ free(mc->dp);
+ free(mc->radii);
+ free(mc);
+ return NULL;
+ }
+ for (i = 0; i < mc->nx * mc->ny * mc->nz; i++) {
+ mc->dp[i] = DBL_MAX;
+ }
+ memmove(mc->c[0].rgba, rgba, sizeof(float) * 4);
+ memmove(mc->c[1].rgba, rgba + 4, sizeof(float) * 4);
+ mol->mcube = mc;
+ }
+ MoleculeCallback_notifyModification(mol, 0);
+ return mol->mcube;
+}
+
+static int sMarchingCubeTable[256][16] = {
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
+ {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
+ {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
+ {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
+ {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
+ {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
+ {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
+ {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
+ {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
+ {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
+ {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
+ {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
+ {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
+ {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
+ {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
+ {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
+ {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
+ {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
+ {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
+ {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
+ {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
+ {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
+ {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
+ {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
+ {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
+ {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
+ {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
+ {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
+ {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
+ {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
+ {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
+ {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
+ {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
+ {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
+ {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
+ {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
+ {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
+ {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
+ {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
+ {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
+ {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
+ {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
+ {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
+ {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
+ {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
+ {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
+ {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
+ {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
+ {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
+ {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
+ {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
+ {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
+ {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
+ {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
+ {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
+ {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
+ {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
+ {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
+ {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
+ {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
+ {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
+ {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
+ {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
+ {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
+ {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
+ {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
+ {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
+ {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
+ {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
+ {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
+ {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
+ {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
+ {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
+ {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
+ {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
+ {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
+ {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
+ {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
+ {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
+ {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
+ {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
+ {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
+ {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
+ {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
+ {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
+ {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
+ {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
+ {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
+ {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
+ {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
+ {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
+ {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
+ {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
+ {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
+ {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
+ {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
+ {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
+ {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
+ {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
+ {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
+ {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
+ {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
+ {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
+ {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
+ {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
+ {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
+ {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
+ {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
+ {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
+ {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
+ {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
+ {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
+ {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
+ {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
+ {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
+ {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
+ {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
+ {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
+ {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
+ {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
+ {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
+ {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
+ {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
+ {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
+ {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
+ {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
+ {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
+ {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
+ {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
+ {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
+ {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
+ {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
+ {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
+ {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
+ {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
+ {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
+ {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
+ {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
+ {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
+ {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
+ {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
+ {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
+ {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
+ {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
+ {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
+ {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
+ {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
+ {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
+ {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
+ {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
+ {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
+ {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
+};
+
+/* Recalculate the MCube */
+/* If idn < 0, then the current grid settings and values are unchanged, and */
+/* only the marching cubes are regenerated. */
+int
+MoleculeUpdateMCube(Molecule *mol, int idn)
+{
+ Int retval, step, sn;
+ Int n, ix, iy, iz, nx, ny, nz;
+ Int nn, iix, iiy, iiz;
+ Int ncubepoints, c1, c2, c3;
+ Int *ip;
+ Double thres, *tmp, dd;
+ Vector p;
+ MCube *mc;
+ MCubePoint *mcp;
+ Atom *ap;
+
+ if (mol == NULL || mol->bset == NULL || mol->mcube == NULL)
+ return -1;
+ if (mol->bset->cns == NULL) {
+ if (sSetupGaussianCoefficients(mol->bset) != 0)
+ return -1;
+ }
+ if (mol->bset->natoms_bs > mol->natoms)
+ return -1; /* Number of atoms is smaller than expected */
+
+ mc = mol->mcube;
+ if (idn >= 0) {
+ ShellInfo *sp;
+ Double *mobasep, *mop, mopmax;
+ Double xmin, xmax, ymin, ymax, zmin, zmax;
+ /* Clear mcube values */
+ for (ix = 0; ix < mc->nx * mc->ny * mc->nz; ix++) {
+ mc->dp[ix] = DBL_MAX;
+ mc->c[0].fp[ix] = 0;
+ mc->c[1].fp[ix] = 0;
+ }
+ mc->idn = idn;
+ /* Estimate the orbital sizes */
+ mc->radii = (Double *)realloc(mc->radii, sizeof(Double) * mol->natoms);
+ if (mc->radii == NULL)
+ return -2; /* Out of memory */
+ mc->nradii = mol->natoms;
+ if (mc->idn == mol->bset->nmos + 1) {
+ /* Total electron density */
+ for (ix = 0; ix < mol->natoms; ix++)
+ mc->radii[ix] = 1.0;
+ mopmax = 1.0;
+ } else {
+ memset(mc->radii, 0, sizeof(Double) * mc->nradii);
+ mobasep = mol->bset->mo + (mc->idn == 0 ? mol->bset->nmos : mc->idn - 1) * mol->bset->ncomps;
+ mopmax = 0.0;
+ for (ix = 0, sp = mol->bset->shells; ix < mol->bset->nshells; ix++, sp++) {
+ if (sp->a_idx >= mol->natoms)
+ continue; /* This may happen when molecule is edited after setting up MO info */
+ mop = mobasep + sp->m_idx;
+ for (iy = 0; iy < sp->ncomp; iy++) {
+ dd = fabs(mop[iy]);
+ if (dd > mc->radii[sp->a_idx])
+ mc->radii[sp->a_idx] = dd;
+ if (dd > mopmax)
+ mopmax = dd;
+ }
+ }
+ }
+ xmin = ymin = zmin = 1e10;
+ xmax = ymax = zmax = -1e10;
+ for (ix = 0, ap = mol->atoms; ix < mol->natoms; ix++, ap = ATOM_NEXT(ap)) {
+ dd = RadiusForAtomicNumber(ap->atomicNumber);
+ dd = (dd * 2.0 + 1.0) * (mc->radii[ix] / mopmax) * (mc->expand > 0.0 ? mc->expand : 1.0);
+ mc->radii[ix] = dd;
+ p = ap->r;
+ dd += 0.1;
+ if (p.x - dd < xmin)
+ xmin = p.x - dd;
+ if (p.y - dd < ymin)
+ ymin = p.y - dd;
+ if (p.z - dd < zmin)
+ zmin = p.z - dd;
+ if (p.x + dd > xmax)
+ xmax = p.x + dd;
+ if (p.y + dd > ymax)
+ ymax = p.y + dd;
+ if (p.z + dd > zmax)
+ zmax = p.z + dd;
+ }
+ mc->origin.x = xmin;
+ mc->origin.y = ymin;
+ mc->origin.z = zmin;
+ mc->dx = (xmax - xmin) / mc->nx;
+ mc->dy = (ymax - ymin) / mc->ny;
+ mc->dz = (zmax - zmin) / mc->nz;
+ }
+
+ /* Temporary work area */
+ tmp = (Double *)calloc(sizeof(Double), mol->bset->natoms_bs * 4);
+ if (tmp == NULL)
+ return -2;
+
+ /* TODO: use multithread */
+ nx = mc->nx;
+ ny = mc->ny;
+ nz = mc->nz;
+ step = 4;
+
+#if 1
+ /* Calculate points within certain distances from atoms */
+ for (nn = 0, ap = mol->atoms; nn < mol->natoms; nn++, ap = ATOM_NEXT(ap)) {
+ /* dd = RadiusForAtomicNumber(ap->atomicNumber);
+ if (dd == 0.0)
+ dd = 1.0;
+ dd = dd * 1.5 + 1.0; */
+ dd = mc->radii[nn];
+ p.x = ap->r.x - dd - mc->origin.x;
+ p.y = ap->r.y - dd - mc->origin.y;
+ p.z = ap->r.z - dd - mc->origin.z;
+ c1 = p.x / mc->dx;
+ c2 = p.y / mc->dy;
+ c3 = p.z / mc->dz;
+ iix = c1 + ceil(dd * 2.0 / mc->dx);
+ iiy = c2 + ceil(dd * 2.0 / mc->dy);
+ iiz = c3 + ceil(dd * 2.0 / mc->dz);
+ if (c1 < 0)
+ c1 = 0;
+ if (c2 < 0)
+ c2 = 0;
+ if (c3 < 0)
+ c3 = 0;
+ if (iix >= nx)
+ iix = nx - 1;
+ if (iiy >= ny)
+ iiy = ny - 1;
+ if (iiz >= nz)
+ iiz = nz - 1;
+ for (ix = c1; ix <= iix; ix++) {
+ p.x = mc->origin.x + mc->dx * ix;
+ for (iy = c2; iy <= iiy; iy++) {
+ p.y = mc->origin.y + mc->dy * iy;
+ for (iz = c3; iz <= iiz; iz++) {
+ n = (ix * ny + iy) * nz + iz;
+ if (mc->dp[n] == DBL_MAX) {
+ p.z = mc->origin.z + mc->dz * iz;
+ if (mc->idn == mol->bset->nmos + 1) {
+ /* Total electron density */
+ Int ne_alpha, ne_beta;
+ mc->dp[n] = 0.0;
+ ne_alpha = mol->bset->ne_alpha;
+ ne_beta = mol->bset->ne_beta;
+ if (mol->bset->rflag == 2 && ne_alpha < ne_beta) {
+ /* ROHF case: ensure ne_alpha >= ne_beta */
+ ne_beta = ne_alpha;
+ ne_alpha = mol->bset->ne_beta;
+ }
+ for (sn = 1; sn <= ne_alpha; sn++) {
+ dd = sCalcMOPoint(mol, mol->bset, sn, &p, tmp);
+ dd = dd * dd;
+ if (mol->bset->rflag != 0 && sn <= ne_beta)
+ dd *= 2;
+ mc->dp[n] += dd;
+ }
+ if (mol->bset->rflag == 0) {
+ for (sn = 1; sn <= ne_beta; sn++) {
+ dd = sCalcMOPoint(mol, mol->bset, sn + mol->bset->ncomps, &p, tmp);
+ mc->dp[n] += dd * dd;
+ }
+ }
+ } else {
+ mc->dp[n] = sCalcMOPoint(mol, mol->bset, mc->idn, &p, tmp);
+ }
+ }
+ }
+ }
+ }
+ }
+
+#else
+ /* (i * step, j * step, k * step) */
+ for (ix = 0; ix < nx; ix += step) {
+ for (iy = 0; iy < ny; iy += step) {
+ for (iz = 0; iz < nz; iz += step) {
+ n = (ix * ny + iy) * nz + iz;
+ if (mc->dp[n] == DBL_MAX) {
+ p.x = mc->origin.x + mc->dx * ix;
+ p.y = mc->origin.y + mc->dy * iy;
+ p.z = mc->origin.z + mc->dz * iz;
+ mc->dp[n] = sCalcMOPoint(mol, mol->bset, mc->idn, &p, tmp);
+ }
+ n += step;
+ }
+ }
+ }
+
+ /* Intermediate points */
+ for (step = 4; step > 1; step /= 2) {
+ hstep = step / 2;
+ for (sn = 0; sn <= 1; sn++) {
+ n = 0;
+ for (ix = 0; ix < nx - 1; ix += step) {
+ for (iy = 0; iy < ny - 1; iy += step) {
+ for (iz = 0; iz < nz - 1; iz += step) {
+ flags = 0;
+ thres = mc->thres * (sn == 0 ? 1 : -1);
+ n = (ix * ny + iy) * nz + iz;
+ if (mc->dp[n] == DBL_MAX || mc->dp[n + step * (nz * (ny + 1) + 1)] == DBL_MAX)
+ continue;
+ /* (ix, iy, iz) */
+ if (mc->dp[n] >= thres)
+ flags |= 1;
+ /* (ix + step, iy, iz) */
+ if (mc->dp[n + step * ny * nz] >= thres)
+ flags |= 2;
+ /* (ix, iy + step, iz) */
+ if (mc->dp[n + step * nz] >= thres)
+ flags |= 4;
+ /* (ix + 4, iy + step, iz) */
+ if (mc->dp[n + step * nz * (ny + 1)] >= thres)
+ flags |= 8;
+ /* (ix, iy, iz + step) */
+ if (mc->dp[n + step] >= thres)
+ flags |= 16;
+ if (mc->dp[n + step * (ny * nz + 1)] >= thres)
+ flags |= 32;
+ /* (ix, iy + step, iz + step) */
+ if (mc->dp[n + step * (nz + 1)] >= thres)
+ flags |= 64;
+ /* (ix + step, iy + step, iz + step) */
+ if (mc->dp[n + step * (nz * (ny + 1) + 1)] >= thres)
+ flags |= 128;
+ if (flags != 0 && flags != 255) {
+ /* Calc the intermediate points */
+ for (iix = 0; iix <= step; iix += hstep) {
+ for (iiy = 0; iiy <= step; iiy += hstep) {
+ for (iiz = 0; iiz <= step; iiz += hstep) {
+ if (iix % step == 0 && iiy % step == 0 && iiz % step == 0)
+ continue;
+ nn = n + (iix * ny + iiy) * nz + iiz;
+ if (mc->dp[nn] == DBL_MAX) {
+ p.x = mc->origin.x + mc->dx * (ix + iix);
+ p.y = mc->origin.y + mc->dy * (iy + iiy);
+ p.z = mc->origin.z + mc->dz * (iz + iiz);
+ mc->dp[nn] = sCalcMOPoint(mol, mol->bset, mc->idn, &p, tmp);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+#endif
+
+ free(tmp);
+
+ /* Calculate vertex positions and normal vectors */
+ for (sn = 0; sn <= 1; sn++) {
+ n = 0;
+ thres = mc->thres * (sn == 0 ? 1 : -1);
+ VecZero(p);
+ for (ix = 0; ix < nx - 1; ix++) {
+ for (iy = 0; iy < ny - 1; iy++) {
+ for (iz = 0; iz < nz - 1; iz++) {
+ Double dd0, dd1;
+ nn = (ix * ny + iy) * nz + iz;
+ dd0 = mc->dp[nn];
+ if (dd0 == DBL_MAX)
+ continue;
+ if (0) {
+ dd1 = mc->dp[nn + ny * nz];
+ if (dd1 != DBL_MAX)
+ p.x = (dd1 - dd0) / mc->dx;
+ else if (ix > 0 && (dd1 = mc->dp[nn - ny * nz]) != DBL_MAX)
+ p.x = (dd0 - dd1) / mc->dx;
+ else continue; /* Cannot define gradient */
+ dd1 = mc->dp[nn + nz];
+ if (dd1 != DBL_MAX)
+ p.y = (dd1 - dd0) / mc->dy;
+ else if (iy > 0 && (dd1 = mc->dp[nn - nz]) != DBL_MAX)
+ p.y = (dd0 - dd1) / mc->dy;
+ else continue;
+ dd1 = mc->dp[nn + 1];
+ if (dd1 != DBL_MAX)
+ p.z = (dd1 - dd0) / mc->dz;
+ else if (iz > 0 && (dd1 = mc->dp[nn - 1]) != DBL_MAX)
+ p.z = (dd0 - dd1) / mc->dz;
+ else continue;
+ NormalizeVec(&p, &p);
+ }
+ if (n + 3 >= mc->c[sn].ncubepoints) {
+ /* Expand cubepoints[] array */
+ mc->c[sn].cubepoints = (MCubePoint *)realloc(mc->c[sn].cubepoints, sizeof(MCubePoint) * (mc->c[sn].ncubepoints + 8192));
+ if (mc->c[sn].cubepoints == NULL) {
+ mc->c[sn].ncubepoints = 0;
+ retval = -3;
+ goto end;
+ }
+ mc->c[sn].ncubepoints += 8192;
+ }
+ mcp = mc->c[sn].cubepoints + n;
+ iix = (dd0 >= thres ? 1 : -1);
+ /* (x, y, z)->(x + 1, y, z) */
+ dd1 = mc->dp[nn + ny * nz];
+ if (dd1 != DBL_MAX) {
+ iiy = (dd1 >= thres ? 1 : -1);
+ if (iix != iiy) {
+ /* Register */
+ mcp->key = nn * 3;
+ mcp->d = (thres - dd0) / (dd1 - dd0);
+ mcp->pos[0] = mc->origin.x + mc->dx * (ix + mcp->d);
+ mcp->pos[1] = mc->origin.y + mc->dy * iy;
+ mcp->pos[2] = mc->origin.z + mc->dz * iz;
+ mcp->grad[0] = p.x;
+ mcp->grad[1] = p.y;
+ mcp->grad[2] = p.z;
+ mcp++;
+ n++;
+ }
+ }
+ /* (x, y, z)->(x, y + 1, z) */
+ dd1 = mc->dp[nn + nz];
+ if (dd1 != DBL_MAX) {
+ iiy = (dd1 >= thres ? 1 : -1);
+ if (iix != iiy) {
+ /* Register */
+ mcp->key = nn * 3 + 1;
+ mcp->d = (thres - dd0) / (dd1 - dd0);
+ mcp->pos[0] = mc->origin.x + mc->dx * ix;
+ mcp->pos[1] = mc->origin.y + mc->dy * (iy + mcp->d);
+ mcp->pos[2] = mc->origin.z + mc->dz * iz;
+ mcp->grad[0] = p.x;
+ mcp->grad[1] = p.y;
+ mcp->grad[2] = p.z;
+ mcp++;
+ n++;
+ }
+ }
+ /* (x, y, z)->(x, y, z + 1) */
+ dd1 = mc->dp[nn + 1];
+ if (dd1 != DBL_MAX) {
+ iiy = (dd1 >= thres ? 1 : -1);
+ if (iix != iiy) {
+ /* Register */
+ mcp->key = nn * 3 + 2;
+ mcp->d = (thres - dd0) / (dd1 - dd0);
+ mcp->pos[0] = mc->origin.x + mc->dx * ix;
+ mcp->pos[1] = mc->origin.y + mc->dy * iy;
+ mcp->pos[2] = mc->origin.z + mc->dz * (iz + mcp->d);
+ mcp->grad[0] = p.x;
+ mcp->grad[1] = p.y;
+ mcp->grad[2] = p.z;
+ mcp++;
+ n++;
+ }
+ }
+ }
+ }
+ }
+ if (n < mc->c[sn].ncubepoints)
+ mc->c[sn].cubepoints[n].key = -1; /* End mark */
+ ncubepoints = n;
+ if (ncubepoints < 3) {
+ /* Less than 3 points: no triangles */
+ if (mc->c[sn].ntriangles > 0)
+ mc->c[sn].triangles[0] = -1; /* End mark */
+ continue;
+ }
+
+ /* Create triangle table */
+ n = 0;
+ for (ix = 0; ix < nx - 1; ix++) {
+ for (iy = 0; iy < ny - 1; iy++) {
+ for (iz = 0; iz < nz - 1; iz++) {
+ nn = (ix * ny + iy) * nz + iz;
+ iix = 0;
+ if ((dd = mc->dp[nn]) == DBL_MAX)
+ continue;
+ else if (dd >= thres)
+ iix |= 1;
+ if ((dd = mc->dp[nn + ny * nz]) == DBL_MAX)
+ continue;
+ else if (dd >= thres)
+ iix |= 2;
+ if ((dd = mc->dp[nn + ny * nz + nz]) == DBL_MAX)
+ continue;
+ else if (dd >= thres)
+ iix |= 4;
+ if ((dd = mc->dp[nn + nz]) == DBL_MAX)
+ continue;
+ else if (dd >= thres)
+ iix |= 8;
+ if ((dd = mc->dp[nn + 1]) == DBL_MAX)
+ continue;
+ else if (dd >= thres)
+ iix |= 16;
+ if ((dd = mc->dp[nn + ny * nz + 1]) == DBL_MAX)
+ continue;
+ else if (dd >= thres)
+ iix |= 32;
+ if ((dd = mc->dp[nn + ny * nz + nz + 1]) == DBL_MAX)
+ continue;
+ else if (dd >= thres)
+ iix |= 64;
+ if ((dd = mc->dp[nn + nz + 1]) == DBL_MAX)
+ continue;
+ else if (dd >= thres)
+ iix |= 128;
+ for (iiy = 0; iiy < 15; iiy++) {
+ nn = sMarchingCubeTable[iix][iiy];
+ if (nn < 0)
+ break;
+ /* key index for edges 0-11 */
+ switch (nn) {
+ case 0: iiz = (( ix * ny + iy ) * nz + iz ) * 3; break;
+ case 1: iiz = (((ix + 1) * ny + iy ) * nz + iz ) * 3 + 1; break;
+ case 2: iiz = (( ix * ny + iy + 1) * nz + iz ) * 3; break;
+ case 3: iiz = (( ix * ny + iy ) * nz + iz ) * 3 + 1; break;
+ case 4: iiz = (( ix * ny + iy ) * nz + iz + 1) * 3; break;
+ case 5: iiz = (((ix + 1) * ny + iy ) * nz + iz + 1) * 3 + 1; break;
+ case 6: iiz = (( ix * ny + iy + 1) * nz + iz + 1) * 3; break;
+ case 7: iiz = (( ix * ny + iy ) * nz + iz + 1) * 3 + 1; break;
+ case 8: iiz = (( ix * ny + iy ) * nz + iz ) * 3 + 2; break;
+ case 9: iiz = (((ix + 1) * ny + iy ) * nz + iz ) * 3 + 2; break;
+ case 10: iiz = (((ix + 1) * ny + iy + 1) * nz + iz ) * 3 + 2; break;
+ case 11: iiz = (( ix * ny + iy + 1) * nz + iz ) * 3 + 2; break;
+ default:
+ /* Skip this triangle */
+ iiy = (iiy - iiy % 3) + 2;
+ n = n - n % 3;
+ continue;
+ }
+ /* Look for the key index in cubepoints */
+ c1 = 0;
+ c3 = ncubepoints - 1;
+ mcp = mc->c[sn].cubepoints;
+ while (1) {
+ int w;
+ /* c1 is always less than c3 */
+ if (c1 + 1 == c3) {
+ /* end of search */
+ if (mcp[c1].key == iiz) {
+ c2 = c1;
+ } else if (mcp[c3].key == iiz) {
+ c2 = c3;
+ } else {
+ c2 = -1;
+ }
+ break;
+ }
+ c2 = (c1 + c3) / 2;
+ w = mcp[c2].key - iiz;
+ if (w == 0)
+ break;
+ if (w < 0) {
+ c1 = c2;
+ } else {
+ c3 = c2;
+ }
+ }
+ if (c2 < 0) {
+ /* Not found: skip this triangle */
+ iiy = (iiy - iiy % 3) + 2;
+ n = n - n % 3;
+ continue;
+ }
+ if (n + 1 >= mc->c[sn].ntriangles) {
+ /* Expand triangles[] array */
+ mc->c[sn].triangles = (Int *)realloc(mc->c[sn].triangles, sizeof(Int) * (mc->c[sn].ntriangles + 8192));
+ if (mc->c[sn].triangles == NULL) {
+ mc->c[sn].ntriangles = 0;
+ retval = -4;
+ goto end;
+ }
+ mc->c[sn].ntriangles += 8192;
+ }
+ mc->c[sn].triangles[n] = c2;
+ n++;
+ }
+ }
+ }
+ }
+ if (n < mc->c[sn].ntriangles)
+ mc->c[sn].triangles[n] = -1; /* End mark */
+
+ /* Estimate the normal vector */
+ for (n = 0, ip = mc->c[sn].triangles; ip[n] >= 0; n += 3) {
+ Vector v[3];
+ for (ix = 0; ix < 3; ix++) {
+ mcp = &(mc->c[sn].cubepoints[ip[n + ix]]);
+ v[ix].x = mcp->pos[0];
+ v[ix].y = mcp->pos[1];
+ v[ix].z = mcp->pos[2];
+ }
+ VecDec(v[2], v[0]);
+ VecDec(v[1], v[0]);
+ VecCross(v[0], v[1], v[2]);
+ NormalizeVec(v, v);
+ for (ix = 0; ix < 3; ix++) {
+ mcp = &(mc->c[sn].cubepoints[ip[n + ix]]);
+ mcp->grad[0] += v[0].x;
+ mcp->grad[1] += v[0].y;
+ mcp->grad[2] += v[0].z;
+ }
+ }
+ for (n = 0, mcp = mc->c[sn].cubepoints; mcp->key >= 0; mcp++) {
+ if (mcp->grad[0] != 0.0 || mcp->grad[1] != 0.0 || mcp->grad[2] != 0.0) {
+ dd = 1.0 / sqrt(mcp->grad[0] * mcp->grad[0] + mcp->grad[1] * mcp->grad[1] + mcp->grad[2] * mcp->grad[2]);
+ if (mc->thres < 0.0)
+ dd = -dd;
+ mcp->grad[0] *= dd;
+ mcp->grad[1] *= dd;
+ mcp->grad[2] *= dd;
+ }
+ }
+ }
+ retval = 0;
+ MoleculeCallback_notifyModification(mol, 0);
+end:
+ /* For debug */
+ if (0) {
+ char *MyAppCallback_getDocumentHomeDir(void);
+ FILE *fp;
+ char *s;
+ Double dmax, dmin;
+ asprintf(&s, "%s/%s", MyAppCallback_getDocumentHomeDir(), "mcube_log.txt");
+ fp = fopen(s, "w");
+ dmax = -1e8;
+ dmin = 1e8;
+ for (n = 0; n < mc->nx * mc->ny * mc->nz; n++) {
+ if (mc->dp[n] == DBL_MAX)
+ continue;
+ if (dmax < mc->dp[n])
+ dmax = mc->dp[n];
+ if (dmin > mc->dp[n])
+ dmin = mc->dp[n];
+ }
+ dmax = fabs(dmax);
+ dmin = fabs(dmin);
+ if (dmax < dmin)
+ dmax = dmin;
+ dmax = 1.001 * dmax;
+ fprintf(fp, "thres = %g = 100\n", mc->thres);
+ for (iz = 0; iz < mc->nz; iz++) {
+ fprintf(fp, "z = %d\n", iz);
+ for (iy = 0; iy < mc->ny; iy++) {
+ for (ix = 0; ix < mc->nx; ix++) {
+ n = (ix * ny + iy) * nz + iz;
+ dd = mc->dp[n];
+ if (dd == DBL_MAX)
+ fprintf(fp, " XXX ");
+ else {
+ dd = dd * 100 / mc->thres;
+ if (dd > 999.0)
+ dd = 999.0;
+ else if (dd < -999.0)
+ dd = -999.0;
+ fprintf(fp, "%4d ", (int)(dd));
+ }
+ }
+ fprintf(fp, "\n");
+ }
+ fprintf(fp, "\n");
+ }
+
+ for (sn = 0; sn <= 1; sn++) {
+ for (n = 0; n < mc->c[sn].ncubepoints; n++) {
+ MCubePoint *mcp = mc->c[sn].cubepoints + n;
+ nn = mcp->key;
+ if (nn == -1)
+ break;
+ iix = nn % 3;
+ iz = nn / 3 % mc->nz;
+ iy = nn / (3 * mc->nz) % mc->ny;
+ ix = nn / (3 * mc->nz * mc->ny);
+ fprintf(fp, "%c%d:[%d,%d,%d,%d] (%g,[%g,%g,%g],[%g,%g,%g])\n", (sn == 0 ? 'p' : 'P'),
+ n, ix, iy, iz, iix,
+ mcp->d, mcp->pos[0], mcp->pos[1], mcp->pos[2], mcp->grad[0], mcp->grad[1], mcp->grad[2]);
+ }
+ for (n = 0; n < mc->c[sn].ntriangles; n += 3) {
+ if (mc->c[sn].triangles[n] < 0)
+ break;
+ fprintf(fp, "%c%d:(%d,%d,%d)\n", (sn == 0 ? 't' : 'T'), n / 3,
+ mc->c[sn].triangles[n], mc->c[sn].triangles[n + 1], mc->c[sn].triangles[n + 2]);
+ }
+ }
+ fclose(fp);
+ }
+
+ return retval;
+}
+
+void
+MoleculeDeallocateMCube(MCube *mcube)
+{
+ free(mcube->dp);
+ free(mcube->radii);
+ free(mcube->c[0].cubepoints);
+ free(mcube->c[0].triangles);
+ free(mcube->c[1].cubepoints);
+ free(mcube->c[1].triangles);
+ free(mcube);
+}