static PyObject * __read_next_frame(PyObject *self, PyObject *args) { dcdhandle *dcd; PyObject *temp; PyArrayObject *x, *y, *z, *uc; int skip=1; int rc,numskip; float* unitcell; float alpha, beta, gamma; if (!self) { /* we were in fact called as a module function, try to retrieve a matching object from args */ if( !PyArg_ParseTuple(args, "OO!O!O!O!|i", &self, &PyArray_Type, &x, &PyArray_Type, &y, &PyArray_Type, &z, &PyArray_Type, &uc, &skip) ) return NULL; } else { /* we were obviously called as an object method so args should only have the int value. */ if( !PyArg_ParseTuple(args, "O!O!O!O!|i", &PyArray_Type, &x, &PyArray_Type, &y, &PyArray_Type, &z, &PyArray_Type, &uc, &skip) ) return NULL; } if ((temp = PyObject_GetAttrString(self, "_dcd_C_ptr")) == NULL) { // This gives me a New Reference // Raise exception PyErr_SetString(PyExc_AttributeError, "_dcd_C_ptr is not an attribute"); return NULL; } dcd = (dcdhandle*)PyCObject_AsVoidPtr(temp); Py_DECREF(temp); unitcell = (float*) uc->data; unitcell[0] = unitcell[2] = unitcell[5] = 0.0f; unitcell[1] = unitcell[3] = unitcell[4] = 90.0f; /* Check for EOF here; that way all EOF's encountered later must be errors */ if (dcd->setsread == dcd->nsets) { // Is this an exception? PyErr_SetString(PyExc_IOError, "End of file reached for dcd file"); return NULL; //return MOLFILE_EOF; } if (skip > 1) { if (dcd->first && dcd->nfixed) { /* We can't just skip it because we need the fixed atom coordinates */ rc = read_dcdstep(dcd->fd, dcd->natoms, (float*)x->data, (float*)y->data, (float*)z->data, unitcell, dcd->nfixed, dcd->first, dcd->freeind, dcd->fixedcoords, dcd->reverse, dcd->charmm); dcd->first = 0; if (rc < 0) { // return an exception PyErr_SetString(PyExc_IOError, "Error reading first frame from DCD file"); //fprintf(stderr, "read_dcdstep returned %d\n", rc); return NULL; //return MOLFILE_ERROR; } dcd->setsread++; temp = Py_BuildValue("i", dcd->setsread); return temp; //return rc; /* XXX this needs to be updated */ } dcd->first = 0; // Figure out how many steps to skip numskip = skip - (dcd->setsread % skip) - 1; /* XXX this needs to be changed */ rc = skip_dcdstep(dcd->fd, dcd->natoms, dcd->nfixed, dcd->charmm, numskip); if (rc < 0) { // return an exception PyErr_SetString(PyExc_IOError, "Error skipping frame from DCD file"); //fprintf(stderr, "read_dcdstep returned %d\n", rc); return NULL; //return MOLFILE_ERROR; } dcd->setsread+=numskip; } rc = read_dcdstep(dcd->fd, dcd->natoms, (float*)x->data, (float*)y->data, (float*)z->data, unitcell, dcd->nfixed, dcd->first, dcd->freeind, dcd->fixedcoords, dcd->reverse, dcd->charmm); dcd->first = 0; dcd->setsread++; if (rc < 0) { // return an exception PyErr_SetString(PyExc_IOError, "Error reading frame from DCD file"); //fprintf(stderr, "read_dcdstep returned %d\n", rc); return NULL; //return MOLFILE_ERROR; } if (unitcell[1] >= -1.0 && unitcell[1] <= 1.0 && unitcell[3] >= -1.0 && unitcell[3] <= 1.0 && unitcell[4] >= -1.0 && unitcell[4] <= 1.0) { /* This file was generated by Charmm, or by NAMD > 2.5, with the angle */ /* cosines of the periodic cell angles written to the DCD file. */ /* This formulation improves rounding behavior for orthogonal cells */ /* so that the angles end up at precisely 90 degrees, unlike acos(). */ /* (changed in MDAnalysis 0.9.0 to have NAMD ordering of the angles; */ /* see Issue 187) */ alpha = 90.0 - asin(unitcell[4]) * 90.0 / M_PI_2; beta = 90.0 - asin(unitcell[3]) * 90.0 / M_PI_2; gamma = 90.0 - asin(unitcell[1]) * 90.0 / M_PI_2; } else { /* This file was likely generated by NAMD 2.5 and the periodic cell */ /* angles are specified in degrees rather than angle cosines. */ alpha = unitcell[4]; beta = unitcell[3]; gamma = unitcell[1]; } unitcell[4] = alpha; unitcell[3] = beta; unitcell[1] = gamma; // Return the frame read temp = Py_BuildValue("i", dcd->setsread); return temp; }
static int read_next_timestep(void *v, int natoms, molfile_timestep_t *ts) { dcdhandle *dcd; int i, j, rc; float unitcell[6]; unitcell[0] = unitcell[2] = unitcell[5] = 1.0f; unitcell[1] = unitcell[3] = unitcell[4] = 90.0f; dcd = (dcdhandle *)v; /* Check for EOF here; that way all EOF's encountered later must be errors */ if (dcd->setsread == dcd->nsets) return MOLFILE_EOF; dcd->setsread++; if (!ts) { if (dcd->first && dcd->nfixed) { /* We can't just skip it because we need the fixed atom coordinates */ rc = read_dcdstep(dcd->fd, dcd->natoms, dcd->x, dcd->y, dcd->z, unitcell, dcd->nfixed, dcd->first, dcd->freeind, dcd->fixedcoords, dcd->reverse, dcd->charmm); dcd->first = 0; return rc; /* XXX this needs to be updated */ } dcd->first = 0; /* XXX this needs to be changed */ return skip_dcdstep(dcd->fd, dcd->natoms, dcd->nfixed, dcd->charmm); } rc = read_dcdstep(dcd->fd, dcd->natoms, dcd->x, dcd->y, dcd->z, unitcell, dcd->nfixed, dcd->first, dcd->freeind, dcd->fixedcoords, dcd->reverse, dcd->charmm); dcd->first = 0; if (rc < 0) { print_dcderror("read_dcdstep", rc); return MOLFILE_ERROR; } /* copy timestep data from plugin-local buffers to VMD's buffer */ /* XXX * This code is still the root of all evil. Just doing this extra copy * cuts the I/O rate of the DCD reader from 728 MB/sec down to * 394 MB/sec when reading from a ram filesystem. * For a physical disk filesystem, the I/O rate goes from * 187 MB/sec down to 122 MB/sec. Clearly this extra copy has to go. */ { int natoms = dcd->natoms; float *nts = ts->coords; const float *bufx = dcd->x; const float *bufy = dcd->y; const float *bufz = dcd->z; for (i=0, j=0; i<natoms; i++, j+=3) { nts[j ] = bufx[i]; nts[j + 1] = bufy[i]; nts[j + 2] = bufz[i]; } } ts->A = unitcell[0]; ts->B = unitcell[2]; ts->C = unitcell[5]; if (unitcell[1] >= -1.0 && unitcell[1] <= 1.0 && unitcell[3] >= -1.0 && unitcell[3] <= 1.0 && unitcell[4] >= -1.0 && unitcell[4] <= 1.0) { /* This file was generated by CHARMM, or by NAMD > 2.5, with the angle */ /* cosines of the periodic cell angles written to the DCD file. */ /* This formulation improves rounding behavior for orthogonal cells */ /* so that the angles end up at precisely 90 degrees, unlike acos(). */ ts->alpha = 90.0 - asin(unitcell[4]) * 90.0 / M_PI_2; /* cosBC */ ts->beta = 90.0 - asin(unitcell[3]) * 90.0 / M_PI_2; /* cosAC */ ts->gamma = 90.0 - asin(unitcell[1]) * 90.0 / M_PI_2; /* cosAB */ } else { /* This file was likely generated by NAMD 2.5 and the periodic cell */ /* angles are specified in degrees rather than angle cosines. */ ts->alpha = unitcell[4]; /* angle between B and C */ ts->beta = unitcell[3]; /* angle between A and C */ ts->gamma = unitcell[1]; /* angle between A and B */ } return MOLFILE_SUCCESS; }
static PyObject * __read_timeseries(PyObject *self, PyObject *args) { PyObject *temp = NULL; PyArrayObject *coord = NULL; PyListObject *atoms = NULL; int lowerb = 0, upperb = 0, range=0; float *tempX = NULL, *tempY = NULL, *tempZ = NULL; int rc; int i, j, index; int n_atoms = 0, n_frames = 0; /* Stop = -1 is incorrect and causes an error, look for a fix of this in line 469 */ int start = 0, stop = -1, step = 1, numskip = 0, remaining_frames=0; dcdhandle *dcd = NULL; int *atomlist = NULL; npy_intp dimensions[3]; float unitcell[6]; const char* format = "afc"; if (!self) { /* we were in fact called as a module function, try to retrieve a matching object from args */ if( !PyArg_ParseTuple(args, "OO!|iiis", &self, &PyList_Type, &atoms, &start, &stop, &step, &format) ) return NULL; } else { /* we were obviously called as an object method so args should only have the int value. */ if( !PyArg_ParseTuple(args, "O!|iiis", &PyList_Type, &atoms, &start, &stop, &step, &format) ) return NULL; } if ((temp = PyObject_GetAttrString(self, "_dcd_C_ptr")) == NULL) { // This gives me a New Reference // Raise exception PyErr_SetString(PyExc_AttributeError, "_dcd_C_ptr is not an attribute"); return NULL; } dcd = (dcdhandle*)PyCObject_AsVoidPtr(temp); Py_DECREF(temp); n_frames = ((stop-start) / step); if ((stop-start) % step > 0) { n_frames++; } //n_frames = dcd->nsets / skip; n_atoms = PyList_Size((PyObject*)atoms); if (n_atoms == 0) { PyErr_SetString(PyExc_Exception, "No atoms passed into _read_timeseries function"); return NULL; } atomlist = (int*)malloc(sizeof(int)*n_atoms); memset(atomlist, 0, sizeof(int)*n_atoms); // Get the atom indexes for (i=0;i<n_atoms;i++) { temp = PyList_GetItem((PyObject*)atoms, i); // Borrowed Reference if (temp==NULL) goto error; // Make sure temp is an integer /* TODO: this is not the proper check but [OB] cannot figure out how to check if this is a numpy.int64 or similar; PyInt_Check would fail on those (Issue 18) */ if (!PyArray_IsAnyScalar((PyObject*)temp)) { PyErr_SetString(PyExc_ValueError, "Atom number is not an integer"); goto error; } atomlist[i] = PyInt_AsLong(temp); } lowerb = atomlist[0]; upperb = atomlist[n_atoms-1]; range = upperb-lowerb+1; // Figure out the format string if (strncasecmp(format, "afc", 3) == 0) { dimensions[0] = n_atoms; dimensions[1] = n_frames; dimensions[2] = 3; } else if (strncasecmp(format, "acf", 3) == 0) { dimensions[0] = n_atoms; dimensions[1] = 3; dimensions[2] = n_frames; } else if (strncasecmp(format, "fac", 3) == 0) { dimensions[0] = n_frames; dimensions[1] = n_atoms; dimensions[2] = 3; } else if (strncasecmp(format, "fca", 3) == 0) { dimensions[0] = n_frames; dimensions[1] = 3; dimensions[2] = n_atoms; } else if (strncasecmp(format, "caf", 3) == 0) { dimensions[0] = 3; dimensions[1] = n_atoms; dimensions[2] = n_frames; } else if (strncasecmp(format, "cfa", 3) == 0) { dimensions[0] = 3; dimensions[1] = n_frames; dimensions[2] = n_atoms; } coord = (PyArrayObject*) PyArray_SimpleNew(3, dimensions, NPY_DOUBLE); if (coord == NULL) goto error; // Reset trajectory rc = fio_fseek(dcd->fd, dcd->header_size, FIO_SEEK_SET); dcd->setsread = 0; dcd->first = 1; // Jump to starting frame jump_to_frame(dcd, start); // Now read through trajectory and get the atom pos tempX = (float*)malloc(sizeof(float)*range); tempY = (float*)malloc(sizeof(float)*range); tempZ = (float*)malloc(sizeof(float)*range); if ((tempX == NULL) | (tempY == NULL) || (tempZ == NULL)) { PyErr_SetString(PyExc_MemoryError, "Can't allocate temporary space for coordinate arrays"); goto error; } remaining_frames = stop-start; for (i=0;i<n_frames;i++) { if (step > 1 && i>0) { // Check if we have fixed atoms // XXX not done /* Figure out how many steps to step over, if step = n, np array slicing treats this as skip over n-1, read the nth. */ numskip = step -1; /* If the number to skip is greater than the number of frames left to be jumped over, just take one more step to reflect np slicing if there is a remainder, guaranteed to have at least one more frame. */ if(remaining_frames < numskip){ numskip = 1; } rc = skip_dcdstep(dcd->fd, dcd->natoms, dcd->nfixed, dcd->charmm, numskip); if (rc < 0) { // return an exception PyErr_SetString(PyExc_IOError, "Error skipping frame from DCD file"); goto error; } } // on first iteration, numskip == 0, first set is always read. dcd->setsread += numskip; //now read from subset rc = read_dcdsubset(dcd->fd, dcd->natoms, lowerb, upperb, tempX, tempY, tempZ, unitcell, dcd->nfixed, dcd->first, dcd->freeind, dcd->fixedcoords, dcd->reverse, dcd->charmm); dcd->first = 0; dcd->setsread++; remaining_frames = stop - dcd->setsread; if (rc < 0) { // return an exception PyErr_SetString(PyExc_IOError, "Error reading frame from DCD file"); goto error; } // Copy into Numeric array only those atoms we are interested in for (j=0;j<n_atoms;j++) { index = atomlist[j]-lowerb; /* * coord[a][b][c] = *(float*)(coord->data + a*coord->strides[0] + b*coord->strides[1] + c*coord->strides[2]) */ if (strncasecmp(format, "afc", 3) == 0) { *(double*)(coord->data + j*coord->strides[0] + i*coord->strides[1] + 0*coord->strides[2]) = tempX[index]; *(double*)(coord->data + j*coord->strides[0] + i*coord->strides[1] + 1*coord->strides[2]) = tempY[index]; *(double*)(coord->data + j*coord->strides[0] + i*coord->strides[1] + 2*coord->strides[2]) = tempZ[index]; } else if (strncasecmp(format, "acf", 3) == 0) { *(double*)(coord->data + j*coord->strides[0] + 0*coord->strides[1] + i*coord->strides[2]) = tempX[index]; *(double*)(coord->data + j*coord->strides[0] + 1*coord->strides[1] + i*coord->strides[2]) = tempY[index]; *(double*)(coord->data + j*coord->strides[0] + 2*coord->strides[1] + i*coord->strides[2]) = tempZ[index]; } else if (strncasecmp(format, "fac", 3) == 0) { *(double*)(coord->data + i*coord->strides[0] + j*coord->strides[1] + 0*coord->strides[2]) = tempX[index]; *(double*)(coord->data + i*coord->strides[0] + j*coord->strides[1] + 1*coord->strides[2]) = tempY[index]; *(double*)(coord->data + i*coord->strides[0] + j*coord->strides[1] + 2*coord->strides[2]) = tempZ[index]; } else if (strncasecmp(format, "fca", 3) == 0) { *(double*)(coord->data + i*coord->strides[0] + 0*coord->strides[1] + j*coord->strides[2]) = tempX[index]; *(double*)(coord->data + i*coord->strides[0] + 1*coord->strides[1] + j*coord->strides[2]) = tempY[index]; *(double*)(coord->data + i*coord->strides[0] + 2*coord->strides[1] + j*coord->strides[2]) = tempZ[index]; } else if (strncasecmp(format, "caf", 3) == 0) { *(double*)(coord->data + 0*coord->strides[0] + j*coord->strides[1] + i*coord->strides[2]) = tempX[index]; *(double*)(coord->data + 1*coord->strides[0] + j*coord->strides[1] + i*coord->strides[2]) = tempY[index]; *(double*)(coord->data + 2*coord->strides[0] + j*coord->strides[1] + i*coord->strides[2]) = tempZ[index]; } else if (strncasecmp(format, "cfa", 3) == 0) { *(double*)(coord->data + 0*coord->strides[0] + i*coord->strides[1] + j*coord->strides[2]) = tempX[index]; *(double*)(coord->data + 1*coord->strides[0] + i*coord->strides[1] + j*coord->strides[2]) = tempY[index]; *(double*)(coord->data + 2*coord->strides[0] + i*coord->strides[1] + j*coord->strides[2]) = tempZ[index]; } } // Check if we've been interupted by the user if (PyErr_CheckSignals() == 1) goto error; } // Reset trajectory rc = fio_fseek(dcd->fd, dcd->header_size, FIO_SEEK_SET); dcd->setsread = 0; dcd->first = 1; free(atomlist); free(tempX); free(tempY); free(tempZ); return PyArray_Return(coord); error: // Reset trajectory rc = fio_fseek(dcd->fd, dcd->header_size, FIO_SEEK_SET); dcd->setsread = 0; dcd->first = 1; Py_XDECREF(coord); if (atomlist != NULL) free(atomlist); if (tempX != NULL) free(tempX); if (tempY != NULL) free(tempY); if (tempZ != NULL) free(tempZ); return NULL; }