void test_linear_ring() { trace.beginBlock("linear ring"); const Domain domain(Point(-5,-5), Point(5,5)); typedef DiscreteExteriorCalculus<1, 2, EigenLinearAlgebraBackend> Calculus; Calculus calculus; calculus.initKSpace<Domain>(domain); for (int kk=-8; kk<10; kk++) calculus.insertSCell( calculus.myKSpace.sCell(Point(-8,kk), kk%2 == 0 ? Calculus::KSpace::POS : Calculus::KSpace::NEG) ); for (int kk=-8; kk<10; kk++) calculus.insertSCell( calculus.myKSpace.sCell(Point(kk,10), kk%2 == 0 ? Calculus::KSpace::POS : Calculus::KSpace::NEG) ); for (int kk=10; kk>-8; kk--) calculus.insertSCell( calculus.myKSpace.sCell(Point(10,kk)) ); for (int kk=10; kk>-8; kk--) calculus.insertSCell( calculus.myKSpace.sCell(Point(kk,-8)) ); calculus.updateIndexes(); { trace.info() << calculus << endl; Board2D board; board << domain; board << calculus; board.saveSVG("ring_structure.svg"); } const Calculus::PrimalDerivative0 d0 = calculus.derivative<0, PRIMAL>(); display_operator_info("d0", d0); const Calculus::PrimalHodge0 h0 = calculus.hodge<0, PRIMAL>(); display_operator_info("h0", h0); const Calculus::DualDerivative0 d0p = calculus.derivative<0, DUAL>(); display_operator_info("d0p", d0p); const Calculus::PrimalHodge1 h1 = calculus.hodge<1, PRIMAL>(); display_operator_info("h1", h1); const Calculus::PrimalIdentity0 laplace = calculus.laplace<PRIMAL>(); display_operator_info("laplace", laplace); const int laplace_size = calculus.kFormLength(0, PRIMAL); const Eigen::MatrixXd laplace_dense(laplace.myContainer); for (int ii=0; ii<laplace_size; ii++) FATAL_ERROR( laplace_dense(ii,ii) == 2 ); FATAL_ERROR( laplace_dense.array().rowwise().sum().abs().sum() == 0 ); FATAL_ERROR( laplace_dense.transpose() == laplace_dense ); trace.endBlock(); }
void propa_2d() { trace.beginBlock("2d propagation"); typedef DiscreteExteriorCalculus<2, 2, EigenLinearAlgebraBackend> Calculus; typedef DiscreteExteriorCalculusFactory<EigenLinearAlgebraBackend> CalculusFactory; { trace.beginBlock("solving time dependent equation"); const Calculus::Scalar cc = 8; // px/s trace.info() << "cc = " << cc << endl; const Z2i::Domain domain(Z2i::Point(0,0), Z2i::Point(29,29)); const Calculus calculus = CalculusFactory::createFromDigitalSet(generateDiskSet(domain), false); //! [time_laplace] const Calculus::DualIdentity0 laplace = calculus.laplace<DUAL>() + 1e-8 * calculus.identity<0, DUAL>(); //! [time_laplace] trace.info() << "laplace = " << laplace << endl; trace.beginBlock("finding eigen pairs"); //! [time_eigen] typedef Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> EigenSolverMatrix; const EigenSolverMatrix eigen_solver(laplace.myContainer); const Eigen::VectorXd eigen_values = eigen_solver.eigenvalues(); const Eigen::MatrixXd eigen_vectors = eigen_solver.eigenvectors(); //! [time_eigen] trace.info() << "eigen_values_range = " << eigen_values.minCoeff() << "/" << eigen_values.maxCoeff() << endl; trace.endBlock(); //! [time_omega] const Eigen::VectorXd angular_frequencies = cc * eigen_values.array().sqrt(); //! [time_omega] Eigen::VectorXcd initial_wave = Eigen::VectorXcd::Zero(calculus.kFormLength(0, DUAL)); //set_initial_phase_null(calculus, initial_wave); set_initial_phase_dir_yy(calculus, initial_wave); { Board2D board; board << domain; board << CustomStyle("KForm", new KFormStyle2D(-1, 1)); board << Calculus::DualForm0(calculus, initial_wave.real()); board.saveSVG("propagation_time_wave_initial_coarse.svg"); } //! [time_init_proj] Eigen::VectorXcd initial_projections = eigen_vectors.transpose() * initial_wave; //! [time_init_proj] // low pass //! [time_low_pass] const Calculus::Scalar lambda_cutoff = 4.5; const Calculus::Scalar angular_frequency_cutoff = 2*M_PI * cc / lambda_cutoff; int cutted = 0; for (int kk=0; kk<initial_projections.rows(); kk++) { const Calculus::Scalar angular_frequency = angular_frequencies(kk); if (angular_frequency < angular_frequency_cutoff) continue; initial_projections(kk) = 0; cutted ++; } //! [time_low_pass] trace.info() << "cutted = " << cutted << "/" << initial_projections.rows() << endl; { const Eigen::VectorXcd wave = eigen_vectors * initial_projections; Board2D board; board << domain; board << CustomStyle("KForm", new KFormStyle2D(-1, 1)); board << Calculus::DualForm0(calculus, wave.real()); board.saveSVG("propagation_time_wave_initial_smoothed.svg"); } const int kk_max = 60; trace.progressBar(0,kk_max); for (int kk=0; kk<kk_max; kk++) { //! [time_solve_time] const Calculus::Scalar time = kk/20.; const Eigen::VectorXcd current_projections = (angular_frequencies * std::complex<double>(0,time)).array().exp() * initial_projections.array(); const Eigen::VectorXcd current_wave = eigen_vectors * current_projections; //! [time_solve_time] std::stringstream ss; ss << "propagation_time_wave_solution_" << std::setfill('0') << std::setw(3) << kk << ".svg"; Board2D board; board << domain; board << CustomStyle("KForm", new KFormStyle2D(-1, 1)); board << Calculus::DualForm0(calculus, current_wave.real()); board.saveSVG(ss.str().c_str()); trace.progressBar(kk+1,kk_max); } trace.info() << endl; trace.endBlock(); } { trace.beginBlock("forced oscillations"); const Z2i::Domain domain(Z2i::Point(0,0), Z2i::Point(50,50)); const Calculus calculus = CalculusFactory::createFromDigitalSet(generateDiskSet(domain), false); const Calculus::DualIdentity0 laplace = calculus.laplace<DUAL>(); trace.info() << "laplace = " << laplace << endl; trace.beginBlock("finding eigen pairs"); typedef Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> EigenSolverMatrix; const EigenSolverMatrix eigen_solver(laplace.myContainer); const Eigen::VectorXd laplace_eigen_values = eigen_solver.eigenvalues(); const Eigen::MatrixXd laplace_eigen_vectors = eigen_solver.eigenvectors(); trace.info() << "eigen_values_range = " << laplace_eigen_values.minCoeff() << "/" << laplace_eigen_values.maxCoeff() << endl; trace.endBlock(); Calculus::DualForm0 concentration(calculus); { const Z2i::Point point(25,25); const Calculus::Cell cell = calculus.myKSpace.uSpel(point); const Calculus::Index index = calculus.getCellIndex(cell); concentration.myContainer(index) = 1; } { Board2D board; board << domain; board << concentration; board.saveSVG("propagation_forced_concentration.svg"); } for (int ll=0; ll<6; ll++) { //! [forced_lambda] const Calculus::Scalar lambda = 4*20.75/(1+2*ll); //! [forced_lambda] trace.info() << "lambda = " << lambda << endl; //! [forced_dalembert_eigen] const Eigen::VectorXd dalembert_eigen_values = (laplace_eigen_values.array() - (2*M_PI/lambda)*(2*M_PI/lambda)).array().inverse(); const Eigen::MatrixXd concentration_to_wave = laplace_eigen_vectors * dalembert_eigen_values.asDiagonal() * laplace_eigen_vectors.transpose(); //! [forced_dalembert_eigen] //! [forced_wave] Calculus::DualForm0 wave(calculus, concentration_to_wave * concentration.myContainer); //! [forced_wave] wave.myContainer /= wave.myContainer(calculus.getCellIndex(calculus.myKSpace.uSpel(Z2i::Point(25,25)))); { trace.info() << "saving samples" << endl; const Calculus::Properties properties = calculus.getProperties(); { std::stringstream ss; ss << "propagation_forced_samples_hv_" << ll << ".dat"; std::ofstream handle(ss.str().c_str()); for (int kk=0; kk<=50; kk++) { const Z2i::Point point_horizontal(kk,25); const Z2i::Point point_vertical(25,kk); const Calculus::Scalar xx = 2 * (kk/50. - .5); handle << xx << " "; handle << sample_dual_0_form<Calculus>(properties, wave, point_horizontal) << " "; handle << sample_dual_0_form<Calculus>(properties, wave, point_vertical) << endl; } } { std::stringstream ss; ss << "propagation_forced_samples_diag_" << ll << ".dat"; std::ofstream handle(ss.str().c_str()); for (int kk=0; kk<=50; kk++) { const Z2i::Point point_diag_pos(kk,kk); const Z2i::Point point_diag_neg(kk,50-kk); const Calculus::Scalar xx = 2 * sqrt(2) * (kk/50. - .5); handle << xx << " "; handle << sample_dual_0_form<Calculus>(properties, wave, point_diag_pos) << " "; handle << sample_dual_0_form<Calculus>(properties, wave, point_diag_neg) << endl; } } } { std::stringstream ss; ss << "propagation_forced_wave_" << ll << ".svg"; Board2D board; board << domain; board << CustomStyle("KForm", new KFormStyle2D(-.5, 1)); board << wave; board.saveSVG(ss.str().c_str()); } } trace.endBlock(); } trace.endBlock(); }
int main(int argc, char* argv[]) { using DGtal::trace; using std::endl; using DGtal::PRIMAL; using DGtal::DUAL; const Options options = parse_options(argc, argv); const KSpace kspace; const Calculus calculus; const FlatVector original_face_normals; if (!ends_with(options.image_filename, ".csv")) { ASSERT( !options.image_filename.empty() ); typedef DGtal::Z3i::Domain Domain; typedef DGtal::ImageSelector<Domain, unsigned char>::Type ImageUChar; trace.info() << "image_filename=" << options.image_filename << endl; ImageUChar image_uchar = DGtal::GenericReader<ImageUChar>::import(options.image_filename); const Domain domain = image_uchar.domain(); trace.info() << "domain=" << domain << endl; const Point center = (domain.upperBound()+domain.lowerBound())/2; trace.info() << "center=" << center << endl; const ImageShape<ImageUChar> shape(&image_uchar, center); const_cast<KSpace&>(kspace).init(domain.lowerBound()-center-Point::diagonal(1), domain.upperBound()-center+Point::diagonal(1), true); std::tie(const_cast<Calculus&>(calculus), const_cast<FlatVector&>(original_face_normals)) = initCalculusAndNormalsWithNoise(kspace, shape, options.normal_radius, options.noise_level); } if (ends_with(options.image_filename, ".csv")) { ASSERT( !options.image_filename.empty() ); trace.info() << "csv_filename=" << options.image_filename << endl; std::tie(const_cast<Calculus&>(calculus), const_cast<FlatVector&>(original_face_normals)) = initCalculusAndNormalsFromSurfelNormalsCSV(options.image_filename); } const FlatVector original_vertex_normals = vertexNormals(calculus, original_face_normals); const FlatVector original_positions; const FlatVector regularized_positions; const FlatVector original_centers; const FlatVector regularized_centers; std::tie(const_cast<FlatVector&>(original_positions), const_cast<FlatVector&>(regularized_positions), const_cast<FlatVector&>(original_centers), const_cast<FlatVector&>(regularized_centers)) = approximateSurface(calculus, original_face_normals, ApproxParams({options.regularization_position, options.regularization_center, options.align, options.fairness, options.barycenter})); ASSERT( original_positions.size() == 3*calculus.kFormLength(0, PRIMAL) ); ASSERT( regularized_positions.size() == 3*calculus.kFormLength(0, PRIMAL) ); ASSERT( original_centers.size() == 3*calculus.kFormLength(2, PRIMAL) ); ASSERT( regularized_centers.size() == 3*calculus.kFormLength(2, PRIMAL) ); { trace.beginBlock( "computing energies" ); { double position_energy = 0; double align_energy = 0; std::tie( position_energy, align_energy ) = approximateSurfaceEnergies( calculus, original_face_normals, original_positions ); align_energy *= options.align; position_energy *= options.regularization_position; trace.info() << "original_energies=" << position_energy << " " << align_energy << " " << position_energy + align_energy << endl; } { double position_energy = 0; double align_energy = 0; std::tie(position_energy, align_energy) = approximateSurfaceEnergies(calculus, original_face_normals, regularized_positions); align_energy *= options.align; position_energy *= options.regularization_position; trace.info() << "regularized_energies=" << position_energy << " " << align_energy << " " << position_energy+align_energy << endl; } trace.endBlock(); } { ASSERT( !options.regularized_obj_filename.empty() ); trace.info() << "regularized_obj_filename=" << options.regularized_obj_filename << endl; exportOBJ(calculus, regularized_positions, options.regularized_obj_filename); } if (!options.cubical_obj_filename.empty()) { ASSERT( !options.cubical_obj_filename.empty() ); trace.info() << "cubical_obj_filename=" << options.cubical_obj_filename << endl; exportOBJ(calculus, original_positions, options.cubical_obj_filename); } return 0; }