void sefield::TetMesh::fill_ve_vec(set<VertexElement*> & veset, vector<VertexElement*> & vevec, queue<VertexElement*> & vequeue, uint ncons, VertexElement ** nbrs) { //cout << "Veset size: " << veset.size(); vector<uint>newindcs=std::vector<uint>(); for (uint i=0; i < ncons; ++i) { bool inserted = veset.insert(nbrs[i]).second; if (inserted) { newindcs.push_back(i); // This is the important one- in a vector to keep the ordering vevec.push_back(nbrs[i]); // And add to the queue too, to find their neighbours: vequeue.push(nbrs[i]); } } // Go to the next element in the queue if (vequeue.empty() == true) return; else { VertexElement * nextve = vequeue.front(); vequeue.pop(); VertexElement ** newneighbs = nextve->getNeighbours(); uint nextcons = nextve->getNCon(); fill_ve_vec(veset, vevec, vequeue, nextcons, newneighbs); } /* for (uint i=0; i < newindcs.size(); ++i) { VertexElement ** newneighbs = nbrs[newindcs[i]]->getNeighbours(); uint newcons = nbrs[newindcs[i]]->getNCon(); fill_ve_vec(veset, vevec, newcons, newneighbs, false); } */ }
void sefield::TetMesh::axisOrderElements(uint opt_method, std::string const & opt_file_name) { // Now this method provides a choice between Stefan and Robert's method // and the new method by Iain. The original method is fast and suffices for // simple geometries, Iain's method is superior and important for complex // geometries, but slow. if (opt_file_name != "") { std::fstream opt_file; opt_file.open(opt_file_name.c_str(), std::fstream::in | std::fstream::binary); opt_file.seekg(0); uint nelems = 0; opt_file.read((char*)&nelems, sizeof(uint)); if (pElements.size() != nelems) { std::ostringstream os; os << "optimal data mismatch with simulator parameters: sefield::Tetmesh::nelems, "; os << nelems << ":" << pElements.size(); throw steps::ArgErr(os.str()); } opt_file.read((char*)pVertexPerm, sizeof(uint) * nelems); VertexElementPVec elements_temp = pElements; for (uint vidx = 0; vidx < nelems; ++vidx) { VertexElementP vep = elements_temp[vidx]; // sanity check assert(vep->getIDX() == vidx); uint new_idx = pVertexPerm[vidx]; pElements[new_idx] = vep; } reindexElements(); reordered(); opt_file.close(); return; } if (opt_method == 2) { // / / / / / / / / / / / / / / NEW / / / / / / / / / / / / / / / / / / // // LOOPING OVER ALL VERTICES, APPLYING THE WALK METHOD AND FINDING WHICH // STARTING VERTEX GIVES THE LOWEST MATRIX WIDTH. uint pNVerts = pElements.size(); // the best vertex(narrowest width) uint bestone = 0; uint bestwidth = pNVerts; std::vector<VertexElement*> orig_indices = pElements; stringstream ss; ss << "\nFinding optimal vertex indexing. This can take some time..."; cout << ss.str() << endl; for (uint vidx = 0; vidx < pNVerts; ++vidx) { set<VertexElement*> verteleset = set<VertexElement*>(); vector<VertexElement*> vertelevec = vector<VertexElement*>(); queue<VertexElement*> vertelqueue = queue<VertexElement*>(); verteleset.insert(orig_indices[vidx]); vertelevec.push_back(orig_indices[vidx]); uint ve0ncons = orig_indices[vidx]->getNCon(); VertexElement ** ve0neighbs = orig_indices[vidx]->getNeighbours(); fill_ve_vec(verteleset, vertelevec, vertelqueue, ve0ncons, ve0neighbs); pElements.clear(); vector<VertexElement*>::iterator vertele_end = vertelevec.end(); uint ielt = 0; for (vector<VertexElement*>::iterator vertele = vertelevec.begin(); vertele != vertele_end; ++vertele) { pElements.push_back(*vertele); pVertexPerm[(*vertele)->getIDX()]=ielt; ielt++; } // Note: this will reorder the vertex indices as we go- not a problem in this loop // but they must be reset for the final index setting to work reindexElements(); uint maxdi = 0; for (int iv = 0; iv < pNVerts; ++iv) { VertexElement* ve = getVertex(iv); int ind = ve->getIDX(); for (int i = 0; i < ve->getNCon(); ++i) { int inbr = ve->nbrIdx(i); int di = ind - inbr; if (di < 0) { di = -di; } if (di > maxdi) { maxdi = di; } } } if (maxdi < bestwidth) { bestone = vidx; bestwidth = maxdi; //cout << "\nOriginal vertex "<< vidx << " gives banded matrix half-width " << maxdi; } } // reset the vertex indices to their original value: important for (uint v = 0; v < pNVerts; ++v) { orig_indices[v]->setIDX(v); } set<VertexElement*> verteleset = set<VertexElement*>(); vector<VertexElement*> vertelevec = vector<VertexElement*>(); queue<VertexElement*> vertelqueue = queue<VertexElement*>(); verteleset.insert(orig_indices[bestone]); vertelevec.push_back(orig_indices[bestone]); uint ve0ncons = orig_indices[bestone]->getNCon(); VertexElement ** ve0neighbs = orig_indices[bestone]->getNeighbours(); fill_ve_vec(verteleset, vertelevec, vertelqueue, ve0ncons, ve0neighbs); pElements.clear(); vector<VertexElement*>::iterator vertele_end = vertelevec.end(); uint ielt = 0; for (vector<VertexElement*>::iterator vertele = vertelevec.begin(); vertele != vertele_end; ++vertele) { pElements.push_back(*vertele); pVertexPerm[(*vertele)->getIDX()]=ielt; ielt++; } } // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / // else if (opt_method == 1) { /* THIS ORIGINAL CODE REPLACED WITH NEW 'WALKING' METHOD. A DRAMATIC REDUCTION IN BAND HALF-WIDTHS FOR COMPLEX 3D MESHES. This is not the end of the story: TODO investigate whether reordering a vertices neighbour's for the queue by distance will improve again. */ std::vector<double> com = centerOfMass(); double ** m = new double*[3]; for (uint i = 0; i < 3; i++) { m[i] = new double[3]; m[i][0] = 0.0; m[i][1] = 0.0; m[i][2] = 0.0; } for (uint ivert = 0; ivert < countVertices(); ivert++) { VertexElement* ve = getVertex(ivert); double x = ve->getX() - com[0]; double y = ve->getY() - com[1]; double z = ve->getZ() - com[2]; m[0][0] += x * x; m[0][1] += x * y; m[0][2] += x * z; m[1][0] += y * x; m[1][1] += y * y; m[1][2] += y * z; m[2][0] += z * x; m[2][1] += z * y; m[2][2] += z * z; } uint iret; double gamma; double evec[3]; mainEvec(3, m, &iret, &gamma, evec); if (iret != 1) { cout << "\nWarning - eigenvalue faliure " << endl; } for (uint i = 0; i < 3; i++) { delete[] m[i]; } delete[] m; double vx = evec[0]; double vy = evec[1]; double vz = evec[2]; vx += 1.e-8; vy += 1.e-9; vz += 1.e-10; stringstream ss; ss << "aligning to axis " << vx << " " << vy << " " << vz << endl; //cout << ss.str(); map<double, VertexElement*> hm; //vector<double> da; for (uint ielt = 0; ielt < countVertices(); ielt++) { VertexElement * ve = getVertex(ielt); double d = vx * ve->getX() + vy * ve->getY() + vz * ve->getZ(); hm[d] = ve; //da.push_back(d); } //sort(da.begin(), da.end()); pElements.clear(); uint ielt = 0; map<double, VertexElement*>::const_iterator iter = hm.begin(); while (iter != hm.end()) { double d = iter->first; pElements.push_back(hm[d]); ++iter; // pVertexPerm[i] contains the new index in the elements array // for the vertex that was originally at index i pVertexPerm[hm[d]->getIDX()] = ielt; ielt++; } } else { std::ostringstream os; os << "Unknown optimization method.\n"; throw steps::ArgErr(os.str()); } reindexElements(); reordered(); }