/******************************************************************************* ** Make points array for visible atoms *******************************************************************************/ static PyObject* makeVisiblePointsArray(PyObject *self, PyObject *args) { int NVisible; PyArrayObject *visibleAtoms=NULL; PyArrayObject *pos=NULL; int i; npy_intp numpydims[2]; PyArrayObject *visiblePos=NULL; /* parse and check arguments from Python */ if (!PyArg_ParseTuple(args, "O!O!", &PyArray_Type, &visibleAtoms, &PyArray_Type, &pos)) return NULL; if (not_intVector(visibleAtoms)) return NULL; NVisible = (int) PyArray_DIM(visibleAtoms, 0); if (not_doubleVector(pos)) return NULL; /* create radius array */ numpydims[0] = (npy_intp) NVisible; numpydims[1] = 3; visiblePos = (PyArrayObject *) PyArray_SimpleNew(2, numpydims, NPY_FLOAT64); /* populate array */ for (i = 0; i < NVisible; i++) { int index, index3, j; index = IIND1(visibleAtoms, i); index3 = index * 3; for (j = 0; j < 3; j++) DIND2(visiblePos, i, j) = DIND1(pos, index3 + j); } return PyArray_Return(visiblePos); }
/******************************************************************************* ** Make arrays for rendering bonds for displacment vectors *******************************************************************************/ static PyObject* makeDisplacementVectorBondsArrays(PyObject *self, PyObject *args) { int numBonds; PyArrayObject *visibleAtoms=NULL; PyArrayObject *scalarsArray=NULL; PyArrayObject *pos=NULL; PyArrayObject *drawBondArray=NULL; PyArrayObject *bondVectorsArray=NULL; PyObject *result=NULL; /* parse arguments from Python */ if (PyArg_ParseTuple(args, "iO!O!O!O!O!", &numBonds, &PyArray_Type, &visibleAtoms, &PyArray_Type, &scalarsArray, &PyArray_Type, &pos, &PyArray_Type, &drawBondArray, &PyArray_Type, &bondVectorsArray)) { int i, count, numVisible; npy_intp numpydims[2]; PyArrayObject *bondCoords = NULL; PyArrayObject *bondScalars = NULL; PyArrayObject *bondVectors = NULL; /* check arguments */ if (not_intVector(visibleAtoms)) return NULL; numVisible = (int) PyArray_DIM(visibleAtoms, 0); if (not_doubleVector(scalarsArray)) return NULL; if (not_doubleVector(pos)) return NULL; if (not_intVector(drawBondArray)) return NULL; if (not_doubleVector(bondVectorsArray)) return NULL; /* create array for bond coordinates */ numpydims[0] = (npy_intp) numBonds; numpydims[1] = 3; bondCoords = (PyArrayObject *) PyArray_SimpleNew(2, numpydims, NPY_FLOAT64); if (bondCoords == NULL) { PyErr_SetString(PyExc_MemoryError, "Could not allocate bondCoords"); return NULL; } /* create array for bond vectors */ numpydims[0] = (npy_intp) numBonds; numpydims[1] = 3; bondVectors = (PyArrayObject *) PyArray_SimpleNew(2, numpydims, NPY_FLOAT64); if (bondVectors == NULL) { PyErr_SetString(PyExc_MemoryError, "Could not allocate bondVectors"); Py_DECREF(bondCoords); return NULL; } /* create array for bond scalars */ numpydims[0] = (npy_intp) numBonds; bondScalars = (PyArrayObject *) PyArray_SimpleNew(1, numpydims, NPY_FLOAT64); if (bondScalars == NULL) { PyErr_SetString(PyExc_MemoryError, "Could not allocate bondScalars"); Py_DECREF(bondCoords); Py_DECREF(bondVectors); return NULL; } /* loop over visible atoms */ count = 0; for (i = 0; i < numVisible; i++) { /* check if we should be drawing this bond */ if (IIND1(drawBondArray, i)) { int j, i3 = 3 * i; int index3 = 3 * IIND1(visibleAtoms, i); /* store bond values */ for (j = 0; j < 3; j++) { DIND2(bondCoords, count, j) = DIND1(pos, index3 + j); DIND2(bondVectors, count, j) = DIND1(bondVectorsArray, i3 + j); } DIND1(bondScalars, count) = DIND1(scalarsArray, i); count++; } } /* tuple for result */ result = PyTuple_New(3); PyTuple_SetItem(result, 0, PyArray_Return(bondCoords)); PyTuple_SetItem(result, 1, PyArray_Return(bondVectors)); PyTuple_SetItem(result, 2, PyArray_Return(bondScalars)); } return result; }
/******************************************************************************* ** Split visible atoms by specie (position and scalar) *******************************************************************************/ static PyObject* splitVisAtomsBySpecie(PyObject *self, PyObject *args) { int NVisible, *visibleAtoms, NSpecies, *specieArray, *specieCount, scalarType, heightAxis, vectorsLen; double *pos, *PE, *KE, *charge, *scalars; PyArrayObject *visibleAtomsIn=NULL; PyArrayObject *specieArrayIn=NULL; PyArrayObject *specieCountIn=NULL; PyArrayObject *posIn=NULL; PyArrayObject *PEIn=NULL; PyArrayObject *KEIn=NULL; PyArrayObject *chargeIn=NULL; PyArrayObject *scalarsIn=NULL; PyArrayObject *vectors=NULL; int i, j, index, specie, count; npy_intp numpyDims[2]; double scalar; PyObject *list=NULL; /* parse and check arguments from Python */ if (!PyArg_ParseTuple(args, "O!iO!O!O!O!O!O!O!iiO!", &PyArray_Type, &visibleAtomsIn, &NSpecies, &PyArray_Type, &specieArrayIn, &PyArray_Type, &specieCountIn, &PyArray_Type, &posIn, &PyArray_Type, &PEIn, &PyArray_Type, &KEIn, &PyArray_Type, &chargeIn, &PyArray_Type, &scalarsIn, &scalarType, &heightAxis, &PyArray_Type, &vectors)) return NULL; if (not_intVector(visibleAtomsIn)) return NULL; visibleAtoms = pyvector_to_Cptr_int(visibleAtomsIn); NVisible = (int) PyArray_DIM(visibleAtomsIn, 0); if (not_intVector(specieArrayIn)) return NULL; specieArray = pyvector_to_Cptr_int(specieArrayIn); if (not_intVector(specieCountIn)) return NULL; specieCount = pyvector_to_Cptr_int(specieCountIn); if (not_doubleVector(posIn)) return NULL; pos = pyvector_to_Cptr_double(posIn); if (not_doubleVector(PEIn)) return NULL; PE = pyvector_to_Cptr_double(PEIn); if (not_doubleVector(KEIn)) return NULL; KE = pyvector_to_Cptr_double(KEIn); if (not_doubleVector(chargeIn)) return NULL; charge = pyvector_to_Cptr_double(chargeIn); if (not_doubleVector(scalarsIn)) return NULL; scalars = pyvector_to_Cptr_double(scalarsIn); if (not_doubleVector(vectors)) return NULL; vectorsLen = (int) PyArray_DIM(vectors, 0); /* first pass to get counters, assume counter zeroed before */ for (i = 0; i < NVisible; i++) { index = visibleAtoms[i]; specie = specieArray[index]; specieCount[specie]++; } /* create list for returning */ list = PyList_New(NSpecies); /* loop over species */ for (i = 0; i < NSpecies; i++) { PyArrayObject *speciePos = NULL; PyArrayObject *specieScalars = NULL; PyArrayObject *specieVectors = NULL; PyObject *tuple = NULL; /* allocate position array */ numpyDims[0] = (npy_intp) specieCount[i]; numpyDims[1] = 3; speciePos = (PyArrayObject *) PyArray_SimpleNew(2, numpyDims, NPY_FLOAT64); /* allocate position array */ numpyDims[0] = (npy_intp) specieCount[i]; specieScalars = (PyArrayObject *) PyArray_SimpleNew(1, numpyDims, NPY_FLOAT64); if (vectorsLen > 0) { /* allocate vectors array */ numpyDims[0] = (npy_intp) specieCount[i]; numpyDims[1] = 3; specieVectors = (PyArrayObject *) PyArray_SimpleNew(2, numpyDims, NPY_FLOAT64); } else { numpyDims[0] = 0; specieVectors = (PyArrayObject *) PyArray_SimpleNew(1, numpyDims, NPY_FLOAT64); } /* loop over atoms */ count = 0; for (j = 0; j < NVisible; j++) { index = visibleAtoms[j]; specie = specieArray[index]; if (specie == i) { /* position */ DIND2(speciePos, count, 0) = pos[3*index+0]; DIND2(speciePos, count, 1) = pos[3*index+1]; DIND2(speciePos, count, 2) = pos[3*index+2]; /* scalar */ if (scalarType == 0) scalar = specie; else if (scalarType == 1) scalar = pos[3*index+heightAxis]; else if (scalarType == 2) scalar = KE[index]; else if (scalarType == 3) scalar = PE[index]; else if (scalarType == 4) scalar = charge[index]; else scalar = scalars[j]; DIND1(specieScalars, count) = scalar; if (vectorsLen > 0) { /* vector */ DIND2(specieVectors, count, 0) = DIND2(vectors, index, 0); DIND2(specieVectors, count, 1) = DIND2(vectors, index, 1); DIND2(specieVectors, count, 2) = DIND2(vectors, index, 2); } count++; } } /* create tuple (setItem steals ownership of array objects!!??) */ tuple = PyTuple_New(3); PyTuple_SetItem(tuple, 0, PyArray_Return(speciePos)); PyTuple_SetItem(tuple, 1, PyArray_Return(specieScalars)); PyTuple_SetItem(tuple, 2, PyArray_Return(specieVectors)); /* store in list (setItem steals ownership of tuple!?) */ PyList_SetItem(list, i, tuple); } return list; }
/******************************************************************************* ** Make arrays for rendering bonds *******************************************************************************/ static PyObject* makeBondsArrays(PyObject *self, PyObject *args) { PyArrayObject *visibleAtoms=NULL; PyArrayObject *scalarsArray=NULL; PyArrayObject *pos=NULL; PyArrayObject *numBondsArray=NULL; PyArrayObject *bondsArray=NULL; PyArrayObject *bondVectorsArray=NULL; PyObject *result=NULL; /* parse arguments from Python */ if (PyArg_ParseTuple(args, "O!O!O!O!O!O!", &PyArray_Type, &visibleAtoms, &PyArray_Type, &scalarsArray, &PyArray_Type, &pos, &PyArray_Type, &numBondsArray, &PyArray_Type, &bondsArray, &PyArray_Type, &bondVectorsArray)) { int i, numVisible, numBonds, count, bondCount; npy_intp numpydims[2]; PyArrayObject *bondCoords = NULL; PyArrayObject *bondScalars = NULL; PyArrayObject *bondVectors = NULL; /* check arguments */ if (not_intVector(visibleAtoms)) return NULL; numVisible = (int) PyArray_DIM(visibleAtoms, 0); if (not_doubleVector(scalarsArray)) return NULL; if (not_doubleVector(pos)) return NULL; if (not_intVector(numBondsArray)) return NULL; if (not_intVector(bondsArray)) return NULL; if (not_doubleVector(bondVectorsArray)) return NULL; /* calculate the number of bonds */ numBonds = 0; for (i = 0; i < numVisible; i++) numBonds += IIND1(numBondsArray, i); /* multiply by two as there are two "bonds" drawn per real bond */ numBonds *= 2; /* create array for bond coordinates */ numpydims[0] = (npy_intp) numBonds; numpydims[1] = 3; bondCoords = (PyArrayObject *) PyArray_SimpleNew(2, numpydims, NPY_FLOAT64); if (bondCoords == NULL) { PyErr_SetString(PyExc_MemoryError, "Could not allocate bondCoords"); return NULL; } /* create array for bond vectors */ numpydims[0] = (npy_intp) numBonds; numpydims[1] = 3; bondVectors = (PyArrayObject *) PyArray_SimpleNew(2, numpydims, NPY_FLOAT64); if (bondVectors == NULL) { PyErr_SetString(PyExc_MemoryError, "Could not allocate bondVectors"); Py_DECREF(bondCoords); return NULL; } /* create array for bond scalars */ numpydims[0] = (npy_intp) numBonds; bondScalars = (PyArrayObject *) PyArray_SimpleNew(1, numpydims, NPY_FLOAT64); if (bondScalars == NULL) { PyErr_SetString(PyExc_MemoryError, "Could not allocate bondScalars"); Py_DECREF(bondCoords); Py_DECREF(bondVectors); return NULL; } /* loop over visible atoms */ count = 0; bondCount = 0; for (i = 0; i < numVisible; i++) { int j; int indexa = IIND1(visibleAtoms, i); int indexa3 = 3 * indexa; int numBondsForAtom = IIND1(numBondsArray, i); double xposa, yposa, zposa, scalara; /* atom position and scalar */ xposa = DIND1(pos, indexa3 ); yposa = DIND1(pos, indexa3 + 1); zposa = DIND1(pos, indexa3 + 2); scalara = DIND1(scalarsArray, i); /* loop over this atoms bonds */ for (j = 0; j < numBondsForAtom; j++) { int cnt3 = count * 3; int visIndex = IIND1(bondsArray, count); int indexb3 = 3 * IIND1(visibleAtoms, visIndex); double xposb = DIND1(pos, indexb3 ); double yposb = DIND1(pos, indexb3 + 1); double zposb = DIND1(pos, indexb3 + 2); double scalarb = DIND1(scalarsArray, visIndex); double bvecx = DIND1(bondVectorsArray, cnt3 ); double bvecy = DIND1(bondVectorsArray, cnt3 + 1); double bvecz = DIND1(bondVectorsArray, cnt3 + 2); /* partial bond from atom a towards b */ DIND2(bondCoords, bondCount, 0) = xposa; DIND2(bondCoords, bondCount, 1) = yposa; DIND2(bondCoords, bondCount, 2) = zposa; DIND2(bondVectors, bondCount, 0) = bvecx; DIND2(bondVectors, bondCount, 1) = bvecy; DIND2(bondVectors, bondCount, 2) = bvecz; DIND1(bondScalars, bondCount) = scalara; bondCount++; /* partial bond from atom b towards a */ DIND2(bondCoords, bondCount, 0) = xposb; DIND2(bondCoords, bondCount, 1) = yposb; DIND2(bondCoords, bondCount, 2) = zposb; DIND2(bondVectors, bondCount, 0) = -1.0 * bvecx; DIND2(bondVectors, bondCount, 1) = -1.0 * bvecy; DIND2(bondVectors, bondCount, 2) = -1.0 * bvecz; DIND1(bondScalars, bondCount) = scalarb; bondCount++; count++; } } /* tuple for result */ result = PyTuple_New(3); PyTuple_SetItem(result, 0, PyArray_Return(bondCoords)); PyTuple_SetItem(result, 1, PyArray_Return(bondVectors)); PyTuple_SetItem(result, 2, PyArray_Return(bondScalars)); } return result; }
/******************************************************************************* ** Calculate the bond order parameters and filter atoms (if required). ** ** Inputs: ** - visibleAtoms: the list of atoms that are currently visible ** - pos: positions of all the atoms ** - maxBondDistance: the maximum bond distance to consider ** - scalarsQ4: array to store the Q4 parameter value ** - scalarsQ6: array to store the Q6 parameter value ** - cellDims: simulation cell dimensions ** - PBC: periodic boundaries conditions ** - NScalars: the number of previously calculated scalar values ** - fullScalars: the full list of previously calculated scalars ** - NVectors: the number of previously calculated vector values ** - fullVectors: the full list of previously calculated vectors ** - filterQ4: filter atoms by the Q4 parameter ** - minQ4: the minimum Q4 for an atom to be visible ** - maxQ4: the maximum Q4 for an atom to be visible ** - filterQ6: filter atoms by the Q6 parameter ** - minQ6: the minimum Q6 for an atom to be visible ** - maxQ6: the maximum Q6 for an atom to be visible *******************************************************************************/ static PyObject* bondOrderFilter(PyObject *self, PyObject *args) { int NVisibleIn, *visibleAtoms, *PBC, NScalars, filterQ4Enabled, filterQ6Enabled; int NVectors; double maxBondDistance, *scalarsQ4, *scalarsQ6, *cellDims; double *pos, *fullScalars, minQ4, maxQ4, minQ6, maxQ6; PyArrayObject *posIn=NULL; PyArrayObject *visibleAtomsIn=NULL; PyArrayObject *PBCIn=NULL; PyArrayObject *scalarsQ4In=NULL; PyArrayObject *scalarsQ6In=NULL; PyArrayObject *cellDimsIn=NULL; PyArrayObject *fullScalarsIn=NULL; PyArrayObject *fullVectors=NULL; int i, NVisible, boxstat; double *visiblePos, maxSep2; struct Boxes *boxes; struct NeighbourList *nebList; struct AtomStructureResults *results; /* parse and check arguments from Python */ if (!PyArg_ParseTuple(args, "O!O!dO!O!O!O!iO!iddiddiO!", &PyArray_Type, &visibleAtomsIn, &PyArray_Type, &posIn, &maxBondDistance, &PyArray_Type, &scalarsQ4In, &PyArray_Type, &scalarsQ6In, &PyArray_Type, &cellDimsIn, &PyArray_Type, &PBCIn, &NScalars, &PyArray_Type, &fullScalarsIn, &filterQ4Enabled, &minQ4, &maxQ4, &filterQ6Enabled, &minQ6, &maxQ6, &NVectors, &PyArray_Type, &fullVectors)) return NULL; if (not_intVector(visibleAtomsIn)) return NULL; visibleAtoms = pyvector_to_Cptr_int(visibleAtomsIn); NVisibleIn = (int) PyArray_DIM(visibleAtomsIn, 0); if (not_doubleVector(posIn)) return NULL; pos = pyvector_to_Cptr_double(posIn); if (not_doubleVector(scalarsQ4In)) return NULL; scalarsQ4 = pyvector_to_Cptr_double(scalarsQ4In); if (not_doubleVector(scalarsQ6In)) return NULL; scalarsQ6 = pyvector_to_Cptr_double(scalarsQ6In); if (not_doubleVector(cellDimsIn)) return NULL; cellDims = pyvector_to_Cptr_double(cellDimsIn); if (not_intVector(PBCIn)) return NULL; PBC = pyvector_to_Cptr_int(PBCIn); if (not_doubleVector(fullScalarsIn)) return NULL; fullScalars = pyvector_to_Cptr_double(fullScalarsIn); if (not_doubleVector(fullVectors)) return NULL; /* construct array of positions of visible atoms */ visiblePos = malloc(3 * NVisibleIn * sizeof(double)); if (visiblePos == NULL) { PyErr_SetString(PyExc_MemoryError, "Could not allocate visiblePos"); return NULL; } for (i = 0; i < NVisibleIn; i++) { int index = visibleAtoms[i]; int ind3 = 3 * index; int i3 = 3 * i; visiblePos[i3 ] = pos[ind3 ]; visiblePos[i3 + 1] = pos[ind3 + 1]; visiblePos[i3 + 2] = pos[ind3 + 2]; } /* box visible atoms */ boxes = setupBoxes(maxBondDistance, PBC, cellDims); if (boxes == NULL) { free(visiblePos); return NULL; } boxstat = putAtomsInBoxes(NVisibleIn, visiblePos, boxes); if (boxstat) { free(visiblePos); return NULL; } /* build neighbour list */ maxSep2 = maxBondDistance * maxBondDistance; nebList = constructNeighbourList(NVisibleIn, visiblePos, boxes, cellDims, PBC, maxSep2); /* only required for building neb list */ free(visiblePos); freeBoxes(boxes); /* return if failed to build the neighbour list */ if (nebList == NULL) return NULL; /* allocate results structure */ results = malloc(NVisibleIn * sizeof(struct AtomStructureResults)); if (results == NULL) { PyErr_SetString(PyExc_MemoryError, "Could not allocate results"); freeNeighbourList(nebList, NVisibleIn); return NULL; } /* first calc q_lm for each atom over all m values */ complex_qlm(NVisibleIn, visibleAtoms, nebList, pos, cellDims, PBC, results); /* free neighbour list */ freeNeighbourList(nebList, NVisibleIn); /* calculate Q4 and Q6 */ calculate_Q(NVisibleIn, results); /* do filtering here, storing results along the way */ NVisible = 0; for (i = 0; i < NVisibleIn; i++) { int j; double q4 = results[i].Q4; double q6 = results[i].Q6; /* skip if not within the valid range */ if (filterQ4Enabled && (q4 < minQ4 || q4 > maxQ4)) continue; if (filterQ6Enabled && (q6 < minQ6 || q6 > maxQ6)) continue; /* store in visible atoms array */ visibleAtoms[NVisible] = visibleAtoms[i]; /* store calculated values */ scalarsQ4[NVisible] = q4; scalarsQ6[NVisible] = q6; /* update full scalars/vectors arrays */ for (j = 0; j < NScalars; j++) { int nj = j * NVisibleIn; fullScalars[nj + NVisible] = fullScalars[nj + i]; } for (j = 0; j < NVectors; j++) { int nj = j * NVisibleIn; DIND2(fullVectors, nj + NVisible, 0) = DIND2(fullVectors, nj + i, 0); DIND2(fullVectors, nj + NVisible, 1) = DIND2(fullVectors, nj + i, 1); DIND2(fullVectors, nj + NVisible, 2) = DIND2(fullVectors, nj + i, 2); } NVisible++; } /* free results memory */ free(results); return Py_BuildValue("i", NVisible); }
/*perform 1d fht for each line (first axis) of the input array */ static PyObject *fht2_%(ctype)s(PyObject *self, PyObject *args) { PyArrayObject *arr1, *oarr; int dim1, dim2; unsigned bit, i, j, k; CTYPE temp; if (!PyArg_ParseTuple(args, "O!O!", &PyArray_Type, &arr1, &PyArray_Type, &oarr)) return NULL; dim1 = arr1->dimensions[0]; dim2 = arr1->dimensions[1]; /* First loop on the first axis (time) */ #pragma omp parallel shared(arr1, oarr, dim1, dim2) private(i, j, k, bit, temp) #pragma omp for for (i = 0; i < dim1; i++) { /* Hadamard transform on the other axis*/ for (j = 0; j < dim2; j+=2) { k = j+1; DIND2(oarr, i, j) = DIND2(arr1, i, j) + DIND2(arr1, i, k); DIND2(oarr, i, k) = DIND2(arr1, i, j) - DIND2(arr1, i, k); } for (bit = 2; bit < dim2; bit <<= 1) { for (j = 0; j < dim2; j++) { if( (bit & j) == 0 ) { k = j | bit; temp = DIND2(oarr, i, j); DIND2(oarr, i, j) = DIND2(oarr, i, j) + DIND2(oarr, i, k); DIND2(oarr, i, k) = temp - DIND2(oarr, i, k); } } } } return Py_BuildValue("d", 1.); }