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 Minimum_dt_but_still_proceed(-1.0),
110 Scale_arc_length(true),
111 Desired_proportion_of_arc_length(0.5),
114 Continuation_direction(1.0),
115 Parameter_derivative(1.0),
116 Parameter_current(0.0),
117 Use_continuation_timestepper(false),
118 Dof_derivative_offset(1),
119 Dof_current_offset(2),
121 Desired_newton_iterations_ds(5),
123 Bifurcation_detection(false),
124 Bisect_to_find_bifurcation(false),
125 First_jacobian_sign_change(false),
126 Arc_length_step_taken(false),
127 Use_finite_differences_for_continuation_derivatives(false),
129 Dist_problem_matrix_distribution(Uniform_matrix_distribution),
130 Parallel_sparse_assemble_previous_allocation(0),
131 Problem_has_been_distributed(false),
132 Bypass_increase_in_dof_check_during_pruning(false),
133 Max_permitted_error_for_halo_check(1.0e-14),
135 Shut_up_in_newton_solve(false),
136 Always_take_one_newton_step(false),
137 Timestep_reduction_factor_after_nonconvergence(0.5),
138 Keep_temporal_error_below_tolerance(true)
207 for (
unsigned c = 0; c < n_copies; c++)
242 unsigned n_non_halo_element_local = 0;
243 for (
unsigned e = 0;
e < n_element;
e++)
252 ++n_non_halo_element_local;
256 for (
unsigned n = 0; n < n_var; n++)
267 unsigned Nelement = 0;
277 MPI_Allreduce(&n_non_halo_element_local,
288 Nelement = n_non_halo_element_local;
303 const unsigned nrow = this->
ndof();
342 bool use_problem_dist =
true;
343 for (
unsigned p = 0; p < nproc; p++)
347 ((
double)uniform_dist_pt->
nrow_local(p)) * 1.1)
349 use_problem_dist =
false;
352 if (use_problem_dist)
360 delete uniform_dist_pt;
366 std::ostringstream error_stream;
367 error_stream <<
"Never get here. Dist_problem_matrix_distribution = "
370 OOMPH_CURRENT_FUNCTION,
371 OOMPH_EXCEPTION_LOCATION);
404 std::map<unsigned, double*> halo_data_pt;
426 return distribute(element_partition, doc_info, report_stats);
439 bool has_non_zero_entry =
false;
440 unsigned n = element_partition.size();
441 for (
unsigned i = 0;
i < n;
i++)
443 if (element_partition[
i] != 0)
445 has_non_zero_entry =
true;
449 if (!has_non_zero_entry)
451 std::ostringstream warn_message;
452 warn_message <<
"WARNING: All entries in specified partitioning vector \n"
453 <<
" are zero -- will ignore this and use METIS\n"
454 <<
" to perform the partitioning\n";
456 warn_message.str(),
"Problem::distribute()", OOMPH_EXCEPTION_LOCATION);
464 return distribute(element_partition, doc_info, report_stats);
472 const bool& report_stats)
481 return distribute(element_partition, doc_info, report_stats);
493 const bool& report_stats)
508 std::ostringstream warn_message;
509 warn_message <<
"WARNING: You've tried to distribute a problem over\n"
510 <<
"only one processor: this would make METIS crash.\n"
511 <<
"Ignoring your request for distribution.\n";
513 "Problem::distribute()",
514 OOMPH_EXCEPTION_LOCATION);
517 else if (n_proc > n_element)
520 std::ostringstream error_stream;
521 error_stream <<
"You have tried to distribute a problem\n"
522 <<
"but there are less elements than processors.\n"
523 <<
"Please re-run with more elements!\n"
524 <<
"Please also ensure that actions_before_distribute().\n"
525 <<
"and actions_after_distribute() are correctly set up.\n"
528 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
534 bool a_mesh_is_not_uniformly_refined =
false;
542 unsigned min_ref_level = 0;
543 unsigned max_ref_level = 0;
544 mmesh_pt->get_refinement_levels(min_ref_level, max_ref_level);
546 if (max_ref_level != min_ref_level)
548 a_mesh_is_not_uniformly_refined =
true;
554 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
561 unsigned min_ref_level = 0;
562 unsigned max_ref_level = 0;
563 mmesh_pt->get_refinement_levels(min_ref_level, max_ref_level);
565 if (max_ref_level != min_ref_level)
567 a_mesh_is_not_uniformly_refined =
true;
574 if (a_mesh_is_not_uniformly_refined)
579 std::ostringstream error_stream;
580 error_stream <<
"You have tried to distribute a problem\n"
581 <<
"but at least one of your meshes is no longer\n"
582 <<
"uniformly refined. In order to preserve the Tree\n"
583 <<
"and TreeForest structure, Problem::distribute() can\n"
584 <<
"only be called while meshes are uniformly refined.\n"
587 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
594 std::ostringstream error_stream;
595 error_stream <<
"You have tried to distribute a problem\n"
596 <<
"and there is some global data.\n"
597 <<
"This is not likely to work...\n"
600 OOMPH_CURRENT_FUNCTION,
601 OOMPH_EXCEPTION_LOCATION);
612 unsigned old_ndof =
ndof();
619 unsigned nelem = global_mesh_pt->
nelement();
624 unsigned n_my_elements = 0;
627 bool used_preset_partitioning =
false;
632 unsigned sum_element_partition = 0;
633 unsigned n_part = element_partition.size();
634 for (
unsigned e = 0;
e < n_part;
e++)
637 if (
int(element_partition[
e]) == my_rank) n_my_elements++;
639 sum_element_partition += element_partition[
e];
641 if (sum_element_partition == 0)
643 oomph_info <<
"INFO: using METIS to partition elements" << std::endl;
645 used_preset_partitioning =
false;
649 oomph_info <<
"INFO: using pre-set partition of elements"
651 used_preset_partitioning =
true;
652 element_domain = element_partition;
662 oomph_info <<
"Time for partitioning of global mesh: "
663 << t_end - t_start << std::endl;
673 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
676 n_element_in_old_submesh[i_mesh] = nsub_elem;
686 oomph_info <<
"Time for actions before distribute: "
687 << t_end - t_start << std::endl;
704 return_element_domain.reserve(element_domain.size());
708 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
711 submesh_element_domain[i_mesh].resize(nsub_elem);
712 unsigned nsub_elem_old = n_element_in_old_submesh[i_mesh];
713 for (
unsigned e = 0;
e < nsub_elem_old;
e++)
715 if (nsub_elem_old == nsub_elem)
717 submesh_element_domain[i_mesh][
e] = element_domain[count];
718 return_element_domain.push_back(element_domain[count]);
727 return_element_domain = element_domain;
743 bool structured_mesh =
true;
746 if (tri_mesh_pt != 0)
748 structured_mesh =
false;
752 const unsigned n_ele = global_mesh_pt->
nelement();
755 for (
unsigned e = 0;
e < n_ele;
e++)
768 unsigned nglobal_element = 0;
770 std::vector<bool> is_structured_mesh(n_mesh);
771 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
775 if (tri_mesh_pt != 0)
779 is_structured_mesh[i_mesh] =
false;
785 is_structured_mesh[i_mesh] =
true;
788 if (is_structured_mesh[i_mesh])
798 unsigned counter = 0;
799 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
802 if (is_structured_mesh[i_mesh])
805 for (
unsigned e = 0;
e < n_ele;
e++)
817 if (counter != nglobal_element)
819 std::ostringstream error_stream;
821 <<
"The number of global elements (" << nglobal_element
822 <<
") is not the sameas the number of\nadded elements ("
823 << counter <<
") to the Base_mesh_element_pt data "
824 <<
"structure!!!\n\n";
826 "Problem::distribute()",
827 OOMPH_EXCEPTION_LOCATION);
838 bool overrule_keep_as_halo_element_status =
false;
839 if ((n_my_elements == 0) && (used_preset_partitioning))
841 oomph_info <<
"INFO: We're over-ruling the \"keep as halo element\"\n"
842 <<
" status because the preset partitioning\n"
843 <<
" didn't place ANY elements on this processor,\n"
844 <<
" probably because of a restart on a larger \n"
845 <<
" number of processors\n";
846 overrule_keep_as_halo_element_status =
true;
859 overrule_keep_as_halo_element_status);
863 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
867 oomph_info <<
"Distributing submesh " << i_mesh << std::endl
868 <<
"--------------------" << std::endl;
871 doc_info.
number() = i_mesh;
873 submesh_element_domain[i_mesh],
877 overrule_keep_as_halo_element_status);
884 unsigned n_del = deleted_element_pt.size();
885 for (
unsigned e = 0;
e < n_del;
e++)
896 oomph_info <<
"Time for mesh-level distribution: " << t_end - t_start
910 oomph_info <<
"Time for actions after distribute: " << t_end - t_start
917 oomph_info <<
"Number of equations: " << n_dof << std::endl;
922 oomph_info <<
"Time for re-assigning eqn numbers (in distribute): "
923 << t_end - t_start << std::endl;
928 if (n_dof != old_ndof)
930 std::ostringstream error_stream;
932 <<
"Number of dofs in distribute() has changed "
933 <<
"from " << old_ndof <<
" to " << n_dof <<
"\n"
934 <<
"Check that you've implemented any necessary "
935 "actions_before/after\n"
936 <<
"distribute functions, e.g. to pin redundant pressure dofs"
939 OOMPH_CURRENT_FUNCTION,
940 OOMPH_EXCEPTION_LOCATION);
955 return return_element_domain;
967 const bool& report_stats)
973 std::ostringstream filename;
974 std::ofstream some_file;
982 filename << doc_info.
directory() <<
"/complete_mesh"
983 << doc_info.
number() <<
".dat";
984 global_mesh_pt->
output(filename.str().c_str(), 5);
991 unsigned objective = 0;
998 nelem = element_domain.size();
1000 MPI_Bcast(&nelem, 1, MPI_UNSIGNED, 0, this->
communicator_pt()->mpi_comm());
1001 element_domain.resize(nelem);
1002 MPI_Bcast(&element_domain[0],
1014 for (
unsigned e = 0;
e < nelem;
e++)
1016 int_element_domain[
e] = element_domain[
e];
1020 int my_number_of_elements = 0;
1023 for (
unsigned e = 0;
e < nelem;
e++)
1025 if (int_element_domain[
e] == rank)
1027 my_number_of_elements++;
1033 MPI_Allgather(&my_number_of_elements,
1036 &number_of_elements[0],
1044 int max_number_of_elements = 0;
1045 int process_with_max_elements = 0;
1046 for (
int d = 0; d < n_proc; d++)
1048 if (number_of_elements[d] == 0)
1051 if (max_number_of_elements <= 1)
1053 for (
int dd = 0; dd < n_proc; dd++)
1055 if (number_of_elements[dd] > max_number_of_elements)
1057 max_number_of_elements = number_of_elements[dd];
1058 process_with_max_elements = dd;
1064 if (max_number_of_elements <= 1)
1067 std::ostringstream error_stream;
1068 error_stream <<
"No process has more than 1 element, and\n"
1069 <<
"at least one process has no elements!\n"
1070 <<
"Suggest rerunning with more refinement.\n"
1073 OOMPH_CURRENT_FUNCTION,
1074 OOMPH_EXCEPTION_LOCATION);
1079 for (
unsigned e = 0;
e < nelem;
e++)
1081 if (int_element_domain[
e] == process_with_max_elements)
1083 int_element_domain[
e] = d;
1085 number_of_elements[d]++;
1086 number_of_elements[process_with_max_elements]--;
1088 max_number_of_elements--;
1092 oomph_info <<
"INFO: Switched element domain at position " <<
e
1094 <<
"from process " << process_with_max_elements
1095 <<
" to process " << d << std::endl
1096 <<
"which was given no elements by METIS partition"
1109 for (
unsigned e = 0;
e < nelem;
e++)
1111 element_domain[
e] = int_element_domain[
e];
1114 unsigned count_elements = 0;
1115 for (
unsigned e = 0;
e < nelem;
e++)
1117 if (
int(element_domain[
e]) == rank)
1126 <<
" elements from this partition" << std::endl
1140 const bool& report_stats)
1149 <<
"WARNING: Problem::prune_halo_elements_and_nodes() was called on a "
1150 <<
"non-distributed Problem!" << std::endl;
1151 oomph_info <<
"Ignoring your request..." << std::endl;
1159 <<
"WARNING: You've tried to prune halo layers on a problem\n"
1160 <<
"with only one processor: this is unnecessary.\n"
1161 <<
"Ignoring your request." << std::endl
1167 unsigned old_ndof =
ndof();
1170 double t_start = 0.0;
1183 oomph_info <<
"Time for actions_before_distribute() in "
1184 <<
"Problem::prune_halo_elements_and_nodes(): "
1185 << t_end - t_start << std::endl;
1191 std::map<GeneralisedElement*, unsigned>
1192 old_base_element_number_plus_one;
1193 std::vector<bool> old_root_is_halo_or_non_existent(nel,
true);
1194 for (
unsigned e = 0;
e < nel;
e++)
1200 if (base_el_pt != 0)
1205 old_root_is_halo_or_non_existent[
e] =
false;
1213 old_base_element_number_plus_one[base_el_pt] =
e + 1;
1220 unsigned ntree = tree_pt.size();
1221 for (
unsigned t = 0;
t < ntree;
t++)
1223 old_base_element_number_plus_one[tree_pt[
t]->object_pt()] =
1234 oomph_info <<
"Time for setup old root elements in "
1235 <<
"Problem::prune_halo_elements_and_nodes(): "
1236 << t_end - t_start << std::endl;
1242 unsigned nel_base_old = nel;
1252 deleted_element_pt, doc_info, report_stats);
1257 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
1260 deleted_element_pt, doc_info, report_stats);
1270 oomph_info <<
"Total time for all mesh-level prunes in "
1271 <<
"Problem::prune_halo_elements_and_nodes(): "
1272 << t_end - t_start << std::endl;
1280 std::map<FiniteElement*, bool> root_el_done;
1285 new_base_element_associated_with_old_base_element(nel_base_old);
1287 unsigned n_meshes = n_mesh;
1298 std::vector<bool> is_structured_mesh(n_meshes);
1303 for (
unsigned i_mesh = 0; i_mesh < n_meshes; i_mesh++)
1307 if (!(tri_mesh_pt != 0))
1310 is_structured_mesh[i_mesh] =
true;
1317 is_structured_mesh[i_mesh] =
false;
1322 for (
unsigned i_mesh = 0; i_mesh < n_meshes; i_mesh++)
1326 if (is_structured_mesh[i_mesh])
1330 for (
unsigned e = 0;
e < nele_submesh;
e++)
1340 unsigned old_base_el_no =
1341 old_base_element_number_plus_one[el_pt] - 1;
1342 new_base_element_associated_with_old_base_element
1353 unsigned old_base_el_no =
1354 old_base_element_number_plus_one[el_pt] - 1;
1355 new_base_element_associated_with_old_base_element
1365 if (!root_el_done[root_el_pt])
1367 root_el_done[root_el_pt] =
true;
1368 unsigned old_base_el_no =
1369 old_base_element_number_plus_one[el_pt] - 1;
1370 new_base_element_associated_with_old_base_element
1372 .push_back(root_el_pt);
1386 for (
unsigned e = 0;
e < nel_base_old;
e++)
1388 local_n_new_root[
e] =
1389 new_base_element_associated_with_old_base_element[
e].size();
1393 n_new_root_back[
e] = local_n_new_root[
e];
1400 oomph_info <<
"Time for setup of new base elements in "
1401 <<
"Problem::prune_halo_elements_and_nodes(): "
1402 << t_end - t_start << std::endl;
1410 MPI_Allreduce(&local_n_new_root[0],
1422 <<
"Problem::prune_halo_elements_and_nodes(): "
1423 << t_end - t_start << std::endl;
1428 unsigned nel_base_new = 0;
1429 for (
unsigned e = 0;
e < nel_base_old;
e++)
1432 nel_base_new += n_new_root[
e];
1439 if (!old_root_is_halo_or_non_existent[
e])
1441 if (n_new_root_back[
e] != 0)
1443 if (n_new_root_back[
e] != n_new_root[
e])
1445 std::ostringstream error_stream;
1447 <<
"Number of new root elements spawned from old root " <<
e
1448 <<
": " << n_new_root[
e] <<
"\nis not consistent"
1449 <<
" with previous value: " << n_new_root_back[
e]
1452 OOMPH_CURRENT_FUNCTION,
1453 OOMPH_EXCEPTION_LOCATION);
1468 for (
unsigned e = 0;
e < nel_base_old;
e++)
1472 if (!old_root_is_halo_or_non_existent[
e])
1475 unsigned n_new_root =
1476 new_base_element_associated_with_old_base_element[
e].size();
1477 for (
unsigned j = 0; j < n_new_root; j++)
1481 new_base_element_associated_with_old_base_element[
e][j];
1494 unsigned nskip = n_new_root[
e];
1507 oomph_info <<
"Time for finishing off base mesh info "
1508 <<
"Problem::prune_halo_elements_and_nodes(): "
1509 << t_end - t_start << std::endl;
1521 oomph_info <<
"Time for actions_after_distribute() "
1522 <<
"Problem::prune_halo_elements_and_nodes(): "
1523 << t_end - t_start << std::endl;
1539 oomph_info <<
"Time for assign_eqn_numbers() "
1540 <<
"Problem::prune_halo_elements_and_nodes(): "
1541 << t_end - t_start << std::endl;
1549 if (n_dof != old_ndof)
1551 std::ostringstream error_stream;
1553 <<
"Number of dofs in prune_halo_elements_and_nodes() has "
1555 <<
"from " << old_ndof <<
" to " << n_dof <<
"\n"
1556 <<
"Check that you've implemented any necessary "
1557 "actions_before/after"
1558 <<
"\nadapt/distribute functions, e.g. to pin redundant pressure"
1561 OOMPH_CURRENT_FUNCTION,
1562 OOMPH_EXCEPTION_LOCATION);
1585 std::string error_message =
"Problem::build_global_mesh() called,\n";
1586 error_message +=
" but a global mesh has already been built:\n";
1587 error_message +=
"Problem::Mesh_pt is not zero!\n";
1590 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1595 std::string error_message =
"Problem::build_global_mesh() called,\n";
1596 error_message +=
" but there are no submeshes:\n";
1597 error_message +=
"Problem::Sub_mesh_pt has no entries\n";
1600 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1644 oomph_info <<
"Created Time with " << ndt <<
" timesteps" << std::endl;
1653 oomph_info <<
"Resized Time to include " << ndt <<
" timesteps"
1659 oomph_info <<
"Time object already has storage for " << ndt
1660 <<
" timesteps" << std::endl;
1683 oomph_info <<
"Created Time with storage for no previous timestep"
1688 oomph_info <<
"Time object already exists " << std::endl;
1693 #ifdef OOMPH_HAS_MPI
1705 unsigned min_el = 10;
1716 unsigned lo_proc = 0;
1717 unsigned hi_proc = n_proc - 1;
1718 if (
int(n_elements) >= n_proc)
1720 range = unsigned(
double(n_elements) /
double(n_proc));
1726 hi_proc = unsigned(
double(n_elements) /
double(min_el));
1729 for (
int p = lo_proc; p <= int(hi_proc); p++)
1733 unsigned last_el_plus_one = (p + 1) * range;
1734 if (last_el_plus_one > n_elements) last_el_plus_one = n_elements;
1739 if (
int(n_elements) >= n_proc)
1749 oomph_info <<
"Problem is not distributed. Parallel assembly of "
1750 <<
"Jacobian uses default partitioning: " << std::endl;
1751 for (
int p = 0; p < n_proc; p++)
1755 oomph_info <<
"Proc " << p <<
" assembles from element "
1761 oomph_info <<
"Proc " << p <<
" assembles no elements\n";
1787 if (
int(nel) < n_proc)
1789 oomph_info <<
"Not re-computing distribution of elemental assembly\n"
1790 <<
"because there are fewer elements than processors\n";
1799 for (
int p = 0; p < n_proc; p++)
1807 receive_count[p] = el_hi - el_lo + 1;
1808 displacement[p] = offset;
1809 offset += el_hi - el_lo + 1;
1813 double* el_ass_time =
new double[nel];
1814 for (
unsigned e = 0;
e < nel;
e++)
1820 unsigned nel_local =
1831 delete[] el_ass_time;
1835 for (
int p = 0; p < n_proc; p++)
1837 first_and_last_element[p].resize(2);
1847 <<
"Re-assigning distribution of element assembly over processors:"
1854 for (
unsigned e = 0;
e < n_elements;
e++)
1860 double target_load = total / double(n_proc);
1864 first_and_last_element[0][0] = 0;
1868 unsigned max_el_avail = n_elements - n_proc;
1872 for (
unsigned e = 0;
e < n_elements;
e++)
1878 if ((total > target_load) || (
e == max_el_avail))
1881 first_and_last_element[proc][1] =
e;
1884 if (proc < (n_proc - 1))
1887 first_and_last_element[proc + 1][0] =
e + 1;
1903 first_and_last_element[n_proc - 1][1] = n_elements - 1;
1910 std::ostringstream error_stream;
1911 for (
int p = 0; p < n_proc - 1; p++)
1913 unsigned first_of_current = first_and_last_element[p][0];
1914 unsigned last_of_current = first_and_last_element[p][1];
1915 if (first_of_current > last_of_current)
1918 error_stream <<
"Error: First/last element of proc " << p <<
": "
1919 << first_of_current <<
" " << last_of_current
1922 unsigned first_of_next = first_and_last_element[p + 1][0];
1923 if (first_of_next != (last_of_current + 1))
1926 error_stream <<
"Error: First element of proc " << p + 1 <<
": "
1927 << first_of_next <<
" and last element of proc " << p
1928 <<
": " << last_of_current << std::endl;
1934 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2008 oomph_info <<
"Processor " << 0 <<
" assembles Jacobians"
2009 <<
" from elements " << first_and_last_element[0][0]
2010 <<
" to " << first_and_last_element[0][1] <<
" "
2015 for (
int p = 1; p < n_proc; ++p)
2017 MPI_Send(&first_and_last_element[p][0],
2027 oomph_info <<
"Processor " << p <<
" assembles Jacobians"
2028 <<
" from elements " << first_and_last_element[p][0]
2029 <<
" to " << first_and_last_element[p][1] <<
" "
2051 for (
int p = 0; p < n_proc; p++)
2076 const bool& assign_local_eqn_numbers)
2082 std::ostringstream error_stream;
2083 error_stream <<
"Global mesh does not exist, so equation numbers cannot "
2088 error_stream <<
"There aren't even any sub-meshes in the Problem.\n"
2089 <<
"You can set the global mesh directly by using\n"
2090 <<
"Problem::mesh_pt() = my_mesh_pt;\n"
2091 <<
"OR you can use Problem::add_sub_mesh(mesh_pt); "
2092 <<
"to add a sub mesh.\n";
2096 error_stream <<
"There are " <<
nsub_mesh() <<
" sub-meshes.\n";
2098 error_stream <<
"You need to call Problem::build_global_mesh() to create "
2100 <<
"from the sub-meshes.\n\n";
2103 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2110 #ifdef OOMPH_HAS_MPI
2140 double t_start = 0.0;
2151 for (
unsigned e = 0;
e < nel;
e++)
2156 #ifdef OOMPH_HAS_MPI
2159 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
2161 for (
int iproc = 0; iproc < n_proc; iproc++)
2164 for (
unsigned e = 0;
e < n_ext_halo_el;
e++)
2180 <<
"Time for complete setup of dependencies in assign_eqn_numbers: "
2181 << t_end - t_start << std::endl;
2191 for (
unsigned loop_count = 0; loop_count < 2; loop_count++)
2202 unsigned long equation_number = 0;
2206 for (
unsigned i = 0;
i < Nglobal_data;
i++)
2221 if (n_sub_mesh == 0)
2225 n_dof = spine_mesh_pt->assign_global_spine_eqn_numbers(
Dof_pt);
2232 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
2237 n_dof = spine_mesh_pt->assign_global_spine_eqn_numbers(
Dof_pt);
2246 <<
"Time for assign_global_eqn_numbers in assign_eqn_numbers: "
2247 << t_end - t_start << std::endl;
2252 #ifdef OOMPH_HAS_MPI
2279 oomph_info <<
"Time for Problem::synchronise_eqn_numbers in "
2280 <<
"Problem::assign_eqn_numbers: " << t_end - t_start
2285 #ifdef OOMPH_HAS_MPI
2297 bool actually_removed_some_data =
false;
2300 if (loop_count == 0)
2302 if (n_sub_mesh == 0)
2308 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
2310 bool tmp_actually_removed_some_data =
false;
2312 tmp_actually_removed_some_data);
2313 if (tmp_actually_removed_some_data)
2314 actually_removed_some_data =
true;
2323 std::stringstream tmp;
2324 tmp <<
"Time for calls to Problem::remove_duplicate_data in "
2325 <<
"Problem::assign_eqn_numbers: " << t_end - t_start
2327 if (!actually_removed_some_data)
2331 tmp <<
" removed some/any data.\n";
2337 unsigned status = 0;
2338 if (actually_removed_some_data) status = 1;
2341 unsigned overall_status = 0;
2342 MPI_Allreduce(&status,
2353 std::stringstream tmp;
2355 <<
"Time for MPI_Allreduce after Problem::remove_duplicate_data in "
2356 <<
"Problem::assign_eqn_numbers: " << t_end - t_start << std::endl;
2362 if (overall_status != 1)
2378 <<
"Problem::remove_null_pointers_from_external_halo_node_"
2380 << t_end - t_start << std::endl;
2410 if (assign_local_eqn_numbers)
2412 if (n_sub_mesh == 0)
2418 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
2429 oomph_info <<
"Total time for all Mesh::assign_local_eqn_numbers in "
2430 <<
"Problem::assign_eqn_numbers: " << t_end - t_start
2451 std::ostringstream error_stream;
2453 <<
"Global mesh does not exist, so equation numbers cannot be found.\n";
2457 error_stream <<
"There aren't even any sub-meshes in the Problem.\n"
2458 <<
"You can set the global mesh directly by using\n"
2459 <<
"Problem::mesh_pt() = my_mesh_pt;\n"
2460 <<
"OR you can use Problem::add_sub_mesh(mesh_pt); "
2461 <<
"to add a sub mesh.\n";
2465 error_stream <<
"There are " <<
nsub_mesh() <<
" sub-meshes.\n";
2467 error_stream <<
"You need to call Problem::build_global_mesh() to create "
2469 <<
"from the sub-meshes.\n\n";
2472 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2477 <<
"Although this program will describe the degrees of freedom in the \n"
2478 <<
"problem, it will do so using the typedef for the elements. This is \n"
2479 <<
"not neccesarily human readable, but there is a solution.\n"
2480 <<
"Pipe your program's output through c++filt, with the argument -t.\n"
2481 <<
"e.g. \"./two_d_multi_poisson | c++filt -t > ReadableOutput.txt\".\n "
2482 <<
"(Disregarding the quotes)\n\n\n";
2484 out <<
"Classifying Global Equation Numbers" << std::endl;
2492 for (
unsigned i = 0;
i < Nglobal_data;
i++)
2494 std::stringstream conversion;
2495 conversion <<
" in Global Data " <<
i <<
".";
2509 if (n_sub_mesh == 0)
2514 spine_mesh_pt->describe_spine_dofs(out, in);
2521 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
2526 std::stringstream conversion;
2527 conversion <<
" in Sub-SpineMesh " <<
i <<
".";
2529 spine_mesh_pt->describe_spine_dofs(out, in);
2538 out <<
"Classifying global eqn numbers in terms of elements." << std::endl;
2540 out <<
"Eqns | Source" << std::endl;
2543 if (n_sub_mesh == 0)
2550 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
2552 std::stringstream conversion;
2553 conversion <<
" in Sub-Mesh " <<
i <<
".";
2568 const unsigned long n_dof =
ndof();
2574 for (
unsigned long l = 0; l < n_dof; l++)
2586 throw OomphLibError(
"Not designed for distributed problems",
2587 OOMPH_EXCEPTION_LOCATION,
2588 OOMPH_CURRENT_FUNCTION);
2598 for (
unsigned i = 0;
i < Nglobal_data;
i++)
2604 if (eqn_number >= 0)
2612 for (
unsigned i = 0, ni =
mesh_pt()->nelement();
i < ni;
i++)
2618 for (
unsigned k = 0, nk = d_pt->
nvalue(); k < nk; k++)
2621 if (eqn_number >= 0)
2623 dofs[eqn_number] = d_pt->
value(
t, k);
2630 for (
unsigned i = 0, ni =
mesh_pt()->nnode();
i < ni;
i++)
2633 for (
unsigned j = 0, nj = node_pt->
nvalue(); j < nj; j++)
2637 if (eqn_number >= 0)
2639 dofs[eqn_number] = node_pt->
value(
t, j);
2646 #ifdef OOMPH_HAS_MPI
2655 bool& actually_removed_some_data)
2669 actually_removed_some_data =
false;
2686 std::map<unsigned, Node*> global_node_pt;
2689 std::map<Node*, bool> node_done;
2693 for (
unsigned e = 0;
e < n_element;
e++)
2700 unsigned n_node = el_pt->
nnode();
2701 for (
unsigned j = 0; j < n_node; j++)
2706 if (!node_done[nod_pt])
2708 node_done[nod_pt] =
true;
2712 unsigned first_non_negative_eqn_number_plus_one = 0;
2713 unsigned n_val = nod_pt->
nvalue();
2714 for (
unsigned i_val = 0; i_val < n_val; i_val++)
2719 first_non_negative_eqn_number_plus_one = eqn_no + 1;
2726 if (first_non_negative_eqn_number_plus_one == 0)
2730 if (solid_nod_pt != 0)
2735 for (
unsigned i_val = 0; i_val < n_val; i_val++)
2741 first_non_negative_eqn_number_plus_one = eqn_no + 1;
2749 if (first_non_negative_eqn_number_plus_one > 0)
2751 global_node_pt[first_non_negative_eqn_number_plus_one - 1] =
2760 ->ncont_interpolated_values();
2761 for (
int i_cont = -1; i_cont < n_cont_int_values; i_cont++)
2766 unsigned n_master = hang_pt->
nmaster();
2767 for (
unsigned m = 0; m < n_master; m++)
2770 if (!node_done[master_nod_pt])
2772 node_done[master_nod_pt] =
true;
2776 unsigned first_non_negative_eqn_number_plus_one = 0;
2777 unsigned n_val = master_nod_pt->
nvalue();
2778 for (
unsigned i_val = 0; i_val < n_val; i_val++)
2780 int eqn_no = master_nod_pt->
eqn_number(i_val);
2783 first_non_negative_eqn_number_plus_one = eqn_no + 1;
2790 if (first_non_negative_eqn_number_plus_one == 0)
2795 dynamic_cast<SolidNode*
>(master_nod_pt);
2796 if (master_solid_nod_pt != 0)
2803 for (
unsigned i_val = 0; i_val < n_val; i_val++)
2810 first_non_negative_eqn_number_plus_one =
2819 if (first_non_negative_eqn_number_plus_one > 0)
2821 global_node_pt[first_non_negative_eqn_number_plus_one -
2840 std::set<Node*> killed_nodes;
2845 for (
int iproc = n_proc - 1; iproc >= 0; iproc--)
2848 if (iproc != my_rank)
2853 for (
unsigned e_ext = 0; e_ext < n_element; e_ext++)
2857 if (finite_ext_el_pt != 0)
2860 unsigned n_node = finite_ext_el_pt->
nnode();
2861 for (
unsigned j = 0; j < n_node; j++)
2867 unsigned first_non_negative_eqn_number_plus_one = 0;
2868 unsigned n_val = nod_pt->
nvalue();
2869 for (
unsigned i_val = 0; i_val < n_val; i_val++)
2874 first_non_negative_eqn_number_plus_one = eqn_no + 1;
2881 if (first_non_negative_eqn_number_plus_one == 0)
2885 if (solid_nod_pt != 0)
2891 for (
unsigned i_val = 0; i_val < n_val; i_val++)
2897 first_non_negative_eqn_number_plus_one = eqn_no + 1;
2907 if (first_non_negative_eqn_number_plus_one > 0)
2909 Node* existing_node_pt =
2910 global_node_pt[first_non_negative_eqn_number_plus_one - 1];
2913 if (existing_node_pt != 0)
2916 actually_removed_some_data =
true;
2920 Node* duplicated_node_pt = nod_pt;
2921 if (!node_done[duplicated_node_pt])
2924 std::set<unsigned>* boundaries_pt;
2926 if (boundaries_pt != 0)
2929 unsigned nb = (*boundaries_pt).size();
2931 for (std::set<unsigned>::iterator it =
2932 (*boundaries_pt).begin();
2933 it != (*boundaries_pt).end();
2936 bound.push_back((*it));
2938 for (
unsigned i = 0;
i < nb;
i++)
2941 duplicated_node_pt);
2946 killed_nodes.insert(duplicated_node_pt);
2947 unsigned i_proc = unsigned(iproc);
2949 duplicated_node_pt);
2965 int n_cont_inter_values =
2967 ->ncont_interpolated_values();
2968 for (
int i_cont = -1; i_cont < n_cont_inter_values;
2971 unsigned n_master_orig = 0;
2974 n_master_orig = finite_ext_el_pt->
node_pt(j)
2983 unsigned n_master_replace = 0;
2990 if (n_master_orig != n_master_replace)
2992 std::ostringstream error_stream;
2994 <<
"Number of master nodes for node to be replaced, "
2995 << n_master_orig <<
", doesn't match"
2996 <<
"those of replacement node, " << n_master_replace
2997 <<
" for i_cont=" << i_cont << std::endl;
3000 <<
"Nodal coordinates of replacement node:";
3001 unsigned ndim = existing_node_pt->
ndim();
3002 for (
unsigned i = 0;
i < ndim;
i++)
3004 error_stream << existing_node_pt->
x(
i) <<
" ";
3006 error_stream <<
"\n";
3007 error_stream <<
"The coordinates of its "
3009 <<
" master nodes are: \n";
3010 for (
unsigned k = 0; k < n_master_replace; k++)
3012 Node* master_nod_pt =
3015 unsigned ndim = master_nod_pt->
ndim();
3016 for (
unsigned i = 0;
i < ndim;
i++)
3018 error_stream << master_nod_pt->
x(
i) <<
" ";
3020 error_stream <<
"\n";
3026 <<
"Nodal coordinates of node to be replaced:";
3027 unsigned ndim = finite_ext_el_pt->
node_pt(j)->
ndim();
3028 for (
unsigned i = 0;
i < ndim;
i++)
3030 error_stream << finite_ext_el_pt->
node_pt(j)->
x(
i)
3033 error_stream <<
"\n";
3034 error_stream <<
"The coordinates of its "
3036 <<
" master nodes are: \n";
3037 for (
unsigned k = 0; k < n_master_orig; k++)
3039 Node* master_nod_pt = finite_ext_el_pt->
node_pt(j)
3042 unsigned ndim = master_nod_pt->
ndim();
3043 for (
unsigned i = 0;
i < ndim;
i++)
3045 error_stream << master_nod_pt->
x(
i) <<
" ";
3047 error_stream <<
"\n";
3053 OOMPH_CURRENT_FUNCTION,
3054 OOMPH_EXCEPTION_LOCATION);
3060 finite_ext_el_pt->
node_pt(j) = existing_node_pt;
3065 global_node_pt[first_non_negative_eqn_number_plus_one - 1] =
3067 node_done[nod_pt] =
true;
3076 int n_cont_inter_values =
3078 ->ncont_interpolated_values();
3079 for (
int i_cont = -1; i_cont < n_cont_inter_values; i_cont++)
3085 unsigned n_master = hang_pt->
nmaster();
3086 for (
unsigned m = 0; m < n_master; m++)
3089 unsigned n_val = master_nod_pt->
nvalue();
3090 unsigned first_non_negative_eqn_number_plus_one = 0;
3091 for (
unsigned i_val = 0; i_val < n_val; i_val++)
3093 int eqn_no = master_nod_pt->
eqn_number(i_val);
3096 first_non_negative_eqn_number_plus_one = eqn_no + 1;
3103 if (first_non_negative_eqn_number_plus_one == 0)
3106 dynamic_cast<SolidNode*
>(master_nod_pt);
3107 if (solid_master_nod_pt != 0)
3114 for (
unsigned i_val = 0; i_val < n_val; i_val++)
3121 first_non_negative_eqn_number_plus_one =
3133 if (first_non_negative_eqn_number_plus_one > 0)
3135 Node* existing_node_pt = global_node_pt
3136 [first_non_negative_eqn_number_plus_one - 1];
3139 if (existing_node_pt != 0)
3142 actually_removed_some_data =
true;
3146 Node* duplicated_node_pt = master_nod_pt;
3148 if (!node_done[duplicated_node_pt])
3151 std::set<unsigned>* boundaries_pt;
3154 if (boundaries_pt != 0)
3156 for (std::set<unsigned>::iterator it =
3157 (*boundaries_pt).begin();
3158 it != (*boundaries_pt).end();
3162 (*it), duplicated_node_pt);
3166 killed_nodes.insert(duplicated_node_pt);
3167 unsigned i_proc = unsigned(iproc);
3169 i_proc, duplicated_node_pt);
3183 std::ostringstream error_stream;
3185 <<
"About to re-set master for i_cont= " << i_cont
3186 <<
" for external node (with proc " << iproc
3187 <<
" )" << tmp_nod_pt <<
" at ";
3188 unsigned n = tmp_nod_pt->
ndim();
3189 for (
unsigned jj = 0; jj < n; jj++)
3191 error_stream << tmp_nod_pt->x(jj) <<
" ";
3194 <<
" which is not hanging --> About to die!"
3195 <<
"Outputting offending element into oomph-info "
3202 OOMPH_CURRENT_FUNCTION,
3203 OOMPH_EXCEPTION_LOCATION);
3217 [first_non_negative_eqn_number_plus_one - 1] =
3219 node_done[master_nod_pt] =
true;
3237 for (std::set<Node*>::iterator it = killed_nodes.begin();
3238 it != killed_nodes.end();
3267 unsigned n_mesh_loop = 1;
3271 n_mesh_loop = nmesh;
3297 for (
int domain = 0; domain < n_proc; domain++)
3300 send_displacement[domain] = send_data.size();
3304 if (domain != my_rank)
3307 Mesh* my_mesh_pt = 0;
3310 for (
unsigned imesh = 0; imesh < n_mesh_loop; imesh++)
3325 unsigned nnod = backup_pt.size();
3329 new_external_halo_node_pt.reserve(nnod);
3332 for (
unsigned j = 0; j < nnod; j++)
3335 Node* nod_pt = backup_pt[j];
3341 send_data.push_back(j);
3346 new_external_halo_node_pt.push_back(nod_pt);
3352 new_external_halo_node_pt);
3355 send_data.push_back(-1);
3362 send_n[domain] = send_data.size() - send_displacement[domain];
3369 MPI_Alltoall(&send_n[0],
3381 int receive_data_count = 0;
3382 for (
int rank = 0; rank < n_proc; ++rank)
3385 receive_displacement[rank] = receive_data_count;
3386 receive_data_count += receive_n[rank];
3391 if (receive_data_count == 0)
3393 ++receive_data_count;
3399 if (send_data.size() == 0)
3401 send_data.resize(1);
3405 MPI_Alltoallv(&send_data[0],
3407 &send_displacement[0],
3411 &receive_displacement[0],
3416 for (
int send_rank = 0; send_rank < n_proc; send_rank++)
3420 if ((send_rank != my_rank) && (receive_n[send_rank] != 0))
3423 unsigned count = receive_displacement[send_rank];
3426 Mesh* my_mesh_pt = 0;
3429 for (
unsigned imesh = 0; imesh < n_mesh_loop; imesh++)
3448 int next_one = receive_data[count++];
3457 backup_pt[next_one] = 0;
3462 unsigned nnod = backup_pt.size();
3466 new_external_haloed_node_pt.reserve(nnod);
3469 for (
unsigned j = 0; j < nnod; j++)
3472 Node* nod_pt = backup_pt[j];
3478 new_external_haloed_node_pt.push_back(nod_pt);
3484 new_external_haloed_node_pt);
3499 const unsigned long n_dof = this->
ndof();
3501 if (n_dof != dofs.
nrow())
3503 std::ostringstream error_stream;
3504 error_stream <<
"Number of degrees of freedom in vector argument "
3505 << dofs.
nrow() <<
"\n"
3506 <<
"does not equal number of degrees of freedom in problem "
3509 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3512 for (
unsigned long l = 0; l < n_dof; l++)
3524 throw OomphLibError(
"Not designed for distributed problems",
3525 OOMPH_EXCEPTION_LOCATION,
3526 OOMPH_CURRENT_FUNCTION);
3533 for (
unsigned i = 0;
i < Nglobal_data;
i++)
3539 if (eqn_number >= 0)
3547 for (
unsigned i = 0, ni =
mesh_pt()->nelement();
i < ni;
i++)
3553 for (
unsigned k = 0, nk = d_pt->
nvalue(); k < nk; k++)
3556 if (eqn_number >= 0)
3565 for (
unsigned i = 0, ni =
mesh_pt()->nnode();
i < ni;
i++)
3568 for (
unsigned j = 0, nj = node_pt->
nvalue(); j < nj; j++)
3572 if (eqn_number >= 0)
3588 throw OomphLibError(
"Not implemented for distributed problems!",
3589 OOMPH_EXCEPTION_LOCATION,
3590 OOMPH_CURRENT_FUNCTION);
3600 for (
unsigned i = 0;
i < Nglobal_data;
i++)
3606 if (eqn_number >= 0)
3615 for (
unsigned i = 0, ni =
mesh_pt()->nnode();
i < ni;
i++)
3618 for (
unsigned j = 0, nj = node_pt->
nvalue(); j < nj; j++)
3622 if (eqn_number >= 0)
3630 for (
unsigned i = 0, ni =
mesh_pt()->nelement();
i < ni;
i++)
3638 if (eqn_number >= 0)
3653 const unsigned long n_dof = this->
ndof();
3654 for (
unsigned long l = 0; l < n_dof; l++)
3656 *
Dof_pt[l] += lambda * increment_dofs[l];
3674 std::ostringstream error_stream;
3675 error_stream <<
"The function get_inverse_mass_matrix_times_residuals() "
3677 <<
"used with the default assembly handler\n\n";
3679 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3684 const unsigned n_dof = this->
ndof();
3688 Mres.
build(&dist, 0.0);
3697 for (
unsigned e = 0;
e < n_element;
e++)
3704 const unsigned n_el_dofs = elem_pt->
ndof();
3708 for (
unsigned i = 0;
i < n_el_dofs;
i++)
3724 oomph_info <<
"Not recomputing Mass Matrix " << std::endl;
3743 oomph_info <<
"Enabling resolve in explicit timestep" << std::endl;
3775 std::vector<bool> was_steady(n_time_steppers);
3776 for (
unsigned i = 0;
i < n_time_steppers;
i++)
3787 for (
unsigned i = 0;
i < n_time_steppers;
i++)
3817 if (residuals.
built())
3821 std::ostringstream error_stream;
3822 error_stream <<
"The distribution of the residuals vector does not "
3823 "have the correct\n"
3824 <<
"number of global rows\n";
3827 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3837 if (residuals.
built())
3850 residuals.
build(dist_pt, 0.0);
3853 #ifdef OOMPH_HAS_MPI
3859 for (
unsigned long e = 0;
e < Element_pt_range;
e++)
3870 for (
unsigned l = 0; l < n_element_dofs; l++)
3873 element_residuals[l];
3877 #ifdef OOMPH_HAS_MPI
3898 dist_pt, column_index, row_start, value, nnz, res);
3925 unsigned n_dof =
ndof();
3931 if (residuals.
built())
3935 std::ostringstream error_stream;
3937 <<
"If the DoubleVector residuals is setup then it must not "
3938 <<
"be distributed.";
3940 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3944 std::ostringstream error_stream;
3946 <<
"If the DoubleVector residuals is setup then it must have"
3947 <<
" the correct number of rows";
3949 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3954 std::ostringstream error_stream;
3956 <<
"If the DoubleVector residuals is setup then it must have"
3957 <<
" the same communicator as the problem.";
3959 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3965 if (!residuals.
built())
3968 residuals.
build(&dist, 0.0);
3982 jacobian.
resize(n_dof, n_dof);
3990 for (
unsigned long e = 0;
e < n_element;
e++)
4002 elem_pt, element_residuals, element_jacobian);
4004 for (
unsigned l = 0; l < n_element_dofs; l++)
4007 residuals[eqn_number] += element_residuals[l];
4008 for (
unsigned l2 = 0; l2 < n_element_dofs; l2++)
4011 element_jacobian(l, l2);
4061 std::ostringstream error_stream;
4062 error_stream <<
"The distribution of the residuals must "
4063 <<
"be the same as the distribution of the jacobian.";
4065 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4069 std::ostringstream error_stream;
4071 <<
"The distribution of the jacobian and residuals does not"
4072 <<
"have the correct number of global rows.";
4074 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4079 std::ostringstream error_stream;
4080 error_stream <<
"The distribution of the jacobian and residuals must "
4081 <<
"both be setup or both not setup";
4083 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4107 bool compressed_row_flag =
true;
4109 #ifdef OOMPH_HAS_MPI
4115 column_index, row_start, value, nnz, res, compressed_row_flag);
4116 jacobian.
build(dist_pt);
4118 dist_pt->
nrow(), nnz[0], value[0], column_index[0], row_start[0]);
4119 residuals.
build(dist_pt, 0.0);
4121 #ifdef OOMPH_HAS_MPI
4128 dist_pt, column_index, row_start, value, nnz, res);
4129 jacobian.
build(dist_pt);
4131 dist_pt->
nrow(), nnz[0], value[0], column_index[0], row_start[0]);
4132 residuals.
build(dist_pt, 0.0);
4140 temp_dist_pt, column_index, row_start, value, nnz, res);
4141 jacobian.
build(temp_dist_pt);
4143 dist_pt->
nrow(), nnz[0], value[0], column_index[0], row_start[0]);
4145 residuals.
build(temp_dist_pt, 0.0);
4148 delete temp_dist_pt;
4180 unsigned n_dof =
ndof();
4186 if (residuals.
built())
4190 std::ostringstream error_stream;
4192 <<
"If the DoubleVector residuals is setup then it must not "
4193 <<
"be distributed.";
4195 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4199 std::ostringstream error_stream;
4201 <<
"If the DoubleVector residuals is setup then it must have"
4202 <<
" the correct number of rows";
4204 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4209 std::ostringstream error_stream;
4211 <<
"If the DoubleVector residuals is setup then it must have"
4212 <<
" the same communicator as the problem.";
4214 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4234 bool compressed_row_flag =
false;
4238 if (!residuals.
built())
4248 #ifdef OOMPH_HAS_MPI
4253 row_index, column_start, value, nnz, res, compressed_row_flag);
4255 value[0], row_index[0], column_start[0], nnz[0], n_dof, n_dof);
4256 residuals.
build(dist_pt, 0.0);
4258 #ifdef OOMPH_HAS_MPI
4262 std::ostringstream error_stream;
4263 error_stream <<
"Cannot assemble a CCDoubleMatrix Jacobian on more "
4264 <<
"than one processor.";
4266 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4288 for (
unsigned i = 0;
i < n_global_data;
i++)
4291 const unsigned n_value = local_data_pt->
nvalue();
4292 for (
unsigned j = 0; j < n_value; j++)
4304 if (n_sub_mesh == 0)
4308 for (
unsigned n = 0; n < n_node; n++)
4311 const unsigned n_value = local_node_pt->
nvalue();
4312 for (
unsigned j = 0; j < n_value; j++)
4323 dynamic_cast<SolidNode*
>(local_node_pt);
4325 if (local_solid_node_pt)
4328 const unsigned n_dim = local_solid_node_pt->
ndim();
4330 const unsigned n_position_type =
4333 for (
unsigned k = 0; k < n_position_type; k++)
4335 for (
unsigned i = 0;
i < n_dim;
i++)
4341 local_solid_node_pt->
x_gen(k,
i) = 0.0;
4350 for (
unsigned e = 0;
e < n_element;
e++)
4354 for (
unsigned i = 0;
i < n_internal;
i++)
4357 const unsigned n_value = local_data_pt->
nvalue();
4358 for (
unsigned j = 0; j < n_value; j++)
4372 for (
unsigned m = 0; m < n_sub_mesh; m++)
4376 for (
unsigned n = 0; n < n_node; n++)
4379 const unsigned n_value = local_node_pt->
nvalue();
4380 for (
unsigned j = 0; j < n_value; j++)
4391 dynamic_cast<SolidNode*
>(local_node_pt);
4393 if (local_solid_node_pt)
4396 const unsigned n_dim = local_solid_node_pt->
ndim();
4398 const unsigned n_position_type =
4401 for (
unsigned k = 0; k < n_position_type; k++)
4403 for (
unsigned i = 0;
i < n_dim;
i++)
4409 local_solid_node_pt->
x_gen(k,
i) = 0.0;
4417 const unsigned n_element =
Sub_mesh_pt[m]->nelement();
4418 for (
unsigned e = 0;
e < n_element;
e++)
4423 for (
unsigned i = 0;
i < n_internal;
i++)
4426 const unsigned n_value = local_data_pt->
nvalue();
4427 for (
unsigned j = 0; j < n_value; j++)
4467 bool compressed_row_flag)
4475 column_or_row_index,
4476 row_or_column_start,
4480 compressed_row_flag);
4487 column_or_row_index,
4488 row_or_column_start,
4492 compressed_row_flag);
4499 row_or_column_start,
4503 compressed_row_flag);
4510 column_or_row_index,
4511 row_or_column_start,
4515 compressed_row_flag);
4522 column_or_row_index,
4523 row_or_column_start,
4527 compressed_row_flag);
4533 std::ostringstream error_stream;
4535 <<
"Error: Incorrect value for Problem::Sparse_assembly_method"
4537 <<
"It should be one of the enumeration Problem::Assembly_method"
4540 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4567 bool compressed_row_flag)
4573 unsigned long el_lo = 0;
4574 unsigned long el_hi = n_elements - 1;
4576 #ifdef OOMPH_HAS_MPI
4594 const unsigned n_vector = residuals.size();
4597 const unsigned n_matrix = column_or_row_index.size();
4602 #ifdef OOMPH_HAS_MPI
4603 bool doing_residuals =
false;
4606 doing_residuals =
true;
4612 if (row_or_column_start.size() != n_matrix)
4614 std::ostringstream error_stream;
4615 error_stream <<
"Error: " << std::endl
4616 <<
"row_or_column_start.size() "
4617 << row_or_column_start.size() <<
" does not equal "
4618 <<
"column_or_row_index.size() "
4619 << column_or_row_index.size() << std::endl;
4621 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4624 if (value.size() != n_matrix)
4626 std::ostringstream error_stream;
4628 <<
"Error in Problem::sparse_assemble_row_or_column_compressed "
4630 <<
"value.size() " << value.size() <<
" does not equal "
4631 <<
"column_or_row_index.size() " << column_or_row_index.size()
4636 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4662 for (
unsigned m = 0; m < n_matrix; m++)
4664 matrix_data_map[m].resize(
ndof);
4668 for (
unsigned v = 0; v < n_vector; v++)
4670 residuals[v] =
new double[
ndof];
4671 for (
unsigned i = 0;
i <
ndof;
i++)
4673 residuals[v][
i] = 0;
4678 #ifdef OOMPH_HAS_MPI
4682 double t_assemble_start = 0.0;
4702 for (
unsigned long e = el_lo;
e <= el_hi;
e++)
4704 #ifdef OOMPH_HAS_MPI
4715 #ifdef OOMPH_HAS_MPI
4725 for (
unsigned v = 0; v < n_vector; v++)
4727 el_residuals[v].resize(nvar);
4729 for (
unsigned m = 0; m < n_matrix; m++)
4731 el_jacobian[m].resize(nvar);
4736 elem_pt, el_residuals, el_jacobian);
4741 for (
unsigned i = 0;
i < nvar;
i++)
4747 for (
unsigned v = 0; v < n_vector; v++)
4750 residuals[v][eqn_number] += el_residuals[v][
i];
4754 for (
unsigned j = 0; j < nvar; j++)
4760 for (
unsigned m = 0; m < n_matrix; m++)
4763 double value = el_jacobian[m](
i, j);
4769 if (compressed_row_flag)
4773 matrix_data_map[m][eqn_number][unknown] += value;
4781 matrix_data_map[m][unknown][eqn_number] += value;
4788 #ifdef OOMPH_HAS_MPI
4793 #ifdef OOMPH_HAS_MPI
4807 #ifdef OOMPH_HAS_MPI
4832 for (
unsigned m = 0; m < n_matrix; m++)
4835 row_or_column_start[m] =
new int[
ndof + 1];
4837 unsigned long entry_count = 0;
4838 row_or_column_start[m][0] = entry_count;
4842 for (
unsigned long i_global = 0; i_global <
ndof; i_global++)
4844 nnz[m] += matrix_data_map[m][i_global].size();
4848 column_or_row_index[m] =
new int[nnz[m]];
4849 value[m] =
new double[nnz[m]];
4852 for (
unsigned long i_global = 0; i_global <
ndof; i_global++)
4855 row_or_column_start[m][i_global] = entry_count;
4857 if (matrix_data_map[m][i_global].empty())
4865 for (std::map<unsigned, double>::iterator it =
4866 matrix_data_map[m][i_global].begin();
4867 it != matrix_data_map[m][i_global].end();
4871 column_or_row_index[m][entry_count] = it->first;
4873 value[m][entry_count] = it->second;
4880 row_or_column_start[m][
ndof] = entry_count;
4885 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
4886 pause(
"Check memory usage now.");
4913 bool compressed_row_flag)
4919 unsigned long el_lo = 0;
4920 unsigned long el_hi = n_elements - 1;
4922 #ifdef OOMPH_HAS_MPI
4940 const unsigned n_vector = residuals.size();
4943 const unsigned n_matrix = column_or_row_index.size();
4948 #ifdef OOMPH_HAS_MPI
4949 bool doing_residuals =
false;
4952 doing_residuals =
true;
4958 if (row_or_column_start.size() != n_matrix)
4960 std::ostringstream error_stream;
4961 error_stream <<
"Error: " << std::endl
4962 <<
"row_or_column_start.size() "
4963 << row_or_column_start.size() <<
" does not equal "
4964 <<
"column_or_row_index.size() "
4965 << column_or_row_index.size() << std::endl;
4967 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4970 if (value.size() != n_matrix)
4972 std::ostringstream error_stream;
4974 <<
"Error in Problem::sparse_assemble_row_or_column_compressed "
4976 <<
"value.size() " << value.size() <<
" does not equal "
4977 <<
"column_or_row_index.size() " << column_or_row_index.size()
4982 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5006 for (
unsigned m = 0; m < n_matrix; m++)
5008 matrix_data_list[m].resize(
ndof);
5012 for (
unsigned v = 0; v < n_vector; v++)
5014 residuals[v] =
new double[
ndof];
5015 for (
unsigned i = 0;
i <
ndof;
i++)
5017 residuals[v][
i] = 0;
5021 #ifdef OOMPH_HAS_MPI
5025 double t_assemble_start = 0.0;
5046 std::list<std::pair<unsigned, double>>* list_pt;
5049 for (
unsigned long e = el_lo;
e <= el_hi;
e++)
5051 #ifdef OOMPH_HAS_MPI
5062 #ifdef OOMPH_HAS_MPI
5072 for (
unsigned v = 0; v < n_vector; v++)
5074 el_residuals[v].resize(nvar);
5076 for (
unsigned m = 0; m < n_matrix; m++)
5078 el_jacobian[m].resize(nvar);
5083 elem_pt, el_residuals, el_jacobian);
5088 for (
unsigned i = 0;
i < nvar;
i++)
5094 for (
unsigned v = 0; v < n_vector; v++)
5097 residuals[v][eqn_number] += el_residuals[v][
i];
5101 for (
unsigned j = 0; j < nvar; j++)
5107 for (
unsigned m = 0; m < n_matrix; m++)
5110 double value = el_jacobian[m](
i, j);
5116 if (compressed_row_flag)
5119 list_pt = &matrix_data_list[m][eqn_number];
5123 list_pt->insert(list_pt->end(),
5124 std::make_pair(unknown, value));
5131 list_pt = &matrix_data_list[m][unknown];
5135 list_pt->insert(list_pt->end(),
5136 std::make_pair(eqn_number, value));
5143 #ifdef OOMPH_HAS_MPI
5148 #ifdef OOMPH_HAS_MPI
5162 #ifdef OOMPH_HAS_MPI
5187 for (
unsigned m = 0; m < n_matrix; m++)
5190 row_or_column_start[m] =
new int[
ndof + 1];
5192 unsigned long entry_count = 0;
5194 row_or_column_start[m][0] = entry_count;
5198 for (
unsigned long i_global = 0; i_global <
ndof; i_global++)
5200 nnz[m] += matrix_data_list[m][i_global].size();
5204 column_or_row_index[m] =
new int[nnz[m]];
5205 value[m] =
new double[nnz[m]];
5208 for (
unsigned long i_global = 0; i_global <
ndof; i_global++)
5211 row_or_column_start[m][i_global] = entry_count;
5213 if (matrix_data_list[m][i_global].empty())
5224 matrix_data_list[m][i_global].sort();
5227 std::list<std::pair<unsigned, double>>::iterator it =
5228 matrix_data_list[m][i_global].begin();
5231 unsigned current_index = it->first;
5233 double current_value = it->second;
5237 for (++it; it != matrix_data_list[m][i_global].end(); ++it)
5242 if ((it->first == current_index) &&
5245 current_value += it->second;
5252 column_or_row_index[m][entry_count] = current_index;
5254 value[m][entry_count] = current_value;
5260 current_index = it->first;
5261 current_value = it->second;
5277 if ((
static_cast<int>(entry_count) == row_or_column_start[m][i_global])
5281 || (
static_cast<int>(current_index) !=
5282 column_or_row_index[m][entry_count - 1]))
5285 column_or_row_index[m][entry_count] = current_index;
5287 value[m][entry_count] = current_value;
5295 row_or_column_start[m][
ndof] = entry_count;
5300 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
5301 pause(
"Check memory usage now.");
5328 bool compressed_row_flag)
5334 unsigned long el_lo = 0;
5335 unsigned long el_hi = n_elements - 1;
5337 #ifdef OOMPH_HAS_MPI
5355 const unsigned n_vector = residuals.size();
5358 const unsigned n_matrix = column_or_row_index.size();
5363 #ifdef OOMPH_HAS_MPI
5364 bool doing_residuals =
false;
5367 doing_residuals =
true;
5373 if (row_or_column_start.size() != n_matrix)
5375 std::ostringstream error_stream;
5376 error_stream <<
"Error: " << std::endl
5377 <<
"row_or_column_start.size() "
5378 << row_or_column_start.size() <<
" does not equal "
5379 <<
"column_or_row_index.size() "
5380 << column_or_row_index.size() << std::endl;
5382 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5385 if (value.size() != n_matrix)
5387 std::ostringstream error_stream;
5388 error_stream <<
"Error: " << std::endl
5389 <<
"value.size() " << value.size() <<
" does not equal "
5390 <<
"column_or_row_index.size() "
5391 << column_or_row_index.size() << std::endl
5395 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5411 for (
unsigned m = 0; m < n_matrix; m++)
5413 matrix_data[m].resize(
ndof);
5417 for (
unsigned v = 0; v < n_vector; v++)
5419 residuals[v] =
new double[
ndof];
5420 for (
unsigned i = 0;
i <
ndof;
i++)
5422 residuals[v][
i] = 0;
5426 #ifdef OOMPH_HAS_MPI
5429 double t_assemble_start = 0.0;
5449 for (
unsigned long e = el_lo;
e <= el_hi;
e++)
5451 #ifdef OOMPH_HAS_MPI
5462 #ifdef OOMPH_HAS_MPI
5472 for (
unsigned v = 0; v < n_vector; v++)
5474 el_residuals[v].resize(nvar);
5476 for (
unsigned m = 0; m < n_matrix; m++)
5478 el_jacobian[m].resize(nvar);
5483 elem_pt, el_residuals, el_jacobian);
5488 for (
unsigned i = 0;
i < nvar;
i++)
5494 for (
unsigned v = 0; v < n_vector; v++)
5497 residuals[v][eqn_number] += el_residuals[v][
i];
5501 for (
unsigned j = 0; j < nvar; j++)
5509 for (
unsigned m = 0; m < n_matrix; m++)
5512 double value = el_jacobian[m](
i, j);
5518 if (compressed_row_flag)
5522 const unsigned size = matrix_data[m][eqn_number].size();
5523 for (
unsigned k = 0; k <= size; k++)
5527 matrix_data[m][eqn_number].push_back(
5528 std::make_pair(unknown, value));
5531 else if (matrix_data[m][eqn_number][k].first == unknown)
5533 matrix_data[m][eqn_number][k].second += value;
5543 const unsigned size = matrix_data[m][unknown].size();
5544 for (
unsigned k = 0; k <= size; k++)
5548 matrix_data[m][unknown].push_back(
5549 std::make_pair(eqn_number, value));
5552 else if (matrix_data[m][unknown][k].first == eqn_number)
5554 matrix_data[m][unknown][k].second += value;
5564 #ifdef OOMPH_HAS_MPI
5569 #ifdef OOMPH_HAS_MPI
5584 #ifdef OOMPH_HAS_MPI
5609 for (
unsigned m = 0; m < n_matrix; m++)
5612 row_or_column_start[m] =
new int[
ndof + 1];
5615 row_or_column_start[m][0] = 0;
5616 for (
unsigned long i = 0;
i <
ndof;
i++)
5618 row_or_column_start[m][
i + 1] =
5619 row_or_column_start[m][
i] + matrix_data[m][
i].size();
5621 const unsigned entries = row_or_column_start[m][
ndof];
5624 column_or_row_index[m] =
new int[entries];
5625 value[m] =
new double[entries];
5629 for (
unsigned long i_global = 0; i_global <
ndof; i_global++)
5632 if (matrix_data[m][i_global].empty())
5640 for (
int j = row_or_column_start[m][i_global];
5641 j < row_or_column_start[m][i_global + 1];
5644 column_or_row_index[m][j] = matrix_data[m][i_global][p].first;
5645 value[m][j] = matrix_data[m][i_global][p].second;
5653 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
5654 pause(
"Check memory usage now.");
5681 bool compressed_row_flag)
5687 unsigned long el_lo = 0;
5688 unsigned long el_hi = n_elements - 1;
5691 #ifdef OOMPH_HAS_MPI
5709 const unsigned n_vector = residuals.size();
5712 const unsigned n_matrix = column_or_row_index.size();
5717 #ifdef OOMPH_HAS_MPI
5718 bool doing_residuals =
false;
5721 doing_residuals =
true;
5727 if (row_or_column_start.size() != n_matrix)
5729 std::ostringstream error_stream;
5730 error_stream <<
"Error: " << std::endl
5731 <<
"row_or_column_start.size() "
5732 << row_or_column_start.size() <<
" does not equal "
5733 <<
"column_or_row_index.size() "
5734 << column_or_row_index.size() << std::endl;
5736 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5739 if (value.size() != n_matrix)
5741 std::ostringstream error_stream;
5742 error_stream <<
"Error: " << std::endl
5743 <<
"value.size() " << value.size() <<
" does not equal "
5744 <<
"column_or_row_index.size() "
5745 << column_or_row_index.size() << std::endl
5749 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5767 for (
unsigned m = 0; m < n_matrix; m++)
5769 matrix_row_or_col_indices[m].resize(
ndof);
5770 matrix_values[m].resize(
ndof);
5774 for (
unsigned v = 0; v < n_vector; v++)
5776 residuals[v] =
new double[
ndof];
5777 for (
unsigned i = 0;
i <
ndof;
i++)
5779 residuals[v][
i] = 0;
5783 #ifdef OOMPH_HAS_MPI
5786 double t_assemble_start = 0.0;
5807 for (
unsigned long e = el_lo;
e <= el_hi;
e++)
5809 #ifdef OOMPH_HAS_MPI
5820 #ifdef OOMPH_HAS_MPI
5830 for (
unsigned v = 0; v < n_vector; v++)
5832 el_residuals[v].resize(nvar);
5834 for (
unsigned m = 0; m < n_matrix; m++)
5836 el_jacobian[m].resize(nvar);
5841 elem_pt, el_residuals, el_jacobian);
5846 for (
unsigned i = 0;
i < nvar;
i++)
5852 for (
unsigned v = 0; v < n_vector; v++)
5855 residuals[v][eqn_number] += el_residuals[v][
i];
5859 for (
unsigned j = 0; j < nvar; j++)
5867 for (
unsigned m = 0; m < n_matrix; m++)
5870 double value = el_jacobian[m](
i, j);
5876 if (compressed_row_flag)
5880 const unsigned size =
5881 matrix_row_or_col_indices[m][eqn_number].size();
5883 for (
unsigned k = 0; k <= size; k++)
5887 matrix_row_or_col_indices[m][eqn_number].push_back(
5889 matrix_values[m][eqn_number].push_back(value);
5892 else if (matrix_row_or_col_indices[m][eqn_number][k] ==
5895 matrix_values[m][eqn_number][k] += value;
5905 const unsigned size =
5906 matrix_row_or_col_indices[m][unknown].size();
5907 for (
unsigned k = 0; k <= size; k++)
5911 matrix_row_or_col_indices[m][unknown].push_back(
5913 matrix_values[m][unknown].push_back(value);
5916 else if (matrix_row_or_col_indices[m][unknown][k] ==
5919 matrix_values[m][unknown][k] += value;
5929 #ifdef OOMPH_HAS_MPI
5934 #ifdef OOMPH_HAS_MPI
5948 #ifdef OOMPH_HAS_MPI
5972 for (
unsigned m = 0; m < n_matrix; m++)
5975 row_or_column_start[m] =
new int[
ndof + 1];
5978 row_or_column_start[m][0] = 0;
5979 for (
unsigned long i = 0;
i <
ndof;
i++)
5981 row_or_column_start[m][
i + 1] =
5982 row_or_column_start[m][
i] + matrix_values[m][
i].size();
5984 const unsigned entries = row_or_column_start[m][
ndof];
5987 column_or_row_index[m] =
new int[entries];
5988 value[m] =
new double[entries];
5992 for (
unsigned long i_global = 0; i_global <
ndof; i_global++)
5995 if (matrix_values[m][i_global].empty())
6003 for (
int j = row_or_column_start[m][i_global];
6004 j < row_or_column_start[m][i_global + 1];
6007 column_or_row_index[m][j] = matrix_row_or_col_indices[m][i_global][p];
6008 value[m][j] = matrix_values[m][i_global][p];
6016 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
6017 pause(
"Check memory usage now.");
6044 bool compressed_row_flag)
6050 unsigned long el_lo = 0;
6051 unsigned long el_hi = n_elements - 1;
6054 #ifdef OOMPH_HAS_MPI
6072 const unsigned n_vector = residuals.size();
6075 const unsigned n_matrix = column_or_row_index.size();
6080 #ifdef OOMPH_HAS_MPI
6081 bool doing_residuals =
false;
6084 doing_residuals =
true;
6090 if (row_or_column_start.size() != n_matrix)
6092 std::ostringstream error_stream;
6093 error_stream <<
"Error: " << std::endl
6094 <<
"row_or_column_start.size() "
6095 << row_or_column_start.size() <<
" does not equal "
6096 <<
"column_or_row_index.size() "
6097 << column_or_row_index.size() << std::endl;
6099 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
6102 if (value.size() != n_matrix)
6104 std::ostringstream error_stream;
6105 error_stream <<
"Error: " << std::endl
6106 <<
"value.size() " << value.size() <<
" does not equal "
6107 <<
"column_or_row_index.size() "
6108 << column_or_row_index.size() << std::endl
6112 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
6130 for (
unsigned m = 0; m < n_matrix; m++)
6132 matrix_row_or_col_indices[m] =
new unsigned*[
ndof];
6133 matrix_values[m] =
new double*[
ndof];
6137 for (
unsigned v = 0; v < n_vector; v++)
6139 residuals[v] =
new double[
ndof];
6140 for (
unsigned i = 0;
i <
ndof;
i++)
6142 residuals[v][
i] = 0;
6146 #ifdef OOMPH_HAS_MPI
6149 double t_assemble_start = 0.0;
6161 for (
unsigned m = 0; m < n_matrix; m++)
6163 ncoef[m].resize(
ndof, 0);
6169 for (
unsigned m = 0; m < n_matrix; m++)
6185 for (
unsigned long e = el_lo;
e <= el_hi;
e++)
6187 #ifdef OOMPH_HAS_MPI
6198 #ifdef OOMPH_HAS_MPI
6208 for (
unsigned v = 0; v < n_vector; v++)
6210 el_residuals[v].resize(nvar);
6212 for (
unsigned m = 0; m < n_matrix; m++)
6214 el_jacobian[m].resize(nvar);
6219 elem_pt, el_residuals, el_jacobian);
6224 for (
unsigned i = 0;
i < nvar;
i++)
6230 for (
unsigned v = 0; v < n_vector; v++)
6233 residuals[v][eqn_number] += el_residuals[v][
i];
6237 for (
unsigned j = 0; j < nvar; j++)
6245 for (
unsigned m = 0; m < n_matrix; m++)
6248 double value = el_jacobian[m](
i, j);
6253 const unsigned size = ncoef[m][eqn_number];
6260 [m][eqn_number] != 0)
6262 matrix_row_or_col_indices[m][eqn_number] =
new unsigned
6265 matrix_values[m][eqn_number] =
new double
6271 matrix_row_or_col_indices[m][eqn_number] =
new unsigned
6273 matrix_values[m][eqn_number] =
new double
6283 if (compressed_row_flag)
6286 for (
unsigned k = 0; k <= size; k++)
6292 [m][eqn_number] == ncoef[m][eqn_number])
6294 unsigned new_allocation =
6295 ncoef[m][eqn_number] +
6297 double* new_values =
new double[new_allocation];
6298 unsigned* new_indices =
new unsigned[new_allocation];
6299 for (
unsigned c = 0; c < ncoef[m][eqn_number]; c++)
6301 new_values[c] = matrix_values[m][eqn_number][c];
6303 matrix_row_or_col_indices[m][eqn_number][c];
6305 delete[] matrix_values[m][eqn_number];
6306 delete[] matrix_row_or_col_indices[m][eqn_number];
6307 matrix_values[m][eqn_number] = new_values;
6308 matrix_row_or_col_indices[m][eqn_number] =
6311 [m][eqn_number] = new_allocation;
6314 unsigned entry = ncoef[m][eqn_number];
6315 ncoef[m][eqn_number]++;
6316 matrix_row_or_col_indices[m][eqn_number][entry] =
6318 matrix_values[m][eqn_number][entry] = value;
6321 else if (matrix_row_or_col_indices[m][eqn_number][k] ==
6324 matrix_values[m][eqn_number][k] += value;
6334 for (
unsigned k = 0; k <= size; k++)
6340 [m][unknown] == ncoef[m][unknown])
6342 unsigned new_allocation =
6345 double* new_values =
new double[new_allocation];
6346 unsigned* new_indices =
new unsigned[new_allocation];
6347 for (
unsigned c = 0; c < ncoef[m][unknown]; c++)
6349 new_values[c] = matrix_values[m][unknown][c];
6351 matrix_row_or_col_indices[m][unknown][c];
6353 delete[] matrix_values[m][unknown];
6354 delete[] matrix_row_or_col_indices[m][unknown];
6356 [m][unknown] = new_allocation;
6359 unsigned entry = ncoef[m][unknown];
6360 ncoef[m][unknown]++;
6361 matrix_row_or_col_indices[m][unknown][entry] =
6363 matrix_values[m][unknown][entry] = value;
6366 else if (matrix_row_or_col_indices[m][unknown][k] ==
6369 matrix_values[m][unknown][k] += value;
6379 #ifdef OOMPH_HAS_MPI
6384 #ifdef OOMPH_HAS_MPI
6398 #ifdef OOMPH_HAS_MPI
6422 for (
unsigned m = 0; m < n_matrix; m++)
6425 row_or_column_start[m] =
new int[
ndof + 1];
6428 row_or_column_start[m][0] = 0;
6429 for (
unsigned long i = 0;
i <
ndof;
i++)
6431 row_or_column_start[m][
i + 1] = row_or_column_start[m][
i] + ncoef[m][
i];
6434 const unsigned entries = row_or_column_start[m][
ndof];
6437 column_or_row_index[m] =
new int[entries];
6438 value[m] =
new double[entries];
6442 for (
unsigned long i_global = 0; i_global <
ndof; i_global++)
6445 if (ncoef[m][i_global] == 0)
6453 for (
int j = row_or_column_start[m][i_global];
6454 j < row_or_column_start[m][i_global + 1];
6457 column_or_row_index[m][j] = matrix_row_or_col_indices[m][i_global][p];
6458 value[m][j] = matrix_values[m][i_global][p];
6463 delete[] matrix_row_or_col_indices[m][i_global];
6464 delete[] matrix_values[m][i_global];
6468 delete[] matrix_row_or_col_indices[m];
6469 delete[] matrix_values[m];
6474 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
6475 pause(
"Check memory usage now.");
6480 #ifdef OOMPH_HAS_MPI
6487 const unsigned& el_lo,
6488 const unsigned& el_hi,
6492 unsigned my_eqns_index = 0;
6495 for (
unsigned long e = el_lo;
e <= el_hi;
e++)
6506 my_eqns.resize(my_eqns_index + nvar);
6509 for (
unsigned i = 0;
i < nvar;
i++)
6512 unsigned global_eqn_number =
6515 my_eqns[my_eqns_index +
i] = global_eqn_number;
6518 my_eqns_index += nvar;
6523 std::sort(my_eqns.begin(), my_eqns.end());
6525 my_eqns.resize(it - my_eqns.begin());
6556 if (n_elements == 0)
6558 std::ostringstream error_stream;
6559 error_stream <<
"Processsor " << my_rank <<
" has no elements. \n"
6560 <<
"This is usually a sign that the problem distribution \n"
6561 <<
"or the load balancing have gone wrong.";
6563 "Problem::parallel_sparse_assemble()",
6564 OOMPH_EXCEPTION_LOCATION);
6570 unsigned long el_lo = 0;
6571 unsigned long el_hi_plus_one = n_elements;
6586 const unsigned n_vector = residuals.size();
6589 const unsigned n_matrix = column_indices.size();
6594 bool doing_residuals =
false;
6597 doing_residuals =
true;
6602 if (row_start.size() != n_matrix)
6604 std::ostringstream error_stream;
6605 error_stream <<
"Error: " << std::endl
6606 <<
"row_or_column_start.size() " << row_start.size()
6607 <<
" does not equal "
6608 <<
"column_or_row_index.size() " << column_indices.size()
6611 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
6614 if (values.size() != n_matrix)
6616 std::ostringstream error_stream;
6617 error_stream <<
"Error: " << std::endl
6618 <<
"value.size() " << values.size() <<
" does not equal "
6619 <<
"column_or_row_index.size() " << column_indices.size()
6624 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
6636 if (n_elements != 0)
6639 assembly_handler_pt, el_lo, el_hi_plus_one - 1, my_eqns);
6643 unsigned my_n_eqn = my_eqns.size();
6659 for (
unsigned m = 0; m < n_matrix; m++)
6661 matrix_col_indices[m] =
new unsigned*[my_n_eqn];
6662 matrix_values[m] =
new double*[my_n_eqn];
6663 for (
unsigned i = 0;
i < my_n_eqn;
i++)
6665 matrix_col_indices[m][
i] = 0;
6666 matrix_values[m][
i] = 0;
6672 for (
unsigned v = 0; v < n_vector; v++)
6674 residuals_data[v] =
new double[my_n_eqn];
6675 for (
unsigned i = 0;
i < my_n_eqn;
i++)
6677 residuals_data[v][
i] = 0;
6682 double t_assemble_start = 0.0;
6692 for (
unsigned m = 0; m < n_matrix; m++)
6694 ncoef[m].resize(my_n_eqn, 0);
6704 for (
unsigned m = 0; m < n_matrix; m++)
6721 for (
unsigned long e = el_lo;
e < el_hi_plus_one;
e++)
6739 for (
unsigned v = 0; v < n_vector; v++)
6741 el_residuals[v].resize(nvar);
6743 for (
unsigned m = 0; m < n_matrix; m++)
6745 el_jacobian[m].resize(nvar);
6750 elem_pt, el_residuals, el_jacobian);
6755 for (
unsigned i = 0;
i < nvar;
i++)
6758 unsigned global_eqn_number =
6764 int right = my_n_eqn - 1;
6765 int eqn_number = right / 2;
6766 while (my_eqns[eqn_number] != global_eqn_number)
6772 bool broken =
false;
6773 for (
unsigned v = 0; v < n_vector; v++)
6775 if (el_residuals[v][
i] != 0.0)
6784 for (
unsigned j = 0; j < nvar; j++)
6793 for (
unsigned m = 0; m < n_matrix; m++)
6796 double value = el_jacobian[m](
i, j);
6808 std::ostringstream error_stream;
6810 <<
"Internal Error: " << std::endl
6811 <<
"Could not find global equation number "
6812 << global_eqn_number
6813 <<
" in my_eqns vector of equation numbers but\n"
6814 <<
"at least one entry in the residual vector is nonzero.";
6816 OOMPH_CURRENT_FUNCTION,
6817 OOMPH_EXCEPTION_LOCATION);
6824 if (my_eqns[eqn_number] > global_eqn_number)
6826 right = std::max(eqn_number - 1, left);
6830 left = std::min(eqn_number + 1, right);
6832 eqn_number = (right + left) / 2;
6836 for (
unsigned v = 0; v < n_vector; v++)
6839 residuals_data[v][eqn_number] += el_residuals[v][
i];
6843 for (
unsigned j = 0; j < nvar; j++)
6851 for (
unsigned m = 0; m < n_matrix; m++)
6854 double value = el_jacobian[m](
i, j);
6859 const unsigned size = ncoef[m][eqn_number];
6866 [m][eqn_number] != 0)
6868 matrix_col_indices[m][eqn_number] =
new unsigned
6872 matrix_values[m][eqn_number] =
new double
6878 matrix_col_indices[m][eqn_number] =
new unsigned
6881 matrix_values[m][eqn_number] =
new double
6891 for (
unsigned k = 0; k <= size; k++)
6897 [m][eqn_number] == ncoef[m][eqn_number])
6899 unsigned new_allocation =
6900 ncoef[m][eqn_number] +
6902 double* new_values =
new double[new_allocation];
6903 unsigned* new_indices =
new unsigned[new_allocation];
6904 for (
unsigned c = 0; c < ncoef[m][eqn_number]; c++)
6906 new_values[c] = matrix_values[m][eqn_number][c];
6907 new_indices[c] = matrix_col_indices[m][eqn_number][c];
6909 delete[] matrix_values[m][eqn_number];
6910 delete[] matrix_col_indices[m][eqn_number];
6912 matrix_values[m][eqn_number] = new_values;
6913 matrix_col_indices[m][eqn_number] = new_indices;
6916 [m][eqn_number] = new_allocation;
6919 unsigned entry = ncoef[m][eqn_number];
6920 ncoef[m][eqn_number]++;
6921 matrix_col_indices[m][eqn_number][entry] = unknown;
6922 matrix_values[m][eqn_number][entry] = value;
6925 else if (matrix_col_indices[m][eqn_number][k] == unknown)
6927 matrix_values[m][eqn_number][k] += value;
6949 double t_local = 0.0;
6956 t_local = t_end - t_start;
6960 MPI_Allreduce(&t_local,
6966 MPI_Allreduce(&t_local,
6972 MPI_Allreduce(&t_local,
6978 double imbalance = (t_max - t_min) / (t_sum /
double(nproc)) * 100.0;
6980 if (doing_residuals)
6982 oomph_info <<
"\nCPU for residual computation (loc/max/min/imbal): ";
6986 oomph_info <<
"\nCPU for Jacobian computation (loc/max/min/imbal): ";
6988 oomph_info << t_local <<
" " << t_max <<
" " << t_min <<
" " << imbalance
6996 for (
unsigned m = 0; m < n_matrix; m++)
6999 unsigned min = INT_MAX;
7001 unsigned sum_total = 0;
7002 for (
unsigned e = 0;
e < my_n_eqn;
e++)
7006 if (ncoef[m][
e] > max) max = ncoef[m][
e];
7007 if (ncoef[m][
e] < min) min = ncoef[m][
e];
7010 unsigned new_allocation = ncoef[m][
e];
7011 double* new_values =
new double[new_allocation];
7012 unsigned* new_indices =
new unsigned[new_allocation];
7013 for (
unsigned c = 0; c < ncoef[m][
e]; c++)
7015 new_values[c] = matrix_values[m][
e][c];
7016 new_indices[c] = matrix_col_indices[m][
e][c];
7018 delete[] matrix_values[m][
e];
7019 delete[] matrix_col_indices[m][
e];
7021 matrix_values[m][
e] = new_values;
7022 matrix_col_indices[m][
e] = new_indices;
7055 first_eqn_element_for_proc[current_p] = 0;
7056 n_eqn_for_proc[current_p] = 1;
7057 for (
unsigned i = 1;
i < my_n_eqn;
i++)
7060 if (next_p != current_p)
7063 first_eqn_element_for_proc[current_p] =
i;
7065 n_eqn_for_proc[current_p]++;
7072 for (
unsigned p = 0; p < nproc; p++)
7074 int first_eqn_element = first_eqn_element_for_proc[p];
7075 int last_eqn_element = (int)(first_eqn_element + n_eqn_for_proc[p]) - 1;
7076 for (
unsigned m = 0; m < n_matrix; m++)
7078 for (
int i = first_eqn_element;
i <= last_eqn_element;
i++)
7080 nnz_for_proc(p, m) += ncoef[m][
i];
7090 for (
unsigned p = 0; p < nproc; p++)
7094 temp_send_storage[p] =
new unsigned[n_matrix + 1];
7095 temp_send_storage[p][0] = n_eqn_for_proc[p];
7096 for (
unsigned m = 0; m < n_matrix; m++)
7098 temp_send_storage[p][m + 1] = nnz_for_proc(p, m);
7101 MPI_Isend(temp_send_storage[p],
7108 send_nnz_reqs.push_back(sreq);
7109 temp_recv_storage[p] =
new unsigned[n_matrix + 1];
7111 MPI_Irecv(temp_recv_storage[p],
7118 recv_nnz_reqs.push_back(rreq);
7133 for (
unsigned p = 0; p < nproc; p++)
7135 unsigned n_eqns_p = n_eqn_for_proc[p];
7138 unsigned first_eqn_element = first_eqn_element_for_proc[p];
7139 unsigned first_row = target_dist_pt->
first_row(p);
7140 eqns_for_proc[p] =
new unsigned[n_eqns_p];
7141 for (
unsigned i = 0;
i < n_eqns_p;
i++)
7143 eqns_for_proc[p][
i] = my_eqns[
i + first_eqn_element] - first_row;
7149 for (
unsigned v = 0; v < n_vector; v++)
7151 for (
unsigned p = 0; p < nproc; p++)
7153 unsigned n_eqns_p = n_eqn_for_proc[p];
7156 unsigned first_eqn_element = first_eqn_element_for_proc[p];
7157 residuals_for_proc(p, v) =
new double[n_eqns_p];
7158 for (
unsigned i = 0;
i < n_eqns_p;
i++)
7160 residuals_for_proc(p, v)[
i] =
7161 residuals_data[v][first_eqn_element +
i];
7165 delete[] residuals_data[v];
7169 for (
unsigned m = 0; m < n_matrix; m++)
7171 for (
unsigned p = 0; p < nproc; p++)
7173 unsigned n_eqns_p = n_eqn_for_proc[p];
7176 unsigned first_eqn_element = first_eqn_element_for_proc[p];
7177 row_start_for_proc(p, m) =
new unsigned[n_eqns_p + 1];
7178 column_indices_for_proc(p, m) =
new unsigned[nnz_for_proc(p, m)];
7179 values_for_proc(p, m) =
new double[nnz_for_proc(p, m)];
7181 for (
unsigned i = 0;
i < n_eqns_p;
i++)
7183 row_start_for_proc(p, m)[
i] = entry;
7184 unsigned n_coef_in_row = ncoef[m][first_eqn_element +
i];
7185 for (
unsigned j = 0; j < n_coef_in_row; j++)
7187 column_indices_for_proc(p, m)[entry] =
7188 matrix_col_indices[m][
i + first_eqn_element][j];
7189 values_for_proc(p, m)[entry] =
7190 matrix_values[m][
i + first_eqn_element][j];
7194 row_start_for_proc(p, m)[n_eqns_p] = entry;
7197 for (
unsigned i = 0;
i < my_n_eqn;
i++)
7199 delete[] matrix_col_indices[m][
i];
7200 delete[] matrix_values[m][
i];
7202 delete[] matrix_col_indices[m];
7203 delete[] matrix_values[m];
7214 MPI_Waitall(nproc - 1, &recv_nnz_reqs[0], &recv_nnz_stat[0]);
7217 for (
unsigned p = 0; p < nproc; p++)
7221 n_eqn_from_proc[p] = temp_recv_storage[p][0];
7222 for (
unsigned m = 0; m < n_matrix; m++)
7224 nnz_from_proc(p, m) = temp_recv_storage[p][m + 1];
7226 delete[] temp_recv_storage[p];
7230 n_eqn_from_proc[p] = n_eqn_for_proc[p];
7231 for (
unsigned m = 0; m < n_matrix; m++)
7233 nnz_from_proc(p, m) = nnz_for_proc(p, m);
7237 recv_nnz_stat.clear();
7238 recv_nnz_reqs.clear();
7252 MPI_Aint communication_base;
7253 MPI_Get_address(&base, &communication_base);
7254 unsigned n_comm_types = 1 + 1 * n_vector + 3 * n_matrix;
7257 for (
unsigned p = 0; p < nproc; p++)
7262 if (n_eqn_from_proc[p] > 0)
7264 eqns_from_proc[p] =
new unsigned[n_eqn_from_proc[p]];
7265 for (
unsigned v = 0; v < n_vector; v++)
7267 residuals_from_proc(p, v) =
new double[n_eqn_from_proc[p]];
7269 for (
unsigned m = 0; m < n_matrix; m++)
7271 row_start_from_proc(p, m) =
new unsigned[n_eqn_from_proc[p] + 1];
7272 column_indices_from_proc(p, m) =
new unsigned[nnz_from_proc(p, m)];
7273 values_from_proc(p, m) =
new double[nnz_from_proc(p, m)];
7278 if (n_eqn_from_proc[p] > 0)
7280 MPI_Datatype types[n_comm_types];
7281 MPI_Aint offsets[n_comm_types];
7282 int count[n_comm_types];
7287 MPI_Get_address(eqns_from_proc[p], &offsets[pt]);
7288 offsets[pt] -= communication_base;
7289 MPI_Type_contiguous(n_eqn_from_proc[p], MPI_UNSIGNED, &types[pt]);
7290 MPI_Type_commit(&types[pt]);
7294 for (
unsigned v = 0; v < n_vector; v++)
7297 MPI_Get_address(residuals_from_proc(p, v), &offsets[pt]);
7298 offsets[pt] -= communication_base;
7299 MPI_Type_contiguous(n_eqn_from_proc[p], MPI_DOUBLE, &types[pt]);
7300 MPI_Type_commit(&types[pt]);
7305 for (
unsigned m = 0; m < n_matrix; m++)
7309 MPI_Get_address(row_start_from_proc(p, m), &offsets[pt]);
7310 offsets[pt] -= communication_base;
7311 MPI_Type_contiguous(
7312 n_eqn_from_proc[p] + 1, MPI_UNSIGNED, &types[pt]);
7313 MPI_Type_commit(&types[pt]);
7319 MPI_Get_address(column_indices_from_proc(p, m), &offsets[pt]);
7320 offsets[pt] -= communication_base;
7321 MPI_Type_contiguous(nnz_from_proc(p, m), MPI_UNSIGNED, &types[pt]);
7322 MPI_Type_commit(&types[pt]);
7327 MPI_Get_address(values_from_proc(p, m), &offsets[pt]);
7328 offsets[pt] -= communication_base;
7329 MPI_Type_contiguous(nnz_from_proc(p, m), MPI_DOUBLE, &types[pt]);
7330 MPI_Type_commit(&types[pt]);
7335 MPI_Datatype recv_type;
7336 MPI_Type_create_struct(
7337 n_comm_types, count, offsets, types, &recv_type);
7338 MPI_Type_commit(&recv_type);
7339 for (
unsigned t = 0;
t < n_comm_types;
t++)
7341 MPI_Type_free(&types[
t]);
7346 MPI_Type_free(&recv_type);
7347 recv_reqs.push_back(req);
7351 if (n_eqn_for_proc[p] > 0)
7353 MPI_Datatype types[n_comm_types];
7354 MPI_Aint offsets[n_comm_types];
7355 int count[n_comm_types];
7360 MPI_Get_address(eqns_for_proc[p], &offsets[pt]);
7361 offsets[pt] -= communication_base;
7362 MPI_Type_contiguous(n_eqn_for_proc[p], MPI_UNSIGNED, &types[pt]);
7363 MPI_Type_commit(&types[pt]);
7367 for (
unsigned v = 0; v < n_vector; v++)
7370 MPI_Get_address(residuals_for_proc(p, v), &offsets[pt]);
7371 offsets[pt] -= communication_base;
7372 MPI_Type_contiguous(n_eqn_for_proc[p], MPI_DOUBLE, &types[pt]);
7373 MPI_Type_commit(&types[pt]);
7378 for (
unsigned m = 0; m < n_matrix; m++)
7382 MPI_Get_address(row_start_for_proc(p, m), &offsets[pt]);
7383 offsets[pt] -= communication_base;
7384 MPI_Type_contiguous(
7385 n_eqn_for_proc[p] + 1, MPI_UNSIGNED, &types[pt]);
7386 MPI_Type_commit(&types[pt]);
7392 MPI_Get_address(column_indices_for_proc(p, m), &offsets[pt]);
7393 offsets[pt] -= communication_base;
7394 MPI_Type_contiguous(nnz_for_proc(p, m), MPI_UNSIGNED, &types[pt]);
7395 MPI_Type_commit(&types[pt]);
7400 MPI_Get_address(values_for_proc(p, m), &offsets[pt]);
7401 offsets[pt] -= communication_base;
7402 MPI_Type_contiguous(nnz_for_proc(p, m), MPI_DOUBLE, &types[pt]);
7403 MPI_Type_commit(&types[pt]);
7408 MPI_Datatype send_type;
7409 MPI_Type_create_struct(
7410 n_comm_types, count, offsets, types, &send_type);
7411 MPI_Type_commit(&send_type);
7412 for (
unsigned t = 0;
t < n_comm_types;
t++)
7414 MPI_Type_free(&types[
t]);
7419 MPI_Type_free(&send_type);
7420 send_reqs.push_back(req);
7426 eqns_from_proc[p] = eqns_for_proc[p];
7427 for (
unsigned v = 0; v < n_vector; v++)
7429 residuals_from_proc(p, v) = residuals_for_proc(p, v);
7431 for (
unsigned m = 0; m < n_matrix; m++)
7433 row_start_from_proc(p, m) = row_start_for_proc(p, m);
7434 column_indices_from_proc(p, m) = column_indices_for_proc(p, m);
7435 values_from_proc(p, m) = values_for_proc(p, m);
7441 unsigned n_recv_req = recv_reqs.size();
7445 MPI_Waitall(n_recv_req, &recv_reqs[0], &recv_stat[0]);
7449 unsigned target_nrow_local = target_dist_pt->
nrow_local();
7452 for (
unsigned m = 0; m < n_matrix; m++)
7455 row_start[m] =
new int[target_nrow_local + 1];
7456 row_start[m][0] = 0;
7461 for (
unsigned p = 0; p < nproc; p++)
7463 nnz_allocation = std::max(nnz_allocation, nnz_from_proc(p, m));
7466 values_chunk[0] =
new double[nnz_allocation];
7468 column_indices_chunk[0] =
new int[nnz_allocation];
7471 size_of_chunk[0] = nnz_allocation;
7472 unsigned current_chunk = 0;
7475 for (
unsigned i = 0;
i < target_nrow_local;
i++)
7477 row_start[m][
i] = 0;
7481 for (
unsigned p = 0; p < nproc; p++)
7483 if (n_eqn_from_proc[p] == 0)
7485 row_on_proc[p] = -1;
7490 int right = n_eqn_from_proc[p] - 1;
7491 int midpoint = right / 2;
7492 bool complete =
false;
7495 midpoint = (right + left) / 2;
7496 if (midpoint > right)
7500 if (midpoint < left)
7506 if (eqns_from_proc[p][midpoint] ==
i)
7516 else if (eqns_from_proc[p][midpoint] ==
i)
7520 else if (eqns_from_proc[p][midpoint] >
i)
7522 right = std::max(midpoint - 1, left);
7526 left = std::min(midpoint + 1, right);
7529 row_on_proc[p] = midpoint;
7534 unsigned check_first = ncoef_in_chunk[current_chunk];
7535 unsigned check_last = check_first;
7536 for (
unsigned p = 0; p < nproc; p++)
7538 if (row_on_proc[p] != -1)
7540 int row = row_on_proc[p];
7541 unsigned first = row_start_from_proc(p, m)[row];
7542 unsigned last = row_start_from_proc(p, m)[row + 1];
7543 for (
unsigned l = first; l < last; l++)
7546 for (
unsigned j = check_first; j <= check_last && !done; j++)
7548 if (j == check_last)
7552 if (ncoef_in_chunk[current_chunk] ==
7553 size_of_chunk[current_chunk])
7556 unsigned n_chunk = values_chunk.size();
7560 unsigned nnz_so_far = 0;
7561 for (
unsigned c = 0; c < n_chunk; c++)
7563 nnz_so_far += ncoef_in_chunk[c];
7565 nnz_so_far -= row_start[m][
i];
7568 unsigned avg_nnz = nnz_so_far / (
i + 1);
7571 unsigned nrows_left = target_nrow_local -
i;
7574 unsigned next_chunk_size =
7575 avg_nnz * nrows_left + row_start[m][
i];
7580 values_chunk.resize(n_chunk);
7581 values_chunk[current_chunk] =
new double[next_chunk_size];
7582 column_indices_chunk.resize(n_chunk);
7583 column_indices_chunk[current_chunk] =
7584 new int[next_chunk_size];
7585 size_of_chunk.resize(n_chunk);
7586 size_of_chunk[current_chunk] = next_chunk_size;
7587 ncoef_in_chunk.resize(n_chunk);
7590 for (
unsigned k = check_first; k < check_last; k++)
7592 values_chunk[current_chunk][k - check_first] =
7593 values_chunk[current_chunk - 1][k];
7594 column_indices_chunk[current_chunk][k - check_first] =
7595 column_indices_chunk[current_chunk - 1][k];
7597 ncoef_in_chunk[current_chunk - 1] -= row_start[m][
i];
7598 ncoef_in_chunk[current_chunk] = row_start[m][
i];
7602 check_last = row_start[m][
i];
7607 values_chunk[current_chunk][j] = values_from_proc(p, m)[l];
7608 column_indices_chunk[current_chunk][j] =
7609 column_indices_from_proc(p, m)[l];
7610 ncoef_in_chunk[current_chunk]++;
7615 else if (column_indices_chunk[current_chunk][j] ==
7616 (
int)column_indices_from_proc(p, m)[l])
7618 values_chunk[current_chunk][j] += values_from_proc(p, m)[l];
7628 for (
unsigned p = 0; p < nproc; p++)
7630 if (n_eqn_from_proc[p] > 0)
7632 delete[] row_start_from_proc(p, m);
7633 delete[] column_indices_from_proc(p, m);
7634 delete[] values_from_proc(p, m);
7641 unsigned n_chunk = values_chunk.size();
7643 for (
unsigned c = 0; c < n_chunk; c++)
7645 nnz[m] += ncoef_in_chunk[c];
7650 values[m] =
new double[nnz[m]];
7651 column_indices[m] =
new int[nnz[m]];
7655 for (
unsigned c = 0; c < n_chunk; c++)
7657 unsigned nc = ncoef_in_chunk[c];
7658 for (
unsigned i = 0;
i < nc;
i++)
7660 values[m][pt +
i] = values_chunk[c][
i];
7661 column_indices[m][pt +
i] = column_indices_chunk[c][
i];
7664 delete[] values_chunk[c];
7665 delete[] column_indices_chunk[c];
7671 unsigned g = row_start[m][0];
7672 row_start[m][0] = 0;
7673 for (
unsigned i = 1;
i < target_nrow_local;
i++)
7675 unsigned h = g + row_start[m][
i];
7676 row_start[m][
i] = g;
7679 row_start[m][target_nrow_local] = g;
7683 for (
unsigned v = 0; v < n_vector; v++)
7685 residuals[v] =
new double[target_nrow_local];
7686 for (
unsigned i = 0;
i < target_nrow_local;
i++)
7688 residuals[v][
i] = 0;
7690 for (
unsigned p = 0; p < nproc; p++)
7692 if (n_eqn_from_proc[p] > 0)
7694 unsigned n_eqn_p = n_eqn_from_proc[p];
7695 for (
unsigned i = 0;
i < n_eqn_p;
i++)
7697 residuals[v][eqns_from_proc[p][
i]] += residuals_from_proc(p, v)[
i];
7699 delete[] residuals_from_proc(p, v);
7705 for (
unsigned p = 0; p < nproc; p++)
7707 if (n_eqn_from_proc[p] > 0)
7709 delete[] eqns_from_proc[p];
7715 MPI_Waitall(nproc - 1, &send_nnz_reqs[0], &send_nnz_stat[0]);
7716 for (
unsigned p = 0; p < nproc; p++)
7720 delete[] temp_send_storage[p];
7723 send_nnz_stat.clear();
7724 send_nnz_reqs.clear();
7727 unsigned n_send_reqs = send_reqs.size();
7728 if (n_send_reqs > 0)
7731 MPI_Waitall(n_send_reqs, &send_reqs[0], &send_stat[0]);
7732 for (
unsigned p = 0; p < nproc; p++)
7736 if (n_eqn_for_proc[p])
7738 delete[] eqns_for_proc[p];
7739 for (
unsigned m = 0; m < n_matrix; m++)
7741 delete[] row_start_for_proc(p, m);
7742 delete[] column_indices_for_proc(p, m);
7743 delete[] values_for_proc(p, m);
7745 for (
unsigned v = 0; v < n_vector; v++)
7747 delete[] residuals_for_proc(p, v);
7758 t_local = t_end - t_start;
7762 MPI_Allreduce(&t_local,
7768 MPI_Allreduce(&t_local,
7774 MPI_Allreduce(&t_local,
7780 double imbalance = (t_max - t_min) / (t_sum /
double(nproc)) * 100.0;
7781 if (doing_residuals)
7783 oomph_info <<
"CPU for residual distribut. (loc/max/min/imbal): ";
7787 oomph_info <<
"CPU for Jacobian distribut. (loc/max/min/imbal): ";
7789 oomph_info << t_local <<
" " << t_max <<
" " << t_min <<
" " << imbalance
7803 #ifdef OOMPH_HAS_MPI
7807 OomphLibWarning(
"This is unlikely to work with a distributed problem",
7808 " Problem::get_fd_jacobian()",
7809 OOMPH_EXCEPTION_LOCATION);
7815 const unsigned long n_dof =
ndof();
7823 const double FD_step = 1.0e-8;
7827 jacobian.
resize(n_dof, n_dof);
7830 for (
unsigned long jdof = 0; jdof < n_dof; jdof++)
7832 double backup = *
Dof_pt[jdof];
7845 for (
unsigned long ieqn = 0; ieqn < n_dof; ieqn++)
7847 jacobian(ieqn, jdof) =
7848 (residuals_pls[ieqn] - residuals[ieqn]) /
FD_step;
7919 const double FD_step = 1.0e-8;
7922 double param_value = *parameter_pt;
7935 const unsigned ndof_local = result.
nrow_local();
7938 for (
unsigned n = 0; n < ndof_local; ++n)
7940 result[n] = (newres[n] - result[n]) /
FD_step;
7944 *parameter_pt = param_value;
7968 const unsigned n_vec = C.size();
7979 for (
unsigned i = 0;
i < n_vec;
i++)
7986 #ifdef OOMPH_HAS_MPI
7989 for (
unsigned i = 0;
i < n_vec;
i++)
8005 for (
unsigned long e = 0;
e < Element_pt_range;
e++)
8010 #ifdef OOMPH_HAS_MPI
8024 for (
unsigned l = 0; l < n_var; l++)
8027 const unsigned long eqn_number =
8031 for (
unsigned i = 0;
i < n_vec;
i++)
8033 C_local(
i, l) = C[
i].global_value(eqn_number);
8039 elem_pt, Y_local, C_local, product_local);
8042 for (
unsigned l = 0; l < n_var; l++)
8044 const unsigned long eqn_number =
8047 for (
unsigned i = 0;
i < n_vec;
i++)
8049 product[
i].global_value(eqn_number) += product_local(
i, l);
8054 #ifdef OOMPH_HAS_MPI
8071 double dof_length = 0.0;
8074 for (
unsigned n = 0; n < n_dof_local; n++)
8076 if (std::fabs(this->
dof(n)) > dof_length)
8078 dof_length = std::fabs(this->
dof(n));
8083 for (
unsigned i = 0;
i < n_vec;
i++)
8085 for (
unsigned n = 0; n < n_dof_local; n++)
8087 if (std::fabs(C[
i][n]) > C_length[
i])
8089 C_length[
i] = std::fabs(C[
i][n]);
8095 #ifdef OOMPH_HAS_MPI
8098 const unsigned n_length = n_vec + 1;
8099 double all_length[n_length];
8100 all_length[0] = dof_length;
8101 for (
unsigned i = 0;
i < n_vec;
i++)
8103 all_length[
i + 1] = C_length[
i];
8107 double all_length_reduce[n_length];
8108 MPI_Allreduce(all_length,
8116 dof_length = all_length_reduce[0];
8117 for (
unsigned i = 0;
i < n_vec;
i++)
8119 C_length[
i] = all_length_reduce[
i + 1];
8126 for (
unsigned i = 0;
i < n_vec;
i++)
8128 C_mult[
i] = dof_length / C_length[
i];
8140 for (
unsigned long e = 0;
e < n_element;
e++)
8144 #ifdef OOMPH_HAS_MPI
8151 dummy_res.resize(n_var);
8159 for (
unsigned n = 0; n < n_var; n++)
8166 for (
unsigned i = 0;
i < n_vec;
i++)
8169 for (
unsigned n = 0; n < n_var; n++)
8174 C_mult[
i] * C[
i].global_value(eqn_number);
8185 for (
unsigned n = 0; n < n_var; n++)
8193 for (
unsigned n = 0; n < n_var; n++)
8196 double prod_c = 0.0;
8197 for (
unsigned m = 0; m < n_var; m++)
8200 prod_c += (jac_C(n, m) - jac(n, m)) * Y.
global_value(unknown);
8204 product[
i].global_value(eqn_number) += prod_c / C_mult[
i];
8207 #ifdef OOMPH_HAS_MPI
8215 #ifdef OOMPH_HAS_MPI
8219 for (
unsigned i = 0;
i < n_vec;
i++)
8221 product[
i].sum_all_halo_and_haloed_values();
8294 const unsigned& n_eval,
8295 Vector<std::complex<double>>& eigenvalue,
8297 const bool& make_timesteppers_steady)
8302 if (make_timesteppers_steady)
8309 std::vector<bool> was_steady(n_time_steppers);
8312 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8318 const bool do_adjoint_problem =
false;
8321 this, n_eval, eigenvalue, eigenvector, do_adjoint_problem);
8326 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8338 const bool do_adjoint_problem =
false;
8341 this, n_eval, eigenvalue, eigenvector, do_adjoint_problem);
8349 Vector<std::complex<double>>& alpha,
8353 const bool& make_timesteppers_steady)
8358 if (make_timesteppers_steady)
8365 std::vector<bool> was_steady(n_time_steppers);
8368 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8374 const bool do_adjoint_problem =
false;
8382 do_adjoint_problem);
8387 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8399 const bool do_adjoint_problem =
false;
8407 do_adjoint_problem);
8416 Vector<std::complex<double>>& eigenvalue,
8419 const bool& make_timesteppers_steady)
8424 if (make_timesteppers_steady)
8431 std::vector<bool> was_steady(n_time_steppers);
8434 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8440 const bool do_adjoint_problem =
false;
8447 do_adjoint_problem);
8452 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8464 const bool do_adjoint_problem =
false;
8471 do_adjoint_problem);
8480 const unsigned& n_eval,
8481 Vector<std::complex<double>>& eigenvalue,
8483 const bool& make_timesteppers_steady)
8488 if (make_timesteppers_steady)
8495 std::vector<bool> was_steady(n_time_steppers);
8498 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8504 const bool do_adjoint_problem =
true;
8508 this, n_eval, eigenvalue, eigenvector, do_adjoint_problem);
8513 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8525 const bool do_adjoint_problem =
true;
8528 this, n_eval, eigenvalue, eigenvector, do_adjoint_problem);
8537 const unsigned& n_eval,
8538 Vector<std::complex<double>>& eigenvalue,
8541 const bool& make_timesteppers_steady)
8546 if (make_timesteppers_steady)
8553 std::vector<bool> was_steady(n_time_steppers);
8556 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8562 const bool do_adjoint_problem =
true;
8569 do_adjoint_problem);
8574 for (
unsigned i = 0;
i < n_time_steppers;
i++)
8586 const bool do_adjoint_problem =
true;
8593 do_adjoint_problem);
8604 const double& shift)
8618 std::ostringstream error_stream;
8620 <<
"The distributions of the jacobian and mass matrix are\n"
8621 <<
"not the same and they must be.\n";
8623 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8626 if (mass_matrix.
nrow() != this->ndof())
8628 std::ostringstream error_stream;
8630 <<
"mass_matrix has a distribution, but the number of rows is not "
8631 <<
"equal to the number of degrees of freedom in the problem.";
8633 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8636 if (main_matrix.
nrow() != this->ndof())
8638 std::ostringstream error_stream;
8640 <<
"main_matrix has a distribution, but the number of rows is not "
8641 <<
"equal to the number of degrees of freedom in the problem.";
8643 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8650 std::ostringstream error_stream;
8651 error_stream <<
"The distribution of the jacobian and mass matrix must "
8652 <<
"both be setup or both not setup";
8654 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8687 bool compressed_row_flag =
true;
8689 #ifdef OOMPH_HAS_MPI
8696 row_or_column_start,
8700 compressed_row_flag);
8703 main_matrix.
build(dist_pt);
8707 column_or_row_index[0],
8708 row_or_column_start[0]);
8710 mass_matrix.
build(dist_pt);
8714 column_or_row_index[1],
8715 row_or_column_start[1]);
8716 #ifdef OOMPH_HAS_MPI
8723 column_or_row_index,
8724 row_or_column_start,
8729 main_matrix.
build(dist_pt);
8733 column_or_row_index[0],
8734 row_or_column_start[0]);
8736 mass_matrix.
build(dist_pt);
8740 column_or_row_index[1],
8741 row_or_column_start[1]);
8748 column_or_row_index,
8749 row_or_column_start,
8754 main_matrix.
build(temp_dist_pt);
8758 column_or_row_index[0],
8759 row_or_column_start[0]);
8762 mass_matrix.
build(temp_dist_pt);
8766 column_or_row_index[1],
8767 row_or_column_start[1]);
8769 delete temp_dist_pt;
8796 #ifdef OOMPH_HAS_MPI
8807 for (
unsigned i = 0;
i < n_row_local;
i++)
8809 (*Saved_dof_pt)[
i] = *(this->
Dof_pt[
i]);
8817 unsigned long n_dof =
ndof();
8823 for (
unsigned long n = 0; n < n_dof; n++)
8825 (*Saved_dof_pt)[n] =
dof(n);
8839 "There are no stored values, use store_current_dof_values()\n",
8840 OOMPH_CURRENT_FUNCTION,
8841 OOMPH_EXCEPTION_LOCATION);
8845 #ifdef OOMPH_HAS_MPI
8854 throw OomphLibError(
"The number of stored values is not equal to the "
8855 "current number of dofs\n",
8856 OOMPH_CURRENT_FUNCTION,
8857 OOMPH_EXCEPTION_LOCATION);
8861 for (
unsigned long n = 0; n < n_row_local; n++)
8871 unsigned long n_dof =
ndof();
8875 throw OomphLibError(
"The number of stored values is not equal to the "
8876 "current number of dofs\n",
8877 OOMPH_CURRENT_FUNCTION,
8878 OOMPH_EXCEPTION_LOCATION);
8882 for (
unsigned long n = 0; n < n_dof; n++)
8884 dof(n) = (*Saved_dof_pt)[n];
8898 unsigned long n_dof =
ndof();
8900 if (eigenvector.
nrow() != n_dof)
8902 std::ostringstream error_message;
8903 error_message <<
"Eigenvector has size " << eigenvector.
nrow()
8904 <<
", not equal to the number of dofs in the problem,"
8905 << n_dof << std::endl;
8908 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8918 for (
unsigned long n = 0; n < eigenvector_dof.
nrow_local(); n++)
8920 dof(n) = eigenvector_dof[n];
8923 #ifdef OOMPH_HAS_MPI
8936 unsigned long n_dof =
ndof();
8938 if (eigenvector.
nrow() != n_dof)
8940 std::ostringstream error_message;
8941 error_message <<
"Eigenvector has size " << eigenvector.
nrow()
8942 <<
", not equal to the number of dofs in the problem,"
8943 << n_dof << std::endl;
8946 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8958 for (
unsigned long n = 0; n < eigenvector.
nrow_local(); n++)
8960 dof(n) += epsilon * eigenvector[n];
8963 #ifdef OOMPH_HAS_MPI
8979 double total_linear_solver_time = 0.0;
8984 unsigned long n_dofs =
ndof();
8995 double half_residual_squared = 0.0;
8996 double max_step = 0.0;
9003 unsigned LOOP_FLAG = 1;
9007 #ifdef OOMPH_HAS_MPI
9011 std::ostringstream error_stream;
9012 error_stream <<
"Globally convergent Newton method has not been "
9013 <<
"implemented in parallel yet!" << std::endl;
9015 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
9044 oomph_info << std::endl << std::endl << std::endl;
9045 oomph_info <<
"This is a bit bizarre: The problem has no dofs."
9048 <<
"I'll just return from the Newton solver without doing anything."
9057 oomph_info <<
"I hope this is what you intended me to do..."
9060 <<
"Note: All actions_...() functions were called"
9062 oomph_info << std::endl <<
" before returning." << std::endl;
9063 oomph_info << std::endl << std::endl << std::endl;
9074 #ifdef OOMPH_HAS_MPI
9087 half_residual_squared = 0.0;
9089 for (
unsigned i = 0;
i < n_dofs;
i++)
9092 half_residual_squared += dx[
i] * dx[
i];
9094 half_residual_squared *= 0.5;
9095 max_step = 100.0 * std::max(sqrt(sum),
double(n_dofs));
9099 double maxres = dx.
max();
9113 oomph_info <<
"\nInitial Maximum residuals " << maxres << std::endl;
9128 <<
"Linear problem -- convergence in one iteration assumed."
9146 oomph_info <<
"Not recomputing Jacobian! " << std::endl;
9166 oomph_info <<
"Enabling resolve" << std::endl;
9176 total_linear_solver_time += t_solver_end - t_solver_start;
9181 oomph_info <<
"Time for linear solver (ndof=" << n_dofs <<
"): "
9183 t_solver_end - t_solver_start)
9198 for (
unsigned i = 0;
i < ndof_local;
i++)
9206 for (
unsigned i = 0;
i < ndof_local;
i++)
9211 double half_residual_squared_old = half_residual_squared;
9213 half_residual_squared_old,
9216 half_residual_squared,
9222 for (
unsigned l = 0; l < ndof_local; l++)
9227 #ifdef OOMPH_HAS_MPI
9237 double maxres = 0.0;
9257 oomph_info <<
"Newton Step " << count <<
": Maximum residuals "
9258 << maxres << std::endl
9279 <<
") has been exceeded in Newton solver." << std::endl;
9283 oomph_info <<
"Reached max. number of iterations ("
9291 }
while (LOOP_FLAG);
9300 oomph_info <<
"Total time for linear solver (ndof=" << n_dofs <<
"): "
9302 total_linear_solver_time)
9307 double total_time = t_end - t_start;
9311 oomph_info <<
"Total time for Newton solver (ndof=" << n_dofs <<
"): "
9315 if (total_time > 0.0)
9319 oomph_info <<
"Time outside linear solver : "
9320 << (total_time - total_linear_solver_time) / total_time *
9322 <<
" %" << std::endl;
9329 oomph_info <<
"Time outside linear solver : "
9330 <<
"[too fast]" << std::endl;
9341 const double& half_residual_squared_old,
9344 double& half_residual_squared,
9345 const double& stpmax)
9347 const double min_fct_decrease = 1.0e-4;
9348 double convergence_tol_on_x = 1.0e-16;
9350 double lambda_aux = 0.0;
9351 double proposed_lambda;
9352 unsigned long n_dof =
ndof();
9354 for (
unsigned i = 0;
i < n_dof;
i++)
9356 sum += newton_dir[
i] * newton_dir[
i];
9361 for (
unsigned i = 0;
i < n_dof;
i++)
9363 newton_dir[
i] *= stpmax / sum;
9367 for (
unsigned i = 0;
i < n_dof;
i++)
9369 slope += gradient[
i] * newton_dir[
i];
9373 std::ostringstream warn_message;
9374 warn_message <<
"WARNING: Non-negative slope, probably due to a "
9375 <<
" roundoff \nproblem in the linesearch: slope=" << slope
9378 "Problem::globally_convergent_line_search()",
9379 OOMPH_EXCEPTION_LOCATION);
9382 for (
unsigned i = 0;
i < n_dof;
i++)
9385 std::fabs(newton_dir[
i]) / std::max(std::fabs(x_old[
i]), 1.0);
9386 if (temp > test) test = temp;
9388 double lambda_min = convergence_tol_on_x / test;
9389 double lambda = 1.0;
9392 for (
unsigned i = 0;
i < n_dof;
i++)
9394 *
Dof_pt[
i] = x_old[
i] + lambda * newton_dir[
i];
9400 half_residual_squared = 0.0;
9401 for (
unsigned i = 0;
i < n_dof;
i++)
9403 half_residual_squared += residuals[
i] * residuals[
i];
9405 half_residual_squared *= 0.5;
9407 if (lambda < lambda_min)
9409 for (
unsigned i = 0;
i < n_dof;
i++) *
Dof_pt[
i] = x_old[
i];
9411 std::ostringstream warn_message;
9412 warn_message <<
"WARNING: Line search converged on x only!\n";
9414 "Problem::globally_convergent_line_search()",
9415 OOMPH_EXCEPTION_LOCATION);
9418 else if (half_residual_squared <=
9419 half_residual_squared_old + min_fct_decrease * lambda * slope)
9421 oomph_info <<
"Returning from linesearch with lambda=" << lambda
9431 (2.0 * (half_residual_squared - half_residual_squared_old - slope));
9436 half_residual_squared - half_residual_squared_old - lambda * slope;
9437 double r2 = f_aux - half_residual_squared_old - lambda_aux * slope;
9439 (r1 / (lambda * lambda) - r2 / (lambda_aux * lambda_aux)) /
9440 (lambda - lambda_aux);
9441 double b_poly = (-lambda_aux * r1 / (lambda * lambda) +
9442 lambda * r2 / (lambda_aux * lambda_aux)) /
9443 (lambda - lambda_aux);
9446 proposed_lambda = -slope / (2.0 * b_poly);
9450 double discriminant = b_poly * b_poly - 3.0 * a_poly * slope;
9451 if (discriminant < 0.0)
9453 proposed_lambda = 0.5 * lambda;
9455 else if (b_poly <= 0.0)
9457 proposed_lambda = (-b_poly + sqrt(discriminant)) / (3.0 * a_poly);
9461 proposed_lambda = -slope / (b_poly + sqrt(discriminant));
9464 if (proposed_lambda > 0.5 * lambda)
9466 proposed_lambda = 0.5 * lambda;
9470 lambda_aux = lambda;
9471 f_aux = half_residual_squared;
9472 lambda = std::max(proposed_lambda, 0.1 * lambda);
9492 std::vector<bool> was_steady(n_time_steppers);
9495 for (
unsigned i = 0;
i < n_time_steppers;
i++)
9517 <<
"USER-DEFINED ERROR IN NEWTON SOLVER " << std::endl;
9521 oomph_info <<
"ERROR IN THE LINEAR SOLVER" << std::endl;
9527 <<
") REACHED WITHOUT CONVERGENCE " << std::endl;
9538 std::ostringstream error_stream;
9539 error_stream <<
"Error occured in Newton solver. " << std::endl;
9541 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
9548 for (
unsigned i = 0;
i < n_time_steppers;
i++)
9606 double uderiv_dot_y = 0.0, uderiv_dot_z = 0.0;
9610 unsigned LOOP_FLAG = 1;
9616 double arc_length_constraint_residual = 0.0;
9635 #ifdef OOMPH_HAS_MPI
9644 double maxres = y.
max();
9647 arc_length_constraint_residual = 0.0;
9649 for (
unsigned long l = 0; l < ndof_local; l++)
9651 arc_length_constraint_residual +=
9656 #ifdef OOMPH_HAS_MPI
9657 double arc_length_cons_res2 = arc_length_constraint_residual;
9661 MPI_Allreduce(&arc_length_constraint_residual,
9662 &arc_length_cons_res2,
9668 arc_length_constraint_residual = arc_length_cons_res2;
9672 arc_length_constraint_residual +=
9677 if (std::fabs(arc_length_constraint_residual) > maxres)
9679 maxres = std::fabs(arc_length_constraint_residual);
9685 oomph_info <<
"Initial Maximum residuals " << maxres << std::endl;
9715 ->solve_for_two_rhs(
this, y, input_z, z);
9754 for (
unsigned long l = 0; l < ndof_local; l++)
9761 #ifdef OOMPH_HAS_MPI
9763 double uderiv_dot[2];
9764 double uderiv_dot2[2];
9765 uderiv_dot[0] = uderiv_dot_y;
9766 uderiv_dot[1] = uderiv_dot_z;
9767 uderiv_dot2[0] = uderiv_dot_y;
9768 uderiv_dot2[1] = uderiv_dot_z;
9773 MPI_Allreduce(uderiv_dot,
9780 uderiv_dot_y = uderiv_dot2[0];
9781 uderiv_dot_z = uderiv_dot2[1];
9796 double dparam = (arc_length_constraint_residual - uderiv_dot_y) /
9800 *parameter_pt -= dparam;
9803 for (
unsigned long l = 0; l < ndof_local; l++)
9805 *
Dof_pt[l] -= y_pt[l] - dparam * z_pt[l];
9809 #ifdef OOMPH_HAS_MPI
9822 double maxres = y.
max();
9825 arc_length_constraint_residual = 0.0;
9827 for (
unsigned long l = 0; l < ndof_local; l++)
9829 arc_length_constraint_residual +=
9834 #ifdef OOMPH_HAS_MPI
9835 double arc_length_cons_res2 = arc_length_constraint_residual;
9839 MPI_Allreduce(&arc_length_constraint_residual,
9840 &arc_length_cons_res2,
9846 arc_length_constraint_residual = arc_length_cons_res2;
9850 arc_length_constraint_residual +=
9854 if (std::fabs(arc_length_constraint_residual) > maxres)
9856 maxres = std::fabs(arc_length_constraint_residual);
9861 oomph_info <<
"Continuation Step " << count <<
": Maximum residuals "
9880 }
while (LOOP_FLAG);
9911 const unsigned long n_dofs =
ndof();
9934 ->solve_for_two_rhs(
this, dummy, input_z, z);
10012 double*
const& parameter_pt)
10040 double*
const& parameter_pt)
10044 for (
unsigned i = 0;
i < n_global; ++
i)
10047 if (
Global_data_pt[
i]->does_pointer_correspond_to_value(parameter_pt))
10060 const unsigned n_sub_mesh = this->
nsub_mesh();
10062 if (n_sub_mesh == 0)
10066 if (spine_mesh_pt->does_pointer_correspond_to_spine_data(parameter_pt))
10076 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
10081 if (spine_mesh_pt->does_pointer_correspond_to_spine_data(
10130 double*
const local_z_pt = local_z.
values_pt();
10131 for (
unsigned long l = 0; l < ndof_local; l++)
10137 #ifdef OOMPH_HAS_MPI
10162 double chi = local_z.
dot(local_z);
10184 for (
unsigned long l = 0; l < ndof_local; l++)
10198 double*
const& parameter_pt)
10207 double length = 0.0;
10209 for (
unsigned long l = 0; l < ndof_local; l++)
10216 #ifdef OOMPH_HAS_MPI
10217 double length2 = length;
10221 MPI_Allreduce(&length,
10236 length = sqrt(length);
10237 for (
unsigned long l = 0; l < ndof_local; l++)
10254 std::ostringstream warn_message;
10256 <<
"Warning: This function is called after spatially adapting the\n"
10257 <<
"eigenfunction associated with a pitchfork bifurcation and should\n"
10258 <<
"ensure that the exact (anti-)symmetries of problem are enforced\n"
10259 <<
"within that eigenfunction. It is problem specific and must be\n"
10260 <<
"filled in by the user if required.\n"
10261 <<
"A sign of problems is if the slack paramter gets too large and\n"
10262 <<
"if the solution at the Pitchfork is not symmetric.\n";
10264 warn_message.str(),
10265 "Problem::symmetrise_eigenfunction_for_adaptive_pitchfork_tracking()",
10266 OOMPH_EXCEPTION_LOCATION);
10297 const bool& block_solve)
10324 const bool& block_solve)
10353 const bool& block_solve)
10361 new FoldHandler(
this, parameter_pt, eigenvector, normalisation);
10383 const bool& block_solve)
10412 const bool& block_solve)
10440 const double& omega,
10443 const bool& block_solve)
10451 new HopfHandler(
this, parameter_pt, omega, null_real, null_imag);
10489 const unsigned& max_adapt)
10495 std::ostringstream error_message;
10497 <<
"The parameter addressed by " << parameter_pt <<
" with the value "
10499 <<
"\n is supposed to be used for arc-length contiunation,\n"
10500 <<
" but it is stored in a Data object used by the problem.\n\n"
10501 <<
"This is bad for two reasons:\n"
10502 <<
"1. If it's a variable in the problem, it must already have an\n"
10503 "associated equation, so it can't be used for continuation;\n"
10504 <<
"2. The problem data will be reorganised in memory during "
10506 <<
" which means that the pointer will become invalid.\n\n"
10507 <<
"If you are sure that this is what you want to do you must:\n"
10508 <<
"A. Ensure that the value is pinned (don't worry we'll shout again "
10510 <<
"B. Use the alternative interface\n"
10511 <<
" Problem::arc_length_step_solve(Data*,unsigned,...)\n"
10512 <<
" which uses a pointer to the data object and not the raw double "
10516 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
10524 bool continuation_time_stepper_added =
false;
10526 for (
unsigned i = 0;
i < n_time_steppers;
i++)
10530 continuation_time_stepper_added =
true;
10536 if (!continuation_time_stepper_added)
10538 oomph_info <<
"Adding the continuation time stepper\n";
10554 <<
" equation numbers allocated for continuation\n";
10576 const unsigned& data_index,
10578 const unsigned& max_adapt)
10583 std::ostringstream error_stream;
10584 error_stream <<
"The value at index " << data_index
10585 <<
" in the data object to be used for continuation\n"
10586 <<
"is not pinned, which means that it is already a\n"
10587 <<
"variable in the problem "
10588 <<
"and cannot be used for continuation.\n\n"
10589 <<
"Please correct your formulation by either:\n"
10590 <<
"A. Pinning the value"
10592 <<
"B. Using a different parameter for continuation"
10595 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
10603 bool continuation_time_stepper_added =
false;
10605 for (
unsigned i = 0;
i < n_time_steppers;
i++)
10609 continuation_time_stepper_added =
true;
10615 if (!continuation_time_stepper_added)
10617 oomph_info <<
"Adding the continuation time stepper\n";
10634 <<
" equation numbers allocated for continuation\n";
10642 double* parameter_pt = data_pt->
value_pt(data_index);
10666 const unsigned n_sub_mesh = this->
nsub_mesh();
10668 if (n_sub_mesh == 0)
10672 spine_mesh_pt->set_consistent_pinned_spine_values_for_continuation(
10681 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
10686 spine_mesh_pt->set_consistent_pinned_spine_values_for_continuation(
10694 for (
unsigned i = 0;
i < n_global; ++
i)
10710 const unsigned& max_adapt)
10718 std::vector<bool> was_steady(n_time_steppers);
10721 for (
unsigned i = 0;
i < n_time_steppers;
i++)
10729 unsigned max_solve = max_adapt + 1;
10731 unsigned max_count_in_adapt_loop = 0;
10748 bool SIGN_CHANGE =
false;
10752 for (
unsigned isolve = 0; isolve < max_solve; ++isolve)
10757 unsigned n_refined;
10758 unsigned n_unrefined;
10761 adapt(n_refined, n_unrefined);
10763 #ifdef OOMPH_HAS_MPI
10766 unsigned total_refined = 0;
10767 unsigned total_unrefined = 0;
10770 MPI_Allreduce(&n_refined,
10776 n_refined = total_refined;
10777 MPI_Allreduce(&n_unrefined,
10783 n_unrefined = total_unrefined;
10787 oomph_info <<
"---> " << n_refined <<
" elements were refined, and "
10788 << n_unrefined <<
" were unrefined"
10789 #ifdef OOMPH_HAS_MPI
10790 <<
", in total (over all processors).\n";
10797 if ((n_refined == 0) && (n_unrefined == 0))
10799 oomph_info <<
"\n \n Solution is fully converged in "
10800 <<
"Problem::newton_solver(). \n \n ";
10836 for (
unsigned long l = 0; l < ndof_local; l++)
10846 unsigned count = 0;
10849 bool STEP_REJECTED =
false;
10864 std::ostringstream error_message;
10865 error_message <<
"DESIRED ARC-LENGTH STEP " <<
Ds_current
10866 <<
" HAS FALLEN BELOW MINIMUM TOLERANCE, " <<
Minimum_ds
10870 OOMPH_CURRENT_FUNCTION,
10871 OOMPH_EXCEPTION_LOCATION);
10875 STEP_REJECTED =
false;
10886 for (
unsigned long l = 0; l < ndof_local; l++)
10902 std::ostringstream error_stream;
10903 error_stream << std::endl
10904 <<
"USER-DEFINED ERROR IN NEWTON SOLVER " << std::endl;
10905 oomph_info <<
"ERROR IN THE LINEAR SOLVER" << std::endl;
10907 OOMPH_CURRENT_FUNCTION,
10908 OOMPH_EXCEPTION_LOCATION);
10913 oomph_info <<
"STEP REJECTED --- TRYING AGAIN" << std::endl;
10914 STEP_REJECTED =
true;
10919 }
while (STEP_REJECTED);
10922 if (count > max_count_in_adapt_loop)
10924 max_count_in_adapt_loop = count;
10930 if (max_count_in_adapt_loop > 0)
10939 "The sign of the jacobian is zero after a linear solve\n";
10940 error_message +=
"Either the matrix is singular (unlikely),\n";
10941 error_message +=
"or the linear solver cannot compute the "
10942 "determinant of the matrix;\n";
10943 error_message +=
"e.g. an iterative linear solver.\n";
10945 "If the latter, bifurcation detection must be via an eigensolver\n";
10947 "Problem::arc_length_step_solve",
10948 OOMPH_EXCEPTION_LOCATION);
10964 SIGN_CHANGE =
true;
10980 std::ostringstream message;
10982 <<
"-----------------------------------------------------------";
10983 message << std::endl
10984 <<
"SIGN CHANGE IN DETERMINANT OF JACOBIAN: " << std::endl;
10985 message <<
"BIFURCATION OR TURNING POINT DETECTED BETWEEN "
10991 <<
"-----------------------------------------------------------"
10998 std::ofstream bifurcation_info(
"bifurcation_info",
10999 std::ios_base::app);
11001 bifurcation_info << message.str();
11002 bifurcation_info.close();
11062 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11064 if (!was_steady[
i])
11116 throw OomphLibError(
"Explicit time stepper pointer is null in problem.",
11117 OOMPH_EXCEPTION_LOCATION,
11118 OOMPH_CURRENT_FUNCTION);
11160 const bool& shift_values)
11176 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11184 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11202 <<
"USER-DEFINED ERROR IN NEWTON SOLVER " << std::endl;
11206 oomph_info <<
"ERROR IN THE LINEAR SOLVER" << std::endl;
11212 <<
") REACHED WITHOUT CONVERGENCE " << std::endl;
11222 std::ostringstream error_stream;
11223 error_stream <<
"Error occured in unsteady Newton solver. " << std::endl;
11225 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
11232 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11250 const double& epsilon)
11270 const double& epsilon,
11271 const bool& shift_values)
11283 for (
unsigned i = 0;
i < n_dof_local;
i++) dofs_current[
i] =
dof(
i);
11289 bool reject_timestep = 0;
11292 unsigned adaptive_flag = 0;
11295 double dt_actual = dt_desired;
11299 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11320 reject_timestep = 0;
11321 double dt_rescaling_factor = 1.0;
11328 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11341 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11362 std::string error_message =
"USER-DEFINED ERROR IN NEWTON SOLVER\n";
11363 error_message +=
"ERROR IN THE LINEAR SOLVER\n";
11367 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
11372 oomph_info <<
"TIMESTEP REJECTED" << std::endl;
11373 reject_timestep = 1;
11384 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11394 if (adaptive_flag && !reject_timestep)
11398 for (
unsigned i = 0;
i < n_time_steppers;
i++)
11410 dt_rescaling_factor = std::pow(
11413 oomph_info <<
"Timestep scaling factor is " << dt_rescaling_factor
11415 oomph_info <<
"Estimated timestepping error is " << error << std::endl;
11419 if (error > epsilon)
11421 oomph_info <<
"Estimated timestepping error " << error
11422 <<
" exceeds tolerance " << epsilon <<
" ";
11425 oomph_info <<
" --> rejecting timestep." << std::endl;
11426 reject_timestep = 1;
11430 oomph_info <<
" ...but we're not rejecting the timestep"
11434 <<
"Note: This behaviour can be adjusted by changing the protected "
11435 <<
"boolean" << std::endl
11437 <<
" Problem::Keep_temporal_error_below_tolerance" << std::endl;
11449 double new_dt_candidate = dt_rescaling_factor * dt_actual;
11454 oomph_info <<
"Tried to increase dt by the ratio "
11455 << dt_rescaling_factor <<
" which is above the maximum ("
11457 <<
"). Attempting to increase by the maximum ratio instead."
11470 <<
"Warning: Adaptation of timestep to ensure satisfaction\n"
11471 <<
" of error bounds during adaptive timestepping\n"
11472 <<
" would lower dt below \n"
11473 <<
" Problem::Minimum_dt_but_still_proceed="
11475 <<
" ---> We're continuing with present timestep.\n"
11477 dt_rescaling_factor = 1.0;
11485 oomph_info <<
"Timestep would decrease by " << dt_rescaling_factor
11486 <<
" which is less than the minimum scaling factor "
11488 oomph_info <<
"TIMESTEP REJECTED" << std::endl;
11489 reject_timestep = 1;
11496 oomph_info <<
"Tried to increase dt to " << new_dt_candidate
11497 <<
" which is above the maximum (" <<
Maximum_dt
11498 <<
"). I increased it to the maximum value instead.";
11503 std::ostringstream err;
11504 err <<
"Tried to reduce dt to " << new_dt_candidate
11505 <<
" which is less than the minimum dt (" <<
Minimum_dt <<
")."
11508 err.str(), OOMPH_EXCEPTION_LOCATION, OOMPH_CURRENT_FUNCTION);
11512 dt_actual = new_dt_candidate;
11520 if (reject_timestep)
11526 unsigned ni = dofs_current.size();
11527 for (
unsigned i = 0;
i < ni;
i++)
11529 dof(
i) = dofs_current[
i];
11532 #ifdef OOMPH_HAS_MPI
11547 while (reject_timestep);
11573 const double& dt_desired,
11574 const double& epsilon,
11575 const unsigned& max_adapt,
11576 const unsigned& suppress_resolve_after_spatial_adapt_flag,
11578 const bool& shift_values)
11587 oomph_info <<
"Accepted solution taken with timestep: " << dt_taken
11592 if (max_adapt == 0)
11594 oomph_info <<
"No spatial refinement allowed; max_adapt=0\n";
11599 unsigned n_refined = 0;
11600 unsigned n_unrefined = 0;
11601 adapt(n_refined, n_unrefined);
11605 total_ref_count[0] = n_refined;
11606 total_ref_count[1] = n_unrefined;
11609 #ifdef OOMPH_HAS_MPI
11614 ref_count[0] = n_refined;
11615 ref_count[1] = n_unrefined;
11616 MPI_Allreduce(&ref_count[0],
11617 &total_ref_count[0],
11627 if ((total_ref_count[0] != 0) || (total_ref_count[1] != 0))
11629 if (suppress_resolve_after_spatial_adapt_flag == 1)
11631 oomph_info <<
"Mesh was adapted but re-solve has been suppressed."
11637 <<
"Mesh was adapted --> we'll re-solve for current timestep."
11646 bool shift =
false;
11655 oomph_info <<
"Re-assigning initial condition at time="
11678 oomph_info <<
"Mesh wasn't adapted --> we'll accept spatial refinement."
11699 for (
unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
11702 ->time_stepper_pt()
11729 OOMPH_CURRENT_FUNCTION,
11730 OOMPH_EXCEPTION_LOCATION);
11747 OOMPH_CURRENT_FUNCTION,
11748 OOMPH_EXCEPTION_LOCATION);
11766 TimeStepper*
const& time_stepper_pt,
const bool& preserve_existing_data)
11773 preserve_existing_data);
11776 const unsigned n_sub_mesh = this->
nsub_mesh();
11778 if (n_sub_mesh == 0)
11781 preserve_existing_data);
11787 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
11790 time_stepper_pt, preserve_existing_data);
11796 for (
unsigned i = 0;
i < n_global; ++
i)
11799 preserve_existing_data);
11805 #ifdef OOMPH_HAS_MPI
11808 std::ostringstream warning_stream;
11809 warning_stream <<
"This has not been comprehensively tested for "
11810 "distributed problems.\n"
11811 <<
"I'm sure that I need to worry about external halo and "
11812 "external elements."
11815 warning_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
11838 for (
unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
11862 std::string err =
"Prediction by explicit step only works for "
11863 "problems with a simple time";
11864 err +=
"stepper. I think implementing anything more general will";
11865 err +=
"require a rewrite of explicit time steppers. - David";
11867 err, OOMPH_EXCEPTION_LOCATION, OOMPH_CURRENT_FUNCTION);
11886 std::string err =
"Requested predictions by explicit step but explicit";
11887 err +=
" predictor pt is null.";
11889 err, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
11895 throw OomphLibError(
"Problem has explicit time stepper other than "
11896 "predictor, not sure how to handle this yet ??ds",
11897 OOMPH_EXCEPTION_LOCATION,
11898 OOMPH_CURRENT_FUNCTION);
11907 double backup_time =
time();
11926 if (std::abs(
time() - backup_time) > 1
e-12)
11928 using namespace StringConversion;
11929 std::string err =
"Predictor landed at the wrong time!";
11930 err +=
" Expected time " +
to_string(backup_time, 14) +
" but got ";
11933 err, OOMPH_EXCEPTION_LOCATION, OOMPH_CURRENT_FUNCTION);
11950 for (
unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
11952 Global_data_pt[iglobal]->time_stepper_pt()->calculate_predicted_values(
11964 #ifdef OOMPH_HAS_MPI
11967 throw OomphLibError(
"Not yet implemented for distributed problems",
11968 OOMPH_EXCEPTION_LOCATION,
11969 OOMPH_CURRENT_FUNCTION);
11978 std::string err =
"Not implemented for multiple time steppers";
11980 err, OOMPH_EXCEPTION_LOCATION, OOMPH_CURRENT_FUNCTION);
11988 for (
unsigned i = 0;
i <
ndof();
i++)
11990 dof(
i) = predicted_dofs[
i];
12011 for (
unsigned e = 0;
e < n_element;
e++)
12036 for (
unsigned e = 0;
e < n_element;
e++)
12064 bool unsteady_flag = (orig_problem_pt->
time_pt() != 0);
12069 oomph_info <<
"Copying an unsteady problem." << std::endl;
12073 unsigned n_dt = orig_problem_pt->
time_pt()->
ndt();
12075 for (
unsigned i = 0;
i < n_dt;
i++)
12084 for (
unsigned i = 0;
i < n_time_steppers;
i++)
12095 if (nmesh == 0) nmesh = 1;
12096 for (
unsigned m = 0; m < nmesh; m++)
12102 unsigned long n_node_orig = orig_problem_pt->
mesh_pt(m)->
nnode();
12103 if (n_node != n_node_orig)
12105 std::ostringstream error_message;
12106 error_message <<
"Number of nodes in copy " << n_node
12107 <<
" not equal to the number in the original "
12108 << n_node_orig << std::endl;
12111 OOMPH_CURRENT_FUNCTION,
12112 OOMPH_EXCEPTION_LOCATION);
12116 for (
unsigned long i = 0;
i < n_node;
i++)
12121 if (el_node_pt != 0)
12125 el_node_pt->
copy(el_node_orig_pt);
12142 unsigned long n_global_orig = orig_problem_pt->
nglobal_data();
12143 if (n_global != n_global_orig)
12145 std::ostringstream error_message;
12146 error_message <<
"Number of global data in copy " << n_global
12147 <<
" not equal to the number in the original "
12148 << n_global_orig << std::endl;
12151 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
12154 for (
unsigned iglobal = 0; iglobal < n_global; iglobal++)
12164 for (
unsigned m = 0; m < nmesh; m++)
12168 for (
unsigned e = 0;
e < n_element;
e++)
12172 if (n_internal > 0)
12175 unsigned long n_internal_orig =
12177 if (n_internal != n_internal_orig)
12179 std::ostringstream error_message;
12180 error_message <<
"Number of internal data in copy " << n_internal
12181 <<
" not equal to the number in the original "
12182 << n_internal_orig << std::endl;
12185 OOMPH_CURRENT_FUNCTION,
12186 OOMPH_EXCEPTION_LOCATION);
12188 for (
unsigned i = 0;
i < n_internal;
i++)
12206 std::ostringstream error_stream;
12208 <<
"This function must be overloaded in your specific problem, and must\n"
12209 <<
"create an exact copy of your problem. Usually this will be achieved\n"
12210 <<
"by a call to the constructor with exactly the same arguments as "
12214 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
12227 dump_file << std::max(
unsigned(1), n_mesh) <<
" # number of (sub)meshes "
12238 dump_file << mmesh_pt->uniform_refinement_level_when_pruned()
12239 <<
" # uniform refinement when pruned " << std::endl;
12243 dump_file << 0 <<
" # (fake) uniform refinement when pruned "
12246 dump_file << 9999 <<
" # test flag for end of sub-meshes " << std::endl;
12254 for (
unsigned imesh = 0; imesh < n_mesh; imesh++)
12259 dump_file << mmesh_pt->uniform_refinement_level_when_pruned()
12260 <<
" # uniform refinement when pruned " << std::endl;
12264 dump_file << 0 <<
" # (fake) uniform refinement when pruned "
12268 dump_file << 9999 <<
" # test flag for end of sub-meshes " << std::endl;
12271 #ifdef OOMPH_HAS_MPI
12279 for (
unsigned e = 0;
e < n;
e++)
12286 local_base_element_processor[
e] = my_rank;
12301 MPI_Allreduce(&local_base_element_processor[0],
12302 &base_element_processor[0],
12312 base_element_processor = local_base_element_processor;
12316 dump_file << n <<
" # Number of base elements; partitioning follows.\n";
12317 for (
unsigned e = 0;
e < n;
e++)
12319 dump_file << base_element_processor[
e] <<
"\n";
12321 dump_file <<
"8888 #test flag for end of base element distribution\n";
12333 mmesh_pt->dump_refinement(dump_file);
12335 #ifdef OOMPH_HAS_TRIANGLE_LIB
12340 #ifdef OOMPH_HAS_MPI
12359 for (
unsigned imesh = 0; imesh < n_mesh; imesh++)
12365 mmesh_pt->dump_refinement(dump_file);
12367 #ifdef OOMPH_HAS_TRIANGLE_LIB
12373 #ifdef OOMPH_HAS_MPI
12393 bool unsteady_flag = (
time_pt() != 0);
12394 dump_file << unsteady_flag <<
" # bool flag for unsteady" << std::endl;
12400 dump_file <<
time_pt()->
time() <<
" # Time " << std::endl;
12403 dump_file << n_dt <<
" # Number of timesteps " << std::endl;
12404 for (
unsigned i = 0;
i < n_dt;
i++)
12406 dump_file <<
time_pt()->
dt(
i) <<
" # dt " << std::endl;
12413 dump_file <<
"0.0 # Dummy time from steady run " << std::endl;
12415 dump_file <<
"0 # Dummy number of timesteps from steady run" << std::endl;
12420 if (nmesh == 0) nmesh = 1;
12421 for (
unsigned m = 0; m < nmesh; m++)
12430 dump_file << Nglobal <<
" # number of global Data items " << std::endl;
12431 for (
unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
12434 dump_file << std::endl;
12450 bool restart_file_is_open =
true;
12451 if (!restart_file.is_open())
12453 std::ostringstream warn_message;
12454 warn_message <<
"Restart file isn't open -- I'm assuming that this is\n";
12455 warn_message <<
"because we're restarting on a larger number of\n";
12456 warn_message <<
"processor than were in use when the restart data was \n";
12457 warn_message <<
"dumped.\n";
12459 warn_message.str(),
"Problem::read()", OOMPH_EXCEPTION_LOCATION);
12460 restart_file_is_open =
false;
12464 unsigned n_mesh = std::max(
unsigned(1),
nsub_mesh());
12469 getline(restart_file, input_string,
'#');
12472 restart_file.ignore(80,
'\n');
12475 unsigned n_submesh_read;
12476 n_submesh_read = std::atoi(input_string.c_str());
12479 if (restart_file_is_open)
12481 if (n_submesh_read != n_mesh)
12483 std::ostringstream error_message;
12485 <<
"Number of sub-meshes specified in restart file, "
12486 << n_submesh_read <<
" doesn't \n match the my number of sub-meshes,"
12487 << n_mesh << std::endl
12488 <<
"Make sure all sub-meshes have been added to the global mesh\n"
12489 <<
"when calling the Problem::dump() function.\n";
12491 OOMPH_CURRENT_FUNCTION,
12492 OOMPH_EXCEPTION_LOCATION);
12503 #ifdef OOMPH_HAS_MPI
12504 bool refine_and_prune_required =
false;
12507 for (
unsigned i = 0;
i < n_mesh;
i++)
12510 getline(restart_file, input_string,
'#');
12513 restart_file.ignore(80,
'\n');
12516 nrefinement_for_mesh[
i] = std::atoi(input_string.c_str());
12523 if (ref_mesh_pt == 0)
12525 if (nrefinement_for_mesh[
i] != 0)
12527 std::ostringstream error_stream;
12528 error_stream <<
"Nonzero uniform-refinement-when-pruned specified\n"
12529 <<
"even though mesh is not tree-based. Odd. May want\n"
12530 <<
"to check this carefully before disabling this \n"
12531 <<
"warning/error -- most likely if/when we start to\n"
12532 <<
"prune unstructured meshes [though I can't see why\n"
12533 <<
"we would want to do this, given that they are \n"
12534 <<
"currently totally re-generated...]\n";
12536 OOMPH_CURRENT_FUNCTION,
12537 OOMPH_EXCEPTION_LOCATION);
12543 unsigned local_min_ref = 0;
12544 unsigned local_max_ref = 0;
12548 unsigned min_ref = local_min_ref;
12550 #ifdef OOMPH_HAS_MPI
12557 int int_local_min_ref = local_min_ref;
12560 int_local_min_ref = INT_MAX;
12562 int int_min_ref = 0;
12563 MPI_Allreduce(&int_local_min_ref,
12571 min_ref = unsigned(int_min_ref);
12576 if (nrefinement_for_mesh[
i] >= min_ref)
12578 nrefinement_for_mesh[
i] -= min_ref;
12582 #ifdef OOMPH_HAS_MPI
12583 if (nrefinement_for_mesh[
i] > 0)
12585 refine_and_prune_required =
true;
12593 #ifdef OOMPH_HAS_MPI
12596 unsigned local_req_flag = 0;
12597 unsigned req_flag = 0;
12598 if (refine_and_prune_required)
12600 local_req_flag = 1;
12602 MPI_Allreduce(&local_req_flag,
12608 refine_and_prune_required =
false;
12611 refine_and_prune_required =
true;
12617 if (refine_and_prune_required)
12622 MPI_Allreduce(&local_nrefinement_for_mesh[0],
12623 &nrefinement_for_mesh[0],
12634 std::ostringstream error_message;
12635 error_message <<
"Number of uniform refinements was not consistent \n"
12636 <<
"for following meshes during restart on processor \n"
12637 <<
"on which restart file could be opened:\n";
12638 for (
unsigned i = 0;
i < n_mesh;
i++)
12640 if ((local_nrefinement_for_mesh[
i] != nrefinement_for_mesh[
i]) &&
12641 restart_file_is_open)
12644 error_message <<
"Sub-mesh: " <<
i <<
"; local nrefinement: "
12645 << local_nrefinement_for_mesh[
i] <<
" "
12646 <<
"; global/synced nrefinement: "
12647 << nrefinement_for_mesh[
i] <<
"\n";
12653 error_message.str(),
"Problem::read()", OOMPH_EXCEPTION_LOCATION);
12661 getline(restart_file, input_string,
'#');
12664 restart_file.ignore(80,
'\n');
12668 tmp = std::atoi(input_string.c_str());
12671 if (restart_file_is_open)
12675 std::ostringstream error_message;
12677 <<
"Error in reading restart data: Uniform refinement when pruned \n"
12678 <<
"flags should be followed by 9999.\n";
12680 OOMPH_CURRENT_FUNCTION,
12681 OOMPH_EXCEPTION_LOCATION);
12692 #ifdef OOMPH_HAS_MPI
12695 if (refine_and_prune_required)
12724 std::streampos position_before_base_element = restart_file.tellg();
12726 bool read_in_base_element_info =
true;
12729 getline(restart_file, input_string,
'#');
12732 restart_file.ignore(80,
'\n');
12735 unsigned n_base_element_read_in = atoi(input_string.c_str());
12737 if (restart_file_is_open)
12739 if (n_base_element_read_in != nbase)
12746 std::ostringstream warn_message;
12748 <<
"The number of base elements in the mesh is 0,\n"
12749 <<
" but the restart file indicates that there are "
12750 << n_base_element_read_in <<
".\n"
12751 <<
"This could be because the restart file was \n"
12752 <<
"generated by using code without MPI.\n"
12754 <<
"The best fix is to include two additional lines\n"
12755 <<
"in the restart file: \n\n"
12756 <<
"0 # Number of base elements; partitioning follows.\n"
12757 <<
"8888 # Test flag for end of base element distribution\n"
12759 <<
"These lines go after the flag 9999 that indicates\n"
12760 <<
"the end of the submesh information.\n"
12762 <<
"The file will now continue to be read assuming that\n"
12763 <<
"the base element information is not present.\n"
12764 <<
"If you get strange results then please look carefully\n"
12765 <<
"at the restart file. The safest thing to do is to \n"
12766 <<
"ensure that the restart file was generated by code\n"
12767 <<
"compiled and run with the same parallel options.\n";
12769 OOMPH_CURRENT_FUNCTION,
12770 OOMPH_EXCEPTION_LOCATION);
12773 read_in_base_element_info =
false;
12774 restart_file.seekg(position_before_base_element);
12779 std::ostringstream error_message;
12780 error_message <<
"About to read " << n_base_element_read_in
12781 <<
" base elements \n"
12782 <<
"though we only have " << nbase
12783 <<
" base elements in mesh.\n";
12785 OOMPH_CURRENT_FUNCTION,
12786 OOMPH_EXCEPTION_LOCATION);
12792 if (read_in_base_element_info ==
true)
12796 for (
unsigned e = 0;
e < nbase;
e++)
12799 getline(restart_file, input_string);
12802 target_domain_for_base_element[
e] = atoi(input_string.c_str());
12806 getline(restart_file, input_string,
'#');
12809 restart_file.ignore(80,
'\n');
12812 tmp = std::atoi(input_string.c_str());
12816 if (restart_file_is_open)
12820 std::ostringstream error_message;
12822 <<
"Error in reading restart data: Target proc for base elements \n"
12823 <<
"should be followed by 8888.\n";
12825 OOMPH_CURRENT_FUNCTION,
12826 OOMPH_EXCEPTION_LOCATION);
12835 unsigned load_balance_required_flag = 0;
12839 unsigned local_load_balance_required_flag = 0;
12844 for (
unsigned e = 0;
e < nel;
e++)
12850 unsigned el_number_in_base_mesh_plus_one =
12856 if (el_number_in_base_mesh_plus_one == 0)
12859 if (face_el_pt != 0)
12866 el_number_in_base_mesh_plus_one =
12870 if (el_number_in_base_mesh_plus_one == 0)
12873 "el_number_in_base_mesh_plus_one=0 for bulk",
12875 OOMPH_EXCEPTION_LOCATION);
12883 if (el_number_in_base_mesh_plus_one == 0)
12886 OOMPH_CURRENT_FUNCTION,
12887 OOMPH_EXCEPTION_LOCATION);
12892 target_domain_for_local_non_halo_element.push_back(
12893 target_domain_for_base_element[el_number_in_base_mesh_plus_one -
12897 if (
int(target_domain_for_base_element
12898 [el_number_in_base_mesh_plus_one - 1]) != my_rank)
12900 local_load_balance_required_flag = 1;
12908 MPI_Allreduce(&local_load_balance_required_flag,
12909 &load_balance_required_flag,
12917 if (load_balance_required_flag == 1)
12919 oomph_info <<
"Doing load balancing after pruning\n";
12922 bool report_stats =
false;
12924 doc_info, report_stats, target_domain_for_local_non_halo_element);
12925 oomph_info <<
"Done load balancing after pruning\n";
12929 oomph_info <<
"No need for load balancing after pruning\n";
12938 bool have_read_unstructured_mesh =
false;
12975 mmesh_pt->refine(restart_file);
12977 #ifdef OOMPH_HAS_TRIANGLE_LIB
12982 #ifdef OOMPH_HAS_MPI
12995 have_read_unstructured_mesh =
true;
12996 #ifdef OOMPH_HAS_MPI
13018 for (
unsigned imesh = 0; imesh < n_mesh; imesh++)
13031 mmesh_pt->refine(restart_file);
13033 #ifdef OOMPH_HAS_TRIANGLE_LIB
13039 #ifdef OOMPH_HAS_MPI
13052 have_read_unstructured_mesh =
true;
13054 #ifdef OOMPH_HAS_MPI
13088 if (have_read_unstructured_mesh)
13093 std::ostringstream warn_message;
13095 <<
"I've just read in some unstructured meshes and have, in\n"
13096 <<
"the process, totally re-generated their nodes and elements.\n"
13097 <<
"This may create dangling pointers that still point to the\n"
13098 <<
"old nodes and elements, e.g. because FaceElements were\n"
13099 <<
"attached to these meshes or pointers to nodes and elements\n"
13100 <<
"were stored somewhere. FaceElements should therefore be\n"
13101 <<
"removed before reading in these meshes, using an overloaded\n"
13102 <<
"version of the function\n\n"
13103 <<
" Problem::actions_before_read_unstructured_meshes()\n\n"
13104 <<
"and then re-attached using an overloaded version of\n\n"
13105 <<
" Problem::actions_after_read_unstructured_meshes().\n\n"
13106 <<
"The required content of these functions is likely to be "
13108 <<
"to the Problem::actions_before_adapt() and \n"
13109 <<
"Problem::actions_after_adapt() that would be required in\n"
13110 <<
"a spatially adaptive computation. If these functions already\n"
13111 <<
"exist and perform the required actions, the \n"
13112 <<
"actions_before/after_read_unstructured_meshes() functions\n"
13113 <<
"can remain empty because the former are called automatically.\n"
13114 <<
"In this case, this warning my be suppressed by setting the\n"
13115 <<
"public boolean\n\n"
13117 "Problem::Suppress_warning_about_actions_before_read_"
13118 "unstructured_meshes\n\n"
13119 <<
"to true." << std::endl;
13121 OOMPH_CURRENT_FUNCTION,
13122 OOMPH_EXCEPTION_LOCATION);
13128 oomph_info <<
"\nNumber of equations in Problem::read(): "
13133 unsigned local_unsteady_restart_flag = 0;
13134 double local_time = -DBL_MAX;
13135 unsigned local_n_dt = 0;
13136 #ifdef OOMPH_HAS_MPI
13137 unsigned local_sync_needed_flag = 0;
13141 if (restart_file.is_open())
13143 oomph_info <<
"Restart file exists" << std::endl;
13144 #ifdef OOMPH_HAS_MPI
13145 local_sync_needed_flag = 0;
13148 getline(restart_file, input_string,
'#');
13151 restart_file.ignore(80,
'\n');
13154 local_unsteady_restart_flag = atoi(input_string.c_str());
13157 getline(restart_file, input_string,
'#');
13160 restart_file.ignore(80,
'\n');
13163 local_time = atof(input_string.c_str());
13166 getline(restart_file, input_string,
'#');
13169 restart_file.ignore(80,
'\n');
13172 local_n_dt = atoi(input_string.c_str());
13173 local_dt.resize(local_n_dt);
13176 for (
unsigned i = 0;
i < local_n_dt;
i++)
13179 getline(restart_file, input_string,
'#');
13182 restart_file.ignore(80,
'\n');
13185 double prev_dt = atof(input_string.c_str());
13186 local_dt[
i] = prev_dt;
13191 oomph_info <<
"Restart file does not exist" << std::endl;
13192 #ifdef OOMPH_HAS_MPI
13193 local_sync_needed_flag = 1;
13202 unsigned sync_needed_flag = 0;
13204 #ifdef OOMPH_HAS_MPI
13208 MPI_Allreduce(&local_sync_needed_flag,
13218 if (sync_needed_flag == 1)
13220 #ifdef OOMPH_HAS_MPI
13226 std::ostringstream error_message;
13227 error_message <<
"Synchronisation of temporal restart data \n"
13228 <<
"required even though Problem hasn't been distributed "
13231 OOMPH_CURRENT_FUNCTION,
13232 OOMPH_EXCEPTION_LOCATION);
13237 unsigned unsteady_restart_flag = 0;
13238 MPI_Allreduce(&local_unsteady_restart_flag,
13239 &unsteady_restart_flag,
13246 unsteady_restart =
false;
13247 if (unsteady_restart_flag == 1)
13249 unsteady_restart =
true;
13252 double time = -DBL_MAX;
13253 MPI_Allreduce(&local_time,
13263 MPI_Allreduce(&local_n_dt,
13273 if (local_dt.size() == 0)
13275 local_dt.resize(n_dt, -DBL_MAX);
13279 MPI_Allreduce(&local_dt[0],
13289 std::ostringstream error_message;
13291 <<
"Synchronisation of temporal restart data \n"
13292 <<
"required even though we don't have mpi support -- very odd!\n";
13294 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13301 unsteady_restart =
false;
13302 if (local_unsteady_restart_flag == 1)
13304 unsteady_restart =
true;
13307 dt.resize(local_n_dt);
13308 for (
unsigned i = 0;
i < local_n_dt;
i++)
13310 dt[
i] = local_dt[
i];
13321 if (nmesh == 0) nmesh = 1;
13322 for (
unsigned m = 0; m < nmesh; m++)
13368 #ifdef OOMPH_HAS_TRIANGLE_LIB
13378 mmesh_pt->update_polyline_representation_from_restart();
13390 getline(restart_file, input_string,
'#');
13393 restart_file.ignore(80,
'\n');
13396 unsigned long check_nglobal = atoi(input_string.c_str());
13399 if (restart_file_is_open)
13401 if (check_nglobal != Nglobal)
13403 std::ostringstream error_message;
13404 error_message <<
"The number of global data " << Nglobal
13405 <<
" is not equal to that specified in the input file "
13406 << check_nglobal << std::endl;
13409 OOMPH_CURRENT_FUNCTION,
13410 OOMPH_EXCEPTION_LOCATION);
13414 for (
unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
13433 for (
unsigned i = 0;
i < n_time_steppers;
i++)
13456 for (
unsigned i = 0;
i < n_time_steppers;
i++)
13472 bool passed =
true;
13484 <<
"\n ERROR: Failed Mesh::self_test() for single mesh in problem"
13491 for (
unsigned imesh = 0; imesh < Nmesh; imesh++)
13496 oomph_info <<
"\n ERROR: Failed Mesh::self_test() for mesh imesh"
13497 << imesh << std::endl;
13505 for (
unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
13511 <<
"\n ERROR: Failed Data::self_test() for global data iglobal"
13512 << iglobal << std::endl;
13517 #ifdef OOMPH_HAS_MPI
13548 unsigned& n_unrefined,
13549 const unsigned& bifurcation_type,
13550 const bool& actually_adapt)
13561 double omega = 0.0;
13563 if (bifurcation_type == 3)
13569 double sigma = 0.0;
13570 if (bifurcation_type == 2)
13572 sigma = this->
dof(this->
ndof() - 1);
13582 const unsigned n_copies = eigenfunction.size();
13586 for (
unsigned c = 0; c < n_copies; c++)
13607 if (mmesh_pt->is_adaptation_enabled())
13614 mmesh_pt->refine_base_mesh_as_in_reference_mesh(
13620 <<
"Info/Warning: Mesh in orginal problem is not refineable."
13626 oomph_info <<
"Info/Warning: Mesh adaptation is disabled in copy."
13632 oomph_info <<
"Info/Warning: Mesh cannot be adapted in copy."
13639 for (
unsigned m = 0; m < N_mesh; m++)
13647 if (mmesh_pt->is_adaptation_enabled())
13654 mmesh_pt->refine_base_mesh_as_in_reference_mesh(
13659 oomph_info <<
"Info/Warning: Mesh in orginal problem is not "
13667 <<
"Info/Warning: Mesh adaptation is disabled in copy."
13673 oomph_info <<
"Info/Warning: Mesh cannot be adapted in copy."
13692 for (
unsigned c = 0; c < n_copies; c++)
13699 std::ostringstream error_stream;
13700 error_stream <<
"Number of unknowns in the problem copy " << c <<
" "
13701 <<
"not equal to number in the original:\n"
13702 << this->
ndof() <<
" (original) "
13706 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13717 if (bifurcation_type == 2)
13720 ->symmetrise_eigenfunction_for_adaptive_pitchfork_tracking();
13728 for (
unsigned c = 0; c < n_copies; c++)
13734 unsigned n_mesh = base_error.size();
13737 if (n_mesh != eigenfunction_error.size())
13739 std::ostringstream error_stream;
13740 error_stream <<
"Problems do not have the same number of meshes\n"
13741 <<
"Base : " << n_mesh
13742 <<
" : Eigenproblem : " << eigenfunction_error.size()
13745 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13749 for (
unsigned m = 0; m < n_mesh; m++)
13752 unsigned n_element = base_error[m].size();
13754 if (n_element != eigenfunction_error[m].size())
13756 std::ostringstream error_stream;
13757 error_stream <<
"Mesh " << m
13758 <<
" does not have the same number of elements in the "
13760 <<
"Base: " << n_element
13761 <<
" : Eigenproblem: " << eigenfunction_error[m].size()
13764 OOMPH_CURRENT_FUNCTION,
13765 OOMPH_EXCEPTION_LOCATION);
13769 for (
unsigned e = 0;
e < n_element;
e++)
13772 base_error[m][
e] += eigenfunction_error[m][
e];
13779 if (actually_adapt)
13782 for (
unsigned c = 0; c < n_copies; c++)
13785 n_refined, n_unrefined, base_error);
13788 if (bifurcation_type == 2)
13791 ->symmetrise_eigenfunction_for_adaptive_pitchfork_tracking();
13795 for (
unsigned c = 0; c < n_copies; c++)
13802 switch (bifurcation_type)
13813 this->
dof(this->
ndof() - 1) = sigma;
13819 parameter_pt, omega, eigenfunction[0], eigenfunction[1]);
13823 std::ostringstream error_stream;
13824 error_stream <<
"Bifurcation type " << bifurcation_type
13826 <<
"1: Fold, 2: Pitchfork, 3: Hopf\n";
13828 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13844 unsigned n_refined, n_unrefined;
13861 double t_start_total = 0.0;
13870 bool continuation_problem =
false;
13878 continuation_problem =
true;
13883 if (bifurcation_type != 0)
13890 if (continuation_problem)
13895 for (
unsigned c = 0; c < 2; c++)
13918 if (mmesh_pt->is_adaptation_enabled())
13925 if (
dynamic_cast<SolidMesh*
>(original_mesh_pt) != 0)
13928 <<
"Info/Warning: Adaptive Continuation is broken in "
13929 <<
"SolidElement" << std::endl;
13931 mmesh_pt->refine_base_mesh_as_in_reference_mesh(
13936 oomph_info <<
"Info/Warning: Mesh in orginal problem is not "
13944 <<
"Info/Warning: Mesh adaptation is disabled in copy."
13955 if (
dynamic_cast<SolidMesh*
>(original_mesh_pt) != 0)
13958 <<
"Info/Warning: Adaptive Continuation is broken in "
13959 <<
"SolidElement" << std::endl;
13965 std::ofstream tri_dump(
"triangle_mesh.dmp");
13966 original_mesh_pt->dump_triangulateio(tri_dump);
13968 std::ifstream tri_read(
"triangle_mesh.dmp");
13969 tmesh_pt->remesh_from_triangulateio(tri_read);
13976 const unsigned n_node = original_mesh_pt->nnode();
13977 for (
unsigned n = 0; n < n_node; ++n)
13979 Node*
const nod_pt = original_mesh_pt->node_pt(n);
13980 Node*
const new_node_pt = tmesh_pt->node_pt(n);
13981 unsigned n_dim = nod_pt->
ndim();
13982 for (
unsigned i = 0;
i < n_dim; ++
i)
13984 new_node_pt->
x(
i) = nod_pt->
x(
i);
13991 <<
"Info/warning: Original Mesh is not TriangleBased\n"
13992 <<
"... but the copy is!" << std::endl;
13997 oomph_info <<
"Info/Warning: Mesh cannot be adapted in copy."
14004 for (
unsigned m = 0; m < N_mesh; m++)
14012 if (mmesh_pt->is_adaptation_enabled())
14019 if (
dynamic_cast<SolidMesh*
>(original_mesh_pt) != 0)
14022 <<
"Info/Warning: Adaptive Continuation is broken in "
14023 <<
"SolidElement" << std::endl;
14026 mmesh_pt->refine_base_mesh_as_in_reference_mesh(
14031 oomph_info <<
"Info/Warning: Mesh in orginal problem is "
14039 <<
"Info/Warning: Mesh adaptation is disabled in copy."
14050 if (
dynamic_cast<SolidMesh*
>(original_mesh_pt) != 0)
14053 <<
"Info/Warning: Adaptive Continuation is broken in "
14054 <<
"SolidElement" << std::endl;
14060 std::ofstream tri_dump(
"triangle_mesh.dmp");
14061 original_mesh_pt->dump_triangulateio(tri_dump);
14063 std::ifstream tri_read(
"triangle_mesh.dmp");
14064 tmesh_pt->remesh_from_triangulateio(tri_read);
14070 const unsigned n_node = original_mesh_pt->nnode();
14071 for (
unsigned n = 0; n < n_node; ++n)
14073 Node*
const nod_pt = original_mesh_pt->node_pt(n);
14074 Node*
const new_node_pt = tmesh_pt->node_pt(n);
14075 unsigned n_dim = nod_pt->
ndim();
14076 for (
unsigned i = 0;
i < n_dim; ++
i)
14078 new_node_pt->
x(
i) = nod_pt->
x(
i);
14085 <<
"Info/warning: Original Mesh is not TriangleBased\n"
14086 <<
"... but the copy is!" << std::endl;
14091 oomph_info <<
"Info/Warning: Mesh cannot be adapted in copy."
14117 std::ostringstream error_stream;
14118 error_stream <<
"Number of unknowns in the problem copy " << c <<
" "
14119 <<
"not equal to number in the original:\n"
14120 << this->
ndof() <<
" (original) "
14124 OOMPH_CURRENT_FUNCTION,
14125 OOMPH_EXCEPTION_LOCATION);
14133 for (
unsigned i = 0;
i < ndof_local;
i++)
14147 n_refined, n_unrefined, base_error);
14149 n_refined, n_unrefined, base_error);
14161 for (
unsigned i = 0;
i < ndof_local;
i++)
14171 oomph_info <<
"Adapting problem:" << std::endl;
14172 oomph_info <<
"=================" << std::endl;
14174 double t_start = 0.0;
14183 double t_end = 0.0;
14187 oomph_info <<
"Time for actions before adapt: " << t_end - t_start
14207 if (mmesh_pt->is_adaptation_enabled())
14213 mmesh_pt->spatial_error_estimator_pt();
14216 if (error_estimator_pt == 0)
14219 OOMPH_CURRENT_FUNCTION,
14220 OOMPH_EXCEPTION_LOCATION);
14227 if (mmesh_pt->doc_info_pt() == 0)
14234 mesh_pt(0), elemental_error, *mmesh_pt->doc_info_pt());
14238 mmesh_pt->max_error() = std::fabs(*std::max_element(
14239 elemental_error.begin(), elemental_error.end(),
AbsCmp<double>()));
14241 mmesh_pt->min_error() = std::fabs(*std::min_element(
14242 elemental_error.begin(), elemental_error.end(),
AbsCmp<double>()));
14244 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
14245 << mmesh_pt->min_error() << std::endl
14252 oomph_info <<
"Time for error estimation: " << t_end - t_start
14258 mmesh_pt->adapt(elemental_error);
14261 n_refined += mmesh_pt->nrefined();
14262 n_unrefined += mmesh_pt->nunrefined();
14267 oomph_info <<
"Time for complete mesh adaptation "
14268 <<
"(but excluding comp of error estimate): "
14269 << t_end - t_start << std::endl;
14275 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14281 oomph_info <<
"Info/Warning: Mesh cannot be adapted" << std::endl;
14289 for (
unsigned imesh = 0; imesh < Nmesh; imesh++)
14299 mmesh_pt->spatial_error_estimator_pt();
14302 if (error_estimator_pt == 0)
14305 OOMPH_CURRENT_FUNCTION,
14306 OOMPH_EXCEPTION_LOCATION);
14310 if (mmesh_pt->is_adaptation_enabled())
14314 if (mmesh_pt->doc_info_pt() == 0)
14322 mesh_pt(imesh), elemental_error, *mmesh_pt->doc_info_pt());
14326 if (
mesh_pt(imesh)->nelement() > 0)
14328 mmesh_pt->max_error() =
14329 std::fabs(*std::max_element(elemental_error.begin(),
14330 elemental_error.end(),
14333 mmesh_pt->min_error() =
14334 std::fabs(*std::min_element(elemental_error.begin(),
14335 elemental_error.end(),
14339 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
14340 << mmesh_pt->min_error() << std::endl;
14346 oomph_info <<
"Time for error estimation: " << t_end - t_start
14352 mmesh_pt->adapt(elemental_error);
14355 n_refined += mmesh_pt->nrefined();
14356 n_unrefined += mmesh_pt->nunrefined();
14362 oomph_info <<
"Time for complete mesh adaptation "
14363 <<
"(but excluding comp of error estimate): "
14364 << t_end - t_start << std::endl;
14370 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14376 oomph_info <<
"Info/Warning: Mesh cannot be adapted." << std::endl;
14389 oomph_info <<
"Total time for actual adaptation "
14390 <<
"(all meshes; incl error estimates): " << t_end - t_start
14402 oomph_info <<
"Time for actions after adapt: " << t_end - t_start
14406 oomph_info <<
"About to start re-assigning eqn numbers "
14407 <<
"with Problem::assign_eqn_numbers() at end of "
14408 <<
"Problem::adapt().\n";
14419 oomph_info <<
"Time for re-assigning eqn numbers with "
14420 <<
"Problem::assign_eqn_numbers() at end of Problem::adapt(): "
14421 << t_end - t_start << std::endl;
14422 oomph_info <<
"Total time for adapt: " << t_end - t_start_total
14438 double t_start_total = 0.0;
14448 if (bifurcation_type != 0)
14456 oomph_info <<
"p-adapting problem:" << std::endl;
14457 oomph_info <<
"===================" << std::endl;
14459 double t_start = 0.0;
14468 double t_end = 0.0;
14472 oomph_info <<
"Time for actions before adapt: " << t_end - t_start
14492 if (mmesh_pt->is_p_adaptation_enabled())
14498 mmesh_pt->spatial_error_estimator_pt();
14501 if (error_estimator_pt == 0)
14504 OOMPH_CURRENT_FUNCTION,
14505 OOMPH_EXCEPTION_LOCATION);
14512 if (mmesh_pt->doc_info_pt() == 0)
14519 mesh_pt(0), elemental_error, *mmesh_pt->doc_info_pt());
14523 mmesh_pt->max_error() = std::fabs(*std::max_element(
14524 elemental_error.begin(), elemental_error.end(),
AbsCmp<double>()));
14526 mmesh_pt->min_error() = std::fabs(*std::min_element(
14527 elemental_error.begin(), elemental_error.end(),
AbsCmp<double>()));
14529 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
14530 << mmesh_pt->min_error() << std::endl
14537 oomph_info <<
"Time for error estimation: " << t_end - t_start
14543 mmesh_pt->p_adapt(elemental_error);
14546 n_refined += mmesh_pt->nrefined();
14547 n_unrefined += mmesh_pt->nunrefined();
14552 oomph_info <<
"Time for complete mesh adaptation "
14553 <<
"(but excluding comp of error estimate): "
14554 << t_end - t_start << std::endl;
14560 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14566 oomph_info <<
"Info/Warning: Mesh cannot be adapted" << std::endl;
14574 for (
unsigned imesh = 0; imesh < Nmesh; imesh++)
14584 mmesh_pt->spatial_error_estimator_pt();
14587 if (error_estimator_pt == 0)
14590 OOMPH_CURRENT_FUNCTION,
14591 OOMPH_EXCEPTION_LOCATION);
14595 if (mmesh_pt->is_p_adaptation_enabled())
14599 if (mmesh_pt->doc_info_pt() == 0)
14607 mesh_pt(imesh), elemental_error, *mmesh_pt->doc_info_pt());
14611 if (
mesh_pt(imesh)->nelement() > 0)
14613 mmesh_pt->max_error() =
14614 std::fabs(*std::max_element(elemental_error.begin(),
14615 elemental_error.end(),
14618 mmesh_pt->min_error() =
14619 std::fabs(*std::min_element(elemental_error.begin(),
14620 elemental_error.end(),
14624 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
14625 << mmesh_pt->min_error() << std::endl;
14631 oomph_info <<
"Time for error estimation: " << t_end - t_start
14637 mmesh_pt->p_adapt(elemental_error);
14640 n_refined += mmesh_pt->nrefined();
14641 n_unrefined += mmesh_pt->nunrefined();
14647 oomph_info <<
"Time for complete mesh adaptation "
14648 <<
"(but excluding comp of error estimate): "
14649 << t_end - t_start << std::endl;
14655 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14661 oomph_info <<
"Info/Warning: Mesh cannot be adapted." << std::endl;
14674 oomph_info <<
"Total time for actual adaptation "
14675 <<
"(all meshes; incl error estimates): " << t_end - t_start
14687 oomph_info <<
"Time for actions after adapt: " << t_end - t_start
14691 oomph_info <<
"About to start re-assigning eqn numbers "
14692 <<
"with Problem::assign_eqn_numbers() at end of "
14693 <<
"Problem::adapt().\n";
14704 oomph_info <<
"Time for re-assigning eqn numbers with "
14705 <<
"Problem::assign_eqn_numbers() at end of Problem::adapt(): "
14706 << t_end - t_start << std::endl;
14707 oomph_info <<
"Total time for adapt: " << t_end - t_start_total
14722 unsigned& n_refined,
14723 unsigned& n_unrefined,
14727 oomph_info <<
"Adapting problem:" << std::endl;
14728 oomph_info <<
"=================" << std::endl;
14748 if (mmesh_pt->is_adaptation_enabled())
14751 mmesh_pt->adapt(elemental_error[0]);
14754 n_refined += mmesh_pt->nrefined();
14755 n_unrefined += mmesh_pt->nunrefined();
14759 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14765 oomph_info <<
"Info/Warning: Mesh cannot be adapted" << std::endl;
14774 for (
unsigned imesh = 0; imesh < Nmesh; imesh++)
14780 if (mmesh_pt->is_adaptation_enabled())
14783 mmesh_pt->adapt(elemental_error[imesh]);
14786 n_refined += mmesh_pt->nrefined();
14787 n_unrefined += mmesh_pt->nunrefined();
14791 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14797 oomph_info <<
"Info/Warning: Mesh cannot be adapted." << std::endl;
14830 elemental_error.resize(1);
14836 if (mmesh_pt->is_adaptation_enabled())
14840 mmesh_pt->spatial_error_estimator_pt();
14843 if (error_estimator_pt == 0)
14846 OOMPH_CURRENT_FUNCTION,
14847 OOMPH_EXCEPTION_LOCATION);
14852 elemental_error[0].resize(mmesh_pt->nelement());
14854 if (mmesh_pt->doc_info_pt() == 0)
14857 elemental_error[0]);
14862 elemental_error[0],
14863 *mmesh_pt->doc_info_pt());
14867 mmesh_pt->max_error() =
14868 std::fabs(*std::max_element(elemental_error[0].begin(),
14869 elemental_error[0].end(),
14872 mmesh_pt->min_error() =
14873 std::fabs(*std::min_element(elemental_error[0].begin(),
14874 elemental_error[0].end(),
14877 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
14878 << mmesh_pt->min_error() << std::endl;
14882 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14888 oomph_info <<
"Info/Warning: Mesh cannot be adapted" << std::endl;
14897 elemental_error.resize(Nmesh);
14900 for (
unsigned imesh = 0; imesh < Nmesh; imesh++)
14908 mmesh_pt->spatial_error_estimator_pt();
14911 if (error_estimator_pt == 0)
14914 OOMPH_CURRENT_FUNCTION,
14915 OOMPH_EXCEPTION_LOCATION);
14919 if (mmesh_pt->is_adaptation_enabled())
14922 elemental_error[imesh].resize(mmesh_pt->nelement());
14923 if (mmesh_pt->doc_info_pt() == 0)
14926 elemental_error[imesh]);
14931 elemental_error[imesh],
14932 *mmesh_pt->doc_info_pt());
14936 mmesh_pt->max_error() =
14937 std::fabs(*std::max_element(elemental_error[imesh].begin(),
14938 elemental_error[imesh].end(),
14941 mmesh_pt->min_error() =
14942 std::fabs(*std::min_element(elemental_error[imesh].begin(),
14943 elemental_error[imesh].end(),
14946 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
14947 << mmesh_pt->min_error() << std::endl;
14951 oomph_info <<
"Info/Warning: Mesh adaptation is disabled."
14957 oomph_info <<
"Info/Warning: Mesh cannot be adapted." << std::endl;
14972 if (bifurcation_type != 0)
14992 mmesh_pt->spatial_error_estimator_pt();
14995 if (error_estimator_pt == 0)
14998 OOMPH_CURRENT_FUNCTION,
14999 OOMPH_EXCEPTION_LOCATION);
15012 mesh_pt(0), elemental_error, doc_info);
15016 mmesh_pt->max_error() = std::fabs(*std::max_element(
15017 elemental_error.begin(), elemental_error.end(),
AbsCmp<double>()));
15019 mmesh_pt->min_error() = std::fabs(*std::min_element(
15020 elemental_error.begin(), elemental_error.end(),
AbsCmp<double>()));
15022 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
15023 << mmesh_pt->min_error() << std::endl;
15032 for (
unsigned imesh = 0; imesh < Nmesh; imesh++)
15040 mmesh_pt->spatial_error_estimator_pt();
15043 if (error_estimator_pt == 0)
15046 OOMPH_CURRENT_FUNCTION,
15047 OOMPH_EXCEPTION_LOCATION);
15053 if (mmesh_pt->doc_info_pt() == 0)
15061 mesh_pt(imesh), elemental_error, *mmesh_pt->doc_info_pt());
15065 if (
mesh_pt(imesh)->nelement() > 0)
15067 mmesh_pt->max_error() =
15068 std::fabs(*std::max_element(elemental_error.begin(),
15069 elemental_error.end(),
15072 mmesh_pt->min_error() =
15073 std::fabs(*std::min_element(elemental_error.begin(),
15074 elemental_error.end(),
15078 oomph_info <<
"\n Max/min error: " << mmesh_pt->max_error() <<
" "
15079 << mmesh_pt->min_error() << std::endl;
15106 mmesh_pt->refine_selected_elements(elements_to_be_refined);
15110 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15116 std::ostringstream error_message;
15117 error_message <<
"Problem::refine_selected_elements(...) only works for\n"
15118 <<
"multiple-mesh problems if you specify the mesh\n"
15119 <<
"number in the function argument before the Vector,\n"
15120 <<
"or a Vector of Vectors for each submesh.\n"
15123 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15152 mmesh_pt->refine_selected_elements(elements_to_be_refined_pt);
15156 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15162 std::ostringstream error_message;
15163 error_message <<
"Problem::refine_selected_elements(...) only works for\n"
15164 <<
"multiple-mesh problems if you specify the mesh\n"
15165 <<
"number in the function argument before the Vector,\n"
15166 <<
"or a Vector of Vectors for each submesh.\n"
15169 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15191 if (i_mesh >= n_mesh)
15193 std::ostringstream error_message;
15194 error_message <<
"Problem only has " << n_mesh
15195 <<
" submeshes. Cannot refine submesh " << i_mesh
15198 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15205 mmesh_pt->refine_selected_elements(elements_to_be_refined);
15209 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15231 const unsigned& i_mesh,
15239 if (i_mesh >= n_mesh)
15241 std::ostringstream error_message;
15242 error_message <<
"Problem only has " << n_mesh
15243 <<
" submeshes. Cannot refine submesh " << i_mesh
15246 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15253 mmesh_pt->refine_selected_elements(elements_to_be_refined_pt);
15257 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15287 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
15292 mmesh_pt->refine_selected_elements(elements_to_be_refined[i_mesh]);
15296 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15324 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
15329 mmesh_pt->refine_selected_elements(elements_to_be_refined_pt[i_mesh]);
15333 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15367 mmesh_pt->p_refine_selected_elements(elements_to_be_refined);
15371 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15377 std::ostringstream error_message;
15379 <<
"Problem::p_refine_selected_elements(...) only works for\n"
15380 <<
"multiple-mesh problems if you specify the mesh\n"
15381 <<
"number in the function argument before the Vector,\n"
15382 <<
"or a Vector of Vectors for each submesh.\n"
15385 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15414 mmesh_pt->p_refine_selected_elements(elements_to_be_refined_pt);
15418 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15424 std::ostringstream error_message;
15426 <<
"Problem::p_refine_selected_elements(...) only works for\n"
15427 <<
"multiple-mesh problems if you specify the mesh\n"
15428 <<
"number in the function argument before the Vector,\n"
15429 <<
"or a Vector of Vectors for each submesh.\n"
15432 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15450 "p-refinement for multiple submeshes has not yet been tested.",
15451 "Problem::p_refine_selected_elements()",
15452 OOMPH_EXCEPTION_LOCATION);
15459 if (i_mesh >= n_mesh)
15461 std::ostringstream error_message;
15462 error_message <<
"Problem only has " << n_mesh
15463 <<
" submeshes. Cannot p-refine submesh " << i_mesh
15466 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15473 mmesh_pt->p_refine_selected_elements(elements_to_be_refined);
15477 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15499 const unsigned& i_mesh,
15503 "p-refinement for multiple submeshes has not yet been tested.",
15504 "Problem::p_refine_selected_elements()",
15505 OOMPH_EXCEPTION_LOCATION);
15512 if (i_mesh >= n_mesh)
15514 std::ostringstream error_message;
15515 error_message <<
"Problem only has " << n_mesh
15516 <<
" submeshes. Cannot p-refine submesh " << i_mesh
15519 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15526 mmesh_pt->p_refine_selected_elements(elements_to_be_refined_pt);
15530 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15555 "p-refinement for multiple submeshes has not yet been tested.",
15556 "Problem::p_refine_selected_elements()",
15557 OOMPH_EXCEPTION_LOCATION);
15565 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
15570 mmesh_pt->p_refine_selected_elements(elements_to_be_refined[i_mesh]);
15574 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15597 "p-refinement for multiple submeshes has not yet been tested.",
15598 "Problem::p_refine_selected_elements()",
15599 OOMPH_EXCEPTION_LOCATION);
15607 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
15612 mmesh_pt->p_refine_selected_elements(elements_to_be_refined_pt[i_mesh]);
15616 oomph_info <<
"Info/Warning: Mesh cannot be refined " << std::endl;
15642 double t_start = 0.0;
15650 double t_end = 0.0;
15655 <<
"Time for actions before adapt in Problem::refine_uniformly_aux(): "
15656 << t_end - t_start << std::endl;
15670 unsigned nref = nrefine_for_mesh[0];
15671 for (
unsigned i = 0;
i < nref;
i++)
15673 mmesh_pt->refine_uniformly(doc_info);
15678 oomph_info <<
"Info/Warning: Mesh cannot be refined uniformly "
15686 for (
unsigned imesh = 0; imesh < n_mesh; imesh++)
15692 unsigned nref = nrefine_for_mesh[imesh];
15693 for (
unsigned i = 0;
i < nref;
i++)
15695 mmesh_pt->refine_uniformly(doc_info);
15700 oomph_info <<
"Info/Warning: Cannot refine mesh " << imesh
15711 oomph_info <<
"Time for mesh-level mesh refinement in "
15712 <<
"Problem::refine_uniformly_aux(): " << t_end - t_start
15725 <<
"Time for actions after adapt Problem::refine_uniformly_aux(): "
15726 << t_end - t_start << std::endl;
15731 #ifdef OOMPH_HAS_MPI
15744 oomph_info <<
"Time for Problem::prune_halo_elements_and_nodes() in "
15745 <<
"Problem::refine_uniformly_aux(): " << t_end - t_start
15753 std::ostringstream error_message;
15755 <<
"Requested pruning in serial build. Ignoring the request.\n";
15757 "Problem::refine_uniformly_aux()",
15758 OOMPH_EXCEPTION_LOCATION);
15764 <<
"Number of equations after Problem::refine_uniformly_aux(): "
15770 oomph_info <<
"Time for Problem::assign_eqn_numbers() in "
15771 <<
"Problem::refine_uniformly_aux(): " << t_end - t_start
15789 double t_start = 0.0;
15797 double t_end = 0.0;
15801 oomph_info <<
"Time for actions before adapt in "
15802 "Problem::p_refine_uniformly_aux(): "
15803 << t_end - t_start << std::endl;
15817 unsigned nref = nrefine_for_mesh[0];
15818 for (
unsigned i = 0;
i < nref;
i++)
15820 mmesh_pt->p_refine_uniformly(doc_info);
15825 oomph_info <<
"Info/Warning: Mesh cannot be p-refined uniformly "
15833 "p-refinement for multiple submeshes has not yet been tested.",
15834 "Problem::p_refine_uniformly_aux()",
15835 OOMPH_EXCEPTION_LOCATION);
15838 for (
unsigned imesh = 0; imesh < n_mesh; imesh++)
15844 unsigned nref = nrefine_for_mesh[imesh];
15845 for (
unsigned i = 0;
i < nref;
i++)
15847 mmesh_pt->p_refine_uniformly(doc_info);
15852 oomph_info <<
"Info/Warning: Cannot p-refine mesh " << imesh
15863 oomph_info <<
"Time for mesh-level mesh refinement in "
15864 <<
"Problem::p_refine_uniformly_aux(): " << t_end - t_start
15877 <<
"Time for actions after adapt Problem::p_refine_uniformly_aux(): "
15878 << t_end - t_start << std::endl;
15883 #ifdef OOMPH_HAS_MPI
15896 oomph_info <<
"Time for Problem::prune_halo_elements_and_nodes() in "
15897 <<
"Problem::p_refine_uniformly_aux(): " << t_end - t_start
15905 std::ostringstream error_message;
15907 <<
"Requested pruning in serial build. Ignoring the request.\n";
15909 "Problem::p_refine_uniformly_aux()",
15910 OOMPH_EXCEPTION_LOCATION);
15916 <<
"Number of equations after Problem::p_refine_uniformly_aux(): "
15922 oomph_info <<
"Time for Problem::assign_eqn_numbers() in "
15923 <<
"Problem::p_refine_uniformly_aux(): " << t_end - t_start
15941 std::ostringstream error_message;
15942 error_message <<
"imesh " << i_mesh
15943 <<
" is greater than the number of sub meshes "
15947 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15955 mmesh_pt->refine_uniformly(doc_info);
15959 oomph_info <<
"Info/Warning: Mesh cannot be refined uniformly "
15985 std::ostringstream error_message;
15986 error_message <<
"imesh " << i_mesh
15987 <<
" is greater than the number of sub meshes "
15991 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15999 mmesh_pt->p_refine_uniformly(doc_info);
16003 oomph_info <<
"Info/Warning: Mesh cannot be refined uniformly "
16030 unsigned success_flag = 0;
16042 success_flag += mmesh_pt->unrefine_uniformly();
16046 oomph_info <<
"Info/Warning: Mesh cannot be unrefined uniformly "
16054 for (
unsigned imesh = 0; imesh < n_mesh; imesh++)
16060 success_flag += mmesh_pt->unrefine_uniformly();
16064 oomph_info <<
"Info/Warning: Cannot unrefine mesh " << imesh
16079 if (success_flag > 0)
16100 unsigned success_flag = 0;
16106 std::ostringstream error_message;
16107 error_message <<
"imesh " << i_mesh
16108 <<
" is greater than the number of sub meshes "
16112 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
16120 success_flag += mmesh_pt->unrefine_uniformly();
16124 oomph_info <<
"Info/Warning: Mesh cannot be unrefined uniformly "
16138 if (success_flag > 0)
16167 mmesh_pt->p_unrefine_uniformly(doc_info);
16171 oomph_info <<
"Info/Warning: Mesh cannot be p-unrefined uniformly "
16179 throw OomphLibError(
"This functionality has not yet been tested.",
16180 OOMPH_CURRENT_FUNCTION,
16181 OOMPH_EXCEPTION_LOCATION);
16183 for (
unsigned imesh = 0; imesh < n_mesh; imesh++)
16189 mmesh_pt->p_unrefine_uniformly(doc_info);
16193 oomph_info <<
"Info/Warning: Cannot p-unrefine mesh " << imesh
16220 std::ostringstream error_message;
16221 error_message <<
"imesh " << i_mesh
16222 <<
" is greater than the number of sub meshes "
16226 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
16234 mmesh_pt->p_unrefine_uniformly(doc_info);
16238 oomph_info <<
"Info/Warning: Mesh cannot be p-unrefined uniformly "
16266 const unsigned& max_adapt,
16267 const bool& first_timestep,
16271 bool shift_it = shift;
16278 <<
"\n\n===========================================================\n";
16279 oomph_info <<
" ******** WARNING *********** \n";
16281 <<
"===========================================================\n";
16282 oomph_info <<
"Problem::unsteady_newton_solve() called with "
16284 oomph_info <<
"first_timestep: " << first_timestep << std::endl;
16285 oomph_info <<
"shift: " << shift << std::endl;
16286 oomph_info <<
"This doesn't make sense (shifting does have to be done"
16288 oomph_info <<
"since we're constantly re-assigning the initial conditions"
16291 <<
"\n===========================================================\n\n";
16299 unsigned max_solve = max_adapt + 1;
16303 for (
unsigned isolve = 0; isolve < max_solve; isolve++)
16308 unsigned n_refined;
16309 unsigned n_unrefined;
16312 adapt(n_refined, n_unrefined);
16314 #ifdef OOMPH_HAS_MPI
16317 unsigned total_refined = 0;
16318 unsigned total_unrefined = 0;
16321 MPI_Allreduce(&n_refined,
16327 n_refined = total_refined;
16328 MPI_Allreduce(&n_unrefined,
16334 n_unrefined = total_unrefined;
16338 oomph_info <<
"---> " << n_refined <<
" elements were refined, and "
16339 << n_unrefined <<
" were unrefined, in total." << std::endl;
16342 if ((n_refined == 0) && (n_unrefined == 0))
16344 oomph_info <<
"\n \n Solution is fully converged in "
16345 <<
"Problem::unsteady_newton_solver() \n \n ";
16355 if (first_timestep)
16360 oomph_info <<
"Re-setting initial condition " << std::endl;
16380 if ((isolve == 0) || (first_timestep))
16391 if (isolve == max_solve - 1)
16395 <<
"----------------------------------------------------------"
16397 <<
"Reached max. number of adaptations in \n"
16398 <<
"Problem::unsteady_newton_solver().\n"
16399 <<
"----------------------------------------------------------"
16419 unsigned max_solve = max_adapt + 1;
16423 for (
unsigned isolve = 0; isolve < max_solve; isolve++)
16428 unsigned n_refined;
16429 unsigned n_unrefined;
16432 adapt(n_refined, n_unrefined);
16434 #ifdef OOMPH_HAS_MPI
16437 unsigned total_refined = 0;
16438 unsigned total_unrefined = 0;
16441 MPI_Allreduce(&n_refined,
16447 n_refined = total_refined;
16448 MPI_Allreduce(&n_unrefined,
16454 n_unrefined = total_unrefined;
16458 oomph_info <<
"---> " << n_refined <<
" elements were refined, and "
16459 << n_unrefined <<
" were unrefined"
16460 #ifdef OOMPH_HAS_MPI
16461 <<
", in total (over all processors).\n";
16468 if ((n_refined == 0) && (n_unrefined == 0))
16470 oomph_info <<
"\n \n Solution is fully converged in "
16471 <<
"Problem::newton_solver(). \n \n ";
16493 <<
"USER-DEFINED ERROR IN NEWTON SOLVER " << std::endl;
16498 <<
") REACHED WITHOUT CONVERGENCE " << std::endl;
16509 std::ostringstream error_stream;
16510 error_stream <<
"Error occured in adaptive Newton solver. "
16513 OOMPH_CURRENT_FUNCTION,
16514 OOMPH_EXCEPTION_LOCATION);
16524 if (isolve == max_solve - 1)
16528 <<
"----------------------------------------------------------"
16530 <<
"Reached max. number of adaptations in \n"
16531 <<
"Problem::newton_solver().\n"
16532 <<
"----------------------------------------------------------"
16556 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
16564 #ifdef OOMPH_HAS_MPI
16585 for (
unsigned imesh = 0; imesh < n_mesh; ++imesh)
16607 oomph_info <<
"Checking halo schemes on single mesh" << std::endl;
16608 doc_info.
label() =
"_one_and_only_mesh_";
16614 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
16616 oomph_info <<
"Checking halo schemes on submesh " << i_mesh
16618 std::stringstream tmp;
16619 tmp <<
"_mesh" << i_mesh <<
"_";
16620 doc_info.
label() = tmp.str();
16635 bool do_halos =
true;
16636 bool do_external_halos =
false;
16641 do_external_halos =
true;
16656 const bool& do_external_halos)
16659 unsigned n_mesh_loop = 1;
16663 n_mesh_loop = nmesh;
16687 for (
int rank = 0; rank < n_proc; rank++)
16690 send_displacement[rank] = send_data.size();
16694 if (rank != my_rank)
16697 Mesh* my_mesh_pt = 0;
16700 for (
unsigned imesh = 0; imesh < n_mesh_loop; imesh++)
16716 for (
unsigned n = 0; n < n_nod; n++)
16727 unsigned nelem_haloed = haloed_elem_pt.size();
16728 for (
unsigned e = 0;
e < nelem_haloed;
e++)
16730 haloed_elem_pt[
e]->add_internal_data_values_to_vector(send_data);
16734 if (do_external_halos)
16739 for (
unsigned n = 0; n < n_ext_nod; n++)
16747 unsigned next_elem_haloed =
16749 for (
unsigned e = 0;
e < next_elem_haloed;
e++)
16759 send_n[rank] = send_data.size() - send_displacement[rank];
16767 MPI_Alltoall(&send_n[0],
16778 int receive_data_count = 0;
16779 for (
int rank = 0; rank < n_proc; ++rank)
16782 receive_displacement[rank] = receive_data_count;
16783 receive_data_count += receive_n[rank];
16788 if (receive_data_count == 0)
16790 ++receive_data_count;
16796 if (send_data.size() == 0)
16798 send_data.resize(1);
16802 MPI_Alltoallv(&send_data[0],
16804 &send_displacement[0],
16808 &receive_displacement[0],
16813 for (
int send_rank = 0; send_rank < n_proc; send_rank++)
16817 if ((send_rank != my_rank) && (receive_n[send_rank] != 0))
16820 unsigned count = receive_displacement[send_rank];
16823 Mesh* my_mesh_pt = 0;
16826 for (
unsigned imesh = 0; imesh < n_mesh_loop; imesh++)
16841 unsigned n_nod = my_mesh_pt->
nhalo_node(send_rank);
16842 for (
unsigned n = 0; n < n_nod; n++)
16854 unsigned nelem_halo = halo_elem_pt.size();
16855 for (
unsigned e = 0;
e < nelem_halo;
e++)
16857 halo_elem_pt[
e]->read_internal_data_values_from_vector(
16858 receive_data, count);
16862 if (do_external_halos)
16870 for (
unsigned n = 0; n < n_ext_nod; n++)
16879 unsigned next_elem_halo =
16881 for (
unsigned e = 0;
e < next_elem_halo;
e++)
16902 unsigned my_n_eqn =
Dof_pt.size();
16927 unsigned n_send = nproc - my_rank - 1;
16929 for (
unsigned p = my_rank + 1; p < nproc; p++)
16931 MPI_Isend(&my_n_eqn,
16937 &send_req[p - my_rank - 1]);
16942 for (
unsigned p = 0; p < my_rank; p++)
16944 MPI_Recv(&n_eqn_on_proc[p],
16950 MPI_STATUS_IGNORE);
16953 double t_end = 0.0;
16957 oomph_info <<
"Time for send and receive stuff: " << t_end - t_start
16964 unsigned my_eqn_num_base = 0;
16965 for (
unsigned p = 0; p < my_rank; p++)
16967 my_eqn_num_base += n_eqn_on_proc[p];
16979 for (
unsigned e = 0;
e < nelem;
e++)
16984 for (
unsigned iintern = 0; iintern < nintern_data; iintern++)
16987 unsigned nval = int_data_pt->
nvalue();
16988 for (
unsigned ival = 0; ival < nval; ival++)
16990 int old_eqn_number = int_data_pt->
eqn_number(ival);
16991 if (old_eqn_number >= 0)
16994 int new_eqn_number = old_eqn_number + my_eqn_num_base;
16995 int_data_pt->
eqn_number(ival) = new_eqn_number;
17004 for (
unsigned j = 0; j < nnod; j++)
17009 unsigned nval = nod_pt->
nvalue();
17011 for (
unsigned ival = 0; ival < nval; ival++)
17013 int old_eqn_number = nod_pt->
eqn_number(ival);
17015 if (old_eqn_number >= 0)
17018 int new_eqn_number = old_eqn_number + my_eqn_num_base;
17026 if (solid_nod_pt != 0)
17030 for (
unsigned ival = 0; ival < nval; ival++)
17032 int old_eqn_number =
17036 if (old_eqn_number >= 0)
17039 int new_eqn_number = old_eqn_number + my_eqn_num_base;
17050 oomph_info <<
"Time for bumping: " << t_end - t_start << std::endl;
17058 bool do_halos =
true;
17059 bool do_external_halos =
false;
17065 oomph_info <<
"Time for copy_haloed_eqn_numbers_helper for halos: "
17066 << t_end - t_start << std::endl;
17072 do_external_halos =
true;
17079 <<
"Time for copy_haloed_eqn_numbers_helper for external halos: "
17080 << t_end - t_start << std::endl;
17088 if (assign_local_eqn_numbers)
17094 if (n_sub_mesh == 0)
17100 for (
unsigned i = 0;
i < n_sub_mesh;
i++)
17110 oomph_info <<
"Time for assign_local_eqn_numbers in sync: "
17111 << t_end - t_start << std::endl;
17119 MPI_Waitall(n_send, &send_req[0], &send_status[0]);
17125 oomph_info <<
"Time for waitall: " << t_end - t_start << std::endl;
17145 const bool& do_external_halos)
17148 unsigned n_mesh_loop = 1;
17152 n_mesh_loop = nmesh;
17174 for (
int rank = 0; rank < n_proc; rank++)
17177 send_displacement[rank] = send_data.size();
17182 if (rank != my_rank)
17185 Mesh* my_mesh_pt = 0;
17188 for (
unsigned imesh = 0; imesh < n_mesh_loop; imesh++)
17203 for (
unsigned n = 0; n < n_nod; n++)
17213 unsigned nelem_haloed = haloed_elem_pt.size();
17214 for (
unsigned e = 0;
e < nelem_haloed;
e++)
17216 haloed_elem_pt[
e]->add_internal_eqn_numbers_to_vector(send_data);
17220 if (do_external_halos)
17224 for (
unsigned n = 0; n < n_ext_nod; n++)
17232 unsigned next_elem_haloed =
17234 for (
unsigned e = 0;
e < next_elem_haloed;
e++)
17246 send_n[rank] = send_data.size() - send_displacement[rank];
17253 MPI_Alltoall(&send_n[0],
17264 int receive_data_count = 0;
17265 for (
int rank = 0; rank < n_proc; ++rank)
17268 receive_displacement[rank] = receive_data_count;
17269 receive_data_count += receive_n[rank];
17274 if (receive_data_count == 0)
17276 ++receive_data_count;
17282 if (send_data.size() == 0)
17284 send_data.resize(1);
17288 MPI_Alltoallv(&send_data[0],
17290 &send_displacement[0],
17294 &receive_displacement[0],
17301 for (
int send_rank = 0; send_rank < n_proc; send_rank++)
17305 if ((send_rank != my_rank) && (receive_n[send_rank] != 0))
17308 unsigned count = receive_displacement[send_rank];
17311 Mesh* my_mesh_pt = 0;
17314 for (
unsigned imesh = 0; imesh < n_mesh_loop; imesh++)
17329 unsigned n_nod = my_mesh_pt->
nhalo_node(send_rank);
17330 for (
unsigned n = 0; n < n_nod; n++)
17341 unsigned nelem_halo = halo_elem_pt.size();
17342 for (
unsigned e = 0;
e < nelem_halo;
e++)
17344 halo_elem_pt[
e]->read_internal_eqn_numbers_from_vector(
17345 receive_data, count);
17349 if (do_external_halos)
17354 for (
unsigned n = 0; n < n_ext_nod; n++)
17362 unsigned next_elem_halo =
17364 for (
unsigned e = 0;
e < next_elem_halo;
e++)
17385 const bool& report_stats,
17398 std::ostringstream warn_message;
17399 warn_message <<
"WARNING: You've tried to load balance a problem over\n"
17400 <<
"only one processor: ignoring your request.\n";
17402 "Problem::load_balance()",
17403 OOMPH_EXCEPTION_LOCATION);
17413 std::ostringstream error_stream;
17414 error_stream <<
"You have called Problem::load_balance()\n"
17415 <<
"on a non-distributed problem. This doesn't\n"
17416 <<
"make sense -- go distribute your problem first."
17419 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
17423 double t_start = 0.0;
17424 double t_metis = 0.0;
17425 double t_partition = 0.0;
17426 double t_distribute = 0.0;
17427 double t_refine = 0.0;
17428 double t_copy_solution = 0.0;
17437 unsigned old_ndof =
ndof();
17449 old_mesh_pt.resize(1);
17455 old_mesh_pt.resize(n_mesh);
17456 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17458 old_mesh_pt[i_mesh] =
mesh_pt(i_mesh);
17477 unsigned local_ntarget =
17478 input_target_domain_for_local_non_halo_element.size();
17479 unsigned global_ntarget = 0;
17480 MPI_Allreduce(&local_ntarget,
17488 if (global_ntarget > 0)
17490 target_domain_for_local_non_halo_element =
17491 input_target_domain_for_local_non_halo_element;
17501 unsigned objective = 0;
17502 bool bypass_metis =
true;
17506 target_domain_for_local_non_halo_element,
17512 unsigned objective = 0;
17514 this, objective, target_domain_for_local_non_halo_element);
17524 std::map<GeneralisedElement*, unsigned>
17525 target_domain_for_local_non_halo_element_map;
17527 unsigned count_non_halo_el = 0;
17528 for (
unsigned e = 0;
e < n_elem;
e++)
17533 target_domain_for_local_non_halo_element_map[el_pt] =
17534 target_domain_for_local_non_halo_element[count_non_halo_el];
17535 count_non_halo_el++;
17550 target_domain_for_local_non_halo_element.clear();
17551 target_domain_for_local_non_halo_element.reserve(n_elem);
17552 count_non_halo_el = 0;
17553 for (
unsigned e = 0;
e < n_elem;
e++)
17558 target_domain_for_local_non_halo_element.push_back(
17559 target_domain_for_local_non_halo_element_map[el_pt]);
17566 const unsigned n_old_sub_meshes = n_mesh;
17578 unsigned count_td = 0;
17579 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17584 for (
unsigned i = 0;
i < nsub_ele;
i++)
17592 const unsigned target_domain =
17593 target_domain_for_local_non_halo_element[count_td++];
17596 target_domain_for_local_non_halo_element_submesh[i_mesh]
17597 .push_back(target_domain);
17605 const unsigned ntarget_domain =
17606 target_domain_for_local_non_halo_element.size();
17607 if (count_td != ntarget_domain)
17609 std::ostringstream error_stream;
17611 <<
"The number of nonhalo elements (" << count_td
17612 <<
") found in (all)\n"
17613 <<
"the (sub)-mesh(es) is different from the number of target "
17615 <<
"(" << ntarget_domain <<
") for the nonhalo elements.\n"
17616 <<
"Please ensure that you called the rebuild_global_mesh() method "
17617 <<
"after the\npossible deletion of FaceElements in "
17618 <<
"actions_before_distribute()!!!\n\n";
17620 "Problem::load_balance()",
17621 OOMPH_EXCEPTION_LOCATION);
17638 std::vector<bool> is_unstructured_mesh;
17642 bool are_there_unstructured_meshes =
false;
17652 unstructured_mesh_pt.push_back(tri_mesh_pt);
17654 is_unstructured_mesh.push_back(
true);
17657 are_there_unstructured_meshes =
true;
17663 unstructured_mesh_pt.push_back(tri_mesh_pt);
17665 is_unstructured_mesh.push_back(
false);
17672 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17679 unstructured_mesh_pt.push_back(tri_mesh_pt);
17681 is_unstructured_mesh.push_back(
true);
17684 are_there_unstructured_meshes =
true;
17690 unstructured_mesh_pt.push_back(tri_mesh_pt);
17692 is_unstructured_mesh.push_back(
false);
17718 std::map<unsigned, Vector<unsigned>> flat_packed_refinement_info_for_root;
17721 unsigned max_refinement_level_overall = 0;
17726 target_domain_for_local_non_halo_element_in_structured_mesh;
17730 if (!is_unstructured_mesh[0])
17732 const unsigned nele_mesh =
17733 target_domain_for_local_non_halo_element.size();
17734 for (
unsigned e = 0;
e < nele_mesh;
e++)
17736 const unsigned target_domain =
17737 target_domain_for_local_non_halo_element[
e];
17738 target_domain_for_local_non_halo_element_in_structured_mesh
17739 .push_back(target_domain);
17746 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17749 if (!is_unstructured_mesh[i_mesh])
17751 const unsigned nele_sub_mesh =
17752 target_domain_for_local_non_halo_element_submesh[i_mesh].size();
17753 for (
unsigned e = 0;
e < nele_sub_mesh;
e++)
17755 const unsigned target_domain =
17756 target_domain_for_local_non_halo_element_submesh[i_mesh][
e];
17757 target_domain_for_local_non_halo_element_in_structured_mesh
17758 .push_back(target_domain);
17768 target_domain_for_local_non_halo_element_in_structured_mesh,
17772 old_domain_for_base_element,
17773 new_domain_for_base_element,
17774 max_refinement_level_overall);
17778 old_domain_for_base_element,
17779 new_domain_for_base_element,
17780 max_refinement_level_overall,
17781 flat_packed_refinement_info_for_root);
17786 oomph_info <<
"CPU for partition calculation for roots: "
17787 << t_partition - t_metis << std::endl;
17800 std::max(
int(n_old_sub_meshes), 1));
17803 pruned_refinement_level[0] = 0;
17806 if (ref_mesh_pt != 0)
17808 pruned_refinement_level[0] =
17817 if (!is_unstructured_mesh[0])
17819 delete old_mesh_pt[0];
17820 old_mesh_pt[0] = 0;
17827 for (
unsigned i_mesh = 0; i_mesh < n_old_sub_meshes; i_mesh++)
17829 pruned_refinement_level[i_mesh] = 0;
17832 if (ref_mesh_pt != 0)
17834 pruned_refinement_level[i_mesh] =
17843 if (!is_unstructured_mesh[i_mesh])
17845 delete old_mesh_pt[i_mesh];
17846 old_mesh_pt[i_mesh] = 0;
17863 bool some_mesh_has_been_pruned =
false;
17864 unsigned n = pruned_refinement_level.size();
17865 for (
unsigned i = 0;
i < n;
i++)
17867 if (pruned_refinement_level[
i] > 0) some_mesh_has_been_pruned =
true;
17876 if (some_mesh_has_been_pruned)
17891 if (ref_mesh_pt != 0)
17894 unsigned local_min_ref = 0;
17895 unsigned local_max_ref = 0;
17902 int int_local_min_ref = local_min_ref;
17905 int_local_min_ref = INT_MAX;
17907 int int_min_ref = 0;
17908 MPI_Allreduce(&int_local_min_ref,
17916 unsigned min_ref = unsigned(int_min_ref);
17920 unsigned nref = pruned_refinement_level[0] - min_ref;
17921 oomph_info <<
"Refining one-and-only mesh uniformly " << nref
17923 for (
unsigned i = 0;
i < nref;
i++)
17931 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17935 if (ref_mesh_pt != 0)
17938 unsigned local_min_ref = 0;
17939 unsigned local_max_ref = 0;
17946 int int_local_min_ref = local_min_ref;
17949 int_local_min_ref = INT_MAX;
17951 int int_min_ref = 0;
17952 MPI_Allreduce(&int_local_min_ref,
17960 unsigned min_ref = unsigned(int_min_ref);
17964 unsigned nref = pruned_refinement_level[i_mesh] - min_ref;
17965 oomph_info <<
"Refining sub-mesh " << i_mesh <<
" uniformly "
17966 << nref <<
" times\n";
17967 for (
unsigned i = 0;
i < nref;
i++)
18007 unsigned count = 0;
18008 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
18011 if (!is_unstructured_mesh[i_mesh])
18015 submesh_element_partition[i_mesh].resize(nsub_ele);
18016 for (
unsigned e = 0;
e < nsub_ele;
e++)
18018 submesh_element_partition[i_mesh][
e] =
18019 new_domain_for_base_element[count++];
18025 const unsigned nnew_domain_for_base_element =
18026 new_domain_for_base_element.size();
18027 if (count != nnew_domain_for_base_element)
18029 std::ostringstream error_stream;
18031 <<
"The number of READ target domains for nonhalo elements\n"
18032 <<
" is (" << count <<
"), but the number of target domains for\n"
18033 <<
"nonhalo elements is (" << nnew_domain_for_base_element
18036 "Problem::load_balance()",
18037 OOMPH_EXCEPTION_LOCATION);
18051 if (!is_unstructured_mesh[0])
18056 for (
unsigned e = 0;
e < n_ele;
e++)
18069 unsigned nglobal_element = 0;
18070 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
18073 if (!is_unstructured_mesh[i_mesh])
18083 unsigned counter_base = 0;
18084 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
18087 if (!is_unstructured_mesh[i_mesh])
18090 for (
unsigned e = 0;
e < n_ele;
e++)
18102 if (counter_base != nglobal_element)
18104 std::ostringstream error_stream;
18105 error_stream <<
"The number of global elements (" << nglobal_element
18106 <<
") is not the same as the number of\nadded elements ("
18107 << counter_base <<
") to the Base_mesh_element_pt data "
18108 <<
"structure!!!\n\n";
18110 "Problem::load_balance()",
18111 OOMPH_EXCEPTION_LOCATION);
18128 std::map<unsigned, std::map<int, unsigned>> face_element_number;
18130 for (
unsigned e = 0;
e < n_element;
e++)
18134 if (face_el_pt != 0)
18137 std::stringstream info;
18138 info <<
"================================================\n";
18139 info <<
"INFO: I've come across a FaceElement while \n";
18140 info <<
" load-balancing a problem. \n";
18141 info <<
"================================================\n";
18149 throw OomphLibError(
"Base_mesh_element_number_plus_one[...]=0",
18150 OOMPH_CURRENT_FUNCTION,
18151 OOMPH_EXCEPTION_LOCATION);
18156 face_element_number[e_bulk][face_index] =
e;
18167 if (!is_unstructured_mesh[0])
18170 if (
mesh_pt()->nelement() != new_domain_for_base_element.size())
18172 std::ostringstream error_stream;
18173 error_stream <<
"Distributing one-and-only mesh containing "
18175 << new_domain_for_base_element.size() << std::endl;
18177 OOMPH_CURRENT_FUNCTION,
18178 OOMPH_EXCEPTION_LOCATION);
18184 oomph_info <<
"Distributing one and only mesh\n"
18185 <<
"------------------------------" << std::endl;
18190 bool overrule_keep_as_halo_element_status =
false;
18193 new_domain_for_base_element,
18194 deleted_element_pt,
18197 overrule_keep_as_halo_element_status);
18205 bool need_to_rebuild_mesh =
false;
18206 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
18210 if (!is_unstructured_mesh[i_mesh])
18214 oomph_info <<
"Distributing submesh " << i_mesh <<
" of "
18215 << n_mesh <<
" in total\n"
18216 <<
"---------------------------------------------"
18221 doc_info.
number() = i_mesh;
18225 bool overrule_keep_as_halo_element_status =
false;
18227 submesh_element_partition[i_mesh],
18228 deleted_element_pt,
18231 overrule_keep_as_halo_element_status);
18234 need_to_rebuild_mesh =
true;
18240 if (need_to_rebuild_mesh)
18249 unsigned n_del = deleted_element_pt.size();
18250 for (
unsigned e = 0;
e < n_del;
e++)
18260 if (some_mesh_has_been_pruned)
18267 if (ref_mesh_pt != 0)
18270 deleted_element_pt, doc_info, report_stats);
18275 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
18279 if (ref_mesh_pt != 0)
18282 deleted_element_pt, doc_info, report_stats);
18290 unsigned n_del = deleted_element_pt.size();
18291 for (
unsigned e = 0;
e < n_del;
e++)
18306 oomph_info <<
"CPU for build and distribution of new mesh(es): "
18307 << t_distribute - t_partition << std::endl;
18327 new_domain_for_base_element,
18328 max_refinement_level_overall,
18329 flat_packed_refinement_info_for_root,
18330 refinement_info_for_root_elements);
18335 max_refinement_level_overall);
18340 oomph_info <<
"CPU for refinement of base mesh: "
18341 << t_refine - t_distribute << std::endl;
18364 send_n, send_data, send_displacement);
18368 if (are_there_unstructured_meshes)
18381 if (is_unstructured_mesh[0])
18386 this->
mesh_pt() = old_mesh_pt[0];
18391 std::ostringstream error_stream;
18392 error_stream <<
"The only one mesh in the problem is not an "
18393 "unstructured mesh,\n"
18394 <<
"but the flag 'are_there_unstructures_meshes' ("
18395 << are_there_unstructured_meshes
18396 <<
") was turned on,\n"
18397 <<
"this is weird. Please check for any condition "
18399 <<
"turned on this flag!!!!\n\n";
18401 "Problem::load_balance()",
18402 OOMPH_EXCEPTION_LOCATION);
18406 unstructured_mesh_pt[0]->load_balance(
18407 target_domain_for_local_non_halo_element);
18414 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
18416 if (is_unstructured_mesh[i_mesh])
18423 this->
mesh_pt(i_mesh) = old_mesh_pt[i_mesh];
18436 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
18438 if (is_unstructured_mesh[i_mesh])
18441 const unsigned n_element = old_mesh_pt[i_mesh]->nelement();
18447 if (n_element > 0 && is_unstructured_mesh[i_mesh])
18449 unstructured_mesh_pt[i_mesh]->load_balance(
18450 target_domain_for_local_non_halo_element_submesh[i_mesh]);
18465 oomph_info <<
"CPU for transferring solution to new mesh(es): "
18466 << t_copy_solution - t_refine << std::endl;
18467 oomph_info <<
"CPU for load balancing: " << t_copy_solution - t_start
18484 <<
"Total number of elements on this processor after load balance: "
18487 oomph_info <<
"Number of non-halo elements on this processor after "
18493 if (n_dof != old_ndof)
18495 std::ostringstream error_stream;
18497 <<
"Number of dofs in load_balance() has changed from " << old_ndof
18498 <<
" to " << n_dof <<
"\n"
18499 <<
"Check that you've implemented any necessary "
18500 "actions_before/after\n"
18501 <<
"adapt/distribute functions, e.g. to pin redundant pressure dofs"
18504 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
18513 oomph_info <<
"Time for load_balance() [sec] : " << end_t - start_t
18524 const unsigned& max_refinement_level_overall,
18525 std::map<
unsigned,
Vector<unsigned>>& flat_packed_refinement_info_for_root,
18533 unsigned n_base_element = old_domain_for_base_element.size();
18534 refinement_info_for_root_elements.resize(n_base_element);
18538 std::map<unsigned, Vector<unsigned>> halo_domain_of_haloed_base_element;
18544 std::map<unsigned, Vector<unsigned>> halo_domains;
18548 unsigned max_mesh = std::max(n_sub_mesh,
unsigned(1));
18549 for (
unsigned i_mesh = 0; i_mesh < max_mesh; i_mesh++)
18552 Mesh* my_mesh_pt = 0;
18553 if (n_sub_mesh == 0)
18559 my_mesh_pt =
mesh_pt(i_mesh);
18565 if (!(sub_mesh_pt != 0))
18570 for (
int p = 0; p < n_proc; p++)
18574 unsigned nhaloed = haloed_elem_pt.size();
18575 for (
unsigned h = 0; h < nhaloed; h++)
18582 throw OomphLibError(
"Base_mesh_element_number_plus_one[...]=0",
18583 OOMPH_CURRENT_FUNCTION,
18584 OOMPH_EXCEPTION_LOCATION);
18588 halo_domains[
e].push_back(p);
18601 std::map<unsigned, Vector<unsigned>> data_for_proc;
18607 unsigned count = 0;
18611 for (
unsigned e = 0;
e < n_base_element;
e++)
18619 if (
int(old_domain_for_base_element[
e]) == my_rank)
18622 unsigned new_domain = new_domain_for_base_element[
e];
18625 nbase_elements_for_proc[new_domain]++;
18628 if (
int(new_domain) == my_rank)
18632 unsigned nhalo = halo_domains[
e].size();
18633 halo_domain_of_haloed_base_element[
e].resize(nhalo);
18634 for (
unsigned j = 0; j < nhalo; j++)
18636 halo_domain_of_haloed_base_element[
e][j] = halo_domains[
e][j];
18640 refinement_info_for_root_elements[
e].resize(
18641 max_refinement_level_overall);
18645 unsigned n_additional_data =
18646 flat_packed_refinement_info_for_root[
e].size();
18650 unsigned n_tree_nodes = flat_packed_refinement_info_for_root[
e][0];
18653 unsigned local_count = 1;
18656 for (
unsigned level = 0; level < max_refinement_level_overall;
18659 for (
unsigned ee = 0; ee < n_tree_nodes; ee++)
18662 if (flat_packed_refinement_info_for_root[
e][local_count] == 1)
18667 if (flat_packed_refinement_info_for_root[
e][local_count] == 1)
18669 refinement_info_for_root_elements[
e][level].push_back(2);
18675 refinement_info_for_root_elements[
e][level].push_back(1);
18682 refinement_info_for_root_elements[
e][level].push_back(0);
18689 if (n_additional_data != local_count)
18691 std::stringstream error_message;
18692 error_message <<
"Number of additional data: " << n_additional_data
18693 <<
" doesn't match that actually send: "
18694 << local_count << std::endl;
18696 OOMPH_CURRENT_FUNCTION,
18697 OOMPH_EXCEPTION_LOCATION);
18706 unsigned current_size = data_for_proc[new_domain].size();
18707 unsigned n_additional_data =
18708 flat_packed_refinement_info_for_root[
e].size();
18709 data_for_proc[new_domain].reserve(current_size + n_additional_data +
18713 count += n_additional_data + 2;
18716 data_for_proc[new_domain].push_back(
e);
18720 data_for_proc[new_domain].push_back(n_additional_data);
18724 for (
unsigned j = 0; j < n_additional_data; j++)
18726 data_for_proc[new_domain].push_back(
18727 flat_packed_refinement_info_for_root[
e][j]);
18742 send_data.reserve(count);
18748 for (
int rank = 0; rank < n_proc; rank++)
18751 send_displacement[rank] = send_data.size();
18755 if (rank != my_rank)
18758 send_data.push_back(nbase_elements_for_proc[rank]);
18761 unsigned n_data = data_for_proc[rank].size();
18762 for (
unsigned j = 0; j < n_data; j++)
18764 send_data.push_back(data_for_proc[rank][j]);
18769 send_n[rank] = send_data.size() - send_displacement[rank];
18776 MPI_Alltoall(&send_n[0],
18787 int receive_data_count = 0;
18788 for (
int rank = 0; rank < n_proc; ++rank)
18791 receive_displacement[rank] = receive_data_count;
18792 receive_data_count += receive_n[rank];
18797 if (receive_data_count == 0)
18799 ++receive_data_count;
18805 if (send_data.size() == 0)
18807 send_data.resize(1);
18811 MPI_Alltoallv(&send_data[0],
18813 &send_displacement[0],
18817 &receive_displacement[0],
18824 for (
int send_rank = 0; send_rank < n_proc; send_rank++)
18828 if ((send_rank != my_rank) && (receive_n[send_rank] != 0))
18831 unsigned count = receive_displacement[send_rank];
18834 unsigned nbase_element = receive_data[count];
18836 for (
unsigned b = 0; b < nbase_element; b++)
18839 unsigned base_element_number = receive_data[count];
18844 unsigned nhalo = halo_domains[base_element_number].size();
18845 halo_domain_of_haloed_base_element[base_element_number].resize(nhalo);
18846 for (
unsigned j = 0; j < nhalo; j++)
18848 halo_domain_of_haloed_base_element[base_element_number][j] =
18849 halo_domains[base_element_number][j];
18853 refinement_info_for_root_elements[base_element_number].resize(
18854 max_refinement_level_overall);
18859 unsigned n_additional_data = receive_data[count];
18863 unsigned check_count = 0;
18867 unsigned n_tree_nodes = receive_data[count];
18875 for (
unsigned level = 0; level < max_refinement_level_overall;
18878 for (
unsigned e = 0;
e < n_tree_nodes;
e++)
18881 if (receive_data[count] == 1)
18890 if (receive_data[count] == 1)
18892 refinement_info_for_root_elements[base_element_number][level]
18903 refinement_info_for_root_elements[base_element_number][level]
18915 refinement_info_for_root_elements[base_element_number][level]
18927 if (n_additional_data != check_count)
18929 std::stringstream error_message;
18930 error_message <<
"Number of additional data: " << n_additional_data
18931 <<
" doesn't match that actually send: "
18932 << check_count << std::endl;
18934 OOMPH_CURRENT_FUNCTION,
18935 OOMPH_EXCEPTION_LOCATION);
18951 std::map<unsigned, Vector<unsigned>> data_for_proc;
18959 halo_domain_of_haloed_base_element.begin();
18960 it != halo_domain_of_haloed_base_element.end();
18964 unsigned base_element_number = (*it).first;
18968 unsigned nd = domains.size();
18969 for (
unsigned jd = 0; jd < nd; jd++)
18972 unsigned d = domains[jd];
18975 nbase_elements_for_proc[d]++;
18978 data_for_proc[d].push_back(base_element_number);
18981 for (
unsigned level = 0; level < max_refinement_level_overall;
18986 refinement_info_for_root_elements[base_element_number][level]
18988 data_for_proc[d].push_back(n);
18989 for (
unsigned j = 0; j < n; j++)
18991 data_for_proc[d].push_back(
18992 refinement_info_for_root_elements[base_element_number][level]
19008 send_data.reserve(count);
19014 for (
int rank = 0; rank < n_proc; rank++)
19017 send_displacement[rank] = send_data.size();
19021 if (rank != my_rank)
19024 send_data.push_back(nbase_elements_for_proc[rank]);
19027 unsigned n_data = data_for_proc[rank].size();
19028 for (
unsigned j = 0; j < n_data; j++)
19030 send_data.push_back(data_for_proc[rank][j]);
19034 send_n[rank] = send_data.size() - send_displacement[rank];
19041 MPI_Alltoall(&send_n[0],
19052 int receive_data_count = 0;
19053 for (
int rank = 0; rank < n_proc; ++rank)
19056 receive_displacement[rank] = receive_data_count;
19057 receive_data_count += receive_n[rank];
19062 if (receive_data_count == 0)
19064 ++receive_data_count;
19070 if (send_data.size() == 0)
19072 send_data.resize(1);
19076 MPI_Alltoallv(&send_data[0],
19078 &send_displacement[0],
19082 &receive_displacement[0],
19089 for (
int send_rank = 0; send_rank < n_proc; send_rank++)
19093 if ((send_rank != my_rank) && (receive_n[send_rank] != 0))
19096 unsigned count = receive_displacement[send_rank];
19099 unsigned nbase_element = receive_data[count];
19102 for (
unsigned e = 0;
e < nbase_element;
e++)
19105 unsigned base_element_number = receive_data[count];
19109 refinement_info_for_root_elements[base_element_number].resize(
19110 max_refinement_level_overall);
19113 for (
unsigned level = 0; level < max_refinement_level_overall;
19117 unsigned n = receive_data[count];
19121 for (
unsigned j = 0; j < n; j++)
19123 refinement_info_for_root_elements[base_element_number][level]
19124 .push_back(receive_data[count]);
19149 const int n_proc = comm_pt->nproc();
19155 MPI_Alltoall(&send_n[0],
19166 int receive_data_count = 0;
19167 for (
int rank = 0; rank < n_proc; ++rank)
19170 receive_displacement[rank] = receive_data_count;
19171 receive_data_count += receive_n[rank];
19176 if (receive_data_count == 0)
19178 ++receive_data_count;
19184 if (send_data.size() == 0)
19186 send_data.resize(1);
19190 MPI_Alltoallv(&send_data[0],
19192 &send_displacement[0],
19196 &receive_displacement[0],
19200 unsigned el_count = 0;
19206 for (
int send_rank = 0; send_rank < n_proc; send_rank++)
19212 if (receive_n[send_rank] != 0)
19215 unsigned count = receive_displacement[send_rank];
19218 unsigned nbatch = unsigned(receive_data[count]);
19222 for (
unsigned b = 0; b < nbatch; b++)
19225 unsigned nel = unsigned(receive_data[count]);
19230 unsigned base_el_no = unsigned(receive_data[count]);
19242 if (ref_root_el_pt != 0)
19247 all_leaf_nodes_pt);
19250 unsigned n_leaf = all_leaf_nodes_pt.size();
19255 std::ostringstream error_message;
19257 <<
"Number of leaves: " << n_leaf <<
" "
19258 <<
" doesn't match number of elements sent in batch: " << nel
19261 OOMPH_CURRENT_FUNCTION,
19262 OOMPH_EXCEPTION_LOCATION);
19268 batch_el_pt.resize(n_leaf);
19269 for (
unsigned e = 0;
e < n_leaf;
e++)
19271 batch_el_pt[
e] = all_leaf_nodes_pt[
e]->object_pt();
19280 std::ostringstream error_message;
19282 <<
"Non-refineable root element should only be associated with"
19283 <<
" one element but nel=" << nel <<
"\n";
19285 OOMPH_CURRENT_FUNCTION,
19286 OOMPH_EXCEPTION_LOCATION);
19289 batch_el_pt.push_back(root_el_pt);
19293 for (
unsigned e = 0;
e < nel;
e++)
19303 unsigned nnod = fe_pt->
nnode();
19304 for (
unsigned j = 0; j < nnod; j++)
19307 if (!node_done[send_rank][nod_pt])
19309 node_done[send_rank][nod_pt] =
true;
19315 unsigned nval = unsigned(receive_data[count]);
19320 if (nval < nod_pt->nvalue())
19322 std::ostringstream error_message;
19324 <<
"Node has more values, namely " << nod_pt->
nvalue()
19325 <<
", than we're about to receive, namely " << nval
19326 <<
". Something's wrong!\n";
19328 OOMPH_CURRENT_FUNCTION,
19329 OOMPH_EXCEPTION_LOCATION);
19336 unsigned is_boundary_node = unsigned(receive_data[count]);
19347 if (is_boundary_node != 1)
19349 std::ostringstream error_message;
19350 error_message <<
"Local node is boundary node but "
19351 "information sent is\n"
19352 <<
"for non-boundary node\n";
19354 OOMPH_CURRENT_FUNCTION,
19355 OOMPH_EXCEPTION_LOCATION);
19360 unsigned n_entry = unsigned(receive_data[count]);
19369 ->index_of_first_value_assigned_by_face_element_pt() ==
19374 new std::map<unsigned, unsigned>;
19379 std::map<unsigned, unsigned>* map_pt =
19384 for (
unsigned i = 0;
i < n_entry;
i++)
19387 unsigned first = unsigned(receive_data[count]);
19389 unsigned second = unsigned(receive_data[count]);
19393 (*map_pt)[first] = second;
19402 if (is_boundary_node != 0)
19404 std::ostringstream error_message;
19405 error_message <<
"Local node is not a boundary node but "
19407 <<
"sent is for boundary node.\n";
19409 OOMPH_CURRENT_FUNCTION,
19410 OOMPH_EXCEPTION_LOCATION);
19419 if (nval > nod_pt->
nvalue())
19439 bool do_halos =
true;
19440 bool do_external_halos =
false;
19447 bool do_halos =
false;
19448 bool do_external_halos =
true;
19479 unsigned& max_refinement_level_overall)
19483 const int n_proc = comm_pt->nproc();
19493 std::map<RefineableElement*, bool> root_el_done;
19499 std::map<RefineableElement*, unsigned> target_plus_one_for_root;
19504 unsigned max_refinement_level = 0;
19509 std::map<unsigned, Vector<GeneralisedElement*>> element_for_processor;
19516 std::map<unsigned, Vector<unsigned>> nelement_batch_for_processor;
19525 std::map<unsigned, Vector<unsigned>>
19526 base_element_for_element_batch_for_processor;
19537 Vector<int> old_domain_for_base_element_local(n_base_element, -1);
19538 Vector<int> new_domain_for_base_element_local(n_base_element, -1);
19544 unsigned count_non_halo_el = 0;
19556 bool are_there_structured_meshes =
false;
19558 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
19563 if (!(sub_mesh_pt != 0))
19571 are_there_structured_meshes =
true;
19574 for (
unsigned e = 0;
e < nele;
e++)
19581 unsigned target_domain =
19582 target_domain_for_local_non_halo_element[count_non_halo_el];
19585 count_non_halo_el++;
19591 if (ref_el_pt == 0)
19594 element_for_processor[target_domain].push_back(el_pt);
19598 nelement_batch_for_processor[target_domain].push_back(1);
19601 unsigned element_number_in_base_mesh =
19604 if (element_number_in_base_mesh == 0)
19606 throw OomphLibError(
"Base_mesh_element_number_plus_one[...]=0",
19607 OOMPH_CURRENT_FUNCTION,
19608 OOMPH_EXCEPTION_LOCATION);
19611 element_number_in_base_mesh -= 1;
19612 base_element_for_element_batch_for_processor[target_domain]
19613 .push_back(element_number_in_base_mesh);
19616 old_domain_for_base_element_local[element_number_in_base_mesh] =
19618 new_domain_for_base_element_local[element_number_in_base_mesh] =
19631 if (!root_el_done[root_el_pt])
19634 root_el_done[root_el_pt] =
true;
19637 unsigned element_number_in_base_mesh =
19640 if (element_number_in_base_mesh == 0)
19643 "Base_mesh_element_number_plus_one[...]=0",
19644 OOMPH_CURRENT_FUNCTION,
19645 OOMPH_EXCEPTION_LOCATION);
19648 element_number_in_base_mesh -= 1;
19651 old_domain_for_base_element_local[element_number_in_base_mesh] =
19653 new_domain_for_base_element_local[element_number_in_base_mesh] =
19660 target_plus_one_for_root[root_el_pt] = target_domain + 1;
19666 all_leaf_nodes_pt);
19669 unsigned n_leaf = all_leaf_nodes_pt.size();
19673 nelement_batch_for_processor[target_domain].push_back(n_leaf);
19676 base_element_for_element_batch_for_processor[target_domain]
19677 .push_back(element_number_in_base_mesh);
19680 for (
unsigned i_leaf = 0; i_leaf < n_leaf; i_leaf++)
19684 all_leaf_nodes_pt[i_leaf]->object_pt();
19685 element_for_processor[target_domain].push_back(leaf_el_pt);
19688 unsigned level = all_leaf_nodes_pt[i_leaf]->level();
19689 if (level > max_refinement_level)
19691 max_refinement_level = level;
19703 if ((target_plus_one_for_root[root_el_pt] - 1) != target_domain)
19705 std::ostringstream error_message;
19707 <<
"All elements associated with same root must have "
19708 <<
"same target. during load balancing\n";
19710 OOMPH_CURRENT_FUNCTION,
19711 OOMPH_EXCEPTION_LOCATION);
19723 if (target_domain_for_local_non_halo_element.size() != count_non_halo_el)
19725 std::ostringstream error_message;
19727 <<
"Have processed " << count_non_halo_el <<
" of "
19728 << target_domain_for_local_non_halo_element.size()
19729 <<
" target domains for local non-halo elelemts. \n "
19730 <<
"Very Odd -- we do (now) strip out the information for elements\n"
19731 <<
"that are removed in actions_before_distribute()...\n";
19733 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
19743 max_refinement_level_overall = 0;
19747 if (are_there_structured_meshes)
19749 MPI_Allreduce(&max_refinement_level,
19750 &max_refinement_level_overall,
19754 comm_pt->mpi_comm());
19759 Vector<int> tmp_old_domain_for_base_element(n_base_element);
19763 if (are_there_structured_meshes)
19765 MPI_Allreduce(&old_domain_for_base_element_local[0],
19766 &tmp_old_domain_for_base_element[0],
19770 comm_pt->mpi_comm());
19773 Vector<int> tmp_new_domain_for_base_element(n_base_element);
19776 if (are_there_structured_meshes)
19778 MPI_Allreduce(&new_domain_for_base_element_local[0],
19779 &tmp_new_domain_for_base_element[0],
19783 comm_pt->mpi_comm());
19787 old_domain_for_base_element.resize(n_base_element);
19788 new_domain_for_base_element.resize(n_base_element);
19789 for (
unsigned j = 0; j < n_base_element; j++)
19792 if (tmp_old_domain_for_base_element[j] == -1)
19794 std::ostringstream error_message;
19795 error_message <<
"Old domain for base element " << j <<
": "
19797 <<
"or its incarnation as refineable el: "
19800 <<
" which is of type "
19803 <<
"appear to have been assigned by any processor\n";
19805 OOMPH_CURRENT_FUNCTION,
19806 OOMPH_EXCEPTION_LOCATION);
19809 old_domain_for_base_element[j] = tmp_old_domain_for_base_element[j];
19811 if (tmp_new_domain_for_base_element[j] == -1)
19813 std::ostringstream error_message;
19814 error_message <<
"New domain for base element " << j
19815 <<
"which is of type "
19818 <<
"appear to have been assigned by any processor\n";
19820 OOMPH_CURRENT_FUNCTION,
19821 OOMPH_EXCEPTION_LOCATION);
19824 new_domain_for_base_element[j] = tmp_new_domain_for_base_element[j];
19838 for (
int rank = 0; rank < n_proc; rank++)
19841 send_displacement[rank] = send_data.size();
19846 unsigned total_nel = element_for_processor[rank].size();
19850 unsigned el_count = 0;
19853 unsigned nbatch = nelement_batch_for_processor[rank].size();
19856 send_data.push_back(
double(nbatch));
19859 for (
unsigned b = 0; b < nbatch; b++)
19862 unsigned nel = nelement_batch_for_processor[rank][b];
19866 unsigned base_el_no =
19867 base_element_for_element_batch_for_processor[rank][b];
19871 send_data.push_back(
double(nel));
19872 send_data.push_back(
double(base_el_no));
19875 for (
unsigned e = 0;
e < nel;
e++)
19885 unsigned nnod = fe_pt->
nnode();
19886 for (
unsigned j = 0; j < nnod; j++)
19892 unsigned n_value = nod_pt->
nvalue();
19895 unsigned n_dim = nod_pt->
ndim();
19899 for (
unsigned t = 0;
t < nt;
t++)
19901 nod_pt->
value(
t, values);
19902 for (
unsigned i = 0;
i < n_value;
i++)
19907 for (
unsigned i = 0;
i < n_dim;
i++)
19909 nod_pt->
x(
t,
i) = position[
i];
19915 if (!node_done[rank][nod_pt])
19918 node_done[rank][nod_pt] =
true;
19923 send_data.push_back(
double(n_value));
19934 send_data.push_back(
double(0));
19942 send_data.push_back(
double(1));
19946 std::map<unsigned, unsigned>* map_pt =
19952 send_data.push_back(
double(0));
19958 send_data.push_back(
double(map_pt->size()));
19961 for (std::map<unsigned, unsigned>::iterator p =
19963 p != map_pt->end();
19966 send_data.push_back(
double((*p).first));
19967 send_data.push_back(
double((*p).second));
19990 if (total_nel != el_count)
19992 std::ostringstream error_message;
19994 <<
"total_nel: " << total_nel <<
" "
19995 <<
" doesn't match total number of elements sent in batch: "
19996 << el_count <<
"\n";
19998 OOMPH_CURRENT_FUNCTION,
19999 OOMPH_EXCEPTION_LOCATION);
20004 send_n[rank] = send_data.size() - send_displacement[rank];
20031 const unsigned& max_refinement_level_overall,
20032 std::map<
unsigned,
Vector<unsigned>>& flat_packed_refinement_info_for_root)
20035 std::map<RefineableElement*, bool> root_el_done;
20046 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
20051 if (!(sub_mesh_pt != 0))
20054 for (
unsigned e = 0;
e < nele_submesh;
e++)
20065 if (ref_el_pt == 0)
20073 throw OomphLibError(
"Base_mesh_element_number_plus_one[...]=0",
20074 OOMPH_CURRENT_FUNCTION,
20075 OOMPH_EXCEPTION_LOCATION);
20079 flat_packed_refinement_info_for_root[
e].push_back(0);
20088 if (!root_el_done[root_el_pt])
20091 unsigned root_element_number =
20095 if (root_element_number == 0)
20098 "Base_mesh_element_number_plus_one[...]=0",
20099 OOMPH_CURRENT_FUNCTION,
20100 OOMPH_EXCEPTION_LOCATION);
20103 root_element_number -= 1;
20108 all_tree_nodes_pt);
20111 unsigned n_tree_nodes = all_tree_nodes_pt.size();
20112 flat_packed_refinement_info_for_root[root_element_number]
20113 .push_back(n_tree_nodes);
20116 for (
unsigned current_level = 0;
20117 current_level < max_refinement_level_overall;
20121 for (
unsigned e = 0;
e < n_tree_nodes;
e++)
20124 unsigned level = all_tree_nodes_pt[
e]->level();
20128 if ((level == current_level) ||
20129 ((level < current_level) &&
20130 (all_tree_nodes_pt[
e]->is_leaf())))
20132 flat_packed_refinement_info_for_root[root_element_number]
20137 if ((level == current_level) &&
20138 (!all_tree_nodes_pt[
e]->is_leaf()))
20140 flat_packed_refinement_info_for_root
20141 [root_element_number]
20148 flat_packed_refinement_info_for_root
20149 [root_element_number]
20157 flat_packed_refinement_info_for_root[root_element_number]
20163 root_el_done[root_el_pt] =
true;
20185 const unsigned& max_level_overall)
20189 unsigned max_mesh = std::max(n_sub_mesh,
unsigned(1));
20190 for (
unsigned i_mesh = 0; i_mesh < max_mesh; i_mesh++)
20193 Mesh* my_mesh_pt = 0;
20194 if (n_sub_mesh == 0)
20200 my_mesh_pt =
mesh_pt(i_mesh);
20205 unsigned n_el_on_this_proc = my_mesh_pt->
nelement();
20218 for (
unsigned level = 0; level < max_level_overall; level++)
20222 for (
unsigned e = 0;
e < n_el_on_this_proc;
e++)
20230 if (root_el_no == 0)
20232 throw OomphLibError(
"Base_mesh_element_number_plus_one[...]=0",
20233 OOMPH_CURRENT_FUNCTION,
20234 OOMPH_EXCEPTION_LOCATION);
20241 unsigned n_refinements =
20242 refinement_info_for_root_elements[root_el_no].size();
20245 if (level < n_refinements)
20249 refinement_info_for_root_elements[root_el_no][level].size();
20250 for (
unsigned ee = 0; ee < n_el; ee++)
20254 if (refinement_info_for_root_elements[root_el_no][level][ee] == 2)
20256 to_be_refined_on_this_proc[level].push_back(
20257 el_count_on_this_proc[level]);
20258 el_count_on_this_proc[level]++;
20262 else if (refinement_info_for_root_elements[root_el_no][level]
20265 el_count_on_this_proc[level]++;
20276 if (ref_mesh_pt != 0)
20283 if (n_sub_mesh != 0)
20303 unsigned max_mesh = std::max(n_sub_mesh,
unsigned(1));
20304 for (
unsigned i_mesh = 0; i_mesh < max_mesh; i_mesh++)
20307 Mesh* my_mesh_pt = 0;
20308 if (n_sub_mesh == 0)
20314 my_mesh_pt =
mesh_pt(i_mesh);
20320 if (!(sub_mesh_pt != 0))
20332 for (
int rank = 0; rank < n_proc; rank++)
20335 send_displacement[rank] = send_data.size();
20339 if (rank != my_rank)
20344 unsigned nel = root_haloed_elements_pt.size();
20347 for (
unsigned e = 0;
e < nel;
e++)
20355 send_n[rank] = send_data.size() - send_displacement[rank];
20362 MPI_Alltoall(&send_n[0],
20373 int receive_data_count = 0;
20374 for (
int rank = 0; rank < n_proc; ++rank)
20377 receive_displacement[rank] = receive_data_count;
20378 receive_data_count += receive_n[rank];
20383 if (receive_data_count == 0)
20385 ++receive_data_count;
20391 if (send_data.size() == 0)
20393 send_data.resize(1);
20397 MPI_Alltoallv(&send_data[0],
20399 &send_displacement[0],
20403 &receive_displacement[0],
20409 for (
int send_rank = 0; send_rank < n_proc; send_rank++)
20413 if ((send_rank != my_rank) && (receive_n[send_rank] != 0))
20416 unsigned count = receive_displacement[send_rank];
20421 unsigned nel = root_halo_elements_pt.size();
20424 for (
unsigned e = 0;
e < nel;
e++)
20427 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....
virtual void solve_eigenproblem_legacy(Problem *const &problem_pt, const int &n_eval, Vector< std::complex< double >> &eigenvalue, Vector< DoubleVector > &eigenvector, const bool &do_adjoint_problem=false)=0
Eigensolver. This takes a pointer to a problem and returns a vector of complex numbers representing t...
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
Error in the linear solver.
unsigned iterations
Max. # of iterations performed when the Newton solver died.
double maxres
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 solve_adjoint_eigenproblem_legacy(const unsigned &n_eval, Vector< std::complex< double >> &eigenvalue, Vector< DoubleVector > &eigenvector, const bool &make_timesteppers_steady=true)
Solve an adjoint eigenvalue problem using the same procedure as solve_eigenproblem....
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,...
void solve_eigenproblem_legacy(const unsigned &n_eval, Vector< std::complex< double >> &eigenvalue, Vector< DoubleVector > &eigenvector, const bool &steady=true)
Get derivative of an element in the problem wrt a global parameter, used in continuation problems.
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.
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...