72 Explicit_time_stepper_pt(0),
74 Default_set_initial_condition_called(false),
75 Use_globally_convergent_newton_method(false),
76 Empty_actions_before_read_unstructured_meshes_has_been_called(false),
77 Empty_actions_after_read_unstructured_meshes_has_been_called(false),
78 Store_local_dof_pt_in_elements(false),
79 Calculate_hessian_products_analytic(false),
81 Doc_imbalance_in_parallel_assembly(false),
82 Use_default_partition_in_load_balance(false),
83 Must_recompute_load_balance_for_assembly(true),
86 Relaxation_factor(1.0),
87 Newton_solver_tolerance(1.0e-8),
89 Nnewton_iter_taken(0),
91 Time_adaptive_newton_crash_on_solve_fail(false),
92 Jacobian_reuse_is_enabled(false),
93 Jacobian_has_been_computed(false),
94 Problem_is_nonlinear(true),
95 Pause_at_end_of_sparse_assembly(false),
96 Doc_time_in_distribute(false),
97 Sparse_assembly_method(Perform_assembly_using_vectors_of_pairs),
98 Sparse_assemble_with_arrays_initial_allocation(400),
99 Sparse_assemble_with_arrays_allocation_increment(150),
100 Numerical_zero_for_sparse_assembly(0.0),
101 FD_step_used_in_get_hessian_vector_products(1.0e-8),
102 Mass_matrix_reuse_is_enabled(false),
103 Mass_matrix_has_been_computed(false),
104 Discontinuous_element_formulation(false),
107 DTSF_max_increase(4.0),
108 DTSF_min_decrease(0.8),
109 Target_error_safety_factor(1.0),
110 Minimum_dt_but_still_proceed(-1.0),
111 Scale_arc_length(true),
112 Desired_proportion_of_arc_length(0.5),
115 Continuation_direction(1.0),
116 Parameter_derivative(1.0),
117 Parameter_current(0.0),
118 Use_continuation_timestepper(false),
119 Dof_derivative_offset(1),
120 Dof_current_offset(2),
122 Desired_newton_iterations_ds(5),
124 Bifurcation_detection(false),
125 Bisect_to_find_bifurcation(false),
126 First_jacobian_sign_change(false),
127 Arc_length_step_taken(false),
128 Use_finite_differences_for_continuation_derivatives(false),
130 Dist_problem_matrix_distribution(Uniform_matrix_distribution),
131 Parallel_sparse_assemble_previous_allocation(0),
132 Problem_has_been_distributed(false),
133 Bypass_increase_in_dof_check_during_pruning(false),
134 Max_permitted_error_for_halo_check(1.0e-14),
136 Shut_up_in_newton_solve(false),
137 Always_take_one_newton_step(false),
138 Timestep_reduction_factor_after_nonconvergence(0.5),
139 Keep_temporal_error_below_tolerance(true)
208 for (
unsigned c = 0; c < n_copies; c++)
243 unsigned n_non_halo_element_local = 0;
244 for (
unsigned e = 0;
e < n_element;
e++)
253 ++n_non_halo_element_local;
257 for (
unsigned n = 0; n < n_var; n++)
268 unsigned Nelement = 0;
278 MPI_Allreduce(&n_non_halo_element_local,
289 Nelement = n_non_halo_element_local;
304 const unsigned nrow = this->
ndof();
343 bool use_problem_dist =
true;
344 for (
unsigned p = 0; p < nproc; p++)
348 ((
double)uniform_dist_pt->
nrow_local(p)) * 1.1)
350 use_problem_dist =
false;
353 if (use_problem_dist)
361 delete uniform_dist_pt;
367 std::ostringstream error_stream;
368 error_stream <<
"Never get here. Dist_problem_matrix_distribution = "
371 OOMPH_CURRENT_FUNCTION,
372 OOMPH_EXCEPTION_LOCATION);
405 std::map<unsigned, double*> halo_data_pt;
427 return distribute(element_partition, doc_info, report_stats);
440 bool has_non_zero_entry =
false;
441 unsigned n = element_partition.size();
442 for (
unsigned i = 0;
i < n;
i++)
444 if (element_partition[
i] != 0)
446 has_non_zero_entry =
true;
450 if (!has_non_zero_entry)
452 std::ostringstream warn_message;
453 warn_message <<
"WARNING: All entries in specified partitioning vector \n"
454 <<
" are zero -- will ignore this and use METIS\n"
455 <<
" to perform the partitioning\n";
457 warn_message.str(),
"Problem::distribute()", OOMPH_EXCEPTION_LOCATION);
465 return distribute(element_partition, doc_info, report_stats);
473 const bool& report_stats)
482 return distribute(element_partition, doc_info, report_stats);
494 const bool& report_stats)
509 std::ostringstream warn_message;
510 warn_message <<
"WARNING: You've tried to distribute a problem over\n"
511 <<
"only one processor: this would make METIS crash.\n"
512 <<
"Ignoring your request for distribution.\n";
514 "Problem::distribute()",
515 OOMPH_EXCEPTION_LOCATION);
518 else if (n_proc > n_element)
521 std::ostringstream error_stream;
522 error_stream <<
"You have tried to distribute a problem\n"
523 <<
"but there are less elements than processors.\n"
524 <<
"Please re-run with more elements!\n"
525 <<
"Please also ensure that actions_before_distribute().\n"
526 <<
"and actions_after_distribute() are correctly set up.\n"
529 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
535 bool a_mesh_is_not_uniformly_refined =
false;
543 unsigned min_ref_level = 0;
544 unsigned max_ref_level = 0;
545 mmesh_pt->get_refinement_levels(min_ref_level, max_ref_level);
547 if (max_ref_level != min_ref_level)
549 a_mesh_is_not_uniformly_refined =
true;
555 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
562 unsigned min_ref_level = 0;
563 unsigned max_ref_level = 0;
564 mmesh_pt->get_refinement_levels(min_ref_level, max_ref_level);
566 if (max_ref_level != min_ref_level)
568 a_mesh_is_not_uniformly_refined =
true;
575 if (a_mesh_is_not_uniformly_refined)
580 std::ostringstream error_stream;
581 error_stream <<
"You have tried to distribute a problem\n"
582 <<
"but at least one of your meshes is no longer\n"
583 <<
"uniformly refined. In order to preserve the Tree\n"
584 <<
"and TreeForest structure, Problem::distribute() can\n"
585 <<
"only be called while meshes are uniformly refined.\n"
588 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
595 std::ostringstream error_stream;
596 error_stream <<
"You have tried to distribute a problem\n"
597 <<
"and there is some global data.\n"
598 <<
"This is not likely to work...\n"
601 OOMPH_CURRENT_FUNCTION,
602 OOMPH_EXCEPTION_LOCATION);
613 unsigned old_ndof =
ndof();
620 unsigned nelem = global_mesh_pt->
nelement();
625 unsigned n_my_elements = 0;
628 bool used_preset_partitioning =
false;
633 unsigned sum_element_partition = 0;
634 unsigned n_part = element_partition.size();
635 for (
unsigned e = 0;
e < n_part;
e++)
638 if (
int(element_partition[
e]) == my_rank) n_my_elements++;
640 sum_element_partition += element_partition[
e];
642 if (sum_element_partition == 0)
644 oomph_info <<
"INFO: using METIS to partition elements" << std::endl;
646 used_preset_partitioning =
false;
650 oomph_info <<
"INFO: using pre-set partition of elements"
652 used_preset_partitioning =
true;
653 element_domain = element_partition;
663 oomph_info <<
"Time for partitioning of global mesh: "
664 << t_end - t_start << std::endl;
674 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
677 n_element_in_old_submesh[i_mesh] = nsub_elem;
687 oomph_info <<
"Time for actions before distribute: "
688 << t_end - t_start << std::endl;
705 return_element_domain.reserve(element_domain.size());
709 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
712 submesh_element_domain[i_mesh].resize(nsub_elem);
713 unsigned nsub_elem_old = n_element_in_old_submesh[i_mesh];
714 for (
unsigned e = 0;
e < nsub_elem_old;
e++)
716 if (nsub_elem_old == nsub_elem)
718 submesh_element_domain[i_mesh][
e] = element_domain[count];
719 return_element_domain.push_back(element_domain[count]);
728 return_element_domain = element_domain;
744 bool structured_mesh =
true;
747 if (tri_mesh_pt != 0)
749 structured_mesh =
false;
753 const unsigned n_ele = global_mesh_pt->
nelement();
756 for (
unsigned e = 0;
e < n_ele;
e++)
769 unsigned nglobal_element = 0;
771 std::vector<bool> is_structured_mesh(n_mesh);
772 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
776 if (tri_mesh_pt != 0)
780 is_structured_mesh[i_mesh] =
false;
786 is_structured_mesh[i_mesh] =
true;
789 if (is_structured_mesh[i_mesh])
799 unsigned counter = 0;
800 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
803 if (is_structured_mesh[i_mesh])
806 for (
unsigned e = 0;
e < n_ele;
e++)
818 if (counter != nglobal_element)
820 std::ostringstream error_stream;
822 <<
"The number of global elements (" << nglobal_element
823 <<
") is not the sameas the number of\nadded elements ("
824 << counter <<
") to the Base_mesh_element_pt data "
825 <<
"structure!!!\n\n";
827 "Problem::distribute()",
828 OOMPH_EXCEPTION_LOCATION);
839 bool overrule_keep_as_halo_element_status =
false;
840 if ((n_my_elements == 0) && (used_preset_partitioning))
842 oomph_info <<
"INFO: We're over-ruling the \"keep as halo element\"\n"
843 <<
" status because the preset partitioning\n"
844 <<
" didn't place ANY elements on this processor,\n"
845 <<
" probably because of a restart on a larger \n"
846 <<
" number of processors\n";
847 overrule_keep_as_halo_element_status =
true;
860 overrule_keep_as_halo_element_status);
864 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
868 oomph_info <<
"Distributing submesh " << i_mesh << std::endl
869 <<
"--------------------" << std::endl;
872 doc_info.
number() = i_mesh;
874 submesh_element_domain[i_mesh],
878 overrule_keep_as_halo_element_status);
885 unsigned n_del = deleted_element_pt.size();
886 for (
unsigned e = 0;
e < n_del;
e++)
897 oomph_info <<
"Time for mesh-level distribution: " << t_end - t_start
911 oomph_info <<
"Time for actions after distribute: " << t_end - t_start
918 oomph_info <<
"Number of equations: " << n_dof << std::endl;
923 oomph_info <<
"Time for re-assigning eqn numbers (in distribute): "
924 << t_end - t_start << std::endl;
929 if (n_dof != old_ndof)
931 std::ostringstream error_stream;
933 <<
"Number of dofs in distribute() has changed "
934 <<
"from " << old_ndof <<
" to " << n_dof <<
"\n"
935 <<
"Check that you've implemented any necessary "
936 "actions_before/after\n"
937 <<
"distribute functions, e.g. to pin redundant pressure dofs"
940 OOMPH_CURRENT_FUNCTION,
941 OOMPH_EXCEPTION_LOCATION);
956 return return_element_domain;
968 const bool& report_stats)
974 std::ostringstream filename;
975 std::ofstream some_file;
983 filename << doc_info.
directory() <<
"/complete_mesh"
984 << doc_info.
number() <<
".dat";
985 global_mesh_pt->
output(filename.str().c_str(), 5);
992 unsigned objective = 0;
999 nelem = element_domain.size();
1001 MPI_Bcast(&nelem, 1, MPI_UNSIGNED, 0, this->
communicator_pt()->mpi_comm());
1002 element_domain.resize(nelem);
1003 MPI_Bcast(&element_domain[0],
1015 for (
unsigned e = 0;
e < nelem;
e++)
1017 int_element_domain[
e] = element_domain[
e];
1021 int my_number_of_elements = 0;
1024 for (
unsigned e = 0;
e < nelem;
e++)
1026 if (int_element_domain[
e] == rank)
1028 my_number_of_elements++;
1034 MPI_Allgather(&my_number_of_elements,
1037 &number_of_elements[0],
1045 int max_number_of_elements = 0;
1046 int process_with_max_elements = 0;
1047 for (
int d = 0; d < n_proc; d++)
1049 if (number_of_elements[d] == 0)
1052 if (max_number_of_elements <= 1)
1054 for (
int dd = 0; dd < n_proc; dd++)
1056 if (number_of_elements[dd] > max_number_of_elements)
1058 max_number_of_elements = number_of_elements[dd];
1059 process_with_max_elements = dd;
1065 if (max_number_of_elements <= 1)
1068 std::ostringstream error_stream;
1069 error_stream <<
"No process has more than 1 element, and\n"
1070 <<
"at least one process has no elements!\n"
1071 <<
"Suggest rerunning with more refinement.\n"
1074 OOMPH_CURRENT_FUNCTION,
1075 OOMPH_EXCEPTION_LOCATION);
1080 for (
unsigned e = 0;
e < nelem;
e++)
1082 if (int_element_domain[
e] == process_with_max_elements)
1084 int_element_domain[
e] = d;
1086 number_of_elements[d]++;
1087 number_of_elements[process_with_max_elements]--;
1089 max_number_of_elements--;
1093 oomph_info <<
"INFO: Switched element domain at position " <<
e
1095 <<
"from process " << process_with_max_elements
1096 <<
" to process " << d << std::endl
1097 <<
"which was given no elements by METIS partition"
1110 for (
unsigned e = 0;
e < nelem;
e++)
1112 element_domain[
e] = int_element_domain[
e];
1115 unsigned count_elements = 0;
1116 for (
unsigned e = 0;
e < nelem;
e++)
1118 if (
int(element_domain[
e]) == rank)
1127 <<
" elements from this partition" << std::endl
1141 const bool& report_stats)
1150 <<
"WARNING: Problem::prune_halo_elements_and_nodes() was called on a "
1151 <<
"non-distributed Problem!" << std::endl;
1152 oomph_info <<
"Ignoring your request..." << std::endl;
1160 <<
"WARNING: You've tried to prune halo layers on a problem\n"
1161 <<
"with only one processor: this is unnecessary.\n"
1162 <<
"Ignoring your request." << std::endl
1168 unsigned old_ndof =
ndof();
1171 double t_start = 0.0;
1184 oomph_info <<
"Time for actions_before_distribute() in "
1185 <<
"Problem::prune_halo_elements_and_nodes(): "
1186 << t_end - t_start << std::endl;
1192 std::map<GeneralisedElement*, unsigned>
1193 old_base_element_number_plus_one;
1194 std::vector<bool> old_root_is_halo_or_non_existent(nel,
true);
1195 for (
unsigned e = 0;
e < nel;
e++)
1201 if (base_el_pt != 0)
1206 old_root_is_halo_or_non_existent[
e] =
false;
1214 old_base_element_number_plus_one[base_el_pt] =
e + 1;
1221 unsigned ntree = tree_pt.size();
1222 for (
unsigned t = 0;
t < ntree;
t++)
1224 old_base_element_number_plus_one[tree_pt[
t]->object_pt()] =
1235 oomph_info <<
"Time for setup old root elements in "
1236 <<
"Problem::prune_halo_elements_and_nodes(): "
1237 << t_end - t_start << std::endl;
1243 unsigned nel_base_old = nel;
1253 deleted_element_pt, doc_info, report_stats);
1258 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
1261 deleted_element_pt, doc_info, report_stats);
1271 oomph_info <<
"Total time for all mesh-level prunes in "
1272 <<
"Problem::prune_halo_elements_and_nodes(): "
1273 << t_end - t_start << std::endl;
1281 std::map<FiniteElement*, bool> root_el_done;
1286 new_base_element_associated_with_old_base_element(nel_base_old);
1288 unsigned n_meshes = n_mesh;
1299 std::vector<bool> is_structured_mesh(n_meshes);
1304 for (
unsigned i_mesh = 0; i_mesh < n_meshes; i_mesh++)
1308 if (!(tri_mesh_pt != 0))
1311 is_structured_mesh[i_mesh] =
true;
1318 is_structured_mesh[i_mesh] =
false;
1323 for (
unsigned i_mesh = 0; i_mesh < n_meshes; i_mesh++)
1327 if (is_structured_mesh[i_mesh])
1331 for (
unsigned e = 0;
e < nele_submesh;
e++)
1341 unsigned old_base_el_no =
1342 old_base_element_number_plus_one[el_pt] - 1;
1343 new_base_element_associated_with_old_base_element
1354 unsigned old_base_el_no =
1355 old_base_element_number_plus_one[el_pt] - 1;
1356 new_base_element_associated_with_old_base_element
1366 if (!root_el_done[root_el_pt])
1368 root_el_done[root_el_pt] =
true;
1369 unsigned old_base_el_no =
1370 old_base_element_number_plus_one[el_pt] - 1;
1371 new_base_element_associated_with_old_base_element
1373 .push_back(root_el_pt);
1387 for (
unsigned e = 0;
e < nel_base_old;
e++)
1389 local_n_new_root[
e] =
1390 new_base_element_associated_with_old_base_element[
e].size();
1394 n_new_root_back[
e] = local_n_new_root[
e];
1401 oomph_info <<
"Time for setup of new base elements in "
1402 <<
"Problem::prune_halo_elements_and_nodes(): "
1403 << t_end - t_start << std::endl;
1411 MPI_Allreduce(&local_n_new_root[0],
1423 <<
"Problem::prune_halo_elements_and_nodes(): "
1424 << t_end - t_start << std::endl;
1429 unsigned nel_base_new = 0;
1430 for (
unsigned e = 0;
e < nel_base_old;
e++)
1433 nel_base_new += n_new_root[
e];
1440 if (!old_root_is_halo_or_non_existent[
e])
1442 if (n_new_root_back[
e] != 0)
1444 if (n_new_root_back[
e] != n_new_root[
e])
1446 std::ostringstream error_stream;
1448 <<
"Number of new root elements spawned from old root " <<
e
1449 <<
": " << n_new_root[
e] <<
"\nis not consistent"
1450 <<
" with previous value: " << n_new_root_back[
e]
1453 OOMPH_CURRENT_FUNCTION,
1454 OOMPH_EXCEPTION_LOCATION);
1469 for (
unsigned e = 0;
e < nel_base_old;
e++)
1473 if (!old_root_is_halo_or_non_existent[
e])
1476 unsigned n_new_root =
1477 new_base_element_associated_with_old_base_element[
e].size();
1478 for (
unsigned j = 0; j < n_new_root; j++)
1482 new_base_element_associated_with_old_base_element[
e][j];
1495 unsigned nskip = n_new_root[
e];
1508 oomph_info <<
"Time for finishing off base mesh info "
1509 <<
"Problem::prune_halo_elements_and_nodes(): "
1510 << t_end - t_start << std::endl;
1522 oomph_info <<
"Time for actions_after_distribute() "
1523 <<
"Problem::prune_halo_elements_and_nodes(): "
1524 << t_end - t_start << std::endl;
1540 oomph_info <<
"Time for assign_eqn_numbers() "
1541 <<
"Problem::prune_halo_elements_and_nodes(): "
1542 << t_end - t_start << std::endl;
1550 if (n_dof != old_ndof)
1552 std::ostringstream error_stream;
1554 <<
"Number of dofs in prune_halo_elements_and_nodes() has "
1556 <<
"from " << old_ndof <<
" to " << n_dof <<
"\n"
1557 <<
"Check that you've implemented any necessary "
1558 "actions_before/after"
1559 <<
"\nadapt/distribute functions, e.g. to pin redundant pressure"
1562 OOMPH_CURRENT_FUNCTION,
1563 OOMPH_EXCEPTION_LOCATION);
1586 std::string error_message =
"Problem::build_global_mesh() called,\n";
1587 error_message +=
" but a global mesh has already been built:\n";
1588 error_message +=
"Problem::Mesh_pt is not zero!\n";
1591 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1596 std::string error_message =
"Problem::build_global_mesh() called,\n";
1597 error_message +=
" but there are no submeshes:\n";
1598 error_message +=
"Problem::Sub_mesh_pt has no entries\n";
1601 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1645 oomph_info <<
"Created Time with " << ndt <<
" timesteps" << std::endl;
1654 oomph_info <<
"Resized Time to include " << ndt <<
" timesteps"
1660 oomph_info <<
"Time object already has storage for " << ndt
1661 <<
" timesteps" << std::endl;
1684 oomph_info <<
"Created Time with storage for no previous timestep"
1689 oomph_info <<
"Time object already exists " << std::endl;
1694 #ifdef OOMPH_HAS_MPI
1706 unsigned min_el = 10;
1717 unsigned lo_proc = 0;
1718 unsigned hi_proc = n_proc - 1;
1719 if (
int(n_elements) >= n_proc)
1721 range = unsigned(
double(n_elements) /
double(n_proc));
1727 hi_proc = unsigned(
double(n_elements) /
double(min_el));
1730 for (
int p = lo_proc; p <= int(hi_proc); p++)
1734 unsigned last_el_plus_one = (p + 1) * range;
1735 if (last_el_plus_one > n_elements) last_el_plus_one = n_elements;
1740 if (
int(n_elements) >= n_proc)
1750 oomph_info <<
"Problem is not distributed. Parallel assembly of "
1751 <<
"Jacobian uses default partitioning: " << std::endl;
1752 for (
int p = 0; p < n_proc; p++)
1756 oomph_info <<
"Proc " << p <<
" assembles from element "
1762 oomph_info <<
"Proc " << p <<
" assembles no elements\n";
1788 if (
int(nel) < n_proc)
1790 oomph_info <<
"Not re-computing distribution of elemental assembly\n"
1791 <<
"because there are fewer elements than processors\n";
1800 for (
int p = 0; p < n_proc; p++)
1808 receive_count[p] = el_hi - el_lo + 1;
1809 displacement[p] = offset;
1810 offset += el_hi - el_lo + 1;
1814 double* el_ass_time =
new double[nel];
1815 for (
unsigned e = 0;
e < nel;
e++)
1821 unsigned nel_local =
1832 delete[] el_ass_time;
1836 for (
int p = 0; p < n_proc; p++)
1838 first_and_last_element[p].resize(2);
1848 <<
"Re-assigning distribution of element assembly over processors:"
1855 for (
unsigned e = 0;
e < n_elements;
e++)
1861 double target_load = total / double(n_proc);
1865 first_and_last_element[0][0] = 0;
1869 unsigned max_el_avail = n_elements - n_proc;
1873 for (
unsigned e = 0;
e < n_elements;
e++)
1879 if ((total > target_load) || (
e == max_el_avail))
1882 first_and_last_element[proc][1] =
e;
1885 if (proc < (n_proc - 1))
1888 first_and_last_element[proc + 1][0] =
e + 1;
1904 first_and_last_element[n_proc - 1][1] = n_elements - 1;
1911 std::ostringstream error_stream;
1912 for (
int p = 0; p < n_proc - 1; p++)
1914 unsigned first_of_current = first_and_last_element[p][0];
1915 unsigned last_of_current = first_and_last_element[p][1];
1916 if (first_of_current > last_of_current)
1919 error_stream <<
"Error: First/last element of proc " << p <<
": "
1920 << first_of_current <<
" " << last_of_current
1923 unsigned first_of_next = first_and_last_element[p + 1][0];
1924 if (first_of_next != (last_of_current + 1))
1927 error_stream <<
"Error: First element of proc " << p + 1 <<
": "
1928 << first_of_next <<
" and last element of proc " << p
1929 <<
": " << last_of_current << std::endl;
1935 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2009 oomph_info <<
"Processor " << 0 <<
" assembles Jacobians"
2010 <<
" from elements " << first_and_last_element[0][0]
2011 <<
" to " << first_and_last_element[0][1] <<
" "
2016 for (
int p = 1; p < n_proc; ++p)
2018 MPI_Send(&first_and_last_element[p][0],
2028 oomph_info <<
"Processor " << p <<
" assembles Jacobians"
2029 <<
" from elements " << first_and_last_element[p][0]
2030 <<
" to " << first_and_last_element[p][1] <<
" "
2052 for (
int p = 0; p < n_proc; p++)
2077 const bool& assign_local_eqn_numbers)
2083 std::ostringstream error_stream;
2084 error_stream <<
"Global mesh does not exist, so equation numbers cannot "
2089 error_stream <<
"There aren't even any sub-meshes in the Problem.\n"
2090 <<
"You can set the global mesh directly by using\n"
2091 <<
"Problem::mesh_pt() = my_mesh_pt;\n"
2092 <<
"OR you can use Problem::add_sub_mesh(mesh_pt); "
2093 <<
"to add a sub mesh.\n";
2097 error_stream <<
"There are " <<
nsub_mesh() <<
" sub-meshes.\n";
2099 error_stream <<
"You need to call Problem::build_global_mesh() to create "
2101 <<
"from the sub-meshes.\n\n";
2104 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2111 #ifdef OOMPH_HAS_MPI
2141 double t_start = 0.0;
2152 for (
unsigned e = 0;
e < nel;
e++)
2157 #ifdef OOMPH_HAS_MPI
2160 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
2162 for (
int iproc = 0; iproc < n_proc; iproc++)
2165 for (
unsigned e = 0;
e < n_ext_halo_el;
e++)
2181 <<
"Time for complete setup of dependencies in assign_eqn_numbers: "
2182 << t_end - t_start << std::endl;
2192 for (
unsigned loop_count = 0; loop_count < 2; loop_count++)
2203 unsigned long equation_number = 0;
2207 for (
unsigned i = 0;
i < Nglobal_data;
i++)
2222 if (n_sub_mesh == 0)
2226 n_dof = spine_mesh_pt->assign_global_spine_eqn_numbers(
Dof_pt);
2233 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
2238 n_dof = spine_mesh_pt->assign_global_spine_eqn_numbers(
Dof_pt);
2247 <<
"Time for assign_global_eqn_numbers in assign_eqn_numbers: "
2248 << t_end - t_start << std::endl;
2253 #ifdef OOMPH_HAS_MPI
2280 oomph_info <<
"Time for Problem::synchronise_eqn_numbers in "
2281 <<
"Problem::assign_eqn_numbers: " << t_end - t_start
2286 #ifdef OOMPH_HAS_MPI
2298 bool actually_removed_some_data =
false;
2301 if (loop_count == 0)
2303 if (n_sub_mesh == 0)
2309 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
2311 bool tmp_actually_removed_some_data =
false;
2313 tmp_actually_removed_some_data);
2314 if (tmp_actually_removed_some_data)
2315 actually_removed_some_data =
true;
2324 std::stringstream tmp;
2325 tmp <<
"Time for calls to Problem::remove_duplicate_data in "
2326 <<
"Problem::assign_eqn_numbers: " << t_end - t_start
2328 if (!actually_removed_some_data)
2332 tmp <<
" removed some/any data.\n";
2338 unsigned status = 0;
2339 if (actually_removed_some_data) status = 1;
2342 unsigned overall_status = 0;
2343 MPI_Allreduce(&status,
2354 std::stringstream tmp;
2356 <<
"Time for MPI_Allreduce after Problem::remove_duplicate_data in "
2357 <<
"Problem::assign_eqn_numbers: " << t_end - t_start << std::endl;
2363 if (overall_status != 1)
2379 <<
"Problem::remove_null_pointers_from_external_halo_node_"
2381 << t_end - t_start << std::endl;
2411 if (assign_local_eqn_numbers)
2413 if (n_sub_mesh == 0)
2419 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
2430 oomph_info <<
"Total time for all Mesh::assign_local_eqn_numbers in "
2431 <<
"Problem::assign_eqn_numbers: " << t_end - t_start
2452 std::ostringstream error_stream;
2454 <<
"Global mesh does not exist, so equation numbers cannot be found.\n";
2458 error_stream <<
"There aren't even any sub-meshes in the Problem.\n"
2459 <<
"You can set the global mesh directly by using\n"
2460 <<
"Problem::mesh_pt() = my_mesh_pt;\n"
2461 <<
"OR you can use Problem::add_sub_mesh(mesh_pt); "
2462 <<
"to add a sub mesh.\n";
2466 error_stream <<
"There are " <<
nsub_mesh() <<
" sub-meshes.\n";
2468 error_stream <<
"You need to call Problem::build_global_mesh() to create "
2470 <<
"from the sub-meshes.\n\n";
2473 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2478 <<
"Although this program will describe the degrees of freedom in the \n"
2479 <<
"problem, it will do so using the typedef for the elements. This is \n"
2480 <<
"not neccesarily human readable, but there is a solution.\n"
2481 <<
"Pipe your program's output through c++filt, with the argument -t.\n"
2482 <<
"e.g. \"./two_d_multi_poisson | c++filt -t > ReadableOutput.txt\".\n "
2483 <<
"(Disregarding the quotes)\n\n\n";
2485 out <<
"Classifying Global Equation Numbers" << std::endl;
2493 for (
unsigned i = 0;
i < Nglobal_data;
i++)
2495 std::stringstream conversion;
2496 conversion <<
" in Global Data " <<
i <<
".";
2510 if (n_sub_mesh == 0)
2515 spine_mesh_pt->describe_spine_dofs(out, in);
2522 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
2527 std::stringstream conversion;
2528 conversion <<
" in Sub-SpineMesh " <<
i <<
".";
2530 spine_mesh_pt->describe_spine_dofs(out, in);
2539 out <<
"Classifying global eqn numbers in terms of elements." << std::endl;
2541 out <<
"Eqns | Source" << std::endl;
2544 if (n_sub_mesh == 0)
2551 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
2553 std::stringstream conversion;
2554 conversion <<
" in Sub-Mesh " <<
i <<
".";
2569 const unsigned long n_dof =
ndof();
2575 for (
unsigned long l = 0; l < n_dof; l++)
2587 throw OomphLibError(
"Not designed for distributed problems",
2588 OOMPH_EXCEPTION_LOCATION,
2589 OOMPH_CURRENT_FUNCTION);
2599 for (
unsigned i = 0;
i < Nglobal_data;
i++)
2605 if (eqn_number >= 0)
2613 for (
unsigned i = 0, ni =
mesh_pt()->nelement();
i < ni;
i++)
2619 for (
unsigned k = 0, nk = d_pt->
nvalue(); k < nk; k++)
2622 if (eqn_number >= 0)
2624 dofs[eqn_number] = d_pt->
value(
t, k);
2631 for (
unsigned i = 0, ni =
mesh_pt()->nnode();
i < ni;
i++)
2634 for (
unsigned j = 0, nj = node_pt->
nvalue(); j < nj; j++)
2638 if (eqn_number >= 0)
2640 dofs[eqn_number] = node_pt->
value(
t, j);
2647 #ifdef OOMPH_HAS_MPI
2656 bool& actually_removed_some_data)
2670 actually_removed_some_data =
false;
2687 std::map<unsigned, Node*> global_node_pt;
2690 std::map<Node*, bool> node_done;
2694 for (
unsigned e = 0;
e < n_element;
e++)
2701 unsigned n_node = el_pt->
nnode();
2702 for (
unsigned j = 0; j < n_node; j++)
2707 if (!node_done[nod_pt])
2709 node_done[nod_pt] =
true;
2713 unsigned first_non_negative_eqn_number_plus_one = 0;
2714 unsigned n_val = nod_pt->
nvalue();
2715 for (
unsigned i_val = 0; i_val < n_val; i_val++)
2720 first_non_negative_eqn_number_plus_one = eqn_no + 1;
2727 if (first_non_negative_eqn_number_plus_one == 0)
2731 if (solid_nod_pt != 0)
2736 for (
unsigned i_val = 0; i_val < n_val; i_val++)
2742 first_non_negative_eqn_number_plus_one = eqn_no + 1;
2750 if (first_non_negative_eqn_number_plus_one > 0)
2752 global_node_pt[first_non_negative_eqn_number_plus_one - 1] =
2761 ->ncont_interpolated_values();
2762 for (
int i_cont = -1; i_cont < n_cont_int_values; i_cont++)
2767 unsigned n_master = hang_pt->
nmaster();
2768 for (
unsigned m = 0; m < n_master; m++)
2771 if (!node_done[master_nod_pt])
2773 node_done[master_nod_pt] =
true;
2777 unsigned first_non_negative_eqn_number_plus_one = 0;
2778 unsigned n_val = master_nod_pt->
nvalue();
2779 for (
unsigned i_val = 0; i_val < n_val; i_val++)
2781 int eqn_no = master_nod_pt->
eqn_number(i_val);
2784 first_non_negative_eqn_number_plus_one = eqn_no + 1;
2791 if (first_non_negative_eqn_number_plus_one == 0)
2796 dynamic_cast<SolidNode*
>(master_nod_pt);
2797 if (master_solid_nod_pt != 0)
2804 for (
unsigned i_val = 0; i_val < n_val; i_val++)
2811 first_non_negative_eqn_number_plus_one =
2820 if (first_non_negative_eqn_number_plus_one > 0)
2822 global_node_pt[first_non_negative_eqn_number_plus_one -
2841 std::set<Node*> killed_nodes;
2846 for (
int iproc = n_proc - 1; iproc >= 0; iproc--)
2849 if (iproc != my_rank)
2854 for (
unsigned e_ext = 0; e_ext < n_element; e_ext++)
2858 if (finite_ext_el_pt != 0)
2861 unsigned n_node = finite_ext_el_pt->
nnode();
2862 for (
unsigned j = 0; j < n_node; j++)
2868 unsigned first_non_negative_eqn_number_plus_one = 0;
2869 unsigned n_val = nod_pt->
nvalue();
2870 for (
unsigned i_val = 0; i_val < n_val; i_val++)
2875 first_non_negative_eqn_number_plus_one = eqn_no + 1;
2882 if (first_non_negative_eqn_number_plus_one == 0)
2886 if (solid_nod_pt != 0)
2892 for (
unsigned i_val = 0; i_val < n_val; i_val++)
2898 first_non_negative_eqn_number_plus_one = eqn_no + 1;
2908 if (first_non_negative_eqn_number_plus_one > 0)
2910 Node* existing_node_pt =
2911 global_node_pt[first_non_negative_eqn_number_plus_one - 1];
2914 if (existing_node_pt != 0)
2917 actually_removed_some_data =
true;
2921 Node* duplicated_node_pt = nod_pt;
2922 if (!node_done[duplicated_node_pt])
2925 std::set<unsigned>* boundaries_pt;
2927 if (boundaries_pt != 0)
2930 unsigned nb = (*boundaries_pt).size();
2932 for (std::set<unsigned>::iterator it =
2933 (*boundaries_pt).begin();
2934 it != (*boundaries_pt).end();
2937 bound.push_back((*it));
2939 for (
unsigned i = 0;
i < nb;
i++)
2942 duplicated_node_pt);
2947 killed_nodes.insert(duplicated_node_pt);
2948 unsigned i_proc = unsigned(iproc);
2950 duplicated_node_pt);
2966 int n_cont_inter_values =
2968 ->ncont_interpolated_values();
2969 for (
int i_cont = -1; i_cont < n_cont_inter_values;
2972 unsigned n_master_orig = 0;
2975 n_master_orig = finite_ext_el_pt->
node_pt(j)
2984 unsigned n_master_replace = 0;
2991 if (n_master_orig != n_master_replace)
2993 std::ostringstream error_stream;
2995 <<
"Number of master nodes for node to be replaced, "
2996 << n_master_orig <<
", doesn't match"
2997 <<
"those of replacement node, " << n_master_replace
2998 <<
" for i_cont=" << i_cont << std::endl;
3001 <<
"Nodal coordinates of replacement node:";
3002 unsigned ndim = existing_node_pt->
ndim();
3003 for (
unsigned i = 0;
i < ndim;
i++)
3005 error_stream << existing_node_pt->
x(
i) <<
" ";
3007 error_stream <<
"\n";
3008 error_stream <<
"The coordinates of its "
3010 <<
" master nodes are: \n";
3011 for (
unsigned k = 0; k < n_master_replace; k++)
3013 Node* master_nod_pt =
3016 unsigned ndim = master_nod_pt->
ndim();
3017 for (
unsigned i = 0;
i < ndim;
i++)
3019 error_stream << master_nod_pt->
x(
i) <<
" ";
3021 error_stream <<
"\n";
3027 <<
"Nodal coordinates of node to be replaced:";
3028 unsigned ndim = finite_ext_el_pt->
node_pt(j)->
ndim();
3029 for (
unsigned i = 0;
i < ndim;
i++)
3031 error_stream << finite_ext_el_pt->
node_pt(j)->
x(
i)
3034 error_stream <<
"\n";
3035 error_stream <<
"The coordinates of its "
3037 <<
" master nodes are: \n";
3038 for (
unsigned k = 0; k < n_master_orig; k++)
3040 Node* master_nod_pt = finite_ext_el_pt->
node_pt(j)
3043 unsigned ndim = master_nod_pt->
ndim();
3044 for (
unsigned i = 0;
i < ndim;
i++)
3046 error_stream << master_nod_pt->
x(
i) <<
" ";
3048 error_stream <<
"\n";
3054 OOMPH_CURRENT_FUNCTION,
3055 OOMPH_EXCEPTION_LOCATION);
3061 finite_ext_el_pt->
node_pt(j) = existing_node_pt;
3066 global_node_pt[first_non_negative_eqn_number_plus_one - 1] =
3068 node_done[nod_pt] =
true;
3077 int n_cont_inter_values =
3079 ->ncont_interpolated_values();
3080 for (
int i_cont = -1; i_cont < n_cont_inter_values; i_cont++)
3086 unsigned n_master = hang_pt->
nmaster();
3087 for (
unsigned m = 0; m < n_master; m++)
3090 unsigned n_val = master_nod_pt->
nvalue();
3091 unsigned first_non_negative_eqn_number_plus_one = 0;
3092 for (
unsigned i_val = 0; i_val < n_val; i_val++)
3094 int eqn_no = master_nod_pt->
eqn_number(i_val);
3097 first_non_negative_eqn_number_plus_one = eqn_no + 1;
3104 if (first_non_negative_eqn_number_plus_one == 0)
3107 dynamic_cast<SolidNode*
>(master_nod_pt);
3108 if (solid_master_nod_pt != 0)
3115 for (
unsigned i_val = 0; i_val < n_val; i_val++)
3122 first_non_negative_eqn_number_plus_one =
3134 if (first_non_negative_eqn_number_plus_one > 0)
3136 Node* existing_node_pt = global_node_pt
3137 [first_non_negative_eqn_number_plus_one - 1];
3140 if (existing_node_pt != 0)
3143 actually_removed_some_data =
true;
3147 Node* duplicated_node_pt = master_nod_pt;
3149 if (!node_done[duplicated_node_pt])
3152 std::set<unsigned>* boundaries_pt;
3155 if (boundaries_pt != 0)
3157 for (std::set<unsigned>::iterator it =
3158 (*boundaries_pt).begin();
3159 it != (*boundaries_pt).end();
3163 (*it), duplicated_node_pt);
3167 killed_nodes.insert(duplicated_node_pt);
3168 unsigned i_proc = unsigned(iproc);
3170 i_proc, duplicated_node_pt);
3184 std::ostringstream error_stream;
3186 <<
"About to re-set master for i_cont= " << i_cont
3187 <<
" for external node (with proc " << iproc
3188 <<
" )" << tmp_nod_pt <<
" at ";
3189 unsigned n = tmp_nod_pt->
ndim();
3190 for (
unsigned jj = 0; jj < n; jj++)
3192 error_stream << tmp_nod_pt->x(jj) <<
" ";
3195 <<
" which is not hanging --> About to die!"
3196 <<
"Outputting offending element into oomph-info "
3203 OOMPH_CURRENT_FUNCTION,
3204 OOMPH_EXCEPTION_LOCATION);
3218 [first_non_negative_eqn_number_plus_one - 1] =
3220 node_done[master_nod_pt] =
true;
3238 for (std::set<Node*>::iterator it = killed_nodes.begin();
3239 it != killed_nodes.end();
3268 unsigned n_mesh_loop = 1;
3272 n_mesh_loop = nmesh;
3298 for (
int domain = 0; domain < n_proc; domain++)
3301 send_displacement[domain] = send_data.size();
3305 if (domain != my_rank)
3308 Mesh* my_mesh_pt = 0;
3311 for (
unsigned imesh = 0; imesh < n_mesh_loop; imesh++)
3326 unsigned nnod = backup_pt.size();
3330 new_external_halo_node_pt.reserve(nnod);
3333 for (
unsigned j = 0; j < nnod; j++)
3336 Node* nod_pt = backup_pt[j];
3342 send_data.push_back(j);
3347 new_external_halo_node_pt.push_back(nod_pt);
3353 new_external_halo_node_pt);
3356 send_data.push_back(-1);
3363 send_n[domain] = send_data.size() - send_displacement[domain];
3370 MPI_Alltoall(&send_n[0],
3382 int receive_data_count = 0;
3383 for (
int rank = 0; rank < n_proc; ++rank)
3386 receive_displacement[rank] = receive_data_count;
3387 receive_data_count += receive_n[rank];
3392 if (receive_data_count == 0)
3394 ++receive_data_count;
3400 if (send_data.size() == 0)
3402 send_data.resize(1);
3406 MPI_Alltoallv(&send_data[0],
3408 &send_displacement[0],
3412 &receive_displacement[0],
3417 for (
int send_rank = 0; send_rank < n_proc; send_rank++)
3421 if ((send_rank != my_rank) && (receive_n[send_rank] != 0))
3424 unsigned count = receive_displacement[send_rank];
3427 Mesh* my_mesh_pt = 0;
3430 for (
unsigned imesh = 0; imesh < n_mesh_loop; imesh++)
3449 int next_one = receive_data[count++];
3458 backup_pt[next_one] = 0;
3463 unsigned nnod = backup_pt.size();
3467 new_external_haloed_node_pt.reserve(nnod);
3470 for (
unsigned j = 0; j < nnod; j++)
3473 Node* nod_pt = backup_pt[j];
3479 new_external_haloed_node_pt.push_back(nod_pt);
3485 new_external_haloed_node_pt);
3500 const unsigned long n_dof = this->
ndof();
3502 if (n_dof != dofs.
nrow())
3504 std::ostringstream error_stream;
3505 error_stream <<
"Number of degrees of freedom in vector argument "
3506 << dofs.
nrow() <<
"\n"
3507 <<
"does not equal number of degrees of freedom in problem "
3510 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3513 for (
unsigned long l = 0; l < n_dof; l++)
3525 throw OomphLibError(
"Not designed for distributed problems",
3526 OOMPH_EXCEPTION_LOCATION,
3527 OOMPH_CURRENT_FUNCTION);
3534 for (
unsigned i = 0;
i < Nglobal_data;
i++)
3540 if (eqn_number >= 0)
3548 for (
unsigned i = 0, ni =
mesh_pt()->nelement();
i < ni;
i++)
3554 for (
unsigned k = 0, nk = d_pt->
nvalue(); k < nk; k++)
3557 if (eqn_number >= 0)
3566 for (
unsigned i = 0, ni =
mesh_pt()->nnode();
i < ni;
i++)
3569 for (
unsigned j = 0, nj = node_pt->
nvalue(); j < nj; j++)
3573 if (eqn_number >= 0)
3589 throw OomphLibError(
"Not implemented for distributed problems!",
3590 OOMPH_EXCEPTION_LOCATION,
3591 OOMPH_CURRENT_FUNCTION);
3601 for (
unsigned i = 0;
i < Nglobal_data;
i++)
3607 if (eqn_number >= 0)
3616 for (
unsigned i = 0, ni =
mesh_pt()->nnode();
i < ni;
i++)
3619 for (
unsigned j = 0, nj = node_pt->
nvalue(); j < nj; j++)
3623 if (eqn_number >= 0)
3631 for (
unsigned i = 0, ni =
mesh_pt()->nelement();
i < ni;
i++)
3639 if (eqn_number >= 0)
3654 const unsigned long n_dof = this->
ndof();
3655 for (
unsigned long l = 0; l < n_dof; l++)
3657 *
Dof_pt[l] += lambda * increment_dofs[l];
3675 std::ostringstream error_stream;
3676 error_stream <<
"The function get_inverse_mass_matrix_times_residuals() "
3678 <<
"used with the default assembly handler\n\n";
3680 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3685 const unsigned n_dof = this->
ndof();
3689 Mres.
build(&dist, 0.0);
3698 for (
unsigned e = 0;
e < n_element;
e++)
3705 const unsigned n_el_dofs = elem_pt->
ndof();
3709 for (
unsigned i = 0;
i < n_el_dofs;
i++)
3725 oomph_info <<
"Not recomputing Mass Matrix " << std::endl;
3744 oomph_info <<
"Enabling resolve in explicit timestep" << std::endl;
3776 std::vector<bool> was_steady(n_time_steppers);
3777 for (
unsigned i = 0;
i < n_time_steppers;
i++)
3788 for (
unsigned i = 0;
i < n_time_steppers;
i++)
3818 if (residuals.
built())
3822 std::ostringstream error_stream;
3823 error_stream <<
"The distribution of the residuals vector does not "
3824 "have the correct\n"
3825 <<
"number of global rows\n";
3828 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3838 if (residuals.
built())
3851 residuals.
build(dist_pt, 0.0);
3854 #ifdef OOMPH_HAS_MPI
3860 for (
unsigned long e = 0;
e < Element_pt_range;
e++)
3871 for (
unsigned l = 0; l < n_element_dofs; l++)
3874 element_residuals[l];
3878 #ifdef OOMPH_HAS_MPI
3899 dist_pt, column_index, row_start, value, nnz, res);
3926 unsigned n_dof =
ndof();
3932 if (residuals.
built())
3936 std::ostringstream error_stream;
3938 <<
"If the DoubleVector residuals is setup then it must not "
3939 <<
"be distributed.";
3941 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3945 std::ostringstream error_stream;
3947 <<
"If the DoubleVector residuals is setup then it must have"
3948 <<
" the correct number of rows";
3950 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3955 std::ostringstream error_stream;
3957 <<
"If the DoubleVector residuals is setup then it must have"
3958 <<
" the same communicator as the problem.";
3960 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3966 if (!residuals.
built())
3969 residuals.
build(&dist, 0.0);
3983 jacobian.
resize(n_dof, n_dof);
3991 for (
unsigned long e = 0;
e < n_element;
e++)
4003 elem_pt, element_residuals, element_jacobian);
4005 for (
unsigned l = 0; l < n_element_dofs; l++)
4008 residuals[eqn_number] += element_residuals[l];
4009 for (
unsigned l2 = 0; l2 < n_element_dofs; l2++)
4012 element_jacobian(l, l2);
4062 std::ostringstream error_stream;
4063 error_stream <<
"The distribution of the residuals must "
4064 <<
"be the same as the distribution of the jacobian.";
4066 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4070 std::ostringstream error_stream;
4072 <<
"The distribution of the jacobian and residuals does not"
4073 <<
"have the correct number of global rows.";
4075 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4080 std::ostringstream error_stream;
4081 error_stream <<
"The distribution of the jacobian and residuals must "
4082 <<
"both be setup or both not setup";
4084 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4108 bool compressed_row_flag =
true;
4110 #ifdef OOMPH_HAS_MPI
4116 column_index, row_start, value, nnz, res, compressed_row_flag);
4117 jacobian.
build(dist_pt);
4119 dist_pt->
nrow(), nnz[0], value[0], column_index[0], row_start[0]);
4120 residuals.
build(dist_pt, 0.0);
4122 #ifdef OOMPH_HAS_MPI
4129 dist_pt, column_index, row_start, value, nnz, res);
4130 jacobian.
build(dist_pt);
4132 dist_pt->
nrow(), nnz[0], value[0], column_index[0], row_start[0]);
4133 residuals.
build(dist_pt, 0.0);
4141 temp_dist_pt, column_index, row_start, value, nnz, res);
4142 jacobian.
build(temp_dist_pt);
4144 dist_pt->
nrow(), nnz[0], value[0], column_index[0], row_start[0]);
4146 residuals.
build(temp_dist_pt, 0.0);
4149 delete temp_dist_pt;
4181 unsigned n_dof =
ndof();
4187 if (residuals.
built())
4191 std::ostringstream error_stream;
4193 <<
"If the DoubleVector residuals is setup then it must not "
4194 <<
"be distributed.";
4196 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4200 std::ostringstream error_stream;
4202 <<
"If the DoubleVector residuals is setup then it must have"
4203 <<
" the correct number of rows";
4205 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4210 std::ostringstream error_stream;
4212 <<
"If the DoubleVector residuals is setup then it must have"
4213 <<
" the same communicator as the problem.";
4215 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4235 bool compressed_row_flag =
false;
4239 if (!residuals.
built())
4249 #ifdef OOMPH_HAS_MPI
4254 row_index, column_start, value, nnz, res, compressed_row_flag);
4256 value[0], row_index[0], column_start[0], nnz[0], n_dof, n_dof);
4257 residuals.
build(dist_pt, 0.0);
4259 #ifdef OOMPH_HAS_MPI
4263 std::ostringstream error_stream;
4264 error_stream <<
"Cannot assemble a CCDoubleMatrix Jacobian on more "
4265 <<
"than one processor.";
4267 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4289 for (
unsigned i = 0;
i < n_global_data;
i++)
4292 const unsigned n_value = local_data_pt->
nvalue();
4293 for (
unsigned j = 0; j < n_value; j++)
4305 if (n_sub_mesh == 0)
4309 for (
unsigned n = 0; n < n_node; n++)
4312 const unsigned n_value = local_node_pt->
nvalue();
4313 for (
unsigned j = 0; j < n_value; j++)
4324 dynamic_cast<SolidNode*
>(local_node_pt);
4326 if (local_solid_node_pt)
4329 const unsigned n_dim = local_solid_node_pt->
ndim();
4331 const unsigned n_position_type =
4334 for (
unsigned k = 0; k < n_position_type; k++)
4336 for (
unsigned i = 0;
i < n_dim;
i++)
4342 local_solid_node_pt->
x_gen(k,
i) = 0.0;
4351 for (
unsigned e = 0;
e < n_element;
e++)
4355 for (
unsigned i = 0;
i < n_internal;
i++)
4358 const unsigned n_value = local_data_pt->
nvalue();
4359 for (
unsigned j = 0; j < n_value; j++)
4373 for (
unsigned m = 0; m < n_sub_mesh; m++)
4377 for (
unsigned n = 0; n < n_node; n++)
4380 const unsigned n_value = local_node_pt->
nvalue();
4381 for (
unsigned j = 0; j < n_value; j++)
4392 dynamic_cast<SolidNode*
>(local_node_pt);
4394 if (local_solid_node_pt)
4397 const unsigned n_dim = local_solid_node_pt->
ndim();
4399 const unsigned n_position_type =
4402 for (
unsigned k = 0; k < n_position_type; k++)
4404 for (
unsigned i = 0;
i < n_dim;
i++)
4410 local_solid_node_pt->
x_gen(k,
i) = 0.0;
4418 const unsigned n_element =
Sub_mesh_pt[m]->nelement();
4419 for (
unsigned e = 0;
e < n_element;
e++)
4424 for (
unsigned i = 0;
i < n_internal;
i++)
4427 const unsigned n_value = local_data_pt->
nvalue();
4428 for (
unsigned j = 0; j < n_value; j++)
4468 bool compressed_row_flag)
4476 column_or_row_index,
4477 row_or_column_start,
4481 compressed_row_flag);
4488 column_or_row_index,
4489 row_or_column_start,
4493 compressed_row_flag);
4500 row_or_column_start,
4504 compressed_row_flag);
4511 column_or_row_index,
4512 row_or_column_start,
4516 compressed_row_flag);
4523 column_or_row_index,
4524 row_or_column_start,
4528 compressed_row_flag);
4534 std::ostringstream error_stream;
4536 <<
"Error: Incorrect value for Problem::Sparse_assembly_method"
4538 <<
"It should be one of the enumeration Problem::Assembly_method"
4541 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4568 bool compressed_row_flag)
4574 unsigned long el_lo = 0;
4575 unsigned long el_hi = n_elements - 1;
4577 #ifdef OOMPH_HAS_MPI
4595 const unsigned n_vector = residuals.size();
4598 const unsigned n_matrix = column_or_row_index.size();
4603 #ifdef OOMPH_HAS_MPI
4604 bool doing_residuals =
false;
4607 doing_residuals =
true;
4613 if (row_or_column_start.size() != n_matrix)
4615 std::ostringstream error_stream;
4616 error_stream <<
"Error: " << std::endl
4617 <<
"row_or_column_start.size() "
4618 << row_or_column_start.size() <<
" does not equal "
4619 <<
"column_or_row_index.size() "
4620 << column_or_row_index.size() << std::endl;
4622 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4625 if (value.size() != n_matrix)
4627 std::ostringstream error_stream;
4629 <<
"Error in Problem::sparse_assemble_row_or_column_compressed "
4631 <<
"value.size() " << value.size() <<
" does not equal "
4632 <<
"column_or_row_index.size() " << column_or_row_index.size()
4637 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4663 for (
unsigned m = 0; m < n_matrix; m++)
4665 matrix_data_map[m].resize(
ndof);
4669 for (
unsigned v = 0; v < n_vector; v++)
4671 residuals[v] =
new double[
ndof];
4672 for (
unsigned i = 0;
i <
ndof;
i++)
4674 residuals[v][
i] = 0;
4679 #ifdef OOMPH_HAS_MPI
4683 double t_assemble_start = 0.0;
4703 for (
unsigned long e = el_lo;
e <= el_hi;
e++)
4705 #ifdef OOMPH_HAS_MPI
4716 #ifdef OOMPH_HAS_MPI
4726 for (
unsigned v = 0; v < n_vector; v++)
4728 el_residuals[v].resize(nvar);
4730 for (
unsigned m = 0; m < n_matrix; m++)
4732 el_jacobian[m].resize(nvar);
4737 elem_pt, el_residuals, el_jacobian);
4742 for (
unsigned i = 0;
i < nvar;
i++)
4748 for (
unsigned v = 0; v < n_vector; v++)
4751 residuals[v][eqn_number] += el_residuals[v][
i];
4755 for (
unsigned j = 0; j < nvar; j++)
4761 for (
unsigned m = 0; m < n_matrix; m++)
4764 double value = el_jacobian[m](
i, j);
4770 if (compressed_row_flag)
4774 matrix_data_map[m][eqn_number][unknown] += value;
4782 matrix_data_map[m][unknown][eqn_number] += value;
4789 #ifdef OOMPH_HAS_MPI
4794 #ifdef OOMPH_HAS_MPI
4808 #ifdef OOMPH_HAS_MPI
4833 for (
unsigned m = 0; m < n_matrix; m++)
4836 row_or_column_start[m] =
new int[
ndof + 1];
4838 unsigned long entry_count = 0;
4839 row_or_column_start[m][0] = entry_count;
4843 for (
unsigned long i_global = 0; i_global <
ndof; i_global++)
4845 nnz[m] += matrix_data_map[m][i_global].size();
4849 column_or_row_index[m] =
new int[nnz[m]];
4850 value[m] =
new double[nnz[m]];
4853 for (
unsigned long i_global = 0; i_global <
ndof; i_global++)
4856 row_or_column_start[m][i_global] = entry_count;
4858 if (matrix_data_map[m][i_global].empty())
4866 for (std::map<unsigned, double>::iterator it =
4867 matrix_data_map[m][i_global].begin();
4868 it != matrix_data_map[m][i_global].end();
4872 column_or_row_index[m][entry_count] = it->first;
4874 value[m][entry_count] = it->second;
4881 row_or_column_start[m][
ndof] = entry_count;
4886 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
4887 pause(
"Check memory usage now.");
4914 bool compressed_row_flag)
4920 unsigned long el_lo = 0;
4921 unsigned long el_hi = n_elements - 1;
4923 #ifdef OOMPH_HAS_MPI
4941 const unsigned n_vector = residuals.size();
4944 const unsigned n_matrix = column_or_row_index.size();
4949 #ifdef OOMPH_HAS_MPI
4950 bool doing_residuals =
false;
4953 doing_residuals =
true;
4959 if (row_or_column_start.size() != n_matrix)
4961 std::ostringstream error_stream;
4962 error_stream <<
"Error: " << std::endl
4963 <<
"row_or_column_start.size() "
4964 << row_or_column_start.size() <<
" does not equal "
4965 <<
"column_or_row_index.size() "
4966 << column_or_row_index.size() << std::endl;
4968 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4971 if (value.size() != n_matrix)
4973 std::ostringstream error_stream;
4975 <<
"Error in Problem::sparse_assemble_row_or_column_compressed "
4977 <<
"value.size() " << value.size() <<
" does not equal "
4978 <<
"column_or_row_index.size() " << column_or_row_index.size()
4983 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5007 for (
unsigned m = 0; m < n_matrix; m++)
5009 matrix_data_list[m].resize(
ndof);
5013 for (
unsigned v = 0; v < n_vector; v++)
5015 residuals[v] =
new double[
ndof];
5016 for (
unsigned i = 0;
i <
ndof;
i++)
5018 residuals[v][
i] = 0;
5022 #ifdef OOMPH_HAS_MPI
5026 double t_assemble_start = 0.0;
5047 std::list<std::pair<unsigned, double>>* list_pt;
5050 for (
unsigned long e = el_lo;
e <= el_hi;
e++)
5052 #ifdef OOMPH_HAS_MPI
5063 #ifdef OOMPH_HAS_MPI
5073 for (
unsigned v = 0; v < n_vector; v++)
5075 el_residuals[v].resize(nvar);
5077 for (
unsigned m = 0; m < n_matrix; m++)
5079 el_jacobian[m].resize(nvar);
5084 elem_pt, el_residuals, el_jacobian);
5089 for (
unsigned i = 0;
i < nvar;
i++)
5095 for (
unsigned v = 0; v < n_vector; v++)
5098 residuals[v][eqn_number] += el_residuals[v][
i];
5102 for (
unsigned j = 0; j < nvar; j++)
5108 for (
unsigned m = 0; m < n_matrix; m++)
5111 double value = el_jacobian[m](
i, j);
5117 if (compressed_row_flag)
5120 list_pt = &matrix_data_list[m][eqn_number];
5124 list_pt->insert(list_pt->end(),
5125 std::make_pair(unknown, value));
5132 list_pt = &matrix_data_list[m][unknown];
5136 list_pt->insert(list_pt->end(),
5137 std::make_pair(eqn_number, value));
5144 #ifdef OOMPH_HAS_MPI
5149 #ifdef OOMPH_HAS_MPI
5163 #ifdef OOMPH_HAS_MPI
5188 for (
unsigned m = 0; m < n_matrix; m++)
5191 row_or_column_start[m] =
new int[
ndof + 1];
5193 unsigned long entry_count = 0;
5195 row_or_column_start[m][0] = entry_count;
5199 for (
unsigned long i_global = 0; i_global <
ndof; i_global++)
5201 nnz[m] += matrix_data_list[m][i_global].size();
5205 column_or_row_index[m] =
new int[nnz[m]];
5206 value[m] =
new double[nnz[m]];
5209 for (
unsigned long i_global = 0; i_global <
ndof; i_global++)
5212 row_or_column_start[m][i_global] = entry_count;
5214 if (matrix_data_list[m][i_global].empty())
5225 matrix_data_list[m][i_global].sort();
5228 std::list<std::pair<unsigned, double>>::iterator it =
5229 matrix_data_list[m][i_global].begin();
5232 unsigned current_index = it->first;
5234 double current_value = it->second;
5238 for (++it; it != matrix_data_list[m][i_global].end(); ++it)
5243 if ((it->first == current_index) &&
5246 current_value += it->second;
5253 column_or_row_index[m][entry_count] = current_index;
5255 value[m][entry_count] = current_value;
5261 current_index = it->first;
5262 current_value = it->second;
5278 if ((
static_cast<int>(entry_count) == row_or_column_start[m][i_global])
5282 || (
static_cast<int>(current_index) !=
5283 column_or_row_index[m][entry_count - 1]))
5286 column_or_row_index[m][entry_count] = current_index;
5288 value[m][entry_count] = current_value;
5296 row_or_column_start[m][
ndof] = entry_count;
5301 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
5302 pause(
"Check memory usage now.");
5329 bool compressed_row_flag)
5335 unsigned long el_lo = 0;
5336 unsigned long el_hi = n_elements - 1;
5338 #ifdef OOMPH_HAS_MPI
5356 const unsigned n_vector = residuals.size();
5359 const unsigned n_matrix = column_or_row_index.size();
5364 #ifdef OOMPH_HAS_MPI
5365 bool doing_residuals =
false;
5368 doing_residuals =
true;
5374 if (row_or_column_start.size() != n_matrix)
5376 std::ostringstream error_stream;
5377 error_stream <<
"Error: " << std::endl
5378 <<
"row_or_column_start.size() "
5379 << row_or_column_start.size() <<
" does not equal "
5380 <<
"column_or_row_index.size() "
5381 << column_or_row_index.size() << std::endl;
5383 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5386 if (value.size() != n_matrix)
5388 std::ostringstream error_stream;
5389 error_stream <<
"Error: " << std::endl
5390 <<
"value.size() " << value.size() <<
" does not equal "
5391 <<
"column_or_row_index.size() "
5392 << column_or_row_index.size() << std::endl
5396 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5412 for (
unsigned m = 0; m < n_matrix; m++)
5414 matrix_data[m].resize(
ndof);
5418 for (
unsigned v = 0; v < n_vector; v++)
5420 residuals[v] =
new double[
ndof];
5421 for (
unsigned i = 0;
i <
ndof;
i++)
5423 residuals[v][
i] = 0;
5427 #ifdef OOMPH_HAS_MPI
5430 double t_assemble_start = 0.0;
5450 for (
unsigned long e = el_lo;
e <= el_hi;
e++)
5452 #ifdef OOMPH_HAS_MPI
5463 #ifdef OOMPH_HAS_MPI
5473 for (
unsigned v = 0; v < n_vector; v++)
5475 el_residuals[v].resize(nvar);
5477 for (
unsigned m = 0; m < n_matrix; m++)
5479 el_jacobian[m].resize(nvar);
5484 elem_pt, el_residuals, el_jacobian);
5489 for (
unsigned i = 0;
i < nvar;
i++)
5495 for (
unsigned v = 0; v < n_vector; v++)
5498 residuals[v][eqn_number] += el_residuals[v][
i];
5502 for (
unsigned j = 0; j < nvar; j++)
5510 for (
unsigned m = 0; m < n_matrix; m++)
5513 double value = el_jacobian[m](
i, j);
5519 if (compressed_row_flag)
5523 const unsigned size = matrix_data[m][eqn_number].size();
5524 for (
unsigned k = 0; k <= size; k++)
5528 matrix_data[m][eqn_number].push_back(
5529 std::make_pair(unknown, value));
5532 else if (matrix_data[m][eqn_number][k].first == unknown)
5534 matrix_data[m][eqn_number][k].second += value;
5544 const unsigned size = matrix_data[m][unknown].size();
5545 for (
unsigned k = 0; k <= size; k++)
5549 matrix_data[m][unknown].push_back(
5550 std::make_pair(eqn_number, value));
5553 else if (matrix_data[m][unknown][k].first == eqn_number)
5555 matrix_data[m][unknown][k].second += value;
5565 #ifdef OOMPH_HAS_MPI
5570 #ifdef OOMPH_HAS_MPI
5585 #ifdef OOMPH_HAS_MPI
5610 for (
unsigned m = 0; m < n_matrix; m++)
5613 row_or_column_start[m] =
new int[
ndof + 1];
5616 row_or_column_start[m][0] = 0;
5617 for (
unsigned long i = 0;
i <
ndof;
i++)
5619 row_or_column_start[m][
i + 1] =
5620 row_or_column_start[m][
i] + matrix_data[m][
i].size();
5622 const unsigned entries = row_or_column_start[m][
ndof];
5625 column_or_row_index[m] =
new int[entries];
5626 value[m] =
new double[entries];
5630 for (
unsigned long i_global = 0; i_global <
ndof; i_global++)
5633 if (matrix_data[m][i_global].empty())
5641 for (
int j = row_or_column_start[m][i_global];
5642 j < row_or_column_start[m][i_global + 1];
5645 column_or_row_index[m][j] = matrix_data[m][i_global][p].first;
5646 value[m][j] = matrix_data[m][i_global][p].second;
5654 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
5655 pause(
"Check memory usage now.");
5682 bool compressed_row_flag)
5688 unsigned long el_lo = 0;
5689 unsigned long el_hi = n_elements - 1;
5692 #ifdef OOMPH_HAS_MPI
5710 const unsigned n_vector = residuals.size();
5713 const unsigned n_matrix = column_or_row_index.size();
5718 #ifdef OOMPH_HAS_MPI
5719 bool doing_residuals =
false;
5722 doing_residuals =
true;
5728 if (row_or_column_start.size() != n_matrix)
5730 std::ostringstream error_stream;
5731 error_stream <<
"Error: " << std::endl
5732 <<
"row_or_column_start.size() "
5733 << row_or_column_start.size() <<
" does not equal "
5734 <<
"column_or_row_index.size() "
5735 << column_or_row_index.size() << std::endl;
5737 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5740 if (value.size() != n_matrix)
5742 std::ostringstream error_stream;
5743 error_stream <<
"Error: " << std::endl
5744 <<
"value.size() " << value.size() <<
" does not equal "
5745 <<
"column_or_row_index.size() "
5746 << column_or_row_index.size() << std::endl
5750 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5768 for (
unsigned m = 0; m < n_matrix; m++)
5770 matrix_row_or_col_indices[m].resize(
ndof);
5771 matrix_values[m].resize(
ndof);
5775 for (
unsigned v = 0; v < n_vector; v++)
5777 residuals[v] =
new double[
ndof];
5778 for (
unsigned i = 0;
i <
ndof;
i++)
5780 residuals[v][
i] = 0;
5784 #ifdef OOMPH_HAS_MPI
5787 double t_assemble_start = 0.0;
5808 for (
unsigned long e = el_lo;
e <= el_hi;
e++)
5810 #ifdef OOMPH_HAS_MPI
5821 #ifdef OOMPH_HAS_MPI
5831 for (
unsigned v = 0; v < n_vector; v++)
5833 el_residuals[v].resize(nvar);
5835 for (
unsigned m = 0; m < n_matrix; m++)
5837 el_jacobian[m].resize(nvar);
5842 elem_pt, el_residuals, el_jacobian);
5847 for (
unsigned i = 0;
i < nvar;
i++)
5853 for (
unsigned v = 0; v < n_vector; v++)
5856 residuals[v][eqn_number] += el_residuals[v][
i];
5860 for (
unsigned j = 0; j < nvar; j++)
5868 for (
unsigned m = 0; m < n_matrix; m++)
5871 double value = el_jacobian[m](
i, j);
5877 if (compressed_row_flag)
5881 const unsigned size =
5882 matrix_row_or_col_indices[m][eqn_number].size();
5884 for (
unsigned k = 0; k <= size; k++)
5888 matrix_row_or_col_indices[m][eqn_number].push_back(
5890 matrix_values[m][eqn_number].push_back(value);
5893 else if (matrix_row_or_col_indices[m][eqn_number][k] ==
5896 matrix_values[m][eqn_number][k] += value;
5906 const unsigned size =
5907 matrix_row_or_col_indices[m][unknown].size();
5908 for (
unsigned k = 0; k <= size; k++)
5912 matrix_row_or_col_indices[m][unknown].push_back(
5914 matrix_values[m][unknown].push_back(value);
5917 else if (matrix_row_or_col_indices[m][unknown][k] ==
5920 matrix_values[m][unknown][k] += value;
5930 #ifdef OOMPH_HAS_MPI
5935 #ifdef OOMPH_HAS_MPI
5949 #ifdef OOMPH_HAS_MPI
5973 for (
unsigned m = 0; m < n_matrix; m++)
5976 row_or_column_start[m] =
new int[
ndof + 1];
5979 row_or_column_start[m][0] = 0;
5980 for (
unsigned long i = 0;
i <
ndof;
i++)
5982 row_or_column_start[m][
i + 1] =
5983 row_or_column_start[m][
i] + matrix_values[m][
i].size();
5985 const unsigned entries = row_or_column_start[m][
ndof];
5988 column_or_row_index[m] =
new int[entries];
5989 value[m] =
new double[entries];
5993 for (
unsigned long i_global = 0; i_global <
ndof; i_global++)
5996 if (matrix_values[m][i_global].empty())
6004 for (
int j = row_or_column_start[m][i_global];
6005 j < row_or_column_start[m][i_global + 1];
6008 column_or_row_index[m][j] = matrix_row_or_col_indices[m][i_global][p];
6009 value[m][j] = matrix_values[m][i_global][p];
6017 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
6018 pause(
"Check memory usage now.");
6045 bool compressed_row_flag)
6051 unsigned long el_lo = 0;
6052 unsigned long el_hi = n_elements - 1;
6055 #ifdef OOMPH_HAS_MPI
6073 const unsigned n_vector = residuals.size();
6076 const unsigned n_matrix = column_or_row_index.size();
6081 #ifdef OOMPH_HAS_MPI
6082 bool doing_residuals =
false;
6085 doing_residuals =
true;
6091 if (row_or_column_start.size() != n_matrix)
6093 std::ostringstream error_stream;
6094 error_stream <<
"Error: " << std::endl
6095 <<
"row_or_column_start.size() "
6096 << row_or_column_start.size() <<
" does not equal "
6097 <<
"column_or_row_index.size() "
6098 << column_or_row_index.size() << std::endl;
6100 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
6103 if (value.size() != n_matrix)
6105 std::ostringstream error_stream;
6106 error_stream <<
"Error: " << std::endl
6107 <<
"value.size() " << value.size() <<
" does not equal "
6108 <<
"column_or_row_index.size() "
6109 << column_or_row_index.size() << std::endl
6113 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
6131 for (
unsigned m = 0; m < n_matrix; m++)
6133 matrix_row_or_col_indices[m] =
new unsigned*[
ndof];
6134 matrix_values[m] =
new double*[
ndof];
6138 for (
unsigned v = 0; v < n_vector; v++)
6140 residuals[v] =
new double[
ndof];
6141 for (
unsigned i = 0;
i <
ndof;
i++)
6143 residuals[v][
i] = 0;
6147 #ifdef OOMPH_HAS_MPI
6150 double t_assemble_start = 0.0;
6162 for (
unsigned m = 0; m < n_matrix; m++)
6164 ncoef[m].resize(
ndof, 0);
6170 for (
unsigned m = 0; m < n_matrix; m++)
6186 for (
unsigned long e = el_lo;
e <= el_hi;
e++)
6188 #ifdef OOMPH_HAS_MPI
6199 #ifdef OOMPH_HAS_MPI
6209 for (
unsigned v = 0; v < n_vector; v++)
6211 el_residuals[v].resize(nvar);
6213 for (
unsigned m = 0; m < n_matrix; m++)
6215 el_jacobian[m].resize(nvar);
6220 elem_pt, el_residuals, el_jacobian);
6225 for (
unsigned i = 0;
i < nvar;
i++)
6231 for (
unsigned v = 0; v < n_vector; v++)
6234 residuals[v][eqn_number] += el_residuals[v][
i];
6238 for (
unsigned j = 0; j < nvar; j++)
6246 for (
unsigned m = 0; m < n_matrix; m++)
6249 double value = el_jacobian[m](
i, j);
6254 const unsigned size = ncoef[m][eqn_number];
6261 [m][eqn_number] != 0)
6263 matrix_row_or_col_indices[m][eqn_number] =
new unsigned
6266 matrix_values[m][eqn_number] =
new double
6272 matrix_row_or_col_indices[m][eqn_number] =
new unsigned
6274 matrix_values[m][eqn_number] =
new double
6284 if (compressed_row_flag)
6287 for (
unsigned k = 0; k <= size; k++)
6293 [m][eqn_number] == ncoef[m][eqn_number])
6295 unsigned new_allocation =
6296 ncoef[m][eqn_number] +
6298 double* new_values =
new double[new_allocation];
6299 unsigned* new_indices =
new unsigned[new_allocation];
6300 for (
unsigned c = 0; c < ncoef[m][eqn_number]; c++)
6302 new_values[c] = matrix_values[m][eqn_number][c];
6304 matrix_row_or_col_indices[m][eqn_number][c];
6306 delete[] matrix_values[m][eqn_number];
6307 delete[] matrix_row_or_col_indices[m][eqn_number];
6308 matrix_values[m][eqn_number] = new_values;
6309 matrix_row_or_col_indices[m][eqn_number] =
6312 [m][eqn_number] = new_allocation;
6315 unsigned entry = ncoef[m][eqn_number];
6316 ncoef[m][eqn_number]++;
6317 matrix_row_or_col_indices[m][eqn_number][entry] =
6319 matrix_values[m][eqn_number][entry] = value;
6322 else if (matrix_row_or_col_indices[m][eqn_number][k] ==
6325 matrix_values[m][eqn_number][k] += value;
6335 for (
unsigned k = 0; k <= size; k++)
6341 [m][unknown] == ncoef[m][unknown])
6343 unsigned new_allocation =
6346 double* new_values =
new double[new_allocation];
6347 unsigned* new_indices =
new unsigned[new_allocation];
6348 for (
unsigned c = 0; c < ncoef[m][unknown]; c++)
6350 new_values[c] = matrix_values[m][unknown][c];
6352 matrix_row_or_col_indices[m][unknown][c];
6354 delete[] matrix_values[m][unknown];
6355 delete[] matrix_row_or_col_indices[m][unknown];
6357 [m][unknown] = new_allocation;
6360 unsigned entry = ncoef[m][unknown];
6361 ncoef[m][unknown]++;
6362 matrix_row_or_col_indices[m][unknown][entry] =
6364 matrix_values[m][unknown][entry] = value;
6367 else if (matrix_row_or_col_indices[m][unknown][k] ==
6370 matrix_values[m][unknown][k] += value;
6380 #ifdef OOMPH_HAS_MPI
6385 #ifdef OOMPH_HAS_MPI
6399 #ifdef OOMPH_HAS_MPI
6423 for (
unsigned m = 0; m < n_matrix; m++)
6426 row_or_column_start[m] =
new int[
ndof + 1];
6429 row_or_column_start[m][0] = 0;
6430 for (
unsigned long i = 0;
i <
ndof;
i++)
6432 row_or_column_start[m][
i + 1] = row_or_column_start[m][
i] + ncoef[m][
i];
6435 const unsigned entries = row_or_column_start[m][
ndof];
6438 column_or_row_index[m] =
new int[entries];
6439 value[m] =
new double[entries];
6443 for (
unsigned long i_global = 0; i_global <
ndof; i_global++)
6446 if (ncoef[m][i_global] == 0)
6454 for (
int j = row_or_column_start[m][i_global];
6455 j < row_or_column_start[m][i_global + 1];
6458 column_or_row_index[m][j] = matrix_row_or_col_indices[m][i_global][p];
6459 value[m][j] = matrix_values[m][i_global][p];
6464 delete[] matrix_row_or_col_indices[m][i_global];
6465 delete[] matrix_values[m][i_global];
6469 delete[] matrix_row_or_col_indices[m];
6470 delete[] matrix_values[m];
6475 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
6476 pause(
"Check memory usage now.");
6481 #ifdef OOMPH_HAS_MPI
6488 const unsigned& el_lo,
6489 const unsigned& el_hi,
6493 unsigned my_eqns_index = 0;
6496 for (
unsigned long e = el_lo;
e <= el_hi;
e++)
6507 my_eqns.resize(my_eqns_index + nvar);
6510 for (
unsigned i = 0;
i < nvar;
i++)
6513 unsigned global_eqn_number =
6516 my_eqns[my_eqns_index +
i] = global_eqn_number;
6519 my_eqns_index += nvar;
6524 std::sort(my_eqns.begin(), my_eqns.end());
6526 my_eqns.resize(it - my_eqns.begin());
6557 if (n_elements == 0)
6559 std::ostringstream error_stream;
6560 error_stream <<
"Processsor " << my_rank <<
" has no elements. \n"
6561 <<
"This is usually a sign that the problem distribution \n"
6562 <<
"or the load balancing have gone wrong.";
6564 "Problem::parallel_sparse_assemble()",
6565 OOMPH_EXCEPTION_LOCATION);
6571 unsigned long el_lo = 0;
6572 unsigned long el_hi_plus_one = n_elements;
6587 const unsigned n_vector = residuals.size();
6590 const unsigned n_matrix = column_indices.size();
6595 bool doing_residuals =
false;
6598 doing_residuals =
true;
6603 if (row_start.size() != n_matrix)
6605 std::ostringstream error_stream;
6606 error_stream <<
"Error: " << std::endl
6607 <<
"row_or_column_start.size() " << row_start.size()
6608 <<
" does not equal "
6609 <<
"column_or_row_index.size() " << column_indices.size()
6612 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
6615 if (values.size() != n_matrix)
6617 std::ostringstream error_stream;
6618 error_stream <<
"Error: " << std::endl
6619 <<
"value.size() " << values.size() <<
" does not equal "
6620 <<
"column_or_row_index.size() " << column_indices.size()
6625 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
6637 if (n_elements != 0)
6640 assembly_handler_pt, el_lo, el_hi_plus_one - 1, my_eqns);
6644 unsigned my_n_eqn = my_eqns.size();
6660 for (
unsigned m = 0; m < n_matrix; m++)
6662 matrix_col_indices[m] =
new unsigned*[my_n_eqn];
6663 matrix_values[m] =
new double*[my_n_eqn];
6664 for (
unsigned i = 0;
i < my_n_eqn;
i++)
6666 matrix_col_indices[m][
i] = 0;
6667 matrix_values[m][
i] = 0;
6673 for (
unsigned v = 0; v < n_vector; v++)
6675 residuals_data[v] =
new double[my_n_eqn];
6676 for (
unsigned i = 0;
i < my_n_eqn;
i++)
6678 residuals_data[v][
i] = 0;
6683 double t_assemble_start = 0.0;
6693 for (
unsigned m = 0; m < n_matrix; m++)
6695 ncoef[m].resize(my_n_eqn, 0);
6705 for (
unsigned m = 0; m < n_matrix; m++)
6722 for (
unsigned long e = el_lo;
e < el_hi_plus_one;
e++)
6740 for (
unsigned v = 0; v < n_vector; v++)
6742 el_residuals[v].resize(nvar);
6744 for (
unsigned m = 0; m < n_matrix; m++)
6746 el_jacobian[m].resize(nvar);
6751 elem_pt, el_residuals, el_jacobian);
6756 for (
unsigned i = 0;
i < nvar;
i++)
6759 unsigned global_eqn_number =
6765 int right = my_n_eqn - 1;
6766 int eqn_number = right / 2;
6767 while (my_eqns[eqn_number] != global_eqn_number)
6773 bool broken =
false;
6774 for (
unsigned v = 0; v < n_vector; v++)
6776 if (el_residuals[v][
i] != 0.0)
6785 for (
unsigned j = 0; j < nvar; j++)
6794 for (
unsigned m = 0; m < n_matrix; m++)
6797 double value = el_jacobian[m](
i, j);
6809 std::ostringstream error_stream;
6811 <<
"Internal Error: " << std::endl
6812 <<
"Could not find global equation number "
6813 << global_eqn_number
6814 <<
" in my_eqns vector of equation numbers but\n"
6815 <<
"at least one entry in the residual vector is nonzero.";
6817 OOMPH_CURRENT_FUNCTION,
6818 OOMPH_EXCEPTION_LOCATION);
6825 if (my_eqns[eqn_number] > global_eqn_number)
6827 right = std::max(eqn_number - 1, left);
6831 left = std::min(eqn_number + 1, right);
6833 eqn_number = (right + left) / 2;
6837 for (
unsigned v = 0; v < n_vector; v++)
6840 residuals_data[v][eqn_number] += el_residuals[v][
i];
6844 for (
unsigned j = 0; j < nvar; j++)
6852 for (
unsigned m = 0; m < n_matrix; m++)
6855 double value = el_jacobian[m](
i, j);
6860 const unsigned size = ncoef[m][eqn_number];
6867 [m][eqn_number] != 0)
6869 matrix_col_indices[m][eqn_number] =
new unsigned
6873 matrix_values[m][eqn_number] =
new double
6879 matrix_col_indices[m][eqn_number] =
new unsigned
6882 matrix_values[m][eqn_number] =
new double
6892 for (
unsigned k = 0; k <= size; k++)
6898 [m][eqn_number] == ncoef[m][eqn_number])
6900 unsigned new_allocation =
6901 ncoef[m][eqn_number] +
6903 double* new_values =
new double[new_allocation];
6904 unsigned* new_indices =
new unsigned[new_allocation];
6905 for (
unsigned c = 0; c < ncoef[m][eqn_number]; c++)
6907 new_values[c] = matrix_values[m][eqn_number][c];
6908 new_indices[c] = matrix_col_indices[m][eqn_number][c];
6910 delete[] matrix_values[m][eqn_number];
6911 delete[] matrix_col_indices[m][eqn_number];
6913 matrix_values[m][eqn_number] = new_values;
6914 matrix_col_indices[m][eqn_number] = new_indices;
6917 [m][eqn_number] = new_allocation;
6920 unsigned entry = ncoef[m][eqn_number];
6921 ncoef[m][eqn_number]++;
6922 matrix_col_indices[m][eqn_number][entry] = unknown;
6923 matrix_values[m][eqn_number][entry] = value;
6926 else if (matrix_col_indices[m][eqn_number][k] == unknown)
6928 matrix_values[m][eqn_number][k] += value;
6950 double t_local = 0.0;
6957 t_local = t_end - t_start;
6961 MPI_Allreduce(&t_local,
6967 MPI_Allreduce(&t_local,
6973 MPI_Allreduce(&t_local,
6979 double imbalance = (t_max - t_min) / (t_sum /
double(nproc)) * 100.0;
6981 if (doing_residuals)
6983 oomph_info <<
"\nCPU for residual computation (loc/max/min/imbal): ";
6987 oomph_info <<
"\nCPU for Jacobian computation (loc/max/min/imbal): ";
6989 oomph_info << t_local <<
" " << t_max <<
" " << t_min <<
" " << imbalance
6997 for (
unsigned m = 0; m < n_matrix; m++)
7000 unsigned min = INT_MAX;
7002 unsigned sum_total = 0;
7003 for (
unsigned e = 0;
e < my_n_eqn;
e++)
7007 if (ncoef[m][
e] > max) max = ncoef[m][
e];
7008 if (ncoef[m][
e] < min) min = ncoef[m][
e];
7011 unsigned new_allocation = ncoef[m][
e];
7012 double* new_values =
new double[new_allocation];
7013 unsigned* new_indices =
new unsigned[new_allocation];
7014 for (
unsigned c = 0; c < ncoef[m][
e]; c++)
7016 new_values[c] = matrix_values[m][
e][c];
7017 new_indices[c] = matrix_col_indices[m][
e][c];
7019 delete[] matrix_values[m][
e];
7020 delete[] matrix_col_indices[m][
e];
7022 matrix_values[m][
e] = new_values;
7023 matrix_col_indices[m][
e] = new_indices;
7056 first_eqn_element_for_proc[current_p] = 0;
7057 n_eqn_for_proc[current_p] = 1;
7058 for (
unsigned i = 1;
i < my_n_eqn;
i++)
7061 if (next_p != current_p)
7064 first_eqn_element_for_proc[current_p] =
i;
7066 n_eqn_for_proc[current_p]++;
7073 for (
unsigned p = 0; p < nproc; p++)
7075 int first_eqn_element = first_eqn_element_for_proc[p];
7076 int last_eqn_element = (int)(first_eqn_element + n_eqn_for_proc[p]) - 1;
7077 for (
unsigned m = 0; m < n_matrix; m++)
7079 for (
int i = first_eqn_element;
i <= last_eqn_element;
i++)
7081 nnz_for_proc(p, m) += ncoef[m][
i];
7091 for (
unsigned p = 0; p < nproc; p++)
7095 temp_send_storage[p] =
new unsigned[n_matrix + 1];
7096 temp_send_storage[p][0] = n_eqn_for_proc[p];
7097 for (
unsigned m = 0; m < n_matrix; m++)
7099 temp_send_storage[p][m + 1] = nnz_for_proc(p, m);
7102 MPI_Isend(temp_send_storage[p],
7109 send_nnz_reqs.push_back(sreq);
7110 temp_recv_storage[p] =
new unsigned[n_matrix + 1];
7112 MPI_Irecv(temp_recv_storage[p],
7119 recv_nnz_reqs.push_back(rreq);
7134 for (
unsigned p = 0; p < nproc; p++)
7136 unsigned n_eqns_p = n_eqn_for_proc[p];
7139 unsigned first_eqn_element = first_eqn_element_for_proc[p];
7140 unsigned first_row = target_dist_pt->
first_row(p);
7141 eqns_for_proc[p] =
new unsigned[n_eqns_p];
7142 for (
unsigned i = 0;
i < n_eqns_p;
i++)
7144 eqns_for_proc[p][
i] = my_eqns[
i + first_eqn_element] - first_row;
7150 for (
unsigned v = 0; v < n_vector; v++)
7152 for (
unsigned p = 0; p < nproc; p++)
7154 unsigned n_eqns_p = n_eqn_for_proc[p];
7157 unsigned first_eqn_element = first_eqn_element_for_proc[p];
7158 residuals_for_proc(p, v) =
new double[n_eqns_p];
7159 for (
unsigned i = 0;
i < n_eqns_p;
i++)
7161 residuals_for_proc(p, v)[
i] =
7162 residuals_data[v][first_eqn_element +
i];
7166 delete[] residuals_data[v];
7170 for (
unsigned m = 0; m < n_matrix; m++)
7172 for (
unsigned p = 0; p < nproc; p++)
7174 unsigned n_eqns_p = n_eqn_for_proc[p];
7177 unsigned first_eqn_element = first_eqn_element_for_proc[p];
7178 row_start_for_proc(p, m) =
new unsigned[n_eqns_p + 1];
7179 column_indices_for_proc(p, m) =
new unsigned[nnz_for_proc(p, m)];
7180 values_for_proc(p, m) =
new double[nnz_for_proc(p, m)];
7182 for (
unsigned i = 0;
i < n_eqns_p;
i++)
7184 row_start_for_proc(p, m)[
i] = entry;
7185 unsigned n_coef_in_row = ncoef[m][first_eqn_element +
i];
7186 for (
unsigned j = 0; j < n_coef_in_row; j++)
7188 column_indices_for_proc(p, m)[entry] =
7189 matrix_col_indices[m][
i + first_eqn_element][j];
7190 values_for_proc(p, m)[entry] =
7191 matrix_values[m][
i + first_eqn_element][j];
7195 row_start_for_proc(p, m)[n_eqns_p] = entry;
7198 for (
unsigned i = 0;
i < my_n_eqn;
i++)
7200 delete[] matrix_col_indices[m][
i];
7201 delete[] matrix_values[m][
i];
7203 delete[] matrix_col_indices[m];
7204 delete[] matrix_values[m];
7215 MPI_Waitall(nproc - 1, &recv_nnz_reqs[0], &recv_nnz_stat[0]);
7218 for (
unsigned p = 0; p < nproc; p++)
7222 n_eqn_from_proc[p] = temp_recv_storage[p][0];
7223 for (
unsigned m = 0; m < n_matrix; m++)
7225 nnz_from_proc(p, m) = temp_recv_storage[p][m + 1];
7227 delete[] temp_recv_storage[p];
7231 n_eqn_from_proc[p] = n_eqn_for_proc[p];
7232 for (
unsigned m = 0; m < n_matrix; m++)
7234 nnz_from_proc(p, m) = nnz_for_proc(p, m);
7238 recv_nnz_stat.clear();
7239 recv_nnz_reqs.clear();
7253 MPI_Aint communication_base;
7254 MPI_Get_address(&base, &communication_base);
7255 unsigned n_comm_types = 1 + 1 * n_vector + 3 * n_matrix;
7258 for (
unsigned p = 0; p < nproc; p++)
7263 if (n_eqn_from_proc[p] > 0)
7265 eqns_from_proc[p] =
new unsigned[n_eqn_from_proc[p]];
7266 for (
unsigned v = 0; v < n_vector; v++)
7268 residuals_from_proc(p, v) =
new double[n_eqn_from_proc[p]];
7270 for (
unsigned m = 0; m < n_matrix; m++)
7272 row_start_from_proc(p, m) =
new unsigned[n_eqn_from_proc[p] + 1];
7273 column_indices_from_proc(p, m) =
new unsigned[nnz_from_proc(p, m)];
7274 values_from_proc(p, m) =
new double[nnz_from_proc(p, m)];
7279 if (n_eqn_from_proc[p] > 0)
7281 MPI_Datatype types[n_comm_types];
7282 MPI_Aint offsets[n_comm_types];
7283 int count[n_comm_types];
7288 MPI_Get_address(eqns_from_proc[p], &offsets[pt]);
7289 offsets[pt] -= communication_base;
7290 MPI_Type_contiguous(n_eqn_from_proc[p], MPI_UNSIGNED, &types[pt]);
7291 MPI_Type_commit(&types[pt]);
7295 for (
unsigned v = 0; v < n_vector; v++)
7298 MPI_Get_address(residuals_from_proc(p, v), &offsets[pt]);
7299 offsets[pt] -= communication_base;
7300 MPI_Type_contiguous(n_eqn_from_proc[p], MPI_DOUBLE, &types[pt]);
7301 MPI_Type_commit(&types[pt]);
7306 for (
unsigned m = 0; m < n_matrix; m++)
7310 MPI_Get_address(row_start_from_proc(p, m), &offsets[pt]);
7311 offsets[pt] -= communication_base;
7312 MPI_Type_contiguous(
7313 n_eqn_from_proc[p] + 1, MPI_UNSIGNED, &types[pt]);
7314 MPI_Type_commit(&types[pt]);
7320 MPI_Get_address(column_indices_from_proc(p, m), &offsets[pt]);
7321 offsets[pt] -= communication_base;
7322 MPI_Type_contiguous(nnz_from_proc(p, m), MPI_UNSIGNED, &types[pt]);
7323 MPI_Type_commit(&types[pt]);
7328 MPI_Get_address(values_from_proc(p, m), &offsets[pt]);
7329 offsets[pt] -= communication_base;
7330 MPI_Type_contiguous(nnz_from_proc(p, m), MPI_DOUBLE, &types[pt]);
7331 MPI_Type_commit(&types[pt]);
7336 MPI_Datatype recv_type;
7337 MPI_Type_create_struct(
7338 n_comm_types, count, offsets, types, &recv_type);
7339 MPI_Type_commit(&recv_type);
7340 for (
unsigned t = 0;
t < n_comm_types;
t++)
7342 MPI_Type_free(&types[
t]);
7347 MPI_Type_free(&recv_type);
7348 recv_reqs.push_back(req);
7352 if (n_eqn_for_proc[p] > 0)
7354 MPI_Datatype types[n_comm_types];
7355 MPI_Aint offsets[n_comm_types];
7356 int count[n_comm_types];
7361 MPI_Get_address(eqns_for_proc[p], &offsets[pt]);
7362 offsets[pt] -= communication_base;
7363 MPI_Type_contiguous(n_eqn_for_proc[p], MPI_UNSIGNED, &types[pt]);
7364 MPI_Type_commit(&types[pt]);
7368 for (
unsigned v = 0; v < n_vector; v++)
7371 MPI_Get_address(residuals_for_proc(p, v), &offsets[pt]);
7372 offsets[pt] -= communication_base;
7373 MPI_Type_contiguous(n_eqn_for_proc[p], MPI_DOUBLE, &types[pt]);
7374 MPI_Type_commit(&types[pt]);
7379 for (
unsigned m = 0; m < n_matrix; m++)
7383 MPI_Get_address(row_start_for_proc(p, m), &offsets[pt]);
7384 offsets[pt] -= communication_base;
7385 MPI_Type_contiguous(
7386 n_eqn_for_proc[p] + 1, MPI_UNSIGNED, &types[pt]);
7387 MPI_Type_commit(&types[pt]);
7393 MPI_Get_address(column_indices_for_proc(p, m), &offsets[pt]);
7394 offsets[pt] -= communication_base;
7395 MPI_Type_contiguous(nnz_for_proc(p, m), MPI_UNSIGNED, &types[pt]);
7396 MPI_Type_commit(&types[pt]);
7401 MPI_Get_address(values_for_proc(p, m), &offsets[pt]);
7402 offsets[pt] -= communication_base;
7403 MPI_Type_contiguous(nnz_for_proc(p, m), MPI_DOUBLE, &types[pt]);
7404 MPI_Type_commit(&types[pt]);
7409 MPI_Datatype send_type;
7410 MPI_Type_create_struct(
7411 n_comm_types, count, offsets, types, &send_type);
7412 MPI_Type_commit(&send_type);
7413 for (
unsigned t = 0;
t < n_comm_types;
t++)
7415 MPI_Type_free(&types[
t]);
7420 MPI_Type_free(&send_type);
7421 send_reqs.push_back(req);
7427 eqns_from_proc[p] = eqns_for_proc[p];
7428 for (
unsigned v = 0; v < n_vector; v++)
7430 residuals_from_proc(p, v) = residuals_for_proc(p, v);
7432 for (
unsigned m = 0; m < n_matrix; m++)
7434 row_start_from_proc(p, m) = row_start_for_proc(p, m);
7435 column_indices_from_proc(p, m) = column_indices_for_proc(p, m);
7436 values_from_proc(p, m) = values_for_proc(p, m);
7442 unsigned n_recv_req = recv_reqs.size();
7446 MPI_Waitall(n_recv_req, &recv_reqs[0], &recv_stat[0]);
7450 unsigned target_nrow_local = target_dist_pt->
nrow_local();
7453 for (
unsigned m = 0; m < n_matrix; m++)
7456 row_start[m] =
new int[target_nrow_local + 1];
7457 row_start[m][0] = 0;
7462 for (
unsigned p = 0; p < nproc; p++)
7464 nnz_allocation = std::max(nnz_allocation, nnz_from_proc(p, m));
7467 values_chunk[0] =
new double[nnz_allocation];
7469 column_indices_chunk[0] =
new int[nnz_allocation];
7472 size_of_chunk[0] = nnz_allocation;
7473 unsigned current_chunk = 0;
7476 for (
unsigned i = 0;
i < target_nrow_local;
i++)
7478 row_start[m][
i] = 0;
7482 for (
unsigned p = 0; p < nproc; p++)
7484 if (n_eqn_from_proc[p] == 0)
7486 row_on_proc[p] = -1;
7491 int right = n_eqn_from_proc[p] - 1;
7492 int midpoint = right / 2;
7493 bool complete =
false;
7496 midpoint = (right + left) / 2;
7497 if (midpoint > right)
7501 if (midpoint < left)
7507 if (eqns_from_proc[p][midpoint] ==
i)
7517 else if (eqns_from_proc[p][midpoint] ==
i)
7521 else if (eqns_from_proc[p][midpoint] >
i)
7523 right = std::max(midpoint - 1, left);
7527 left = std::min(midpoint + 1, right);
7530 row_on_proc[p] = midpoint;
7535 unsigned check_first = ncoef_in_chunk[current_chunk];
7536 unsigned check_last = check_first;
7537 for (
unsigned p = 0; p < nproc; p++)
7539 if (row_on_proc[p] != -1)
7541 int row = row_on_proc[p];
7542 unsigned first = row_start_from_proc(p, m)[row];
7543 unsigned last = row_start_from_proc(p, m)[row + 1];
7544 for (
unsigned l = first; l < last; l++)
7547 for (
unsigned j = check_first; j <= check_last && !done; j++)
7549 if (j == check_last)
7553 if (ncoef_in_chunk[current_chunk] ==
7554 size_of_chunk[current_chunk])
7557 unsigned n_chunk = values_chunk.size();
7561 unsigned nnz_so_far = 0;
7562 for (
unsigned c = 0; c < n_chunk; c++)
7564 nnz_so_far += ncoef_in_chunk[c];
7566 nnz_so_far -= row_start[m][
i];
7569 unsigned avg_nnz = nnz_so_far / (
i + 1);
7572 unsigned nrows_left = target_nrow_local -
i;
7575 unsigned next_chunk_size =
7576 avg_nnz * nrows_left + row_start[m][
i];
7581 values_chunk.resize(n_chunk);
7582 values_chunk[current_chunk] =
new double[next_chunk_size];
7583 column_indices_chunk.resize(n_chunk);
7584 column_indices_chunk[current_chunk] =
7585 new int[next_chunk_size];
7586 size_of_chunk.resize(n_chunk);
7587 size_of_chunk[current_chunk] = next_chunk_size;
7588 ncoef_in_chunk.resize(n_chunk);
7591 for (
unsigned k = check_first; k < check_last; k++)
7593 values_chunk[current_chunk][k - check_first] =
7594 values_chunk[current_chunk - 1][k];
7595 column_indices_chunk[current_chunk][k - check_first] =
7596 column_indices_chunk[current_chunk - 1][k];
7598 ncoef_in_chunk[current_chunk - 1] -= row_start[m][
i];
7599 ncoef_in_chunk[current_chunk] = row_start[m][
i];
7603 check_last = row_start[m][
i];
7608 values_chunk[current_chunk][j] = values_from_proc(p, m)[l];
7609 column_indices_chunk[current_chunk][j] =
7610 column_indices_from_proc(p, m)[l];
7611 ncoef_in_chunk[current_chunk]++;
7616 else if (column_indices_chunk[current_chunk][j] ==
7617 (
int)column_indices_from_proc(p, m)[l])
7619 values_chunk[current_chunk][j] += values_from_proc(p, m)[l];
7629 for (
unsigned p = 0; p < nproc; p++)
7631 if (n_eqn_from_proc[p] > 0)
7633 delete[] row_start_from_proc(p, m);
7634 delete[] column_indices_from_proc(p, m);
7635 delete[] values_from_proc(p, m);
7642 unsigned n_chunk = values_chunk.size();
7644 for (
unsigned c = 0; c < n_chunk; c++)
7646 nnz[m] += ncoef_in_chunk[c];
7651 values[m] =
new double[nnz[m]];
7652 column_indices[m] =
new int[nnz[m]];
7656 for (
unsigned c = 0; c < n_chunk; c++)
7658 unsigned nc = ncoef_in_chunk[c];
7659 for (
unsigned i = 0;
i < nc;
i++)
7661 values[m][pt +
i] = values_chunk[c][
i];
7662 column_indices[m][pt +
i] = column_indices_chunk[c][
i];
7665 delete[] values_chunk[c];
7666 delete[] column_indices_chunk[c];
7672 unsigned g = row_start[m][0];
7673 row_start[m][0] = 0;
7674 for (
unsigned i = 1;
i < target_nrow_local;
i++)
7676 unsigned h = g + row_start[m][
i];
7677 row_start[m][
i] = g;
7680 row_start[m][target_nrow_local] = g;
7684 for (
unsigned v = 0; v < n_vector; v++)
7686 residuals[v] =
new double[target_nrow_local];
7687 for (
unsigned i = 0;
i < target_nrow_local;
i++)
7689 residuals[v][
i] = 0;
7691 for (
unsigned p = 0; p < nproc; p++)
7693 if (n_eqn_from_proc[p] > 0)
7695 unsigned n_eqn_p = n_eqn_from_proc[p];
7696 for (
unsigned i = 0;
i < n_eqn_p;
i++)
7698 residuals[v][eqns_from_proc[p][
i]] += residuals_from_proc(p, v)[
i];
7700 delete[] residuals_from_proc(p, v);
7706 for (
unsigned p = 0; p < nproc; p++)
7708 if (n_eqn_from_proc[p] > 0)
7710 delete[] eqns_from_proc[p];
7716 MPI_Waitall(nproc - 1, &send_nnz_reqs[0], &send_nnz_stat[0]);
7717 for (
unsigned p = 0; p < nproc; p++)
7721 delete[] temp_send_storage[p];
7724 send_nnz_stat.clear();
7725 send_nnz_reqs.clear();
7728 unsigned n_send_reqs = send_reqs.size();
7729 if (n_send_reqs > 0)
7732 MPI_Waitall(n_send_reqs, &send_reqs[0], &send_stat[0]);
7733 for (
unsigned p = 0; p < nproc; p++)
7737 if (n_eqn_for_proc[p])
7739 delete[] eqns_for_proc[p];
7740 for (
unsigned m = 0; m < n_matrix; m++)
7742 delete[] row_start_for_proc(p, m);
7743 delete[] column_indices_for_proc(p, m);
7744 delete[] values_for_proc(p, m);
7746 for (
unsigned v = 0; v < n_vector; v++)
7748 delete[] residuals_for_proc(p, v);
7759 t_local = t_end - t_start;
7763 MPI_Allreduce(&t_local,
7769 MPI_Allreduce(&t_local,
7775 MPI_Allreduce(&t_local,
7781 double imbalance = (t_max - t_min) / (t_sum /
double(nproc)) * 100.0;
7782 if (doing_residuals)
7784 oomph_info <<
"CPU for residual distribut. (loc/max/min/imbal): ";
7788 oomph_info <<
"CPU for Jacobian distribut. (loc/max/min/imbal): ";
7790 oomph_info << t_local <<
" " << t_max <<
" " << t_min <<
" " << imbalance
7804 #ifdef OOMPH_HAS_MPI
7808 OomphLibWarning(
"This is unlikely to work with a distributed problem",
7809 " Problem::get_fd_jacobian()",
7810 OOMPH_EXCEPTION_LOCATION);
7816 const unsigned long n_dof =
ndof();
7824 const double FD_step = 1.0e-8;
7828 jacobian.
resize(n_dof, n_dof);
7831 for (
unsigned long jdof = 0; jdof < n_dof; jdof++)
7833 double backup = *
Dof_pt[jdof];
7846 for (
unsigned long ieqn = 0; ieqn < n_dof; ieqn++)
7848 jacobian(ieqn, jdof) =
7849 (residuals_pls[ieqn] - residuals[ieqn]) /
FD_step;
7920 const double FD_step = 1.0e-8;
7923 double param_value = *parameter_pt;
7936 const unsigned ndof_local = result.
nrow_local();
7939 for (
unsigned n = 0; n < ndof_local; ++n)
7941 result[n] = (newres[n] - result[n]) /
FD_step;
7945 *parameter_pt = param_value;
7969 const unsigned n_vec = C.size();
7980 for (
unsigned i = 0;
i < n_vec;
i++)
7987 #ifdef OOMPH_HAS_MPI
7990 for (
unsigned i = 0;
i < n_vec;
i++)
8006 for (
unsigned long e = 0;
e < Element_pt_range;
e++)
8011 #ifdef OOMPH_HAS_MPI
8025 for (
unsigned l = 0; l < n_var; l++)
8028 const unsigned long eqn_number =
8032 for (
unsigned i = 0;
i < n_vec;
i++)
8034 C_local(
i, l) = C[
i].global_value(eqn_number);
8040 elem_pt, Y_local, C_local, product_local);
8043 for (
unsigned l = 0; l < n_var; l++)
8045 const unsigned long eqn_number =
8048 for (
unsigned i = 0;
i < n_vec;
i++)
8050 product[
i].global_value(eqn_number) += product_local(
i, l);
8055 #ifdef OOMPH_HAS_MPI
8072 double dof_length = 0.0;
8075 for (
unsigned n = 0; n < n_dof_local; n++)
8077 if (std::fabs(this->
dof(n)) > dof_length)
8079 dof_length = std::fabs(this->
dof(n));
8084 for (
unsigned i = 0;
i < n_vec;
i++)
8086 for (
unsigned n = 0; n < n_dof_local; n++)
8088 if (std::fabs(C[
i][n]) > C_length[
i])
8090 C_length[
i] = std::fabs(C[
i][n]);
8096 #ifdef OOMPH_HAS_MPI
8099 const unsigned n_length = n_vec + 1;
8100 double all_length[n_length];
8101 all_length[0] = dof_length;
8102 for (
unsigned i = 0;
i < n_vec;
i++)
8104 all_length[
i + 1] = C_length[
i];
8108 double all_length_reduce[n_length];
8109 MPI_Allreduce(all_length,
8117 dof_length = all_length_reduce[0];
8118 for (
unsigned i = 0;
i < n_vec;
i++)
8120 C_length[
i] = all_length_reduce[
i + 1];
8127 for (
unsigned i = 0;
i < n_vec;
i++)
8129 C_mult[
i] = dof_length / C_length[
i];
8141 for (
unsigned long e = 0;
e < n_element;
e++)
8145 #ifdef OOMPH_HAS_MPI
8152 dummy_res.resize(n_var);
8160 for (
unsigned n = 0; n < n_var; n++)
8167 for (
unsigned i = 0;
i < n_vec;
i++)
8170 for (
unsigned n = 0; n < n_var; n++)
8175 C_mult[
i] * C[
i].global_value(eqn_number);
8186 for (
unsigned n = 0; n < n_var; n++)
8194 for (
unsigned n = 0; n < n_var; n++)
8197 double prod_c = 0.0;
8198 for (
unsigned m = 0; m < n_var; m++)
8201 prod_c += (jac_C(n, m) - jac(n, m)) * Y.
global_value(unknown);
8205 product[
i].global_value(eqn_number) += prod_c / C_mult[
i];
8208 #ifdef OOMPH_HAS_MPI
8216 #ifdef OOMPH_HAS_MPI
8220 for (
unsigned i = 0;
i < n_vec;
i++)
8222 product[
i].sum_all_halo_and_haloed_values();
8233 Vector<std::complex<double>>& alpha,
8237 const bool& make_timesteppers_steady)
8242 if (make_timesteppers_steady)
8249 std::vector<bool> was_steady(n_time_steppers);
8252 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8258 const bool do_adjoint_problem =
false;
8266 do_adjoint_problem);
8271 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8283 const bool do_adjoint_problem =
false;
8291 do_adjoint_problem);
8300 Vector<std::complex<double>>& eigenvalue,
8303 const bool& make_timesteppers_steady)
8308 if (make_timesteppers_steady)
8315 std::vector<bool> was_steady(n_time_steppers);
8318 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8324 const bool do_adjoint_problem =
false;
8331 do_adjoint_problem);
8336 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8348 const bool do_adjoint_problem =
false;
8355 do_adjoint_problem);
8364 const unsigned& n_eval,
8365 Vector<std::complex<double>>& eigenvalue,
8368 const bool& make_timesteppers_steady)
8373 if (make_timesteppers_steady)
8380 std::vector<bool> was_steady(n_time_steppers);
8383 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8389 const bool do_adjoint_problem =
true;
8396 do_adjoint_problem);
8401 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8413 const bool do_adjoint_problem =
true;
8420 do_adjoint_problem);
8431 const double& shift)
8445 std::ostringstream error_stream;
8447 <<
"The distributions of the jacobian and mass matrix are\n"
8448 <<
"not the same and they must be.\n";
8450 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8453 if (mass_matrix.
nrow() != this->ndof())
8455 std::ostringstream error_stream;
8457 <<
"mass_matrix has a distribution, but the number of rows is not "
8458 <<
"equal to the number of degrees of freedom in the problem.";
8460 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8463 if (main_matrix.
nrow() != this->ndof())
8465 std::ostringstream error_stream;
8467 <<
"main_matrix has a distribution, but the number of rows is not "
8468 <<
"equal to the number of degrees of freedom in the problem.";
8470 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8477 std::ostringstream error_stream;
8478 error_stream <<
"The distribution of the jacobian and mass matrix must "
8479 <<
"both be setup or both not setup";
8481 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8514 bool compressed_row_flag =
true;
8516 #ifdef OOMPH_HAS_MPI
8523 row_or_column_start,
8527 compressed_row_flag);
8530 main_matrix.
build(dist_pt);
8534 column_or_row_index[0],
8535 row_or_column_start[0]);
8537 mass_matrix.
build(dist_pt);
8541 column_or_row_index[1],
8542 row_or_column_start[1]);
8543 #ifdef OOMPH_HAS_MPI
8550 column_or_row_index,
8551 row_or_column_start,
8556 main_matrix.
build(dist_pt);
8560 column_or_row_index[0],
8561 row_or_column_start[0]);
8563 mass_matrix.
build(dist_pt);
8567 column_or_row_index[1],
8568 row_or_column_start[1]);
8575 column_or_row_index,
8576 row_or_column_start,
8581 main_matrix.
build(temp_dist_pt);
8585 column_or_row_index[0],
8586 row_or_column_start[0]);
8589 mass_matrix.
build(temp_dist_pt);
8593 column_or_row_index[1],
8594 row_or_column_start[1]);
8596 delete temp_dist_pt;
8623 #ifdef OOMPH_HAS_MPI
8634 for (
unsigned i = 0;
i < n_row_local;
i++)
8636 (*Saved_dof_pt)[
i] = *(this->
Dof_pt[
i]);
8644 unsigned long n_dof =
ndof();
8650 for (
unsigned long n = 0; n < n_dof; n++)
8652 (*Saved_dof_pt)[n] =
dof(n);
8666 "There are no stored values, use store_current_dof_values()\n",
8667 OOMPH_CURRENT_FUNCTION,
8668 OOMPH_EXCEPTION_LOCATION);
8672 #ifdef OOMPH_HAS_MPI
8681 throw OomphLibError(
"The number of stored values is not equal to the "
8682 "current number of dofs\n",
8683 OOMPH_CURRENT_FUNCTION,
8684 OOMPH_EXCEPTION_LOCATION);
8688 for (
unsigned long n = 0; n < n_row_local; n++)
8698 unsigned long n_dof =
ndof();
8702 throw OomphLibError(
"The number of stored values is not equal to the "
8703 "current number of dofs\n",
8704 OOMPH_CURRENT_FUNCTION,
8705 OOMPH_EXCEPTION_LOCATION);
8709 for (
unsigned long n = 0; n < n_dof; n++)
8711 dof(n) = (*Saved_dof_pt)[n];
8725 unsigned long n_dof =
ndof();
8727 if (eigenvector.
nrow() != n_dof)
8729 std::ostringstream error_message;
8730 error_message <<
"Eigenvector has size " << eigenvector.
nrow()
8731 <<
", not equal to the number of dofs in the problem,"
8732 << n_dof << std::endl;
8735 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8745 for (
unsigned long n = 0; n < eigenvector_dof.
nrow_local(); n++)
8747 dof(n) = eigenvector_dof[n];
8750 #ifdef OOMPH_HAS_MPI
8763 unsigned long n_dof =
ndof();
8765 if (eigenvector.
nrow() != n_dof)
8767 std::ostringstream error_message;
8768 error_message <<
"Eigenvector has size " << eigenvector.
nrow()
8769 <<
", not equal to the number of dofs in the problem,"
8770 << n_dof << std::endl;
8773 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8785 for (
unsigned long n = 0; n < eigenvector.
nrow_local(); n++)
8787 dof(n) += epsilon * eigenvector[n];
8790 #ifdef OOMPH_HAS_MPI
8806 double total_linear_solver_time = 0.0;
8811 unsigned long n_dofs =
ndof();
8822 double half_residual_squared = 0.0;
8823 double max_step = 0.0;
8830 unsigned LOOP_FLAG = 1;
8834 #ifdef OOMPH_HAS_MPI
8838 std::ostringstream error_stream;
8839 error_stream <<
"Globally convergent Newton method has not been "
8840 <<
"implemented in parallel yet!" << std::endl;
8842 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8871 oomph_info << std::endl << std::endl << std::endl;
8872 oomph_info <<
"This is a bit bizarre: The problem has no dofs."
8875 <<
"I'll just return from the Newton solver without doing anything."
8884 oomph_info <<
"I hope this is what you intended me to do..."
8887 <<
"Note: All actions_...() functions were called"
8889 oomph_info << std::endl <<
" before returning." << std::endl;
8890 oomph_info << std::endl << std::endl << std::endl;
8901 #ifdef OOMPH_HAS_MPI
8914 half_residual_squared = 0.0;
8916 for (
unsigned i = 0;
i < n_dofs;
i++)
8919 half_residual_squared += dx[
i] * dx[
i];
8921 half_residual_squared *= 0.5;
8922 max_step = 100.0 * std::max(sqrt(sum),
double(n_dofs));
8926 double maxres = dx.
max();
8940 oomph_info <<
"\nInitial Maximum residuals " << maxres << std::endl;
8955 <<
"Linear problem -- convergence in one iteration assumed."
8973 oomph_info <<
"Not recomputing Jacobian! " << std::endl;
8993 oomph_info <<
"Enabling resolve" << std::endl;
9003 total_linear_solver_time += t_solver_end - t_solver_start;
9008 oomph_info <<
"Time for linear solver (ndof=" << n_dofs <<
"): "
9010 t_solver_end - t_solver_start)
9025 for (
unsigned i = 0;
i < ndof_local;
i++)
9033 for (
unsigned i = 0;
i < ndof_local;
i++)
9038 double half_residual_squared_old = half_residual_squared;
9040 half_residual_squared_old,
9043 half_residual_squared,
9049 for (
unsigned l = 0; l < ndof_local; l++)
9054 #ifdef OOMPH_HAS_MPI
9064 double maxres = 0.0;
9084 oomph_info <<
"Newton Step " << count <<
": Maximum residuals "
9085 << maxres << std::endl
9106 <<
") has been exceeded in Newton solver." << std::endl;
9110 oomph_info <<
"Reached max. number of iterations ("
9118 }
while (LOOP_FLAG);
9127 oomph_info <<
"Total time for linear solver (ndof=" << n_dofs <<
"): "
9129 total_linear_solver_time)
9134 double total_time = t_end - t_start;
9138 oomph_info <<
"Total time for Newton solver (ndof=" << n_dofs <<
"): "
9142 if (total_time > 0.0)
9146 oomph_info <<
"Time outside linear solver : "
9147 << (total_time - total_linear_solver_time) / total_time *
9149 <<
" %" << std::endl;
9156 oomph_info <<
"Time outside linear solver : "
9157 <<
"[too fast]" << std::endl;
9168 const double& half_residual_squared_old,
9171 double& half_residual_squared,
9172 const double& stpmax)
9174 const double min_fct_decrease = 1.0e-4;
9175 double convergence_tol_on_x = 1.0e-16;
9177 double lambda_aux = 0.0;
9178 double proposed_lambda;
9179 unsigned long n_dof =
ndof();
9181 for (
unsigned i = 0;
i < n_dof;
i++)
9183 sum += newton_dir[
i] * newton_dir[
i];
9188 for (
unsigned i = 0;
i < n_dof;
i++)
9190 newton_dir[
i] *= stpmax / sum;
9194 for (
unsigned i = 0;
i < n_dof;
i++)
9196 slope += gradient[
i] * newton_dir[
i];
9200 std::ostringstream warn_message;
9201 warn_message <<
"WARNING: Non-negative slope, probably due to a "
9202 <<
" roundoff \nproblem in the linesearch: slope=" << slope
9205 "Problem::globally_convergent_line_search()",
9206 OOMPH_EXCEPTION_LOCATION);
9209 for (
unsigned i = 0;
i < n_dof;
i++)
9212 std::fabs(newton_dir[
i]) / std::max(std::fabs(x_old[
i]), 1.0);
9213 if (temp > test) test = temp;
9215 double lambda_min = convergence_tol_on_x / test;
9216 double lambda = 1.0;
9219 for (
unsigned i = 0;
i < n_dof;
i++)
9221 *
Dof_pt[
i] = x_old[
i] + lambda * newton_dir[
i];
9227 half_residual_squared = 0.0;
9228 for (
unsigned i = 0;
i < n_dof;
i++)
9230 half_residual_squared += residuals[
i] * residuals[
i];
9232 half_residual_squared *= 0.5;
9234 if (lambda < lambda_min)
9236 for (
unsigned i = 0;
i < n_dof;
i++) *
Dof_pt[
i] = x_old[
i];
9238 std::ostringstream warn_message;
9239 warn_message <<
"WARNING: Line search converged on x only!\n";
9241 "Problem::globally_convergent_line_search()",
9242 OOMPH_EXCEPTION_LOCATION);
9245 else if (half_residual_squared <=
9246 half_residual_squared_old + min_fct_decrease * lambda * slope)
9248 oomph_info <<
"Returning from linesearch with lambda=" << lambda
9258 (2.0 * (half_residual_squared - half_residual_squared_old - slope));
9263 half_residual_squared - half_residual_squared_old - lambda * slope;
9264 double r2 = f_aux - half_residual_squared_old - lambda_aux * slope;
9266 (r1 / (lambda * lambda) - r2 / (lambda_aux * lambda_aux)) /
9267 (lambda - lambda_aux);
9268 double b_poly = (-lambda_aux * r1 / (lambda * lambda) +
9269 lambda * r2 / (lambda_aux * lambda_aux)) /
9270 (lambda - lambda_aux);
9273 proposed_lambda = -slope / (2.0 * b_poly);
9277 double discriminant = b_poly * b_poly - 3.0 * a_poly * slope;
9278 if (discriminant < 0.0)
9280 proposed_lambda = 0.5 * lambda;
9282 else if (b_poly <= 0.0)
9284 proposed_lambda = (-b_poly + sqrt(discriminant)) / (3.0 * a_poly);
9288 proposed_lambda = -slope / (b_poly + sqrt(discriminant));
9291 if (proposed_lambda > 0.5 * lambda)
9293 proposed_lambda = 0.5 * lambda;
9297 lambda_aux = lambda;
9298 f_aux = half_residual_squared;
9299 lambda = std::max(proposed_lambda, 0.1 * lambda);
9319 std::vector<bool> was_steady(n_time_steppers);
9322 for (
unsigned i = 0;
i < n_time_steppers;
i++)
9344 <<
"USER-DEFINED ERROR IN NEWTON SOLVER " << std::endl;
9348 oomph_info <<
"ERROR IN THE LINEAR SOLVER" << std::endl;
9354 <<
") REACHED WITHOUT CONVERGENCE " << std::endl;
9365 std::ostringstream error_stream;
9366 error_stream <<
"Error occured in Newton solver. " << std::endl;
9368 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
9375 for (
unsigned i = 0;
i < n_time_steppers;
i++)
9433 double uderiv_dot_y = 0.0, uderiv_dot_z = 0.0;
9437 unsigned LOOP_FLAG = 1;
9443 double arc_length_constraint_residual = 0.0;
9462 #ifdef OOMPH_HAS_MPI
9471 double maxres = y.
max();
9474 arc_length_constraint_residual = 0.0;
9476 for (
unsigned long l = 0; l < ndof_local; l++)
9478 arc_length_constraint_residual +=
9483 #ifdef OOMPH_HAS_MPI
9484 double arc_length_cons_res2 = arc_length_constraint_residual;
9488 MPI_Allreduce(&arc_length_constraint_residual,
9489 &arc_length_cons_res2,
9495 arc_length_constraint_residual = arc_length_cons_res2;
9499 arc_length_constraint_residual +=
9504 if (std::fabs(arc_length_constraint_residual) > maxres)
9506 maxres = std::fabs(arc_length_constraint_residual);
9512 oomph_info <<
"Initial Maximum residuals " << maxres << std::endl;
9542 ->solve_for_two_rhs(
this, y, input_z, z);
9581 for (
unsigned long l = 0; l < ndof_local; l++)
9588 #ifdef OOMPH_HAS_MPI
9590 double uderiv_dot[2];
9591 double uderiv_dot2[2];
9592 uderiv_dot[0] = uderiv_dot_y;
9593 uderiv_dot[1] = uderiv_dot_z;
9594 uderiv_dot2[0] = uderiv_dot_y;
9595 uderiv_dot2[1] = uderiv_dot_z;
9600 MPI_Allreduce(uderiv_dot,
9607 uderiv_dot_y = uderiv_dot2[0];
9608 uderiv_dot_z = uderiv_dot2[1];
9623 double dparam = (arc_length_constraint_residual - uderiv_dot_y) /
9627 *parameter_pt -= dparam;
9630 for (
unsigned long l = 0; l < ndof_local; l++)
9632 *
Dof_pt[l] -= y_pt[l] - dparam * z_pt[l];
9636 #ifdef OOMPH_HAS_MPI
9649 double maxres = y.
max();
9652 arc_length_constraint_residual = 0.0;
9654 for (
unsigned long l = 0; l < ndof_local; l++)
9656 arc_length_constraint_residual +=
9661 #ifdef OOMPH_HAS_MPI
9662 double arc_length_cons_res2 = arc_length_constraint_residual;
9666 MPI_Allreduce(&arc_length_constraint_residual,
9667 &arc_length_cons_res2,
9673 arc_length_constraint_residual = arc_length_cons_res2;
9677 arc_length_constraint_residual +=
9681 if (std::fabs(arc_length_constraint_residual) > maxres)
9683 maxres = std::fabs(arc_length_constraint_residual);
9688 oomph_info <<
"Continuation Step " << count <<
": Maximum residuals "
9707 }
while (LOOP_FLAG);
9738 const unsigned long n_dofs =
ndof();
9761 ->solve_for_two_rhs(
this, dummy, input_z, z);
9839 double*
const& parameter_pt)
9867 double*
const& parameter_pt)
9871 for (
unsigned i = 0;
i < n_global; ++
i)
9874 if (
Global_data_pt[
i]->does_pointer_correspond_to_value(parameter_pt))
9887 const unsigned n_sub_mesh = this->
nsub_mesh();
9889 if (n_sub_mesh == 0)
9893 if (spine_mesh_pt->does_pointer_correspond_to_spine_data(parameter_pt))
9903 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
9908 if (spine_mesh_pt->does_pointer_correspond_to_spine_data(
9957 double*
const local_z_pt = local_z.
values_pt();
9958 for (
unsigned long l = 0; l < ndof_local; l++)
9964 #ifdef OOMPH_HAS_MPI
9989 double chi = local_z.
dot(local_z);
10011 for (
unsigned long l = 0; l < ndof_local; l++)
10025 double*
const& parameter_pt)
10034 double length = 0.0;
10036 for (
unsigned long l = 0; l < ndof_local; l++)
10043 #ifdef OOMPH_HAS_MPI
10044 double length2 = length;
10048 MPI_Allreduce(&length,
10063 length = sqrt(length);
10064 for (
unsigned long l = 0; l < ndof_local; l++)
10081 std::ostringstream warn_message;
10083 <<
"Warning: This function is called after spatially adapting the\n"
10084 <<
"eigenfunction associated with a pitchfork bifurcation and should\n"
10085 <<
"ensure that the exact (anti-)symmetries of problem are enforced\n"
10086 <<
"within that eigenfunction. It is problem specific and must be\n"
10087 <<
"filled in by the user if required.\n"
10088 <<
"A sign of problems is if the slack paramter gets too large and\n"
10089 <<
"if the solution at the Pitchfork is not symmetric.\n";
10091 warn_message.str(),
10092 "Problem::symmetrise_eigenfunction_for_adaptive_pitchfork_tracking()",
10093 OOMPH_EXCEPTION_LOCATION);
10124 const bool& block_solve)
10151 const bool& block_solve)
10180 const bool& block_solve)
10188 new FoldHandler(
this, parameter_pt, eigenvector, normalisation);
10210 const bool& block_solve)
10239 const bool& block_solve)
10267 const double& omega,
10270 const bool& block_solve)
10278 new HopfHandler(
this, parameter_pt, omega, null_real, null_imag);
10316 const unsigned& max_adapt)
10322 std::ostringstream error_message;
10324 <<
"The parameter addressed by " << parameter_pt <<
" with the value "
10326 <<
"\n is supposed to be used for arc-length contiunation,\n"
10327 <<
" but it is stored in a Data object used by the problem.\n\n"
10328 <<
"This is bad for two reasons:\n"
10329 <<
"1. If it's a variable in the problem, it must already have an\n"
10330 "associated equation, so it can't be used for continuation;\n"
10331 <<
"2. The problem data will be reorganised in memory during "
10333 <<
" which means that the pointer will become invalid.\n\n"
10334 <<
"If you are sure that this is what you want to do you must:\n"
10335 <<
"A. Ensure that the value is pinned (don't worry we'll shout again "
10337 <<
"B. Use the alternative interface\n"
10338 <<
" Problem::arc_length_step_solve(Data*,unsigned,...)\n"
10339 <<
" which uses a pointer to the data object and not the raw double "
10343 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
10351 bool continuation_time_stepper_added =
false;
10353 for (
unsigned i = 0;
i < n_time_steppers;
i++)
10357 continuation_time_stepper_added =
true;
10363 if (!continuation_time_stepper_added)
10365 oomph_info <<
"Adding the continuation time stepper\n";
10381 <<
" equation numbers allocated for continuation\n";
10403 const unsigned& data_index,
10405 const unsigned& max_adapt)
10410 std::ostringstream error_stream;
10411 error_stream <<
"The value at index " << data_index
10412 <<
" in the data object to be used for continuation\n"
10413 <<
"is not pinned, which means that it is already a\n"
10414 <<
"variable in the problem "
10415 <<
"and cannot be used for continuation.\n\n"
10416 <<
"Please correct your formulation by either:\n"
10417 <<
"A. Pinning the value"
10419 <<
"B. Using a different parameter for continuation"
10422 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
10430 bool continuation_time_stepper_added =
false;
10432 for (
unsigned i = 0;
i < n_time_steppers;
i++)
10436 continuation_time_stepper_added =
true;
10442 if (!continuation_time_stepper_added)
10444 oomph_info <<
"Adding the continuation time stepper\n";
10461 <<
" equation numbers allocated for continuation\n";
10469 double* parameter_pt = data_pt->
value_pt(data_index);
10493 const unsigned n_sub_mesh = this->
nsub_mesh();
10495 if (n_sub_mesh == 0)
10499 spine_mesh_pt->set_consistent_pinned_spine_values_for_continuation(
10508 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
10513 spine_mesh_pt->set_consistent_pinned_spine_values_for_continuation(
10521 for (
unsigned i = 0;
i < n_global; ++
i)
10537 const unsigned& max_adapt)
10545 std::vector<bool> was_steady(n_time_steppers);
10548 for (
unsigned i = 0;
i < n_time_steppers;
i++)
10556 unsigned max_solve = max_adapt + 1;
10558 unsigned max_count_in_adapt_loop = 0;
10575 bool SIGN_CHANGE =
false;
10579 for (
unsigned isolve = 0; isolve < max_solve; ++isolve)
10584 unsigned n_refined;
10585 unsigned n_unrefined;
10588 adapt(n_refined, n_unrefined);
10590 #ifdef OOMPH_HAS_MPI
10593 unsigned total_refined = 0;
10594 unsigned total_unrefined = 0;
10597 MPI_Allreduce(&n_refined,
10603 n_refined = total_refined;
10604 MPI_Allreduce(&n_unrefined,
10610 n_unrefined = total_unrefined;
10614 oomph_info <<
"---> " << n_refined <<
" elements were refined, and "
10615 << n_unrefined <<
" were unrefined"
10616 #ifdef OOMPH_HAS_MPI
10617 <<
", in total (over all processors).\n";
10624 if ((n_refined == 0) && (n_unrefined == 0))
10626 oomph_info <<
"\n \n Solution is fully converged in "
10627 <<
"Problem::newton_solver(). \n \n ";
10663 for (
unsigned long l = 0; l < ndof_local; l++)
10673 unsigned count = 0;
10676 bool STEP_REJECTED =
false;
10691 std::ostringstream error_message;
10692 error_message <<
"DESIRED ARC-LENGTH STEP " <<
Ds_current
10693 <<
" HAS FALLEN BELOW MINIMUM TOLERANCE, " <<
Minimum_ds
10697 OOMPH_CURRENT_FUNCTION,
10698 OOMPH_EXCEPTION_LOCATION);
10702 STEP_REJECTED =
false;
10713 for (
unsigned long l = 0; l < ndof_local; l++)
10729 std::ostringstream error_stream;
10730 error_stream << std::endl
10731 <<
"USER-DEFINED ERROR IN NEWTON SOLVER " << std::endl;
10732 oomph_info <<
"ERROR IN THE LINEAR SOLVER" << std::endl;
10734 OOMPH_CURRENT_FUNCTION,
10735 OOMPH_EXCEPTION_LOCATION);
10740 oomph_info <<
"STEP REJECTED DUE TO NEWTON SOLVER --- TRYING AGAIN"
10742 STEP_REJECTED =
true;
10750 <<
"STEP REJECTED DUE TO INVERTED ELEMENTS --- TRYING AGAIN"
10752 STEP_REJECTED =
true;
10756 }
while (STEP_REJECTED);
10759 if (count > max_count_in_adapt_loop)
10761 max_count_in_adapt_loop = count;
10767 if (max_count_in_adapt_loop > 0)
10776 "The sign of the jacobian is zero after a linear solve\n";
10777 error_message +=
"Either the matrix is singular (unlikely),\n";
10778 error_message +=
"or the linear solver cannot compute the "
10779 "determinant of the matrix;\n";
10780 error_message +=
"e.g. an iterative linear solver.\n";
10782 "If the latter, bifurcation detection must be via an eigensolver\n";
10784 "Problem::arc_length_step_solve",
10785 OOMPH_EXCEPTION_LOCATION);
10801 SIGN_CHANGE =
true;
10817 std::ostringstream message;
10819 <<
"-----------------------------------------------------------";
10820 message << std::endl
10821 <<
"SIGN CHANGE IN DETERMINANT OF JACOBIAN: " << std::endl;
10822 message <<
"BIFURCATION OR TURNING POINT DETECTED BETWEEN "
10828 <<
"-----------------------------------------------------------"
10835 std::ofstream bifurcation_info(
"bifurcation_info",
10836 std::ios_base::app);
10838 bifurcation_info << message.str();
10839 bifurcation_info.close();
10899 for (
unsigned i = 0;
i < n_time_steppers;
i++)
10901 if (!was_steady[
i])
10953 throw OomphLibError(
"Explicit time stepper pointer is null in problem.",
10954 OOMPH_EXCEPTION_LOCATION,
10955 OOMPH_CURRENT_FUNCTION);
10997 const bool& shift_values)
11013 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11021 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11039 <<
"USER-DEFINED ERROR IN NEWTON SOLVER " << std::endl;
11043 oomph_info <<
"ERROR IN THE LINEAR SOLVER" << std::endl;
11049 <<
") REACHED WITHOUT CONVERGENCE " << std::endl;
11059 std::ostringstream error_stream;
11060 error_stream <<
"Error occured in unsteady Newton solver. " << std::endl;
11062 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
11069 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11087 const double& epsilon)
11107 const double& epsilon,
11108 const bool& shift_values)
11120 for (
unsigned i = 0;
i < n_dof_local;
i++) dofs_current[
i] =
dof(
i);
11126 bool reject_timestep = 0;
11129 unsigned adaptive_flag = 0;
11132 double dt_actual = dt_desired;
11136 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11157 reject_timestep = 0;
11158 double dt_rescaling_factor = 1.0;
11165 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11178 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11199 std::string error_message =
"USER-DEFINED ERROR IN NEWTON SOLVER\n";
11200 error_message +=
"ERROR IN THE LINEAR SOLVER\n";
11204 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
11209 oomph_info <<
"TIMESTEP REJECTED DUE TO THE NEWTON SOLVER"
11211 reject_timestep =
true;
11220 oomph_info <<
"TIMESTEP REJECTED DUE TO INVERTED ELEMENTS" << std::endl;
11221 reject_timestep =
true;
11231 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11241 if (adaptive_flag && !reject_timestep)
11245 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11261 dt_rescaling_factor = std::pow(
11265 <<
"- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"
11266 <<
"Estimated timestepping error is " << error <<
"\n"
11267 <<
"Timestep scaling factor is " << dt_rescaling_factor <<
"\n";
11271 if (error > epsilon)
11273 oomph_info <<
"Estimated timestepping error " << error
11274 <<
" exceeds tolerance " << epsilon <<
"\n";
11278 reject_timestep =
true;
11282 oomph_info <<
" ...but we're not rejecting the timestep\n";
11285 <<
"Note: This behaviour can be adjusted by changing the\n"
11286 <<
"protected boolean\n"
11287 <<
" Problem::Keep_temporal_error_below_tolerance\n\n"
11288 <<
"Also, if you are noticing that many of your timesteps result\n"
11289 <<
"in error > tolerance, try reducing the target error with\n"
11290 <<
"respect to the error tolerance by reducing the value of\n"
11291 <<
"Target_error_safety_factor from its default value of 1.0\n"
11292 <<
"using the access function\n"
11293 <<
" target_error_safety_factor() = 0.5 (e.g.)\n"
11294 <<
"The default strategy (Target_error_safety_factor=1.0) tries\n"
11295 <<
"to suggest a timestep which will produce an error equal to\n"
11296 <<
"the error tolerance `epsilon` which risks error > tolerance\n"
11297 <<
"quite often. Setting the safety factor to too small a value\n"
11298 <<
"will make the timesteps unnecessarily small; too large will\n"
11299 <<
"not address the issue -- neither is optimal and a problem\n"
11300 <<
"dependent compromise is needed.\n"
11301 <<
"for more info see:\n"
11302 <<
" Mayr et al. (2018), p5,9, DOI:10.1016/j.finel.2017.12.002\n"
11303 <<
" Harrier et al. (1993), p168, ISBN:978-3-540-56670-0\n"
11304 <<
" Söderlind (2002), (2.7) on p5, DOI:10.1023/A:1021160023092\n";
11307 <<
"- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"
11319 double new_dt_candidate = dt_rescaling_factor * dt_actual;
11324 oomph_info <<
"Tried to increase dt by the ratio "
11325 << dt_rescaling_factor <<
" which is above the maximum ("
11327 <<
"). Attempting to increase by the maximum ratio instead."
11340 <<
"Warning: Adaptation of timestep to ensure satisfaction\n"
11341 <<
" of error bounds during adaptive timestepping\n"
11342 <<
" would lower dt below \n"
11343 <<
" Problem::Minimum_dt_but_still_proceed="
11345 <<
" ---> We're continuing with present timestep.\n"
11347 dt_rescaling_factor = 1.0;
11355 oomph_info <<
"Timestep would decrease by " << dt_rescaling_factor
11356 <<
" which is less than the minimum scaling factor "
11358 oomph_info <<
"TIMESTEP REJECTED" << std::endl;
11359 reject_timestep = 1;
11366 oomph_info <<
"Tried to increase dt to " << new_dt_candidate
11367 <<
" which is above the maximum (" <<
Maximum_dt
11368 <<
"). I increased it to the maximum value instead.";
11373 std::ostringstream err;
11374 err <<
"Tried to reduce dt to " << new_dt_candidate
11375 <<
" which is less than the minimum dt (" <<
Minimum_dt <<
")."
11378 err.str(), OOMPH_EXCEPTION_LOCATION, OOMPH_CURRENT_FUNCTION);
11382 dt_actual = new_dt_candidate;
11390 if (reject_timestep)
11396 unsigned ni = dofs_current.size();
11397 for (
unsigned i = 0;
i < ni;
i++)
11399 dof(
i) = dofs_current[
i];
11402 #ifdef OOMPH_HAS_MPI
11417 while (reject_timestep);
11443 const double& dt_desired,
11444 const double& epsilon,
11445 const unsigned& max_adapt,
11446 const unsigned& suppress_resolve_after_spatial_adapt_flag,
11448 const bool& shift_values)
11457 oomph_info <<
"Accepted solution taken with timestep: " << dt_taken
11462 if (max_adapt == 0)
11464 oomph_info <<
"No spatial refinement allowed; max_adapt=0\n";
11469 unsigned n_refined = 0;
11470 unsigned n_unrefined = 0;
11471 adapt(n_refined, n_unrefined);
11475 total_ref_count[0] = n_refined;
11476 total_ref_count[1] = n_unrefined;
11479 #ifdef OOMPH_HAS_MPI
11484 ref_count[0] = n_refined;
11485 ref_count[1] = n_unrefined;
11486 MPI_Allreduce(&ref_count[0],
11487 &total_ref_count[0],
11497 if ((total_ref_count[0] != 0) || (total_ref_count[1] != 0))
11499 if (suppress_resolve_after_spatial_adapt_flag == 1)
11501 oomph_info <<
"Mesh was adapted but re-solve has been suppressed."
11507 <<
"Mesh was adapted --> we'll re-solve for current timestep."
11516 bool shift =
false;
11525 oomph_info <<
"Re-assigning initial condition at time="
11548 oomph_info <<
"Mesh wasn't adapted --> we'll accept spatial refinement."
11569 for (
unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
11572 ->time_stepper_pt()
11599 OOMPH_CURRENT_FUNCTION,
11600 OOMPH_EXCEPTION_LOCATION);
11617 OOMPH_CURRENT_FUNCTION,
11618 OOMPH_EXCEPTION_LOCATION);
11636 TimeStepper*
const& time_stepper_pt,
const bool& preserve_existing_data)
11643 preserve_existing_data);
11646 const unsigned n_sub_mesh = this->
nsub_mesh();
11648 if (n_sub_mesh == 0)
11651 preserve_existing_data);
11657 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
11660 time_stepper_pt, preserve_existing_data);
11666 for (
unsigned i = 0;
i < n_global; ++
i)
11669 preserve_existing_data);
11675 #ifdef OOMPH_HAS_MPI
11678 std::ostringstream warning_stream;
11679 warning_stream <<
"This has not been comprehensively tested for "
11680 "distributed problems.\n"
11681 <<
"I'm sure that I need to worry about external halo and "
11682 "external elements."
11685 warning_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
11708 for (
unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
11732 std::string err =
"Prediction by explicit step only works for "
11733 "problems with a simple time";
11734 err +=
"stepper. I think implementing anything more general will";
11735 err +=
"require a rewrite of explicit time steppers. - David";
11737 err, OOMPH_EXCEPTION_LOCATION, OOMPH_CURRENT_FUNCTION);
11756 std::string err =
"Requested predictions by explicit step but explicit";
11757 err +=
" predictor pt is null.";
11759 err, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
11765 throw OomphLibError(
"Problem has explicit time stepper other than "
11766 "predictor, not sure how to handle this yet ??ds",
11767 OOMPH_EXCEPTION_LOCATION,
11768 OOMPH_CURRENT_FUNCTION);
11777 double backup_time =
time();
11796 if (std::abs(
time() - backup_time) > 1
e-12)
11798 using namespace StringConversion;
11799 std::string err =
"Predictor landed at the wrong time!";
11800 err +=
" Expected time " +
to_string(backup_time, 14) +
" but got ";
11803 err, OOMPH_EXCEPTION_LOCATION, OOMPH_CURRENT_FUNCTION);
11820 for (
unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
11822 Global_data_pt[iglobal]->time_stepper_pt()->calculate_predicted_values(
11834 #ifdef OOMPH_HAS_MPI
11837 throw OomphLibError(
"Not yet implemented for distributed problems",
11838 OOMPH_EXCEPTION_LOCATION,
11839 OOMPH_CURRENT_FUNCTION);
11848 std::string err =
"Not implemented for multiple time steppers";
11850 err, OOMPH_EXCEPTION_LOCATION, OOMPH_CURRENT_FUNCTION);
11858 for (
unsigned i = 0;
i <
ndof();
i++)
11860 dof(
i) = predicted_dofs[
i];
11881 for (
unsigned e = 0;
e < n_element;
e++)
11906 for (
unsigned e = 0;
e < n_element;
e++)
11934 bool unsteady_flag = (orig_problem_pt->
time_pt() != 0);
11939 oomph_info <<
"Copying an unsteady problem." << std::endl;
11943 unsigned n_dt = orig_problem_pt->
time_pt()->
ndt();
11945 for (
unsigned i = 0;
i < n_dt;
i++)
11954 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11965 if (nmesh == 0) nmesh = 1;
11966 for (
unsigned m = 0; m < nmesh; m++)
11972 unsigned long n_node_orig = orig_problem_pt->
mesh_pt(m)->
nnode();
11973 if (n_node != n_node_orig)
11975 std::ostringstream error_message;
11976 error_message <<
"Number of nodes in copy " << n_node
11977 <<
" not equal to the number in the original "
11978 << n_node_orig << std::endl;
11981 OOMPH_CURRENT_FUNCTION,
11982 OOMPH_EXCEPTION_LOCATION);
11986 for (
unsigned long i = 0;
i < n_node;
i++)
11991 if (el_node_pt != 0)
11995 el_node_pt->
copy(el_node_orig_pt);
12012 unsigned long n_global_orig = orig_problem_pt->
nglobal_data();
12013 if (n_global != n_global_orig)
12015 std::ostringstream error_message;
12016 error_message <<
"Number of global data in copy " << n_global
12017 <<
" not equal to the number in the original "
12018 << n_global_orig << std::endl;
12021 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
12024 for (
unsigned iglobal = 0; iglobal < n_global; iglobal++)
12034 for (
unsigned m = 0; m < nmesh; m++)
12038 for (
unsigned e = 0;
e < n_element;
e++)
12042 if (n_internal > 0)
12045 unsigned long n_internal_orig =
12047 if (n_internal != n_internal_orig)
12049 std::ostringstream error_message;
12050 error_message <<
"Number of internal data in copy " << n_internal
12051 <<
" not equal to the number in the original "
12052 << n_internal_orig << std::endl;
12055 OOMPH_CURRENT_FUNCTION,
12056 OOMPH_EXCEPTION_LOCATION);
12058 for (
unsigned i = 0;
i < n_internal;
i++)
12076 std::ostringstream error_stream;
12078 <<
"This function must be overloaded in your specific problem, and must\n"
12079 <<
"create an exact copy of your problem. Usually this will be achieved\n"
12080 <<
"by a call to the constructor with exactly the same arguments as "
12084 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
12097 dump_file << std::max(
unsigned(1), n_mesh) <<
" # number of (sub)meshes "
12108 dump_file << mmesh_pt->uniform_refinement_level_when_pruned()
12109 <<
" # uniform refinement when pruned " << std::endl;
12113 dump_file << 0 <<
" # (fake) uniform refinement when pruned "
12116 dump_file << 9999 <<
" # test flag for end of sub-meshes " << std::endl;
12124 for (
unsigned imesh = 0; imesh < n_mesh; imesh++)
12129 dump_file << mmesh_pt->uniform_refinement_level_when_pruned()
12130 <<
" # uniform refinement when pruned " << std::endl;
12134 dump_file << 0 <<
" # (fake) uniform refinement when pruned "
12138 dump_file << 9999 <<
" # test flag for end of sub-meshes " << std::endl;
12141 #ifdef OOMPH_HAS_MPI
12149 for (
unsigned e = 0;
e < n;
e++)
12156 local_base_element_processor[
e] = my_rank;
12171 MPI_Allreduce(&local_base_element_processor[0],
12172 &base_element_processor[0],
12182 base_element_processor = local_base_element_processor;
12186 dump_file << n <<
" # Number of base elements; partitioning follows.\n";
12187 for (
unsigned e = 0;
e < n;
e++)
12189 dump_file << base_element_processor[
e] <<
"\n";
12191 dump_file <<
"8888 #test flag for end of base element distribution\n";
12203 mmesh_pt->dump_refinement(dump_file);
12205 #ifdef OOMPH_HAS_TRIANGLE_LIB
12210 #ifdef OOMPH_HAS_MPI
12229 for (
unsigned imesh = 0; imesh < n_mesh; imesh++)
12235 mmesh_pt->dump_refinement(dump_file);
12237 #ifdef OOMPH_HAS_TRIANGLE_LIB
12243 #ifdef OOMPH_HAS_MPI
12263 bool unsteady_flag = (
time_pt() != 0);
12264 dump_file << unsteady_flag <<
" # bool flag for unsteady" << std::endl;
12270 dump_file <<
time_pt()->
time() <<
" # Time " << std::endl;
12273 dump_file << n_dt <<
" # Number of timesteps " << std::endl;
12274 for (
unsigned i = 0;
i < n_dt;
i++)
12276 dump_file <<
time_pt()->
dt(
i) <<
" # dt " << std::endl;
12283 dump_file <<
"0.0 # Dummy time from steady run " << std::endl;
12285 dump_file <<
"0 # Dummy number of timesteps from steady run" << std::endl;
12290 if (nmesh == 0) nmesh = 1;
12291 for (
unsigned m = 0; m < nmesh; m++)
12300 dump_file << Nglobal <<
" # number of global Data items " << std::endl;
12301 for (
unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
12304 dump_file << std::endl;
12320 bool restart_file_is_open =
true;
12321 if (!restart_file.is_open())
12323 std::ostringstream warn_message;
12324 warn_message <<
"Restart file isn't open -- I'm assuming that this is\n";
12325 warn_message <<
"because we're restarting on a larger number of\n";
12326 warn_message <<
"processor than were in use when the restart data was \n";
12327 warn_message <<
"dumped.\n";
12329 warn_message.str(),
"Problem::read()", OOMPH_EXCEPTION_LOCATION);
12330 restart_file_is_open =
false;
12334 unsigned n_mesh = std::max(
unsigned(1),
nsub_mesh());
12339 getline(restart_file, input_string,
'#');
12342 restart_file.ignore(80,
'\n');
12345 unsigned n_submesh_read;
12346 n_submesh_read = std::atoi(input_string.c_str());
12349 if (restart_file_is_open)
12351 if (n_submesh_read != n_mesh)
12353 std::ostringstream error_message;
12355 <<
"Number of sub-meshes specified in restart file, "
12356 << n_submesh_read <<
" doesn't \n match the my number of sub-meshes,"
12357 << n_mesh << std::endl
12358 <<
"Make sure all sub-meshes have been added to the global mesh\n"
12359 <<
"when calling the Problem::dump() function.\n";
12361 OOMPH_CURRENT_FUNCTION,
12362 OOMPH_EXCEPTION_LOCATION);
12373 #ifdef OOMPH_HAS_MPI
12374 bool refine_and_prune_required =
false;
12377 for (
unsigned i = 0;
i < n_mesh;
i++)
12380 getline(restart_file, input_string,
'#');
12383 restart_file.ignore(80,
'\n');
12386 nrefinement_for_mesh[
i] = std::atoi(input_string.c_str());
12393 if (ref_mesh_pt == 0)
12395 if (nrefinement_for_mesh[
i] != 0)
12397 std::ostringstream error_stream;
12398 error_stream <<
"Nonzero uniform-refinement-when-pruned specified\n"
12399 <<
"even though mesh is not tree-based. Odd. May want\n"
12400 <<
"to check this carefully before disabling this \n"
12401 <<
"warning/error -- most likely if/when we start to\n"
12402 <<
"prune unstructured meshes [though I can't see why\n"
12403 <<
"we would want to do this, given that they are \n"
12404 <<
"currently totally re-generated...]\n";
12406 OOMPH_CURRENT_FUNCTION,
12407 OOMPH_EXCEPTION_LOCATION);
12413 unsigned local_min_ref = 0;
12414 unsigned local_max_ref = 0;
12418 unsigned min_ref = local_min_ref;
12420 #ifdef OOMPH_HAS_MPI
12427 int int_local_min_ref = local_min_ref;
12430 int_local_min_ref = INT_MAX;
12432 int int_min_ref = 0;
12433 MPI_Allreduce(&int_local_min_ref,
12441 min_ref = unsigned(int_min_ref);
12446 if (nrefinement_for_mesh[
i] >= min_ref)
12448 nrefinement_for_mesh[
i] -= min_ref;
12452 #ifdef OOMPH_HAS_MPI
12453 if (nrefinement_for_mesh[
i] > 0)
12455 refine_and_prune_required =
true;
12463 #ifdef OOMPH_HAS_MPI
12466 unsigned local_req_flag = 0;
12467 unsigned req_flag = 0;
12468 if (refine_and_prune_required)
12470 local_req_flag = 1;
12472 MPI_Allreduce(&local_req_flag,
12478 refine_and_prune_required =
false;
12481 refine_and_prune_required =
true;
12487 if (refine_and_prune_required)
12492 MPI_Allreduce(&local_nrefinement_for_mesh[0],
12493 &nrefinement_for_mesh[0],
12504 std::ostringstream error_message;
12505 error_message <<
"Number of uniform refinements was not consistent \n"
12506 <<
"for following meshes during restart on processor \n"
12507 <<
"on which restart file could be opened:\n";
12508 for (
unsigned i = 0;
i < n_mesh;
i++)
12510 if ((local_nrefinement_for_mesh[
i] != nrefinement_for_mesh[
i]) &&
12511 restart_file_is_open)
12514 error_message <<
"Sub-mesh: " <<
i <<
"; local nrefinement: "
12515 << local_nrefinement_for_mesh[
i] <<
" "
12516 <<
"; global/synced nrefinement: "
12517 << nrefinement_for_mesh[
i] <<
"\n";
12523 error_message.str(),
"Problem::read()", OOMPH_EXCEPTION_LOCATION);
12531 getline(restart_file, input_string,
'#');
12534 restart_file.ignore(80,
'\n');
12538 tmp = std::atoi(input_string.c_str());
12541 if (restart_file_is_open)
12545 std::ostringstream error_message;
12547 <<
"Error in reading restart data: Uniform refinement when pruned \n"
12548 <<
"flags should be followed by 9999.\n";
12550 OOMPH_CURRENT_FUNCTION,
12551 OOMPH_EXCEPTION_LOCATION);
12562 #ifdef OOMPH_HAS_MPI
12565 if (refine_and_prune_required)
12594 std::streampos position_before_base_element = restart_file.tellg();
12596 bool read_in_base_element_info =
true;
12599 getline(restart_file, input_string,
'#');
12602 restart_file.ignore(80,
'\n');
12605 unsigned n_base_element_read_in = atoi(input_string.c_str());
12607 if (restart_file_is_open)
12609 if (n_base_element_read_in != nbase)
12616 std::ostringstream warn_message;
12618 <<
"The number of base elements in the mesh is 0,\n"
12619 <<
" but the restart file indicates that there are "
12620 << n_base_element_read_in <<
".\n"
12621 <<
"This could be because the restart file was \n"
12622 <<
"generated by using code without MPI.\n"
12624 <<
"The best fix is to include two additional lines\n"
12625 <<
"in the restart file: \n\n"
12626 <<
"0 # Number of base elements; partitioning follows.\n"
12627 <<
"8888 # Test flag for end of base element distribution\n"
12629 <<
"These lines go after the flag 9999 that indicates\n"
12630 <<
"the end of the submesh information.\n"
12632 <<
"The file will now continue to be read assuming that\n"
12633 <<
"the base element information is not present.\n"
12634 <<
"If you get strange results then please look carefully\n"
12635 <<
"at the restart file. The safest thing to do is to \n"
12636 <<
"ensure that the restart file was generated by code\n"
12637 <<
"compiled and run with the same parallel options.\n";
12639 OOMPH_CURRENT_FUNCTION,
12640 OOMPH_EXCEPTION_LOCATION);
12643 read_in_base_element_info =
false;
12644 restart_file.seekg(position_before_base_element);
12649 std::ostringstream error_message;
12650 error_message <<
"About to read " << n_base_element_read_in
12651 <<
" base elements \n"
12652 <<
"though we only have " << nbase
12653 <<
" base elements in mesh.\n";
12655 OOMPH_CURRENT_FUNCTION,
12656 OOMPH_EXCEPTION_LOCATION);
12662 if (read_in_base_element_info ==
true)
12666 for (
unsigned e = 0;
e < nbase;
e++)
12669 getline(restart_file, input_string);
12672 target_domain_for_base_element[
e] = atoi(input_string.c_str());
12676 getline(restart_file, input_string,
'#');
12679 restart_file.ignore(80,
'\n');
12682 tmp = std::atoi(input_string.c_str());
12686 if (restart_file_is_open)
12690 std::ostringstream error_message;
12692 <<
"Error in reading restart data: Target proc for base elements \n"
12693 <<
"should be followed by 8888.\n";
12695 OOMPH_CURRENT_FUNCTION,
12696 OOMPH_EXCEPTION_LOCATION);
12705 unsigned load_balance_required_flag = 0;
12709 unsigned local_load_balance_required_flag = 0;
12714 for (
unsigned e = 0;
e < nel;
e++)
12720 unsigned el_number_in_base_mesh_plus_one =
12726 if (el_number_in_base_mesh_plus_one == 0)
12729 if (face_el_pt != 0)
12736 el_number_in_base_mesh_plus_one =
12740 if (el_number_in_base_mesh_plus_one == 0)
12743 "el_number_in_base_mesh_plus_one=0 for bulk",
12745 OOMPH_EXCEPTION_LOCATION);
12753 if (el_number_in_base_mesh_plus_one == 0)
12756 OOMPH_CURRENT_FUNCTION,
12757 OOMPH_EXCEPTION_LOCATION);
12762 target_domain_for_local_non_halo_element.push_back(
12763 target_domain_for_base_element[el_number_in_base_mesh_plus_one -
12767 if (
int(target_domain_for_base_element
12768 [el_number_in_base_mesh_plus_one - 1]) != my_rank)
12770 local_load_balance_required_flag = 1;
12778 MPI_Allreduce(&local_load_balance_required_flag,
12779 &load_balance_required_flag,
12787 if (load_balance_required_flag == 1)
12789 oomph_info <<
"Doing load balancing after pruning\n";
12792 bool report_stats =
false;
12794 doc_info, report_stats, target_domain_for_local_non_halo_element);
12795 oomph_info <<
"Done load balancing after pruning\n";
12799 oomph_info <<
"No need for load balancing after pruning\n";
12808 bool have_read_unstructured_mesh =
false;
12845 mmesh_pt->refine(restart_file);
12847 #ifdef OOMPH_HAS_TRIANGLE_LIB
12852 #ifdef OOMPH_HAS_MPI
12865 have_read_unstructured_mesh =
true;
12866 #ifdef OOMPH_HAS_MPI
12888 for (
unsigned imesh = 0; imesh < n_mesh; imesh++)
12901 mmesh_pt->refine(restart_file);
12903 #ifdef OOMPH_HAS_TRIANGLE_LIB
12909 #ifdef OOMPH_HAS_MPI
12922 have_read_unstructured_mesh =
true;
12924 #ifdef OOMPH_HAS_MPI
12958 if (have_read_unstructured_mesh)
12963 std::ostringstream warn_message;
12965 <<
"I've just read in some unstructured meshes and have, in\n"
12966 <<
"the process, totally re-generated their nodes and elements.\n"
12967 <<
"This may create dangling pointers that still point to the\n"
12968 <<
"old nodes and elements, e.g. because FaceElements were\n"
12969 <<
"attached to these meshes or pointers to nodes and elements\n"
12970 <<
"were stored somewhere. FaceElements should therefore be\n"
12971 <<
"removed before reading in these meshes, using an overloaded\n"
12972 <<
"version of the function\n\n"
12973 <<
" Problem::actions_before_read_unstructured_meshes()\n\n"
12974 <<
"and then re-attached using an overloaded version of\n\n"
12975 <<
" Problem::actions_after_read_unstructured_meshes().\n\n"
12976 <<
"The required content of these functions is likely to be "
12978 <<
"to the Problem::actions_before_adapt() and \n"
12979 <<
"Problem::actions_after_adapt() that would be required in\n"
12980 <<
"a spatially adaptive computation. If these functions already\n"
12981 <<
"exist and perform the required actions, the \n"
12982 <<
"actions_before/after_read_unstructured_meshes() functions\n"
12983 <<
"can remain empty because the former are called automatically.\n"
12984 <<
"In this case, this warning my be suppressed by setting the\n"
12985 <<
"public boolean\n\n"
12987 "Problem::Suppress_warning_about_actions_before_read_"
12988 "unstructured_meshes\n\n"
12989 <<
"to true." << std::endl;
12991 OOMPH_CURRENT_FUNCTION,
12992 OOMPH_EXCEPTION_LOCATION);
12998 oomph_info <<
"\nNumber of equations in Problem::read(): "
13003 unsigned local_unsteady_restart_flag = 0;
13004 double local_time = -DBL_MAX;
13005 unsigned local_n_dt = 0;
13006 #ifdef OOMPH_HAS_MPI
13007 unsigned local_sync_needed_flag = 0;
13011 if (restart_file.is_open())
13013 oomph_info <<
"Restart file exists" << std::endl;
13014 #ifdef OOMPH_HAS_MPI
13015 local_sync_needed_flag = 0;
13018 getline(restart_file, input_string,
'#');
13021 restart_file.ignore(80,
'\n');
13024 local_unsteady_restart_flag = atoi(input_string.c_str());
13027 getline(restart_file, input_string,
'#');
13030 restart_file.ignore(80,
'\n');
13033 local_time = atof(input_string.c_str());
13036 getline(restart_file, input_string,
'#');
13039 restart_file.ignore(80,
'\n');
13042 local_n_dt = atoi(input_string.c_str());
13043 local_dt.resize(local_n_dt);
13046 for (
unsigned i = 0;
i < local_n_dt;
i++)
13049 getline(restart_file, input_string,
'#');
13052 restart_file.ignore(80,
'\n');
13055 double prev_dt = atof(input_string.c_str());
13056 local_dt[
i] = prev_dt;
13061 oomph_info <<
"Restart file does not exist" << std::endl;
13062 #ifdef OOMPH_HAS_MPI
13063 local_sync_needed_flag = 1;
13072 unsigned sync_needed_flag = 0;
13074 #ifdef OOMPH_HAS_MPI
13078 MPI_Allreduce(&local_sync_needed_flag,
13088 if (sync_needed_flag == 1)
13090 #ifdef OOMPH_HAS_MPI
13096 std::ostringstream error_message;
13097 error_message <<
"Synchronisation of temporal restart data \n"
13098 <<
"required even though Problem hasn't been distributed "
13101 OOMPH_CURRENT_FUNCTION,
13102 OOMPH_EXCEPTION_LOCATION);
13107 unsigned unsteady_restart_flag = 0;
13108 MPI_Allreduce(&local_unsteady_restart_flag,
13109 &unsteady_restart_flag,
13116 unsteady_restart =
false;
13117 if (unsteady_restart_flag == 1)
13119 unsteady_restart =
true;
13122 double time = -DBL_MAX;
13123 MPI_Allreduce(&local_time,
13133 MPI_Allreduce(&local_n_dt,
13143 if (local_dt.size() == 0)
13145 local_dt.resize(n_dt, -DBL_MAX);
13149 MPI_Allreduce(&local_dt[0],
13159 std::ostringstream error_message;
13161 <<
"Synchronisation of temporal restart data \n"
13162 <<
"required even though we don't have mpi support -- very odd!\n";
13164 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13171 unsteady_restart =
false;
13172 if (local_unsteady_restart_flag == 1)
13174 unsteady_restart =
true;
13177 dt.resize(local_n_dt);
13178 for (
unsigned i = 0;
i < local_n_dt;
i++)
13180 dt[
i] = local_dt[
i];
13191 if (nmesh == 0) nmesh = 1;
13192 for (
unsigned m = 0; m < nmesh; m++)
13238 #ifdef OOMPH_HAS_TRIANGLE_LIB
13248 mmesh_pt->update_polyline_representation_from_restart();
13260 getline(restart_file, input_string,
'#');
13263 restart_file.ignore(80,
'\n');
13266 unsigned long check_nglobal = atoi(input_string.c_str());
13269 if (restart_file_is_open)
13271 if (check_nglobal != Nglobal)
13273 std::ostringstream error_message;
13274 error_message <<
"The number of global data " << Nglobal
13275 <<
" is not equal to that specified in the input file "
13276 << check_nglobal << std::endl;
13279 OOMPH_CURRENT_FUNCTION,
13280 OOMPH_EXCEPTION_LOCATION);
13284 for (
unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
13303 for (
unsigned i = 0;
i < n_time_steppers;
i++)
13326 for (
unsigned i = 0;
i < n_time_steppers;
i++)
13342 bool passed =
true;
13354 <<
"\n ERROR: Failed Mesh::self_test() for single mesh in problem"
13361 for (
unsigned imesh = 0; imesh < Nmesh; imesh++)
13366 oomph_info <<
"\n ERROR: Failed Mesh::self_test() for mesh imesh"
13367 << imesh << std::endl;
13375 for (
unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
13381 <<
"\n ERROR: Failed Data::self_test() for global data iglobal"
13382 << iglobal << std::endl;
13387 #ifdef OOMPH_HAS_MPI
13418 unsigned& n_unrefined,
13419 const unsigned& bifurcation_type,
13420 const bool& actually_adapt)
13431 double omega = 0.0;
13433 if (bifurcation_type == 3)
13439 double sigma = 0.0;
13440 if (bifurcation_type == 2)
13442 sigma = this->
dof(this->
ndof() - 1);
13452 const unsigned n_copies = eigenfunction.size();
13456 for (
unsigned c = 0; c < n_copies; c++)
13477 if (mmesh_pt->is_adaptation_enabled())
13484 mmesh_pt->refine_base_mesh_as_in_reference_mesh(
13490 <<
"Info/Warning: Mesh in orginal problem is not refineable."
13496 oomph_info <<
"Info/Warning: Mesh adaptation is disabled in copy."
13502 oomph_info <<
"Info/Warning: Mesh cannot be adapted in copy."
13509 for (
unsigned m = 0; m < N_mesh; m++)
13517 if (mmesh_pt->is_adaptation_enabled())
13524 mmesh_pt->refine_base_mesh_as_in_reference_mesh(
13529 oomph_info <<
"Info/Warning: Mesh in orginal problem is not "
13537 <<
"Info/Warning: Mesh adaptation is disabled in copy."
13543 oomph_info <<
"Info/Warning: Mesh cannot be adapted in copy."
13562 for (
unsigned c = 0; c < n_copies; c++)
13569 std::ostringstream error_stream;
13570 error_stream <<
"Number of unknowns in the problem copy " << c <<
" "
13571 <<
"not equal to number in the original:\n"
13572 << this->
ndof() <<
" (original) "
13576 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13587 if (bifurcation_type == 2)
13590 ->symmetrise_eigenfunction_for_adaptive_pitchfork_tracking();
13598 for (
unsigned c = 0; c < n_copies; c++)
13604 unsigned n_mesh = base_error.size();
13607 if (n_mesh != eigenfunction_error.size())
13609 std::ostringstream error_stream;
13610 error_stream <<
"Problems do not have the same number of meshes\n"
13611 <<
"Base : " << n_mesh
13612 <<
" : Eigenproblem : " << eigenfunction_error.size()
13615 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13619 for (
unsigned m = 0; m < n_mesh; m++)
13622 unsigned n_element = base_error[m].size();
13624 if (n_element != eigenfunction_error[m].size())
13626 std::ostringstream error_stream;
13627 error_stream <<
"Mesh " << m
13628 <<
" does not have the same number of elements in the "
13630 <<
"Base: " << n_element
13631 <<
" : Eigenproblem: " << eigenfunction_error[m].size()
13634 OOMPH_CURRENT_FUNCTION,
13635 OOMPH_EXCEPTION_LOCATION);
13639 for (
unsigned e = 0;
e < n_element;
e++)
13642 base_error[m][
e] += eigenfunction_error[m][
e];
13649 if (actually_adapt)
13652 for (
unsigned c = 0; c < n_copies; c++)
13655 n_refined, n_unrefined, base_error);
13658 if (bifurcation_type == 2)
13661 ->symmetrise_eigenfunction_for_adaptive_pitchfork_tracking();
13665 for (
unsigned c = 0; c < n_copies; c++)
13672 switch (bifurcation_type)
13683 this->
dof(this->
ndof() - 1) = sigma;
13689 parameter_pt, omega, eigenfunction[0], eigenfunction[1]);
13693 std::ostringstream error_stream;
13694 error_stream <<
"Bifurcation type " << bifurcation_type
13696 <<
"1: Fold, 2: Pitchfork, 3: Hopf\n";
13698 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13714 unsigned n_refined, n_unrefined;
13731 double t_start_total = 0.0;
13740 bool continuation_problem =
false;
13748 continuation_problem =
true;
13753 if (bifurcation_type != 0)
13760 if (continuation_problem)
13765 for (
unsigned c = 0; c < 2; c++)
13788 if (mmesh_pt->is_adaptation_enabled())
13795 if (
dynamic_cast<SolidMesh*
>(original_mesh_pt) != 0)
13798 <<
"Info/Warning: Adaptive Continuation is broken in "
13799 <<
"SolidElement" << std::endl;
13801 mmesh_pt->refine_base_mesh_as_in_reference_mesh(
13806 oomph_info <<
"Info/Warning: Mesh in orginal problem is not "
13814 <<
"Info/Warning: Mesh adaptation is disabled in copy."
13825 if (
dynamic_cast<SolidMesh*
>(original_mesh_pt) != 0)
13828 <<
"Info/Warning: Adaptive Continuation is broken in "
13829 <<
"SolidElement" << std::endl;
13835 std::ofstream tri_dump(
"triangle_mesh.dmp");
13836 original_mesh_pt->dump_triangulateio(tri_dump);
13838 std::ifstream tri_read(
"triangle_mesh.dmp");
13839 tmesh_pt->remesh_from_triangulateio(tri_read);
13846 const unsigned n_node = original_mesh_pt->nnode();
13847 for (
unsigned n = 0; n < n_node; ++n)
13849 Node*
const nod_pt = original_mesh_pt->node_pt(n);
13850 Node*
const new_node_pt = tmesh_pt->node_pt(n);
13851 unsigned n_dim = nod_pt->
ndim();
13852 for (
unsigned i = 0;
i < n_dim; ++
i)
13854 new_node_pt->
x(
i) = nod_pt->
x(
i);
13861 <<
"Info/warning: Original Mesh is not TriangleBased\n"
13862 <<
"... but the copy is!" << std::endl;
13867 oomph_info <<
"Info/Warning: Mesh cannot be adapted in copy."
13874 for (
unsigned m = 0; m < N_mesh; m++)
13882 if (mmesh_pt->is_adaptation_enabled())
13889 if (
dynamic_cast<SolidMesh*
>(original_mesh_pt) != 0)
13892 <<
"Info/Warning: Adaptive Continuation is broken in "
13893 <<
"SolidElement" << std::endl;
13896 mmesh_pt->refine_base_mesh_as_in_reference_mesh(
13901 oomph_info <<
"Info/Warning: Mesh in orginal problem is "
13909 <<
"Info/Warning: Mesh adaptation is disabled in copy."
13920 if (
dynamic_cast<SolidMesh*
>(original_mesh_pt) != 0)
13923 <<
"Info/Warning: Adaptive Continuation is broken in "
13924 <<
"SolidElement" << std::endl;
13930 std::ofstream tri_dump(
"triangle_mesh.dmp");
13931 original_mesh_pt->dump_triangulateio(tri_dump);
13933 std::ifstream tri_read(
"triangle_mesh.dmp");
13934 tmesh_pt->remesh_from_triangulateio(tri_read);
13940 const unsigned n_node = original_mesh_pt->nnode();
13941 for (
unsigned n = 0; n < n_node; ++n)
13943 Node*
const nod_pt = original_mesh_pt->node_pt(n);
13944 Node*
const new_node_pt = tmesh_pt->node_pt(n);
13945 unsigned n_dim = nod_pt->
ndim();
13946 for (
unsigned i = 0;
i < n_dim; ++
i)
13948 new_node_pt->
x(
i) = nod_pt->
x(
i);
13955 <<
"Info/warning: Original Mesh is not TriangleBased\n"
13956 <<
"... but the copy is!" << std::endl;
13961 oomph_info <<
"Info/Warning: Mesh cannot be adapted in copy."
13987 std::ostringstream error_stream;
13988 error_stream <<
"Number of unknowns in the problem copy " << c <<
" "
13989 <<
"not equal to number in the original:\n"
13990 << this->
ndof() <<
" (original) "
13994 OOMPH_CURRENT_FUNCTION,
13995 OOMPH_EXCEPTION_LOCATION);
14003 for (
unsigned i = 0;
i < ndof_local;
i++)
14017 n_refined, n_unrefined, base_error);
14019 n_refined, n_unrefined, base_error);
14031 for (
unsigned i = 0;
i < ndof_local;
i++)
14041 oomph_info <<
"Adapting problem:" << std::endl;
14042 oomph_info <<
"=================" << std::endl;
14044 double t_start = 0.0;
14053 double t_end = 0.0;
14057 oomph_info <<
"Time for actions before adapt: " << t_end - t_start
14077 if (mmesh_pt->is_adaptation_enabled())
14083 mmesh_pt->spatial_error_estimator_pt();
14086 if (error_estimator_pt == 0)
14089 OOMPH_CURRENT_FUNCTION,
14090 OOMPH_EXCEPTION_LOCATION);
14097 if (mmesh_pt->doc_info_pt() == 0)
14104 mesh_pt(0), elemental_error, *mmesh_pt->doc_info_pt());
14108 mmesh_pt->max_error() = std::fabs(*std::max_element(
14109 elemental_error.begin(), elemental_error.end(),
AbsCmp<double>()));
14111 mmesh_pt->min_error() = std::fabs(*std::min_element(
14112 elemental_error.begin(), elemental_error.end(),
AbsCmp<double>()));
14114 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
14115 << mmesh_pt->min_error() << std::endl
14122 oomph_info <<
"Time for error estimation: " << t_end - t_start
14128 mmesh_pt->adapt(elemental_error);
14131 n_refined += mmesh_pt->nrefined();
14132 n_unrefined += mmesh_pt->nunrefined();
14137 oomph_info <<
"Time for complete mesh adaptation "
14138 <<
"(but excluding comp of error estimate): "
14139 << t_end - t_start << std::endl;
14145 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14151 oomph_info <<
"Info/Warning: Mesh cannot be adapted" << std::endl;
14159 for (
unsigned imesh = 0; imesh < Nmesh; imesh++)
14169 mmesh_pt->spatial_error_estimator_pt();
14172 if (error_estimator_pt == 0)
14175 OOMPH_CURRENT_FUNCTION,
14176 OOMPH_EXCEPTION_LOCATION);
14180 if (mmesh_pt->is_adaptation_enabled())
14184 if (mmesh_pt->doc_info_pt() == 0)
14192 mesh_pt(imesh), elemental_error, *mmesh_pt->doc_info_pt());
14196 if (
mesh_pt(imesh)->nelement() > 0)
14198 mmesh_pt->max_error() =
14199 std::fabs(*std::max_element(elemental_error.begin(),
14200 elemental_error.end(),
14203 mmesh_pt->min_error() =
14204 std::fabs(*std::min_element(elemental_error.begin(),
14205 elemental_error.end(),
14209 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
14210 << mmesh_pt->min_error() << std::endl;
14216 oomph_info <<
"Time for error estimation: " << t_end - t_start
14222 mmesh_pt->adapt(elemental_error);
14225 n_refined += mmesh_pt->nrefined();
14226 n_unrefined += mmesh_pt->nunrefined();
14232 oomph_info <<
"Time for complete mesh adaptation "
14233 <<
"(but excluding comp of error estimate): "
14234 << t_end - t_start << std::endl;
14240 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14246 oomph_info <<
"Info/Warning: Mesh cannot be adapted." << std::endl;
14259 oomph_info <<
"Total time for actual adaptation "
14260 <<
"(all meshes; incl error estimates): " << t_end - t_start
14272 oomph_info <<
"Time for actions after adapt: " << t_end - t_start
14276 oomph_info <<
"About to start re-assigning eqn numbers "
14277 <<
"with Problem::assign_eqn_numbers() at end of "
14278 <<
"Problem::adapt().\n";
14289 oomph_info <<
"Time for re-assigning eqn numbers with "
14290 <<
"Problem::assign_eqn_numbers() at end of Problem::adapt(): "
14291 << t_end - t_start << std::endl;
14292 oomph_info <<
"Total time for adapt: " << t_end - t_start_total
14308 double t_start_total = 0.0;
14318 if (bifurcation_type != 0)
14326 oomph_info <<
"p-adapting problem:" << std::endl;
14327 oomph_info <<
"===================" << std::endl;
14329 double t_start = 0.0;
14338 double t_end = 0.0;
14342 oomph_info <<
"Time for actions before adapt: " << t_end - t_start
14362 if (mmesh_pt->is_p_adaptation_enabled())
14368 mmesh_pt->spatial_error_estimator_pt();
14371 if (error_estimator_pt == 0)
14374 OOMPH_CURRENT_FUNCTION,
14375 OOMPH_EXCEPTION_LOCATION);
14382 if (mmesh_pt->doc_info_pt() == 0)
14389 mesh_pt(0), elemental_error, *mmesh_pt->doc_info_pt());
14393 mmesh_pt->max_error() = std::fabs(*std::max_element(
14394 elemental_error.begin(), elemental_error.end(),
AbsCmp<double>()));
14396 mmesh_pt->min_error() = std::fabs(*std::min_element(
14397 elemental_error.begin(), elemental_error.end(),
AbsCmp<double>()));
14399 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
14400 << mmesh_pt->min_error() << std::endl
14407 oomph_info <<
"Time for error estimation: " << t_end - t_start
14413 mmesh_pt->p_adapt(elemental_error);
14416 n_refined += mmesh_pt->nrefined();
14417 n_unrefined += mmesh_pt->nunrefined();
14422 oomph_info <<
"Time for complete mesh adaptation "
14423 <<
"(but excluding comp of error estimate): "
14424 << t_end - t_start << std::endl;
14430 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14436 oomph_info <<
"Info/Warning: Mesh cannot be adapted" << std::endl;
14444 for (
unsigned imesh = 0; imesh < Nmesh; imesh++)
14454 mmesh_pt->spatial_error_estimator_pt();
14457 if (error_estimator_pt == 0)
14460 OOMPH_CURRENT_FUNCTION,
14461 OOMPH_EXCEPTION_LOCATION);
14465 if (mmesh_pt->is_p_adaptation_enabled())
14469 if (mmesh_pt->doc_info_pt() == 0)
14477 mesh_pt(imesh), elemental_error, *mmesh_pt->doc_info_pt());
14481 if (
mesh_pt(imesh)->nelement() > 0)
14483 mmesh_pt->max_error() =
14484 std::fabs(*std::max_element(elemental_error.begin(),
14485 elemental_error.end(),
14488 mmesh_pt->min_error() =
14489 std::fabs(*std::min_element(elemental_error.begin(),
14490 elemental_error.end(),
14494 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
14495 << mmesh_pt->min_error() << std::endl;
14501 oomph_info <<
"Time for error estimation: " << t_end - t_start
14507 mmesh_pt->p_adapt(elemental_error);
14510 n_refined += mmesh_pt->nrefined();
14511 n_unrefined += mmesh_pt->nunrefined();
14517 oomph_info <<
"Time for complete mesh adaptation "
14518 <<
"(but excluding comp of error estimate): "
14519 << t_end - t_start << std::endl;
14525 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14531 oomph_info <<
"Info/Warning: Mesh cannot be adapted." << std::endl;
14544 oomph_info <<
"Total time for actual adaptation "
14545 <<
"(all meshes; incl error estimates): " << t_end - t_start
14557 oomph_info <<
"Time for actions after adapt: " << t_end - t_start
14561 oomph_info <<
"About to start re-assigning eqn numbers "
14562 <<
"with Problem::assign_eqn_numbers() at end of "
14563 <<
"Problem::adapt().\n";
14574 oomph_info <<
"Time for re-assigning eqn numbers with "
14575 <<
"Problem::assign_eqn_numbers() at end of Problem::adapt(): "
14576 << t_end - t_start << std::endl;
14577 oomph_info <<
"Total time for adapt: " << t_end - t_start_total
14592 unsigned& n_refined,
14593 unsigned& n_unrefined,
14597 oomph_info <<
"Adapting problem:" << std::endl;
14598 oomph_info <<
"=================" << std::endl;
14618 if (mmesh_pt->is_adaptation_enabled())
14621 mmesh_pt->adapt(elemental_error[0]);
14624 n_refined += mmesh_pt->nrefined();
14625 n_unrefined += mmesh_pt->nunrefined();
14629 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14635 oomph_info <<
"Info/Warning: Mesh cannot be adapted" << std::endl;
14644 for (
unsigned imesh = 0; imesh < Nmesh; imesh++)
14650 if (mmesh_pt->is_adaptation_enabled())
14653 mmesh_pt->adapt(elemental_error[imesh]);
14656 n_refined += mmesh_pt->nrefined();
14657 n_unrefined += mmesh_pt->nunrefined();
14661 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14667 oomph_info <<
"Info/Warning: Mesh cannot be adapted." << std::endl;
14700 elemental_error.resize(1);
14706 if (mmesh_pt->is_adaptation_enabled())
14710 mmesh_pt->spatial_error_estimator_pt();
14713 if (error_estimator_pt == 0)
14716 OOMPH_CURRENT_FUNCTION,
14717 OOMPH_EXCEPTION_LOCATION);
14722 elemental_error[0].resize(mmesh_pt->nelement());
14724 if (mmesh_pt->doc_info_pt() == 0)
14727 elemental_error[0]);
14732 elemental_error[0],
14733 *mmesh_pt->doc_info_pt());
14737 mmesh_pt->max_error() =
14738 std::fabs(*std::max_element(elemental_error[0].begin(),
14739 elemental_error[0].end(),
14742 mmesh_pt->min_error() =
14743 std::fabs(*std::min_element(elemental_error[0].begin(),
14744 elemental_error[0].end(),
14747 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
14748 << mmesh_pt->min_error() << std::endl;
14752 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14758 oomph_info <<
"Info/Warning: Mesh cannot be adapted" << std::endl;
14767 elemental_error.resize(Nmesh);
14770 for (
unsigned imesh = 0; imesh < Nmesh; imesh++)
14778 mmesh_pt->spatial_error_estimator_pt();
14781 if (error_estimator_pt == 0)
14784 OOMPH_CURRENT_FUNCTION,
14785 OOMPH_EXCEPTION_LOCATION);
14789 if (mmesh_pt->is_adaptation_enabled())
14792 elemental_error[imesh].resize(mmesh_pt->nelement());
14793 if (mmesh_pt->doc_info_pt() == 0)
14796 elemental_error[imesh]);
14801 elemental_error[imesh],
14802 *mmesh_pt->doc_info_pt());
14806 mmesh_pt->max_error() =
14807 std::fabs(*std::max_element(elemental_error[imesh].begin(),
14808 elemental_error[imesh].end(),
14811 mmesh_pt->min_error() =
14812 std::fabs(*std::min_element(elemental_error[imesh].begin(),
14813 elemental_error[imesh].end(),
14816 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
14817 << mmesh_pt->min_error() << std::endl;
14821 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14827 oomph_info <<
"Info/Warning: Mesh cannot be adapted." << std::endl;
14842 if (bifurcation_type != 0)
14862 mmesh_pt->spatial_error_estimator_pt();
14865 if (error_estimator_pt == 0)
14868 OOMPH_CURRENT_FUNCTION,
14869 OOMPH_EXCEPTION_LOCATION);
14882 mesh_pt(0), elemental_error, doc_info);
14886 mmesh_pt->max_error() = std::fabs(*std::max_element(
14887 elemental_error.begin(), elemental_error.end(),
AbsCmp<double>()));
14889 mmesh_pt->min_error() = std::fabs(*std::min_element(
14890 elemental_error.begin(), elemental_error.end(),
AbsCmp<double>()));
14892 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
14893 << mmesh_pt->min_error() << std::endl;
14902 for (
unsigned imesh = 0; imesh < Nmesh; imesh++)
14910 mmesh_pt->spatial_error_estimator_pt();
14913 if (error_estimator_pt == 0)
14916 OOMPH_CURRENT_FUNCTION,
14917 OOMPH_EXCEPTION_LOCATION);
14923 if (mmesh_pt->doc_info_pt() == 0)
14931 mesh_pt(imesh), elemental_error, *mmesh_pt->doc_info_pt());
14935 if (
mesh_pt(imesh)->nelement() > 0)
14937 mmesh_pt->max_error() =
14938 std::fabs(*std::max_element(elemental_error.begin(),
14939 elemental_error.end(),
14942 mmesh_pt->min_error() =
14943 std::fabs(*std::min_element(elemental_error.begin(),
14944 elemental_error.end(),
14948 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
14949 << mmesh_pt->min_error() << std::endl;
14976 mmesh_pt->refine_selected_elements(elements_to_be_refined);
14980 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
14986 std::ostringstream error_message;
14987 error_message <<
"Problem::refine_selected_elements(...) only works for\n"
14988 <<
"multiple-mesh problems if you specify the mesh\n"
14989 <<
"number in the function argument before the Vector,\n"
14990 <<
"or a Vector of Vectors for each submesh.\n"
14993 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15022 mmesh_pt->refine_selected_elements(elements_to_be_refined_pt);
15026 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15032 std::ostringstream error_message;
15033 error_message <<
"Problem::refine_selected_elements(...) only works for\n"
15034 <<
"multiple-mesh problems if you specify the mesh\n"
15035 <<
"number in the function argument before the Vector,\n"
15036 <<
"or a Vector of Vectors for each submesh.\n"
15039 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15061 if (i_mesh >= n_mesh)
15063 std::ostringstream error_message;
15064 error_message <<
"Problem only has " << n_mesh
15065 <<
" submeshes. Cannot refine submesh " << i_mesh
15068 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15075 mmesh_pt->refine_selected_elements(elements_to_be_refined);
15079 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15101 const unsigned& i_mesh,
15109 if (i_mesh >= n_mesh)
15111 std::ostringstream error_message;
15112 error_message <<
"Problem only has " << n_mesh
15113 <<
" submeshes. Cannot refine submesh " << i_mesh
15116 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15123 mmesh_pt->refine_selected_elements(elements_to_be_refined_pt);
15127 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15157 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
15162 mmesh_pt->refine_selected_elements(elements_to_be_refined[i_mesh]);
15166 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15194 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
15199 mmesh_pt->refine_selected_elements(elements_to_be_refined_pt[i_mesh]);
15203 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15237 mmesh_pt->p_refine_selected_elements(elements_to_be_refined);
15241 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15247 std::ostringstream error_message;
15249 <<
"Problem::p_refine_selected_elements(...) only works for\n"
15250 <<
"multiple-mesh problems if you specify the mesh\n"
15251 <<
"number in the function argument before the Vector,\n"
15252 <<
"or a Vector of Vectors for each submesh.\n"
15255 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15284 mmesh_pt->p_refine_selected_elements(elements_to_be_refined_pt);
15288 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15294 std::ostringstream error_message;
15296 <<
"Problem::p_refine_selected_elements(...) only works for\n"
15297 <<
"multiple-mesh problems if you specify the mesh\n"
15298 <<
"number in the function argument before the Vector,\n"
15299 <<
"or a Vector of Vectors for each submesh.\n"
15302 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15320 "p-refinement for multiple submeshes has not yet been tested.",
15321 "Problem::p_refine_selected_elements()",
15322 OOMPH_EXCEPTION_LOCATION);
15329 if (i_mesh >= n_mesh)
15331 std::ostringstream error_message;
15332 error_message <<
"Problem only has " << n_mesh
15333 <<
" submeshes. Cannot p-refine submesh " << i_mesh
15336 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15343 mmesh_pt->p_refine_selected_elements(elements_to_be_refined);
15347 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15369 const unsigned& i_mesh,
15373 "p-refinement for multiple submeshes has not yet been tested.",
15374 "Problem::p_refine_selected_elements()",
15375 OOMPH_EXCEPTION_LOCATION);
15382 if (i_mesh >= n_mesh)
15384 std::ostringstream error_message;
15385 error_message <<
"Problem only has " << n_mesh
15386 <<
" submeshes. Cannot p-refine submesh " << i_mesh
15389 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15396 mmesh_pt->p_refine_selected_elements(elements_to_be_refined_pt);
15400 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15425 "p-refinement for multiple submeshes has not yet been tested.",
15426 "Problem::p_refine_selected_elements()",
15427 OOMPH_EXCEPTION_LOCATION);
15435 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
15440 mmesh_pt->p_refine_selected_elements(elements_to_be_refined[i_mesh]);
15444 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15467 "p-refinement for multiple submeshes has not yet been tested.",
15468 "Problem::p_refine_selected_elements()",
15469 OOMPH_EXCEPTION_LOCATION);
15477 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
15482 mmesh_pt->p_refine_selected_elements(elements_to_be_refined_pt[i_mesh]);
15486 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15512 double t_start = 0.0;
15520 double t_end = 0.0;
15525 <<
"Time for actions before adapt in Problem::refine_uniformly_aux(): "
15526 << t_end - t_start << std::endl;
15540 unsigned nref = nrefine_for_mesh[0];
15541 for (
unsigned i = 0;
i < nref;
i++)
15543 mmesh_pt->refine_uniformly(doc_info);
15548 oomph_info <<
"Info/Warning: Mesh cannot be refined uniformly "
15556 for (
unsigned imesh = 0; imesh < n_mesh; imesh++)
15562 unsigned nref = nrefine_for_mesh[imesh];
15563 for (
unsigned i = 0;
i < nref;
i++)
15565 mmesh_pt->refine_uniformly(doc_info);
15570 oomph_info <<
"Info/Warning: Cannot refine mesh " << imesh
15581 oomph_info <<
"Time for mesh-level mesh refinement in "
15582 <<
"Problem::refine_uniformly_aux(): " << t_end - t_start
15595 <<
"Time for actions after adapt Problem::refine_uniformly_aux(): "
15596 << t_end - t_start << std::endl;
15601 #ifdef OOMPH_HAS_MPI
15614 oomph_info <<
"Time for Problem::prune_halo_elements_and_nodes() in "
15615 <<
"Problem::refine_uniformly_aux(): " << t_end - t_start
15623 std::ostringstream error_message;
15625 <<
"Requested pruning in serial build. Ignoring the request.\n";
15627 "Problem::refine_uniformly_aux()",
15628 OOMPH_EXCEPTION_LOCATION);
15634 <<
"Number of equations after Problem::refine_uniformly_aux(): "
15640 oomph_info <<
"Time for Problem::assign_eqn_numbers() in "
15641 <<
"Problem::refine_uniformly_aux(): " << t_end - t_start
15659 double t_start = 0.0;
15667 double t_end = 0.0;
15671 oomph_info <<
"Time for actions before adapt in "
15672 "Problem::p_refine_uniformly_aux(): "
15673 << t_end - t_start << std::endl;
15687 unsigned nref = nrefine_for_mesh[0];
15688 for (
unsigned i = 0;
i < nref;
i++)
15690 mmesh_pt->p_refine_uniformly(doc_info);
15695 oomph_info <<
"Info/Warning: Mesh cannot be p-refined uniformly "
15703 "p-refinement for multiple submeshes has not yet been tested.",
15704 "Problem::p_refine_uniformly_aux()",
15705 OOMPH_EXCEPTION_LOCATION);
15708 for (
unsigned imesh = 0; imesh < n_mesh; imesh++)
15714 unsigned nref = nrefine_for_mesh[imesh];
15715 for (
unsigned i = 0;
i < nref;
i++)
15717 mmesh_pt->p_refine_uniformly(doc_info);
15722 oomph_info <<
"Info/Warning: Cannot p-refine mesh " << imesh
15733 oomph_info <<
"Time for mesh-level mesh refinement in "
15734 <<
"Problem::p_refine_uniformly_aux(): " << t_end - t_start
15747 <<
"Time for actions after adapt Problem::p_refine_uniformly_aux(): "
15748 << t_end - t_start << std::endl;
15753 #ifdef OOMPH_HAS_MPI
15766 oomph_info <<
"Time for Problem::prune_halo_elements_and_nodes() in "
15767 <<
"Problem::p_refine_uniformly_aux(): " << t_end - t_start
15775 std::ostringstream error_message;
15777 <<
"Requested pruning in serial build. Ignoring the request.\n";
15779 "Problem::p_refine_uniformly_aux()",
15780 OOMPH_EXCEPTION_LOCATION);
15786 <<
"Number of equations after Problem::p_refine_uniformly_aux(): "
15792 oomph_info <<
"Time for Problem::assign_eqn_numbers() in "
15793 <<
"Problem::p_refine_uniformly_aux(): " << t_end - t_start
15811 std::ostringstream error_message;
15812 error_message <<
"imesh " << i_mesh
15813 <<
" is greater than the number of sub meshes "
15817 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15825 mmesh_pt->refine_uniformly(doc_info);
15829 oomph_info <<
"Info/Warning: Mesh cannot be refined uniformly "
15855 std::ostringstream error_message;
15856 error_message <<
"imesh " << i_mesh
15857 <<
" is greater than the number of sub meshes "
15861 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15869 mmesh_pt->p_refine_uniformly(doc_info);
15873 oomph_info <<
"Info/Warning: Mesh cannot be refined uniformly "
15900 unsigned success_flag = 0;
15912 success_flag += mmesh_pt->unrefine_uniformly();
15916 oomph_info <<
"Info/Warning: Mesh cannot be unrefined uniformly "
15924 for (
unsigned imesh = 0; imesh < n_mesh; imesh++)
15930 success_flag += mmesh_pt->unrefine_uniformly();
15934 oomph_info <<
"Info/Warning: Cannot unrefine mesh " << imesh
15949 if (success_flag > 0)
15970 unsigned success_flag = 0;
15976 std::ostringstream error_message;
15977 error_message <<
"imesh " << i_mesh
15978 <<
" is greater than the number of sub meshes "
15982 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15990 success_flag += mmesh_pt->unrefine_uniformly();
15994 oomph_info <<
"Info/Warning: Mesh cannot be unrefined uniformly "
16008 if (success_flag > 0)
16037 mmesh_pt->p_unrefine_uniformly(doc_info);
16041 oomph_info <<
"Info/Warning: Mesh cannot be p-unrefined uniformly "
16049 throw OomphLibError(
"This functionality has not yet been tested.",
16050 OOMPH_CURRENT_FUNCTION,
16051 OOMPH_EXCEPTION_LOCATION);
16053 for (
unsigned imesh = 0; imesh < n_mesh; imesh++)
16059 mmesh_pt->p_unrefine_uniformly(doc_info);
16063 oomph_info <<
"Info/Warning: Cannot p-unrefine mesh " << imesh
16090 std::ostringstream error_message;
16091 error_message <<
"imesh " << i_mesh
16092 <<
" is greater than the number of sub meshes "
16096 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
16104 mmesh_pt->p_unrefine_uniformly(doc_info);
16108 oomph_info <<
"Info/Warning: Mesh cannot be p-unrefined uniformly "
16136 const unsigned& max_adapt,
16137 const bool& first_timestep,
16141 bool shift_it = shift;
16148 <<
"\n\n===========================================================\n";
16149 oomph_info <<
" ******** WARNING *********** \n";
16151 <<
"===========================================================\n";
16152 oomph_info <<
"Problem::unsteady_newton_solve() called with "
16154 oomph_info <<
"first_timestep: " << first_timestep << std::endl;
16155 oomph_info <<
"shift: " << shift << std::endl;
16156 oomph_info <<
"This doesn't make sense (shifting does have to be done"
16158 oomph_info <<
"since we're constantly re-assigning the initial conditions"
16161 <<
"\n===========================================================\n\n";
16169 unsigned max_solve = max_adapt + 1;
16173 for (
unsigned isolve = 0; isolve < max_solve; isolve++)
16178 unsigned n_refined;
16179 unsigned n_unrefined;
16182 adapt(n_refined, n_unrefined);
16184 #ifdef OOMPH_HAS_MPI
16187 unsigned total_refined = 0;
16188 unsigned total_unrefined = 0;
16191 MPI_Allreduce(&n_refined,
16197 n_refined = total_refined;
16198 MPI_Allreduce(&n_unrefined,
16204 n_unrefined = total_unrefined;
16208 oomph_info <<
"---> " << n_refined <<
" elements were refined, and "
16209 << n_unrefined <<
" were unrefined, in total." << std::endl;
16212 if ((n_refined == 0) && (n_unrefined == 0))
16214 oomph_info <<
"\n \n Solution is fully converged in "
16215 <<
"Problem::unsteady_newton_solver() \n \n ";
16225 if (first_timestep)
16230 oomph_info <<
"Re-setting initial condition " << std::endl;
16250 if ((isolve == 0) || (first_timestep))
16261 if (isolve == max_solve - 1)
16265 <<
"----------------------------------------------------------"
16267 <<
"Reached max. number of adaptations in \n"
16268 <<
"Problem::unsteady_newton_solver().\n"
16269 <<
"----------------------------------------------------------"
16289 unsigned max_solve = max_adapt + 1;
16293 for (
unsigned isolve = 0; isolve < max_solve; isolve++)
16298 unsigned n_refined;
16299 unsigned n_unrefined;
16302 adapt(n_refined, n_unrefined);
16304 #ifdef OOMPH_HAS_MPI
16307 unsigned total_refined = 0;
16308 unsigned total_unrefined = 0;
16311 MPI_Allreduce(&n_refined,
16317 n_refined = total_refined;
16318 MPI_Allreduce(&n_unrefined,
16324 n_unrefined = total_unrefined;
16328 oomph_info <<
"---> " << n_refined <<
" elements were refined, and "
16329 << n_unrefined <<
" were unrefined"
16330 #ifdef OOMPH_HAS_MPI
16331 <<
", in total (over all processors).\n";
16338 if ((n_refined == 0) && (n_unrefined == 0))
16340 oomph_info <<
"\n \n Solution is fully converged in "
16341 <<
"Problem::newton_solver(). \n \n ";
16363 <<
"USER-DEFINED ERROR IN NEWTON SOLVER " << std::endl;
16368 <<
") REACHED WITHOUT CONVERGENCE " << std::endl;
16379 std::ostringstream error_stream;
16380 error_stream <<
"Error occured in adaptive Newton solver. "
16383 OOMPH_CURRENT_FUNCTION,
16384 OOMPH_EXCEPTION_LOCATION);
16394 if (isolve == max_solve - 1)
16398 <<
"----------------------------------------------------------"
16400 <<
"Reached max. number of adaptations in \n"
16401 <<
"Problem::newton_solver().\n"
16402 <<
"----------------------------------------------------------"
16426 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
16434 #ifdef OOMPH_HAS_MPI
16455 for (
unsigned imesh = 0; imesh < n_mesh; ++imesh)
16477 oomph_info <<
"Checking halo schemes on single mesh" << std::endl;
16478 doc_info.
label() =
"_one_and_only_mesh_";
16484 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
16486 oomph_info <<
"Checking halo schemes on submesh " << i_mesh
16488 std::stringstream tmp;
16489 tmp <<
"_mesh" << i_mesh <<
"_";
16490 doc_info.
label() = tmp.str();
16505 bool do_halos =
true;
16506 bool do_external_halos =
false;
16511 do_external_halos =
true;
16526 const bool& do_external_halos)
16529 unsigned n_mesh_loop = 1;
16533 n_mesh_loop = nmesh;
16557 for (
int rank = 0; rank < n_proc; rank++)
16560 send_displacement[rank] = send_data.size();
16564 if (rank != my_rank)
16567 Mesh* my_mesh_pt = 0;
16570 for (
unsigned imesh = 0; imesh < n_mesh_loop; imesh++)
16586 for (
unsigned n = 0; n < n_nod; n++)
16597 unsigned nelem_haloed = haloed_elem_pt.size();
16598 for (
unsigned e = 0;
e < nelem_haloed;
e++)
16600 haloed_elem_pt[
e]->add_internal_data_values_to_vector(send_data);
16604 if (do_external_halos)
16609 for (
unsigned n = 0; n < n_ext_nod; n++)
16617 unsigned next_elem_haloed =
16619 for (
unsigned e = 0;
e < next_elem_haloed;
e++)
16629 send_n[rank] = send_data.size() - send_displacement[rank];
16637 MPI_Alltoall(&send_n[0],
16648 int receive_data_count = 0;
16649 for (
int rank = 0; rank < n_proc; ++rank)
16652 receive_displacement[rank] = receive_data_count;
16653 receive_data_count += receive_n[rank];
16658 if (receive_data_count == 0)
16660 ++receive_data_count;
16666 if (send_data.size() == 0)
16668 send_data.resize(1);
16672 MPI_Alltoallv(&send_data[0],
16674 &send_displacement[0],
16678 &receive_displacement[0],
16683 for (
int send_rank = 0; send_rank < n_proc; send_rank++)
16687 if ((send_rank != my_rank) && (receive_n[send_rank] != 0))
16690 unsigned count = receive_displacement[send_rank];
16693 Mesh* my_mesh_pt = 0;
16696 for (
unsigned imesh = 0; imesh < n_mesh_loop; imesh++)
16711 unsigned n_nod = my_mesh_pt->
nhalo_node(send_rank);
16712 for (
unsigned n = 0; n < n_nod; n++)
16724 unsigned nelem_halo = halo_elem_pt.size();
16725 for (
unsigned e = 0;
e < nelem_halo;
e++)
16727 halo_elem_pt[
e]->read_internal_data_values_from_vector(
16728 receive_data, count);
16732 if (do_external_halos)
16740 for (
unsigned n = 0; n < n_ext_nod; n++)
16749 unsigned next_elem_halo =
16751 for (
unsigned e = 0;
e < next_elem_halo;
e++)
16772 unsigned my_n_eqn =
Dof_pt.size();
16797 unsigned n_send = nproc - my_rank - 1;
16799 for (
unsigned p = my_rank + 1; p < nproc; p++)
16801 MPI_Isend(&my_n_eqn,
16807 &send_req[p - my_rank - 1]);
16812 for (
unsigned p = 0; p < my_rank; p++)
16814 MPI_Recv(&n_eqn_on_proc[p],
16820 MPI_STATUS_IGNORE);
16823 double t_end = 0.0;
16827 oomph_info <<
"Time for send and receive stuff: " << t_end - t_start
16834 unsigned my_eqn_num_base = 0;
16835 for (
unsigned p = 0; p < my_rank; p++)
16837 my_eqn_num_base += n_eqn_on_proc[p];
16849 for (
unsigned e = 0;
e < nelem;
e++)
16854 for (
unsigned iintern = 0; iintern < nintern_data; iintern++)
16857 unsigned nval = int_data_pt->
nvalue();
16858 for (
unsigned ival = 0; ival < nval; ival++)
16860 int old_eqn_number = int_data_pt->
eqn_number(ival);
16861 if (old_eqn_number >= 0)
16864 int new_eqn_number = old_eqn_number + my_eqn_num_base;
16865 int_data_pt->
eqn_number(ival) = new_eqn_number;
16874 for (
unsigned j = 0; j < nnod; j++)
16879 unsigned nval = nod_pt->
nvalue();
16881 for (
unsigned ival = 0; ival < nval; ival++)
16883 int old_eqn_number = nod_pt->
eqn_number(ival);
16885 if (old_eqn_number >= 0)
16888 int new_eqn_number = old_eqn_number + my_eqn_num_base;
16896 if (solid_nod_pt != 0)
16900 for (
unsigned ival = 0; ival < nval; ival++)
16902 int old_eqn_number =
16906 if (old_eqn_number >= 0)
16909 int new_eqn_number = old_eqn_number + my_eqn_num_base;
16920 oomph_info <<
"Time for bumping: " << t_end - t_start << std::endl;
16928 bool do_halos =
true;
16929 bool do_external_halos =
false;
16935 oomph_info <<
"Time for copy_haloed_eqn_numbers_helper for halos: "
16936 << t_end - t_start << std::endl;
16942 do_external_halos =
true;
16949 <<
"Time for copy_haloed_eqn_numbers_helper for external halos: "
16950 << t_end - t_start << std::endl;
16958 if (assign_local_eqn_numbers)
16964 if (n_sub_mesh == 0)
16970 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
16980 oomph_info <<
"Time for assign_local_eqn_numbers in sync: "
16981 << t_end - t_start << std::endl;
16989 MPI_Waitall(n_send, &send_req[0], &send_status[0]);
16995 oomph_info <<
"Time for waitall: " << t_end - t_start << std::endl;
17015 const bool& do_external_halos)
17018 unsigned n_mesh_loop = 1;
17022 n_mesh_loop = nmesh;
17044 for (
int rank = 0; rank < n_proc; rank++)
17047 send_displacement[rank] = send_data.size();
17052 if (rank != my_rank)
17055 Mesh* my_mesh_pt = 0;
17058 for (
unsigned imesh = 0; imesh < n_mesh_loop; imesh++)
17073 for (
unsigned n = 0; n < n_nod; n++)
17083 unsigned nelem_haloed = haloed_elem_pt.size();
17084 for (
unsigned e = 0;
e < nelem_haloed;
e++)
17086 haloed_elem_pt[
e]->add_internal_eqn_numbers_to_vector(send_data);
17090 if (do_external_halos)
17094 for (
unsigned n = 0; n < n_ext_nod; n++)
17102 unsigned next_elem_haloed =
17104 for (
unsigned e = 0;
e < next_elem_haloed;
e++)
17116 send_n[rank] = send_data.size() - send_displacement[rank];
17123 MPI_Alltoall(&send_n[0],
17134 int receive_data_count = 0;
17135 for (
int rank = 0; rank < n_proc; ++rank)
17138 receive_displacement[rank] = receive_data_count;
17139 receive_data_count += receive_n[rank];
17144 if (receive_data_count == 0)
17146 ++receive_data_count;
17152 if (send_data.size() == 0)
17154 send_data.resize(1);
17158 MPI_Alltoallv(&send_data[0],
17160 &send_displacement[0],
17164 &receive_displacement[0],
17171 for (
int send_rank = 0; send_rank < n_proc; send_rank++)
17175 if ((send_rank != my_rank) && (receive_n[send_rank] != 0))
17178 unsigned count = receive_displacement[send_rank];
17181 Mesh* my_mesh_pt = 0;
17184 for (
unsigned imesh = 0; imesh < n_mesh_loop; imesh++)
17199 unsigned n_nod = my_mesh_pt->
nhalo_node(send_rank);
17200 for (
unsigned n = 0; n < n_nod; n++)
17211 unsigned nelem_halo = halo_elem_pt.size();
17212 for (
unsigned e = 0;
e < nelem_halo;
e++)
17214 halo_elem_pt[
e]->read_internal_eqn_numbers_from_vector(
17215 receive_data, count);
17219 if (do_external_halos)
17224 for (
unsigned n = 0; n < n_ext_nod; n++)
17232 unsigned next_elem_halo =
17234 for (
unsigned e = 0;
e < next_elem_halo;
e++)
17255 const bool& report_stats,
17268 std::ostringstream warn_message;
17269 warn_message <<
"WARNING: You've tried to load balance a problem over\n"
17270 <<
"only one processor: ignoring your request.\n";
17272 "Problem::load_balance()",
17273 OOMPH_EXCEPTION_LOCATION);
17283 std::ostringstream error_stream;
17284 error_stream <<
"You have called Problem::load_balance()\n"
17285 <<
"on a non-distributed problem. This doesn't\n"
17286 <<
"make sense -- go distribute your problem first."
17289 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
17293 double t_start = 0.0;
17294 double t_metis = 0.0;
17295 double t_partition = 0.0;
17296 double t_distribute = 0.0;
17297 double t_refine = 0.0;
17298 double t_copy_solution = 0.0;
17307 unsigned old_ndof =
ndof();
17319 old_mesh_pt.resize(1);
17325 old_mesh_pt.resize(n_mesh);
17326 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17328 old_mesh_pt[i_mesh] =
mesh_pt(i_mesh);
17347 unsigned local_ntarget =
17348 input_target_domain_for_local_non_halo_element.size();
17349 unsigned global_ntarget = 0;
17350 MPI_Allreduce(&local_ntarget,
17358 if (global_ntarget > 0)
17360 target_domain_for_local_non_halo_element =
17361 input_target_domain_for_local_non_halo_element;
17371 unsigned objective = 0;
17372 bool bypass_metis =
true;
17376 target_domain_for_local_non_halo_element,
17382 unsigned objective = 0;
17384 this, objective, target_domain_for_local_non_halo_element);
17394 std::map<GeneralisedElement*, unsigned>
17395 target_domain_for_local_non_halo_element_map;
17397 unsigned count_non_halo_el = 0;
17398 for (
unsigned e = 0;
e < n_elem;
e++)
17403 target_domain_for_local_non_halo_element_map[el_pt] =
17404 target_domain_for_local_non_halo_element[count_non_halo_el];
17405 count_non_halo_el++;
17420 target_domain_for_local_non_halo_element.clear();
17421 target_domain_for_local_non_halo_element.reserve(n_elem);
17422 count_non_halo_el = 0;
17423 for (
unsigned e = 0;
e < n_elem;
e++)
17428 target_domain_for_local_non_halo_element.push_back(
17429 target_domain_for_local_non_halo_element_map[el_pt]);
17436 const unsigned n_old_sub_meshes = n_mesh;
17448 unsigned count_td = 0;
17449 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17454 for (
unsigned i = 0;
i < nsub_ele;
i++)
17462 const unsigned target_domain =
17463 target_domain_for_local_non_halo_element[count_td++];
17466 target_domain_for_local_non_halo_element_submesh[i_mesh]
17467 .push_back(target_domain);
17475 const unsigned ntarget_domain =
17476 target_domain_for_local_non_halo_element.size();
17477 if (count_td != ntarget_domain)
17479 std::ostringstream error_stream;
17481 <<
"The number of nonhalo elements (" << count_td
17482 <<
") found in (all)\n"
17483 <<
"the (sub)-mesh(es) is different from the number of target "
17485 <<
"(" << ntarget_domain <<
") for the nonhalo elements.\n"
17486 <<
"Please ensure that you called the rebuild_global_mesh() method "
17487 <<
"after the\npossible deletion of FaceElements in "
17488 <<
"actions_before_distribute()!!!\n\n";
17490 "Problem::load_balance()",
17491 OOMPH_EXCEPTION_LOCATION);
17508 std::vector<bool> is_unstructured_mesh;
17512 bool are_there_unstructured_meshes =
false;
17522 unstructured_mesh_pt.push_back(tri_mesh_pt);
17524 is_unstructured_mesh.push_back(
true);
17527 are_there_unstructured_meshes =
true;
17533 unstructured_mesh_pt.push_back(tri_mesh_pt);
17535 is_unstructured_mesh.push_back(
false);
17542 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17549 unstructured_mesh_pt.push_back(tri_mesh_pt);
17551 is_unstructured_mesh.push_back(
true);
17554 are_there_unstructured_meshes =
true;
17560 unstructured_mesh_pt.push_back(tri_mesh_pt);
17562 is_unstructured_mesh.push_back(
false);
17588 std::map<unsigned, Vector<unsigned>> flat_packed_refinement_info_for_root;
17591 unsigned max_refinement_level_overall = 0;
17596 target_domain_for_local_non_halo_element_in_structured_mesh;
17600 if (!is_unstructured_mesh[0])
17602 const unsigned nele_mesh =
17603 target_domain_for_local_non_halo_element.size();
17604 for (
unsigned e = 0;
e < nele_mesh;
e++)
17606 const unsigned target_domain =
17607 target_domain_for_local_non_halo_element[
e];
17608 target_domain_for_local_non_halo_element_in_structured_mesh
17609 .push_back(target_domain);
17616 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17619 if (!is_unstructured_mesh[i_mesh])
17621 const unsigned nele_sub_mesh =
17622 target_domain_for_local_non_halo_element_submesh[i_mesh].size();
17623 for (
unsigned e = 0;
e < nele_sub_mesh;
e++)
17625 const unsigned target_domain =
17626 target_domain_for_local_non_halo_element_submesh[i_mesh][
e];
17627 target_domain_for_local_non_halo_element_in_structured_mesh
17628 .push_back(target_domain);
17638 target_domain_for_local_non_halo_element_in_structured_mesh,
17642 old_domain_for_base_element,
17643 new_domain_for_base_element,
17644 max_refinement_level_overall);
17648 old_domain_for_base_element,
17649 new_domain_for_base_element,
17650 max_refinement_level_overall,
17651 flat_packed_refinement_info_for_root);
17656 oomph_info <<
"CPU for partition calculation for roots: "
17657 << t_partition - t_metis << std::endl;
17670 std::max(
int(n_old_sub_meshes), 1));
17673 pruned_refinement_level[0] = 0;
17676 if (ref_mesh_pt != 0)
17678 pruned_refinement_level[0] =
17687 if (!is_unstructured_mesh[0])
17689 delete old_mesh_pt[0];
17690 old_mesh_pt[0] = 0;
17697 for (
unsigned i_mesh = 0; i_mesh < n_old_sub_meshes; i_mesh++)
17699 pruned_refinement_level[i_mesh] = 0;
17702 if (ref_mesh_pt != 0)
17704 pruned_refinement_level[i_mesh] =
17713 if (!is_unstructured_mesh[i_mesh])
17715 delete old_mesh_pt[i_mesh];
17716 old_mesh_pt[i_mesh] = 0;
17733 bool some_mesh_has_been_pruned =
false;
17734 unsigned n = pruned_refinement_level.size();
17735 for (
unsigned i = 0;
i < n;
i++)
17737 if (pruned_refinement_level[
i] > 0) some_mesh_has_been_pruned =
true;
17746 if (some_mesh_has_been_pruned)
17761 if (ref_mesh_pt != 0)
17764 unsigned local_min_ref = 0;
17765 unsigned local_max_ref = 0;
17772 int int_local_min_ref = local_min_ref;
17775 int_local_min_ref = INT_MAX;
17777 int int_min_ref = 0;
17778 MPI_Allreduce(&int_local_min_ref,
17786 unsigned min_ref = unsigned(int_min_ref);
17790 unsigned nref = pruned_refinement_level[0] - min_ref;
17791 oomph_info <<
"Refining one-and-only mesh uniformly " << nref
17793 for (
unsigned i = 0;
i < nref;
i++)
17801 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17805 if (ref_mesh_pt != 0)
17808 unsigned local_min_ref = 0;
17809 unsigned local_max_ref = 0;
17816 int int_local_min_ref = local_min_ref;
17819 int_local_min_ref = INT_MAX;
17821 int int_min_ref = 0;
17822 MPI_Allreduce(&int_local_min_ref,
17830 unsigned min_ref = unsigned(int_min_ref);
17834 unsigned nref = pruned_refinement_level[i_mesh] - min_ref;
17835 oomph_info <<
"Refining sub-mesh " << i_mesh <<
" uniformly "
17836 << nref <<
" times\n";
17837 for (
unsigned i = 0;
i < nref;
i++)
17877 unsigned count = 0;
17878 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17881 if (!is_unstructured_mesh[i_mesh])
17885 submesh_element_partition[i_mesh].resize(nsub_ele);
17886 for (
unsigned e = 0;
e < nsub_ele;
e++)
17888 submesh_element_partition[i_mesh][
e] =
17889 new_domain_for_base_element[count++];
17895 const unsigned nnew_domain_for_base_element =
17896 new_domain_for_base_element.size();
17897 if (count != nnew_domain_for_base_element)
17899 std::ostringstream error_stream;
17901 <<
"The number of READ target domains for nonhalo elements\n"
17902 <<
" is (" << count <<
"), but the number of target domains for\n"
17903 <<
"nonhalo elements is (" << nnew_domain_for_base_element
17906 "Problem::load_balance()",
17907 OOMPH_EXCEPTION_LOCATION);
17921 if (!is_unstructured_mesh[0])
17926 for (
unsigned e = 0;
e < n_ele;
e++)
17939 unsigned nglobal_element = 0;
17940 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17943 if (!is_unstructured_mesh[i_mesh])
17953 unsigned counter_base = 0;
17954 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17957 if (!is_unstructured_mesh[i_mesh])
17960 for (
unsigned e = 0;
e < n_ele;
e++)
17972 if (counter_base != nglobal_element)
17974 std::ostringstream error_stream;
17975 error_stream <<
"The number of global elements (" << nglobal_element
17976 <<
") is not the same as the number of\nadded elements ("
17977 << counter_base <<
") to the Base_mesh_element_pt data "
17978 <<
"structure!!!\n\n";
17980 "Problem::load_balance()",
17981 OOMPH_EXCEPTION_LOCATION);
17998 std::map<unsigned, std::map<int, unsigned>> face_element_number;
18000 for (
unsigned e = 0;
e < n_element;
e++)
18004 if (face_el_pt != 0)
18007 std::stringstream info;
18008 info <<
"================================================\n";
18009 info <<
"INFO: I've come across a FaceElement while \n";
18010 info <<
" load-balancing a problem. \n";
18011 info <<
"================================================\n";
18019 throw OomphLibError(
"Base_mesh_element_number_plus_one[...]=0",
18020 OOMPH_CURRENT_FUNCTION,
18021 OOMPH_EXCEPTION_LOCATION);
18026 face_element_number[e_bulk][face_index] =
e;
18037 if (!is_unstructured_mesh[0])
18040 if (
mesh_pt()->nelement() != new_domain_for_base_element.size())
18042 std::ostringstream error_stream;
18043 error_stream <<
"Distributing one-and-only mesh containing "
18045 << new_domain_for_base_element.size() << std::endl;
18047 OOMPH_CURRENT_FUNCTION,
18048 OOMPH_EXCEPTION_LOCATION);
18054 oomph_info <<
"Distributing one and only mesh\n"
18055 <<
"------------------------------" << std::endl;
18060 bool overrule_keep_as_halo_element_status =
false;
18063 new_domain_for_base_element,
18064 deleted_element_pt,
18067 overrule_keep_as_halo_element_status);
18075 bool need_to_rebuild_mesh =
false;
18076 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
18080 if (!is_unstructured_mesh[i_mesh])
18084 oomph_info <<
"Distributing submesh " << i_mesh <<
" of "
18085 << n_mesh <<
" in total\n"
18086 <<
"---------------------------------------------"
18091 doc_info.
number() = i_mesh;
18095 bool overrule_keep_as_halo_element_status =
false;
18097 submesh_element_partition[i_mesh],
18098 deleted_element_pt,
18101 overrule_keep_as_halo_element_status);
18104 need_to_rebuild_mesh =
true;
18110 if (need_to_rebuild_mesh)
18119 unsigned n_del = deleted_element_pt.size();
18120 for (
unsigned e = 0;
e < n_del;
e++)
18130 if (some_mesh_has_been_pruned)
18137 if (ref_mesh_pt != 0)
18140 deleted_element_pt, doc_info, report_stats);
18145 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
18149 if (ref_mesh_pt != 0)
18152 deleted_element_pt, doc_info, report_stats);
18160 unsigned n_del = deleted_element_pt.size();
18161 for (
unsigned e = 0;
e < n_del;
e++)
18176 oomph_info <<
"CPU for build and distribution of new mesh(es): "
18177 << t_distribute - t_partition << std::endl;
18197 new_domain_for_base_element,
18198 max_refinement_level_overall,
18199 flat_packed_refinement_info_for_root,
18200 refinement_info_for_root_elements);
18205 max_refinement_level_overall);
18210 oomph_info <<
"CPU for refinement of base mesh: "
18211 << t_refine - t_distribute << std::endl;
18234 send_n, send_data, send_displacement);
18238 if (are_there_unstructured_meshes)
18251 if (is_unstructured_mesh[0])
18256 this->
mesh_pt() = old_mesh_pt[0];
18261 std::ostringstream error_stream;
18262 error_stream <<
"The only one mesh in the problem is not an "
18263 "unstructured mesh,\n"
18264 <<
"but the flag 'are_there_unstructures_meshes' ("
18265 << are_there_unstructured_meshes
18266 <<
") was turned on,\n"
18267 <<
"this is weird. Please check for any condition "
18269 <<
"turned on this flag!!!!\n\n";
18271 "Problem::load_balance()",
18272 OOMPH_EXCEPTION_LOCATION);
18276 unstructured_mesh_pt[0]->load_balance(
18277 target_domain_for_local_non_halo_element);
18284 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
18286 if (is_unstructured_mesh[i_mesh])
18293 this->
mesh_pt(i_mesh) = old_mesh_pt[i_mesh];
18306 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
18308 if (is_unstructured_mesh[i_mesh])
18311 const unsigned n_element = old_mesh_pt[i_mesh]->nelement();
18317 if (n_element > 0 && is_unstructured_mesh[i_mesh])
18319 unstructured_mesh_pt[i_mesh]->load_balance(
18320 target_domain_for_local_non_halo_element_submesh[i_mesh]);
18335 oomph_info <<
"CPU for transferring solution to new mesh(es): "
18336 << t_copy_solution - t_refine << std::endl;
18337 oomph_info <<
"CPU for load balancing: " << t_copy_solution - t_start
18354 <<
"Total number of elements on this processor after load balance: "
18357 oomph_info <<
"Number of non-halo elements on this processor after "
18363 if (n_dof != old_ndof)
18365 std::ostringstream error_stream;
18367 <<
"Number of dofs in load_balance() has changed from " << old_ndof
18368 <<
" to " << n_dof <<
"\n"
18369 <<
"Check that you've implemented any necessary "
18370 "actions_before/after\n"
18371 <<
"adapt/distribute functions, e.g. to pin redundant pressure dofs"
18374 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
18383 oomph_info <<
"Time for load_balance() [sec] : " << end_t - start_t
18394 const unsigned& max_refinement_level_overall,
18395 std::map<
unsigned,
Vector<unsigned>>& flat_packed_refinement_info_for_root,
18403 unsigned n_base_element = old_domain_for_base_element.size();
18404 refinement_info_for_root_elements.resize(n_base_element);
18408 std::map<unsigned, Vector<unsigned>> halo_domain_of_haloed_base_element;
18414 std::map<unsigned, Vector<unsigned>> halo_domains;
18418 unsigned max_mesh = std::max(n_sub_mesh,
unsigned(1));
18419 for (
unsigned i_mesh = 0; i_mesh < max_mesh; i_mesh++)
18422 Mesh* my_mesh_pt = 0;
18423 if (n_sub_mesh == 0)
18429 my_mesh_pt =
mesh_pt(i_mesh);
18435 if (!(sub_mesh_pt != 0))
18440 for (
int p = 0; p < n_proc; p++)
18444 unsigned nhaloed = haloed_elem_pt.size();
18445 for (
unsigned h = 0; h < nhaloed; h++)
18452 throw OomphLibError(
"Base_mesh_element_number_plus_one[...]=0",
18453 OOMPH_CURRENT_FUNCTION,
18454 OOMPH_EXCEPTION_LOCATION);
18458 halo_domains[
e].push_back(p);
18471 std::map<unsigned, Vector<unsigned>> data_for_proc;
18477 unsigned count = 0;
18481 for (
unsigned e = 0;
e < n_base_element;
e++)
18489 if (
int(old_domain_for_base_element[
e]) == my_rank)
18492 unsigned new_domain = new_domain_for_base_element[
e];
18495 nbase_elements_for_proc[new_domain]++;
18498 if (
int(new_domain) == my_rank)
18502 unsigned nhalo = halo_domains[
e].size();
18503 halo_domain_of_haloed_base_element[
e].resize(nhalo);
18504 for (
unsigned j = 0; j < nhalo; j++)
18506 halo_domain_of_haloed_base_element[
e][j] = halo_domains[
e][j];
18510 refinement_info_for_root_elements[
e].resize(
18511 max_refinement_level_overall);
18515 unsigned n_additional_data =
18516 flat_packed_refinement_info_for_root[
e].size();
18520 unsigned n_tree_nodes = flat_packed_refinement_info_for_root[
e][0];
18523 unsigned local_count = 1;
18526 for (
unsigned level = 0; level < max_refinement_level_overall;
18529 for (
unsigned ee = 0; ee < n_tree_nodes; ee++)
18532 if (flat_packed_refinement_info_for_root[
e][local_count] == 1)
18537 if (flat_packed_refinement_info_for_root[
e][local_count] == 1)
18539 refinement_info_for_root_elements[
e][level].push_back(2);
18545 refinement_info_for_root_elements[
e][level].push_back(1);
18552 refinement_info_for_root_elements[
e][level].push_back(0);
18559 if (n_additional_data != local_count)
18561 std::stringstream error_message;
18562 error_message <<
"Number of additional data: " << n_additional_data
18563 <<
" doesn't match that actually send: "
18564 << local_count << std::endl;
18566 OOMPH_CURRENT_FUNCTION,
18567 OOMPH_EXCEPTION_LOCATION);
18576 unsigned current_size = data_for_proc[new_domain].size();
18577 unsigned n_additional_data =
18578 flat_packed_refinement_info_for_root[
e].size();
18579 data_for_proc[new_domain].reserve(current_size + n_additional_data +
18583 count += n_additional_data + 2;
18586 data_for_proc[new_domain].push_back(
e);
18590 data_for_proc[new_domain].push_back(n_additional_data);
18594 for (
unsigned j = 0; j < n_additional_data; j++)
18596 data_for_proc[new_domain].push_back(
18597 flat_packed_refinement_info_for_root[
e][j]);
18612 send_data.reserve(count);
18618 for (
int rank = 0; rank < n_proc; rank++)
18621 send_displacement[rank] = send_data.size();
18625 if (rank != my_rank)
18628 send_data.push_back(nbase_elements_for_proc[rank]);
18631 unsigned n_data = data_for_proc[rank].size();
18632 for (
unsigned j = 0; j < n_data; j++)
18634 send_data.push_back(data_for_proc[rank][j]);
18639 send_n[rank] = send_data.size() - send_displacement[rank];
18646 MPI_Alltoall(&send_n[0],
18657 int receive_data_count = 0;
18658 for (
int rank = 0; rank < n_proc; ++rank)
18661 receive_displacement[rank] = receive_data_count;
18662 receive_data_count += receive_n[rank];
18667 if (receive_data_count == 0)
18669 ++receive_data_count;
18675 if (send_data.size() == 0)
18677 send_data.resize(1);
18681 MPI_Alltoallv(&send_data[0],
18683 &send_displacement[0],
18687 &receive_displacement[0],
18694 for (
int send_rank = 0; send_rank < n_proc; send_rank++)
18698 if ((send_rank != my_rank) && (receive_n[send_rank] != 0))
18701 unsigned count = receive_displacement[send_rank];
18704 unsigned nbase_element = receive_data[count];
18706 for (
unsigned b = 0; b < nbase_element; b++)
18709 unsigned base_element_number = receive_data[count];
18714 unsigned nhalo = halo_domains[base_element_number].size();
18715 halo_domain_of_haloed_base_element[base_element_number].resize(nhalo);
18716 for (
unsigned j = 0; j < nhalo; j++)
18718 halo_domain_of_haloed_base_element[base_element_number][j] =
18719 halo_domains[base_element_number][j];
18723 refinement_info_for_root_elements[base_element_number].resize(
18724 max_refinement_level_overall);
18729 unsigned n_additional_data = receive_data[count];
18733 unsigned check_count = 0;
18737 unsigned n_tree_nodes = receive_data[count];
18745 for (
unsigned level = 0; level < max_refinement_level_overall;
18748 for (
unsigned e = 0;
e < n_tree_nodes;
e++)
18751 if (receive_data[count] == 1)
18760 if (receive_data[count] == 1)
18762 refinement_info_for_root_elements[base_element_number][level]
18773 refinement_info_for_root_elements[base_element_number][level]
18785 refinement_info_for_root_elements[base_element_number][level]
18797 if (n_additional_data != check_count)
18799 std::stringstream error_message;
18800 error_message <<
"Number of additional data: " << n_additional_data
18801 <<
" doesn't match that actually send: "
18802 << check_count << std::endl;
18804 OOMPH_CURRENT_FUNCTION,
18805 OOMPH_EXCEPTION_LOCATION);
18821 std::map<unsigned, Vector<unsigned>> data_for_proc;
18829 halo_domain_of_haloed_base_element.begin();
18830 it != halo_domain_of_haloed_base_element.end();
18834 unsigned base_element_number = (*it).first;
18838 unsigned nd = domains.size();
18839 for (
unsigned jd = 0; jd < nd; jd++)
18842 unsigned d = domains[jd];
18845 nbase_elements_for_proc[d]++;
18848 data_for_proc[d].push_back(base_element_number);
18851 for (
unsigned level = 0; level < max_refinement_level_overall;
18856 refinement_info_for_root_elements[base_element_number][level]
18858 data_for_proc[d].push_back(n);
18859 for (
unsigned j = 0; j < n; j++)
18861 data_for_proc[d].push_back(
18862 refinement_info_for_root_elements[base_element_number][level]
18878 send_data.reserve(count);
18884 for (
int rank = 0; rank < n_proc; rank++)
18887 send_displacement[rank] = send_data.size();
18891 if (rank != my_rank)
18894 send_data.push_back(nbase_elements_for_proc[rank]);
18897 unsigned n_data = data_for_proc[rank].size();
18898 for (
unsigned j = 0; j < n_data; j++)
18900 send_data.push_back(data_for_proc[rank][j]);
18904 send_n[rank] = send_data.size() - send_displacement[rank];
18911 MPI_Alltoall(&send_n[0],
18922 int receive_data_count = 0;
18923 for (
int rank = 0; rank < n_proc; ++rank)
18926 receive_displacement[rank] = receive_data_count;
18927 receive_data_count += receive_n[rank];
18932 if (receive_data_count == 0)
18934 ++receive_data_count;
18940 if (send_data.size() == 0)
18942 send_data.resize(1);
18946 MPI_Alltoallv(&send_data[0],
18948 &send_displacement[0],
18952 &receive_displacement[0],
18959 for (
int send_rank = 0; send_rank < n_proc; send_rank++)
18963 if ((send_rank != my_rank) && (receive_n[send_rank] != 0))
18966 unsigned count = receive_displacement[send_rank];
18969 unsigned nbase_element = receive_data[count];
18972 for (
unsigned e = 0;
e < nbase_element;
e++)
18975 unsigned base_element_number = receive_data[count];
18979 refinement_info_for_root_elements[base_element_number].resize(
18980 max_refinement_level_overall);
18983 for (
unsigned level = 0; level < max_refinement_level_overall;
18987 unsigned n = receive_data[count];
18991 for (
unsigned j = 0; j < n; j++)
18993 refinement_info_for_root_elements[base_element_number][level]
18994 .push_back(receive_data[count]);
19019 const int n_proc = comm_pt->nproc();
19025 MPI_Alltoall(&send_n[0],
19036 int receive_data_count = 0;
19037 for (
int rank = 0; rank < n_proc; ++rank)
19040 receive_displacement[rank] = receive_data_count;
19041 receive_data_count += receive_n[rank];
19046 if (receive_data_count == 0)
19048 ++receive_data_count;
19054 if (send_data.size() == 0)
19056 send_data.resize(1);
19060 MPI_Alltoallv(&send_data[0],
19062 &send_displacement[0],
19066 &receive_displacement[0],
19070 unsigned el_count = 0;
19076 for (
int send_rank = 0; send_rank < n_proc; send_rank++)
19082 if (receive_n[send_rank] != 0)
19085 unsigned count = receive_displacement[send_rank];
19088 unsigned nbatch = unsigned(receive_data[count]);
19092 for (
unsigned b = 0; b < nbatch; b++)
19095 unsigned nel = unsigned(receive_data[count]);
19100 unsigned base_el_no = unsigned(receive_data[count]);
19112 if (ref_root_el_pt != 0)
19117 all_leaf_nodes_pt);
19120 unsigned n_leaf = all_leaf_nodes_pt.size();
19125 std::ostringstream error_message;
19127 <<
"Number of leaves: " << n_leaf <<
" "
19128 <<
" doesn't match number of elements sent in batch: " << nel
19131 OOMPH_CURRENT_FUNCTION,
19132 OOMPH_EXCEPTION_LOCATION);
19138 batch_el_pt.resize(n_leaf);
19139 for (
unsigned e = 0;
e < n_leaf;
e++)
19141 batch_el_pt[
e] = all_leaf_nodes_pt[
e]->object_pt();
19150 std::ostringstream error_message;
19152 <<
"Non-refineable root element should only be associated with"
19153 <<
" one element but nel=" << nel <<
"\n";
19155 OOMPH_CURRENT_FUNCTION,
19156 OOMPH_EXCEPTION_LOCATION);
19159 batch_el_pt.push_back(root_el_pt);
19163 for (
unsigned e = 0;
e < nel;
e++)
19173 unsigned nnod = fe_pt->
nnode();
19174 for (
unsigned j = 0; j < nnod; j++)
19177 if (!node_done[send_rank][nod_pt])
19179 node_done[send_rank][nod_pt] =
true;
19185 unsigned nval = unsigned(receive_data[count]);
19190 if (nval < nod_pt->nvalue())
19192 std::ostringstream error_message;
19194 <<
"Node has more values, namely " << nod_pt->
nvalue()
19195 <<
", than we're about to receive, namely " << nval
19196 <<
". Something's wrong!\n";
19198 OOMPH_CURRENT_FUNCTION,
19199 OOMPH_EXCEPTION_LOCATION);
19206 unsigned is_boundary_node = unsigned(receive_data[count]);
19217 if (is_boundary_node != 1)
19219 std::ostringstream error_message;
19220 error_message <<
"Local node is boundary node but "
19221 "information sent is\n"
19222 <<
"for non-boundary node\n";
19224 OOMPH_CURRENT_FUNCTION,
19225 OOMPH_EXCEPTION_LOCATION);
19230 unsigned n_entry = unsigned(receive_data[count]);
19239 ->index_of_first_value_assigned_by_face_element_pt() ==
19244 new std::map<unsigned, unsigned>;
19249 std::map<unsigned, unsigned>* map_pt =
19254 for (
unsigned i = 0;
i < n_entry;
i++)
19257 unsigned first = unsigned(receive_data[count]);
19259 unsigned second = unsigned(receive_data[count]);
19263 (*map_pt)[first] = second;
19272 if (is_boundary_node != 0)
19274 std::ostringstream error_message;
19275 error_message <<
"Local node is not a boundary node but "
19277 <<
"sent is for boundary node.\n";
19279 OOMPH_CURRENT_FUNCTION,
19280 OOMPH_EXCEPTION_LOCATION);
19289 if (nval > nod_pt->
nvalue())
19309 bool do_halos =
true;
19310 bool do_external_halos =
false;
19317 bool do_halos =
false;
19318 bool do_external_halos =
true;
19349 unsigned& max_refinement_level_overall)
19353 const int n_proc = comm_pt->nproc();
19363 std::map<RefineableElement*, bool> root_el_done;
19369 std::map<RefineableElement*, unsigned> target_plus_one_for_root;
19374 unsigned max_refinement_level = 0;
19379 std::map<unsigned, Vector<GeneralisedElement*>> element_for_processor;
19386 std::map<unsigned, Vector<unsigned>> nelement_batch_for_processor;
19395 std::map<unsigned, Vector<unsigned>>
19396 base_element_for_element_batch_for_processor;
19407 Vector<int> old_domain_for_base_element_local(n_base_element, -1);
19408 Vector<int> new_domain_for_base_element_local(n_base_element, -1);
19414 unsigned count_non_halo_el = 0;
19426 bool are_there_structured_meshes =
false;
19428 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
19433 if (!(sub_mesh_pt != 0))
19441 are_there_structured_meshes =
true;
19444 for (
unsigned e = 0;
e < nele;
e++)
19451 unsigned target_domain =
19452 target_domain_for_local_non_halo_element[count_non_halo_el];
19455 count_non_halo_el++;
19461 if (ref_el_pt == 0)
19464 element_for_processor[target_domain].push_back(el_pt);
19468 nelement_batch_for_processor[target_domain].push_back(1);
19471 unsigned element_number_in_base_mesh =
19474 if (element_number_in_base_mesh == 0)
19476 throw OomphLibError(
"Base_mesh_element_number_plus_one[...]=0",
19477 OOMPH_CURRENT_FUNCTION,
19478 OOMPH_EXCEPTION_LOCATION);
19481 element_number_in_base_mesh -= 1;
19482 base_element_for_element_batch_for_processor[target_domain]
19483 .push_back(element_number_in_base_mesh);
19486 old_domain_for_base_element_local[element_number_in_base_mesh] =
19488 new_domain_for_base_element_local[element_number_in_base_mesh] =
19501 if (!root_el_done[root_el_pt])
19504 root_el_done[root_el_pt] =
true;
19507 unsigned element_number_in_base_mesh =
19510 if (element_number_in_base_mesh == 0)
19513 "Base_mesh_element_number_plus_one[...]=0",
19514 OOMPH_CURRENT_FUNCTION,
19515 OOMPH_EXCEPTION_LOCATION);
19518 element_number_in_base_mesh -= 1;
19521 old_domain_for_base_element_local[element_number_in_base_mesh] =
19523 new_domain_for_base_element_local[element_number_in_base_mesh] =
19530 target_plus_one_for_root[root_el_pt] = target_domain + 1;
19536 all_leaf_nodes_pt);
19539 unsigned n_leaf = all_leaf_nodes_pt.size();
19543 nelement_batch_for_processor[target_domain].push_back(n_leaf);
19546 base_element_for_element_batch_for_processor[target_domain]
19547 .push_back(element_number_in_base_mesh);
19550 for (
unsigned i_leaf = 0; i_leaf < n_leaf; i_leaf++)
19554 all_leaf_nodes_pt[i_leaf]->object_pt();
19555 element_for_processor[target_domain].push_back(leaf_el_pt);
19558 unsigned level = all_leaf_nodes_pt[i_leaf]->level();
19559 if (level > max_refinement_level)
19561 max_refinement_level = level;
19573 if ((target_plus_one_for_root[root_el_pt] - 1) != target_domain)
19575 std::ostringstream error_message;
19577 <<
"All elements associated with same root must have "
19578 <<
"same target. during load balancing\n";
19580 OOMPH_CURRENT_FUNCTION,
19581 OOMPH_EXCEPTION_LOCATION);
19593 if (target_domain_for_local_non_halo_element.size() != count_non_halo_el)
19595 std::ostringstream error_message;
19597 <<
"Have processed " << count_non_halo_el <<
" of "
19598 << target_domain_for_local_non_halo_element.size()
19599 <<
" target domains for local non-halo elelemts. \n "
19600 <<
"Very Odd -- we do (now) strip out the information for elements\n"
19601 <<
"that are removed in actions_before_distribute()...\n";
19603 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
19613 max_refinement_level_overall = 0;
19617 if (are_there_structured_meshes)
19619 MPI_Allreduce(&max_refinement_level,
19620 &max_refinement_level_overall,
19624 comm_pt->mpi_comm());
19629 Vector<int> tmp_old_domain_for_base_element(n_base_element);
19633 if (are_there_structured_meshes)
19635 MPI_Allreduce(&old_domain_for_base_element_local[0],
19636 &tmp_old_domain_for_base_element[0],
19640 comm_pt->mpi_comm());
19643 Vector<int> tmp_new_domain_for_base_element(n_base_element);
19646 if (are_there_structured_meshes)
19648 MPI_Allreduce(&new_domain_for_base_element_local[0],
19649 &tmp_new_domain_for_base_element[0],
19653 comm_pt->mpi_comm());
19657 old_domain_for_base_element.resize(n_base_element);
19658 new_domain_for_base_element.resize(n_base_element);
19659 for (
unsigned j = 0; j < n_base_element; j++)
19662 if (tmp_old_domain_for_base_element[j] == -1)
19664 std::ostringstream error_message;
19665 error_message <<
"Old domain for base element " << j <<
": "
19667 <<
"or its incarnation as refineable el: "
19670 <<
" which is of type "
19673 <<
"appear to have been assigned by any processor\n";
19675 OOMPH_CURRENT_FUNCTION,
19676 OOMPH_EXCEPTION_LOCATION);
19679 old_domain_for_base_element[j] = tmp_old_domain_for_base_element[j];
19681 if (tmp_new_domain_for_base_element[j] == -1)
19683 std::ostringstream error_message;
19684 error_message <<
"New domain for base element " << j
19685 <<
"which is of type "
19688 <<
"appear to have been assigned by any processor\n";
19690 OOMPH_CURRENT_FUNCTION,
19691 OOMPH_EXCEPTION_LOCATION);
19694 new_domain_for_base_element[j] = tmp_new_domain_for_base_element[j];
19708 for (
int rank = 0; rank < n_proc; rank++)
19711 send_displacement[rank] = send_data.size();
19716 unsigned total_nel = element_for_processor[rank].size();
19720 unsigned el_count = 0;
19723 unsigned nbatch = nelement_batch_for_processor[rank].size();
19726 send_data.push_back(
double(nbatch));
19729 for (
unsigned b = 0; b < nbatch; b++)
19732 unsigned nel = nelement_batch_for_processor[rank][b];
19736 unsigned base_el_no =
19737 base_element_for_element_batch_for_processor[rank][b];
19741 send_data.push_back(
double(nel));
19742 send_data.push_back(
double(base_el_no));
19745 for (
unsigned e = 0;
e < nel;
e++)
19755 unsigned nnod = fe_pt->
nnode();
19756 for (
unsigned j = 0; j < nnod; j++)
19762 unsigned n_value = nod_pt->
nvalue();
19765 unsigned n_dim = nod_pt->
ndim();
19769 for (
unsigned t = 0;
t < nt;
t++)
19771 nod_pt->
value(
t, values);
19772 for (
unsigned i = 0;
i < n_value;
i++)
19777 for (
unsigned i = 0;
i < n_dim;
i++)
19779 nod_pt->
x(
t,
i) = position[
i];
19785 if (!node_done[rank][nod_pt])
19788 node_done[rank][nod_pt] =
true;
19793 send_data.push_back(
double(n_value));
19804 send_data.push_back(
double(0));
19812 send_data.push_back(
double(1));
19816 std::map<unsigned, unsigned>* map_pt =
19822 send_data.push_back(
double(0));
19828 send_data.push_back(
double(map_pt->size()));
19831 for (std::map<unsigned, unsigned>::iterator p =
19833 p != map_pt->end();
19836 send_data.push_back(
double((*p).first));
19837 send_data.push_back(
double((*p).second));
19860 if (total_nel != el_count)
19862 std::ostringstream error_message;
19864 <<
"total_nel: " << total_nel <<
" "
19865 <<
" doesn't match total number of elements sent in batch: "
19866 << el_count <<
"\n";
19868 OOMPH_CURRENT_FUNCTION,
19869 OOMPH_EXCEPTION_LOCATION);
19874 send_n[rank] = send_data.size() - send_displacement[rank];
19901 const unsigned& max_refinement_level_overall,
19902 std::map<
unsigned,
Vector<unsigned>>& flat_packed_refinement_info_for_root)
19905 std::map<RefineableElement*, bool> root_el_done;
19916 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
19921 if (!(sub_mesh_pt != 0))
19924 for (
unsigned e = 0;
e < nele_submesh;
e++)
19935 if (ref_el_pt == 0)
19943 throw OomphLibError(
"Base_mesh_element_number_plus_one[...]=0",
19944 OOMPH_CURRENT_FUNCTION,
19945 OOMPH_EXCEPTION_LOCATION);
19949 flat_packed_refinement_info_for_root[
e].push_back(0);
19958 if (!root_el_done[root_el_pt])
19961 unsigned root_element_number =
19965 if (root_element_number == 0)
19968 "Base_mesh_element_number_plus_one[...]=0",
19969 OOMPH_CURRENT_FUNCTION,
19970 OOMPH_EXCEPTION_LOCATION);
19973 root_element_number -= 1;
19978 all_tree_nodes_pt);
19981 unsigned n_tree_nodes = all_tree_nodes_pt.size();
19982 flat_packed_refinement_info_for_root[root_element_number]
19983 .push_back(n_tree_nodes);
19986 for (
unsigned current_level = 0;
19987 current_level < max_refinement_level_overall;
19991 for (
unsigned e = 0;
e < n_tree_nodes;
e++)
19994 unsigned level = all_tree_nodes_pt[
e]->level();
19998 if ((level == current_level) ||
19999 ((level < current_level) &&
20000 (all_tree_nodes_pt[
e]->is_leaf())))
20002 flat_packed_refinement_info_for_root[root_element_number]
20007 if ((level == current_level) &&
20008 (!all_tree_nodes_pt[
e]->is_leaf()))
20010 flat_packed_refinement_info_for_root
20011 [root_element_number]
20018 flat_packed_refinement_info_for_root
20019 [root_element_number]
20027 flat_packed_refinement_info_for_root[root_element_number]
20033 root_el_done[root_el_pt] =
true;
20055 const unsigned& max_level_overall)
20059 unsigned max_mesh = std::max(n_sub_mesh,
unsigned(1));
20060 for (
unsigned i_mesh = 0; i_mesh < max_mesh; i_mesh++)
20063 Mesh* my_mesh_pt = 0;
20064 if (n_sub_mesh == 0)
20070 my_mesh_pt =
mesh_pt(i_mesh);
20075 unsigned n_el_on_this_proc = my_mesh_pt->
nelement();
20088 for (
unsigned level = 0; level < max_level_overall; level++)
20092 for (
unsigned e = 0;
e < n_el_on_this_proc;
e++)
20100 if (root_el_no == 0)
20102 throw OomphLibError(
"Base_mesh_element_number_plus_one[...]=0",
20103 OOMPH_CURRENT_FUNCTION,
20104 OOMPH_EXCEPTION_LOCATION);
20111 unsigned n_refinements =
20112 refinement_info_for_root_elements[root_el_no].size();
20115 if (level < n_refinements)
20119 refinement_info_for_root_elements[root_el_no][level].size();
20120 for (
unsigned ee = 0; ee < n_el; ee++)
20124 if (refinement_info_for_root_elements[root_el_no][level][ee] == 2)
20126 to_be_refined_on_this_proc[level].push_back(
20127 el_count_on_this_proc[level]);
20128 el_count_on_this_proc[level]++;
20132 else if (refinement_info_for_root_elements[root_el_no][level]
20135 el_count_on_this_proc[level]++;
20146 if (ref_mesh_pt != 0)
20153 if (n_sub_mesh != 0)
20173 unsigned max_mesh = std::max(n_sub_mesh,
unsigned(1));
20174 for (
unsigned i_mesh = 0; i_mesh < max_mesh; i_mesh++)
20177 Mesh* my_mesh_pt = 0;
20178 if (n_sub_mesh == 0)
20184 my_mesh_pt =
mesh_pt(i_mesh);
20190 if (!(sub_mesh_pt != 0))
20202 for (
int rank = 0; rank < n_proc; rank++)
20205 send_displacement[rank] = send_data.size();
20209 if (rank != my_rank)
20214 unsigned nel = root_haloed_elements_pt.size();
20217 for (
unsigned e = 0;
e < nel;
e++)
20225 send_n[rank] = send_data.size() - send_displacement[rank];
20232 MPI_Alltoall(&send_n[0],
20243 int receive_data_count = 0;
20244 for (
int rank = 0; rank < n_proc; ++rank)
20247 receive_displacement[rank] = receive_data_count;
20248 receive_data_count += receive_n[rank];
20253 if (receive_data_count == 0)
20255 ++receive_data_count;
20261 if (send_data.size() == 0)
20263 send_data.resize(1);
20267 MPI_Alltoallv(&send_data[0],
20269 &send_displacement[0],
20273 &receive_displacement[0],
20279 for (
int send_rank = 0; send_rank < n_proc; send_rank++)
20283 if ((send_rank != my_rank) && (receive_n[send_rank] != 0))
20286 unsigned count = receive_displacement[send_rank];
20291 unsigned nel = root_halo_elements_pt.size();
20294 for (
unsigned e = 0;
e < nel;
e++)
20297 unsigned el_number_plus_one = receive_data[count++];
Function-type-object to perform absolute comparison of objects. Apparently this inlines better.
A class that is used to define the functions used to assemble the elemental contributions to the resi...
virtual unsigned ndof(GeneralisedElement *const &elem_pt)
Return the number of degrees of freedom in the element elem_pt.
virtual void synchronise()
Function that is used to perform any synchronisation required during the solution.
virtual int bifurcation_type() const
Return an unsigned integer to indicate whether the handler is a bifurcation tracking handler....
virtual void get_hessian_vector_products(GeneralisedElement *const &elem_pt, Vector< double > const &Y, DenseMatrix< double > const &C, DenseMatrix< double > &product)
Calculate the product of the Hessian (derivative of Jacobian with respect to all variables) an eigenv...
virtual double * bifurcation_parameter_pt() const
Return a pointer to the bifurcation parameter in bifurcation tracking problems.
virtual void get_all_vectors_and_matrices(GeneralisedElement *const &elem_pt, Vector< Vector< double >> &vec, Vector< DenseMatrix< double >> &matrix)
Calculate all desired vectors and matrices provided by the element elem_pt.
virtual void get_eigenfunction(Vector< DoubleVector > &eigenfunction)
Return the eigenfunction(s) associated with the bifurcation that has been detected in bifurcation tra...
virtual void get_residuals(GeneralisedElement *const &elem_pt, Vector< double > &residuals)
Return the contribution to the residuals of the element elem_pt.
virtual unsigned long eqn_number(GeneralisedElement *const &elem_pt, const unsigned &ieqn_local)
Return the global equation number of the local unknown ieqn_local in elem_pt.
virtual void get_jacobian(GeneralisedElement *const &elem_pt, Vector< double > &residuals, DenseMatrix< double > &jacobian)
Calculate the elemental Jacobian matrix "d equation / d variable" for elem_pt.
A custom linear solver class that is used to solve a block-factorised version of the Hopf bifurcation...
A class that contains the information required by Nodes that are located on Mesh boundaries....
std::map< unsigned, unsigned > *& index_of_first_value_assigned_by_face_element_pt()
Return pointer to the map giving the index of the first face element value.
//////////////////////////////////////////////////////////////// ////////////////////////////////////...
void build_without_copy(T *value, int *row_index, int *column_start, const unsigned long &nnz, const unsigned long &n, const unsigned long &m)
Function to build matrix from pointers to arrays which hold the column starts, row indices and non-ze...
A class for compressed row matrices. This is a distributable object.
void redistribute(const LinearAlgebraDistribution *const &dist_pt)
The contents of the matrix are redistributed to match the new distribution. In a non-MPI build this m...
void build_without_copy(const unsigned &ncol, const unsigned &nnz, double *value, int *column_index, int *row_start)
keeps the existing distribution and just matrix that is stored without copying the matrix data
unsigned long nrow() const
Return the number of rows of the matrix.
void build(const LinearAlgebraDistribution *distribution_pt, const unsigned &ncol, const Vector< double > &value, const Vector< int > &column_index, const Vector< int > &row_start)
build method: vector of values, vector of column indices, vector of row starts and number of rows and...
void set_consistent_pinned_values(Data *const &data_pt)
Set consistent values of the derivatives and current value when the data is pinned....
A Base class for DGElements.
void disable_mass_matrix_reuse()
Function that disables the reuse of the mass matrix.
void enable_mass_matrix_reuse()
Function that allows the reuse of the mass matrix.
virtual void get_inverse_mass_matrix_times_residuals(Vector< double > &minv_res)
Function that returns the current value of the residuals multiplied by the inverse mass matrix (virtu...
A class that represents a collection of data; each Data object may contain many different individual ...
long & eqn_number(const unsigned &i)
Return the equation number of the i-th stored variable.
virtual void add_eqn_numbers_to_vector(Vector< long > &vector_of_eqn_numbers)
Add all equation numbers to the vector in the internal storage order.
double * value_pt(const unsigned &i) const
Return the pointer to the i-the stored value. Typically this is required when direct access to the st...
void copy(Data *orig_data_pt)
Copy Data values from specified Data object.
void set_value(const unsigned &i, const double &value_)
Set the i-th stored data value to specified value. The only reason that we require an explicit set fu...
unsigned nvalue() const
Return number of values stored in data object (incl pinned ones).
double value(const unsigned &i) const
Return i-th stored value. This function is not virtual so that it can be inlined. This means that if ...
unsigned ntstorage() const
Return total number of doubles stored per value to record time history of each value (one for steady ...
virtual void read_eqn_numbers_from_vector(const Vector< long > &vector_of_eqn_numbers, unsigned &index)
Read all equation numbers from the vector starting from index. On return the index will be set to the...
bool is_pinned(const unsigned &i) const
Test whether the i-th variable is pinned (1: true; 0: false).
Class of matrices containing doubles, and stored as a DenseMatrix<double>, but with solving functiona...
void initialise(const T &val)
Initialize all values in the matrix to val.
void resize(const unsigned long &n)
Resize to a square nxn matrix; any values already present will be transfered.
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
unsigned nrow() const
access function to the number of global rows.
bool distribution_built() const
if the communicator_pt is null then the distribution is not setup then false is returned,...
unsigned nrow_local() const
access function for the num of local rows on this processor.
Information for documentation of results: Directory and file number to enable output in the form RESL...
bool is_doc_enabled() const
Are we documenting?
void disable_doc()
Disable documentation.
std::string & label()
String used (e.g.) for labeling output files.
std::string directory() const
Output directory.
unsigned & number()
Number used (e.g.) for labeling output files.
A class that stores the halo/haloed entries required when using a DoubleVectorWithHaloEntries....
void setup_halo_dofs(const std::map< unsigned, double * > &halo_data_pt, Vector< double * > &halo_dof_pt)
Function that sets up a vector of pointers to halo data, index using the scheme in Local_index.
===================================================================== An extension of DoubleVector th...
void build_halo_scheme(DoubleVectorHaloScheme *const &halo_scheme_pt)
Construct the halo scheme and storage for the halo data.
void sum_all_halo_and_haloed_values()
Sum all the data, store in the master (haloed) data and then synchronise.
double & global_value(const unsigned &i)
Direct access to global entry.
A vector in the mathematical sense, initially developed for linear algebra type applications....
void initialise(const double &v)
initialise the whole vector with value v
void set_external_values(const LinearAlgebraDistribution *const &dist_pt, double *external_values, bool delete_external_values)
Allows are external data to be used by this vector. WARNING: The size of the external data must corre...
double max() const
returns the maximum coefficient
void build(const DoubleVector &old_vector)
Just copys the argument DoubleVector.
double * values_pt()
access function to the underlying values
void redistribute(const LinearAlgebraDistribution *const &dist_pt)
The contents of the vector are redistributed to match the new distribution. In a non-MPI rebuild this...
double dot(const DoubleVector &vec) const
compute the dot product of this vector with the vector vec.
void clear()
wipes the DoubleVector
A class that is used to define the functions used to assemble the elemental contributions to the mass...
virtual void solve_eigenproblem(Problem *const &problem_pt, const int &n_eval, Vector< std::complex< double >> &eigenvalue, Vector< DoubleVector > &eigenvector_real, Vector< DoubleVector > &eigenvector_imag, const bool &do_adjoint_problem=false)
Solve the real eigenproblem that is assembled by elements in a mesh in a Problem object....
Base class for spatial error estimators.
void get_element_errors(Mesh *&mesh_pt, Vector< double > &elemental_error)
Compute the elemental error-measures for a given mesh and store them in a vector.
A class that is used to define the functions used to assemble and invert the mass matrix when taking ...
A Base class for explicit timesteppers.
virtual void timestep(ExplicitTimeSteppableObject *const &object_pt, const double &dt)=0
Pure virtual function that is used to advance time in the object.
FaceElements are elements that coincide with the faces of higher-dimensional "bulk" elements....
int & face_index()
Index of the face (a number that uniquely identifies the face in the element)
FiniteElement *& bulk_element_pt()
Pointer to higher-dimensional "bulk" element.
A general Finite Element class.
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
virtual void output(std::ostream &outfile)
Output the element data — typically the values at the nodes in a format suitable for post-processing.
unsigned nnode() const
Return the number of nodes.
A Generalised Element class.
bool is_halo() const
Is this element a halo?
void read_internal_eqn_numbers_from_vector(const Vector< long > &vector_of_eqn_numbers, unsigned &index)
Read all equation numbers associated with internal data from the vector starting from index....
unsigned ndof() const
Return the number of equations/dofs in the element.
unsigned long eqn_number(const unsigned &ieqn_local) const
Return the global equation number corresponding to the ieqn_local-th local equation number.
void add_internal_data_values_to_vector(Vector< double > &vector_of_values)
Add all internal data and time history values to the vector in the internal storage order.
Data *& internal_data_pt(const unsigned &i)
Return a pointer to i-th internal data object.
unsigned ninternal_data() const
Return the number of internal data objects.
void add_internal_eqn_numbers_to_vector(Vector< long > &vector_of_eqn_numbers)
Add all equation numbers associated with internal data to the vector in the internal storage order.
virtual void complete_setup_of_dependencies()
Complete the setup of any additional dependencies that the element may have. Empty virtual function t...
void read_internal_data_values_from_vector(const Vector< double > &vector_of_values, unsigned &index)
Read all internal data and time history values from the vector starting from index....
Class that contains data for hanging nodes.
double const & master_weight(const unsigned &i) const
Return weight for dofs on i-th master node.
Node *const & master_node_pt(const unsigned &i) const
Return a pointer to the i-th master node.
unsigned nmaster() const
Return the number of master nodes.
void set_master_node_pt(const unsigned &i, Node *const &master_node_pt, const double &weight)
Set the pointer to the i-th master node and its weight.
A class that is used to assemble the augmented system that defines a Hopf bifurcation....
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
Class for the LAPACK QZ eigensolver.
Describes the distribution of a distributable linear algebra type object. Typically this is a contain...
bool distributed() const
access function to the distributed - indicates whether the distribution is serial or distributed
unsigned first_row() const
access function for the first row on this processor. If not distributed then this is just zero.
OomphCommunicator * communicator_pt() const
const access to the communicator pointer
void build(const OomphCommunicator *const comm_pt, const unsigned &first_row, const unsigned &nrow_local, const unsigned &nrow=0)
Sets the distribution. Takes first_row, nrow_local and nrow as arguments. If nrow is not provided or ...
unsigned nrow() const
access function to the number of global rows.
unsigned nrow_local() const
access function for the num of local rows on this processor. If no MPI then Nrow is returned.
unsigned rank_of_global_row(const unsigned i) const
return the processor rank of the global row number i
virtual void solve(Problem *const &problem_pt, DoubleVector &result)=0
Solver: Takes pointer to problem and returns the results vector which contains the solution of the li...
virtual void enable_resolve()
Enable resolve (i.e. store matrix and/or LU decomposition, say) Virtual so it can be overloaded to pe...
virtual void enable_computation_of_gradient()
function to enable the computation of the gradient required for the globally convergent Newton method
virtual void resolve(const DoubleVector &rhs, DoubleVector &result)
Resolve the system defined by the last assembled jacobian and the rhs vector. Solution is returned in...
void get_gradient(DoubleVector &gradient)
function to access the gradient, provided it has been computed
void reset_gradient()
function to reset the size of the gradient before each Newton solve
virtual void disable_resolve()
Disable resolve (i.e. store matrix and/or LU decomposition, say) This function simply resets an inter...
bool is_resolve_enabled() const
Boolean flag indicating if resolves are enabled.
static bool mpi_has_been_initialised()
return true if MPI has been initialised
static OomphCommunicator * communicator_pt()
access to global communicator. This is the oomph-lib equivalent of MPI_COMM_WORLD
void set_external_halo_node_pt(const unsigned &p, const Vector< Node * > &external_halo_node_pt)
Set vector of external halo node in this Mesh whose non-halo external counterpart is held on processo...
Node * halo_node_pt(const unsigned &p, const unsigned &j)
Access fct to the j-th halo node in this Mesh whose non-halo counterpart is held on processor p.
bool does_pointer_correspond_to_mesh_data(double *const ¶meter_pt)
Does the double pointer correspond to any mesh data.
void remove_boundary_node(const unsigned &b, Node *const &node_pt)
Remove a node from the boundary b.
bool is_mesh_distributed() const
Boolean to indicate if Mesh has been distributed.
unsigned nexternal_haloed_element()
Total number of external haloed elements in this Mesh.
Node * haloed_node_pt(const unsigned &p, const unsigned &j)
Access fct to the j-th haloed node in this Mesh whose halo counterpart is held on processor p.
unsigned nexternal_halo_node()
Total number of external halo nodes in this Mesh.
void flush_element_and_node_storage()
Flush storage for elements and nodes by emptying the vectors that store the pointers to them....
Node *& external_halo_node_pt(const unsigned &p, const unsigned &j)
Access fct to the j-th external halo node in this Mesh whose non-halo external counterpart is held on...
FiniteElement * finite_element_pt(const unsigned &e) const
Upcast (downcast?) to FiniteElement (needed to access FiniteElement member functions).
void check_halo_schemes(DocInfo &doc_info, double &max_permitted_error_for_halo_check)
Check halo and shared schemes on the mesh.
virtual void set_mesh_level_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Function that can be used to set any additional timestepper data stored at the Mesh (as opposed to no...
Vector< GeneralisedElement * > haloed_element_pt(const unsigned &p)
Return vector of haloed elements in this Mesh whose haloing counterpart is held on processor p.
void describe_local_dofs(std::ostream &out, const std::string ¤t_string) const
Function to describe the local dofs of the elements. The ostream specifies the output stream to which...
GeneralisedElement *& external_halo_element_pt(const unsigned &p, const unsigned &e)
Access fct to the e-th external halo element in this Mesh whose non-halo counterpart is held on proce...
void set_nodal_and_elemental_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Set the timestepper associated with all nodal and elemental data stored in the mesh.
void set_external_haloed_node_pt(const unsigned &p, const Vector< Node * > &external_haloed_node_pt)
Set vector of external haloed node in this Mesh whose halo external counterpart is held on processor ...
Node *& external_haloed_node_pt(const unsigned &p, const unsigned &j)
Access fct to the j-th external haloed node in this Mesh whose halo external counterpart is held on p...
void shift_time_values()
Shift time-dependent data along for next timestep: Deal with nodal Data/positions and the element's i...
void prune_halo_elements_and_nodes(Vector< GeneralisedElement * > &deleted_element_pt, const bool &report_stats=false)
(Irreversibly) prune halo(ed) elements and nodes, usually after another round of refinement,...
void calculate_predictions()
Calculate predictions for all Data and positions associated with the mesh, usually used in adaptive t...
void describe_dofs(std::ostream &out, const std::string ¤t_string) const
Function to describe the dofs of the Mesh. The ostream specifies the output stream to which the descr...
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
unsigned long nnode() const
Return number of nodes in the mesh.
void delete_all_external_storage()
Wipe the storage for all externally-based elements.
unsigned nnon_halo_element()
Total number of non-halo elements in this mesh (Costly call computes result on the fly)
void get_all_halo_data(std::map< unsigned, double * > &map_of_halo_data)
Get all the halo data stored in the mesh and add pointers to the data to the map, indexed by global e...
unsigned nhalo_node()
Total number of halo nodes in this Mesh.
void set_communicator_pt(OomphCommunicator *comm_pt)
Function to set communicator (mesh is assumed to be distributed if the communicator pointer is non-nu...
void output(std::ostream &outfile)
Output for all elements.
void assign_initial_values_impulsive()
Assign initial values for an impulsive start.
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
void assign_local_eqn_numbers(const bool &store_local_dof_pt)
Assign the local equation numbers in all elements If the boolean argument is true then also store poi...
virtual void read(std::ifstream &restart_file)
Read solution from restart file.
void set_consistent_pinned_values_for_continuation(ContinuationStorageScheme *const &continuation_stepper_pt)
Set consistent values for pinned data in continuation.
unsigned nhaloed_node()
Total number of haloed nodes in this Mesh.
unsigned nexternal_haloed_node()
Total number of external haloed nodes in this Mesh.
unsigned long assign_global_eqn_numbers(Vector< double * > &Dof_pt)
Assign the global equation numbers in the Data stored at the nodes and also internal element Data....
virtual void distribute(OomphCommunicator *comm_pt, const Vector< unsigned > &element_domain, Vector< GeneralisedElement * > &deleted_element_pt, DocInfo &doc_info, const bool &report_stats, const bool &overrule_keep_as_halo_element_status)
Distribute the problem and doc; make this virtual to allow overloading for particular meshes where fu...
void null_external_halo_node(const unsigned &p, Node *nod_pt)
Null out specified external halo node (used when deleting duplicates)
Vector< GeneralisedElement * > root_haloed_element_pt(const unsigned &p)
Vector of pointers to root haloed elements in this Mesh whose non-halo counterpart is held on process...
GeneralisedElement *& external_haloed_element_pt(const unsigned &p, const unsigned &e)
Access fct to the e-th external haloed element in this Mesh whose non-halo counterpart is held on pro...
unsigned long nelement() const
Return number of elements in the mesh.
Vector< GeneralisedElement * > root_halo_element_pt(const unsigned &p)
Vector of pointers to root halo elements in this Mesh whose non-halo counterpart is held on processor...
void merge_meshes(const Vector< Mesh * > &sub_mesh_pt)
Merge meshes. Note: This simply merges the meshes' elements and nodes (ignoring duplicates; no bounda...
unsigned nexternal_halo_element()
Total number of external halo elements in this Mesh.
virtual void dump(std::ofstream &dump_file, const bool &use_old_ordering=true) const
Dump the data in the mesh into a file for restart.
Vector< GeneralisedElement * > halo_element_pt(const unsigned &p)
Return vector of halo elements in this Mesh whose non-halo counterpart is held on processor p.
A class to handle errors in the Newton solver.
bool linear_solver_error()
Access function to the error in the linear solver.
unsigned iterations()
Access function to Max. # of iterations performed when the Newton solver died.
double maxres()
Access function to Max. residual when Newton solver died.
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
double & x(const unsigned &i)
Return the i-th nodal coordinate.
double & x_gen(const unsigned &k, const unsigned &i)
Reference to the generalised position x(k,i). ‘Type’: k; Coordinate direction: i.
HangInfo *const & hanging_pt() const
Return pointer to hanging node data (this refers to the geometric hanging node status) (const version...
void copy(Node *orig_node_pt)
Copy all nodal data from specified Node object.
void add_values_to_vector(Vector< double > &vector_of_values)
Add all data and time history values to the vector. Overloaded to add the position information as wel...
virtual void get_boundaries_pt(std::set< unsigned > *&boundaries_pt)
Return a pointer to set of mesh boundaries that this node occupies; this will be overloaded by Bounda...
void position(Vector< double > &pos) const
Compute Vector of nodal positions either directly or via hanging node representation.
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
void read_values_from_vector(const Vector< double > &vector_of_values, unsigned &index)
Read all data and time history values from the vector starting from index. On return the index will b...
void resize(const unsigned &n_value)
Resize the number of equations.
unsigned nposition_type() const
Number of coordinate types needed in the mapping between local and global coordinates.
bool is_hanging() const
Test whether the node is geometrically hanging.
double value(const unsigned &i) const
Return i-th value (dofs or pinned) at this node either directly or via hanging node representation....
An oomph-lib wrapper to the MPI_Comm communicator object. Just contains an MPI_Comm object (which is ...
std::ostream *& stream_pt()
Access function for the stream pointer.
An OomphLibError object which should be thrown when an run-time error is encountered....
An OomphLibWarning object which should be created as a temporary object to issue a warning....
A class that is used to assemble the residuals in parallel by overloading the get_all_vectors_and_mat...
A class that is used to define the functions used when assembling the derivatives of the residuals wi...
////////////////////////////////////////////////////////////////// //////////////////////////////////...
virtual void actions_after_implicit_timestep()
Actions that should be performed after each implicit time step. This is needed when one wants to solv...
bool Always_take_one_newton_step
Boolean to indicate whether a Newton step should be taken even if the initial residuals are below the...
bool Jacobian_reuse_is_enabled
Is re-use of Jacobian in Newton iteration enabled? Default: false.
double *& dof_pt(const unsigned &i)
Pointer to i-th dof in the problem.
virtual void actions_after_newton_solve()
Any actions that are to be performed after a complete Newton solve, e.g. post processing....
void parallel_sparse_assemble(const LinearAlgebraDistribution *const &dist_pt, Vector< int * > &column_or_row_index, Vector< int * > &row_or_column_start, Vector< double * > &value, Vector< unsigned > &nnz, Vector< double * > &residuals)
Helper method to assemble CRDoubleMatrices from distributed on multiple processors.
void describe_dofs(std::ostream &out= *(oomph_info.stream_pt())) const
Function to describe the dofs in terms of the global equation number, i.e. what type of value (nodal ...
virtual void sparse_assemble_row_or_column_compressed(Vector< int * > &column_or_row_index, Vector< int * > &row_or_column_start, Vector< double * > &value, Vector< unsigned > &nnz, Vector< double * > &residual, bool compressed_row_flag)
Protected helper function that is used to assemble the Jacobian matrix in the case when the storage i...
bool Store_local_dof_pt_in_elements
Boolean to indicate whether local dof pointers should be stored in the elements.
virtual void actions_before_newton_step()
Any actions that are to be performed before each individual Newton step. Most likely to be used for d...
void remove_duplicate_data(Mesh *const &mesh_pt, bool &actually_removed_some_data)
Private helper function to remove repeated data in external haloed elements in specified mesh....
bool Bifurcation_detection
Boolean to control bifurcation detection via determinant of Jacobian.
void adapt()
Adapt problem: Perform mesh adaptation for (all) refineable (sub)mesh(es), based on their own error e...
virtual void actions_before_newton_solve()
Any actions that are to be performed before a complete Newton solve (e.g. adjust boundary conditions)...
Vector< unsigned > First_el_for_assembly
First element to be assembled by given processor for non-distributed problem (only kept up to date wh...
unsigned long assign_eqn_numbers(const bool &assign_local_eqn_numbers=true)
Assign all equation numbers for problem: Deals with global data (= data that isn't attached to any el...
void refine_uniformly_aux(const Vector< unsigned > &nrefine_for_mesh, DocInfo &doc_info, const bool &prune)
Helper function to do compund refinement of (all) refineable (sub)mesh(es) uniformly as many times as...
void build_global_mesh()
Build the global mesh by combining the all the submeshes. Note: The nodes boundary information refers...
unsigned unrefine_uniformly()
Refine (all) refineable (sub)mesh(es) uniformly and rebuild problem. Return 0 for success,...
void assign_initial_values_impulsive()
Initialise data and nodal positions to simulate impulsive start from initial configuration/solution.
double & dof_current(const unsigned &i)
Access function to the current value of the i-th (local) dof at the start of a continuation step.
double Theta_squared
Value of the scaling parameter required so that the parameter occupies the desired proportion of the ...
LinearAlgebraDistribution *const & dof_distribution_pt() const
Return the pointer to the dof distribution (read-only)
virtual void get_eigenproblem_matrices(CRDoubleMatrix &mass_matrix, CRDoubleMatrix &main_matrix, const double &shift=0.0)
Get the matrices required by a eigensolver. If the shift parameter is non-zero the second matrix will...
Vector< double > Dof_derivative
Storage for the derivative of the problem variables wrt arc-length.
virtual void sparse_assemble_row_or_column_compressed_with_lists(Vector< int * > &column_or_row_index, Vector< int * > &row_or_column_start, Vector< double * > &value, Vector< unsigned > &nnz, Vector< double * > &residual, bool compressed_row_flag)
Private helper function that is used to assemble the Jacobian matrix in the case when the storage is ...
virtual void sparse_assemble_row_or_column_compressed_with_two_arrays(Vector< int * > &column_or_row_index, Vector< int * > &row_or_column_start, Vector< double * > &value, Vector< unsigned > &nnz, Vector< double * > &residual, bool compressed_row_flag)
Private helper function that is used to assemble the Jacobian matrix in the case when the storage is ...
friend class BlockHopfLinearSolver
void synchronise_dofs(const bool &do_halos, const bool &do_external_halos)
Synchronise the degrees of freedom by overwriting the haloed values with their non-halo counterparts ...
virtual void actions_before_distribute()
Actions to be performed before a (mesh) distribution.
Distributed_problem_matrix_distribution Dist_problem_matrix_distribution
The distributed matrix distribution method 1 - Automatic - the Problem distribution is employed,...
DoubleVectorHaloScheme * Halo_scheme_pt
Pointer to the halo scheme for any global vectors that have the Dof_distribution.
virtual void actions_after_change_in_global_parameter(double *const ¶meter_pt)
Actions that are to be performed when the global parameter addressed by parameter_pt has been changed...
void p_refine_selected_elements(const Vector< unsigned > &elements_to_be_refined)
p-refine (one and only!) mesh by refining the elements identified by their numbers relative to the pr...
void setup_dof_halo_scheme()
Function that is used to setup the halo scheme.
unsigned long ndof() const
Return the number of dofs.
void p_unrefine_uniformly(DocInfo &doc_info)
p-unrefine (all) p-refineable (sub)mesh(es) uniformly and rebuild problem.
virtual void build_mesh()
Function to build the Problem's base mesh; this must be supplied by the user if they wish to use the ...
static bool Suppress_warning_about_actions_before_read_unstructured_meshes
Flag to allow suppression of warning messages re reading in unstructured meshes during restart.
void solve_adjoint_eigenproblem(const unsigned &n_eval, Vector< std::complex< double >> &eigenvalue, Vector< DoubleVector > &eigenvector_real, Vector< DoubleVector > &eigenvector_imag, const bool &steady=true)
Solve an adjoint eigenvalue problem using the same procedure as solve_eigenproblem....
bool Use_default_partition_in_load_balance
Flag to use "default partition" during load balance. Should only be set to true when run in validatio...
void bifurcation_adapt_helper(unsigned &n_refined, unsigned &n_unrefined, const unsigned &bifurcation_type, const bool &actually_adapt=true)
A function that is used to adapt a bifurcation-tracking problem, which requires separate interpolatio...
friend class AugmentedBlockFoldLinearSolver
Vector< double > Elemental_assembly_time
Storage for assembly times (used for load balancing)
bool Jacobian_has_been_computed
Has a Jacobian been computed (and can therefore be re-used if required)? Default: false.
bool Bypass_increase_in_dof_check_during_pruning
Boolean to bypass check of increase in dofs during pruning.
virtual void get_dvaluesdt(DoubleVector &f)
Get the time derivative of all values (using get_inverse_mass_matrix_times_residuals(....
void initialise_dt(const double &dt)
Set all timesteps to the same value, dt, and assign weights for all timesteppers in the problem.
void add_to_dofs(const double &lambda, const DoubleVector &increment_dofs)
Add lambda x incremenet_dofs[l] to the l-th dof.
double Timestep_reduction_factor_after_nonconvergence
What it says: If temporally adaptive Newton solver fails to to converge, reduce timestep by this fact...
Vector< double > Dof_current
Storage for the present values of the variables.
double Desired_proportion_of_arc_length
Proportion of the arc-length to taken by the parameter.
AssemblyHandler *& assembly_handler_pt()
Return a pointer to the assembly handler object.
virtual void actions_after_implicit_timestep_and_error_estimation()
Actions that should be performed after each implicit time step. This is needed if your actions_after_...
void disable_mass_matrix_reuse()
Turn off recyling of the mass matrix in explicit timestepping schemes.
EigenSolver * Default_eigen_solver_pt
Pointer to the default eigensolver.
unsigned Nnewton_iter_taken
Actual number of Newton iterations taken during the most recent iteration.
double * bifurcation_parameter_pt() const
Return pointer to the parameter that is used in the bifurcation detection. If we are not tracking a b...
void copy_haloed_eqn_numbers_helper(const bool &do_halos, const bool &do_external_halos)
A private helper function to copy the haloed equation numbers into the halo equation numbers,...
virtual void sparse_assemble_row_or_column_compressed_with_vectors_of_pairs(Vector< int * > &column_or_row_index, Vector< int * > &row_or_column_start, Vector< double * > &value, Vector< unsigned > &nnz, Vector< double * > &residual, bool compressed_row_flag)
Private helper function that is used to assemble the Jacobian matrix in the case when the storage is ...
void send_data_to_be_sent_during_load_balancing(Vector< int > &send_n, Vector< double > &send_data, Vector< int > &send_displacement)
Load balance helper routine: Send data to other processors during load balancing.
bool Time_adaptive_newton_crash_on_solve_fail
Bool to specify what to do if a Newton solve fails within a time adaptive solve. Default (false) is t...
Problem()
Constructor: Allocate space for one time stepper and set all pointers to NULL and set defaults for al...
bool is_dparameter_calculated_analytically(double *const ¶meter_pt)
Function to determine whether the parameter derivatives are calculated analytically.
void flush_sub_meshes()
Flush the problem's collection of sub-meshes. Must be followed by call to rebuild_global_mesh().
bool & use_predictor_values_as_initial_guess()
unsigned Sparse_assembly_method
Flag to determine which sparse assembly method to use By default we use assembly by vectors of pairs.
Time *& time_pt()
Return a pointer to the global time object.
void calculate_predictions()
Calculate predictions.
Vector< unsigned > Last_el_plus_one_for_assembly
Last element (plus one) to be assembled by given processor for non-distributed problem (only kept up ...
double * global_dof_pt(const unsigned &i)
Return a pointer to the dof, indexed by global equation number which may be haloed or stored locally....
virtual void actions_after_read_unstructured_meshes()
Actions that are to be performed before reading in restart data for problems involving unstructured b...
void copy(Problem *orig_problem_pt)
Copy Data values, nodal positions etc from specified problem. Note: This is not a copy constructor....
virtual void get_jacobian(DoubleVector &residuals, DenseDoubleMatrix &jacobian)
Return the fully-assembled Jacobian and residuals for the problem Interface for the case when the Jac...
void set_explicit_time_stepper_pt(ExplicitTimeStepper *const &explicit_time_stepper_pt)
Set the explicit timestepper for the problem. The function will automatically create or resize the Ti...
virtual void actions_after_distribute()
Actions to be performed after a (mesh) distribution.
virtual void actions_before_implicit_timestep()
Actions that should be performed before each implicit time step. This is needed when one wants to sol...
LinearSolver * Linear_solver_pt
Pointer to the linear solver for the problem.
bool Doc_time_in_distribute
Protected boolean flag to provide comprehensive timimings during problem distribution....
unsigned Max_newton_iterations
Maximum number of Newton iterations.
Vector< Vector< unsigned > > Sparse_assemble_with_arrays_previous_allocation
the number of elements in each row of a compressed matrix in the previous matrix assembly.
virtual void actions_after_parameter_increase(double *const ¶meter_pt)
Empty virtual function; provides hook to perform actions after the increase in the arclength paramete...
friend class PitchForkHandler
void calculate_continuation_derivatives(double *const ¶meter_pt)
A function to calculate the derivatives wrt the arc-length. This version of the function actually doe...
void store_current_dof_values()
Store the current values of the degrees of freedom.
bool Problem_has_been_distributed
Has the problem been distributed amongst multiple processors?
void synchronise_all_dofs()
Perform all required synchronisation in solvers.
bool Empty_actions_before_read_unstructured_meshes_has_been_called
Boolean to indicate that empty actions_before_read_unstructured_meshes() function has been called.
OomphCommunicator * communicator_pt()
access function to the oomph-lib communicator
bool Mass_matrix_has_been_computed
Has the mass matrix been computed (and can therefore be reused) Default: false.
unsigned nglobal_data() const
Return the number of global data values.
virtual void actions_before_adapt()
Actions that are to be performed before a mesh adaptation. These might include removing any additiona...
void newton_solve()
Use Newton method to solve the problem.
bool First_jacobian_sign_change
Boolean to indicate whether a sign change has occured in the Jacobian.
void refine_distributed_base_mesh(Vector< Vector< Vector< unsigned >>> &to_be_refined_on_each_root, const unsigned &max_level_overall)
Load balance helper routine: refine each new base (sub)mesh based upon the elements to be refined wit...
void calculate_continuation_derivatives_fd_helper(double *const ¶meter_pt)
A function that performs the guts of the continuation derivative calculation in arc-length continuati...
double Continuation_direction
The direction of the change in parameter that will ensure that a branch is followed in one direction ...
unsigned Parallel_sparse_assemble_previous_allocation
The amount of data allocated during the previous parallel sparse assemble. Used to optimise the next ...
void enable_mass_matrix_reuse()
Enable recycling of the mass matrix in explicit timestepping schemes. Useful for timestepping on fixe...
void steady_newton_solve(unsigned const &max_adapt=0)
Solve a steady problem using adaptive Newton's method, but in the context of an overall unstady probl...
bool Scale_arc_length
Boolean to control whether arc-length should be scaled.
double doubly_adaptive_unsteady_newton_solve_helper(const double &dt, const double &epsilon, const unsigned &max_adapt, const unsigned &suppress_resolve_after_spatial_adapt, const bool &first, const bool &shift=true)
Private helper function that actually performs the unsteady "doubly" adaptive Newton solve....
bool Empty_actions_after_read_unstructured_meshes_has_been_called
Boolean to indicate that empty actions_after_read_unstructured_meshes() function has been called.
virtual void get_residuals(DoubleVector &residuals)
Return the fully-assembled residuals Vector for the problem: Virtual so it can be overloaded in for m...
Vector< GeneralisedElement * > Base_mesh_element_pt
Vector to store the correspondence between a root element and its element number within the global me...
double & dof(const unsigned &i)
i-th dof in the problem
void get_fd_jacobian(DoubleVector &residuals, DenseMatrix< double > &jacobian)
Return the fully-assembled Jacobian and residuals, generated by finite differences.
virtual void sparse_assemble_row_or_column_compressed_with_two_vectors(Vector< int * > &column_or_row_index, Vector< int * > &row_or_column_start, Vector< double * > &value, Vector< unsigned > &nnz, Vector< double * > &residual, bool compressed_row_flag)
Private helper function that is used to assemble the Jacobian matrix in the case when the storage is ...
virtual Problem * make_copy()
Make and return a pointer to the copy of the problem. A virtual function that must be filled in by th...
double Maximum_dt
Maximum desired dt.
unsigned long set_timestepper_for_all_data(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data=false)
Set all problem data to have the same timestepper (timestepper_pt) Return the new number of dofs in t...
void activate_pitchfork_tracking(double *const ¶meter_pt, const DoubleVector &symmetry_vector, const bool &block_solve=true)
Turn on pitchfork tracking using the augmented system specified in the PitchForkHandler class....
virtual void dump(std::ofstream &dump_file) const
Dump refinement pattern of all refineable meshes and all generic Problem data to file for restart.
bool Use_finite_differences_for_continuation_derivatives
Boolean to specify which scheme to use to calculate the continuation derivatievs.
bool Arc_length_step_taken
Boolean to indicate whether an arc-length step has been taken.
void set_pinned_values_to_zero()
Set all pinned values to zero. Used to set boundary conditions to be homogeneous in the copy of the p...
bool Default_set_initial_condition_called
Has default set_initial_condition function been called? Default: false.
void get_bifurcation_eigenfunction(Vector< DoubleVector > &eigenfunction)
Return the eigenfunction calculated as part of a bifurcation tracking process. If we are not tracking...
double Relaxation_factor
Relaxation fator for Newton method (only a fractional Newton correction is applied if this is less th...
void add_time_stepper_pt(TimeStepper *const &time_stepper_pt)
Add a timestepper to the problem. The function will automatically create or resize the Time object so...
void refine_selected_elements(const Vector< unsigned > &elements_to_be_refined)
Refine (one and only!) mesh by splitting the elements identified by their numbers relative to the pro...
void prune_halo_elements_and_nodes(DocInfo &doc_info, const bool &report_stats)
(Irreversibly) prune halo(ed) elements and nodes, usually after another round of refinement,...
virtual void get_inverse_mass_matrix_times_residuals(DoubleVector &Mres)
Return the residual vector multiplied by the inverse mass matrix Virtual so that it can be overloaded...
void check_halo_schemes()
Check the halo/haloed node/element schemes.
double Parameter_current
Storage for the present value of the global parameter.
void assign_eigenvector_to_dofs(DoubleVector &eigenvector)
Assign the eigenvector passed to the function to the dofs in the problem so that it can be output by ...
@ Uniform_matrix_distribution
@ Default_matrix_distribution
@ Problem_matrix_distribution
unsigned setup_element_count_per_dof()
Function that populates the Element_counter_per_dof vector with the number of elements that contribut...
LinearSolver *& mass_matrix_solver_for_explicit_timestepper_pt()
Return a pointer to the linear solver object used for explicit time stepping.
OomphCommunicator * Communicator_pt
The communicator for this problem.
double Newton_solver_tolerance
The Tolerance below which the Newton Method is deemed to have converged.
void get_flat_packed_refinement_pattern_for_load_balancing(const Vector< unsigned > &old_domain_for_base_element, const Vector< unsigned > &new_domain_for_base_element, const unsigned &max_refinement_level_overall, std::map< unsigned, Vector< unsigned >> &flat_packed_refinement_info_for_root)
Get flat-packed refinement pattern for each root element in current mesh (labeled by unique number of...
void set_consistent_pinned_values_for_continuation()
Private helper function that is used to set the appropriate pinned values for continuation.
void activate_bifurcation_tracking(double *const ¶meter_pt, const DoubleVector &eigenvector, const bool &block_solve=true)
Activate generic bifurcation tracking for a single (real) eigenvalue where the initial guess for the ...
bool Discontinuous_element_formulation
Is the problem a discontinuous one, i.e. can the elemental contributions be treated independently....
bool Doc_imbalance_in_parallel_assembly
Boolean to switch on assessment of load imbalance in parallel assembly of distributed problem.
long synchronise_eqn_numbers(const bool &assign_local_eqn_numbers=true)
Classify any non-classified nodes into halo/haloed and synchronise equation numbers....
void create_new_linear_algebra_distribution(LinearAlgebraDistribution *&dist_pt)
Get new linear algebra distribution (you're in charge of deleting it!)
void p_refine_uniformly_aux(const Vector< unsigned > &nrefine_for_mesh, DocInfo &doc_info, const bool &prune)
Helper function to do compund p-refinement of (all) p-refineable (sub)mesh(es) uniformly as many time...
void calculate_continuation_derivatives_helper(const DoubleVector &z)
A function that performs the guts of the continuation derivative calculation in arc length continuati...
Vector< Problem * > Copy_of_problem_pt
Vector of pointers to copies of the problem used in adaptive bifurcation tracking problems (ALH: TEMP...
Vector< unsigned > distribute(const Vector< unsigned > &element_partition, DocInfo &doc_info, const bool &report_stats=false)
Distribute the problem and doc, using the specified partition; returns a vector which details the par...
Mesh * Mesh_pt
The mesh pointer.
double Parameter_derivative
Storage for the derivative of the global parameter wrt arc-length.
void add_eigenvector_to_dofs(const double &epsilon, const DoubleVector &eigenvector)
Add the eigenvector passed to the function scaled by the constat epsilon to the dofs in the problem s...
Vector< Data * > Global_data_pt
Vector of global data: "Nobody" (i.e. none of the elements etc.) is "in charge" of this Data so it wo...
void recompute_load_balanced_assembly()
Helper function to re-assign the first and last elements to be assembled by each processor during par...
Vector< double * > Dof_pt
Vector of pointers to dofs.
void p_adapt()
p-adapt problem: Perform mesh adaptation for (all) refineable (sub)mesh(es), based on their own error...
double DTSF_max_increase
Maximum possible increase of dt between time-steps in adaptive schemes.
bool Must_recompute_load_balance_for_assembly
Boolean indicating that the division of elements over processors during the assembly process must be ...
virtual void shift_time_values()
Shift all values along to prepare for next timestep.
double Target_error_safety_factor
Safety factor to ensure we are aiming for a target error, TARGET, that is below our tolerance: TARGET...
Mesh *& mesh_pt()
Return a pointer to the global mesh.
void set_default_first_and_last_element_for_assembly()
Set default first and last elements for parallel assembly of non-distributed problem.
bool Keep_temporal_error_below_tolerance
Boolean to decide if a timestep is to be rejected if the error estimate post-solve (computed by globa...
bool Shut_up_in_newton_solve
Boolean to indicate if all output is suppressed in Problem::newton_solve(). Defaults to false.
void set_dofs(const DoubleVector &dofs)
Set the values of the dofs.
void setup_base_mesh_info_after_pruning()
Helper function to re-setup the Base_mesh enumeration (used during load balancing) after pruning.
Vector< Mesh * > Sub_mesh_pt
Vector of pointers to submeshes.
Vector< double > Max_res
Maximum residuals at start and after each newton iteration.
EigenSolver * Eigen_solver_pt
Pointer to the eigen solver for the problem.
bool Bisect_to_find_bifurcation
Boolean to control wheter bisection is used to located bifurcation.
void explicit_timestep(const double &dt, const bool &shift_values=true)
Take an explicit timestep of size dt and optionally shift any stored values of the time history.
void delete_all_external_storage()
Wrapper function to delete external storage for each submesh of the problem.
friend class BlockPitchForkLinearSolver
double DTSF_min_decrease
Minimum allowed decrease of dt between time-steps in adaptive schemes. Lower scaling values will reje...
virtual void symmetrise_eigenfunction_for_adaptive_pitchfork_tracking()
Virtual function that is used to symmetrise the problem so that the current solution exactly satisfie...
double Minimum_dt_but_still_proceed
If Minimum_dt_but_still_proceed positive, then dt will not be reduced below this value during adaptiv...
double adaptive_unsteady_newton_solve(const double &dt_desired, const double &epsilon)
Attempt to advance timestep by dt_desired. If the solution fails the timestep will be halved until co...
unsigned Desired_newton_iterations_ds
The desired number of Newton Steps to reach convergence at each step along the arc.
void rebuild_global_mesh()
If one of the submeshes has changed (e.g. by mesh adaptation) we need to update the global mesh....
ExplicitTimeStepper *& explicit_time_stepper_pt()
Return a pointer to the explicit timestepper.
void activate_hopf_tracking(double *const ¶meter_pt, const bool &block_solve=true)
Turn on Hopf bifurcation tracking using the augmented system specified in the HopfHandler class....
Vector< double * > Halo_dof_pt
Storage for the halo degrees of freedom (only required) when accessing via the global equation number...
void deactivate_bifurcation_tracking()
Deactivate all bifuraction tracking, by reseting the assembly handler to the default.
void globally_convergent_line_search(const Vector< double > &x_old, const double &half_residual_squared_old, DoubleVector &gradient, DoubleVector &newton_dir, double &half_residual_squared, const double &stpmax)
Line search helper for globally convergent Newton method.
void get_hessian_vector_products(DoubleVectorWithHaloEntries const &Y, Vector< DoubleVectorWithHaloEntries > const &C, Vector< DoubleVectorWithHaloEntries > &product)
Return the product of the global hessian (derivative of Jacobian matrix with respect to all variables...
virtual double global_temporal_error_norm()
Function to calculate a global error norm, used in adaptive timestepping to control the change in tim...
@ Perform_assembly_using_two_arrays
@ Perform_assembly_using_maps
@ Perform_assembly_using_two_vectors
@ Perform_assembly_using_vectors_of_pairs
@ Perform_assembly_using_lists
int Sign_of_jacobian
Storage for the sign of the global Jacobian.
std::map< GeneralisedElement *, unsigned > Base_mesh_element_number_plus_one
Map which stores the correspondence between a root element and its element number (plus one) within t...
double Max_residuals
Maximum desired residual: if the maximum residual exceeds this value, the program will exit.
unsigned nsub_mesh() const
Return number of submeshes.
double & time()
Return the current value of continuous time.
unsigned self_test()
Self-test: Check meshes and global data. Return 0 for OK.
unsigned ntime_stepper() const
Return the number of time steppers.
void activate_fold_tracking(double *const ¶meter_pt, const bool &block_solve=true)
Turn on fold tracking using the augmented system specified in the FoldHandler class....
bool Use_globally_convergent_newton_method
Use the globally convergent newton method.
LinearSolver * Default_linear_solver_pt
Pointer to the default linear solver.
double Minimum_ds
Minimum desired value of arc-length.
void get_data_to_be_sent_during_load_balancing(const Vector< unsigned > &element_domain_on_this_proc, Vector< int > &send_n, Vector< double > &send_data, Vector< int > &send_displacement, Vector< unsigned > &old_domain_for_base_element, Vector< unsigned > &new_domain_for_base_element, unsigned &max_refinement_level_overall)
Load balance helper routine: Get data to be sent to other processors during load balancing and other ...
void restore_dof_values()
Restore the stored values of the degrees of freedom.
double Numerical_zero_for_sparse_assembly
A tolerance used to determine whether the entry in a sparse matrix is zero. If it is then storage nee...
double FD_step_used_in_get_hessian_vector_products
virtual void partition_global_mesh(Mesh *&global_mesh_pt, DocInfo &doc_info, Vector< unsigned > &element_domain, const bool &report_stats=false)
Partition the global mesh, return vector specifying the processor number for each element....
unsigned Sparse_assemble_with_arrays_initial_allocation
the number of elements to initially allocate for a matrix row within the sparse_assembly_with_two_arr...
void bifurcation_adapt_doc_errors(const unsigned &bifurcation_type)
A function that is used to document the errors used in the adaptive solution of bifurcation problems.
double Ds_current
Storage for the current step value.
virtual void set_initial_condition()
Set initial condition (incl previous timesteps). We need to establish this interface because I....
LinearSolver * Mass_matrix_solver_for_explicit_timestepper_pt
Pointer to the linear solver used for explicit time steps (this is likely to be different to the line...
void get_all_halo_data(std::map< unsigned, double * > &map_of_halo_data)
Get pointers to all possible halo data indexed by global equation number in a map.
void load_balance()
Balance the load of a (possibly non-uniformly refined) problem that has already been distributed,...
double & dof_derivative(const unsigned &i)
Access function to the derivative of the i-th (local) dof with respect to the arc length,...
double Minimum_dt
Minimum desired dt: if dt falls below this value, exit.
TimeStepper *& time_stepper_pt()
Access function for the pointer to the first (presumably only) timestepper.
double arc_length_step_solve(double *const ¶meter_pt, const double &ds, const unsigned &max_adapt=0)
Solve a steady problem using arc-length continuation, when the parameter that becomes a variable corr...
virtual void actions_after_adapt()
Actions that are to be performed after a mesh adaptation.
void p_refine_uniformly()
p-refine (all) p-refineable (sub)mesh(es) uniformly and rebuild problem
bool Use_continuation_timestepper
Boolean to control original or new storage of dof stuff.
void calculate_continuation_derivatives_fd(double *const ¶meter_pt)
A function to calculate the derivatives with respect to the arc-length required for continuation by f...
LinearAlgebraDistribution * Dof_distribution_pt
The distribution of the DOFs in this problem. This object is created in the Problem constructor and s...
void refine_uniformly()
Refine (all) refineable (sub)mesh(es) uniformly and rebuild problem.
static ContinuationStorageScheme Continuation_time_stepper
Storage for the single static continuation timestorage object.
bool Problem_is_nonlinear
Boolean flag indicating if we're dealing with a linear or nonlinear Problem – if set to false the New...
virtual void sparse_assemble_row_or_column_compressed_with_maps(Vector< int * > &column_or_row_index, Vector< int * > &row_or_column_start, Vector< double * > &value, Vector< unsigned > &nnz, Vector< double * > &residual, bool compressed_row_flag)
Private helper function that is used to assemble the Jacobian matrix in the case when the storage is ...
void send_refinement_info_helper(Vector< unsigned > &old_domain_for_base_element, Vector< unsigned > &new_domain_for_base_element, const unsigned &max_refinement_level_overall, std::map< unsigned, Vector< unsigned >> &refinement_info_for_root_local, Vector< Vector< Vector< unsigned >>> &refinement_info_for_root_elements)
Send refinement information between processors.
AssemblyHandler * Default_assembly_handler_pt
Pointer to the default assembly handler.
void get_my_eqns(AssemblyHandler *const &assembly_handler_pt, const unsigned &el_lo, const unsigned &el_hi, Vector< unsigned > &my_eqns)
Helper method that returns the (unique) global equations to which the elements in the range el_lo to ...
virtual void read(std::ifstream &restart_file, bool &unsteady_restart)
Read refinement pattern of all refineable meshes and refine them accordingly, then read all Data and ...
virtual ~Problem()
Virtual destructor to clean up memory.
void get_dofs(DoubleVector &dofs) const
Return the vector of dofs, i.e. a vector containing the current values of all unknowns.
Time * Time_pt
Pointer to global time for the problem.
DoubleVectorWithHaloEntries Element_count_per_dof
Counter that records how many elements contribute to each dof. Used to determine the (discrete) arc-l...
Data *& global_data_pt(const unsigned &i)
Return a pointer to the the i-th global data object.
virtual void actions_before_newton_convergence_check()
Any actions that are to be performed before the residual is checked in the Newton method,...
unsigned newton_solve_continuation(double *const ¶meter_pt)
Perform a basic arc-length continuation step using Newton's method. Returns number of Newton steps ta...
double Max_permitted_error_for_halo_check
Threshold for error throwing in Problem::check_halo_schemes()
unsigned Sparse_assemble_with_arrays_allocation_increment
the number of elements to add to a matrix row when the initial allocation is exceeded within the spar...
void reset_assembly_handler_to_default()
Reset the system to the standard non-augemented state.
virtual void actions_after_newton_step()
Any actions that are to be performed after each individual Newton step. Most likely to be used for di...
bool Pause_at_end_of_sparse_assembly
Protected boolean flag to halt program execution during sparse assemble process to assess peak memory...
void remove_null_pointers_from_external_halo_node_storage()
Consolidate external halo node storage by removing nulled out pointers in external halo and haloed sc...
Vector< double > * Saved_dof_pt
Pointer to vector for backup of dofs.
void unsteady_newton_solve(const double &dt)
Advance time by dt and solve by Newton's method. This version always shifts time values.
AssemblyHandler * Assembly_handler_pt
void get_all_error_estimates(Vector< Vector< double >> &elemental_error)
Return the error estimates computed by (all) refineable (sub)mesh(es) in the elemental_error structur...
virtual void actions_before_read_unstructured_meshes()
Actions that are to be performed before reading in restart data for problems involving unstructured b...
Vector< TimeStepper * > Time_stepper_pt
The Vector of time steppers (there could be many different ones in multiphysics problems)
void doc_errors()
Get max and min error for all elements in submeshes.
bool Mass_matrix_reuse_is_enabled
Is re-use of the mass matrix in explicit timestepping enabled Default:false.
void get_derivative_wrt_global_parameter(double *const ¶meter_pt, DoubleVector &result)
Get the derivative of the entire residuals vector wrt a global parameter, used in continuation proble...
void adapt_based_on_error_estimates(unsigned &n_refined, unsigned &n_unrefined, Vector< Vector< double >> &elemental_error)
Adapt problem: Perform mesh adaptation for (all) refineable (sub)mesh(es), based on the error estimat...
bool distributed() const
If we have MPI return the "problem has been distributed" flag, otherwise it can't be distributed so r...
bool are_hessian_products_calculated_analytically()
Function to determine whether the hessian products are calculated analytically.
bool does_pointer_correspond_to_problem_data(double *const ¶meter_pt)
Return a boolean flag to indicate whether the pointer parameter_pt refers to values stored in a Data ...
ExplicitTimeStepper * Explicit_time_stepper_pt
Pointer to a single explicit timestepper.
double arc_length_step_solve_helper(double *const ¶meter_pt, const double &ds, const unsigned &max_adapt)
Private helper function that actually contains the guts of the arc-length stepping,...
void solve_eigenproblem(const unsigned &n_eval, Vector< std::complex< double >> &alpha, Vector< double > &beta, Vector< DoubleVector > &eigenvector_real, Vector< DoubleVector > &eigenvector_imag, const bool &steady=true)
Solve an eigenproblem as assembled by the Problem's constituent elements. Calculate (at least) n_eval...
bool Use_predictor_values_as_initial_guess
Use values from the time stepper predictor as an initial guess.
RefineableElements are FiniteElements that may be subdivided into children to provide a better local ...
Tree * tree_pt()
Access function: Pointer to quadtree representation of this element.
virtual RefineableElement * root_element_pt()
Pointer to the root element in refinement hierarchy (must be implemented in specific elements that do...
Base class for refineable meshes. Provides standardised interfaces for the following standard mesh ad...
A Class for nodes that deform elastically (i.e. position is an unknown in the problem)....
void copy(SolidNode *orig_node_pt)
Copy nodal positions and associated data from specified node object.
Data *const & variable_position_pt() const
Pointer to variable_position data (const version)
bool position_is_pinned(const unsigned &i)
Test whether the i-th coordinate is pinned, 0: false; 1: true.
/////////////////////////////////////////////////////////////////////// /////////////////////////////...
//////////////////////////////////////////////////////////////////////////// ////////////////////////...
////////////////////////////////////////////////////////////////////// //////////////////////////////...
virtual unsigned ndt() const =0
Number of timestep increments that are required by the scheme.
virtual void set_weights()=0
Function to set the weights for present timestep (don't need to pass present timestep or previous tim...
virtual void set_predictor_weights()
Set the weights for the predictor previous timestep (currently empty – overwrite for specific scheme)
virtual void actions_before_timestep(Problem *problem_pt)
Interface for any actions that need to be performed before a time step.
virtual void actions_after_timestep(Problem *problem_pt)
Interface for any actions that need to be performed after a time step.
void make_steady()
Function to make the time stepper temporarily steady. This is trivially achieved by setting all the w...
virtual void undo_make_steady()
Reset the is_steady status of a specific TimeStepper to its default and re-assign the weights.
ExplicitTimeStepper * explicit_predictor_pt()
Get the pointer to the explicit timestepper to use as a predictor in adaptivity if Predict_by_explici...
void update_predicted_time(const double &new_time)
Set the time that the current predictions apply for, only needed for paranoid checks when doing Predi...
bool is_steady() const
Flag to indicate if a timestepper has been made steady (possibly temporarily to switch off time-depen...
virtual void set_error_weights()
Set the weights for the error computation, (currently empty – overwrite for specific scheme)
Time *const & time_pt() const
Access function for the pointer to time (const version)
Class to keep track of discrete/continous time. It is essential to have a single Time object when usi...
double & dt(const unsigned &t=0)
Return the value of the t-th stored timestep (t=0: present; t>0: previous).
double & time()
Return the current value of the continuous time.
void shift_dt()
Update all stored values of dt by shifting each value along the array. This function must be called b...
void initialise_dt(const double &dt_)
Set all timesteps to the same value, dt.
unsigned ndt() const
Return the number of timesteps stored.
void resize(const unsigned &n_dt)
Resize the vector holding the number of previous timesteps and initialise the new values to zero.
///////////////////////////////////////////////////////////////// ///////////////////////////////////...
void refine_base_mesh(Vector< Vector< unsigned >> &to_be_refined)
Refine base mesh according to specified refinement pattern.
unsigned uniform_refinement_level_when_pruned() const
Level to which the mesh was uniformly refined when it was pruned (const version)
virtual void get_refinement_levels(unsigned &min_refinement_level, unsigned &max_refinement_level)
Get max/min refinement levels in mesh.
void refine_uniformly(DocInfo &doc_info)
Refine mesh uniformly and doc process.
TreeRoot is a Tree that forms the root of a (recursive) tree. The "root node" is special as it holds ...
void stick_all_tree_nodes_into_vector(Vector< Tree * > &)
Traverse and stick pointers to all "nodes" into Vector.
RefineableElement * object_pt() const
Return the pointer to the object (RefineableElement) represented by the tree.
void stick_leaves_into_vector(Vector< Tree * > &)
Traverse tree and stick pointers to leaf "nodes" (only) into Vector.
TreeRoot *& root_pt()
Return pointer to root of the tree.
Base class for triangle meshes (meshes made of 2D triangle elements). Note: we choose to template Tri...
void dump_triangulateio(std::ostream &dump_file)
Dump the triangulateio structure to a dump file and record boundary coordinates of boundary nodes.
virtual void read_distributed_info_for_restart(std::istream &restart_file)
Virtual function that is used to read info. related with distributed triangle meshes.
bool use_triangulateio_restart() const
const access for Use_triangulateio_restart.
void remesh_from_triangulateio(std::istream &restart_file)
Regenerate the mesh from a dumped triangulateio file and dumped boundary coordinates of boundary node...
virtual void dump_distributed_info_for_restart(std::ostream &dump_file)
Virtual function that is used to dump info. related with distributed triangle meshes.
virtual void reestablish_distribution_info_for_restart(OomphCommunicator *comm_pt, std::istream &restart_file)
Virtual function used to re-establish any additional info. related with the distribution after a re-s...
void initialise(const _Tp &__value)
Iterate over all values and set to the desired value.
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
bool Doc_comprehensive_timings
Global boolean to switch on comprehensive timing – can probably be declared const false when developm...
unsigned Max_newton_iterations
Maximum number of newton iterations.
void partition_distributed_mesh(Problem *problem_pt, const unsigned &objective, Vector< unsigned > &element_domain_on_this_proc, const bool &bypass_metis=false)
Use METIS to assign each element in an already-distributed mesh to a domain. On return,...
void partition_mesh(Problem *problem_pt, const unsigned &ndomain, const unsigned &objective, Vector< unsigned > &element_domain)
Use METIS to assign each element to a domain. On return, element_domain[ielem] contains the number of...
std::string to_string(T object, unsigned float_precision=8)
Conversion function that should work for anything with operator<< defined (at least all basic types).
void clean_up_memory()
Clean up function that deletes anything dynamically allocated in this namespace.
void setup()
Setup terminate helper.
double timer()
returns the time in seconds after some point in past
std::string convert_secs_to_formatted_string(const double &time_in_sec)
Returns a nicely formatted string from an input time in seconds; the format depends on the size of ti...
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
void pause(std::string message)
Pause and display message.
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...