504 const std::string directory =
"output/data_points";
505 bool points_loaded =
false;
506 target_points.clear();
509 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) {
510 auto [fe, map] = Utils::create_fe_and_mapping_for_mesh<dim, spacedim>(target_mesh);
511 fe_system_target = std::move(fe);
512 mapping_target = std::move(map);
513 dof_handler_target.distribute_dofs(*fe_system_target);
518 points_loaded =
true;
519 pcout <<
"Target points loaded from file" << std::endl;
521 std::map<types::global_dof_index, Point<spacedim>> support_points_target;
522 DoFTools::map_dofs_to_support_points(*mapping_target, dof_handler_target, support_points_target);
523 for (
const auto &point_pair : support_points_target)
525 target_points.push_back(point_pair.second);
528 points_loaded =
true;
529 pcout <<
"Target points computed and saved to file" << std::endl;
532 if (target_params.use_custom_density)
534 pcout <<
"Using custom target density from file: " << target_params.density_file_path << std::endl;
535 bool density_loaded =
false;
537 if (target_params.density_file_format ==
"vtk")
542 pcout <<
"Loading VTK file using VTKHandler: " << target_params.density_file_path << std::endl;
550 pcout <<
"Target density loaded from VTK file" << std::endl;
551 target_density.reinit(dof_handler_target.n_dofs());
552 pcout <<
"Target density size: " << target_density.size() << std::endl;
557 VectorTools::interpolate(dof_handler_target, vtk_handler, target_density);
559 pcout <<
"Successfully interpolated VTK field to target mesh" << std::endl;
560 pcout <<
"L1 norm of interpolated field: " << target_density.l1_norm() << std::endl;
561 target_density /= target_density.l1_norm();
563 density_loaded =
true;
565 catch (
const std::exception &e)
568 density_loaded =
false;
573 std::vector<double> density_values;
577 target_density = Vector<double>(density_values.size());
578 for (
unsigned int i = 0; i < density_values.size(); ++i)
580 target_density[i] = density_values[i];
582 target_density /= target_density.l1_norm();
586 pcout <<
Color::red <<
"Failed to load custom density, using uniform density" <<
Color::reset << std::endl;
587 target_density.reinit(target_points.size());
588 target_density = 1.0 / target_points.size();
594 target_density.reinit(target_points.size());
595 target_density = 1.0 / target_points.size();
600 points_loaded = Utilities::MPI::broadcast(mpi_communicator, points_loaded, 0);
603 throw std::runtime_error(
"Failed to load or compute target points");
607 unsigned int n_points = 0;
608 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0)
610 n_points = target_points.size();
612 n_points = Utilities::MPI::broadcast(mpi_communicator, n_points, 0);
615 if (Utilities::MPI::this_mpi_process(mpi_communicator) != 0)
617 target_points.resize(n_points);
618 target_density.reinit(n_points);
621 target_points = Utilities::MPI::broadcast(mpi_communicator, target_points, 0);
622 target_density = Utilities::MPI::broadcast(mpi_communicator, target_density, 0);
624 pcout <<
"Setup complete with " << target_points.size() <<
" target points" << std::endl;
625 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0)
628 std::string output_dir =
"output/data_density";
629 fs::create_directories(output_dir);
632 std::string density_file = output_dir +
"/target_density";
633 std::vector<double> output_density_values(target_density.begin(), target_density.end());
636 pcout <<
"Target density saved to " << density_file << std::endl;
639 Utils::write_points_with_density_vtk<spacedim>(
641 output_density_values,
642 output_dir +
"/target_points_with_density.vtk",
643 "Target points with density values",
754 if (!is_setup_programmatically_) {
755 setup_finite_elements();
760 <<
" target points and " << source_density.size() <<
" source points" <<
Color::reset << std::endl;
766 sot_solver->setup_source(dof_handler_source,
773 sot_solver->setup_target(target_points, target_density);
776 Vector<double> potential;
777 if (initial_potential.size() > 0) {
779 if (initial_potential.size() != target_points.size()) {
781 <<
") does not match target points size (" << target_points.size() <<
")" <<
Color::reset << std::endl;
782 return Vector<double>();
785 potential = initial_potential;
788 potential.reinit(target_points.size());
796 pcout <<
"Using epsilon scaling with EpsilonScalingHandler:" << std::endl
797 <<
" Initial epsilon: " << solver_config.
epsilon << std::endl
801 std::vector<std::vector<double>> epsilon_distribution =
802 epsilon_scaling_handler->compute_epsilon_distribution(1);
804 if (!epsilon_distribution.empty() && !epsilon_distribution[0].empty())
806 const auto &epsilon_sequence = epsilon_distribution[0];
809 for (
size_t i = 0; i < epsilon_sequence.size(); ++i)
811 pcout <<
"\nEpsilon scaling step " << i + 1 <<
"/" << epsilon_sequence.size()
812 <<
" (ε = " << epsilon_sequence[i] <<
")" << std::endl;
814 solver_config.
epsilon = epsilon_sequence[i];
818 sot_solver->solve(potential, solver_config);
821 if (i < epsilon_sequence.size() - 1)
823 std::string eps_suffix =
"_eps" + std::to_string(i + 1);
824 save_results(potential,
"potential" + eps_suffix);
827 catch (
const SolverControl::NoConvergence &exc)
829 if (exc.last_step >= solver_params.max_iterations)
832 <<
" (epsilon=" << epsilon_sequence[i] <<
"): Max iterations reached"
844 sot_solver->solve(potential, solver_config);
846 catch (
const SolverControl::NoConvergence &exc)
852 catch (
const std::exception &e)
858 save_results(potential,
"potentials");
861 const double total_time = timer.wall_time();
866 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) {
868 fs::create_directories(eps_dir);
869 std::ofstream conv_info(eps_dir +
"/convergence_info.txt");
870 conv_info <<
"Regularization parameter (ε): " << solver_config.
epsilon <<
"\n";
871 conv_info <<
"Number of iterations: " << sot_solver->get_last_iteration_count() <<
"\n";
872 conv_info <<
"Final function value: " << sot_solver->get_last_functional_value() <<
"\n";
873 conv_info <<
"Last threshold value: " << sot_solver->get_last_distance_threshold() <<
"\n";
874 conv_info <<
"Total execution time: " << total_time <<
" seconds\n";
875 conv_info <<
"Convergence achieved: " << sot_solver->get_convergence_status() <<
"\n";
886 global_timer.start();
889 double total_softmax_time = 0.0;
894 if (!is_setup_programmatically_)
896 mesh_manager->load_source_mesh(source_mesh, source_mesh_name);
897 setup_source_finite_elements();
901 unsigned int num_levels = 0;
902 std::vector<std::pair<std::string, std::string>> hierarchy_files;
903 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0)
909 catch (
const std::exception &e)
912 pcout <<
"Please run prepare_target_multilevel first." << std::endl;
913 return Vector<double>();
916 if (hierarchy_files.empty())
918 pcout <<
"No target point cloud hierarchy found. Please run prepare_target_multilevel first." << std::endl;
919 return Vector<double>();
921 num_levels = hierarchy_files.size();
924 num_levels = Utilities::MPI::broadcast(mpi_communicator, num_levels, 0);
927 if (!has_hierarchy_data_)
929 pcout <<
"Initializing hierarchy data structure..." << std::endl;
930 load_hierarchy_data(multilevel_params.target_hierarchy_dir, -1);
933 if (!has_hierarchy_data_)
935 pcout <<
"Failed to initialize hierarchy data. Cannot proceed with multilevel computation." << std::endl;
936 return Vector<double>();
940 const unsigned int original_max_iterations = solver_params.max_iterations;
941 const double original_tolerance = solver_params.tolerance;
942 const double original_regularization = solver_params.epsilon;
946 std::string target_multilevel_dir = eps_dir +
"/target_multilevel";
947 fs::create_directories(target_multilevel_dir);
950 std::ofstream summary_log;
951 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) {
952 summary_log.open(target_multilevel_dir +
"/summary_log.txt", std::ios::app);
954 if (summary_log.tellp() == 0) {
955 summary_log <<
"Target Level | Solver Iterations | Time (s) | Last Threshold\n";
956 summary_log <<
"------------------------------------------------------------\n";
961 std::vector<std::vector<double>> epsilon_distribution;
962 if (solver_params.use_epsilon_scaling && epsilon_scaling_handler)
964 pcout <<
"Computing epsilon distribution for target multilevel optimization..." << std::endl;
965 epsilon_distribution = epsilon_scaling_handler->compute_epsilon_distribution(
967 epsilon_scaling_handler->print_epsilon_distribution();
971 Vector<double> level_potentials;
977 sot_solver->setup_source(dof_handler_source,
984 for (
size_t level = 0; level < num_levels; ++level)
986 int level_number = 0;
987 std::string level_output_dir;
988 std::string points_file;
989 std::string potentials_file;
990 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0)
992 const auto &hierarchy_file = hierarchy_files[level];
993 points_file = hierarchy_file.first;
994 potentials_file = hierarchy_file.second;
997 std::string level_num = points_file.substr(
998 points_file.find(
"level_") + 6,
999 points_file.find(
"_points") - points_file.find(
"level_") - 6);
1000 level_number = std::stoi(level_num);
1003 level_output_dir = target_multilevel_dir +
"/target_level_" + level_num;
1004 fs::create_directories(level_output_dir);
1006 level_number = Utilities::MPI::broadcast(mpi_communicator, level_number, 0);
1014 load_hierarchy_data(multilevel_params.target_hierarchy_dir, level_number);
1019 target_points_coarse = target_points;
1020 target_density_coarse = target_density;
1022 load_target_points_at_level(points_file, potentials_file);
1023 pcout <<
"Target points loaded for level " << level_number << std::endl;
1024 pcout <<
"Target points size: " << target_points.size() << std::endl;
1027 sot_solver->setup_target(target_points, target_density);
1030 Vector<double> current_level_potentials(target_points.size());
1034 Timer transfer_timer;
1035 transfer_timer.start();
1036 assign_potentials_by_hierarchy(current_level_potentials, level_number + 1, level_number, level_potentials);
1037 transfer_timer.stop();
1040 if (multilevel_params.use_softmax_potential_transfer)
1042 total_softmax_time += transfer_timer.wall_time();
1048 if (initial_potential.size() > 0)
1050 if (initial_potential.size() != target_points.size())
1053 <<
") does not match coarsest target points size (" << target_points.size() <<
")" <<
Color::reset << std::endl;
1054 return Vector<double>();
1056 pcout <<
Color::green <<
"Using provided initial potential for coarsest level " << level_number <<
Color::reset << std::endl;
1057 current_level_potentials = initial_potential;
1062 current_level_potentials = 0.0;
1067 level_timer.start();
1070 if (solver_params.use_epsilon_scaling && epsilon_scaling_handler && !epsilon_distribution.empty())
1072 const auto &level_epsilons = epsilon_scaling_handler->get_epsilon_values_for_level(level);
1074 if (!level_epsilons.empty())
1076 pcout <<
"Using " << level_epsilons.size() <<
" epsilon values for level " << level_number << std::endl;
1079 for (
size_t eps_idx = 0; eps_idx < level_epsilons.size(); ++eps_idx)
1081 double current_epsilon = level_epsilons[eps_idx];
1082 pcout <<
" Epsilon scaling step " << eps_idx + 1 <<
"/" << level_epsilons.size()
1083 <<
" (ε = " << current_epsilon <<
")" << std::endl;
1086 solver_config.
epsilon = current_epsilon;
1091 sot_solver->solve(current_level_potentials, solver_config);
1094 if (eps_idx < level_epsilons.size() - 1)
1096 std::string eps_suffix =
"_eps" + std::to_string(eps_idx + 1);
1097 save_results(current_level_potentials, level_output_dir +
"/potentials" + eps_suffix,
false);
1100 catch (
const SolverControl::NoConvergence &exc)
1102 if (exc.last_step >= solver_params.max_iterations)
1105 <<
" (epsilon=" << current_epsilon <<
"): Max iterations reached"
1109 << current_epsilon <<
" at target level " << level_number <<
Color::reset << std::endl;
1117 solver_config.
epsilon = original_regularization;
1122 sot_solver->solve(current_level_potentials, solver_config);
1124 catch (
const SolverControl::NoConvergence &exc)
1126 if (exc.last_step >= solver_params.max_iterations)
1129 <<
" (epsilon=" << original_regularization <<
"): Max iterations reached"
1133 pcout <<
" Iterations: " << exc.last_step << std::endl;
1143 sot_solver->solve(current_level_potentials, solver_config);
1145 catch (SolverControl::NoConvergence &exc)
1147 if (exc.last_step >= solver_params.max_iterations)
1150 <<
" (epsilon=" << original_regularization <<
"): Max iterations reached"
1154 pcout <<
" Iterations: " << exc.last_step << std::endl;
1156 return Vector<double>();
1161 const double level_time = level_timer.wall_time();
1162 const unsigned int last_iterations = sot_solver->get_last_iteration_count();
1163 current_distance_threshold = sot_solver->get_last_distance_threshold();
1166 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0 && summary_log.is_open()) {
1167 summary_log << std::setw(13) << level_number <<
" | "
1168 << std::setw(17) << last_iterations <<
" | "
1169 << std::setw(8) << std::fixed << std::setprecision(4) << level_time <<
" | "
1170 << std::setw(14) << std::scientific << std::setprecision(6) << current_distance_threshold <<
"\n";
1174 save_results(current_level_potentials, level_output_dir +
"/potentials",
false);
1175 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0)
1177 std::ofstream conv_info(level_output_dir +
"/convergence_info.txt");
1178 conv_info <<
"Regularization parameter (ε): " << solver_params.epsilon <<
"\n";
1179 conv_info <<
"Number of iterations: " << sot_solver->get_last_iteration_count() <<
"\n";
1180 conv_info <<
"Final function value: " << sot_solver->get_last_functional_value() <<
"\n";
1181 conv_info <<
"Convergence achieved: " << sot_solver->get_convergence_status() <<
"\n";
1182 conv_info <<
"Level: " << level_number <<
"\n";
1183 pcout <<
"Level " << level_number <<
" results saved to " << level_output_dir <<
"/potentials" << std::endl;
1187 level_potentials = current_level_potentials;
1192 coarsest_potential = current_level_potentials;
1197 save_results(level_potentials, target_multilevel_dir +
"/potentials",
false);
1200 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0 && summary_log.is_open()) {
1201 summary_log.close();
1205 solver_params.tolerance = original_tolerance;
1206 solver_params.max_iterations = original_max_iterations;
1207 solver_params.epsilon = original_regularization;
1209 global_timer.stop();
1210 const double total_time = global_timer.wall_time();
1213 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) {
1214 std::ofstream conv_info(target_multilevel_dir +
"/convergence_info.txt");
1215 conv_info <<
"Regularization parameter (ε): " << original_regularization <<
"\n";
1216 conv_info <<
"Final number of iterations: " << sot_solver->get_last_iteration_count() <<
"\n";
1217 conv_info <<
"Final function value: " << sot_solver->get_last_functional_value() <<
"\n";
1218 conv_info <<
"Last threshold value: " << current_distance_threshold <<
"\n";
1219 conv_info <<
"Total execution time: " << total_time <<
" seconds\n";
1220 conv_info <<
"Convergence achieved: " << sot_solver->get_convergence_status() <<
"\n";
1221 conv_info <<
"Number of levels: " << num_levels <<
"\n";
1229 if (multilevel_params.use_softmax_potential_transfer && total_softmax_time > 0.0)
1232 <<
" seconds (" << (total_softmax_time / total_time * 100.0) <<
"%)" <<
Color::reset << std::endl;
1238 return level_potentials;
1245 global_timer.start();
1250 std::vector<std::string> source_mesh_files = mesh_manager->get_mesh_hierarchy_files(multilevel_params.source_hierarchy_dir);
1251 if (source_mesh_files.empty())
1253 pcout <<
"No source mesh hierarchy found. Please run prepare_source_multilevel first." << std::endl;
1254 return Vector<double>();
1256 unsigned int num_levels = source_mesh_files.size();
1259 const unsigned int original_max_iterations = solver_params.max_iterations;
1260 const double original_tolerance = solver_params.tolerance;
1261 const double original_regularization = solver_params.epsilon;
1265 std::string source_multilevel_dir = eps_dir +
"/source_multilevel";
1266 fs::create_directories(source_multilevel_dir);
1269 std::ofstream summary_log;
1270 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) {
1271 summary_log.open(source_multilevel_dir +
"/summary_log.txt", std::ios::app);
1273 if (summary_log.tellp() == 0) {
1274 summary_log <<
"Source Level | Solver Iterations | Time (s) | Last Threshold\n";
1275 summary_log <<
"------------------------------------------------------------\n";
1280 std::vector<std::vector<double>> epsilon_distribution;
1281 if (solver_params.use_epsilon_scaling && epsilon_scaling_handler)
1283 pcout <<
"Computing epsilon distribution for source multilevel optimization..." << std::endl;
1284 epsilon_distribution = epsilon_scaling_handler->compute_epsilon_distribution(num_levels);
1285 epsilon_scaling_handler->print_epsilon_distribution();
1289 auto process_epsilon_scaling_for_source_multilevel =
1290 [
this, &original_regularization, &epsilon_distribution](
1291 Vector<double> &potentials,
1292 const unsigned int level_idx,
1293 const std::string &level_output_dir) {
1294 if (solver_params.use_epsilon_scaling && epsilon_scaling_handler && !epsilon_distribution.empty())
1296 const auto &level_epsilons = epsilon_scaling_handler->get_epsilon_values_for_level(level_idx);
1297 if (!level_epsilons.empty())
1299 pcout <<
"Using " << level_epsilons.size() <<
" epsilon values for source level " << level_idx << std::endl;
1300 for (
size_t eps_idx = 0; eps_idx < level_epsilons.size(); ++eps_idx)
1302 double current_epsilon = level_epsilons[eps_idx];
1303 pcout <<
" Epsilon scaling step " << eps_idx + 1 <<
"/" << level_epsilons.size()
1304 <<
" (ε = " << current_epsilon <<
")" << std::endl;
1305 solver_params.epsilon = current_epsilon;
1309 sot_solver->solve(potentials, solver_params);
1310 if (eps_idx < level_epsilons.size() - 1)
1312 std::string eps_suffix =
"_eps" + std::to_string(eps_idx + 1);
1313 save_results(potentials, level_output_dir +
"/potentials" + eps_suffix,
false);
1316 catch (
const SolverControl::NoConvergence &exc)
1318 if (exc.last_step >= solver_params.max_iterations)
1321 <<
" (epsilon=" << current_epsilon <<
"): Max iterations reached" <<
Color::reset << std::endl;
1324 << current_epsilon <<
" at source level " << level_idx <<
Color::reset << std::endl;
1332 solver_params.epsilon = original_regularization;
1333 sot_solver->solve(potentials, solver_params);
1336 Vector<double> final_potentials;
1337 Vector<double> previous_source_potentials;
1339 if (!is_setup_programmatically_) {
1340 mesh_manager->load_source_mesh(source_mesh, source_mesh_name);
1341 setup_source_finite_elements();
1342 setup_target_points();
1345 for (
size_t source_level_idx = 0; source_level_idx < source_mesh_files.size(); ++source_level_idx)
1347 const unsigned int current_level_display_name = num_levels - source_level_idx -1 ;
1350 <<
"============================================" <<
Color::reset << std::endl;
1352 <<
" (mesh: " << source_mesh_files[source_level_idx] <<
")" <<
Color::reset << std::endl;
1354 <<
"============================================" <<
Color::reset << std::endl;
1356 std::string source_level_dir = source_multilevel_dir +
"/source_level_" + std::to_string(current_level_display_name);
1357 fs::create_directories(source_level_dir);
1359 Vector<double> level_potentials;
1361 level_timer.start();
1363 mesh_manager->load_mesh_at_level(source_mesh, dof_handler_source, source_mesh_files[source_level_idx]);
1364 setup_source_finite_elements(
true);
1366 if (source_level_idx == 0)
1368 level_potentials.reinit(target_points.size());
1370 if (initial_potential.size() > 0)
1372 if (initial_potential.size() != target_points.size())
1375 <<
") does not match target points size (" << target_points.size() <<
")" <<
Color::reset << std::endl;
1376 return Vector<double>();
1378 pcout <<
Color::green <<
"Using provided initial potential for coarsest source level " << current_level_display_name <<
Color::reset << std::endl;
1379 level_potentials = initial_potential;
1383 level_potentials = 0.0;
1388 level_potentials.reinit(previous_source_potentials.size());
1389 level_potentials = previous_source_potentials;
1391 pcout <<
" Max iterations: " << solver_params.max_iterations << std::endl;
1394 sot_solver->setup_source(dof_handler_source, *mapping, *fe_system, source_density, solver_params.quadrature_order);
1395 sot_solver->setup_target(target_points, target_density);
1397 process_epsilon_scaling_for_source_multilevel(level_potentials, source_level_idx, source_level_dir);
1400 const double level_time = level_timer.wall_time();
1401 const unsigned int last_iterations = sot_solver->get_last_iteration_count();
1402 const double last_threshold = sot_solver->get_last_distance_threshold();
1405 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0 && summary_log.is_open()) {
1406 summary_log << std::setw(13) << current_level_display_name <<
" | "
1407 << std::setw(17) << last_iterations <<
" | "
1408 << std::setw(8) << std::fixed << std::setprecision(4) << level_time <<
" | "
1409 << std::setw(14) << std::scientific << std::setprecision(6) << last_threshold <<
"\n";
1412 save_results(level_potentials, source_level_dir +
"/potentials",
false);
1416 pcout <<
Color::blue <<
" Time taken: " << level_timer.wall_time() <<
" seconds" <<
Color::reset << std::endl;
1417 pcout <<
Color::blue <<
" Final number of iterations: " << sot_solver->get_last_iteration_count() <<
Color::reset << std::endl;
1418 pcout <<
Color::blue <<
" Final function value: " << sot_solver->get_last_functional_value() <<
Color::reset << std::endl;
1421 previous_source_potentials = level_potentials;
1422 if (source_level_idx == source_mesh_files.size() - 1)
1424 final_potentials = level_potentials;
1426 coarsest_potential = level_potentials;
1431 save_results(final_potentials, source_multilevel_dir +
"/potentials",
false);
1434 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0 && summary_log.is_open()) {
1435 summary_log.close();
1438 solver_params.max_iterations = original_max_iterations;
1439 solver_params.tolerance = original_tolerance;
1440 solver_params.epsilon = original_regularization;
1442 global_timer.stop();
1443 const double total_time = global_timer.wall_time();
1446 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) {
1447 std::ofstream conv_info(source_multilevel_dir +
"/convergence_info.txt");
1448 conv_info <<
"Regularization parameter (ε): " << original_regularization <<
"\n";
1449 conv_info <<
"Final number of iterations: " << sot_solver->get_last_iteration_count() <<
"\n";
1450 conv_info <<
"Final function value: " << sot_solver->get_last_functional_value() <<
"\n";
1451 conv_info <<
"Last threshold value: " << sot_solver->get_last_distance_threshold() <<
"\n";
1452 conv_info <<
"Total execution time: " << total_time <<
" seconds\n";
1453 conv_info <<
"Convergence achieved: " << sot_solver->get_convergence_status() <<
"\n";
1454 conv_info <<
"Number of levels: " << num_levels <<
"\n";
1459 <<
"============================================" <<
Color::reset << std::endl;
1464 <<
"============================================" <<
Color::reset << std::endl;
1467 return final_potentials;
1475 global_timer.start();
1480 std::vector<std::string> source_mesh_files = mesh_manager->get_mesh_hierarchy_files(multilevel_params.source_hierarchy_dir);
1481 unsigned int n_s_levels = Utilities::MPI::broadcast(mpi_communicator, source_mesh_files.size(), 0);
1484 std::vector<std::pair<std::string, std::string>> target_hierarchy_files;
1485 unsigned int n_t_levels = 0;
1486 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) {
1488 n_t_levels = target_hierarchy_files.size();
1490 n_t_levels = Utilities::MPI::broadcast(mpi_communicator, n_t_levels, 0);
1493 const unsigned int n_c_levels = std::max(n_s_levels, n_t_levels);
1496 const unsigned int original_max_iterations = solver_params.max_iterations;
1497 const double original_tolerance = solver_params.tolerance;
1498 const double original_regularization = solver_params.epsilon;
1502 std::string combined_multilevel_dir = eps_dir +
"/combined_multilevel";
1503 fs::create_directories(combined_multilevel_dir);
1506 std::ofstream summary_log;
1507 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) {
1508 summary_log.open(combined_multilevel_dir +
"/summary_log.txt", std::ios::app);
1510 if (summary_log.tellp() == 0) {
1511 summary_log <<
"Combined Level | Solver Iterations | Time (s) | Last Threshold\n";
1512 summary_log <<
"------------------------------------------------------------\n";
1517 if (solver_params.use_epsilon_scaling && epsilon_scaling_handler) {
1518 pcout <<
"Computing epsilon distribution for combined multilevel optimization..." << std::endl;
1519 epsilon_scaling_handler->compute_epsilon_distribution(n_c_levels);
1520 epsilon_scaling_handler->print_epsilon_distribution();
1524 Vector<double> current_potentials;
1525 int prev_actual_target_level_num = -1;
1526 unsigned int prev_source_idx = -1;
1527 double total_softmax_time = 0.0;
1530 if (!is_setup_programmatically_) {
1531 mesh_manager->load_source_mesh(source_mesh);
1532 setup_source_finite_elements();
1536 for (
unsigned int combined_iter = 0; combined_iter < n_c_levels; ++combined_iter) {
1538 level_timer.start();
1541 <<
"============================================" <<
Color::reset << std::endl;
1543 <<
" of " << n_c_levels - 1 <<
Color::reset << std::endl;
1546 unsigned int current_source_idx = 0;
1547 unsigned int current_target_idx = 0;
1549 if (n_s_levels >= n_t_levels) {
1550 current_source_idx = combined_iter;
1551 current_target_idx = (combined_iter >= (n_s_levels - n_t_levels)) ?
1552 (combined_iter - (n_s_levels - n_t_levels)) : 0;
1554 current_target_idx = combined_iter;
1555 current_source_idx = (combined_iter >= (n_t_levels - n_s_levels)) ?
1556 (combined_iter - (n_t_levels - n_s_levels)) : 0;
1560 const std::string current_source_mesh_file = source_mesh_files[current_source_idx];
1561 std::string current_target_points_file;
1562 std::string current_target_density_file;
1564 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) {
1565 current_target_points_file = target_hierarchy_files[current_target_idx].first;
1566 current_target_density_file = target_hierarchy_files[current_target_idx].second;
1570 current_target_points_file = Utilities::MPI::broadcast(mpi_communicator, current_target_points_file, 0);
1571 current_target_density_file = Utilities::MPI::broadcast(mpi_communicator, current_target_density_file, 0);
1574 int current_actual_target_level_num = -1;
1575 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) {
1576 size_t level_pos = current_target_points_file.find(
"level_");
1577 size_t level_end = current_target_points_file.find(
"_points");
1578 if (level_pos != std::string::npos && level_end != std::string::npos) {
1579 current_actual_target_level_num = std::stoi(current_target_points_file.substr(
1580 level_pos + 6, level_end - (level_pos + 6)));
1583 current_actual_target_level_num = Utilities::MPI::broadcast(mpi_communicator, current_actual_target_level_num, 0);
1586 std::string level_dir = combined_multilevel_dir +
"/combined_level_" + std::to_string(combined_iter);
1587 fs::create_directories(level_dir);
1590 if (current_source_idx != prev_source_idx) {
1591 mesh_manager->load_mesh_at_level(source_mesh, dof_handler_source, current_source_mesh_file);
1592 setup_source_finite_elements(
true);
1593 prev_source_idx = current_source_idx;
1597 if (combined_iter > 0) {
1598 target_points_coarse = target_points;
1599 target_density_coarse = target_density;
1603 load_target_points_at_level(current_target_points_file, current_target_density_file);
1606 Vector<double> potentials_for_this_level(target_points.size());
1608 if (combined_iter == 0) {
1610 if (initial_potential.size() > 0) {
1611 if (initial_potential.size() != target_points.size()) {
1613 <<
") does not match coarsest target points size (" << target_points.size() <<
")" <<
Color::reset << std::endl;
1614 return Vector<double>();
1616 pcout <<
Color::green <<
"Using provided initial potential for coarsest combined level " << combined_iter <<
Color::reset << std::endl;
1617 potentials_for_this_level = initial_potential;
1619 potentials_for_this_level = 0.0;
1622 bool target_level_changed = (current_actual_target_level_num != prev_actual_target_level_num);
1623 bool hierarchical_transfer_possible = target_level_changed &&
1624 (prev_actual_target_level_num == current_actual_target_level_num + 1);
1626 if (hierarchical_transfer_possible) {
1627 load_hierarchy_data(multilevel_params.target_hierarchy_dir, current_actual_target_level_num);
1628 Timer transfer_timer;
1629 transfer_timer.start();
1631 assign_potentials_by_hierarchy(potentials_for_this_level,
1632 prev_actual_target_level_num,
1633 current_actual_target_level_num,
1634 current_potentials);
1636 transfer_timer.stop();
1637 if (multilevel_params.use_softmax_potential_transfer) {
1638 total_softmax_time += transfer_timer.wall_time();
1640 }
else if (current_potentials.size() == potentials_for_this_level.size()) {
1641 potentials_for_this_level = current_potentials;
1646 sot_solver->setup_source(dof_handler_source, *mapping, *fe_system, source_density, solver_params.quadrature_order);
1647 sot_solver->setup_target(target_points, target_density);
1650 bool solve_successful =
true;
1651 if (solver_params.use_epsilon_scaling && epsilon_scaling_handler) {
1652 const auto& level_epsilons = epsilon_scaling_handler->get_epsilon_values_for_level(combined_iter);
1653 if (!level_epsilons.empty()) {
1654 for (
size_t eps_idx = 0; eps_idx < level_epsilons.size(); ++eps_idx) {
1655 solver_params.epsilon = level_epsilons[eps_idx];
1657 sot_solver->solve(potentials_for_this_level, solver_params);
1658 if (eps_idx < level_epsilons.size() - 1) {
1659 save_results(potentials_for_this_level, level_dir +
"/potentials_eps" + std::to_string(eps_idx + 1),
false);
1661 }
catch (
const SolverControl::NoConvergence& exc) {
1662 solve_successful =
false;
1666 solver_params.epsilon = original_regularization;
1668 sot_solver->solve(potentials_for_this_level, solver_params);
1669 }
catch (
const SolverControl::NoConvergence& exc) {
1670 solve_successful =
false;
1674 solver_params.epsilon = original_regularization;
1676 sot_solver->solve(potentials_for_this_level, solver_params);
1677 }
catch (
const SolverControl::NoConvergence& exc) {
1678 solve_successful =
false;
1682 if (!solve_successful && combined_iter == 0) {
1688 save_results(potentials_for_this_level, level_dir +
"/potentials",
false);
1691 current_potentials = potentials_for_this_level;
1692 prev_actual_target_level_num = current_actual_target_level_num;
1693 current_distance_threshold = sot_solver->get_last_distance_threshold();
1696 if (combined_iter == 0)
1698 coarsest_potential = potentials_for_this_level;
1702 const double level_time = level_timer.wall_time();
1703 const unsigned int last_iterations = sot_solver->get_last_iteration_count();
1706 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0 && summary_log.is_open()) {
1707 summary_log << std::setw(13) << combined_iter <<
" | "
1708 << std::setw(17) << last_iterations <<
" | "
1709 << std::setw(8) << std::fixed << std::setprecision(4) << level_time <<
" | "
1710 << std::setw(14) << std::scientific << std::setprecision(6) << current_distance_threshold <<
"\n";
1715 if (current_potentials.size() > 0) {
1716 save_results(current_potentials, combined_multilevel_dir +
"/potentials",
false);
1720 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0 && summary_log.is_open()) {
1721 summary_log.close();
1725 solver_params.max_iterations = original_max_iterations;
1726 solver_params.tolerance = original_tolerance;
1727 solver_params.epsilon = original_regularization;
1729 global_timer.stop();
1730 const double total_time = global_timer.wall_time();
1733 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) {
1734 std::ofstream conv_info(combined_multilevel_dir +
"/convergence_info.txt");
1735 conv_info <<
"Regularization parameter (ε): " << original_regularization <<
"\n";
1736 conv_info <<
"Final number of iterations: " << sot_solver->get_last_iteration_count() <<
"\n";
1737 conv_info <<
"Final function value: " << sot_solver->get_last_functional_value() <<
"\n";
1738 conv_info <<
"Last threshold value: " << current_distance_threshold <<
"\n";
1739 conv_info <<
"Total execution time: " << total_time <<
" seconds\n";
1740 conv_info <<
"Convergence achieved: " << sot_solver->get_convergence_status() <<
"\n";
1741 conv_info <<
"Number of levels: " << n_c_levels <<
"\n";
1745 <<
"============================================" <<
Color::reset << std::endl;
1748 if (multilevel_params.use_softmax_potential_transfer && total_softmax_time > 0.0) {
1750 <<
" seconds (" << (total_softmax_time / total_time * 100.0) <<
"%)" <<
Color::reset << std::endl;
1755 return current_potentials;
2013 setup_finite_elements();
2016 std::vector<std::string> selected_folders;
2021 catch (
const std::exception &e)
2023 pcout <<
"Error: " << e.what() << std::endl;
2031 std::vector<Point<spacedim>> source_points;
2032 pcout <<
"Source density size: " << source_density.size() << std::endl;
2034 const std::string directory =
"output/data_points";
2035 bool points_loaded =
false;
2038 points_loaded =
true;
2039 std::cout <<
"Source points loaded from file" << std::endl;
2040 std::cout <<
"First 4 values of source density: ";
2045 std::map<types::global_dof_index, Point<spacedim>> support_points_source;
2046 DoFTools::map_dofs_to_support_points(*mapping, dof_handler_source, support_points_source);
2047 source_points.clear();
2048 for (
const auto &point_pair : support_points_source)
2050 source_points.push_back(point_pair.second);
2055 std::cout <<
"Source points computed and saved to file" << std::endl;
2059 std::vector<double> source_density_vec(source_density.begin(), source_density.end());
2060 std::vector<double> target_density_vec(target_density.begin(), target_density.end());
2062 std::cout <<
"Setup complete with " << source_points.size() <<
" source points and "
2063 << target_points.size() <<
" target points" << std::endl;
2066 for (
const auto &selected_folder : selected_folders)
2068 pcout <<
"\nProcessing folder: " << selected_folder << std::endl;
2071 std::vector<double> potentials_vec;
2072 bool success =
Utils::read_vector(potentials_vec,
"output/" + selected_folder +
"/potentials", io_coding);
2075 pcout <<
"Failed to read potentials from output/" + selected_folder +
"/potentials" << std::endl;
2079 if (potentials_vec.size() != target_points.size())
2081 pcout <<
Color::red <<
Color::bold <<
"Error: Mismatch between potentials size (" << potentials_vec.size()
2082 <<
") and target points size (" << target_points.size() <<
")" <<
Color::reset << std::endl;
2087 std::string eps_str = selected_folder.substr(selected_folder.find(
"epsilon_") + 8);
2088 double epsilon = std::stod(eps_str);
2091 const std::string output_dir =
"output/" + selected_folder +
"/transport_map";
2092 fs::create_directories(output_dir);
2095 Vector<double> potentials_dealii(potentials_vec.size());
2096 std::copy(potentials_vec.begin(), potentials_vec.end(), potentials_dealii.begin());
2107 pcout <<
"Computing transport map using " << strategy <<
" strategy..." << std::endl;
2111 transport_plan.
save_map(output_dir +
"/" + strategy);
2113 pcout <<
"Results saved in " << output_dir +
"/" + strategy << std::endl;
2117 if (selected_folders.size() > 1)
2119 pcout <<
"\nCompleted transport map computation for all selected folders." << std::endl;
2127 setup_finite_elements();
2130 std::vector<std::string> selected_folders;
2135 catch (
const std::exception &e)
2137 pcout <<
"Error: " << e.what() << std::endl;
2142 for (
const auto &selected_folder : selected_folders)
2144 pcout <<
"\nProcessing folder: " << selected_folder << std::endl;
2147 std::vector<double> potentials_vec;
2148 bool success =
Utils::read_vector(potentials_vec,
"output/" + selected_folder +
"/potentials", io_coding);
2151 pcout <<
"Failed to read potentials from output/" << selected_folder <<
"/potentials" << std::endl;
2155 if (potentials_vec.size() != target_points.size())
2157 pcout <<
Color::red <<
Color::bold <<
"Error: Mismatch between potentials size (" << potentials_vec.size()
2158 <<
") and target points size (" << target_points.size() <<
")" <<
Color::reset << std::endl;
2163 Vector<double> potentials(potentials_vec.size());
2164 std::copy(potentials_vec.begin(), potentials_vec.end(), potentials.begin());
2167 const std::string output_dir =
"output/" + selected_folder +
"/power_diagram_" + power_diagram_params.implementation;
2168 fs::create_directories(output_dir);
2171 std::unique_ptr<PowerDiagramSpace::PowerDiagramBase<dim, spacedim>> power_diagram;
2175 if (power_diagram_params.implementation ==
"geogram")
2177 if constexpr (dim == 3 and spacedim==dim)
2179 power_diagram = PowerDiagramSpace::create_power_diagram<dim, spacedim>(
2182 "output/data_mesh/source.msh");
2183 pcout <<
"Using Geogram implementation for power diagram" << std::endl;
2187 pcout <<
"Geogram implementation is only available for 3D problems" << std::endl;
2188 pcout <<
"Falling back to Deal.II implementation" << std::endl;
2189 power_diagram = PowerDiagramSpace::create_power_diagram<dim, spacedim>(
2196 power_diagram = PowerDiagramSpace::create_power_diagram<dim, spacedim>(
2199 pcout <<
"Using Deal.II implementation for power diagram" << std::endl;
2202 catch (
const std::exception &e)
2204 pcout <<
Color::red <<
Color::bold <<
"Failed to initialize " << power_diagram_params.implementation
2205 <<
" implementation: " << e.what() <<
Color::reset << std::endl;
2206 if (power_diagram_params.implementation ==
"geogram")
2208 pcout <<
"Falling back to Deal.II implementation" << std::endl;
2209 power_diagram = PowerDiagramSpace::create_power_diagram<dim, spacedim>(
2220 power_diagram->set_generators(target_points, potentials);
2221 power_diagram->compute_power_diagram();
2222 power_diagram->compute_cell_centroids();
2225 power_diagram->save_centroids_to_file(output_dir +
"/centroids");
2226 power_diagram->output_vtu(output_dir +
"/power_diagram");
2228 pcout <<
"Power diagram computation completed for " << selected_folder << std::endl;
2229 pcout <<
"Results saved in " << output_dir << std::endl;
2232 if (selected_folders.size() > 1)
2234 pcout <<
"\nCompleted power diagram computation for all selected folders." << std::endl;
2242 setup_finite_elements();
2245 sot_solver->setup_source(dof_handler_source,
2249 solver_params.quadrature_order);
2252 sot_solver->setup_target(target_points, target_density);
2253 sot_solver->configure(solver_params);
2256 std::vector<unsigned int> indices = param_manager.conditional_density_params.indices;
2257 std::string potential_folder = param_manager.conditional_density_params.potential_folder;
2260 if (indices.empty())
2263 pcout <<
"Please specify indices in the parameter file under conditional_density_parameters/indices." << std::endl;
2268 std::string selected_folder;
2269 if (potential_folder.empty())
2272 std::vector<std::string> selected_folders;
2276 if (selected_folders.empty())
2278 pcout <<
"No folder selected. Exiting." << std::endl;
2281 selected_folder = selected_folders[0];
2283 catch (
const std::exception &e)
2285 pcout <<
"Error: " << e.what() << std::endl;
2291 selected_folder = potential_folder;
2294 pcout <<
"Computing conditional densities for folder: " << selected_folder << std::endl;
2295 pcout <<
"Indices: ";
2296 for (
size_t i = 0; i < indices.size(); ++i)
2298 if (i > 0) pcout <<
", ";
2299 pcout << indices[i];
2304 std::vector<double> potentials_vec;
2305 bool success =
Utils::read_vector(potentials_vec,
"output/" + selected_folder +
"/potentials", io_coding);
2308 pcout <<
"Failed to read potentials from output/" + selected_folder +
"/potentials" << std::endl;
2312 if (potentials_vec.size() != target_points.size())
2314 pcout <<
Color::red <<
Color::bold <<
"Error: Mismatch between potentials size (" << potentials_vec.size()
2315 <<
") and target points size (" << target_points.size() <<
")" <<
Color::reset << std::endl;
2320 Vector<double> potentials(potentials_vec.size());
2321 std::copy(potentials_vec.begin(), potentials_vec.end(), potentials.begin());
2324 for (
unsigned int idx : indices)
2326 if (idx >= target_points.size())
2328 pcout <<
Color::red <<
Color::bold <<
"Error: Index " << idx <<
" is out of bounds. Maximum index is "
2329 << target_points.size() - 1 <<
"." <<
Color::reset << std::endl;
2335 std::vector<LinearAlgebra::distributed::Vector<double, MemorySpace::Host>> conditioned_densities;
2338 if (param_manager.conditional_density_params.truncation_radius > 0.0)
2340 pcout <<
"Using truncation radius: " << param_manager.conditional_density_params.truncation_radius << std::endl;
2341 sot_solver->set_distance_threshold(param_manager.conditional_density_params.truncation_radius);
2344 pcout <<
"Computing conditional densities..." << std::endl;
2345 sot_solver->get_potential_conditioned_density(
2346 dof_handler_source, *mapping,
2347 potentials, indices, conditioned_densities);
2350 const std::string output_dir =
"output/" + selected_folder +
"/conditional_densities";
2351 fs::create_directories(output_dir);
2354 DataOut<dim, spacedim> data_out;
2355 data_out.attach_dof_handler(dof_handler_source);
2357 std::vector<DataComponentInterpretation::DataComponentInterpretation>
2358 interpretation(1, DataComponentInterpretation::component_is_scalar);
2360 pcout <<
"Saving " << conditioned_densities.size() <<
" conditional densities..." << std::endl;
2362 for (
unsigned int i = 0; i < conditioned_densities.size(); ++i)
2364 data_out.add_data_vector(
2365 conditioned_densities[i],
2366 std::string(
"conditional_density_") + std::to_string(indices[i]),
2367 DataOut<dim, spacedim>::type_dof_data,
2371 data_out.build_patches(*mapping, fe_system->degree);
2373 const std::string filename_base =
"conditional_densities";
2374 data_out.write_vtu_with_pvtu_record(output_dir +
"/",
2379 pcout <<
"Conditional densities saved to " << output_dir <<
"/" << filename_base <<
"_0.pvtu" << std::endl;
2382 for (
unsigned int i = 0; i < conditioned_densities.size(); ++i)
2384 DataOut<dim, spacedim> individual_data_out;
2385 individual_data_out.attach_dof_handler(dof_handler_source);
2386 individual_data_out.add_data_vector(
2387 conditioned_densities[i],
2388 std::string(
"conditional_density_") + std::to_string(indices[i]),
2389 DataOut<dim, spacedim>::type_dof_data,
2391 individual_data_out.build_patches(*mapping, fe_system->degree);
2393 const std::string individual_filename =
"conditional_density_" + std::to_string(indices[i]);
2394 individual_data_out.write_vtu_with_pvtu_record(output_dir +
"/",
2395 individual_filename,
2400 pcout <<
"Conditional density computation completed successfully." << std::endl;
2407 setup_finite_elements();
2410 const std::string directory =
"output/discrete_measures";
2411 fs::create_directories(directory);
2414 auto quadrature = Utils::create_quadrature_for_mesh<dim, spacedim>(source_mesh, solver_params.quadrature_order);
2416 FEValues<dim, spacedim> fe_values(*mapping, *fe_system, *quadrature,
2417 update_values | update_quadrature_points | update_JxW_values);
2420 const unsigned int n_q_points = quadrature->size();
2421 const unsigned int total_q_points = source_mesh.n_active_cells() * n_q_points;
2424 std::vector<Point<spacedim>> quad_points;
2425 std::vector<double> quad_weights;
2426 std::vector<double> density_values;
2427 quad_points.reserve(total_q_points);
2428 quad_weights.reserve(total_q_points);
2429 density_values.reserve(total_q_points);
2432 std::vector<double> local_density_values(n_q_points);
2435 for (
const auto &cell : dof_handler_source.active_cell_iterators())
2437 fe_values.reinit(cell);
2438 fe_values.get_function_values(source_density, local_density_values);
2440 for (
unsigned int q = 0; q < n_q_points; ++q)
2442 quad_points.push_back(fe_values.quadrature_point(q));
2443 quad_weights.push_back(fe_values.JxW(q));
2444 density_values.push_back(local_density_values[q]);
2455 std::vector<double> target_density_vec(target_density.begin(), target_density.end());
2459 std::ofstream meta(directory +
"/metadata.txt");
2460 meta <<
"Dimension: " << dim <<
"\n"
2461 <<
"Space dimension: " << spacedim <<
"\n"
2462 <<
"Number of quadrature points per cell: " << n_q_points <<
"\n"
2463 <<
"Total number of quadrature points: " << total_q_points <<
"\n"
2464 <<
"Number of target points: " << target_points.size() <<
"\n"
2465 <<
"Quadrature order: " << solver_params.quadrature_order <<
"\n"
2466 <<
"Using tetrahedral mesh: " << source_params.use_tetrahedral_mesh <<
"\n";
2469 pcout <<
"Discrete measures data saved in " << directory << std::endl;
2470 pcout <<
"Total quadrature points: " << total_q_points << std::endl;
2471 pcout <<
"Number of target points: " << target_points.size() << std::endl;
2479 std::string output_dir =
"output/interpolated_fields";
2480 fs::create_directories(output_dir);
2482 std::string source_field_name = source_params.density_field_name;
2483 std::string target_field_name = target_params.density_field_name;
2485 pcout <<
"Using source field name: " << source_field_name << std::endl;
2486 pcout <<
"Using target field name: " << target_field_name << std::endl;
2491 mesh_manager->load_source_mesh(source_mesh);
2492 setup_source_finite_elements(
false);
2494 std::string base_source_dir = output_dir +
"/base_source";
2495 fs::create_directories(base_source_dir);
2497 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0)
2499 DataOut<dim, spacedim> data_out;
2500 data_out.attach_dof_handler(dof_handler_source);
2501 data_out.add_data_vector(source_density, source_field_name);
2502 data_out.build_patches();
2504 std::string vtk_filename = base_source_dir +
"/" + source_field_name +
".vtk";
2505 std::ofstream output(vtk_filename);
2506 data_out.write_vtk(output);
2508 pcout <<
"Saved interpolated field for base source mesh to: " << vtk_filename << std::endl;
2514 mesh_manager->load_target_mesh(target_mesh);
2515 setup_target_finite_elements();
2517 std::string base_target_dir = output_dir +
"/base_target";
2518 fs::create_directories(base_target_dir);
2520 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0)
2522 DataOut<dim, spacedim> data_out;
2523 data_out.attach_dof_handler(dof_handler_target);
2524 data_out.add_data_vector(target_density, target_field_name);
2525 data_out.build_patches();
2527 std::string vtk_filename = base_target_dir +
"/" + target_field_name +
".vtk";
2528 std::ofstream output(vtk_filename);
2529 data_out.write_vtk(output);
2531 pcout <<
"Saved interpolated field for base target mesh to: " << vtk_filename << std::endl;
2534 if (multilevel_params.source_enabled)
2539 std::vector<std::string> source_mesh_files;
2540 unsigned int num_levels = 0;
2542 source_mesh_files = mesh_manager->get_mesh_hierarchy_files(multilevel_params.source_hierarchy_dir);
2543 if (source_mesh_files.empty())
2549 num_levels = source_mesh_files.size();
2550 pcout <<
"Found " << num_levels <<
" levels in the source mesh hierarchy" << std::endl;
2552 for (
size_t level = 0; level < source_mesh_files.size(); ++level)
2554 const unsigned int level_name = num_levels - level - 1;
2557 <<
"Processing source mesh level " << level_name
2558 <<
" (mesh: " << source_mesh_files[level] <<
")" <<
Color::reset << std::endl;
2560 std::string level_dir = output_dir +
"/source_level_" + std::to_string(level_name);
2561 fs::create_directories(level_dir);
2563 mesh_manager->load_mesh_at_level(source_mesh, dof_handler_source, source_mesh_files[level]);
2565 setup_source_finite_elements(
true);
2567 if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0)
2569 DataOut<dim, spacedim> data_out;
2570 data_out.attach_dof_handler(dof_handler_source);
2571 data_out.add_data_vector(source_density, source_field_name);
2572 data_out.build_patches();
2574 std::string vtk_filename = level_dir +
"/" + source_field_name +
".vtk";
2575 std::ofstream output(vtk_filename);
2576 data_out.write_vtk(output);
2578 pcout <<
"Saved interpolated field for source level " << level_name
2579 <<
" to: " << vtk_filename << std::endl;
2587 <<
"Field interpolation visualization completed!" <<
Color::reset << std::endl;
2588 pcout <<
"Results saved in: " << output_dir << std::endl;