void approximatedNormals(const pointSet& mesh, vector<int> neighb, int pnb, double& nx_out, double& ny_out) { if (mesh.getBND(pnb)==0) throw mfpmExcept(0); int NP = neighb.size(); double sl2 = mesh.getSL(pnb); // New approach double sumX = 0, sumY = 0; double nx, ny; int count = 0; for (int i=0; i<NP; i++) { if (pnb!=neighb[i] ) { nx = (mesh.y(pnb)-mesh.y(neighb[i])); ny = -(mesh.x(pnb)-mesh.x(neighb[i])); double weight = exp(-5.0* (nx*nx+ny*ny) / sl2); double length = sqrt(nx*nx+ny*ny); nx /= length; ny /= length; if ( nx*mesh.getNormal(0,pnb) + ny*mesh.getNormal(1,pnb) < 0) { nx *= -1.0; ny *= -1.0; } sumX += nx*weight; sumY += ny*weight; } } sumX /= NP-1; sumY /= NP-1; double length = sqrt(sumX*sumX+sumY*sumY); if (length==0) throw mfpmExcept(1000); nx_out = sumX / length; ny_out = sumY / length; }
int partialNeumannMatEntry(const pointSet& mesh, int pnb, const Array& active, Array& entries, bool forceLowOrder) { int NP = mesh.getNIDX(pnb); double b[NP]; double A[6*NP]; double weight[NP]; int arrayEntry[NP]; if (NP < 4) throw mfpmExcept(20); double sl2 = pow(mesh.getSL(pnb),2); b[0] = 0*3.0 / mesh.getSL(pnb); b[1] = 0.0; b[2] = mesh.getNormal(0,pnb); b[3] = mesh.getNormal(1,pnb); b[4] = 0.0; b[5] = 0.0; b[6] = 0.0; int orderFac = 6; if (NP<6 | forceLowOrder) orderFac = 4; int idx, mi; int diagEntry=0; double h, k; int cnt = 0; // Store matrix in Fortran format for (int i=0; i<NP; i++) { idx = mesh.getIDX(pnb,i); mi = orderFac*cnt; if (idx!=pnb) { if (active(i) > 0.5) { h = mesh.x(idx) - mesh.x(pnb); k = mesh.y(idx) - mesh.y(pnb); weight[cnt] = exp(-2.0 * (h*h+k*k)/sl2 ); A[mi+0] = 0.0; A[mi+1] = 1.0 * weight[cnt]; A[mi+2] = h * weight[cnt]; A[mi+3] = k * weight[cnt]; if (orderFac>4) { A[mi+4] = h*h * weight[cnt]; A[mi+5] = h*k * weight[cnt]; A[mi+6] = k*k * weight[cnt]; } arrayEntry[cnt] = i; cnt++; } } else { weight[cnt] = 1.0; A[mi+0] = 1.0; A[mi+1] = 1.0; A[mi+2] = 0.0; A[mi+3] = 0.0; if (orderFac>4) { A[mi+4] = 0.0; A[mi+5] = 0.0; } arrayEntry[cnt] = i; cnt++; } } int n = orderFac; int m = cnt; double work[2*(m+n)]; int info, workl = 2*(m+n); int one = 1; char TN[] ="N"; dgels_(TN, &n, &m, &one, A, &n, b, &m, work, &workl, &info); if (info!=0) { cout << "Error solving least squares: laplaceMatEntry!" << endl; throw mfpmExcept(27); } entries = 0.0; for (int i=0; i<cnt; i++) { entries(arrayEntry[i]) = b[i]*weight[i]; } //~ // Test operator: //~ double tmp = entries(diagEntry); //~ for (int i=0; i<NP; i++) //~ { //~ if (abs(entries(i))>tmp) //~ { //~ //cout << "Invalid Neumann matrix entries!!" << endl; //~ //return -1; //~ } //~ } //~ double sum = 0; //~ for (int i=0; i<NP; i++) //~ { //~ idx = mesh.getIDX(pnb,i); //~ sum += entries(i)*(mesh.x(idx)+mesh.y(idx)); //~ } //~ if ( (sum - mesh.getNormal(0,pnb) - mesh.getNormal(1,pnb)) > 1e-7 ) //~ { //~ //cout << "Invalid Neumann matrix entries!!" << endl; //~ return -2; //~ } return 0; }
int neumannMatEntry(const pointSet& mesh, int pnb, Array& entries, bool forceLowOrder) { int NP = mesh.getNIDX(pnb); double b[NP]; double A[6*NP]; double weight[NP]; if (NP < 4) throw mfpmExcept(20); double sl2 = pow(mesh.getSL(pnb),2); b[0] = 3.0 / mesh.getSL(pnb); b[1] = 0.0; b[2] = mesh.getNormal(0,pnb); b[3] = mesh.getNormal(1,pnb); b[4] = 0.0; b[5] = 0.0; int orderFac = 6; if (NP<6 | forceLowOrder) orderFac = 4; int idx, mi; int diagEntry=0; double h, k; // Store matrix in Fortran format for (int i=0; i<NP; i++) { idx = mesh.getIDX(pnb,i); mi = orderFac*i; if (idx!=pnb) { h = mesh.x(idx) - mesh.x(pnb); k = mesh.y(idx) - mesh.y(pnb); weight[i] = exp(-2.0 * (h*h+k*k)/sl2 ); A[mi+0] = 0.0; A[mi+1] = 1.0 * weight[i]; A[mi+2] = h * weight[i]; A[mi+3] = k * weight[i]; if (orderFac>4) { A[mi+4] = h*h * weight[i]; A[mi+5] = k*k * weight[i]; } } else { diagEntry = i; weight[i] = 1.0; A[mi+0] = 1.0; A[mi+1] = 1.0; A[mi+2] = 0.0; A[mi+3] = 0.0; if (orderFac>4) { A[mi+4] = 0.0; A[mi+5] = 0.0; } } } int n = orderFac; int m = NP; double work[m+n]; int info, workl = m+n; int one = 1; char TN[] ="N"; dgels_(TN, &n, &m, &one, A, &n, b, &m, work, &workl, &info); if (info!=0) { cout << "Error solving least squares: laplaceMatEntry!" << endl; throw mfpmExcept(27); } for (int i=0; i<NP; i++) { entries(i) = b[i]*weight[i]; } // Test operator: double tmp = entries(diagEntry); for (int i=0; i<NP; i++) { if (abs(entries(i))>tmp) { //cout << "Invalid Neumann matrix entries!!" << endl; //return -1; } } double sum = 0; for (int i=0; i<NP; i++) { idx = mesh.getIDX(pnb,i); sum += entries(i)*(mesh.x(idx)+mesh.y(idx)); } if ( (sum - mesh.getNormal(0,pnb) - mesh.getNormal(1,pnb)) > 1e-7 ) { //cout << "Invalid Neumann matrix entries!!" << endl; return -2; } return 0; }