From 04cebe7fff58702e1a06aa89a992d1132444518a Mon Sep 17 00:00:00 2001 From: lschulze <lschulze@mpi-cbg.de> Date: Fri, 6 May 2022 15:36:58 +0200 Subject: [PATCH] Add and adjust things --- src/level_set/particle_cp/particle_cp.hpp | 172 +++++++++++++--------- 1 file changed, 102 insertions(+), 70 deletions(-) diff --git a/src/level_set/particle_cp/particle_cp.hpp b/src/level_set/particle_cp/particle_cp.hpp index a5c2287d..382eedaa 100644 --- a/src/level_set/particle_cp/particle_cp.hpp +++ b/src/level_set/particle_cp/particle_cp.hpp @@ -48,6 +48,8 @@ struct Redist_options int compute_normals = 0; int compute_curvatures = 0; + + int write_sdf = 1; }; // Add new polynomial degrees here in case new interpolation schemes are implemented. @@ -75,20 +77,21 @@ public: void run_redistancing() { - std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); + //std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); detect_surface_particles(); - std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); - std::cout << "Time difference for detection = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << "[µs]" << std::endl; + //std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); + //std::cout << "Time difference for detection = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << "[µs]" << std::endl; - begin = std::chrono::steady_clock::now(); + //begin = std::chrono::steady_clock::now(); interpolate_sdf_field(); - end = std::chrono::steady_clock::now(); - std::cout << "Time difference for "<<polynomialDegree<<" interpolation = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << "[µs]" << std::endl; + //end = std::chrono::steady_clock::now(); + //std::cout << "Time difference for "<<polynomialDegree<<" interpolation = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << "[µs]" << std::endl; - begin = std::chrono::steady_clock::now(); + //begin = std::chrono::steady_clock::now(); find_closest_point(vd_in, vd_s); - end = std::chrono::steady_clock::now(); - std::cout << "Time difference for optimization = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << "[µs]" << std::endl; + //std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); + //std::cout << "Time difference for optimization = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << "[µs]" << std::endl; + //std::cout << "Time difference for pcp redistancing = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << "[µs]" << std::endl; } void run_optimization() @@ -123,6 +126,9 @@ private: (dim == 2 && std::is_same<polynomial_degree,taylor4>::value) ? 15 : (dim == 3 && std::is_same<polynomial_degree,taylor4>::value) ? 35 : 1; + int dim_r = dim; + int n_c_r = n_c; + particles_surface<dim, n_c> vd_s; double r_cutoff2; std::string polynomialDegree; @@ -153,6 +159,12 @@ private: while (part.isNext()) { vect_dist_key_dx akey = part.get(); + // depending on the application this can spare computational effort + if (std::abs(vd_in.template getProp<vd_in_sdf>(akey)) > redistOptions.sampling_radius) + { + ++part; + continue; + } int surfaceflag = 0; int sgn_a = return_sign(vd_in.template getProp<vd_in_sdf>(akey)); Point<dim,double> xa = vd_in.getPos(akey); @@ -215,6 +227,9 @@ private: // within the loop itself. void interpolate_sdf_field() { + int message_insufficient_support = 0; + int message_projection_fail = 0; + vd_s.template ghost_get<vd_s_sdf>(); int verbose = 0; auto NN_s = vd_s.getCellList(sqrt(r_cutoff2)); @@ -236,7 +251,6 @@ private: const int num_neibs_a = vd_s.template getProp<num_neibs>(a); Point<dim, double> xa = vd_s.getPos(a); int neib = 0; - // initialize monomial basis functions m, Vandermonde row builder vrb, Vandermonde matrix V, the right-hand // side vector phi and the solution vector that contains the coefficients of the interpolation polynomial, c. @@ -265,7 +279,7 @@ private: // do nothing as it has already been initialized like this } - if(m.size() > num_neibs_a) std::cout<<"warning: less number of neighbours than required for interpolation for particle "<<a.getKey()<<std::endl; + if(m.size() > num_neibs_a) message_insufficient_support = 1; VandermondeRowBuilder<dim, double> vrb(m); @@ -276,6 +290,7 @@ private: // iterate over the support of the central particle, in order to build the Vandermonde matrix and the // right-hand side vector auto Np = NN_s.template getNNIterator<NO_CHECK>(NN_s.getCell(vd_s.getPos(a))); + while(Np.isNext()) { vect_dist_key_dx b = Np.get(); @@ -283,24 +298,24 @@ private: Point<dim, double> dr = xa - xb; double r2 = norm2(dr); - if (r2 > r_cutoff2) - { - ++Np; - continue; - } - - // debug given data - //std::cout<<std::setprecision(15)<<xb[0]<<"\t"<<xb[1]<<"\t"<<vd.getProp<sdf>(b)<<std::endl; - //xb[0] = 0.1; - //xb[1] = 0.5; - //xb[2] = 3.0; - - // Fill phi-vector from the right hand side - phi[neib] = vd_s.template getProp<vd_s_sdf>(b); - vrb.buildRow(V, neib, xb, 1.0); - - ++neib; - ++Np; + if (r2 < r_cutoff2) + { + // debug given data + //std::cout<<std::setprecision(15)<<xb[0]<<"\t"<<xb[1]<<"\t"<<vd.getProp<sdf>(b)<<std::endl; + //xb[0] = 0.1; + //xb[1] = 0.5; + //xb[2] = 3.0; + //std::cout<<"hya?"<<std::endl; + // Fill phi-vector from the right hand side + //std::cout<<num_neibs_a<<std::endl; + + phi[neib] = vd_s.template getProp<vd_s_sdf>(b); + //std::cout<<"or hya?"<<std::endl; + vrb.buildRow(V, neib, xb, 1.0); + + ++neib; + } + ++Np; } // solve the system of equations using an orthogonal decomposition (if I am not mistaken, this is @@ -321,10 +336,10 @@ private: // double incr; // this is an optional variable in case the iterations are aborted depending on the magnitude // of the increment instead of the magnitude of the polynomial value and the number of iterations. - EMatrix<double, Eigen::Dynamic, 1> grad_p(dim, 1); + EMatrix<double, Eigen::Dynamic, 1> grad_p(dim_r, 1); double grad_p_mag2; - EMatrix<double, Eigen::Dynamic, 1> x(dim, 1); + EMatrix<double, Eigen::Dynamic, 1> x(dim_r, 1); for(int k = 0; k < dim; k++) x[k] = xa[k]; double p = get_p(x, c, polynomialDegree); int k_project = 0; @@ -343,18 +358,18 @@ private: ++k_project; } - if (k_project == redistOptions.max_iter) std::cout<<"Warning: Newton-style projections towards the interface do not satisfy given tolerance."<<std::endl; + if (k_project == redistOptions.max_iter) message_projection_fail = 1; // store the resulting sample point on the surface at the central particle. for(int k = 0; k < dim; k++) vd_s.template getProp<vd_s_sample>(a)[k] = x[k]; // debugging stuff: //if (a.getKey() == 5424) verbose = 1; - //verbose = 1; + //verbose = 0; if (verbose) { std::cout<<"VERBOSE"<<std::endl; - EMatrix<double, Eigen::Dynamic, 1> xaa(dim,1); + EMatrix<double, Eigen::Dynamic, 1> xaa(dim_r,1); for(int k = 0; k < dim; k++) xaa[k] = xa[k]; //double curvature = get_dpdxdx(xaa, c) + get_dpdydy(xaa, c); // matlab debugging stuff: @@ -376,6 +391,11 @@ private: ++part; } + if (message_insufficient_support) std::cout<<"Warning: less number of neighbours than required for interpolation" + <<" for some particles"<<std::endl; + if (message_projection_fail) std::cout<<"Warning: Newton-style projections towards the interface do not satisfy" + <<" given tolerance for some particles"<<std::endl; + } // This function now finds the exact closest point on the surface to any given particle. @@ -396,24 +416,33 @@ private: vd_s.template ghost_get<vd_s_close_part,vd_s_sample,interpol_coeff>(); auto NN_s = vd_s.getCellList(redistOptions.sampling_radius); - auto part = vd_in.getDomainIterator(); //todo: include the sampling radius somewhere (bandwidth) + auto part = vd_in.getDomainIterator(); int verbose = 0; + int message_step_limitation = 0; + int message_convergence_problem = 0; // do iteration over all query particles while (part.isNext()) { vect_dist_key_dx a = part.get(); + // this is somewhat usecase + if (std::abs(vd_in.template getProp<vd_in_sdf>(a)) > redistOptions.sampling_radius) + { + ++part; + continue; + } + // initialise all variables specific to the query particle - EMatrix<double, Eigen::Dynamic, 1> xa(dim, 1); + EMatrix<double, Eigen::Dynamic, 1> xa(dim_r, 1); for(int k = 0; k < dim; k++) xa[k] = vd_in.getPos(a)[k]; double val; // spatial variable that is optimized - EMatrix<double, Eigen::Dynamic, 1> x(dim,1); + EMatrix<double, Eigen::Dynamic, 1> x(dim_r,1); // Increment variable containing the increment of 2 spatial variables + 1 Lagrange multiplier - EMatrix<double, Eigen::Dynamic, 1> dx(dim + 1, 1); + EMatrix<double, Eigen::Dynamic, 1> dx(dim_r + 1, 1); for(int k = 0; k < (dim + 1); k++) dx[k] = 1.0; // Lagrange multiplier lambda @@ -421,21 +450,21 @@ private: // values regarding the gradient of the Lagrangian and the Hessian of the Lagrangian, which contain // derivatives of the constraint function also. double p = 0; - EMatrix<double, Eigen::Dynamic, 1> grad_p(dim, 1); + EMatrix<double, Eigen::Dynamic, 1> grad_p(dim_r, 1); for(int k = 0; k < dim; k++) grad_p[k] = 0.0; - EMatrix<double, Eigen::Dynamic, Eigen::Dynamic> H_p(dim, dim); + EMatrix<double, Eigen::Dynamic, Eigen::Dynamic> H_p(dim_r, dim_r); for(int k = 0; k < dim; k++) { for(int l = 0; l < dim; l++) H_p(k, l) = 0.0; } - EMatrix<double, Eigen::Dynamic, 1> c(n_c, 1); + EMatrix<double, Eigen::Dynamic, 1> c(n_c_r, 1); for (int k = 0; k < n_c; k++) c[k] = 0.0; // f(x, lambda) is the Lagrangian, initialize its gradient and Hessian - EMatrix<double, Eigen::Dynamic, 1> nabla_f(dim + 1, 1); - EMatrix<double, Eigen::Dynamic, Eigen::Dynamic> H_f(dim + 1, dim + 1); + EMatrix<double, Eigen::Dynamic, 1> nabla_f(dim_r + 1, 1); + EMatrix<double, Eigen::Dynamic, Eigen::Dynamic> H_f(dim_r + 1, dim_r + 1); for(int k = 0; k < (dim + 1); k++) { nabla_f[k] = 0.0; @@ -489,10 +518,10 @@ private: // warnings if the solution strays far from the neighborhood. While the latter is sensible, the optional // subroutines haven't proven to be especially useful so far, so one should consider throwing them out. // (Armijo, barrier, random step when step is too big) - EMatrix<double, Eigen::Dynamic, 1> x00(dim,1); + EMatrix<double, Eigen::Dynamic, 1> x00(dim_r,1); for(int k = 0; k < dim; k++) x00[k] = x[k]; - EMatrix<double, Eigen::Dynamic, 1> x00x(dim,1); + EMatrix<double, Eigen::Dynamic, 1> x00x(dim_r,1); for(int k = 0; k < dim; k++) x00x[k] = 0.0; // take the interpolation polynomial of the sample particle closest to the query particle @@ -514,11 +543,6 @@ private: // iteration counter k int k_newton = 0; - // barrier method initialisation - double barrier = 0.0; - double barrier2 = 0.0; - double barrier3 = 0.0; - // calculations needed specifically for k_newton == 0 p = get_p(x, c, polynomialDegree); grad_p = get_grad_p(x, c, polynomialDegree); @@ -543,11 +567,11 @@ private: H_p = get_H_p(x, c, polynomialDegree); // Assemble Hessian matrix, grad f has been computed at the end of the last iteration. - H_f(Eigen::seq(0, dim - 1), Eigen::seq(0, dim - 1)) = lambda*H_p; + H_f(Eigen::seq(0, dim_r - 1), Eigen::seq(0, dim_r - 1)) = lambda*H_p; for(int k = 0; k < dim; k++) H_f(k, k) = H_f(k, k) + 1.0; - H_f(Eigen::seq(0, dim - 1), dim) = grad_p; - H_f(dim, Eigen::seq(0, dim - 1)) = grad_p.transpose(); - H_f(dim, dim) = 0.0; + H_f(Eigen::seq(0, dim_r - 1), dim_r) = grad_p; + H_f(dim_r, Eigen::seq(0, dim_r - 1)) = grad_p.transpose(); + H_f(dim_r, dim_r) = 0.0; // compute Newton increment dx = - H_f.inverse()*nabla_f; @@ -560,7 +584,7 @@ private: { auto & v_cl = create_vcluster(); - std::cout<<"Step size limitation invoked for particle " << a.getKey() << " on processor " << v_cl.rank() << " " <<std::endl; + message_step_limitation = 1; dx = 0.1*dx; } @@ -597,14 +621,23 @@ private: // Check if the Newton algorithm achieved the required accuracy within the allowed number of iterations. // If not, throw a warning, but proceed as usual (even if the accuracy dictated by the user cannot be reached, // the result can still be very good. - if (k_newton == redistOptions.max_iter) std::cout<<"Warning: Newton algorithm has reached maximum number of iterations, does not converge for particle "<<a.getKey()<<std::endl; + if (k_newton == redistOptions.max_iter) message_convergence_problem = 1; // And finally, compute the new sdf value as the distance of the query particle x_a and the result of the // optimization scheme x. We conserve the initial sign of the sdf, since the particle moves with the phase // and does not cross the interface. - vd_in.template getProp<vd_in_sdf>(a) = return_sign(vd_in.template getProp<vd_in_sdf>(a))*xax.norm(); - - // debug optimisation + if (redistOptions.write_sdf) vd_in.template getProp<vd_in_sdf>(a) = return_sign(vd_in.template getProp<vd_in_sdf>(a))*xax.norm(); + + // This is to avoid loss of mass conservation - in some simulations, a particle can get assigned a 0-sdf, so + // that it lies on the surface and cannot be distinguished from the one phase or the other. The reason for + // this probably lies in the numerical tolerance. As a quick fix, we introduce an error of the tolerance, + // but keep the sign. + if ((k_newton == 0) && (xax.norm() < redistOptions.tolerance)) + { + vd_in.template getProp<vd_in_sdf>(a) = return_sign(vd_in.template getProp<vd_in_sdf>(a))*redistOptions.tolerance; + } + + // debug optimisation if(verbose) { //std::cout<<"new sdf: "<<vd.getProp<sdf>(a)<<std::endl; @@ -616,15 +649,6 @@ private: } verbose = 0; - // if the Newton scheme nevertheless strayed from its support, throw a warning. For future todo's, one could - // try using the interpolation polynomial of the neigboring sample point then. - if (((abs(x00[0] - x[0]))>sqrt(r_cutoff2))||((abs(x00[1] - x[1]))>sqrt(r_cutoff2))) - { - std::cout<<"straying out of local neighborhood.."<<std::endl; - std::cout<<"computed sdf: "<<vd_in.template getProp<vd_in_sdf>(a)<<std::endl; - std::cout<<"analytical value: "<<vd_in.template getProp<8>(a)<<", diff: "<<abs(vd_in.template getProp<vd_in_sdf>(a) - vd_in.template getProp<8>(a))<<std::endl; - } - if (redistOptions.compute_normals) { for(int k = 0; k<dim; k++) vd_in.template getProp<vd_in_normal>(a)[k] = return_sign(vd_in.template getProp<vd_in_sdf>(a))*grad_p(k)*1/grad_p.norm(); @@ -648,6 +672,14 @@ private: } ++part; } + if (message_step_limitation) + { + std::cout<<"Step size limitation invoked"<<std::endl; + } + if (message_convergence_problem) + { + std::cout<<"Warning: Newton algorithm has reached maximum number of iterations, does not converge for some particles"<<std::endl; + } } @@ -691,7 +723,7 @@ private: { const double x = xvector[0]; const double y = xvector[1]; - EMatrix<double, Eigen::Dynamic, 1> grad_p(dim, 1); + EMatrix<double, Eigen::Dynamic, 1> grad_p(dim_r, 1); if (dim == 2) { @@ -735,7 +767,7 @@ private: { const double x = xvector[0]; const double y = xvector[1]; - EMatrix<double, Eigen::Dynamic, Eigen::Dynamic> H_p(dim, dim); + EMatrix<double, Eigen::Dynamic, Eigen::Dynamic> H_p(dim_r, dim_r); if (dim == 2) { -- GitLab