2 #include "../include/tracker.h"
3 #include "../include/fileIO.h"
4 #include "../include/minions.h"
5 #include "../include/constants.h"
6 #include "../include/vort.h"
9 * Contains all the glorious info you need to track vortices and see what they are up to.
15 * Determines the vortex separation at the centre of the lattice.
17 double vortSepAvg(const std::vector<std::shared_ptr<Vtx::Vortex> > &vArray, const std::shared_ptr<Vtx::Vortex> centre){
20 min = sqrt( pow(centre->getCoordsD().x - vArray[0]->getCoordsD().x,2) + pow(centre->getCoordsD().y - vArray[0]->getCoordsD().y,2));
21 for (int j=1; j<vArray.size(); ++j){
22 min_tmp = sqrt( pow(centre->getCoordsD().x - vArray[j]->getCoordsD().x,2) + pow(centre->getCoordsD().y - vArray[j]->getCoordsD().y,2));
23 if(min > min_tmp && min_tmp > 1e-7){//100nm length
31 * Finds the maxima of the optical lattice. Deprecated.
34 int findOLMaxima(int *marker, double *Vopt, double radius, int xDim, double* x){
40 for (i=1; i<xDim-1; ++i ){
41 for(j=1; j<xDim-1;++j){
42 if(sqrt(x[i]*x[i] + x[j]*x[j]) < radius){
43 gridValues[0] = Vopt[(i-1)*xDim + (j-1)];
44 gridValues[1] = Vopt[(i-1)*xDim + j];
45 gridValues[2] = Vopt[(i-1)*xDim + (j+1)];
46 gridValues[3] = Vopt[i*xDim + (j-1)];
47 gridValues[4] = Vopt[i*xDim + j];
48 gridValues[5] = Vopt[i*xDim + (j+1)];
49 gridValues[6] = Vopt[(i+1)*xDim + (j-1)];
50 gridValues[7] = Vopt[(i+1)*xDim + j];
51 gridValues[8] = Vopt[(i+1)*xDim + (j+1)];
52 if(fabs((gridValues[4]-Minions::maxValue(gridValues,9))/gridValues[4]) <= 1e-7){
53 //printf ("%d,%d\n",i,j);
54 (marker)[i*xDim + j] = 1;
57 mIndex[found] = index;
68 int findVortex(int *marker, const double2* wfc, double radius, int xDim,
69 const double* x, int timestep){
76 // #pragma omp parallel for private(j)
77 for (i=1; i<xDim-1; ++i ){
78 for(j=1; j<xDim-1;++j){
79 if(sqrt(x[i]*x[i] + x[j]*x[j]) < radius){
80 gridValues[0] = Minions::psi2(wfc[(i-1)*xDim + (j-1)]);
81 gridValues[1] = Minions::psi2(wfc[(i-1)*xDim + j]);
82 gridValues[2] = Minions::psi2(wfc[(i-1)*xDim + (j+1)]);
83 gridValues[3] = Minions::psi2(wfc[(i)*xDim + (j-1)]);
84 gridValues[4] = Minions::psi2(wfc[(i)*xDim + j]);
85 gridValues[5] = Minions::psi2(wfc[(i)*xDim + (j+1)]);
86 gridValues[6] = Minions::psi2(wfc[(i+1)*xDim + (j-1)]);
87 gridValues[7] = Minions::psi2(wfc[(i+1)*xDim + j]);
88 gridValues[8] = Minions::psi2(wfc[(i+1)*xDim + (j+1)]);
89 if(fabs((gridValues[4]-Minions::minValue(gridValues,9)) /
90 gridValues[4]) < 1e-7){
91 //printf ("%d,%d\n",i,j);
92 (marker)[i*xDim + j] = 1;
95 vIndex[found] = index;
105 * Phase winding method to determine vortex positions. Calculates the phase around a loop and checks if ~ +/-2Pi.
107 int findVortex(int *marker, const double2* wfc, double radius, int xDim, const double *x, int timestep){
108 double2 *g = (double2*) malloc(sizeof(double2)*4);
109 double *phiDelta = (double*) malloc(sizeof(double)*4);
112 cond_x = 0; cond_y = 0;
116 for ( i=0; i < xDim-1; ++i ){
117 for( j=0; j < xDim-1; ++j ){
118 if(sqrt(x[i]*x[i] + x[j]*x[j]) < radius){
119 g[0] = Minions::complexScale(
120 Minions::complexDiv( wfc[i*xDim + j],
121 wfc[(i+1)*xDim + j] ),
122 (Minions::complexMag(wfc[(i+1)*xDim+j])
123 / Minions::complexMag(wfc[i*xDim+j])));
124 g[1] = Minions::complexScale(
125 Minions::complexDiv(wfc[(i+1)*xDim+j],
126 wfc[(i+1)*xDim + (j+1)] ),
127 (Minions::complexMag(wfc[(i+1)*xDim+(j+1)])
128 / Minions::complexMag( wfc[(i+1)*xDim + j] )));
129 g[2] = Minions::complexScale(
130 Minions::complexDiv( wfc[(i+1)*xDim + (j+1)],
131 wfc[i*xDim + (j+1)] ),
132 ( Minions::complexMag( wfc[i*xDim + (j+1)])
133 / Minions::complexMag( wfc[(i+1)*xDim + (j+1)] )));
134 g[3] = Minions::complexScale(
135 Minions::complexDiv( wfc[i*xDim + (j+1)],
137 ( Minions::complexMag( wfc[i*xDim + j])
138 / Minions::complexMag( wfc[i*xDim + (j+1)] )));
139 for (int k=0; k<4; ++k){
140 phiDelta[k] = atan2( g[k].y, g[k].x );
141 if(phiDelta[k] <= -PI){
145 sum = phiDelta[0] + phiDelta[1] + phiDelta[2] + phiDelta[3];
146 rnd_value = lround(sum/(2*PI));
147 if( sum >= 1.9*PI && cond_x <= 0 && cond_y <= 0){
148 marker[i*xDim + j] = rnd_value;
151 cond_x = 2; cond_y = 2;
153 else if( sum <= -1.9*PI && cond_x <= 0 && cond_y <= 0 ) {
154 marker[i*xDim + j] = -rnd_value;
157 cond_x = 2; cond_y = 2;
164 free(g); free(phiDelta);
170 * Accepts matrix of vortex locations as argument, returns array of x,y coordinates of locations and first encountered vortex angle
173 void olPos(int *marker, int2 *olLocation, int xDim){
175 unsigned int counter=0;
176 for(i=0; i<xDim; ++i){
177 for(j=0; j<xDim; ++j){
178 if((marker)[i*xDim + j] == 1){
179 (olLocation)[ counter ].x=i;
180 (olLocation)[ counter ].y=j;
188 * Tests the phase winding of the wavefunction, looking for vortices
190 int phaseTest(int2 vLoc, const double2* wfc, int xDim){
192 double2 gridValues[4];
195 int i=vLoc.x, j=vLoc.y;
196 gridValues[0] = Minions::complexScale( Minions::complexDiv(wfc[i*xDim + j],wfc[(i+1)*xDim + j]), (Minions::complexMag(wfc[(i+1)*xDim + j]) / Minions::complexMag(wfc[i*xDim + j])));
197 gridValues[1] = Minions::complexScale( Minions::complexDiv(wfc[(i+1)*xDim + j],wfc[(i+1)*xDim + (j+1)]), (Minions::complexMag(wfc[(i+1)*xDim + (j+1)])/ Minions::complexMag(wfc[(i+1)*xDim + j])));
198 gridValues[2] = Minions::complexScale( Minions::complexDiv(wfc[(i+1)*xDim + (j+1)],wfc[i*xDim + (j+1)]), (Minions::complexMag(wfc[i*xDim + (j+1)]) / Minions::complexMag(wfc[(i+1)*xDim + (j+1)])));
199 gridValues[3] = Minions::complexScale( Minions::complexDiv(wfc[i*xDim + (j+1)],wfc[i*xDim + j]), (Minions::complexMag(wfc[i*xDim + j]) / Minions::complexMag(wfc[i*xDim + (j+1)])));
201 for (int k=0; k<4; ++k){
202 phiDelta[k] = atan2(gridValues[k].y,gridValues[k].x);
203 if(phiDelta[k] <= -PI){
207 sum = phiDelta[0] + phiDelta[1] + phiDelta[2] + phiDelta[3];
215 * Accepts matrix of vortex locations as argument, returns array of x,y coordinates of locations and first encountered vortex angle
217 void vortPos(const int *marker, std::vector<std::shared_ptr<Vtx::Vortex> > &vLocation, int xDim, const double2 *wfc){
219 unsigned int counter=0;
221 int2 coords; double2 coordsD;
222 coords.x=0; coords.y = 0;
223 coordsD.x=0.; coordsD.y = 0.;
225 for( i = 0; i < xDim; ++i){
226 for( j = 0; j < xDim; ++j){
227 if( abs((marker)[i*xDim + j]) >= 1){
228 coords.x = i; coords.y = j;
229 vLocation.push_back(std::make_shared<Vtx::Vortex>(coords, coordsD, marker[i*xDim + j], false, 0));
237 * Ensures the vortices are tracked and arranged in the right order based on minimum distance between previous and current positions
239 void vortArrange(std::vector<std::shared_ptr<Vtx::Vortex> > &vCoordsC, const std::vector<std::shared_ptr<Vtx::Vortex> > &vCoordsP){
242 for ( i = 0; i < vCoordsC.size(); ++i ){
243 dist = 0x7FFFFFFF; //arbitrary big value fo initial distance value
245 for ( j = i; j < vCoordsC.size() ; ++j){//Changed to C and P from num_vort[0] size for both. May be an issue here with inconsistent sizing
246 dist_t = ( (vCoordsP[i]->getCoordsD().x
247 - vCoordsC[j]->getCoordsD().x)
248 * (vCoordsP[i]->getCoordsD().x
249 - vCoordsC[j]->getCoordsD().x)
250 + (vCoordsP[i]->getCoordsD().y
251 - vCoordsC[j]->getCoordsD().y)
252 * (vCoordsP[i]->getCoordsD().y
253 - vCoordsC[j]->getCoordsD().y) );
259 std::swap(vCoordsC[index], vCoordsC[i]); // Swap the elements at the given positions. Remove call to Minions::coordSwap(vCoordsC,index,i);
264 * Determines the coords of the vortex closest to the central position. Useful for centering the optical lattice over v. lattice*
266 std::shared_ptr<Vtx::Vortex> vortCentre(const std::vector<std::shared_ptr<Vtx::Vortex> > &cArray, int xDim){
269 double valueTest, value = 0.0;
270 valX = (cArray)[0]->getCoordsD().x - ((xDim/2)-1);
271 valY = (cArray)[0]->getCoordsD().y - ((xDim/2)-1);
272 value = sqrt( valX*valX + valY*valY );//Calcs the sqrt(x^2+y^2) from central position. try to minimise this value
273 for ( i=1; i<cArray.size(); ++i ){
274 valX = (cArray)[i]->getCoordsD().x - ((xDim/2)-1);
275 valY = (cArray)[i]->getCoordsD().y - ((xDim/2)-1);
276 valueTest = sqrt(valX*valX + valY*valY);
277 if(value > valueTest){
282 return (cArray)[counter];
286 * Determines the angle of the vortex lattice relative to the x-axis
288 double vortAngle(const std::vector<std::shared_ptr<Vtx::Vortex>> &vortCoords, const std::shared_ptr<Vtx::Vortex> central){
290 double minVal=1e300;//(pow(central.x - vortCoords[0].x,2) + pow(central.y - vortCoords[0].y,2));
291 for (int i=0; i < vortCoords.size(); ++i){//Assuming healing length on the order of 2 um
292 if (minVal > (pow(central->getCoordsD().x - vortCoords[i]->getCoordsD().x,2) + pow(central->getCoordsD().y - vortCoords[i]->getCoordsD().y,2)) && std::abs(central->getCoordsD().x - vortCoords[i]->getCoordsD().x) > 2e-6 && std::abs(central->getCoordsD().y - vortCoords[i]->getCoordsD().y) > 2e-6){
293 minVal = (pow(central->getCoordsD().x - vortCoords[i]->getCoordsD().x,2) + pow(central->getCoordsD().y - vortCoords[i]->getCoordsD().y,2));
297 double ang=(fmod(atan2( (vortCoords[location]->getCoordsD().y - central->getCoordsD().y), (vortCoords[location]->getCoordsD().x - central->getCoordsD().x) ),PI/3));
298 printf("Angle=%e\n",ang);
301 //return PI/2 + fmod(atan2(vortCoords[location].y-central.y, vortCoords[location].x - central.x), PI/3);
302 //return PI/2 - sign*acos( ( (central.x - vortCoords[location].x)*(central.x - vortCoords[location].x) ) / ( minVal*(central.x - vortCoords[location].x) ) );
306 * Sigma of vortex lattice and optical lattice. Deprecated
309 double sigVOL(const std::vector<std::shared_ptr<Vtx::Vortex> > &vArr, const int2 *opLatt, const double *x){
311 double dx = std::abs(x[1]-x[0]);
312 for (int i=0; i<vArr.size(); ++i){
313 sigma += pow( std::abs( sqrt( (vArr[i]->getCoordsD().x - opLatt[i].x)*(vArr[i]->getCoordsD().x - opLatt[i].x) + (vArr[i]->getCoordsD().y - opLatt[i].y)*(vArr[i]->getCoordsD().y - opLatt[i].y) )*dx),2);
315 sigma /= vArr.size();
320 * Performs least squares fitting to get exact vortex core position.
322 void lsFit(std::vector<std::shared_ptr<Vtx::Vortex> > &vortCoords, const double2 *wfc, int xDim){
323 double2 *wfc_grid = (double2*) malloc(sizeof(double2)*4);
324 double2 *res = (double2*) malloc(sizeof(double2)*3);
326 double2 coordsAdjusted;
328 for(int ii=0; ii < vortCoords.size(); ++ii){
329 //vortCoords[ii]->getCoordsD().x = 0.0; vortCoords[ii]->getCoordsD().y = 0.0;
330 coordsAdjusted.x=0.; coordsAdjusted.y=0.;
332 wfc_grid[0] = wfc[vortCoords[ii]->getCoords().x*xDim + vortCoords[ii]->getCoords().y];
333 wfc_grid[1] = wfc[(vortCoords[ii]->getCoords().x + 1)*xDim + vortCoords[ii]->getCoords().y];
334 wfc_grid[2] = wfc[vortCoords[ii]->getCoords().x*xDim + (vortCoords[ii]->getCoords().y + 1)];
335 wfc_grid[3] = wfc[(vortCoords[ii]->getCoords().x + 1)*xDim + (vortCoords[ii]->getCoords().y + 1)];
337 for(int jj=0; jj<3; ++jj) {
338 res[jj].x = lsq[jj][0]*wfc_grid[0].x + lsq[jj][1]*wfc_grid[1].x + lsq[jj][2]*wfc_grid[2].x + lsq[jj][3]*wfc_grid[3].x;
339 res[jj].y = lsq[jj][0]*wfc_grid[0].y + lsq[jj][1]*wfc_grid[1].y + lsq[jj][2]*wfc_grid[2].y + lsq[jj][3]*wfc_grid[3].y;
342 //Solve Ax=b here. A = res[0,1], b = - res[2]. Solution -> X
343 det = 1.0/(res[0].x*res[1].y - res[0].y*res[1].x);
344 R.x = det*(res[1].y*res[2].x - res[0].y*res[2].y);
345 R.y = det*(-res[1].x*res[2].x + res[0].x*res[2].y);
346 coordsAdjusted.x = vortCoords[ii]->getCoords().x - R.x;
347 coordsAdjusted.y = vortCoords[ii]->getCoords().y - R.y;
348 vortCoords[ii]->updateCoordsD(coordsAdjusted);
352 void updateVortices(std::shared_ptr<Vtx::VtxList> vLCurrent, std::shared_ptr<Vtx::VtxList> &vLPrev){
353 //Iterate through the previous vortices, and compare the distances
354 for (auto vtxPrev : vLPrev->getVortices()) {
355 auto vtxMin = vLCurrent->minDistPair(vtxPrev, 1);
356 //If the vortex has a min-pairing, and has a UID < 0 then we can assign it the same UID as the paired vortex
357 if (vtxMin.second != nullptr && vtxMin.second->getUID() < 0 ) {
358 vtxMin.second->updateUID(vtxPrev->getUID());
359 vtxMin.second->updateIsOn(true);
361 //If no pairing found, then the vortex has disappeared or been killed. Switch it off, and add it to the current list with the given UID
363 vtxPrev->updateIsOn(false);
364 vLCurrent->addVtx(vtxPrev);//Will this cause trouble? Maybe rethink the UID determination
367 //Find new vortices, assign them UIDs and switch them on
368 for (auto v: vLCurrent->getVortices()) {
369 if (v->getUID() < 0){
370 v->updateUID(vLCurrent->getMax_Uid()++);
374 //Sort the list based on vortex UIDS. This may not be necessary, but helps for now with debugging things
376 vLCurrent->getVortices().begin(),
377 vLCurrent->getVortices().end(),
378 []( std::shared_ptr<Vtx::Vortex> a,
379 std::shared_ptr<Vtx::Vortex> b) {
380 return b->getUID() < a->getUID();
382 //Overwrite previous list with current list.
383 vLPrev->getVortices().swap(vLCurrent->getVortices());