/******************************************************************************* * Construct neighbour lists for "ref" atoms where the neighbour lists contain * "input" atoms only. If separation is very close to 0 we don't add it. *******************************************************************************/ struct NeighbourList2 * constructNeighbourList2DiffPos(int NAtomsRef, double *refPos, int NAtomsInp, double *inpPos, double *cellDims, int *PBC, double maxSep) { int i; int boxstat; double approxBoxWidth; double maxSep2 = maxSep * maxSep; double rxb, ryb, rzb, sep2; struct Boxes *boxes; struct NeighbourList2 *nebList; /* box input atoms */ approxBoxWidth = maxSep; boxes = setupBoxes(approxBoxWidth, PBC, cellDims); if (boxes == NULL) return NULL; boxstat = putAtomsInBoxes(NAtomsInp, inpPos, boxes); if (boxstat) return NULL; /* allocate neb list */ nebList = malloc(NAtomsRef * sizeof(struct NeighbourList2)); if (nebList == NULL) { PyErr_SetString(PyExc_MemoryError, "Could not allocate nebList"); freeBoxes(boxes); return NULL; } /* initialise */ for (i = 0; i < NAtomsRef; i++) { nebList[i].chunk = 16; nebList[i].neighbourCount = 0; nebList[i].neighbour = NULL; } /* loop over ref atoms */ for (i = 0; i < NAtomsRef; i++) { int i3 = 3 * i; int j, boxNebListSize, boxIndex, boxNebList[27]; double rxa, rya, rza; /* atom position */ rxa = refPos[i3 ]; rya = refPos[i3 + 1]; rza = refPos[i3 + 2]; /* get box index of this atom */ boxIndex = boxIndexOfAtom(rxa, rya, rza, boxes); if (boxIndex < 0) { freeNeighbourList2(nebList, NAtomsRef); freeBoxes(boxes); return NULL; } /* find neighbouring boxes */ boxNebListSize = getBoxNeighbourhood(boxIndex, boxNebList, boxes); /* loop over box neighbourhood */ for (j = 0; j < boxNebListSize; j++) { int k; boxIndex = boxNebList[j]; /* loop over atoms in box */ for (k = 0; k < boxes->boxNAtoms[boxIndex]; k++) { int indexb = boxes->boxAtoms[boxIndex][k]; int indb3 = indexb * 3; /* atom position */ rxb = inpPos[indb3 ]; ryb = inpPos[indb3 + 1]; rzb = inpPos[indb3 + 2]; /* separation */ sep2 = atomicSeparation2(rxa, rya, rza, rxb, ryb, rzb, cellDims[0], cellDims[1], cellDims[2], PBC[0], PBC[1], PBC[2]); /* check if neighbour */ if (sep2 < maxSep2) { if (fabs(sep2 - 0.0) > 1e-6) { int addstat; double sep = sqrt(sep2); addstat = addAtomToNebList(i, indexb, sep, nebList); if (addstat) { freeNeighbourList2(nebList, NAtomsRef); freeBoxes(boxes); return NULL; } } } } } } freeBoxes(boxes); return nebList; }
/******************************************************************************* ** Check if an object has been picked *******************************************************************************/ static PyObject* pickObject(PyObject *self, PyObject *args) { int visibleAtomsDim, *visibleAtoms, vacsDim, *vacs, intsDim, *ints, onAntsDim, *onAnts, splitsDim, *splits; int *PBC, *specie, *refSpecie; double *pickPos, *pos, *refPos, *cellDims, *specieCovRad, *refSpecieCovRad, *result; PyArrayObject *visibleAtomsIn=NULL; PyArrayObject *vacsIn=NULL; PyArrayObject *intsIn=NULL; PyArrayObject *onAntsIn=NULL; PyArrayObject *splitsIn=NULL; PyArrayObject *pickPosIn=NULL; PyArrayObject *posIn=NULL; PyArrayObject *refPosIn=NULL; PyArrayObject *PBCIn=NULL; PyArrayObject *cellDimsIn=NULL; PyArrayObject *specieIn=NULL; PyArrayObject *refSpecieIn=NULL; PyArrayObject *specieCovRadIn=NULL; PyArrayObject *refSpecieCovRadIn=NULL; PyArrayObject *resultIn=NULL; int minSepIndex, minSepType; double approxBoxWidth, minSepRad, minSep2, minSep; /* parse and check arguments from Python */ if (!PyArg_ParseTuple(args, "O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!", &PyArray_Type, &visibleAtomsIn, &PyArray_Type, &vacsIn, &PyArray_Type, &intsIn, &PyArray_Type, &onAntsIn, &PyArray_Type, &splitsIn, &PyArray_Type, &pickPosIn, &PyArray_Type, &posIn, &PyArray_Type, &refPosIn, &PyArray_Type, &PBCIn, &PyArray_Type, &cellDimsIn, &PyArray_Type, &specieIn, &PyArray_Type, &refSpecieIn, &PyArray_Type, &specieCovRadIn, &PyArray_Type, &refSpecieCovRadIn, &PyArray_Type, &resultIn)) return NULL; if (not_intVector(visibleAtomsIn)) return NULL; visibleAtoms = pyvector_to_Cptr_int(visibleAtomsIn); visibleAtomsDim = (int) PyArray_DIM(visibleAtomsIn, 0); if (not_intVector(vacsIn)) return NULL; vacs = pyvector_to_Cptr_int(vacsIn); vacsDim = (int) PyArray_DIM(vacsIn, 0); if (not_intVector(intsIn)) return NULL; ints = pyvector_to_Cptr_int(intsIn); intsDim = (int) PyArray_DIM(intsIn, 0); if (not_intVector(onAntsIn)) return NULL; onAnts = pyvector_to_Cptr_int(onAntsIn); onAntsDim = (int) PyArray_DIM(onAntsIn, 0); if (not_intVector(splitsIn)) return NULL; splits = pyvector_to_Cptr_int(splitsIn); splitsDim = (int) PyArray_DIM(splitsIn, 0); if (not_doubleVector(pickPosIn)) return NULL; pickPos = pyvector_to_Cptr_double(pickPosIn); if (not_doubleVector(posIn)) return NULL; pos = pyvector_to_Cptr_double(posIn); if (not_doubleVector(refPosIn)) return NULL; refPos = pyvector_to_Cptr_double(refPosIn); 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_intVector(specieIn)) return NULL; specie = pyvector_to_Cptr_int(specieIn); if (not_intVector(refSpecieIn)) return NULL; refSpecie = pyvector_to_Cptr_int(refSpecieIn); if (not_doubleVector(specieCovRadIn)) return NULL; specieCovRad = pyvector_to_Cptr_double(specieCovRadIn); if (not_doubleVector(refSpecieCovRadIn)) return NULL; refSpecieCovRad = pyvector_to_Cptr_double(refSpecieCovRadIn); if (not_doubleVector(resultIn)) return NULL; result = pyvector_to_Cptr_double(resultIn); // this should be detected automatically depending on cell size... approxBoxWidth = 4.0; /* initialise */ minSep2 = 9999999.0; minSepIndex = -1; minSepRad = 0.0; minSepType = 0; /* pick atoms (if there are any) */ if (visibleAtomsDim > 0) { int i, boxIndex, boxNebList[27], boxstat; int boxNebListSize; double *visPos; struct Boxes *boxes; #ifdef DEBUG printf("PICKC: Picking atoms\n"); #endif /* vis atoms pos */ visPos = malloc(3 * visibleAtomsDim * sizeof(double)); if (visPos == NULL) { PyErr_SetString(PyExc_RuntimeError, "Could not allocate visPos"); return NULL; } for (i = 0; i < visibleAtomsDim; i++) { int i3 = 3 * i; int index = visibleAtoms[i]; int index3 = 3 * index; visPos[i3 ] = pos[index3 ]; visPos[i3 + 1] = pos[index3 + 1]; visPos[i3 + 2] = pos[index3 + 2]; } /* box vis atoms */ boxes = setupBoxes(approxBoxWidth, PBC, cellDims); if (boxes == NULL) { free(visPos); return NULL; } boxstat = putAtomsInBoxes(visibleAtomsDim, visPos, boxes); if (boxstat) { free(visPos); return NULL; } /* box index of picked pos */ boxIndex = boxIndexOfAtom(pickPos[0], pickPos[1], pickPos[2], boxes); if (boxIndex < 0) { free(visPos); freeBoxes(boxes); return NULL; } /* neighbouring boxes */ boxNebListSize = getBoxNeighbourhood(boxIndex, boxNebList, boxes); /* loop over neighbouring boxes, looking for nearest atom */ for (i = 0; i < boxNebListSize; i++) { int k; int checkBox = boxNebList[i]; for (k = 0; k < boxes->boxNAtoms[checkBox]; k++) { int index, realIndex; double sep2, rad; index = boxes->boxAtoms[checkBox][k]; /* atomic separation */ sep2 = atomicSeparation2(pickPos[0], pickPos[1], pickPos[2], visPos[3*index], visPos[3*index+1], visPos[3*index+2], cellDims[0], cellDims[1], cellDims[2], PBC[0], PBC[1], PBC[2]); /* need radius too */ realIndex = visibleAtoms[index]; rad = specieCovRad[specie[realIndex]]; if (sep2 < minSep2) { minSep2 = sep2; minSepIndex = index; minSepRad = rad; } } } /* free memory */ free(visPos); freeBoxes(boxes); } /* now check defects (if there are any) */ if (vacsDim + intsDim + onAntsDim + splitsDim > 0) { int i, NVis, count, boxNebListSize, minSepIsDefect; int boxIndex, boxNebList[27], boxstat; double *visPos, *visCovRad; struct Boxes *boxes; #ifdef DEBUG printf("PICKC: Picking defect\n"); #endif /* build positions array of all defects */ NVis = vacsDim + intsDim + onAntsDim + splitsDim; visPos = malloc(3 * NVis * sizeof(double)); if (visPos == NULL) { PyErr_SetString(PyExc_RuntimeError, "Could not allocate visPos"); return NULL; } visCovRad = malloc(NVis * sizeof(double)); if (visCovRad == NULL) { PyErr_SetString(PyExc_RuntimeError, "Could not allocate visCovRad"); free(visPos); return NULL; } /* add defects positions: vac then int then ant */ count = 0; for (i = 0; i < vacsDim; i++) { int c3 = 3 * count; int index = vacs[i]; int index3 = 3 * index; visPos[c3 ] = refPos[index3 ]; visPos[c3 + 1] = refPos[index3 + 1]; visPos[c3 + 2] = refPos[index3 + 2]; visCovRad[count++] = refSpecieCovRad[refSpecie[index]] * 1.2; // * 0.75; // multiply by 0.75 because vacs aren't full size (rendering.py) } for (i = 0; i < intsDim; i++) { int c3 = 3 * count; int index = ints[i]; int index3 = 3 * index; visPos[c3 ] = pos[index3 ]; visPos[c3 + 1] = pos[index3 + 1]; visPos[c3 + 2] = pos[index3 + 2]; visCovRad[count++] = specieCovRad[specie[index]]; } for (i = 0; i < onAntsDim; i++) { int c3 = 3 * count; int index = onAnts[i]; int index3 = 3 * index; visPos[c3 ] = pos[index3 ]; visPos[c3 + 1] = pos[index3 + 1]; visPos[c3 + 2] = pos[index3 + 2]; visCovRad[count++] = specieCovRad[specie[index]]; } for (i = 0; i < splitsDim / 3; i++) { int i3 = 3 * i; int index, c3, index3; index = splits[i3 ]; index3 = index * 3; c3 = count * 3; visPos[c3 ] = refPos[index3 ]; visPos[c3 + 1] = refPos[index3 + 1]; visPos[c3 + 2] = refPos[index3 + 2]; visCovRad[count++] = refSpecieCovRad[refSpecie[index]]; index = splits[i3 + 1]; index3 = index * 3; c3 = count * 3; visPos[c3 ] = pos[index3 ]; visPos[c3 + 1] = pos[index3 + 1]; visPos[c3 + 2] = pos[index3 + 2]; visCovRad[count++] = specieCovRad[specie[index]]; index = splits[i3 + 2]; index3 = index * 3; c3 = count * 3; visPos[c3 ] = pos[index3 ]; visPos[c3 + 1] = pos[index3 + 1]; visPos[c3 + 2] = pos[index3 + 2]; visCovRad[count++] = specieCovRad[specie[index]]; } /* box vis atoms */ boxes = setupBoxes(approxBoxWidth, PBC, cellDims); if (boxes == NULL) { free(visPos); free(visCovRad); return NULL; } boxstat = putAtomsInBoxes(NVis, visPos, boxes); if (boxstat) { free(visPos); free(visCovRad); return NULL; } /* box index of picked pos */ boxIndex = boxIndexOfAtom(pickPos[0], pickPos[1], pickPos[2], boxes); if (boxIndex < 0) { free(visPos); free(visCovRad); freeBoxes(boxes); return NULL; } /* neighbouring boxes */ boxNebListSize = getBoxNeighbourhood(boxIndex, boxNebList, boxes); /* loop over neighbouring boxes, looking for nearest atom */ minSepIsDefect = 0; for (i = 0; i < boxNebListSize; i++) { int k; int checkBox = boxNebList[i]; for (k = 0; k < boxes->boxNAtoms[checkBox]; k++) { int index; double sep2, rad; index = boxes->boxAtoms[checkBox][k]; /* atomic separation */ sep2 = atomicSeparation2(pickPos[0], pickPos[1], pickPos[2], visPos[3*index], visPos[3*index+1], visPos[3*index+2], cellDims[0], cellDims[1], cellDims[2], PBC[0], PBC[1], PBC[2]); /* need radius too */ rad = visCovRad[index]; if (sep2 < minSep2) { minSep2 = sep2; minSepIndex = index; minSepRad = rad; minSepIsDefect = 1; } } } if (minSepIsDefect) { /* picked type */ if (minSepIndex < vacsDim) { minSepType = 1; } else if (minSepIndex < vacsDim + intsDim) { minSepIndex -= vacsDim; minSepType = 2; } else if (minSepIndex < vacsDim + intsDim + onAntsDim) { minSepIndex -= vacsDim + intsDim; minSepType = 3; } else { minSepIndex -= vacsDim + intsDim + onAntsDim; minSepIndex = (int) (minSepIndex / 3); minSepType = 4; } } /* free memory */ freeBoxes(boxes); free(visPos); free(visCovRad); } /* min separation */ minSep = sqrt(minSep2); /* if separation is greater than radius, subtract radius, * otherwise set to zero (within radius is good enough for me) */ minSep = (minSep > minSepRad) ? minSep - minSepRad : 0.0; /* store result */ result[0] = minSepType; result[1] = minSepIndex; result[2] = minSep; #ifdef DEBUG printf("PICKC: End\n"); #endif return Py_BuildValue("i", 0); }
/******************************************************************************* ** 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); }
/******************************************************************************* ** Compute the histogram for the RDF *******************************************************************************/ static int computeHistogram(int NAtoms, int NVisible, int *visibleAtoms, double *pos, int *PBC, double *cellDims, int *sel1, int *sel2, double start, double finish, double interval, double *hist) { int i, errorCount, boxstat; double *visiblePos, approxBoxWidth; const double start2 = start * start; const double finish2 = finish * finish; struct Boxes *boxes; /* positions of visible atoms */ if (NAtoms == NVisible) visiblePos = pos; else { visiblePos = malloc(3 * NVisible * sizeof(double)); if (visiblePos == NULL) { PyErr_SetString(PyExc_MemoryError, "Could not allocate visiblePos"); return 1; } for (i = 0; i < NVisible; i++) { int index = visibleAtoms[i]; int i3 = 3 * i; int ind3 = 3 * index; visiblePos[i3 ] = pos[ind3 ]; visiblePos[i3 + 1] = pos[ind3 + 1]; visiblePos[i3 + 2] = pos[ind3 + 2]; } } /* spatial decomposition - box width must be at least `finish` */ approxBoxWidth = finish; boxes = setupBoxes(approxBoxWidth, PBC, cellDims); if (boxes == NULL) { if (NAtoms != NVisible) free(visiblePos); return 2; } boxstat = putAtomsInBoxes(NVisible, visiblePos, boxes); if (NAtoms != NVisible) free(visiblePos); if (boxstat) return 3; /* loop over visible atoms */ errorCount = 0; #pragma omp parallel for reduction(+: errorCount) num_threads(prefs_numThreads) for (i = 0; i < NVisible; i++) { int j, index, ind3, boxIndex, boxNebList[27], boxNebListSize; double rxa, rya, rza; /* skip if this atom is not in the first selection */ if (!sel1[i]) continue; /* the index of this atom in the pos array */ index = visibleAtoms[i]; /* position of this atom and its box index */ ind3 = index * 3; rxa = pos[ind3 ]; rya = pos[ind3 + 1]; rza = pos[ind3 + 2]; boxIndex = boxIndexOfAtom(rxa, rya, rza, boxes); if (boxIndex < 0) errorCount++; if (!errorCount) { /* find neighbouring boxes */ boxNebListSize = getBoxNeighbourhood(boxIndex, boxNebList, boxes); /* loop over the box neighbourhood */ for (j = 0; j < boxNebListSize; j++) { int k; int checkBox = boxNebList[j]; for (k = 0; k < boxes->boxNAtoms[checkBox]; k++) { int visIndex, index2, ind23; double sep2; /* the index of this atom in the visibleAtoms array */ visIndex = boxes->boxAtoms[checkBox][k]; /* skip if this atom is not in the second selection */ if (!sel2[visIndex]) continue; /* atom index */ index2 = visibleAtoms[visIndex]; /* skip if same atom */ if (index == index2) continue; /* atomic separation */ ind23 = index2 * 3; sep2 = atomicSeparation2(rxa, rya, rza, pos[ind23], pos[ind23 + 1], pos[ind23 + 2], cellDims[0], cellDims[1], cellDims[2], PBC[0], PBC[1], PBC[2]); /* put in bin */ if (sep2 >= start2 && sep2 < finish2) { int binIndex; double sep; sep = sqrt(sep2); binIndex = (int) ((sep - start) / interval); #pragma omp atomic hist[binIndex]++; } } } } } /* free memory */ freeBoxes(boxes); /* raise an exception if there were any errors */ if (errorCount) { PyErr_SetString(PyExc_RuntimeError, "computeHistogram failed; probably box index error (check stderr)"); return 4; } return 0; }
/******************************************************************************* * Search for defects and return the sub-system surrounding them *******************************************************************************/ int findDefects( int includeVacs, int includeInts, int includeAnts, int* defectList, int* NDefectsByType, int* vacancies, int* interstitials, int* antisites, int* onAntisites, int inclSpecDim, int* inclSpec, int exclSpecInputDim, int* exclSpecInput, int exclSpecRefDim, int* exclSpecRef, int NAtoms, char* specieList, int* specie, double* pos, int refNAtoms, char* specieListRef, int* specieRef, double* refPos, double *cellDims, int *PBC, double vacancyRadius, double inclusionRadius, double *minPos, double *maxPos, int verboseLevel, int debugDefects) { int i, exitLoop, k, j, index; double vacRad2, xpos, ypos, zpos; int boxNebList[27]; char symtemp[3], symtemp2[3]; int checkBox, refIndex, comp, boxIndex; double refxpos, refypos, refzpos; double sep2, incRad2, approxBoxWidth; int NDefects, NAntisites, NInterstitials, NVacancies; int *possibleVacancy, *possibleInterstitial; int *possibleAntisite, *possibleOnAntisite; int count, addToInt, skip; struct Boxes *boxes; if ( verboseLevel > 2) { printf("CLIB: finding defects\n"); printf(" vac rad %f\n", vacancyRadius); printf(" inc rad %f\n", inclusionRadius); } /* approx width, must be at least vacRad */ approxBoxWidth = 1.1 * vacancyRadius; /* box reference atoms */ boxes = setupBoxes(approxBoxWidth, minPos, maxPos, PBC, cellDims); putAtomsInBoxes(refNAtoms, refPos, boxes); /* allocate local arrays for checking atoms */ possibleVacancy = malloc( refNAtoms * sizeof(int) ); if (possibleVacancy == NULL) { printf("ERROR: Boxes: could not allocate possibleVacancy\n"); exit(1); } possibleInterstitial = malloc( NAtoms * sizeof(int) ); if (possibleInterstitial == NULL) { printf("ERROR: Boxes: could not allocate possibleInterstitial\n"); exit(1); } possibleAntisite = malloc( refNAtoms * sizeof(int) ); if (possibleAntisite == NULL) { printf("ERROR: Boxes: could not allocate possibleAntisite\n"); exit(1); } possibleOnAntisite = malloc( refNAtoms * sizeof(int) ); if (possibleOnAntisite == NULL) { printf("ERROR: Boxes: could not allocate possibleOnAntisite\n"); exit(1); } /* initialise arrays */ for ( i=0; i<NAtoms; i++ ) { possibleInterstitial[i] = 1; } for ( i=0; i<refNAtoms; i++ ) { possibleVacancy[i] = 1; possibleAntisite[i] = 1; } /* build local specie list */ vacRad2 = vacancyRadius * vacancyRadius; incRad2 = inclusionRadius * inclusionRadius; /* loop over all input atoms */ for ( i=0; i<NAtoms; i++ ) { int nboxes; xpos = pos[3*i]; ypos = pos[3*i+1]; zpos = pos[3*i+2]; /* get box index of this atom */ boxIndex = boxIndexOfAtom(xpos, ypos, zpos, boxes); /* find neighbouring boxes */ nboxes = getBoxNeighbourhood(boxIndex, boxNebList, boxes); /* loop over neighbouring boxes */ exitLoop = 0; for (j = 0; j < nboxes; j++) { if (exitLoop) { break; } checkBox = boxNebList[j]; /* now loop over all reference atoms in the box */ for ( k=0; k<boxes->boxNAtoms[checkBox]; k++ ) { refIndex = boxes->boxAtoms[checkBox][k]; /* if this vacancy has already been filled then skip to the next one */ if ( possibleVacancy[refIndex] == 0 ) { continue; } refxpos = refPos[3*refIndex]; refypos = refPos[3*refIndex+1]; refzpos = refPos[3*refIndex+2]; /* atomic separation of possible vacancy and possible interstitial */ sep2 = atomicSeparation2(xpos, ypos, zpos, refxpos, refypos, refzpos, cellDims[0], cellDims[1], cellDims[2], PBC[0], PBC[1], PBC[2]); /* if within vacancy radius, is it an antisite or normal lattice point */ if ( sep2 < vacRad2 ) { /* compare symbols */ symtemp[0] = specieList[2*specie[i]]; symtemp[1] = specieList[2*specie[i]+1]; symtemp[2] = '\0'; symtemp2[0] = specieListRef[2*specieRef[refIndex]]; symtemp2[1] = specieListRef[2*specieRef[refIndex]+1]; symtemp2[2] = '\0'; comp = strcmp( symtemp, symtemp2 ); if ( comp == 0 ) { /* match, so not antisite */ possibleAntisite[refIndex] = 0; } else { possibleOnAntisite[refIndex] = i; } /* not an interstitial or vacancy */ possibleInterstitial[i] = 0; possibleVacancy[refIndex] = 0; /* no need to check further for this (no longer) possible interstitial */ exitLoop = 1; break; } } } } /* free boxes structure */ freeBoxes(boxes); /* now box input atoms, approx width must be at least incRad */ approxBoxWidth = 1.1 * inclusionRadius; boxes = setupBoxes(approxBoxWidth, minPos, maxPos, PBC, cellDims); putAtomsInBoxes(NAtoms, pos, boxes); /* now classify defects */ NVacancies = 0; NInterstitials = 0; NAntisites = 0; count = 0; for ( i=0; i<refNAtoms; i++ ) { skip = 0; for (j=0; j<exclSpecRefDim; j++) { if (specieRef[i] == exclSpecRef[j]) { skip = 1; } } if (skip == 1) { continue; } /* vacancies */ if (possibleVacancy[i] == 1) { if (includeVacs == 1) { int nboxes; vacancies[NVacancies] = i; NVacancies++; /* find input atoms within inclusionRadius of this vacancy */ refxpos = refPos[3*i]; refypos = refPos[3*i+1]; refzpos = refPos[3*i+2]; boxIndex = boxIndexOfAtom(refxpos, refypos, refzpos, boxes); /* find neighbouring boxes */ nboxes = getBoxNeighbourhood(boxIndex, boxNebList, boxes); for (j = 0; j < nboxes; j++ ) { checkBox = boxNebList[j]; /* loop over atoms in box */ for ( k=0; k<boxes->boxNAtoms[checkBox]; k++ ) { index = boxes->boxAtoms[checkBox][k]; /* if already on defect list continue */ if (defectList[index] == 1) { continue; } /* if close to defect add to list */ xpos = pos[3*index]; ypos = pos[3*index+1]; zpos = pos[3*index+2]; sep2 = atomicSeparation2(xpos, ypos, zpos, refxpos, refypos, refzpos, cellDims[0], cellDims[1], cellDims[2], PBC[0], PBC[1], PBC[2]); if ( sep2 < incRad2 ) { defectList[index] = 1; count++; } } } } } /* antisites */ else if ( (possibleAntisite[i] == 1) && (includeAnts == 1) ) { int nboxes; antisites[NAntisites] = i; onAntisites[NAntisites] = possibleOnAntisite[i]; NAntisites++; /* find input atoms within inclusionRadius of this antisite */ refxpos = refPos[3*i]; refypos = refPos[3*i+1]; refzpos = refPos[3*i+2]; boxIndex = boxIndexOfAtom(refxpos, refypos, refzpos, boxes); /* find neighbouring boxes */ nboxes = getBoxNeighbourhood(boxIndex, boxNebList, boxes); for (j = 0; j < nboxes; j++) { checkBox = boxNebList[j]; /* loop over atoms in box */ for ( k=0; k<boxes->boxNAtoms[checkBox]; k++ ) { index = boxes->boxAtoms[checkBox][k]; /* if already on defect list continue */ if (defectList[index] == 1) { continue; } /* if close to defect add to list */ xpos = pos[3*index]; ypos = pos[3*index+1]; zpos = pos[3*index+2]; sep2 = atomicSeparation2(xpos, ypos, zpos, refxpos, refypos, refzpos, cellDims[0], cellDims[1], cellDims[2], PBC[0], PBC[1], PBC[2]); if ( sep2 < incRad2 ) { defectList[index] = 1; count++; } } } } } if (includeInts == 1) { for ( i=0; i<NAtoms; i++ ) { skip = 0; for (j=0; j<exclSpecInputDim; j++) { if (specie[i] == exclSpecInput[j]) { skip = 1; break; } } if (skip == 1) { continue; } addToInt = 0; for (j=0; j<inclSpecDim; j++) { if (specie[i] == inclSpec[j]) { addToInt = 1; break; } } /* interstitials */ if ( (possibleInterstitial[i] == 1) || (addToInt == 1) ) { int nboxes; interstitials[NInterstitials] = i; NInterstitials++; defectList[i] = 1; count++; /* find input atoms within inclusionRadius of this interstitial */ refxpos = pos[3*i]; refypos = pos[3*i+1]; refzpos = pos[3*i+2]; boxIndex = boxIndexOfAtom(refxpos, refypos, refzpos, boxes); /* find neighbouring boxes */ nboxes = getBoxNeighbourhood(boxIndex, boxNebList, boxes); for (j = 0; j < nboxes; j++) { checkBox = boxNebList[j]; /* loop over atoms in box */ for ( k=0; k<boxes->boxNAtoms[checkBox]; k++ ) { index = boxes->boxAtoms[checkBox][k]; /* if same atom continue */ if ( index == i ) { continue; } /* if already on defect list continue */ if (defectList[index] == 1) { continue; } /* if close to defect add to list */ xpos = pos[3*index]; ypos = pos[3*index+1]; zpos = pos[3*index+2]; sep2 = atomicSeparation2(xpos, ypos, zpos, refxpos, refypos, refzpos, cellDims[0], cellDims[1], cellDims[2], PBC[0], PBC[1], PBC[2]); if ( sep2 < incRad2 ) { defectList[index] = 1; count++; } } } } } } /* shift indexes to zero */ count = 0; for (i=0; i<NAtoms; i++) { if (defectList[i] == 1) { defectList[count] = i; count++; } } NDefects = NVacancies + NInterstitials + NAntisites; if ( verboseLevel > 2 ) { printf(" found %d defects\n", NDefects); printf(" %d vacancies\n", NVacancies); printf(" %d interstitials\n", NInterstitials); printf(" %d antisites\n", NAntisites); printf(" including %d atoms in sub-system\n", count); } NDefectsByType[0] = NDefects; NDefectsByType[1] = NVacancies; NDefectsByType[2] = NInterstitials; NDefectsByType[3] = NAntisites; freeBoxes(boxes); free(possibleVacancy); free(possibleInterstitial); free(possibleAntisite); free(possibleOnAntisite); return count; }