76 Mesh_pt(0), Time_pt(0), Explicit_time_stepper_pt(0), Saved_dof_pt(0),
77 Default_set_initial_condition_called(false),
78 Use_globally_convergent_newton_method(false),
79 Empty_actions_before_read_unstructured_meshes_has_been_called(false),
80 Empty_actions_after_read_unstructured_meshes_has_been_called(false),
81 Store_local_dof_pt_in_elements(false),
82 Calculate_hessian_products_analytic(false),
84 Doc_imbalance_in_parallel_assembly(false),
85 Use_default_partition_in_load_balance(false),
86 Must_recompute_load_balance_for_assembly(true),
89 Relaxation_factor(1.0),
90 Newton_solver_tolerance(1.0
e-8),
92 Nnewton_iter_taken(0),
94 Time_adaptive_newton_crash_on_solve_fail(false),
95 Jacobian_reuse_is_enabled(false), Jacobian_has_been_computed(false),
96 Problem_is_nonlinear(true),
97 Pause_at_end_of_sparse_assembly(false),
98 Doc_time_in_distribute(false),
99 Sparse_assembly_method(Perform_assembly_using_vectors_of_pairs),
100 Sparse_assemble_with_arrays_initial_allocation(400),
101 Sparse_assemble_with_arrays_allocation_increment(150),
102 Numerical_zero_for_sparse_assembly(0.0),
103 FD_step_used_in_get_hessian_vector_products(1.0
e-8),
104 Mass_matrix_reuse_is_enabled(false), Mass_matrix_has_been_computed(false),
105 Discontinuous_element_formulation(false),
106 Minimum_dt(1.0
e-12), Maximum_dt(1.0e12),
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), Desired_proportion_of_arc_length(0.5),
111 Theta_squared(1.0), Sign_of_jacobian(0), Continuation_direction(1.0),
112 Parameter_derivative(1.0), Parameter_current(0.0),
113 Use_continuation_timestepper(false),
114 Dof_derivative_offset(1),
115 Dof_current_offset(2),
116 Ds_current(0.0), Desired_newton_iterations_ds(5),
117 Minimum_ds(1.0
e-10), Bifurcation_detection(false),
118 Bisect_to_find_bifurcation(false),
119 First_jacobian_sign_change(false),Arc_length_step_taken(false),
120 Use_finite_differences_for_continuation_derivatives(false),
122 Dist_problem_matrix_distribution(Uniform_matrix_distribution),
123 Parallel_sparse_assemble_previous_allocation(0),
124 Problem_has_been_distributed(false),
125 Bypass_increase_in_dof_check_during_pruning(false),
126 Max_permitted_error_for_halo_check(1.0
e-14),
128 Shut_up_in_newton_solve(false),
129 Always_take_one_newton_step(false),
130 Timestep_reduction_factor_after_nonconvergence(0.5),
131 Keep_temporal_error_below_tolerance(true)
201 for(
unsigned c=0;c<n_copies;c++)
231 unsigned n_non_halo_element_local=0;
232 for(
unsigned e=0;
e<n_element;
e++)
241 ++n_non_halo_element_local;
245 for(
unsigned n=0;n<n_var;n++)
266 MPI_Allreduce(&n_non_halo_element_local,&Nelement,1,MPI_UNSIGNED,MPI_SUM,
273 Nelement = n_non_halo_element_local;
303 std::map<unsigned,double*> halo_data_pt;
325 return distribute(element_partition,doc_info,report_stats);
338 bool has_non_zero_entry=
false;
339 unsigned n=element_partition.size();
340 for (
unsigned i=0;
i<n;
i++)
342 if (element_partition[
i]!=0)
344 has_non_zero_entry=
true;
348 if (!has_non_zero_entry)
350 std::ostringstream warn_message;
351 warn_message <<
"WARNING: All entries in specified partitioning vector \n" 352 <<
" are zero -- will ignore this and use METIS\n" 353 <<
" to perform the partitioning\n";
355 "Problem::distribute()",
356 OOMPH_EXCEPTION_LOCATION);
364 return distribute(element_partition,doc_info,report_stats);
372 const bool& report_stats)
381 return distribute(element_partition,doc_info,report_stats);
392 DocInfo& doc_info,
const bool& report_stats)
407 std::ostringstream warn_message;
408 warn_message <<
"WARNING: You've tried to distribute a problem over\n" 409 <<
"only one processor: this would make METIS crash.\n" 410 <<
"Ignoring your request for distribution.\n";
412 "Problem::distribute()",
413 OOMPH_EXCEPTION_LOCATION);
416 else if (n_proc>n_element)
419 std::ostringstream error_stream;
420 error_stream <<
"You have tried to distribute a problem\n" 421 <<
"but there are less elements than processors.\n" 422 <<
"Please re-run with more elements!\n" 423 <<
"Please also ensure that actions_before_distribute().\n" 424 <<
"and actions_after_distribute() are correctly set up.\n" 427 OOMPH_CURRENT_FUNCTION,
428 OOMPH_EXCEPTION_LOCATION);
434 bool a_mesh_is_not_uniformly_refined=
false;
440 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(0)))
442 unsigned min_ref_level=0;
443 unsigned max_ref_level=0;
444 mmesh_pt->get_refinement_levels(min_ref_level,max_ref_level);
446 if (max_ref_level!=min_ref_level)
448 a_mesh_is_not_uniformly_refined=
true;
454 for (
unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
459 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(i_mesh)))
461 unsigned min_ref_level=0;
462 unsigned max_ref_level=0;
463 mmesh_pt->get_refinement_levels(min_ref_level,max_ref_level);
465 if (max_ref_level!=min_ref_level)
467 a_mesh_is_not_uniformly_refined=
true;
474 if (a_mesh_is_not_uniformly_refined)
479 std::ostringstream error_stream;
480 error_stream <<
"You have tried to distribute a problem\n" 481 <<
"but at least one of your meshes is no longer\n" 482 <<
"uniformly refined. In order to preserve the Tree\n" 483 <<
"and TreeForest structure, Problem::distribute() can\n" 484 <<
"only be called while meshes are uniformly refined.\n" 487 OOMPH_CURRENT_FUNCTION,
488 OOMPH_EXCEPTION_LOCATION);
495 std::ostringstream error_stream;
496 error_stream <<
"You have tried to distribute a problem\n" 497 <<
"and there is some global data.\n" 498 <<
"This is not likely to work...\n" 501 OOMPH_CURRENT_FUNCTION,
502 OOMPH_EXCEPTION_LOCATION);
513 unsigned old_ndof=
ndof();
520 unsigned nelem=global_mesh_pt->
nelement();
525 unsigned n_my_elements=0;
528 bool used_preset_partitioning=
false;
532 unsigned sum_element_partition=0;
533 unsigned n_part=element_partition.size();
534 for (
unsigned e=0;
e<n_part;
e++)
537 if (
int(element_partition[
e])==my_rank) n_my_elements++;
539 sum_element_partition+=element_partition[
e];
541 if (sum_element_partition==0)
543 oomph_info <<
"INFO: using METIS to partition elements" 546 used_preset_partitioning=
false;
550 oomph_info <<
"INFO: using pre-set partition of elements" 552 used_preset_partitioning=
true;
553 element_domain=element_partition;
563 oomph_info <<
"Time for partitioning of global mesh: " 564 << t_end-t_start << std::endl;
574 for (
unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
577 n_element_in_old_submesh[i_mesh]=nsub_elem;
587 oomph_info <<
"Time for actions before distribute: " 588 << t_end-t_start << std::endl;
605 return_element_domain.reserve(element_domain.size());
609 for (
unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
612 submesh_element_domain[i_mesh].resize(nsub_elem);
613 unsigned nsub_elem_old=n_element_in_old_submesh[i_mesh];
614 for (
unsigned e=0;
e<nsub_elem_old;
e++)
616 if (nsub_elem_old==nsub_elem)
618 submesh_element_domain[i_mesh][
e]=element_domain[count];
619 return_element_domain.push_back(element_domain[count]);
628 return_element_domain=element_domain;
644 bool structured_mesh =
true;
647 if (tri_mesh_pt != 0)
649 structured_mesh =
false;
653 const unsigned n_ele = global_mesh_pt->
nelement();
656 for (
unsigned e=0;
e<n_ele;
e++)
669 unsigned nglobal_element = 0;
671 std::vector<bool> is_structured_mesh(n_mesh);
672 for (
unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
676 if (tri_mesh_pt != 0)
680 is_structured_mesh[i_mesh] =
false;
686 is_structured_mesh[i_mesh] =
true;
689 if (is_structured_mesh[i_mesh])
699 unsigned counter = 0;
700 for (
unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
703 if (is_structured_mesh[i_mesh])
706 for (
unsigned e=0;
e<n_ele;
e++)
718 if (counter != nglobal_element)
720 std::ostringstream error_stream;
722 <<
"The number of global elements ("<<nglobal_element
723 <<
") is not the sameas the number of\nadded elements (" 724 << counter <<
") to the Base_mesh_element_pt data " 725 <<
"structure!!!\n\n";
727 "Problem::distribute()",
728 OOMPH_EXCEPTION_LOCATION);
730 #endif // #ifdef PARANOID 739 bool overrule_keep_as_halo_element_status=
false;
740 if ((n_my_elements==0)&&(used_preset_partitioning))
742 oomph_info <<
"INFO: We're over-ruling the \"keep as halo element\"\n" 743 <<
" status because the preset partitioning\n" 744 <<
" didn't place ANY elements on this processor,\n" 745 <<
" probably because of a restart on a larger \n" 746 <<
" number of processors\n";
747 overrule_keep_as_halo_element_status=
true;
758 doc_info,report_stats,
759 overrule_keep_as_halo_element_status);
763 for (
unsigned i_mesh=0; i_mesh<n_mesh; i_mesh++)
767 oomph_info <<
"Distributing submesh " << i_mesh << std::endl
768 <<
"--------------------" << std::endl;
773 submesh_element_domain[i_mesh],
775 doc_info,report_stats,
776 overrule_keep_as_halo_element_status);
783 unsigned n_del=deleted_element_pt.size();
784 for (
unsigned e=0;
e<n_del;
e++)
795 oomph_info <<
"Time for mesh-level distribution: " 796 << t_end-t_start << std::endl;
809 oomph_info <<
"Time for actions after distribute: " 810 << t_end-t_start << std::endl;
816 oomph_info <<
"Number of equations: " << n_dof
822 oomph_info <<
"Time for re-assigning eqn numbers (in distribute): " 823 << t_end-t_start << std::endl;
830 std::ostringstream error_stream;
832 <<
"Number of dofs in distribute() has changed " 833 <<
"from " << old_ndof <<
" to " << n_dof <<
"\n" 834 <<
"Check that you've implemented any necessary actions_before/after\n" 835 <<
"distribute functions, e.g. to pin redundant pressure dofs" 838 OOMPH_CURRENT_FUNCTION,
839 OOMPH_EXCEPTION_LOCATION);
854 return return_element_domain;
866 const bool& report_stats)
872 std::ostringstream filename;
873 std::ofstream some_file;
881 filename << doc_info.
directory() <<
"/complete_mesh" 882 << doc_info.
number() <<
".dat";
883 global_mesh_pt->
output(filename.str().c_str(),5);
890 unsigned objective=0;
897 nelem=element_domain.size();
899 MPI_Bcast(&nelem,1,MPI_UNSIGNED,0,this->
communicator_pt()->mpi_comm());
900 element_domain.resize(nelem);
901 MPI_Bcast(&element_domain[0],nelem,MPI_UNSIGNED,0,
910 for (
unsigned e=0;
e<nelem;
e++)
912 int_element_domain[
e]=element_domain[
e];
916 int my_number_of_elements=0;
919 for (
unsigned e=0;
e<nelem;
e++)
921 if (int_element_domain[
e]==rank)
923 my_number_of_elements++;
929 MPI_Allgather(&my_number_of_elements,1,MPI_INT,
930 &number_of_elements[0],1,MPI_INT,
936 int max_number_of_elements=0;
937 int process_with_max_elements=0;
938 for (
int d=0;d<n_proc;d++)
940 if (number_of_elements[d]==0)
943 if (max_number_of_elements<=1)
945 for (
int dd=0;dd<n_proc;dd++)
947 if (number_of_elements[dd]>max_number_of_elements)
949 max_number_of_elements=number_of_elements[dd];
950 process_with_max_elements=dd;
956 if (max_number_of_elements<=1)
959 std::ostringstream error_stream;
960 error_stream <<
"No process has more than 1 element, and\n" 961 <<
"at least one process has no elements!\n" 962 <<
"Suggest rerunning with more refinement.\n" 965 OOMPH_CURRENT_FUNCTION,
966 OOMPH_EXCEPTION_LOCATION);
972 for (
unsigned e=0;
e<nelem;
e++)
974 if (int_element_domain[
e]==process_with_max_elements)
976 int_element_domain[
e]=d;
978 number_of_elements[d]++;
979 number_of_elements[process_with_max_elements]--;
981 max_number_of_elements--;
985 oomph_info <<
"INFO: Switched element domain at position " <<
e 987 <<
"from process " << process_with_max_elements
988 <<
" to process " << d
990 <<
"which was given no elements by METIS partition" 1004 for (
unsigned e=0;
e<nelem;
e++)
1006 element_domain[
e]=int_element_domain[
e];
1009 unsigned count_elements=0;
1010 for (
unsigned e=0;
e<nelem;
e++)
1012 if(
int(element_domain[
e])==rank)
1021 <<
" elements from this partition" << std::endl << std::endl;
1034 const bool& report_stats)
1044 <<
"WARNING: Problem::prune_halo_elements_and_nodes() was called on a " 1045 <<
"non-distributed Problem!" << std::endl;
1046 oomph_info <<
"Ignoring your request..." << std::endl;
1053 oomph_info <<
"WARNING: You've tried to prune halo layers on a problem\n" 1054 <<
"with only one processor: this is unnecessary.\n" 1055 <<
"Ignoring your request." 1056 << std::endl << std::endl;
1062 unsigned old_ndof=
ndof();
1065 double t_start = 0.0;
1079 <<
"Time for actions_before_distribute() in " 1080 <<
"Problem::prune_halo_elements_and_nodes(): " 1081 << t_end-t_start << std::endl;
1087 std::map<GeneralisedElement*,unsigned> old_base_element_number_plus_one;
1088 std::vector<bool> old_root_is_halo_or_non_existent(nel,
true);
1089 for (
unsigned e=0;
e<nel;
e++)
1100 old_root_is_halo_or_non_existent[
e]=
false;
1108 old_base_element_number_plus_one[base_el_pt]=
e+1;
1115 unsigned ntree=tree_pt.size();
1116 for (
unsigned t=0;
t<ntree;
t++)
1118 old_base_element_number_plus_one[tree_pt[
t]->object_pt()]=
e+1;
1130 <<
"Time for setup old root elements in " 1131 <<
"Problem::prune_halo_elements_and_nodes(): " 1132 << t_end-t_start << std::endl;
1138 unsigned nel_base_old=nel;
1148 doc_info,report_stats);
1153 for (
unsigned i_mesh=0; i_mesh<n_mesh; i_mesh++)
1156 doc_info,report_stats);
1167 <<
"Total time for all mesh-level prunes in " 1168 <<
"Problem::prune_halo_elements_and_nodes(): " 1169 << t_end-t_start << std::endl;
1177 std::map<FiniteElement*,bool> root_el_done;
1182 new_base_element_associated_with_old_base_element(nel_base_old);
1184 unsigned n_meshes = n_mesh;
1193 std::vector<bool> is_structured_mesh(n_meshes);
1198 for (
unsigned i_mesh = 0; i_mesh < n_meshes; i_mesh++)
1202 if (!(tri_mesh_pt!=0))
1205 is_structured_mesh[i_mesh] =
true;
1212 is_structured_mesh[i_mesh] =
false;
1217 for (
unsigned i_mesh = 0; i_mesh < n_meshes; i_mesh++)
1221 if (is_structured_mesh[i_mesh])
1225 for (
unsigned e = 0;
e < nele_submesh;
e++)
1235 unsigned old_base_el_no =
1236 old_base_element_number_plus_one[el_pt]-1;
1237 new_base_element_associated_with_old_base_element
1238 [old_base_el_no].push_back(el_pt);
1245 if (dynamic_cast<TreeRoot*>(ref_el_pt->
tree_pt()))
1247 unsigned old_base_el_no =
1248 old_base_element_number_plus_one[el_pt]-1;
1249 new_base_element_associated_with_old_base_element
1250 [old_base_el_no].push_back(el_pt);
1258 if (!root_el_done[root_el_pt])
1260 root_el_done[root_el_pt]=
true;
1261 unsigned old_base_el_no=
1262 old_base_element_number_plus_one[el_pt]-1;
1263 new_base_element_associated_with_old_base_element
1264 [old_base_el_no].push_back(root_el_pt);
1278 for (
unsigned e=0;
e<nel_base_old;
e++)
1280 local_n_new_root[
e]=
1281 new_base_element_associated_with_old_base_element[
e].size();
1285 n_new_root_back[
e]=local_n_new_root[
e];
1293 <<
"Time for setup of new base elements in " 1294 <<
"Problem::prune_halo_elements_and_nodes(): " 1295 << t_end-t_start << std::endl;
1303 MPI_Allreduce(&local_n_new_root[0],&n_new_root[0],nel_base_old,
1311 <<
"Time for allreduce in " 1312 <<
"Problem::prune_halo_elements_and_nodes(): " 1313 << t_end-t_start << std::endl;
1318 unsigned nel_base_new=0;
1319 for (
unsigned e=0;
e<nel_base_old;
e++)
1322 nel_base_new+=n_new_root[
e];
1329 if (!old_root_is_halo_or_non_existent[
e])
1331 if (n_new_root_back[e]!=0)
1333 if (n_new_root_back[e]!=n_new_root[e])
1335 std::ostringstream error_stream;
1337 <<
"Number of new root elements spawned from old root " 1338 << e <<
": " << n_new_root[
e] <<
"\nis not consistent" 1339 <<
" with previous value: " << n_new_root_back[
e] << std::endl;
1342 OOMPH_CURRENT_FUNCTION,
1343 OOMPH_EXCEPTION_LOCATION);
1358 for (
unsigned e=0;
e<nel_base_old;
e++)
1362 if (!old_root_is_halo_or_non_existent[
e])
1365 unsigned n_new_root=
1366 new_base_element_associated_with_old_base_element[
e].size();
1367 for (
unsigned j=0;j<n_new_root;j++)
1371 new_base_element_associated_with_old_base_element[
e][j];
1384 unsigned nskip=n_new_root[
e];
1398 <<
"Time for finishing off base mesh info " 1399 <<
"Problem::prune_halo_elements_and_nodes(): " 1400 << t_end-t_start << std::endl;
1413 <<
"Time for actions_after_distribute() " 1414 <<
"Problem::prune_halo_elements_and_nodes(): " 1415 << t_end-t_start << std::endl;
1432 <<
"Time for assign_eqn_numbers() " 1433 <<
"Problem::prune_halo_elements_and_nodes(): " 1434 << t_end-t_start << std::endl;
1442 if (n_dof!=old_ndof)
1444 std::ostringstream error_stream;
1446 <<
"Number of dofs in prune_halo_elements_and_nodes() has changed " 1447 <<
"from " << old_ndof <<
" to " << n_dof <<
"\n" 1448 <<
"Check that you've implemented any necessary actions_before/after" 1449 <<
"\nadapt/distribute functions, e.g. to pin redundant pressure" 1452 OOMPH_CURRENT_FUNCTION,
1453 OOMPH_EXCEPTION_LOCATION);
1480 "Problem::build_global_mesh() called,\n";
1481 error_message +=
" but a global mesh has already been built:\n";
1482 error_message +=
"Problem::Mesh_pt is not zero!\n";
1485 OOMPH_CURRENT_FUNCTION,
1486 OOMPH_EXCEPTION_LOCATION);
1492 "Problem::build_global_mesh() called,\n";
1493 error_message +=
" but there are no submeshes:\n";
1494 error_message +=
"Problem::Sub_mesh_pt has no entries\n";
1497 OOMPH_CURRENT_FUNCTION,
1498 OOMPH_EXCEPTION_LOCATION);
1535 unsigned ndt = time_stepper_pt->
ndt();
1542 oomph_info <<
"Created Time with " << ndt <<
" timesteps" << std::endl;
1551 oomph_info <<
"Resized Time to include " << ndt <<
" timesteps" 1557 oomph_info <<
"Time object already has storage for " << ndt
1558 <<
" timesteps" << std::endl;
1581 oomph_info <<
"Created Time with storage for no previous timestep" 1586 oomph_info <<
"Time object already exists " << std::endl;
1592 #ifdef OOMPH_HAS_MPI 1617 unsigned hi_proc=n_proc-1;
1618 if (
int(n_elements)>=n_proc)
1620 range=unsigned(
double(n_elements)/
double(n_proc));
1626 hi_proc=unsigned(
double(n_elements)/
double(min_el));
1629 for (
int p=lo_proc;p<=int(hi_proc);p++)
1633 unsigned last_el_plus_one=(p+1)*range;
1634 if (last_el_plus_one>n_elements) last_el_plus_one=n_elements;
1639 if (
int(n_elements)>=n_proc)
1650 oomph_info <<
"Problem is not distributed. Parallel assembly of " 1651 <<
"Jacobian uses default partitioning: "<< std::endl;
1652 for (
int p=0;p<n_proc;p++)
1656 oomph_info <<
"Proc " << p <<
" assembles from element " 1662 oomph_info <<
"Proc " << p <<
" assembles no elements\n";
1689 if (
int(nel)<n_proc)
1691 oomph_info <<
"Not re-computing distribution of elemental assembly\n" 1692 <<
"because there are fewer elements than processors\n";
1701 for (
int p=0;p<n_proc;p++)
1709 receive_count[p]=el_hi-el_lo+1;
1710 displacement[p]=offset;
1711 offset+=el_hi-el_lo+1;
1715 double* el_ass_time =
new double[nel];
1716 for (
unsigned e=0;
e<nel;
e++)
1725 &el_ass_time[First_el_for_assembly[rank]],nel_local,MPI_DOUBLE,
1728 delete[] el_ass_time;
1732 for(
int p=0;p<n_proc;p++) {first_and_last_element[p].resize(2);}
1741 <<
"Re-assigning distribution of element assembly over processors:" 1748 for (
unsigned e=0;
e<n_elements;
e++)
1754 double target_load=total/double(n_proc);
1758 first_and_last_element[0][0] = 0;
1762 unsigned max_el_avail=n_elements-n_proc;
1766 for (
unsigned e=0;
e<n_elements;
e++)
1772 if ((total>target_load)||(
e==max_el_avail))
1776 first_and_last_element[proc][1]=
e;
1779 if (proc<(n_proc-1))
1782 first_and_last_element[proc+1][0]=
e+1;
1798 first_and_last_element[n_proc-1][1]=n_elements-1;
1805 std::ostringstream error_stream;
1806 for (
int p=0;p<n_proc-1;p++)
1808 unsigned first_of_current=first_and_last_element[p][0];
1809 unsigned last_of_current=first_and_last_element[p][1];
1810 if (first_of_current>last_of_current)
1813 error_stream <<
"Error: First/last element of proc " << p <<
": " 1814 << first_of_current <<
" " << last_of_current
1817 unsigned first_of_next=first_and_last_element[p+1][0];
1818 if (first_of_next!=(last_of_current+1))
1821 error_stream <<
"Error: First element of proc " << p+1 <<
": " 1822 << first_of_next <<
" and last element of proc " 1823 << p <<
": " << last_of_current
1830 OOMPH_CURRENT_FUNCTION,
1831 OOMPH_EXCEPTION_LOCATION);
1900 First_el_for_assembly[0]= first_and_last_element[0][0];
1906 <<
"Processor " << 0 <<
" assembles Jacobians" 1907 <<
" from elements " << first_and_last_element[0][0] <<
" to " 1908 << first_and_last_element[0][1] <<
" " 1913 for(
int p=1;p<n_proc;++p)
1916 MPI_Send(&first_and_last_element[p][0],2,MPI_INT,p,
1923 <<
"Processor " << p <<
" assembles Jacobians" 1924 <<
" from elements " << first_and_last_element[p][0] <<
" to " 1925 << first_and_last_element[p][1] <<
" " 1935 MPI_Recv(&aux[0],2,MPI_INT,0,0,
1937 First_el_for_assembly[rank]=aux[0];
1942 for (
int p=0;p<n_proc;p++)
1946 First_el_for_assembly[p]=0;
1972 std::ostringstream error_stream;
1974 "Global mesh does not exist, so equation numbers cannot be assigned.\n";
1978 error_stream <<
"There aren't even any sub-meshes in the Problem.\n" 1979 <<
"You can set the global mesh directly by using\n" 1980 <<
"Problem::mesh_pt() = my_mesh_pt;\n" 1981 <<
"OR you can use Problem::add_sub_mesh(mesh_pt); " 1982 <<
"to add a sub mesh.\n";
1986 error_stream <<
"There are " <<
nsub_mesh() <<
" sub-meshes.\n";
1989 "You need to call Problem::build_global_mesh() to create a global mesh\n" 1990 <<
"from the sub-meshes.\n\n";
1993 OOMPH_CURRENT_FUNCTION,
1994 OOMPH_EXCEPTION_LOCATION);
2001 #ifdef OOMPH_HAS_MPI 2031 double t_start = 0.0;
2042 for (
unsigned e=0;
e<nel;
e++)
2047 #ifdef OOMPH_HAS_MPI 2050 for (
unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
2052 for (
int iproc=0;iproc<n_proc;iproc++)
2055 for (
unsigned e=0;
e<n_ext_halo_el;
e++)
2072 <<
"Time for complete setup of dependencies in assign_eqn_numbers: " 2073 << t_end-t_start << std::endl;
2083 for (
unsigned loop_count=0;loop_count<2;loop_count++)
2094 unsigned long equation_number=0;
2098 for(
unsigned i=0;
i<Nglobal_data;
i++)
2115 n_dof = spine_mesh_pt->assign_global_spine_eqn_numbers(
Dof_pt);
2122 for(
unsigned i=0;
i<n_sub_mesh;
i++)
2127 n_dof = spine_mesh_pt->assign_global_spine_eqn_numbers(
Dof_pt);
2136 <<
"Time for assign_global_eqn_numbers in assign_eqn_numbers: " 2137 << t_end-t_start << std::endl;
2142 #ifdef OOMPH_HAS_MPI 2170 <<
"Time for Problem::synchronise_eqn_numbers in " 2171 <<
"Problem::assign_eqn_numbers: " 2172 << t_end-t_start << std::endl;
2176 #ifdef OOMPH_HAS_MPI 2189 bool actually_removed_some_data=
false;
2200 for (
unsigned i=0;
i<n_sub_mesh;
i++)
2202 bool tmp_actually_removed_some_data=
false;
2204 tmp_actually_removed_some_data);
2205 if (tmp_actually_removed_some_data) actually_removed_some_data=
true;
2214 std::stringstream tmp;
2215 tmp <<
"Time for calls to Problem::remove_duplicate_data in " 2216 <<
"Problem::assign_eqn_numbers: " 2217 << t_end-t_start <<
" ; have ";
2218 if (!actually_removed_some_data)
2222 tmp <<
" removed some/any data.\n";
2229 if (actually_removed_some_data) status=1;
2232 unsigned overall_status=0;
2233 MPI_Allreduce(&status,&overall_status,1,
2240 std::stringstream tmp;
2241 tmp <<
"Time for MPI_Allreduce after Problem::remove_duplicate_data in " 2242 <<
"Problem::assign_eqn_numbers: " 2243 << t_end-t_start << std::endl;
2249 if (overall_status!=1)
2265 <<
"Total time for " 2266 <<
"Problem::remove_null_pointers_from_external_halo_node_storage(): " 2267 << t_end-t_start << std::endl;
2298 if (assign_local_eqn_numbers)
2306 for (
unsigned i=0;
i<n_sub_mesh;
i++)
2318 <<
"Total time for all Mesh::assign_local_eqn_numbers in " 2319 <<
"Problem::assign_eqn_numbers: " 2320 << t_end-t_start << std::endl;
2341 std::ostringstream error_stream;
2343 "Global mesh does not exist, so equation numbers cannot be found.\n";
2347 error_stream <<
"There aren't even any sub-meshes in the Problem.\n" 2348 <<
"You can set the global mesh directly by using\n" 2349 <<
"Problem::mesh_pt() = my_mesh_pt;\n" 2350 <<
"OR you can use Problem::add_sub_mesh(mesh_pt); " 2351 <<
"to add a sub mesh.\n";
2355 error_stream <<
"There are " <<
nsub_mesh() <<
" sub-meshes.\n";
2358 "You need to call Problem::build_global_mesh() to create a global mesh\n" 2359 <<
"from the sub-meshes.\n\n";
2362 OOMPH_CURRENT_FUNCTION,
2363 OOMPH_EXCEPTION_LOCATION);
2367 out <<
"Although this program will describe the degrees of freedom in the \n" 2368 <<
"problem, it will do so using the typedef for the elements. This is \n" 2369 <<
"not neccesarily human readable, but there is a solution.\n" 2370 <<
"Pipe your program's output through c++filt, with the argument -t.\n" 2371 <<
"e.g. \"./two_d_multi_poisson | c++filt -t > ReadableOutput.txt\".\n " 2372 <<
"(Disregarding the quotes)\n\n\n";
2374 out <<
"Classifying Global Equation Numbers" << std::endl;
2382 for(
unsigned i=0;
i<Nglobal_data;
i++)
2384 std::stringstream conversion;
2385 conversion <<
" in Global Data "<<
i<<
".";
2404 spine_mesh_pt->describe_spine_dofs(out,in);
2411 for(
unsigned i=0;
i<n_sub_mesh;
i++)
2416 std::stringstream conversion;
2417 conversion <<
" in Sub-SpineMesh "<<i<<
".";
2419 spine_mesh_pt->describe_spine_dofs(out,in);
2428 out <<
"Classifying global eqn numbers in terms of elements." << std::endl;
2430 out <<
"Eqns | Source" << std::endl;
2440 for (
unsigned i=0;
i<n_sub_mesh;
i++)
2442 std::stringstream conversion;
2443 conversion <<
" in Sub-Mesh "<<
i<<
".";
2458 const unsigned long n_dof =
ndof();
2464 for(
unsigned long l=0;l<n_dof;l++)
2476 throw OomphLibError(
"Not designed for distributed problems",
2477 OOMPH_EXCEPTION_LOCATION,
2478 OOMPH_CURRENT_FUNCTION);
2488 for(
unsigned i=0;
i<Nglobal_data;
i++)
2502 for(
unsigned i=0, ni=
mesh_pt()->nelement();
i<ni;
i++)
2510 for(
unsigned k=0, nk=d_pt->
nvalue(); k<nk; k++)
2516 dofs[eqn_number] = d_pt->
value(t, k);
2523 for(
unsigned i=0, ni=
mesh_pt()->nnode();
i<ni;
i++)
2526 for(
unsigned j=0, nj=node_pt->
nvalue(); j<nj; j++)
2532 dofs[eqn_number] = node_pt->
value(t, j);
2540 #ifdef OOMPH_HAS_MPI 2549 bool& actually_removed_some_data)
2564 actually_removed_some_data=
false;
2581 std::map<unsigned,Node*> global_node_pt;
2584 std::map<Node*,bool> node_done;
2587 unsigned n_element=mesh_pt->
nelement();
2588 for (
unsigned e=0;
e<n_element;
e++)
2595 unsigned n_node=el_pt->
nnode();
2596 for (
unsigned j=0;j<n_node;j++)
2601 if (!node_done[nod_pt])
2603 node_done[nod_pt]=
true;
2607 unsigned first_non_negative_eqn_number_plus_one=0;
2608 unsigned n_val=nod_pt->
nvalue();
2609 for (
unsigned i_val=0;i_val<n_val;i_val++)
2611 int eqn_no=nod_pt->eqn_number(i_val);
2614 first_non_negative_eqn_number_plus_one=eqn_no+1;
2621 if (first_non_negative_eqn_number_plus_one==0)
2625 if (solid_nod_pt!=0)
2630 for (
unsigned i_val=0;i_val<n_val;i_val++)
2632 int eqn_no=solid_nod_pt->
2636 first_non_negative_eqn_number_plus_one=eqn_no+1;
2644 if (first_non_negative_eqn_number_plus_one>0)
2646 global_node_pt[first_non_negative_eqn_number_plus_one-1]=nod_pt;
2651 if (dynamic_cast<RefineableElement*>(el_pt)!=0)
2654 (el_pt)->ncont_interpolated_values();
2655 for (
int i_cont=-1;i_cont<n_cont_int_values;i_cont++)
2657 if (nod_pt->is_hanging(i_cont))
2659 HangInfo* hang_pt=nod_pt->hanging_pt(i_cont);
2660 unsigned n_master=hang_pt->
nmaster();
2661 for (
unsigned m=0;m<n_master;m++)
2664 if (!node_done[master_nod_pt])
2666 node_done[master_nod_pt]=
true;
2670 unsigned first_non_negative_eqn_number_plus_one=0;
2671 unsigned n_val=master_nod_pt->
nvalue();
2672 for (
unsigned i_val=0;i_val<n_val;i_val++)
2674 int eqn_no=master_nod_pt->eqn_number(i_val);
2677 first_non_negative_eqn_number_plus_one=eqn_no+1;
2684 if (first_non_negative_eqn_number_plus_one==0)
2690 if (master_solid_nod_pt!=0)
2694 unsigned n_val=master_solid_nod_pt->
2695 variable_position_pt()->
nvalue();
2696 for (
unsigned i_val=0;i_val<n_val;i_val++)
2698 int eqn_no=master_solid_nod_pt->
2702 first_non_negative_eqn_number_plus_one=eqn_no+1;
2710 if (first_non_negative_eqn_number_plus_one>0)
2712 global_node_pt[first_non_negative_eqn_number_plus_one-1]
2731 std::set<Node*> killed_nodes;
2736 for (
int iproc=n_proc-1;iproc>=0;iproc--)
2744 for (
unsigned e_ext=0;e_ext<n_element;e_ext++)
2748 external_halo_element_pt(iproc,e_ext));
2749 if(finite_ext_el_pt!=0)
2752 unsigned n_node=finite_ext_el_pt->
nnode();
2753 for (
unsigned j=0;j<n_node;j++)
2759 unsigned first_non_negative_eqn_number_plus_one=0;
2760 unsigned n_val=nod_pt->
nvalue();
2761 for (
unsigned i_val=0;i_val<n_val;i_val++)
2766 first_non_negative_eqn_number_plus_one=eqn_no+1;
2773 if (first_non_negative_eqn_number_plus_one==0)
2777 if (solid_nod_pt!=0)
2782 for (
unsigned i_val=0;i_val<n_val;i_val++)
2784 int eqn_no=solid_nod_pt->
2788 first_non_negative_eqn_number_plus_one=eqn_no+1;
2798 if (first_non_negative_eqn_number_plus_one>0)
2800 Node* existing_node_pt=
2801 global_node_pt[first_non_negative_eqn_number_plus_one-1];
2804 if (existing_node_pt!=0)
2807 actually_removed_some_data=
true;
2811 Node* duplicated_node_pt=nod_pt;
2812 if (!node_done[duplicated_node_pt])
2816 std::set<unsigned>* boundaries_pt;
2817 duplicated_node_pt->
2818 get_boundaries_pt(boundaries_pt);
2819 if (boundaries_pt!=0)
2822 unsigned nb=(*boundaries_pt).size();
2824 for (std::set<unsigned>::iterator it=
2825 (*boundaries_pt).begin(); it!=
2826 (*boundaries_pt).end(); it++)
2828 bound.push_back((*it));
2830 for (
unsigned i=0;
i<nb;
i++)
2833 duplicated_node_pt);
2838 killed_nodes.insert(duplicated_node_pt);
2839 unsigned i_proc=unsigned(iproc);
2841 duplicated_node_pt);
2855 if (dynamic_cast<RefineableElement*>(finite_ext_el_pt)!=0)
2858 (finite_ext_el_pt)->ncont_interpolated_values();
2859 for (
int i_cont=-1;i_cont<n_cont_inter_values;i_cont++)
2861 unsigned n_master_orig=0;
2864 n_master_orig=finite_ext_el_pt->
node_pt(j)->
2865 hanging_pt(i_cont)->nmaster();
2872 unsigned n_master_replace=0;
2875 n_master_replace=existing_node_pt->
2876 hanging_pt(i_cont)->nmaster();
2879 if (n_master_orig!=n_master_replace)
2881 std::ostringstream error_stream;
2882 error_stream <<
"Number of master nodes for node to be replaced, " 2883 << n_master_orig <<
", doesn't match" 2884 <<
"those of replacement node, " 2885 << n_master_replace <<
" for i_cont=" 2886 << i_cont << std::endl;
2888 error_stream <<
"Nodal coordinates of replacement node:";
2889 unsigned ndim=existing_node_pt->
ndim();
2890 for (
unsigned i=0;
i<ndim;
i++)
2892 error_stream << existing_node_pt->
x(
i) <<
" ";
2894 error_stream <<
"\n";
2895 error_stream <<
"The coordinates of its " 2896 << n_master_replace <<
" master nodes are: \n";
2897 for (
unsigned k=0;k<n_master_replace;k++)
2899 Node* master_nod_pt=existing_node_pt->
2900 hanging_pt(i_cont)->master_node_pt(k);
2901 unsigned ndim=master_nod_pt->
ndim();
2902 for (
unsigned i=0;
i<ndim;
i++)
2904 error_stream << master_nod_pt->
x(
i) <<
" ";
2906 error_stream <<
"\n";
2911 error_stream <<
"Nodal coordinates of node to be replaced:";
2912 unsigned ndim=finite_ext_el_pt->
node_pt(j)->
ndim();
2913 for (
unsigned i=0;
i<ndim;
i++)
2915 error_stream << finite_ext_el_pt->
node_pt(j)->
x(
i) <<
" ";
2917 error_stream <<
"\n";
2918 error_stream <<
"The coordinates of its " 2919 << n_master_orig <<
" master nodes are: \n";
2920 for (
unsigned k=0;k<n_master_orig;k++)
2922 Node* master_nod_pt=finite_ext_el_pt->
node_pt(j)->
2923 hanging_pt(i_cont)->master_node_pt(k);
2924 unsigned ndim=master_nod_pt->
ndim();
2925 for (
unsigned i=0;
i<ndim;
i++)
2927 error_stream << master_nod_pt->
x(
i) <<
" ";
2929 error_stream <<
"\n";
2935 OOMPH_CURRENT_FUNCTION,
2936 OOMPH_EXCEPTION_LOCATION);
2942 finite_ext_el_pt->
node_pt(j)=existing_node_pt;
2947 global_node_pt[first_non_negative_eqn_number_plus_one-1]=
2949 node_done[nod_pt]=
true;
2955 if (dynamic_cast<RefineableElement*>(finite_ext_el_pt)!=0)
2958 (finite_ext_el_pt)->ncont_interpolated_values();
2959 for (
int i_cont=-1;i_cont<n_cont_inter_values;i_cont++)
2964 unsigned n_master=hang_pt->
nmaster();
2965 for (
unsigned m=0;m<n_master;m++)
2968 unsigned n_val=master_nod_pt->
nvalue();
2969 unsigned first_non_negative_eqn_number_plus_one=0;
2970 for (
unsigned i_val=0;i_val<n_val;i_val++)
2975 first_non_negative_eqn_number_plus_one=eqn_no+1;
2982 if (first_non_negative_eqn_number_plus_one==0)
2986 if (solid_master_nod_pt!=0)
2990 unsigned n_val=solid_master_nod_pt->
2991 variable_position_pt()->
nvalue();
2992 for (
unsigned i_val=0;i_val<n_val;i_val++)
2994 int eqn_no=solid_master_nod_pt->
2998 first_non_negative_eqn_number_plus_one=eqn_no+1;
3009 if (first_non_negative_eqn_number_plus_one>0)
3011 Node* existing_node_pt=
3013 first_non_negative_eqn_number_plus_one-1];
3016 if (existing_node_pt!=0)
3019 actually_removed_some_data=
true;
3023 Node* duplicated_node_pt=master_nod_pt;
3025 if (!node_done[duplicated_node_pt])
3028 std::set<unsigned>* boundaries_pt;
3029 duplicated_node_pt->
3030 get_boundaries_pt(boundaries_pt);
3031 if (boundaries_pt!=0)
3033 for (std::set<unsigned>::iterator it=
3034 (*boundaries_pt).begin(); it!=
3035 (*boundaries_pt).end(); it++)
3038 (*it),duplicated_node_pt);
3042 killed_nodes.insert(duplicated_node_pt);
3043 unsigned i_proc=unsigned(iproc);
3045 duplicated_node_pt);
3059 std::ostringstream error_stream;
3061 <<
"About to re-set master for i_cont= " 3062 << i_cont <<
" for external node (with proc " 3064 << tmp_nod_pt <<
" at ";
3065 unsigned n=tmp_nod_pt->
ndim();
3066 for (
unsigned jj=0;jj<n;jj++)
3068 error_stream << tmp_nod_pt->x(jj) <<
" ";
3071 <<
" which is not hanging --> About to die!" 3072 <<
"Outputting offending element into oomph-info " 3080 OOMPH_CURRENT_FUNCTION,
3081 OOMPH_EXCEPTION_LOCATION);
3087 finite_ext_el_pt->
node_pt(j)->
3088 hanging_pt(i_cont)->
3089 set_master_node_pt(m,existing_node_pt,
3096 first_non_negative_eqn_number_plus_one-1]=
3098 node_done[master_nod_pt]=
true;
3116 for (std::set<Node*>::iterator it=killed_nodes.begin();
3117 it!=killed_nodes.end();it++)
3147 unsigned n_mesh_loop=1;
3159 if(n_proc==1) {
return;}
3174 for (
int domain=0;domain<n_proc;domain++)
3177 send_displacement[domain] = send_data.size();
3188 for (
unsigned imesh=0;imesh<n_mesh_loop;imesh++)
3203 unsigned nnod=backup_pt.size();
3207 new_external_halo_node_pt.reserve(nnod);
3210 for (
unsigned j=0;j<nnod;j++)
3213 Node* nod_pt=backup_pt[j];
3219 send_data.push_back(j);
3224 new_external_halo_node_pt.push_back(nod_pt);
3232 send_data.push_back(-1);
3239 send_n[domain] = send_data.size() - send_displacement[domain];
3247 MPI_Alltoall(&send_n[0],1,MPI_INT,&receive_n[0],1,MPI_INT,
3254 int receive_data_count=0;
3255 for(
int rank=0;rank<n_proc;++rank)
3258 receive_displacement[rank] = receive_data_count;
3259 receive_data_count += receive_n[rank];
3264 if(receive_data_count==0) {++receive_data_count;}
3269 if(send_data.size()==0) {send_data.resize(1);}
3272 MPI_Alltoallv(&send_data[0],&send_n[0],&send_displacement[0],
3274 &receive_data[0],&receive_n[0],
3275 &receive_displacement[0],
3280 for (
int send_rank=0;send_rank<n_proc;send_rank++)
3284 if((send_rank != my_rank) && (receive_n[send_rank] != 0))
3287 unsigned count=receive_displacement[send_rank];
3293 for (
unsigned imesh=0;imesh<n_mesh_loop;imesh++)
3311 int next_one=receive_data[count++];
3320 backup_pt[next_one]=0;
3325 unsigned nnod=backup_pt.size();
3329 new_external_haloed_node_pt.reserve(nnod);
3332 for (
unsigned j=0;j<nnod;j++)
3335 Node* nod_pt=backup_pt[j];
3341 new_external_haloed_node_pt.push_back(nod_pt);
3347 new_external_haloed_node_pt);
3364 const unsigned long n_dof = this->
ndof();
3366 if(n_dof != dofs.
nrow())
3368 std::ostringstream error_stream;
3369 error_stream <<
"Number of degrees of freedom in vector argument " 3370 << dofs.
nrow() <<
"\n" 3371 <<
"does not equal number of degrees of freedom in problem " 3374 OOMPH_CURRENT_FUNCTION,
3375 OOMPH_EXCEPTION_LOCATION);
3378 for(
unsigned long l=0;l<n_dof;l++)
3390 throw OomphLibError(
"Not designed for distributed problems",
3391 OOMPH_EXCEPTION_LOCATION,
3392 OOMPH_CURRENT_FUNCTION);
3399 for(
unsigned i=0;
i<Nglobal_data;
i++)
3413 for(
unsigned i=0, ni=
mesh_pt()->nelement();
i<ni;
i++)
3421 for(
unsigned k=0, nk=d_pt->
nvalue(); k<nk; k++)
3427 d_pt->
set_value(t, k, dofs[eqn_number]);
3434 for(
unsigned i=0, ni=
mesh_pt()->nnode();
i<ni;
i++)
3437 for(
unsigned j=0, nj=node_pt->
nvalue(); j<nj; j++)
3443 node_pt->
set_value(t, j, dofs[eqn_number]);
3457 throw OomphLibError(
"Not implemented for distributed problems!",
3458 OOMPH_EXCEPTION_LOCATION,
3459 OOMPH_CURRENT_FUNCTION);
3469 for(
unsigned i=0;
i<Nglobal_data;
i++)
3484 for(
unsigned i=0, ni=
mesh_pt()->nnode();
i<ni;
i++)
3487 for(
unsigned j=0, nj=node_pt->
nvalue(); j<nj; j++)
3493 node_pt->
set_value(t, j, *(dof_pt[eqn_number]));
3499 for(
unsigned i=0, ni=
mesh_pt()->nelement();
i<ni;
i++)
3509 data_pt->
set_value(t, j, *(dof_pt[eqn_number]));
3523 const unsigned long n_dof = this->
ndof();
3524 for(
unsigned long l=0;l<n_dof;l++)
3526 *
Dof_pt[l] += lambda*increment_dofs[l];
3545 std::ostringstream error_stream;
3548 "The function get_inverse_mass_matrix_times_residuals() can only be\n" 3550 "used with the default assembly handler\n\n";
3552 OOMPH_CURRENT_FUNCTION,
3553 OOMPH_EXCEPTION_LOCATION);
3558 const unsigned n_dof = this->
ndof();
3562 Mres.
build(&dist,0.0);
3571 for(
unsigned e=0;
e<n_element;
e++)
3578 const unsigned n_el_dofs = elem_pt->
ndof();
3582 for(
unsigned i=0;
i<n_el_dofs;
i++)
3598 oomph_info <<
"Not recomputing Mass Matrix " << std::endl;
3616 oomph_info <<
"Enabling resolve in explicit timestep" << std::endl;
3646 std::vector<bool> was_steady(n_time_steppers);
3647 for(
unsigned i=0;
i<n_time_steppers;
i++)
3658 for(
unsigned i=0;
i<n_time_steppers;
i++)
3689 if(residuals.
built())
3693 std::ostringstream error_stream;
3695 "The distribution of the residuals vector does not have the correct\n" 3697 "number of global rows\n";
3700 OOMPH_CURRENT_FUNCTION,
3701 OOMPH_EXCEPTION_LOCATION);
3707 const unsigned nrow = this->
ndof();
3714 if (residuals.
built())
3720 #ifdef OOMPH_HAS_MPI 3747 bool use_problem_dist =
true;
3749 for (
unsigned p = 0; p < nproc; p++)
3752 ((double)uniform_dist_pt->
nrow_local(p))*1.1)
3754 use_problem_dist =
false;
3757 if (use_problem_dist)
3765 delete uniform_dist_pt;
3778 residuals.
build(dist_pt,0.0);
3781 #ifdef OOMPH_HAS_MPI 3784 #endif // OOMPH_HAS_MPI 3787 for(
unsigned long e=0;
e<Element_pt_range;
e++)
3792 unsigned n_element_dofs = assembly_handler_pt->
ndof(elem_pt);
3796 assembly_handler_pt->
get_residuals(elem_pt,element_residuals);
3798 for(
unsigned l=0;l<n_element_dofs;l++)
3800 residuals[assembly_handler_pt->
eqn_number(elem_pt,l)]
3801 += element_residuals[l];
3805 #ifdef OOMPH_HAS_MPI 3856 unsigned n_dof=
ndof();
3862 if (residuals.
built())
3866 std::ostringstream error_stream;
3868 <<
"If the DoubleVector residuals is setup then it must not " 3869 <<
"be distributed.";
3871 OOMPH_CURRENT_FUNCTION,
3872 OOMPH_EXCEPTION_LOCATION);
3876 std::ostringstream error_stream;
3878 <<
"If the DoubleVector residuals is setup then it must have" 3879 <<
" the correct number of rows";
3881 OOMPH_CURRENT_FUNCTION,
3882 OOMPH_EXCEPTION_LOCATION);
3886 std::ostringstream error_stream;
3888 <<
"If the DoubleVector residuals is setup then it must have" 3889 <<
" the same communicator as the problem.";
3891 OOMPH_CURRENT_FUNCTION,
3892 OOMPH_EXCEPTION_LOCATION);
3898 if (!residuals.
built())
3901 residuals.
build(&dist,0.0);
3915 jacobian.
resize(n_dof,n_dof);
3923 for(
unsigned long e=0;
e<n_element;
e++)
3928 unsigned n_element_dofs = assembly_handler_pt->
ndof(elem_pt);
3935 element_residuals,element_jacobian);
3937 for(
unsigned l=0;l<n_element_dofs;l++)
3939 unsigned long eqn_number = assembly_handler_pt->
eqn_number(elem_pt,l);
3940 residuals[eqn_number] += element_residuals[l];
3941 for(
unsigned l2=0;l2<n_element_dofs;l2++)
3943 jacobian(eqn_number ,
3944 assembly_handler_pt->
eqn_number(elem_pt,l2)) +=
3945 element_jacobian(l,l2);
3992 if (residuals.
built() &&
3997 std::ostringstream error_stream;
3998 error_stream <<
"The distribution of the residuals must " 3999 <<
"be the same as the distribution of the jacobian.";
4001 OOMPH_CURRENT_FUNCTION,
4002 OOMPH_EXCEPTION_LOCATION);
4006 std::ostringstream error_stream;
4007 error_stream <<
"The distribution of the jacobian and residuals does not" 4008 <<
"have the correct number of global rows.";
4010 OOMPH_CURRENT_FUNCTION,
4011 OOMPH_EXCEPTION_LOCATION);
4014 else if (residuals.
built() !=
4017 std::ostringstream error_stream;
4018 error_stream <<
"The distribution of the jacobian and residuals must " 4019 <<
"both be setup or both not setup";
4021 OOMPH_CURRENT_FUNCTION,
4022 OOMPH_EXCEPTION_LOCATION);
4031 unsigned nrow = this->
ndof();
4044 #ifdef OOMPH_HAS_MPI 4070 bool use_problem_dist =
true;
4072 for (
unsigned p = 0; p < nproc; p++)
4075 ((double)uniform_dist_pt->
nrow_local(p))*1.1)
4077 use_problem_dist =
false;
4080 if (use_problem_dist)
4088 delete uniform_dist_pt;
4099 bool compressed_row_flag=
true;
4101 #ifdef OOMPH_HAS_MPI 4111 compressed_row_flag);
4112 jacobian.
build(dist_pt);
4114 value[0],column_index[0],row_start[0]);
4115 residuals.
build(dist_pt,0.0);
4117 #ifdef OOMPH_HAS_MPI 4129 jacobian.
build(dist_pt);
4131 value[0],column_index[0],
4133 residuals.
build(dist_pt,0.0);
4146 jacobian.
build(temp_dist_pt);
4148 value[0],column_index[0],
4151 residuals.
build(temp_dist_pt,0.0);
4154 delete temp_dist_pt;
4186 unsigned n_dof=
ndof();
4192 if (residuals.
built())
4196 std::ostringstream error_stream;
4198 <<
"If the DoubleVector residuals is setup then it must not " 4199 <<
"be distributed.";
4201 OOMPH_CURRENT_FUNCTION,
4202 OOMPH_EXCEPTION_LOCATION);
4206 std::ostringstream error_stream;
4208 <<
"If the DoubleVector residuals is setup then it must have" 4209 <<
" the correct number of rows";
4211 OOMPH_CURRENT_FUNCTION,
4212 OOMPH_EXCEPTION_LOCATION);
4216 std::ostringstream error_stream;
4218 <<
"If the DoubleVector residuals is setup then it must have" 4219 <<
" the same communicator as the problem.";
4221 OOMPH_CURRENT_FUNCTION,
4222 OOMPH_EXCEPTION_LOCATION);
4242 bool compressed_row_flag=
false;
4246 if (!residuals.
built())
4256 #ifdef OOMPH_HAS_MPI 4265 compressed_row_flag);
4268 residuals.
build(dist_pt,0.0);
4270 #ifdef OOMPH_HAS_MPI 4274 std::ostringstream error_stream;
4276 <<
"Cannot assemble a CCDoubleMatrix Jacobian on more " 4277 <<
"than one processor.";
4279 OOMPH_CURRENT_FUNCTION,
4280 OOMPH_EXCEPTION_LOCATION);
4302 for(
unsigned i=0;
i<n_global_data;
i++)
4305 const unsigned n_value = local_data_pt->
nvalue();
4306 for(
unsigned j=0;j<n_value;j++)
4319 for(
unsigned n=0;n<n_node;n++)
4322 const unsigned n_value = local_node_pt->
nvalue();
4323 for(
unsigned j=0;j<n_value;j++)
4331 dynamic_cast<SolidNode*
>(local_node_pt);
4333 if(local_solid_node_pt)
4336 const unsigned n_dim = local_solid_node_pt->
ndim();
4338 const unsigned n_position_type = local_solid_node_pt->
nposition_type();
4340 for(
unsigned k=0;k<n_position_type;k++)
4342 for(
unsigned i=0;
i<n_dim;
i++)
4348 local_solid_node_pt->
x_gen(k,
i) = 0.0;
4357 for(
unsigned e=0;
e<n_element;
e++)
4361 for(
unsigned i=0;
i<n_internal;
i++)
4364 const unsigned n_value = local_data_pt->
nvalue();
4365 for(
unsigned j=0;j<n_value;j++)
4376 for (
unsigned m=0;m<n_sub_mesh;m++)
4380 for(
unsigned n=0;n<n_node;n++)
4383 const unsigned n_value = local_node_pt->
nvalue();
4384 for(
unsigned j=0;j<n_value;j++)
4392 dynamic_cast<SolidNode*
>(local_node_pt);
4394 if(local_solid_node_pt)
4397 const unsigned n_dim = local_solid_node_pt->
ndim();
4399 const unsigned n_position_type =
4402 for(
unsigned k=0;k<n_position_type;k++)
4404 for(
unsigned i=0;
i<n_dim;
i++)
4410 local_solid_node_pt->
x_gen(k,
i) = 0.0;
4418 const unsigned n_element =
Sub_mesh_pt[m]->nelement();
4419 for(
unsigned e=0;
e<n_element;
e++)
4424 for(
unsigned i=0;
i<n_internal;
i++)
4427 const unsigned n_value = local_data_pt->
nvalue();
4428 for(
unsigned j=0;j<n_value;j++)
4467 bool compressed_row_flag)
4477 column_or_row_index,
4478 row_or_column_start,
4482 compressed_row_flag);
4489 column_or_row_index,
4490 row_or_column_start,
4494 compressed_row_flag);
4501 column_or_row_index,
4502 row_or_column_start,
4506 compressed_row_flag);
4513 column_or_row_index,
4514 row_or_column_start,
4518 compressed_row_flag);
4525 column_or_row_index,
4526 row_or_column_start,
4530 compressed_row_flag);
4536 std::ostringstream error_stream;
4538 <<
"Error: Incorrect value for Problem::Sparse_assembly_method" 4540 <<
"It should be one of the enumeration Problem::Assembly_method" 4543 OOMPH_CURRENT_FUNCTION,
4544 OOMPH_EXCEPTION_LOCATION);
4574 bool compressed_row_flag)
4580 unsigned long el_lo=0;
4581 unsigned long el_hi=n_elements-1;
4583 #ifdef OOMPH_HAS_MPI 4601 const unsigned n_vector = residuals.size();
4604 const unsigned n_matrix = column_or_row_index.size();
4609 #ifdef OOMPH_HAS_MPI 4610 bool doing_residuals=
false;
4613 doing_residuals=
true;
4619 if(row_or_column_start.size() != n_matrix)
4621 std::ostringstream error_stream;
4623 <<
"Error: " << std::endl
4624 <<
"row_or_column_start.size() " << row_or_column_start.size()
4625 <<
" does not equal " 4626 <<
"column_or_row_index.size() " 4627 << column_or_row_index.size() << std::endl;
4630 OOMPH_CURRENT_FUNCTION,
4631 OOMPH_EXCEPTION_LOCATION);
4634 if(value.size() != n_matrix)
4636 std::ostringstream error_stream;
4638 <<
"Error in Problem::sparse_assemble_row_or_column_compressed " 4640 <<
"value.size() " << value.size() <<
" does not equal " 4641 <<
"column_or_row_index.size() " 4642 << column_or_row_index.size() << std::endl<< std::endl
4646 OOMPH_CURRENT_FUNCTION,
4647 OOMPH_EXCEPTION_LOCATION);
4673 for(
unsigned m=0;m<n_matrix;m++) {matrix_data_map[m].resize(ndof);}
4676 for(
unsigned v=0;v<n_vector;v++)
4678 residuals[v] =
new double[
ndof];
4679 for (
unsigned i = 0;
i <
ndof;
i++)
4681 residuals[v][
i] = 0;
4686 #ifdef OOMPH_HAS_MPI 4690 double t_assemble_start=0.0;
4693 if ((!doing_residuals)&&
4711 for(
unsigned long e=el_lo;
e<=el_hi;
e++)
4714 #ifdef OOMPH_HAS_MPI 4716 if ((!doing_residuals)&&
4726 #ifdef OOMPH_HAS_MPI 4733 const unsigned nvar = assembly_handler_pt->
ndof(elem_pt);
4736 for(
unsigned v=0;v<n_vector;v++) {el_residuals[v].resize(nvar);}
4737 for(
unsigned m=0;m<n_matrix;m++) {el_jacobian[m].resize(nvar);}
4740 assembly_handler_pt->
4741 get_all_vectors_and_matrices(elem_pt,el_residuals, el_jacobian);
4746 for(
unsigned i=0;
i<nvar;
i++)
4753 for(
unsigned v=0;v<n_vector;v++)
4756 residuals[v][eqn_number] += el_residuals[v][
i];
4760 for(
unsigned j=0;j<nvar;j++)
4763 unsigned unknown = assembly_handler_pt->
eqn_number(elem_pt,j);
4766 for(
unsigned m=0;m<n_matrix;m++)
4769 double value = el_jacobian[m](
i,j);
4775 if(compressed_row_flag)
4778 matrix_data_map[m][eqn_number][unknown] += value;
4785 matrix_data_map[m][unknown][eqn_number] += value;
4792 #ifdef OOMPH_HAS_MPI 4797 #ifdef OOMPH_HAS_MPI 4799 if ((!doing_residuals)&&
4811 #ifdef OOMPH_HAS_MPI 4815 if ((!doing_residuals)&&
4825 if ((!doing_residuals)&&
4838 for(
unsigned m=0;m<n_matrix;m++)
4841 row_or_column_start[m] =
new int[ndof+1];
4843 unsigned long entry_count=0;
4844 row_or_column_start[m][0] = entry_count;
4848 for(
unsigned long i_global=0;i_global<
ndof;i_global++)
4850 nnz[m] += matrix_data_map[m][i_global].size();
4854 column_or_row_index[m] =
new int[nnz[m]];
4855 value[m] =
new double[nnz[m]];
4858 for(
unsigned long i_global=0;i_global<
ndof;i_global++)
4861 row_or_column_start[m][i_global] = entry_count;
4863 if(matrix_data_map[m][i_global].empty()) {
continue;}
4868 for(std::map<unsigned,double>::iterator
4869 it = matrix_data_map[m][i_global].begin();
4870 it!=matrix_data_map[m][i_global].end();++it)
4873 column_or_row_index[m][entry_count] = it->first;
4875 value[m][entry_count] = it->second;
4882 row_or_column_start[m][
ndof] = entry_count;
4887 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
4888 pause(
"Check memory usage now.");
4919 bool compressed_row_flag)
4925 unsigned long el_lo=0;
4926 unsigned long el_hi=n_elements-1;
4928 #ifdef OOMPH_HAS_MPI 4946 const unsigned n_vector = residuals.size();
4949 const unsigned n_matrix = column_or_row_index.size();
4954 #ifdef OOMPH_HAS_MPI 4955 bool doing_residuals=
false;
4958 doing_residuals=
true;
4964 if(row_or_column_start.size() != n_matrix)
4966 std::ostringstream error_stream;
4968 <<
"Error: " << std::endl
4969 <<
"row_or_column_start.size() " << row_or_column_start.size()
4970 <<
" does not equal " 4971 <<
"column_or_row_index.size() " 4972 << column_or_row_index.size() << std::endl;
4975 OOMPH_CURRENT_FUNCTION,
4976 OOMPH_EXCEPTION_LOCATION);
4979 if(value.size() != n_matrix)
4981 std::ostringstream error_stream;
4983 <<
"Error in Problem::sparse_assemble_row_or_column_compressed " 4985 <<
"value.size() " << value.size() <<
" does not equal " 4986 <<
"column_or_row_index.size() " 4987 << column_or_row_index.size() << std::endl<< std::endl
4991 OOMPH_CURRENT_FUNCTION,
4992 OOMPH_EXCEPTION_LOCATION);
5014 matrix_data_list(n_matrix);
5016 for(
unsigned m=0;m<n_matrix;m++) {matrix_data_list[m].resize(ndof);}
5019 for(
unsigned v=0;v<n_vector;v++)
5021 residuals[v] =
new double[
ndof];
5022 for (
unsigned i = 0;
i <
ndof;
i++)
5024 residuals[v][
i] = 0;
5028 #ifdef OOMPH_HAS_MPI 5032 double t_assemble_start=0.0;
5035 if ((!doing_residuals)&&
5054 std::list<std::pair<unsigned,double> > *list_pt;
5057 for(
unsigned long e=el_lo;
e<=el_hi;
e++)
5060 #ifdef OOMPH_HAS_MPI 5062 if ((!doing_residuals)&&
5072 #ifdef OOMPH_HAS_MPI 5079 const unsigned nvar = assembly_handler_pt->
ndof(elem_pt);
5082 for(
unsigned v=0;v<n_vector;v++) {el_residuals[v].resize(nvar);}
5083 for(
unsigned m=0;m<n_matrix;m++) {el_jacobian[m].resize(nvar);}
5086 assembly_handler_pt->
5087 get_all_vectors_and_matrices(elem_pt,el_residuals, el_jacobian);
5092 for(
unsigned i=0;
i<nvar;
i++)
5099 for(
unsigned v=0;v<n_vector;v++)
5102 residuals[v][eqn_number] += el_residuals[v][
i];
5106 for(
unsigned j=0;j<nvar;j++)
5109 unsigned unknown = assembly_handler_pt->
eqn_number(elem_pt,j);
5112 for(
unsigned m=0;m<n_matrix;m++)
5115 double value = el_jacobian[m](
i,j);
5121 if(compressed_row_flag)
5124 list_pt = &matrix_data_list[m][eqn_number];
5129 insert(list_pt->end(),std::make_pair(unknown,value));
5136 list_pt = &matrix_data_list[m][unknown];
5141 insert(list_pt->end(),std::make_pair(eqn_number,value));
5148 #ifdef OOMPH_HAS_MPI 5153 #ifdef OOMPH_HAS_MPI 5155 if ((!doing_residuals)&&
5167 #ifdef OOMPH_HAS_MPI 5171 if ((!doing_residuals)&&
5181 if ((!doing_residuals)&&
5194 for(
unsigned m=0;m<n_matrix;m++)
5197 row_or_column_start[m] =
new int[ndof+1];
5199 unsigned long entry_count=0;
5201 row_or_column_start[m][0] = entry_count;
5205 for(
unsigned long i_global=0;i_global<
ndof;i_global++)
5207 nnz[m] += matrix_data_list[m][i_global].size();
5211 column_or_row_index[m] =
new int[nnz[m]];
5212 value[m] =
new double[nnz[m]];
5215 for(
unsigned long i_global=0;i_global<
ndof;i_global++)
5218 row_or_column_start[m][i_global] = entry_count;
5220 if(matrix_data_list[m][i_global].empty()) {
continue;}
5228 matrix_data_list[m][i_global].sort();
5231 std::list<std::pair<unsigned,double> >::iterator it
5232 = matrix_data_list[m][i_global].begin();
5235 unsigned current_index = it->first;
5237 double current_value = it->second;
5241 for(++it;it!=matrix_data_list[m][i_global].end();++it)
5246 if((it->first == current_index) &&
5249 current_value += it->second;
5256 column_or_row_index[m][entry_count] = current_index;
5258 value[m][entry_count] = current_value;
5264 current_index = it->first;
5265 current_value = it->second;
5281 if((static_cast<int>(entry_count) == row_or_column_start[m][i_global])
5285 ||(static_cast<int>(current_index) !=
5286 column_or_row_index[m][entry_count-1]))
5289 column_or_row_index[m][entry_count] = current_index;
5291 value[m][entry_count] = current_value;
5299 row_or_column_start[m][
ndof] = entry_count;
5304 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
5305 pause(
"Check memory usage now.");
5334 bool compressed_row_flag)
5340 unsigned long el_lo=0;
5341 unsigned long el_hi=n_elements-1;
5343 #ifdef OOMPH_HAS_MPI 5361 const unsigned n_vector = residuals.size();
5364 const unsigned n_matrix = column_or_row_index.size();
5369 #ifdef OOMPH_HAS_MPI 5370 bool doing_residuals=
false;
5373 doing_residuals=
true;
5379 if(row_or_column_start.size() != n_matrix)
5381 std::ostringstream error_stream;
5383 <<
"Error: " << std::endl
5384 <<
"row_or_column_start.size() " << row_or_column_start.size()
5385 <<
" does not equal " 5386 <<
"column_or_row_index.size() " 5387 << column_or_row_index.size() << std::endl;
5390 OOMPH_CURRENT_FUNCTION,
5391 OOMPH_EXCEPTION_LOCATION);
5394 if(value.size() != n_matrix)
5396 std::ostringstream error_stream;
5400 <<
"value.size() " << value.size() <<
" does not equal " 5401 <<
"column_or_row_index.size() " 5402 << column_or_row_index.size() << std::endl<< std::endl
5406 OOMPH_CURRENT_FUNCTION,
5407 OOMPH_EXCEPTION_LOCATION);
5423 for(
unsigned m=0;m<n_matrix;m++) {matrix_data[m].resize(ndof);}
5426 for(
unsigned v=0;v<n_vector;v++)
5428 residuals[v] =
new double[
ndof];
5429 for (
unsigned i = 0;
i <
ndof;
i++)
5431 residuals[v][
i] = 0;
5435 #ifdef OOMPH_HAS_MPI 5438 double t_assemble_start=0.0;
5441 if ((!doing_residuals)&&
5459 for(
unsigned long e=el_lo;
e<=el_hi;
e++)
5462 #ifdef OOMPH_HAS_MPI 5464 if ((!doing_residuals)&&
5474 #ifdef OOMPH_HAS_MPI 5481 const unsigned nvar = assembly_handler_pt->
ndof(elem_pt);
5484 for(
unsigned v=0;v<n_vector;v++) {el_residuals[v].resize(nvar);}
5485 for(
unsigned m=0;m<n_matrix;m++) {el_jacobian[m].resize(nvar);}
5488 assembly_handler_pt->
5489 get_all_vectors_and_matrices(elem_pt,el_residuals, el_jacobian);
5494 for(
unsigned i=0;
i<nvar;
i++)
5502 for(
unsigned v=0;v<n_vector;v++)
5505 residuals[v][eqn_number] += el_residuals[v][
i];
5509 for(
unsigned j=0;j<nvar;j++)
5512 unsigned unknown = assembly_handler_pt->
eqn_number(elem_pt,j);
5517 for(
unsigned m=0;m<n_matrix;m++)
5520 double value = el_jacobian[m](
i,j);
5526 if(compressed_row_flag)
5529 const unsigned size = matrix_data[m][eqn_number].size();
5530 for(
unsigned k=0; k<=size; k++)
5534 matrix_data[m][eqn_number].push_back(
5535 std::make_pair(unknown,value));
5538 else if(matrix_data[m][eqn_number][k].first == unknown)
5540 matrix_data[m][eqn_number][k].second += value;
5550 const unsigned size = matrix_data[m][unknown].size();
5551 for(
unsigned k=0; k<=size; k++)
5555 matrix_data[m][unknown].push_back(
5556 std::make_pair(eqn_number,value));
5559 else if(matrix_data[m][unknown][k].first == eqn_number)
5561 matrix_data[m][unknown][k].second += value;
5571 #ifdef OOMPH_HAS_MPI 5576 #ifdef OOMPH_HAS_MPI 5578 if ((!doing_residuals)&&
5592 #ifdef OOMPH_HAS_MPI 5596 if ((!doing_residuals)&&
5606 if ((!doing_residuals)&&
5619 for(
unsigned m=0;m<n_matrix;m++)
5622 row_or_column_start[m] =
new int[ndof+1];
5625 row_or_column_start[m][0] = 0;
5626 for(
unsigned long i=0;
i<
ndof;
i++)
5628 row_or_column_start[m][
i+1] = row_or_column_start[m][
i]
5629 + matrix_data[m][
i].size();
5631 const unsigned entries = row_or_column_start[m][
ndof];
5634 column_or_row_index[m] =
new int[entries];
5635 value[m] =
new double[entries];
5639 for(
unsigned long i_global=0;i_global<
ndof;i_global++)
5642 if(matrix_data[m][i_global].empty()) {
continue;}
5647 for(
int j=row_or_column_start[m][i_global];
5648 j<row_or_column_start[m][i_global+1]; j++)
5650 column_or_row_index[m][j] = matrix_data[m][i_global][p].first;
5651 value[m][j] = matrix_data[m][i_global][p].second;
5659 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
5660 pause(
"Check memory usage now.");
5693 bool compressed_row_flag)
5699 unsigned long el_lo=0;
5700 unsigned long el_hi=n_elements-1;
5703 #ifdef OOMPH_HAS_MPI 5721 const unsigned n_vector = residuals.size();
5724 const unsigned n_matrix = column_or_row_index.size();
5729 #ifdef OOMPH_HAS_MPI 5730 bool doing_residuals=
false;
5733 doing_residuals=
true;
5739 if(row_or_column_start.size() != n_matrix)
5741 std::ostringstream error_stream;
5743 <<
"Error: " << std::endl
5744 <<
"row_or_column_start.size() " << row_or_column_start.size()
5745 <<
" does not equal " 5746 <<
"column_or_row_index.size() " 5747 << column_or_row_index.size() << std::endl;
5750 OOMPH_CURRENT_FUNCTION,
5751 OOMPH_EXCEPTION_LOCATION);
5754 if(value.size() != n_matrix)
5756 std::ostringstream error_stream;
5760 <<
"value.size() " << value.size() <<
" does not equal " 5761 <<
"column_or_row_index.size() " 5762 << column_or_row_index.size() << std::endl<< std::endl
5766 OOMPH_CURRENT_FUNCTION,
5767 OOMPH_EXCEPTION_LOCATION);
5785 for(
unsigned m=0;m<n_matrix;m++)
5787 matrix_row_or_col_indices[m].resize(ndof);
5788 matrix_values[m].resize(ndof);
5792 for(
unsigned v=0;v<n_vector;v++)
5794 residuals[v] =
new double[
ndof];
5795 for (
unsigned i = 0;
i <
ndof;
i++)
5797 residuals[v][
i] = 0;
5801 #ifdef OOMPH_HAS_MPI 5804 double t_assemble_start=0.0;
5807 if ((!doing_residuals)&&
5826 for(
unsigned long e=el_lo;
e<=el_hi;
e++)
5829 #ifdef OOMPH_HAS_MPI 5831 if ((!doing_residuals)&&
5841 #ifdef OOMPH_HAS_MPI 5848 const unsigned nvar = assembly_handler_pt->
ndof(elem_pt);
5851 for(
unsigned v=0;v<n_vector;v++) {el_residuals[v].resize(nvar);}
5852 for(
unsigned m=0;m<n_matrix;m++) {el_jacobian[m].resize(nvar);}
5855 assembly_handler_pt->
5856 get_all_vectors_and_matrices(elem_pt,el_residuals, el_jacobian);
5861 for(
unsigned i=0;
i<nvar;
i++)
5868 for(
unsigned v=0;v<n_vector;v++)
5871 residuals[v][eqn_number] += el_residuals[v][
i];
5875 for(
unsigned j=0;j<nvar;j++)
5878 unsigned unknown = assembly_handler_pt->
eqn_number(elem_pt,j);
5883 for(
unsigned m=0;m<n_matrix;m++)
5886 double value = el_jacobian[m](
i,j);
5892 if(compressed_row_flag)
5895 const unsigned size =
5896 matrix_row_or_col_indices[m][eqn_number].size();
5898 for(
unsigned k=0; k<=size; k++)
5902 matrix_row_or_col_indices[m][eqn_number].
5904 matrix_values[m][eqn_number].push_back(value);
5907 else if(matrix_row_or_col_indices[m][eqn_number][k] ==
5910 matrix_values[m][eqn_number][k] += value;
5920 const unsigned size =
5921 matrix_row_or_col_indices[m][unknown].size();
5922 for (
unsigned k=0; k<=size; k++)
5926 matrix_row_or_col_indices[m][unknown].
5927 push_back(eqn_number);
5928 matrix_values[m][unknown].push_back(value);
5931 else if (matrix_row_or_col_indices[m][unknown][k] ==
5934 matrix_values[m][unknown][k] += value;
5944 #ifdef OOMPH_HAS_MPI 5949 #ifdef OOMPH_HAS_MPI 5951 if ((!doing_residuals)&&
5964 #ifdef OOMPH_HAS_MPI 5968 if ((!doing_residuals)&&
5978 if ((!doing_residuals)&&
5990 for(
unsigned m=0;m<n_matrix;m++)
5993 row_or_column_start[m] =
new int[ndof+1];
5996 row_or_column_start[m][0] = 0;
5997 for (
unsigned long i=0;
i<
ndof;
i++)
5999 row_or_column_start[m][
i+1] = row_or_column_start[m][
i]
6000 + matrix_values[m][
i].size();
6002 const unsigned entries = row_or_column_start[m][
ndof];
6005 column_or_row_index[m] =
new int[entries];
6006 value[m] =
new double[entries];
6010 for(
unsigned long i_global=0;i_global<
ndof;i_global++)
6013 if(matrix_values[m][i_global].empty()) {
continue;}
6018 for(
int j=row_or_column_start[m][i_global];
6019 j<row_or_column_start[m][i_global+1]; j++)
6021 column_or_row_index[m][j] = matrix_row_or_col_indices[m][i_global][p];
6022 value[m][j] = matrix_values[m][i_global][p];
6030 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
6031 pause(
"Check memory usage now.");
6059 bool compressed_row_flag)
6066 unsigned long el_lo=0;
6067 unsigned long el_hi=n_elements-1;
6070 #ifdef OOMPH_HAS_MPI 6088 const unsigned n_vector = residuals.size();
6091 const unsigned n_matrix = column_or_row_index.size();
6096 #ifdef OOMPH_HAS_MPI 6097 bool doing_residuals=
false;
6100 doing_residuals=
true;
6106 if(row_or_column_start.size() != n_matrix)
6108 std::ostringstream error_stream;
6110 <<
"Error: " << std::endl
6111 <<
"row_or_column_start.size() " << row_or_column_start.size()
6112 <<
" does not equal " 6113 <<
"column_or_row_index.size() " 6114 << column_or_row_index.size() << std::endl;
6117 OOMPH_CURRENT_FUNCTION,
6118 OOMPH_EXCEPTION_LOCATION);
6121 if(value.size() != n_matrix)
6123 std::ostringstream error_stream;
6127 <<
"value.size() " << value.size() <<
" does not equal " 6128 <<
"column_or_row_index.size() " 6129 << column_or_row_index.size() << std::endl<< std::endl
6133 OOMPH_CURRENT_FUNCTION,
6134 OOMPH_EXCEPTION_LOCATION);
6152 for(
unsigned m=0;m<n_matrix;m++)
6154 matrix_row_or_col_indices[m] =
new unsigned*[
ndof];
6155 matrix_values[m] =
new double*[
ndof];
6159 for(
unsigned v=0;v<n_vector;v++)
6161 residuals[v] =
new double[
ndof];
6162 for (
unsigned i = 0;
i <
ndof;
i++)
6164 residuals[v][
i] = 0;
6168 #ifdef OOMPH_HAS_MPI 6171 double t_assemble_start=0.0;
6174 if ((!doing_residuals)&&
6184 for (
unsigned m = 0; m < n_matrix; m++)
6186 ncoef[m].resize(ndof,0);
6192 for (
unsigned m = 0; m < n_matrix; m++)
6208 for(
unsigned long e=el_lo;
e<=el_hi;
e++)
6211 #ifdef OOMPH_HAS_MPI 6213 if ((!doing_residuals)&&
6223 #ifdef OOMPH_HAS_MPI 6230 const unsigned nvar = assembly_handler_pt->
ndof(elem_pt);
6233 for(
unsigned v=0;v<n_vector;v++) {el_residuals[v].resize(nvar);}
6234 for(
unsigned m=0;m<n_matrix;m++) {el_jacobian[m].resize(nvar);}
6237 assembly_handler_pt->
6238 get_all_vectors_and_matrices(elem_pt,el_residuals, el_jacobian);
6243 for(
unsigned i=0;
i<nvar;
i++)
6250 for(
unsigned v=0;v<n_vector;v++)
6253 residuals[v][eqn_number] += el_residuals[v][
i];
6257 for(
unsigned j=0;j<nvar;j++)
6260 unsigned unknown = assembly_handler_pt->
eqn_number(elem_pt,j);
6265 for(
unsigned m=0;m<n_matrix;m++)
6268 double value = el_jacobian[m](
i,j);
6273 const unsigned size = ncoef[m][eqn_number];
6280 [m][eqn_number] != 0)
6282 matrix_row_or_col_indices[m][eqn_number] =
6286 matrix_values[m][eqn_number] =
6288 [Sparse_assemble_with_arrays_previous_allocation[m]
6293 matrix_row_or_col_indices[m][eqn_number] =
6296 matrix_values[m][eqn_number] =
6307 if(compressed_row_flag)
6310 for(
unsigned k=0; k<=size; k++)
6316 [m][eqn_number] == ncoef[m][eqn_number])
6318 unsigned new_allocation = ncoef[m][eqn_number]+
6320 double* new_values =
new double[new_allocation];
6321 unsigned* new_indices =
new unsigned[new_allocation];
6322 for (
unsigned c = 0; c < ncoef[m][eqn_number]; c++)
6324 new_values[c] = matrix_values[m][eqn_number][c];
6326 matrix_row_or_col_indices[m][eqn_number][c];
6328 delete[] matrix_values[m][eqn_number];
6329 delete[] matrix_row_or_col_indices[m][eqn_number];
6330 matrix_values[m][eqn_number]=new_values;
6331 matrix_row_or_col_indices[m][eqn_number]=new_indices;
6333 [m][eqn_number] = new_allocation;
6336 unsigned entry = ncoef[m][eqn_number];
6337 ncoef[m][eqn_number]++;
6338 matrix_row_or_col_indices[m][eqn_number][entry] = unknown;
6339 matrix_values[m][eqn_number][entry] = value;
6342 else if(matrix_row_or_col_indices[m][eqn_number][k] ==
6345 matrix_values[m][eqn_number][k] += value;
6355 for(
unsigned k=0; k<=size; k++)
6361 [m][unknown] == ncoef[m][unknown])
6363 unsigned new_allocation = ncoef[m][unknown]+
6365 double* new_values =
new double[new_allocation];
6366 unsigned* new_indices =
new unsigned[new_allocation];
6367 for (
unsigned c = 0; c < ncoef[m][unknown]; c++)
6369 new_values[c] = matrix_values[m][unknown][c];
6371 matrix_row_or_col_indices[m][unknown][c];
6373 delete[] matrix_values[m][unknown];
6374 delete[] matrix_row_or_col_indices[m][unknown];
6376 [m][unknown] = new_allocation;
6379 unsigned entry = ncoef[m][unknown];
6380 ncoef[m][unknown]++;
6381 matrix_row_or_col_indices[m][unknown][entry] = eqn_number;
6382 matrix_values[m][unknown][entry] = value;
6385 else if(matrix_row_or_col_indices[m][unknown][k] ==
6388 matrix_values[m][unknown][k] += value;
6398 #ifdef OOMPH_HAS_MPI 6403 #ifdef OOMPH_HAS_MPI 6405 if ((!doing_residuals)&&
6418 #ifdef OOMPH_HAS_MPI 6422 if ((!doing_residuals)&&
6432 if ((!doing_residuals)&&
6444 for(
unsigned m=0;m<n_matrix;m++)
6447 row_or_column_start[m] =
new int[ndof+1];
6450 row_or_column_start[m][0] = 0;
6451 for (
unsigned long i=0;
i<
ndof;
i++)
6453 row_or_column_start[m][
i+1] = row_or_column_start[m][
i]
6457 const unsigned entries = row_or_column_start[m][
ndof];
6460 column_or_row_index[m] =
new int[entries];
6461 value[m] =
new double[entries];
6465 for(
unsigned long i_global=0;i_global<
ndof;i_global++)
6468 if(ncoef[m][i_global]==0) {
continue;}
6473 for(
int j=row_or_column_start[m][i_global];
6474 j<row_or_column_start[m][i_global+1]; j++)
6476 column_or_row_index[m][j] = matrix_row_or_col_indices[m][i_global][p];
6477 value[m][j] = matrix_values[m][i_global][p];
6482 delete[] matrix_row_or_col_indices[m][i_global];
6483 delete[] matrix_values[m][i_global];
6487 delete[] matrix_row_or_col_indices[m];
6488 delete[] matrix_values[m];
6493 oomph_info <<
"Pausing at end of sparse assembly." << std::endl;
6494 pause(
"Check memory usage now.");
6499 #ifdef OOMPH_HAS_MPI 6506 const unsigned &el_lo,
const unsigned &el_hi,
6510 unsigned my_eqns_index=0;
6513 for(
unsigned long e=el_lo;
e<=el_hi;
e++)
6522 const unsigned nvar = assembly_handler_pt->
ndof(elem_pt);
6524 my_eqns.resize(my_eqns_index+nvar);
6527 for(
unsigned i=0;
i<nvar;
i++)
6530 unsigned global_eqn_number
6533 my_eqns[my_eqns_index+
i] = global_eqn_number;
6536 my_eqns_index += nvar;
6541 std::sort(my_eqns.begin(),my_eqns.end());
6543 my_eqns.resize(it-my_eqns.begin());
6577 std::ostringstream error_stream;
6579 <<
"Processsor " << my_rank
6580 <<
" has no elements. \n" 6581 <<
"This is usually a sign that the problem distribution \n" 6582 <<
"or the load balancing have gone wrong.";
6585 "Problem::parallel_sparse_assemble()",
6586 OOMPH_EXCEPTION_LOCATION);
6592 unsigned long el_lo=0;
6593 unsigned long el_hi_plus_one=n_elements;
6608 const unsigned n_vector = residuals.size();
6611 const unsigned n_matrix = column_indices.size();
6616 bool doing_residuals=
false;
6619 doing_residuals=
true;
6624 if(row_start.size() != n_matrix)
6626 std::ostringstream error_stream;
6628 <<
"Error: " << std::endl
6629 <<
"row_or_column_start.size() " << row_start.size()
6630 <<
" does not equal " 6631 <<
"column_or_row_index.size() " 6632 << column_indices.size() << std::endl;
6635 OOMPH_CURRENT_FUNCTION,
6636 OOMPH_EXCEPTION_LOCATION);
6639 if(values.size() != n_matrix)
6641 std::ostringstream error_stream;
6645 <<
"value.size() " << values.size() <<
" does not equal " 6646 <<
"column_or_row_index.size() " 6647 << column_indices.size() << std::endl<< std::endl
6651 OOMPH_CURRENT_FUNCTION,
6652 OOMPH_EXCEPTION_LOCATION);
6666 this->
get_my_eqns(assembly_handler_pt,el_lo,el_hi_plus_one-1,my_eqns);
6670 unsigned my_n_eqn = my_eqns.size();
6686 for(
unsigned m=0;m<n_matrix;m++)
6688 matrix_col_indices[m] =
new unsigned*[my_n_eqn];
6689 matrix_values[m] =
new double*[my_n_eqn];
6690 for (
unsigned i = 0;
i < my_n_eqn;
i++)
6692 matrix_col_indices[m][
i]=0;
6693 matrix_values[m][
i]=0;
6699 for(
unsigned v=0;v<n_vector;v++)
6701 residuals_data[v] =
new double[my_n_eqn];
6702 for (
unsigned i = 0;
i < my_n_eqn;
i++)
6704 residuals_data[v][
i] = 0;
6709 double t_assemble_start=0.0;
6712 if ((!doing_residuals)&&
6720 for (
unsigned m = 0; m < n_matrix; m++)
6722 ncoef[m].resize(my_n_eqn,0);
6732 for (
unsigned m = 0; m < n_matrix; m++)
6749 for(
unsigned long e=el_lo;
e<el_hi_plus_one;
e++)
6752 if ((!doing_residuals)&&
6766 const unsigned nvar = assembly_handler_pt->
ndof(elem_pt);
6769 for(
unsigned v=0;v<n_vector;v++) {el_residuals[v].resize(nvar);}
6770 for(
unsigned m=0;m<n_matrix;m++) {el_jacobian[m].resize(nvar);}
6773 assembly_handler_pt->
6774 get_all_vectors_and_matrices(elem_pt,el_residuals, el_jacobian);
6779 for(
unsigned i=0;
i<nvar;
i++)
6782 unsigned global_eqn_number
6788 int right = my_n_eqn-1;
6789 int eqn_number = right/2;
6790 while (my_eqns[eqn_number] != global_eqn_number)
6797 for(
unsigned v=0;v<n_vector;v++)
6799 if (el_residuals[v][
i]!=0.0)
6808 for(
unsigned j=0;j<nvar;j++)
6816 for(
unsigned m=0;m<n_matrix;m++)
6819 double value = el_jacobian[m](
i,j);
6831 std::ostringstream error_stream;
6833 <<
"Internal Error: " 6835 <<
"Could not find global equation number " 6836 << global_eqn_number
6837 <<
" in my_eqns vector of equation numbers but\n" 6838 <<
"at least one entry in the residual vector is nonzero.";
6841 OOMPH_CURRENT_FUNCTION,
6842 OOMPH_EXCEPTION_LOCATION);
6849 if (my_eqns[eqn_number] > global_eqn_number)
6851 right = std::max(eqn_number-1,left);
6855 left = std::min(eqn_number+1,right);
6857 eqn_number = (right+left)/2;
6861 for(
unsigned v=0;v<n_vector;v++)
6864 residuals_data[v][eqn_number] += el_residuals[v][
i];
6868 for(
unsigned j=0;j<nvar;j++)
6871 unsigned unknown = assembly_handler_pt->
eqn_number(elem_pt,j);
6876 for(
unsigned m=0;m<n_matrix;m++)
6879 double value = el_jacobian[m](
i,j);
6884 const unsigned size = ncoef[m][eqn_number];
6891 [m][eqn_number] != 0)
6893 matrix_col_indices[m][eqn_number] =
6898 matrix_values[m][eqn_number] =
6900 [Sparse_assemble_with_arrays_previous_allocation[m]
6905 matrix_col_indices[m][eqn_number] =
6909 matrix_values[m][eqn_number] =
6920 for(
unsigned k=0; k<=size; k++)
6926 [m][eqn_number] == ncoef[m][eqn_number])
6928 unsigned new_allocation = ncoef[m][eqn_number]+
6930 double* new_values =
new double[new_allocation];
6931 unsigned* new_indices =
new unsigned[new_allocation];
6932 for (
unsigned c = 0; c < ncoef[m][eqn_number]; c++)
6934 new_values[c] = matrix_values[m][eqn_number][c];
6935 new_indices[c] = matrix_col_indices[m][eqn_number][c];
6937 delete[] matrix_values[m][eqn_number];
6938 delete[] matrix_col_indices[m][eqn_number];
6940 matrix_values[m][eqn_number] = new_values;
6941 matrix_col_indices[m][eqn_number] = new_indices;
6944 [m][eqn_number] = new_allocation;
6947 unsigned entry = ncoef[m][eqn_number];
6948 ncoef[m][eqn_number]++;
6949 matrix_col_indices[m][eqn_number][entry] = unknown;
6950 matrix_values[m][eqn_number][entry] = value;
6953 else if(matrix_col_indices[m][eqn_number][k] == unknown)
6955 matrix_values[m][eqn_number][k] += value;
6966 if ((!doing_residuals)&&
6984 t_local=t_end-t_start;
6988 MPI_Allreduce(&t_local,&t_max,1,
6991 MPI_Allreduce(&t_local,&t_min,1,
6994 MPI_Allreduce(&t_local,&t_sum,1,
6997 double imbalance=(t_max-t_min)/(t_sum/
double(nproc))*100.0;
6999 if (doing_residuals)
7002 <<
"\nCPU for residual computation (loc/max/min/imbal): ";
7007 <<
"\nCPU for Jacobian computation (loc/max/min/imbal): ";
7013 << imbalance <<
"%\n";
7020 for (
unsigned m = 0; m < n_matrix; m++)
7023 unsigned min=INT_MAX;
7025 unsigned sum_total=0;
7026 for (
unsigned e = 0;
e < my_n_eqn;
e++)
7030 if (ncoef[m][
e]>max) max=ncoef[m][
e];
7031 if (ncoef[m][
e]<min) min=ncoef[m][
e];
7034 unsigned new_allocation = ncoef[m][
e];
7035 double* new_values =
new double[new_allocation];
7036 unsigned* new_indices =
new unsigned[new_allocation];
7037 for (
unsigned c = 0; c < ncoef[m][
e]; c++)
7039 new_values[c] = matrix_values[m][
e][c];
7040 new_indices[c] = matrix_col_indices[m][
e][c];
7042 delete[] matrix_values[m][
e];
7043 delete[] matrix_col_indices[m][
e];
7045 matrix_values[m][
e] = new_values;
7046 matrix_col_indices[m][
e] = new_indices;
7054 if ((!doing_residuals)&&
7064 if ((!doing_residuals)&&
7082 first_eqn_element_for_proc[current_p] = 0;
7083 n_eqn_for_proc[current_p] = 1;
7084 for (
unsigned i = 1;
i < my_n_eqn;
i++)
7087 if (next_p != current_p)
7090 first_eqn_element_for_proc[current_p] =
i;
7092 n_eqn_for_proc[current_p]++;
7099 for (
unsigned p = 0; p < nproc; p++)
7101 int first_eqn_element = first_eqn_element_for_proc[p];
7102 int last_eqn_element = (int)(first_eqn_element + n_eqn_for_proc[p]) - 1;
7103 for (
unsigned m = 0; m < n_matrix; m++)
7105 for (
int i = first_eqn_element;
i <= last_eqn_element;
i++)
7107 nnz_for_proc(p,m) += ncoef[m][
i];
7117 for (
unsigned p = 0; p < nproc; p++)
7121 temp_send_storage[p] =
new unsigned[n_matrix+1];
7122 temp_send_storage[p][0] = n_eqn_for_proc[p];
7123 for (
unsigned m = 0; m < n_matrix; m++)
7125 temp_send_storage[p][m+1] = nnz_for_proc(p,m);
7128 MPI_Isend(temp_send_storage[p],n_matrix+1,MPI_UNSIGNED,p,0,
7130 send_nnz_reqs.push_back(sreq);
7131 temp_recv_storage[p] =
new unsigned[n_matrix+1];
7133 MPI_Irecv(temp_recv_storage[p],n_matrix+1,MPI_UNSIGNED,p,0,
7135 recv_nnz_reqs.push_back(rreq);
7150 for (
unsigned p = 0; p < nproc; p++)
7152 unsigned n_eqns_p = n_eqn_for_proc[p];
7155 unsigned first_eqn_element = first_eqn_element_for_proc[p];
7156 unsigned first_row = target_dist_pt->
first_row(p);
7157 eqns_for_proc[p] =
new unsigned[n_eqns_p];
7158 for (
unsigned i = 0;
i < n_eqns_p;
i++)
7160 eqns_for_proc[p][
i] = my_eqns[
i+first_eqn_element]-first_row;
7166 for (
unsigned v = 0; v < n_vector; v++)
7168 for (
unsigned p = 0; p < nproc; p++)
7170 unsigned n_eqns_p = n_eqn_for_proc[p];
7173 unsigned first_eqn_element = first_eqn_element_for_proc[p];
7174 residuals_for_proc(p,v) =
new double[n_eqns_p];
7175 for (
unsigned i = 0;
i < n_eqns_p;
i++)
7177 residuals_for_proc(p,v)[
i] = residuals_data[v][first_eqn_element+
i];
7181 delete[] residuals_data[v];
7185 for (
unsigned m = 0; m < n_matrix; m++)
7187 for (
unsigned p = 0; p < nproc; p++)
7189 unsigned n_eqns_p = n_eqn_for_proc[p];
7192 unsigned first_eqn_element = first_eqn_element_for_proc[p];
7193 row_start_for_proc(p,m) =
new unsigned[n_eqns_p+1];
7194 column_indices_for_proc(p,m) =
new unsigned[nnz_for_proc(p,m)];
7195 values_for_proc(p,m) =
new double[nnz_for_proc(p,m)];
7197 for (
unsigned i = 0;
i < n_eqns_p;
i++)
7199 row_start_for_proc(p,m)[
i] = entry;
7200 unsigned n_coef_in_row = ncoef[m][first_eqn_element+
i];
7201 for (
unsigned j = 0; j < n_coef_in_row; j++)
7203 column_indices_for_proc(p,m)[entry]
7204 = matrix_col_indices[m][
i+first_eqn_element][j];
7205 values_for_proc(p,m)[entry]
7206 = matrix_values[m][
i+first_eqn_element][j];
7210 row_start_for_proc(p,m)[n_eqns_p]=entry;
7213 for (
unsigned i = 0;
i < my_n_eqn;
i++)
7215 delete[] matrix_col_indices[m][
i];
7216 delete[] matrix_values[m][
i];
7218 delete[] matrix_col_indices[m];
7219 delete[] matrix_values[m];
7230 MPI_Waitall(nproc-1,&recv_nnz_reqs[0],&recv_nnz_stat[0]);
7233 for (
unsigned p = 0; p < nproc; p++)
7237 n_eqn_from_proc[p] = temp_recv_storage[p][0];
7238 for (
unsigned m = 0; m < n_matrix; m++)
7240 nnz_from_proc(p,m) = temp_recv_storage[p][m+1];
7242 delete[] temp_recv_storage[p];
7246 n_eqn_from_proc[p] = n_eqn_for_proc[p];
7247 for (
unsigned m = 0; m < n_matrix; m++)
7249 nnz_from_proc(p,m) = nnz_for_proc(p,m);
7253 recv_nnz_stat.clear();
7254 recv_nnz_reqs.clear();
7268 MPI_Aint communication_base;
7269 MPI_Get_address(&base,&communication_base);
7270 unsigned n_comm_types = 1 + 1*n_vector + 3*n_matrix;
7273 for (
unsigned p = 0; p < nproc; p++)
7279 if (n_eqn_from_proc[p] > 0)
7281 eqns_from_proc[p] =
new unsigned[n_eqn_from_proc[p]];
7282 for (
unsigned v = 0; v < n_vector; v++)
7284 residuals_from_proc(p,v) =
new double[n_eqn_from_proc[p]];
7286 for (
unsigned m = 0; m < n_matrix; m++)
7288 row_start_from_proc(p,m) =
new unsigned[n_eqn_from_proc[p]+1];
7289 column_indices_from_proc(p,m) =
new unsigned[nnz_from_proc(p,m)];
7290 values_from_proc(p,m) =
new double[nnz_from_proc(p,m)];
7295 if (n_eqn_from_proc[p] > 0)
7297 MPI_Datatype types[n_comm_types];
7298 MPI_Aint offsets[n_comm_types];
7299 int count[n_comm_types];
7304 MPI_Get_address(eqns_from_proc[p],&offsets[pt]);
7305 offsets[pt] -= communication_base;
7306 MPI_Type_contiguous(n_eqn_from_proc[p],MPI_UNSIGNED,&types[pt]);
7307 MPI_Type_commit(&types[pt]);
7311 for (
unsigned v = 0; v < n_vector; v++)
7314 MPI_Get_address(residuals_from_proc(p,v),&offsets[pt]);
7315 offsets[pt] -= communication_base;
7316 MPI_Type_contiguous(n_eqn_from_proc[p],MPI_DOUBLE,&types[pt]);
7317 MPI_Type_commit(&types[pt]);
7322 for (
unsigned m = 0; m < n_matrix; m++)
7326 MPI_Get_address(row_start_from_proc(p,m),&offsets[pt]);
7327 offsets[pt] -= communication_base;
7328 MPI_Type_contiguous(n_eqn_from_proc[p]+1,MPI_UNSIGNED,&types[pt]);
7329 MPI_Type_commit(&types[pt]);
7335 MPI_Get_address(column_indices_from_proc(p,m),&offsets[pt]);
7336 offsets[pt] -= communication_base;
7337 MPI_Type_contiguous(nnz_from_proc(p,m),MPI_UNSIGNED,&types[pt]);
7338 MPI_Type_commit(&types[pt]);
7343 MPI_Get_address(values_from_proc(p,m),&offsets[pt]);
7344 offsets[pt] -= communication_base;
7345 MPI_Type_contiguous(nnz_from_proc(p,m),MPI_DOUBLE,&types[pt]);
7346 MPI_Type_commit(&types[pt]);
7351 MPI_Datatype recv_type;
7352 MPI_Type_create_struct(n_comm_types,count,offsets,types,&recv_type);
7353 MPI_Type_commit(&recv_type);
7354 for (
unsigned t = 0;
t < n_comm_types;
t++)
7356 MPI_Type_free(&types[
t]);
7359 MPI_Irecv(&base,1,recv_type,p,1,
7361 MPI_Type_free(&recv_type);
7362 recv_reqs.push_back(req);
7366 if (n_eqn_for_proc[p] > 0)
7368 MPI_Datatype types[n_comm_types];
7369 MPI_Aint offsets[n_comm_types];
7370 int count[n_comm_types];
7375 MPI_Get_address(eqns_for_proc[p],&offsets[pt]);
7376 offsets[pt] -= communication_base;
7377 MPI_Type_contiguous(n_eqn_for_proc[p],MPI_UNSIGNED,&types[pt]);
7378 MPI_Type_commit(&types[pt]);
7382 for (
unsigned v = 0; v < n_vector; v++)
7385 MPI_Get_address(residuals_for_proc(p,v),&offsets[pt]);
7386 offsets[pt] -= communication_base;
7387 MPI_Type_contiguous(n_eqn_for_proc[p],MPI_DOUBLE,&types[pt]);
7388 MPI_Type_commit(&types[pt]);
7393 for (
unsigned m = 0; m < n_matrix; m++)
7397 MPI_Get_address(row_start_for_proc(p,m),&offsets[pt]);
7398 offsets[pt] -= communication_base;
7399 MPI_Type_contiguous(n_eqn_for_proc[p]+1,MPI_UNSIGNED,&types[pt]);
7400 MPI_Type_commit(&types[pt]);
7406 MPI_Get_address(column_indices_for_proc(p,m),&offsets[pt]);
7407 offsets[pt] -= communication_base;
7408 MPI_Type_contiguous(nnz_for_proc(p,m),MPI_UNSIGNED,&types[pt]);
7409 MPI_Type_commit(&types[pt]);
7414 MPI_Get_address(values_for_proc(p,m),&offsets[pt]);
7415 offsets[pt] -= communication_base;
7416 MPI_Type_contiguous(nnz_for_proc(p,m),MPI_DOUBLE,&types[pt]);
7417 MPI_Type_commit(&types[pt]);
7422 MPI_Datatype send_type;
7423 MPI_Type_create_struct(n_comm_types,count,offsets,types,&send_type);
7424 MPI_Type_commit(&send_type);
7425 for (
unsigned t = 0;
t < n_comm_types;
t++)
7427 MPI_Type_free(&types[
t]);
7430 MPI_Isend(&base,1,send_type,p,1,
7432 MPI_Type_free(&send_type);
7433 send_reqs.push_back(req);
7439 eqns_from_proc[p] = eqns_for_proc[p];
7440 for (
unsigned v = 0; v < n_vector; v++)
7442 residuals_from_proc(p,v) = residuals_for_proc(p,v);
7444 for (
unsigned m = 0; m < n_matrix; m++)
7446 row_start_from_proc(p,m) = row_start_for_proc(p,m);
7447 column_indices_from_proc(p,m) = column_indices_for_proc(p,m);
7448 values_from_proc(p,m) = values_for_proc(p,m);
7454 unsigned n_recv_req = recv_reqs.size();
7458 MPI_Waitall(n_recv_req,&recv_reqs[0],&recv_stat[0]);
7462 unsigned target_nrow_local = target_dist_pt->
nrow_local();
7465 for (
unsigned m = 0; m < n_matrix; m++)
7469 row_start[m] =
new int[target_nrow_local+1];
7470 row_start[m][0] = 0;
7475 for (
unsigned p = 0; p < nproc; p++)
7477 nnz_allocation = std::max(nnz_allocation,nnz_from_proc(p,m));
7480 values_chunk[0] =
new double[nnz_allocation];
7482 column_indices_chunk[0] =
new int[nnz_allocation];
7485 size_of_chunk[0] = nnz_allocation;
7486 unsigned current_chunk = 0;
7489 for (
unsigned i = 0;
i < target_nrow_local;
i++)
7495 for (
unsigned p = 0; p < nproc; p++)
7497 if (n_eqn_from_proc[p]==0)
7504 int right = n_eqn_from_proc[p]-1;
7505 int midpoint = right/2;
7506 bool complete =
false;
7509 midpoint = (right+left)/2;
7510 if (midpoint > right) { midpoint = right; }
7511 if (midpoint < left) { midpoint = left; }
7514 if (eqns_from_proc[p][midpoint] ==
i)
7524 else if (eqns_from_proc[p][midpoint] ==
i)
7528 else if (eqns_from_proc[p][midpoint] >
i)
7530 right = std::max(midpoint-1,left);
7534 left = std::min(midpoint+1,right);
7537 row_on_proc[p] = midpoint;
7542 unsigned check_first = ncoef_in_chunk[current_chunk];
7543 unsigned check_last = check_first;
7544 for (
unsigned p = 0; p < nproc; p++)
7546 if (row_on_proc[p] != -1)
7548 int row = row_on_proc[p];
7549 unsigned first = row_start_from_proc(p,m)[row];
7550 unsigned last = row_start_from_proc(p,m)[row+1];
7551 for (
unsigned l = first; l < last; l++)
7554 for (
unsigned j = check_first; j <=check_last && !done; j++)
7560 if (ncoef_in_chunk[current_chunk] ==
7561 size_of_chunk[current_chunk])
7565 unsigned n_chunk = values_chunk.size();
7569 unsigned nnz_so_far = 0;
7570 for (
unsigned c = 0; c < n_chunk; c++)
7572 nnz_so_far += ncoef_in_chunk[c];
7574 nnz_so_far -= row_start[m][
i];
7577 unsigned avg_nnz = nnz_so_far/(
i+1);
7580 unsigned nrows_left = target_nrow_local-
i;
7583 unsigned next_chunk_size = avg_nnz*nrows_left+row_start[m][
i];
7588 values_chunk.resize(n_chunk);
7589 values_chunk[current_chunk] =
new double[next_chunk_size];
7590 column_indices_chunk.resize(n_chunk);
7591 column_indices_chunk[current_chunk]
7592 =
new int[next_chunk_size];
7593 size_of_chunk.resize(n_chunk);
7594 size_of_chunk[current_chunk] = next_chunk_size;
7595 ncoef_in_chunk.resize(n_chunk);
7598 for (
unsigned k = check_first; k < check_last; k++)
7600 values_chunk[current_chunk][k-check_first] =
7601 values_chunk[current_chunk-1][k];
7602 column_indices_chunk[current_chunk][k-check_first] =
7603 column_indices_chunk[current_chunk-1][k];
7605 ncoef_in_chunk[current_chunk-1]-=row_start[m][
i];
7606 ncoef_in_chunk[current_chunk]=row_start[m][
i];
7610 check_last=row_start[m][
i];
7615 values_chunk[current_chunk][j]=values_from_proc(p,m)[l];
7616 column_indices_chunk[current_chunk][j]
7617 =column_indices_from_proc(p,m)[l];
7618 ncoef_in_chunk[current_chunk]++;
7623 else if (column_indices_chunk[current_chunk][j] ==
7624 (
int)column_indices_from_proc(p,m)[l])
7626 values_chunk[current_chunk][j] += values_from_proc(p,m)[l];
7636 for (
unsigned p = 0; p < nproc; p++)
7638 if (n_eqn_from_proc[p] > 0)
7640 delete[] row_start_from_proc(p,m);
7641 delete[] column_indices_from_proc(p,m);
7642 delete[] values_from_proc(p,m);
7649 unsigned n_chunk = values_chunk.size();
7651 for (
unsigned c = 0; c < n_chunk; c++)
7653 nnz[m]+=ncoef_in_chunk[c];
7658 values[m] =
new double[nnz[m]];
7659 column_indices[m] =
new int[nnz[m]];
7663 for (
unsigned c = 0; c < n_chunk; c++)
7665 unsigned nc = ncoef_in_chunk[c];
7666 for (
unsigned i = 0;
i < nc;
i++)
7668 values[m][pt+
i]=values_chunk[c][
i];
7669 column_indices[m][pt+
i]=column_indices_chunk[c][
i];
7672 delete[] values_chunk[c];
7673 delete[] column_indices_chunk[c];
7679 unsigned g = row_start[m][0];
7680 row_start[m][0] = 0;
7681 for (
unsigned i = 1;
i < target_nrow_local;
i++)
7683 unsigned h = g+row_start[m][
i];
7684 row_start[m][
i] = g;
7687 row_start[m][target_nrow_local]=g;
7691 for (
unsigned v = 0; v < n_vector; v++)
7693 residuals[v] =
new double[target_nrow_local];
7694 for (
unsigned i = 0;
i < target_nrow_local;
i++)
7696 residuals[v][
i] = 0;
7698 for (
unsigned p = 0; p < nproc; p++)
7700 if (n_eqn_from_proc[p] > 0)
7702 unsigned n_eqn_p = n_eqn_from_proc[p];
7703 for (
unsigned i = 0;
i < n_eqn_p;
i++)
7705 residuals[v][eqns_from_proc[p][
i]]+=residuals_from_proc(p,v)[
i];
7707 delete[] residuals_from_proc(p,v);
7713 for (
unsigned p = 0; p < nproc; p++)
7715 if (n_eqn_from_proc[p] > 0)
7717 delete[] eqns_from_proc[p];
7723 MPI_Waitall(nproc-1,&send_nnz_reqs[0],&send_nnz_stat[0]);
7724 for (
unsigned p = 0; p < nproc; p++)
7728 delete[] temp_send_storage[p];
7731 send_nnz_stat.clear();
7732 send_nnz_reqs.clear();
7735 unsigned n_send_reqs = send_reqs.size();
7736 if (n_send_reqs > 0)
7739 MPI_Waitall(n_send_reqs,&send_reqs[0],&send_stat[0]);
7740 for (
unsigned p = 0; p < nproc; p++)
7744 if (n_eqn_for_proc[p])
7746 delete[] eqns_for_proc[p];
7747 for (
unsigned m = 0; m < n_matrix; m++)
7749 delete[] row_start_for_proc(p,m);
7750 delete[] column_indices_for_proc(p,m);
7751 delete[] values_for_proc(p,m);
7753 for (
unsigned v = 0; v < n_vector; v++)
7755 delete[] residuals_for_proc(p,v);
7766 t_local=t_end-t_start;
7770 MPI_Allreduce(&t_local,&t_max,1,
7773 MPI_Allreduce(&t_local,&t_min,1,
7776 MPI_Allreduce(&t_local,&t_sum,1,
7779 double imbalance=(t_max-t_min)/(t_sum/
double(nproc))*100.0;
7780 if (doing_residuals)
7783 <<
"CPU for residual distribut. (loc/max/min/imbal): ";
7788 <<
"CPU for Jacobian distribut. (loc/max/min/imbal): ";
7794 << imbalance <<
"%\n\n";
7809 #ifdef OOMPH_HAS_MPI 7813 OomphLibWarning(
"This is unlikely to work with a distributed problem",
7814 " Problem::get_fd_jacobian()",
7815 OOMPH_EXCEPTION_LOCATION);
7821 const unsigned long n_dof =
ndof();
7832 jacobian.
resize(n_dof,n_dof);
7835 for(
unsigned long jdof=0;jdof<n_dof;jdof++)
7837 double backup=*
Dof_pt[jdof];
7850 for (
unsigned long ieqn=0;ieqn<n_dof;ieqn++)
7852 jacobian(ieqn,jdof)=(residuals_pls[ieqn]-residuals[ieqn])/FD_step;
7881 old_assembly_handler_pt,parameter_pt);
7924 const double FD_step = 1.0e-8;
7927 double param_value = *parameter_pt;
7940 const unsigned ndof_local = result.
nrow_local();
7943 for(
unsigned n=0;n<ndof_local;++n)
7945 result[n] = (newres[n] - result[n])/FD_step;
7949 *parameter_pt = param_value;
7974 const unsigned n_vec = C.size();
7985 for(
unsigned i=0;
i<n_vec;
i++)
7992 #ifdef OOMPH_HAS_MPI 7995 for(
unsigned i=0;
i<n_vec;
i++)
8011 for(
unsigned long e=0;
e<Element_pt_range;
e++)
8016 #ifdef OOMPH_HAS_MPI 8021 unsigned n_var = assembly_handler_pt->
ndof(elem_pt);
8030 for(
unsigned l=0;l<n_var;l++)
8033 const unsigned long eqn_number =
8037 for(
unsigned i=0;
i<n_vec;
i++)
8039 C_local(
i,l) = C[
i].global_value(eqn_number);
8045 C_local,product_local);
8048 for(
unsigned l=0;l<n_var;l++)
8050 const unsigned long eqn_number =
8053 for(
unsigned i=0;
i<n_vec;
i++)
8055 product[
i].global_value(eqn_number) += product_local(
i,l);
8060 #ifdef OOMPH_HAS_MPI 8077 double dof_length=0.0;
8080 for(
unsigned n=0;n<n_dof_local;n++)
8082 if(std::fabs(this->
dof(n)) > dof_length)
8083 {dof_length = std::fabs(this->
dof(n));}
8087 for(
unsigned i=0;
i<n_vec;
i++)
8089 for(
unsigned n=0;n<n_dof_local;n++)
8091 if(std::fabs(C[
i][n]) > C_length[
i]) {C_length[
i] = std::fabs(C[i][n]);}
8096 #ifdef OOMPH_HAS_MPI 8099 const unsigned n_length = n_vec+1;
8100 double all_length[n_length];
8101 all_length[0] = dof_length;
8102 for(
unsigned i=0;
i<n_vec;
i++) {all_length[
i+1] = C_length[
i];}
8105 double all_length_reduce[n_length];
8106 MPI_Allreduce(all_length,all_length_reduce,n_length,MPI_DOUBLE,
8110 dof_length = all_length_reduce[0];
8111 for(
unsigned i=0;
i<n_vec;
i++) {C_length[
i] = all_length_reduce[
i+1];}
8117 for(
unsigned i=0;
i<n_vec;
i++)
8119 C_mult[
i] = dof_length/C_length[
i];
8131 for(
unsigned long e = 0;
e<n_element;
e++)
8135 #ifdef OOMPH_HAS_MPI 8140 unsigned n_var = assembly_handler_pt->
ndof(elem_pt);
8142 dummy_res.resize(n_var);
8146 assembly_handler_pt->
get_jacobian(elem_pt,dummy_res,jac);
8150 for(
unsigned n=0;n<n_var;n++)
8152 unsigned eqn_number = assembly_handler_pt->
eqn_number(elem_pt,n);
8157 for(
unsigned i=0;
i<n_vec;
i++)
8160 for(
unsigned n=0;n<n_var;n++)
8162 unsigned eqn_number = assembly_handler_pt->
eqn_number(elem_pt,n);
8165 C_mult[
i]*C[
i].global_value(eqn_number);
8173 assembly_handler_pt->
get_jacobian(elem_pt,dummy_res,jac_C);
8176 for(
unsigned n=0;n<n_var;n++)
8178 unsigned eqn_number = assembly_handler_pt->
eqn_number(elem_pt,n);
8184 for(
unsigned n=0;n<n_var;n++)
8186 unsigned eqn_number = assembly_handler_pt->
eqn_number(elem_pt,n);
8188 for(
unsigned m=0;m<n_var;m++)
8190 unsigned unknown = assembly_handler_pt->
eqn_number(elem_pt,m);
8191 prod_c += (jac_C(n,m) - jac(n,m))*Y.
global_value(unknown);
8195 product[
i].global_value(eqn_number) += prod_c/C_mult[
i];
8198 #ifdef OOMPH_HAS_MPI 8206 #ifdef OOMPH_HAS_MPI 8210 for(
unsigned i=0;
i<n_vec;
i++)
8212 product[
i].sum_all_halo_and_haloed_values();
8284 Vector<std::complex<double> > &eigenvalue,
8298 std::vector<bool> was_steady(n_time_steppers);
8301 for(
unsigned i=0;
i<n_time_steppers;
i++)
8313 for(
unsigned i=0;
i<n_time_steppers;
i++)
8340 const double &shift)
8354 std::ostringstream error_stream;
8356 <<
"The distributions of the jacobian and mass matrix are\n" 8357 <<
"not the same and they must be.\n";
8359 OOMPH_CURRENT_FUNCTION,
8360 OOMPH_EXCEPTION_LOCATION);
8363 if (mass_matrix.
nrow() != this->
ndof())
8365 std::ostringstream error_stream;
8367 <<
"mass_matrix has a distribution, but the number of rows is not " 8368 <<
"equal to the number of degrees of freedom in the problem.";
8370 OOMPH_CURRENT_FUNCTION,
8371 OOMPH_EXCEPTION_LOCATION);
8374 if (main_matrix.
nrow() != this->
ndof())
8376 std::ostringstream error_stream;
8378 <<
"main_matrix has a distribution, but the number of rows is not " 8379 <<
"equal to the number of degrees of freedom in the problem.";
8381 OOMPH_CURRENT_FUNCTION,
8382 OOMPH_EXCEPTION_LOCATION);
8388 std::ostringstream error_stream;
8389 error_stream <<
"The distribution of the jacobian and mass matrix must " 8390 <<
"both be setup or both not setup";
8392 OOMPH_CURRENT_FUNCTION,
8393 OOMPH_EXCEPTION_LOCATION);
8411 unsigned nrow = this->
ndof();
8424 #ifdef OOMPH_HAS_MPI 8450 bool use_problem_dist =
true;
8452 for (
unsigned p = 0; p < nproc; p++)
8455 ((double)uniform_dist_pt->
nrow_local(p))*1.1)
8457 use_problem_dist =
false;
8460 if (use_problem_dist)
8468 delete uniform_dist_pt;
8479 bool compressed_row_flag=
true;
8481 #ifdef OOMPH_HAS_MPI 8488 row_or_column_start,
8492 compressed_row_flag);
8495 main_matrix.
build(dist_pt);
8497 column_or_row_index[0],
8498 row_or_column_start[0]);
8500 mass_matrix.
build(dist_pt);
8502 column_or_row_index[1],
8503 row_or_column_start[1]);
8504 #ifdef OOMPH_HAS_MPI 8511 column_or_row_index,
8512 row_or_column_start,
8517 main_matrix.
build(dist_pt);
8519 value[0],column_or_row_index[0],
8520 row_or_column_start[0]);
8522 mass_matrix.
build(dist_pt);
8524 column_or_row_index[1],
8525 row_or_column_start[1]);
8533 column_or_row_index,
8534 row_or_column_start,
8539 main_matrix.
build(temp_dist_pt);
8541 value[0],column_or_row_index[0],
8542 row_or_column_start[0]);
8545 mass_matrix.
build(temp_dist_pt);
8547 column_or_row_index[1],
8548 row_or_column_start[1]);
8550 delete temp_dist_pt;
8575 #ifdef OOMPH_HAS_MPI 8580 const unsigned n_row_local =
8587 for (
unsigned i=0;
i<n_row_local;
i++)
8589 (*Saved_dof_pt)[
i]=*(this->
Dof_pt[
i]);
8597 unsigned long n_dof =
ndof();
8603 for(
unsigned long n=0;n<n_dof;n++) {(*Saved_dof_pt)[n] =
dof(n);}
8616 "There are no stored values, use store_current_dof_values()\n",
8617 OOMPH_CURRENT_FUNCTION,
8618 OOMPH_EXCEPTION_LOCATION);
8622 #ifdef OOMPH_HAS_MPI 8628 const unsigned n_row_local =
8634 "The number of stored values is not equal to the current number of dofs\n",
8635 OOMPH_CURRENT_FUNCTION,
8636 OOMPH_EXCEPTION_LOCATION);
8640 for(
unsigned long n=0;n<n_row_local;n++)
8650 unsigned long n_dof =
ndof();
8655 "The number of stored values is not equal to the current number of dofs\n",
8656 OOMPH_CURRENT_FUNCTION,
8657 OOMPH_EXCEPTION_LOCATION);
8661 for(
unsigned long n=0;n<n_dof;n++) {
dof(n) = (*Saved_dof_pt)[n];}
8674 unsigned long n_dof =
ndof();
8676 if(eigenvector.
nrow() != n_dof)
8678 std::ostringstream error_message;
8679 error_message <<
"Eigenvector has size " << eigenvector.
nrow()
8680 <<
", not equal to the number of dofs in the problem," 8681 << n_dof << std::endl;
8684 OOMPH_CURRENT_FUNCTION,
8685 OOMPH_EXCEPTION_LOCATION);
8689 for(
unsigned long n=0;n<eigenvector.
nrow_local();n++)
8691 dof(n) = eigenvector[n];
8694 #ifdef OOMPH_HAS_MPI 8708 unsigned long n_dof =
ndof();
8710 if(eigenvector.
nrow() != n_dof)
8712 std::ostringstream error_message;
8713 error_message <<
"Eigenvector has size " << eigenvector.
nrow()
8714 <<
", not equal to the number of dofs in the problem," 8715 << n_dof << std::endl;
8718 OOMPH_CURRENT_FUNCTION,
8719 OOMPH_EXCEPTION_LOCATION);
8724 for(
unsigned long n=0;n<eigenvector.
nrow_local();n++)
8726 dof(n) += epsilon*eigenvector[n];
8729 #ifdef OOMPH_HAS_MPI 8746 double total_linear_solver_time=0.0;
8751 unsigned long n_dofs =
ndof();
8762 double half_residual_squared=0.0;
8763 double max_step=0.0;
8770 unsigned LOOP_FLAG=1;
8774 #ifdef OOMPH_HAS_MPI 8778 std::ostringstream error_stream;
8779 error_stream <<
"Globally convergent Newton method has not been " 8780 <<
"implemented in parallel yet!" 8783 OOMPH_CURRENT_FUNCTION,
8784 OOMPH_EXCEPTION_LOCATION);
8813 oomph_info << std::endl << std::endl << std::endl;
8814 oomph_info <<
"This is a bit bizarre: The problem has no dofs." 8817 <<
"I'll just return from the Newton solver without doing anything." 8826 oomph_info <<
"I hope this is what you intended me to do..." << std::endl;
8828 << std::endl <<
"Note: All actions_...() functions were called" 8830 oomph_info << std::endl <<
" before returning." << std::endl;
8831 oomph_info << std::endl << std::endl << std::endl;
8842 #ifdef OOMPH_HAS_MPI 8855 half_residual_squared=0.0;
8857 for (
unsigned i=0;
i<n_dofs;
i++)
8860 half_residual_squared+=dx[
i]*dx[
i];
8862 half_residual_squared*=0.5;
8863 max_step=100.0*std::max(sqrt(sum),
double(n_dofs));
8867 double maxres = dx.
max();
8880 oomph_info <<
"\nInitial Maximum residuals " << maxres << std::endl;
8891 <<
"Linear problem -- convergence in one iteration assumed." 8909 oomph_info <<
"Not recomputing Jacobian! " << std::endl;
8929 oomph_info <<
"Enabling resolve" << std::endl;
8939 total_linear_solver_time+=t_solver_end-t_solver_start;
8944 oomph_info <<
"Time for linear solver ( ndof = " 8945 << n_dofs <<
" ) [sec]: " 8946 << t_solver_end-t_solver_start
8947 << std::endl << std::endl;
8960 for(
unsigned i=0;
i<ndof_local;
i++)
8968 for(
unsigned i=0;
i<ndof_local;
i++)
8973 double half_residual_squared_old=half_residual_squared;
8975 half_residual_squared_old,
8978 half_residual_squared,
8985 for (
unsigned l = 0; l < ndof_local; l++)
8990 #ifdef OOMPH_HAS_MPI 9020 oomph_info <<
"Newton Step " << count <<
": Maximum residuals " 9021 << maxres << std::endl;
9037 <<
") has been exceeded in Newton solver." << std::endl;
9041 oomph_info <<
"Reached max. number of iterations (" 9043 <<
") in Newton solver." << std::endl;
9059 oomph_info <<
"Total time for linear solver (ndof="<< n_dofs <<
") [sec]: " 9060 << total_linear_solver_time << std::endl;
9064 double total_time=t_end-t_start;
9068 oomph_info <<
"Total time for Newton solver (ndof="<< n_dofs <<
") [sec]: " 9069 << total_time << std::endl;
9075 oomph_info <<
"Time outside linear solver : " 9076 << (total_time-total_linear_solver_time)/total_time*100.0
9085 oomph_info <<
"Time outside linear solver : " 9098 const double& half_residual_squared_old,
9101 double& half_residual_squared,
9102 const double& stpmax)
9104 const double min_fct_decrease=1.0e-4;
9105 double convergence_tol_on_x=1.0e-16;
9107 double lambda_aux=0.0;
9108 double proposed_lambda;
9109 unsigned long n_dof=
ndof();
9111 for(
unsigned i=0;
i<n_dof;
i++)
9113 sum += newton_dir[
i]*newton_dir[
i];
9118 for(
unsigned i=0;
i<n_dof;
i++)
9120 newton_dir[
i] *= stpmax/sum;
9124 for(
unsigned i=0;
i<n_dof;
i++)
9126 slope += gradient[
i]*newton_dir[
i];
9130 std::ostringstream warn_message;
9131 warn_message <<
"WARNING: Non-negative slope, probably due to a " 9132 <<
" roundoff \nproblem in the linesearch: slope=" 9135 "Problem::globally_convergent_line_search()",
9136 OOMPH_EXCEPTION_LOCATION);
9139 for(
unsigned i=0;
i<n_dof;
i++)
9141 double temp=std::fabs(newton_dir[
i])/std::max(std::fabs(x_old[i]),1.0);
9142 if(temp > test) test=temp;
9144 double lambda_min=convergence_tol_on_x/test;
9148 for(
unsigned i=0;
i<n_dof;
i++)
9150 *
Dof_pt[
i]=x_old[
i]+lambda*newton_dir[
i];
9156 half_residual_squared=0.0;
9157 for(
unsigned i=0;
i<n_dof;
i++)
9159 half_residual_squared+=residuals[
i]*residuals[
i];
9161 half_residual_squared*=0.5;
9163 if (lambda < lambda_min)
9165 for(
unsigned i=0;
i<n_dof;
i++) *
Dof_pt[
i]=x_old[
i];
9167 std::ostringstream warn_message;
9168 warn_message <<
"WARNING: Line search converged on x only!\n";
9170 "Problem::globally_convergent_line_search()",
9171 OOMPH_EXCEPTION_LOCATION);
9174 else if(half_residual_squared <= half_residual_squared_old+
9175 min_fct_decrease*lambda*slope)
9183 proposed_lambda = -slope/(2.0*(half_residual_squared-
9184 half_residual_squared_old-slope));
9188 double r1=half_residual_squared-half_residual_squared_old-lambda*slope;
9189 double r2=f_aux-half_residual_squared_old-lambda_aux*slope;
9190 double a_poly=(r1/(lambda*lambda)-r2/(lambda_aux*lambda_aux))/
9191 (lambda-lambda_aux);
9192 double b_poly=(-lambda_aux*r1/(lambda*lambda)+lambda*r2/
9193 (lambda_aux*lambda_aux))/(lambda-lambda_aux);
9196 proposed_lambda = -slope/(2.0*b_poly);
9200 double discriminant=b_poly*b_poly-3.0*a_poly*slope;
9201 if(discriminant < 0.0)
9203 proposed_lambda=0.5*lambda;
9205 else if(b_poly <= 0.0)
9207 proposed_lambda=(-b_poly+sqrt(discriminant))/(3.0*a_poly);
9211 proposed_lambda=-slope/(b_poly+sqrt(discriminant));
9214 if(proposed_lambda>0.5*lambda)
9216 proposed_lambda=0.5*lambda;
9221 f_aux = half_residual_squared;
9222 lambda=std::max(proposed_lambda,0.1*lambda);
9243 std::vector<bool> was_steady(n_time_steppers);
9246 for(
unsigned i=0;
i<n_time_steppers;
i++)
9267 oomph_info << std::endl <<
"USER-DEFINED ERROR IN NEWTON SOLVER " 9272 oomph_info <<
"ERROR IN THE LINEAR SOLVER" << std::endl;
9278 ") REACHED WITHOUT CONVERGENCE " << std::endl;
9289 std::ostringstream error_stream;
9290 error_stream <<
"Error occured in Newton solver. " 9293 OOMPH_CURRENT_FUNCTION,
9294 OOMPH_EXCEPTION_LOCATION);
9301 for(
unsigned i=0;
i<n_time_steppers;
i++)
9363 double uderiv_dot_y = 0.0, uderiv_dot_z = 0.0;
9367 unsigned LOOP_FLAG=1;
9373 double arc_length_constraint_residual=0.0;
9392 #ifdef OOMPH_HAS_MPI 9401 double maxres = y.
max();
9404 arc_length_constraint_residual = 0.0;
9406 for(
unsigned long l=0;l<ndof_local;l++)
9408 arc_length_constraint_residual +=
9413 #ifdef OOMPH_HAS_MPI 9414 double arc_length_cons_res2 = arc_length_constraint_residual;
9418 MPI_Allreduce(&arc_length_constraint_residual,
9419 &arc_length_cons_res2,1,MPI_DOUBLE,MPI_SUM,
9422 arc_length_constraint_residual = arc_length_cons_res2;
9426 arc_length_constraint_residual +=
9430 if(std::fabs(arc_length_constraint_residual) > maxres)
9432 maxres = std::fabs(arc_length_constraint_residual);
9438 oomph_info <<
"Initial Maximum residuals " << maxres << std::endl;
9463 solve_for_two_rhs(
this,y,input_z,z);
9495 uderiv_dot_y = 0.0; uderiv_dot_z=0.0;
9501 for(
unsigned long l=0;l<ndof_local;l++)
9508 #ifdef OOMPH_HAS_MPI 9510 double uderiv_dot[2];
double uderiv_dot2[2];
9511 uderiv_dot[0] = uderiv_dot_y; uderiv_dot[1] = uderiv_dot_z;
9512 uderiv_dot2[0] = uderiv_dot_y; uderiv_dot2[1] = uderiv_dot_z;
9517 MPI_Allreduce(uderiv_dot,
9518 uderiv_dot2,2,MPI_DOUBLE,MPI_SUM,
9521 uderiv_dot_y = uderiv_dot2[0];
9522 uderiv_dot_z = uderiv_dot2[1];
9537 double dparam = (arc_length_constraint_residual - uderiv_dot_y)
9541 *parameter_pt -= dparam;
9544 for(
unsigned long l=0;l<ndof_local;l++)
9546 *
Dof_pt[l] -= y_pt[l] - dparam*z_pt[l];
9550 #ifdef OOMPH_HAS_MPI 9563 double maxres = y.
max();
9566 arc_length_constraint_residual = 0.0;
9568 for(
unsigned long l=0;l<ndof_local;l++)
9570 arc_length_constraint_residual +=
9575 #ifdef OOMPH_HAS_MPI 9576 double arc_length_cons_res2 = arc_length_constraint_residual;
9580 MPI_Allreduce(&arc_length_constraint_residual,
9581 &arc_length_cons_res2,1,MPI_DOUBLE,MPI_SUM,
9584 arc_length_constraint_residual = arc_length_cons_res2;
9588 arc_length_constraint_residual +=
9593 if(std::fabs(arc_length_constraint_residual) > maxres)
9595 maxres = std::fabs(arc_length_constraint_residual);
9600 oomph_info <<
"Continuation Step " << count <<
": Maximum residuals " 9648 const unsigned long n_dofs =
ndof();
9671 solve_for_two_rhs(
this,dummy,input_z,z);
9750 double*
const ¶meter_pt)
9779 double*
const ¶meter_pt)
9783 for (
unsigned i=0;
i<n_global;++
i)
9795 const unsigned n_sub_mesh = this->
nsub_mesh();
9801 if(spine_mesh_pt->does_pointer_correspond_to_spine_data(parameter_pt))
9809 for(
unsigned i=0;
i<n_sub_mesh;
i++)
9814 if(spine_mesh_pt->does_pointer_correspond_to_spine_data(parameter_pt))
9860 double*
const local_z_pt = local_z.
values_pt();
9861 for(
unsigned long l=0;l<ndof_local;l++)
9865 #ifdef OOMPH_HAS_MPI 9871 &cont_dir2,1,MPI_DOUBLE,MPI_SUM,
9887 double chi = local_z.
dot(local_z);
9905 for(
unsigned long l=0;l<ndof_local;l++)
9919 double*
const ¶meter_pt)
9930 for(
unsigned long l=0;l<ndof_local;l++)
9937 #ifdef OOMPH_HAS_MPI 9938 double length2 = length;
9942 MPI_Allreduce(&length,
9943 &length2,1,MPI_DOUBLE,MPI_SUM,
9954 length = sqrt(length);
9955 for(
unsigned long l=0;l<ndof_local;l++)
9972 std::ostringstream warn_message;
9974 <<
"Warning: This function is called after spatially adapting the\n" 9975 <<
"eigenfunction associated with a pitchfork bifurcation and should\n" 9976 <<
"ensure that the exact (anti-)symmetries of problem are enforced\n" 9977 <<
"within that eigenfunction. It is problem specific and must be\n" 9978 <<
"filled in by the user if required.\n" 9979 <<
"A sign of problems is if the slack paramter gets too large and\n" 9980 <<
"if the solution at the Pitchfork is not symmetric.\n";
9983 "Problem::symmetrise_eigenfunction_for_adaptive_pitchfork_tracking()",
9984 OOMPH_EXCEPTION_LOCATION);
10013 const bool &block_solve)
10039 double*
const ¶meter_pt,
10041 const bool &block_solve)
10069 double*
const ¶meter_pt,
10072 const bool &block_solve)
10080 eigenvector,normalisation);
10104 double*
const ¶meter_pt,
10105 const DoubleVector &symmetry_vector,
const bool &block_solve)
10137 double*
const ¶meter_pt,
const bool &block_solve)
10165 double*
const ¶meter_pt,
const double &omega,
10167 const bool &block_solve)
10175 null_real,null_imag);
10213 const unsigned &max_adapt)
10219 std::ostringstream error_message;
10220 error_message <<
"The parameter addressed by " << parameter_pt
10221 <<
" with the value " << *parameter_pt
10222 <<
"\n is supposed to be used for arc-length contiunation,\n" 10223 <<
" but it is stored in a Data object used by the problem.\n\n" 10224 <<
"This is bad for two reasons:\n" 10226 "1. If it's a variable in the problem, it must already have an\n" 10227 "associated equation, so it can't be used for continuation;\n" 10229 "2. The problem data will be reorganised in memory during continuation,\n" 10231 " which means that the pointer will become invalid.\n\n" 10233 "If you are sure that this is what you want to do you must:\n" 10235 "A. Ensure that the value is pinned (don't worry we'll shout again if not)\n" 10237 "B. Use the alternative interface\n" 10239 " Problem::arc_length_step_solve(Data*,unsigned,...)\n" 10241 " which uses a pointer to the data object and not the raw double pointer." 10244 OOMPH_CURRENT_FUNCTION,
10245 OOMPH_EXCEPTION_LOCATION);
10253 bool continuation_time_stepper_added =
false;
10255 for(
unsigned i=0;
i<n_time_steppers;
i++)
10259 continuation_time_stepper_added =
true;
10265 if(!continuation_time_stepper_added)
10267 oomph_info <<
"Adding the continuation time stepper\n";
10284 " equation numbers allocated for continuation\n";
10306 const unsigned &data_index,
10308 const unsigned &max_adapt)
10313 std::ostringstream error_stream;
10314 error_stream <<
"The value at index " << data_index
10315 <<
" in the data object to be used for continuation\n" 10316 <<
"is not pinned, which means that it is already a\n" 10317 <<
"variable in the problem " 10318 <<
"and cannot be used for continuation.\n\n" 10319 <<
"Please correct your formulation by either:\n" 10320 <<
"A. Pinning the value" <<
"\n or \n" 10321 <<
"B. Using a different parameter for continuation" 10324 OOMPH_CURRENT_FUNCTION,
10325 OOMPH_EXCEPTION_LOCATION);
10333 bool continuation_time_stepper_added =
false;
10335 for(
unsigned i=0;
i<n_time_steppers;
i++)
10339 continuation_time_stepper_added =
true;
10345 if(!continuation_time_stepper_added)
10347 oomph_info <<
"Adding the continuation time stepper\n";
10365 " equation numbers allocated for continuation\n";
10373 double* parameter_pt = data_pt->
value_pt(data_index);
10397 const unsigned n_sub_mesh = this->
nsub_mesh();
10403 spine_mesh_pt->set_consistent_pinned_spine_values_for_continuation(
10413 for(
unsigned i=0;
i<n_sub_mesh;
i++)
10418 spine_mesh_pt->set_consistent_pinned_spine_values_for_continuation(
10426 for (
unsigned i=0;
i<n_global;++
i)
10442 const unsigned &max_adapt)
10451 std::vector<bool> was_steady(n_time_steppers);
10454 for(
unsigned i=0;
i<n_time_steppers;
i++)
10462 unsigned max_solve = max_adapt+1;
10464 unsigned max_count_in_adapt_loop=0;
10481 bool SIGN_CHANGE=
false;
10485 for(
unsigned isolve=0;isolve<max_solve;++isolve)
10490 unsigned n_refined;
10491 unsigned n_unrefined;
10494 adapt(n_refined,n_unrefined);
10496 #ifdef OOMPH_HAS_MPI 10499 unsigned total_refined=0;
10500 unsigned total_unrefined=0;
10503 MPI_Allreduce(&n_refined,&total_refined,1,MPI_UNSIGNED,MPI_SUM,
10505 n_refined=total_refined;
10506 MPI_Allreduce(&n_unrefined,&total_unrefined,1,MPI_UNSIGNED,MPI_SUM,
10508 n_unrefined=total_unrefined;
10512 oomph_info <<
"---> " << n_refined <<
" elements were refined, and " 10514 <<
" were unrefined" 10515 #ifdef OOMPH_HAS_MPI 10516 <<
", in total (over all processors).\n";
10523 if ((n_refined==0)&&(n_unrefined==0))
10525 oomph_info <<
"\n \n Solution is fully converged in " 10526 <<
"Problem::newton_solver(). \n \n ";
10565 bool STEP_REJECTED=
false;
10580 std::ostringstream error_message;
10581 error_message <<
"DESIRED ARC-LENGTH STEP " <<
Ds_current 10582 <<
" HAS FALLEN BELOW MINIMUM TOLERANCE, " 10586 OOMPH_CURRENT_FUNCTION,
10587 OOMPH_EXCEPTION_LOCATION);
10591 STEP_REJECTED=
false;
10602 for(
unsigned long l=0;l<ndof_local;l++)
10618 std::ostringstream error_stream;
10619 error_stream << std::endl
10620 <<
"USER-DEFINED ERROR IN NEWTON SOLVER " << std::endl;
10621 oomph_info <<
"ERROR IN THE LINEAR SOLVER" << std::endl;
10623 OOMPH_CURRENT_FUNCTION,
10624 OOMPH_EXCEPTION_LOCATION);
10629 oomph_info <<
"STEP REJECTED --- TRYING AGAIN" << std::endl;
10630 STEP_REJECTED=
true;
10632 Ds_current *= (2.0/3.0);
10636 while(STEP_REJECTED);
10639 if(count > max_count_in_adapt_loop) {max_count_in_adapt_loop = count;}
10644 if(max_count_in_adapt_loop>0)
10654 "The sign of the jacobian is zero after a linear solve\n";
10656 "Either the matrix is singular (unlikely),\n";
10658 "or the linear solver cannot compute the determinant of the matrix;\n";
10659 error_message +=
"e.g. an iterative linear solver.\n";
10661 "If the latter, bifurcation detection must be via an eigensolver\n";
10663 "Problem::arc_length_step_solve",
10664 OOMPH_EXCEPTION_LOCATION);
10694 std::ostringstream message;
10695 message <<
"-----------------------------------------------------------";
10696 message << std::endl <<
"SIGN CHANGE IN DETERMINANT OF JACOBIAN: " 10698 message <<
"BIFURCATION OR TURNING POINT DETECTED BETWEEN " 10703 message <<
"-----------------------------------------------------------" 10710 std::ofstream bifurcation_info(
"bifurcation_info",std::ios_base::app);
10712 bifurcation_info << message.str();
10713 bifurcation_info.close();
10773 for(
unsigned i=0;
i<n_time_steppers;
i++)
10775 if (!was_steady[
i])
10820 throw OomphLibError(
"Explicit time stepper pointer is null in problem.",
10821 OOMPH_EXCEPTION_LOCATION,
10822 OOMPH_CURRENT_FUNCTION);
10870 for(
unsigned i=0;
i<n_time_steppers;
i++)
10878 for(
unsigned i=0;
i<n_time_steppers;
i++)
10893 oomph_info << std::endl <<
"USER-DEFINED ERROR IN NEWTON SOLVER " 10898 oomph_info <<
"ERROR IN THE LINEAR SOLVER" << std::endl;
10904 <<
") REACHED WITHOUT CONVERGENCE " << std::endl;
10914 std::ostringstream error_stream;
10915 error_stream <<
"Error occured in unsteady Newton solver. " 10918 OOMPH_CURRENT_FUNCTION,
10919 OOMPH_EXCEPTION_LOCATION);
10926 for(
unsigned i=0;
i<n_time_steppers;
i++)
10943 const double &epsilon)
10964 const double &epsilon,
10965 const bool &shift_values)
10977 for(
unsigned i=0;
i<n_dof_local;
i++) dofs_current[
i] =
dof(
i);
10983 bool reject_timestep=0;
10986 unsigned adaptive_flag=0;
10989 double dt_actual=dt_desired;
10993 for(
unsigned i=0;
i<n_time_steppers;
i++)
11012 double dt_rescaling_factor = 1.0;
11019 for(
unsigned i=0;
i<n_time_steppers;
i++)
11032 for(
unsigned i=0;
i<n_time_steppers;
i++)
11051 "USER-DEFINED ERROR IN NEWTON SOLVER\n";
11052 error_message +=
"ERROR IN THE LINEAR SOLVER\n";
11056 OOMPH_CURRENT_FUNCTION,
11057 OOMPH_EXCEPTION_LOCATION);
11062 oomph_info <<
"TIMESTEP REJECTED" << std::endl;
11074 for(
unsigned i=0;
i<n_time_steppers;
i++)
11082 if(adaptive_flag && !reject_timestep)
11086 for(
unsigned i=0;
i<n_time_steppers;
i++)
11099 dt_rescaling_factor =
11103 << dt_rescaling_factor << std::endl;
11104 oomph_info <<
"Estimated timestepping error is " << error << std::endl;
11111 <<
"Estimated timestepping error " 11112 << error <<
" exceeds tolerance " 11122 oomph_info <<
" ...but we're not rejecting the timestep" 11126 <<
"Note: This behaviour can be adjusted by changing the protected " 11127 <<
"boolean" << std::endl << std::endl
11128 <<
" Problem::Keep_temporal_error_below_tolerance" 11142 double new_dt_candidate = dt_rescaling_factor * dt_actual;
11147 oomph_info <<
"Tried to increase dt by the ratio " << dt_rescaling_factor
11149 <<
"). Attempting to increase by the maximum ratio instead." 11162 <<
"Warning: Adaptation of timestep to ensure satisfaction\n" 11163 <<
" of error bounds during adaptive timestepping\n" 11164 <<
" would lower dt below \n" 11165 <<
" Problem::Minimum_dt_but_still_proceed=" 11167 <<
" ---> We're continuing with present timestep.\n" 11169 dt_rescaling_factor=1.0;
11177 oomph_info <<
"Timestep would decrease by " << dt_rescaling_factor
11178 <<
" which is less than the minimum scaling factor " 11180 oomph_info <<
"TIMESTEP REJECTED" << std::endl;
11189 oomph_info <<
"Tried to increase dt to " << new_dt_candidate
11190 <<
" which is above the maximum (" <<
Maximum_dt 11191 <<
"). I increased it to the maximum value instead.";
11196 std::ostringstream err;
11197 err <<
"Tried to reduce dt to " << new_dt_candidate
11198 <<
" which is less than the minimum dt (" <<
Minimum_dt 11199 <<
")." << std::endl;
11201 OOMPH_CURRENT_FUNCTION);
11205 dt_actual = new_dt_candidate;
11213 if(reject_timestep)
11219 unsigned ni = dofs_current.size();
11220 for(
unsigned i=0;
i<ni;
i++) {
dof(
i) = dofs_current[
i];}
11222 #ifdef OOMPH_HAS_MPI 11237 while(reject_timestep);
11264 (
const double &dt_desired,
11265 const double &epsilon,
11266 const unsigned &max_adapt,
11267 const unsigned& suppress_resolve_after_spatial_adapt_flag,
11269 const bool &shift_values)
11279 oomph_info <<
"Accepted solution taken with timestep: " 11280 << dt_taken << std::endl;
11286 oomph_info <<
"No spatial refinement allowed; max_adapt=0\n";
11291 unsigned n_refined=0;
11292 unsigned n_unrefined=0;
11293 adapt(n_refined,n_unrefined);
11297 total_ref_count[0]=n_refined;
11298 total_ref_count[1]=n_unrefined;
11301 #ifdef OOMPH_HAS_MPI 11306 ref_count[0]=n_refined;
11307 ref_count[1]=n_unrefined;
11308 MPI_Allreduce(&ref_count[0],&total_ref_count[0],2,MPI_INT,MPI_SUM,
11315 if ((total_ref_count[0]!=0)||
11316 (total_ref_count[1]!=0))
11318 if (suppress_resolve_after_spatial_adapt_flag==1)
11320 oomph_info <<
"Mesh was adapted but re-solve has been suppressed." 11325 oomph_info <<
"Mesh was adapted --> we'll re-solve for current timestep." 11343 oomph_info <<
"Re-assigning initial condition at time=" 11363 oomph_info <<
"Mesh wasn't adapted --> we'll accept spatial refinement." 11387 for (
unsigned iglobal=0;iglobal<Nglobal;iglobal++)
11416 OOMPH_CURRENT_FUNCTION,
11417 OOMPH_EXCEPTION_LOCATION);
11431 OOMPH_CURRENT_FUNCTION,
11432 OOMPH_EXCEPTION_LOCATION);
11454 preserve_existing_data);
11457 const unsigned n_sub_mesh = this->
nsub_mesh();
11467 for(
unsigned i=0;
i<n_sub_mesh;
i++)
11469 this->
Sub_mesh_pt[
i]->set_mesh_level_time_stepper(time_stepper_pt,
11470 preserve_existing_data);
11476 for (
unsigned i=0;
i<n_global;++
i)
11478 Global_data_pt[
i]->set_time_stepper(time_stepper_pt,preserve_existing_data);
11484 #ifdef OOMPH_HAS_MPI 11487 std::ostringstream warning_stream;
11489 "This has not been comprehensively tested for distributed problems.\n" 11491 "I'm sure that I need to worry about external halo and external elements." 11494 OOMPH_CURRENT_FUNCTION,
11495 OOMPH_EXCEPTION_LOCATION);
11518 for (
unsigned iglobal=0;iglobal<Nglobal;iglobal++)
11545 "Prediction by explicit step only works for problems with a simple time";
11546 err +=
"stepper. I think implementing anything more general will";
11547 err +=
"require a rewrite of explicit time steppers. - David";
11549 OOMPH_CURRENT_FUNCTION);
11568 std::string err =
"Requested predictions by explicit step but explicit";
11569 err +=
" predictor pt is null.";
11571 OOMPH_EXCEPTION_LOCATION);
11577 throw OomphLibError(
"Problem has explicit time stepper other than predictor, not sure how to handle this yet ??ds",
11578 OOMPH_EXCEPTION_LOCATION,
11579 OOMPH_CURRENT_FUNCTION);
11588 double backup_time =
time();
11607 if(std::abs(
time() - backup_time) > 1
e-12)
11609 using namespace StringConversion;
11610 std::string err =
"Predictor landed at the wrong time!";
11611 err +=
" Expected time " +
to_string(backup_time, 14) +
" but got ";
11614 OOMPH_CURRENT_FUNCTION);
11631 for (
unsigned iglobal=0;iglobal<Nglobal;iglobal++)
11646 #ifdef OOMPH_HAS_MPI 11649 throw OomphLibError(
"Not yet implemented for distributed problems",
11650 OOMPH_EXCEPTION_LOCATION, OOMPH_CURRENT_FUNCTION);
11659 std::string err =
"Not implemented for multiple time steppers";
11661 OOMPH_CURRENT_FUNCTION);
11669 for(
unsigned i=0;
i<
ndof();
i++)
11671 dof(
i) = predicted_dofs[
i];
11693 for(
unsigned e=0;
e<n_element;
e++)
11718 for(
unsigned e=0;
e<n_element;
e++)
11747 bool unsteady_flag=(orig_problem_pt->
time_pt()!=0);
11752 oomph_info <<
"Copying an unsteady problem." << std::endl;
11756 unsigned n_dt=orig_problem_pt->
time_pt()->
ndt();
11758 for (
unsigned i=0;
i<n_dt;
i++)
11767 for(
unsigned i=0;
i<n_time_steppers;
i++)
11780 if (nmesh==0) nmesh=1;
11781 for (
unsigned m=0;m<nmesh;m++)
11787 unsigned long n_node_orig=orig_problem_pt->
mesh_pt(m)->
nnode();
11788 if (n_node!=n_node_orig)
11790 std::ostringstream error_message;
11791 error_message <<
"Number of nodes in copy " << n_node
11792 <<
" not equal to the number in the original " 11793 << n_node_orig << std::endl;
11796 OOMPH_CURRENT_FUNCTION,
11797 OOMPH_EXCEPTION_LOCATION);
11801 for(
unsigned long i=0;
i<n_node;
i++)
11809 el_node_pt->
copy(el_node_orig_pt);
11826 unsigned long n_global_orig=orig_problem_pt->
nglobal_data();
11827 if (n_global!=n_global_orig)
11829 std::ostringstream error_message;
11830 error_message <<
"Number of global data in copy " << n_global
11831 <<
" not equal to the number in the original " 11832 << n_global_orig << std::endl;
11835 OOMPH_CURRENT_FUNCTION,
11836 OOMPH_EXCEPTION_LOCATION);
11839 for (
unsigned iglobal=0;iglobal<n_global;iglobal++)
11849 for (
unsigned m=0;m<nmesh;m++)
11853 for (
unsigned e=0;
e<n_element;
e++)
11860 unsigned long n_internal_orig=orig_problem_pt->
11862 if (n_internal!=n_internal_orig)
11864 std::ostringstream error_message;
11865 error_message <<
"Number of internal data in copy " << n_internal
11866 <<
" not equal to the number in the original " 11867 << n_internal_orig << std::endl;
11870 OOMPH_CURRENT_FUNCTION,
11871 OOMPH_EXCEPTION_LOCATION);
11873 for (
unsigned i=0;
i<n_internal;
i++)
11877 internal_data_pt(
i));
11893 std::ostringstream error_stream;
11895 <<
"This function must be overloaded in your specific problem, and must\n" 11896 <<
"create an exact copy of your problem. Usually this will be achieved\n" 11897 <<
"by a call to the constructor with exactly the same arguments as used\n";
11900 OOMPH_CURRENT_FUNCTION,
11901 OOMPH_EXCEPTION_LOCATION);
11916 dump_file << std::max(
unsigned(1),n_mesh)
11917 <<
" # number of (sub)meshes " << std::endl;
11925 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(0)))
11927 dump_file << mmesh_pt->uniform_refinement_level_when_pruned()
11928 <<
" # uniform refinement when pruned " << std::endl;
11933 <<
" # (fake) uniform refinement when pruned " << std::endl;
11935 dump_file << 9999 <<
" # test flag for end of sub-meshes " << std::endl;
11943 for (
unsigned imesh=0;imesh<n_mesh;imesh++)
11946 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(imesh)))
11948 dump_file << mmesh_pt->uniform_refinement_level_when_pruned()
11949 <<
" # uniform refinement when pruned " << std::endl;
11954 <<
" # (fake) uniform refinement when pruned " << std::endl;
11957 dump_file << 9999 <<
" # test flag for end of sub-meshes " << std::endl;
11960 #ifdef OOMPH_HAS_MPI 11968 for (
unsigned e=0;
e<n;
e++)
11975 local_base_element_processor[
e]=my_rank;
11991 MPI_Allreduce(&local_base_element_processor[0],
11992 &base_element_processor[0],
12000 base_element_processor=local_base_element_processor;
12004 dump_file << n <<
" # Number of base elements; partitioning follows.\n";
12005 for (
unsigned e=0;
e<n;
e++)
12007 dump_file << base_element_processor[
e] <<
"\n";
12009 dump_file <<
"8888 #test flag for end of base element distribution\n";
12019 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(0)))
12021 mmesh_pt->dump_refinement(dump_file);
12023 #ifdef OOMPH_HAS_TRIANGLE_LIB 12028 #ifdef OOMPH_HAS_MPI 12048 for (
unsigned imesh=0;imesh<n_mesh;imesh++)
12052 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(imesh)))
12054 mmesh_pt->dump_refinement(dump_file);
12056 #ifdef OOMPH_HAS_TRIANGLE_LIB 12062 #ifdef OOMPH_HAS_MPI 12082 bool unsteady_flag=(
time_pt()!=0);
12083 dump_file << unsteady_flag <<
" # bool flag for unsteady" << std::endl;
12089 dump_file <<
time_pt()->
time() <<
" # Time " << std::endl;
12092 dump_file << n_dt <<
" # Number of timesteps " << std::endl;
12093 for (
unsigned i=0;
i<n_dt;
i++)
12095 dump_file <<
time_pt()->
dt(
i) <<
" # dt " << std::endl;
12102 dump_file <<
"0.0 # Dummy time from steady run " << std::endl;
12104 dump_file <<
"0 # Dummy number of timesteps from steady run" << std::endl;
12109 if (nmesh==0) nmesh=1;
12110 for(
unsigned m=0;m<nmesh;m++)
12119 dump_file << Nglobal <<
" # number of global Data items " << std::endl;
12120 for (
unsigned iglobal=0;iglobal<Nglobal;iglobal++)
12123 dump_file << std::endl;
12141 bool restart_file_is_open=
true;
12142 if (!restart_file.is_open())
12144 std::ostringstream warn_message;
12145 warn_message <<
"Restart file isn't open -- I'm assuming that this is\n";
12146 warn_message <<
"because we're restarting on a larger number of\n";
12147 warn_message <<
"processor than were in use when the restart data was \n";
12148 warn_message <<
"dumped.\n";
12151 OOMPH_EXCEPTION_LOCATION);
12152 restart_file_is_open=
false;
12156 unsigned n_mesh=std::max(
unsigned(1),
nsub_mesh());
12161 getline(restart_file,input_string,
'#');
12164 restart_file.ignore(80,
'\n');
12167 unsigned n_submesh_read;
12168 n_submesh_read=std::atoi(input_string.c_str());
12171 if (restart_file_is_open)
12173 if (n_submesh_read!=n_mesh)
12175 std::ostringstream error_message;
12177 <<
"Number of sub-meshes specified in restart file, " 12178 << n_submesh_read <<
" doesn't \n match the my number of sub-meshes," 12179 << n_mesh << std::endl
12180 <<
"Make sure all sub-meshes have been added to the global mesh\n" 12181 <<
"when calling the Problem::dump() function.\n";
12183 OOMPH_CURRENT_FUNCTION,
12184 OOMPH_EXCEPTION_LOCATION);
12195 #ifdef OOMPH_HAS_MPI 12196 bool refine_and_prune_required=
false;
12199 for (
unsigned i=0;
i<n_mesh;
i++)
12202 getline(restart_file,input_string,
'#');
12205 restart_file.ignore(80,
'\n');
12208 nrefinement_for_mesh[
i]=std::atoi(input_string.c_str());
12215 if (ref_mesh_pt==0)
12217 if (nrefinement_for_mesh[
i]!=0)
12219 std::ostringstream error_stream;
12220 error_stream <<
"Nonzero uniform-refinement-when-pruned specified\n" 12221 <<
"even though mesh is not tree-based. Odd. May want\n" 12222 <<
"to check this carefully before disabling this \n" 12223 <<
"warning/error -- most likely if/when we start to\n" 12224 <<
"prune unstructured meshes [though I can't see why\n" 12225 <<
"we would want to do this, given that they are \n" 12226 <<
"currently totally re-generated...]\n";
12228 OOMPH_CURRENT_FUNCTION,
12229 OOMPH_EXCEPTION_LOCATION);
12235 unsigned local_min_ref=0;
12236 unsigned local_max_ref=0;
12237 ref_mesh_pt->get_refinement_levels(local_min_ref,local_max_ref);
12240 unsigned min_ref=local_min_ref;
12242 #ifdef OOMPH_HAS_MPI 12249 int int_local_min_ref=local_min_ref;
12250 if (ref_mesh_pt->nelement()==0)
12252 int_local_min_ref=INT_MAX;
12255 MPI_Allreduce(&int_local_min_ref,&int_min_ref,1,
12260 min_ref=unsigned(int_min_ref);
12265 if (nrefinement_for_mesh[
i]>=min_ref)
12267 nrefinement_for_mesh[
i]-=min_ref;
12271 #ifdef OOMPH_HAS_MPI 12272 if (nrefinement_for_mesh[
i]>0)
12274 refine_and_prune_required=
true;
12283 #ifdef OOMPH_HAS_MPI 12286 unsigned local_req_flag=0;
12287 unsigned req_flag=0;
12288 if (refine_and_prune_required)
12292 MPI_Allreduce(&local_req_flag,&req_flag,1,
12293 MPI_UNSIGNED,MPI_MAX,
12295 refine_and_prune_required=
false;
12298 refine_and_prune_required=
true;
12304 if (refine_and_prune_required)
12309 MPI_Allreduce(&local_nrefinement_for_mesh[0],
12310 &nrefinement_for_mesh[0],
12312 MPI_UNSIGNED,MPI_MAX,
12320 std::ostringstream error_message;
12321 error_message <<
"Number of uniform refinements was not consistent \n" 12322 <<
"for following meshes during restart on processor \n" 12323 <<
"on which restart file could be opened:\n";
12324 for (
unsigned i=0;
i<n_mesh;
i++)
12326 if ((local_nrefinement_for_mesh[
i]!=nrefinement_for_mesh[
i])&&
12327 restart_file_is_open)
12330 error_message <<
"Sub-mesh: " << i
12331 <<
"; local nrefinement: " 12332 << local_nrefinement_for_mesh[
i] <<
" " 12333 <<
"; global/synced nrefinement: " 12334 << nrefinement_for_mesh[
i] <<
"\n";
12341 OOMPH_EXCEPTION_LOCATION);
12349 getline(restart_file,input_string,
'#');
12352 restart_file.ignore(80,
'\n');
12356 tmp=std::atoi(input_string.c_str());
12359 if (restart_file_is_open)
12363 std::ostringstream error_message;
12365 <<
"Error in reading restart data: Uniform refinement when pruned \n" 12366 <<
"flags should be followed by 9999.\n";
12368 OOMPH_CURRENT_FUNCTION,
12369 OOMPH_EXCEPTION_LOCATION);
12380 #ifdef OOMPH_HAS_MPI 12383 if (refine_and_prune_required)
12397 getline(restart_file,input_string,
'#');
12400 restart_file.ignore(80,
'\n');
12403 unsigned n_base_element_read_in=atoi(input_string.c_str());
12405 if (restart_file_is_open)
12407 if (n_base_element_read_in!=nbase)
12409 std::ostringstream error_message;
12411 <<
"About to read " << n_base_element_read_in <<
" base elements \n" 12412 <<
"though we only have " << nbase <<
" base elements in mesh.\n";
12414 OOMPH_CURRENT_FUNCTION,
12415 OOMPH_EXCEPTION_LOCATION);
12421 for (
unsigned e=0;
e<nbase;
e++)
12424 getline(restart_file,input_string);
12427 target_domain_for_base_element[
e]=atoi(input_string.c_str());
12431 getline(restart_file,input_string,
'#');
12434 restart_file.ignore(80,
'\n');
12437 tmp=std::atoi(input_string.c_str());
12441 if (restart_file_is_open)
12445 std::ostringstream error_message;
12447 <<
"Error in reading restart data: Target proc for base elements \n" 12448 <<
"should be followed by 8888.\n";
12450 OOMPH_CURRENT_FUNCTION,
12451 OOMPH_EXCEPTION_LOCATION);
12461 unsigned load_balance_required_flag=0;
12465 unsigned local_load_balance_required_flag=0;
12466 if(dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(0)))
12470 for (
unsigned e=0;
e<nel;
e++)
12476 unsigned el_number_in_base_mesh_plus_one=
12482 if (el_number_in_base_mesh_plus_one==0)
12491 el_number_in_base_mesh_plus_one=
12495 if (el_number_in_base_mesh_plus_one==0)
12497 throw OomphLibError(
"el_number_in_base_mesh_plus_one=0 for bulk",
12499 OOMPH_EXCEPTION_LOCATION);
12507 if (el_number_in_base_mesh_plus_one==0)
12510 OOMPH_CURRENT_FUNCTION,
12511 OOMPH_EXCEPTION_LOCATION);
12516 target_domain_for_local_non_halo_element.push_back(
12517 target_domain_for_base_element[el_number_in_base_mesh_plus_one-1]);
12520 if (
int(target_domain_for_base_element
12521 [el_number_in_base_mesh_plus_one-1])
12524 local_load_balance_required_flag=1;
12532 MPI_Allreduce(&local_load_balance_required_flag,
12533 &load_balance_required_flag,1,
12539 if (load_balance_required_flag==1)
12541 oomph_info <<
"Doing load balancing after pruning\n";
12544 bool report_stats=
false;
12546 target_domain_for_local_non_halo_element);
12547 oomph_info <<
"Done load balancing after pruning\n";
12551 oomph_info <<
"No need for load balancing after pruning\n";
12560 bool have_read_unstructured_mesh=
false;
12588 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(0)))
12597 mmesh_pt->refine(restart_file);
12599 #ifdef OOMPH_HAS_TRIANGLE_LIB 12604 #ifdef OOMPH_HAS_MPI 12617 have_read_unstructured_mesh=
true;
12618 #ifdef OOMPH_HAS_MPI 12643 for (
unsigned imesh=0;imesh<n_mesh;imesh++)
12647 =dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(imesh)))
12656 mmesh_pt->refine(restart_file);
12658 #ifdef OOMPH_HAS_TRIANGLE_LIB 12664 #ifdef OOMPH_HAS_MPI 12677 have_read_unstructured_mesh=
true;
12679 #ifdef OOMPH_HAS_MPI 12714 if (have_read_unstructured_mesh)
12719 std::ostringstream warn_message;
12721 <<
"I've just read in some unstructured meshes and have, in\n" 12722 <<
"the process, totally re-generated their nodes and elements.\n" 12723 <<
"This may create dangling pointers that still point to the\n" 12724 <<
"old nodes and elements, e.g. because FaceElements were\n" 12725 <<
"attached to these meshes or pointers to nodes and elements\n" 12726 <<
"were stored somewhere. FaceElements should therefore be\n" 12727 <<
"removed before reading in these meshes, using an overloaded\n" 12728 <<
"version of the function\n\n" 12729 <<
" Problem::actions_before_read_unstructured_meshes()\n\n" 12730 <<
"and then re-attached using an overloaded version of\n\n" 12731 <<
" Problem::actions_after_read_unstructured_meshes().\n\n" 12732 <<
"The required content of these functions is likely to be similar\n" 12733 <<
"to the Problem::actions_before_adapt() and \n" 12734 <<
"Problem::actions_after_adapt() that would be required in\n" 12735 <<
"a spatially adaptive computation. If these functions already\n" 12736 <<
"exist and perform the required actions, the \n" 12737 <<
"actions_before/after_read_unstructured_meshes() functions\n" 12738 <<
"can remain empty because the former are called automatically.\n" 12739 <<
"In this case, this warning my be suppressed by setting the\n" 12740 <<
"public boolean\n\n" 12741 <<
" Problem::Suppress_warning_about_actions_before_read_unstructured_meshes\n\n" 12745 OOMPH_CURRENT_FUNCTION,
12746 OOMPH_EXCEPTION_LOCATION);
12752 oomph_info <<
"\nNumber of equations in Problem::read(): " 12754 << std::endl<< std::endl;
12757 unsigned local_unsteady_restart_flag=0;
12758 double local_time=-DBL_MAX;
12759 unsigned local_n_dt=0;
12760 #ifdef OOMPH_HAS_MPI 12761 unsigned local_sync_needed_flag=0;
12765 if (restart_file.is_open())
12767 oomph_info <<
"Restart file exists" << std::endl;
12768 #ifdef OOMPH_HAS_MPI 12769 local_sync_needed_flag=0;
12772 getline(restart_file,input_string,
'#');
12775 restart_file.ignore(80,
'\n');
12778 local_unsteady_restart_flag=atoi(input_string.c_str());
12781 getline(restart_file,input_string,
'#');
12784 restart_file.ignore(80,
'\n');
12787 local_time=atof(input_string.c_str());
12790 getline(restart_file,input_string,
'#');
12793 restart_file.ignore(80,
'\n');
12796 local_n_dt=atoi(input_string.c_str());
12797 local_dt.resize(local_n_dt);
12800 for (
unsigned i=0;
i<local_n_dt;
i++)
12803 getline(restart_file,input_string,
'#');
12806 restart_file.ignore(80,
'\n');
12809 double prev_dt=atof(input_string.c_str());
12810 local_dt[
i]=prev_dt;
12815 oomph_info <<
"Restart file does not exist" << std::endl;
12816 #ifdef OOMPH_HAS_MPI 12817 local_sync_needed_flag=1;
12826 unsigned sync_needed_flag=0;
12828 #ifdef OOMPH_HAS_MPI 12832 MPI_Allreduce(&local_sync_needed_flag,&sync_needed_flag,1,
12838 if (sync_needed_flag==1)
12841 #ifdef OOMPH_HAS_MPI 12847 std::ostringstream error_message;
12849 <<
"Synchronisation of temporal restart data \n" 12850 <<
"required even though Problem hasn't been distributed -- very odd!\n";
12852 OOMPH_CURRENT_FUNCTION,
12853 OOMPH_EXCEPTION_LOCATION);
12858 unsigned unsteady_restart_flag=0;
12859 MPI_Allreduce(&local_unsteady_restart_flag,&unsteady_restart_flag,1,
12863 unsteady_restart=
false;
12864 if (unsteady_restart_flag==1)
12866 unsteady_restart=
true;
12869 double time=-DBL_MAX;
12870 MPI_Allreduce(&local_time,&time,1,
12876 MPI_Allreduce(&local_n_dt,&n_dt,1,
12882 if (local_dt.size()==0)
12884 local_dt.resize(n_dt,-DBL_MAX);
12888 MPI_Allreduce(&local_dt[0],&dt[0],n_dt,
12894 std::ostringstream error_message;
12896 <<
"Synchronisation of temporal restart data \n" 12897 <<
"required even though we don't have mpi support -- very odd!\n";
12899 OOMPH_CURRENT_FUNCTION,
12900 OOMPH_EXCEPTION_LOCATION);
12908 unsteady_restart=
false;
12909 if (local_unsteady_restart_flag==1)
12911 unsteady_restart=
true;
12914 dt.resize(local_n_dt);
12915 for (
unsigned i=0;
i<local_n_dt;
i++)
12928 if (nmesh==0) nmesh=1;
12929 for (
unsigned m=0;m<nmesh;m++)
12977 #ifdef OOMPH_HAS_TRIANGLE_LIB 12981 dynamic_cast<TriangleMeshBase*>(
mesh_pt(m)))
12987 mmesh_pt->update_polyline_representation_from_restart();
12989 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB 13000 getline(restart_file,input_string,
'#');
13003 restart_file.ignore(80,
'\n');
13006 unsigned long check_nglobal=atoi(input_string.c_str());
13009 if (restart_file_is_open)
13011 if (check_nglobal!=Nglobal)
13013 std::ostringstream error_message;
13014 error_message <<
"The number of global data " << Nglobal
13015 <<
" is not equal to that specified in the input file " 13016 << check_nglobal << std::endl;
13019 OOMPH_CURRENT_FUNCTION,
13020 OOMPH_EXCEPTION_LOCATION);
13024 for (
unsigned iglobal=0;iglobal<Nglobal;iglobal++)
13044 for(
unsigned i=0;
i<n_time_steppers;
i++)
13067 for(
unsigned i=0;
i<n_time_steppers;
i++)
13095 <<
"\n ERROR: Failed Mesh::self_test() for single mesh in problem" 13102 for (
unsigned imesh=0;imesh<Nmesh;imesh++)
13107 oomph_info <<
"\n ERROR: Failed Mesh::self_test() for mesh imesh" 13108 << imesh << std::endl;
13116 for (
unsigned iglobal=0;iglobal<Nglobal;iglobal++)
13122 <<
"\n ERROR: Failed Data::self_test() for global data iglobal" 13123 << iglobal << std::endl;
13128 #ifdef OOMPH_HAS_MPI 13141 if (passed) {
return 0;}
13154 unsigned &n_refined,
unsigned &n_unrefined,
13155 const unsigned &bifurcation_type,
const bool &actually_adapt)
13166 double omega = 0.0;
13168 if(bifurcation_type==3)
13174 double sigma = 0.0;
13175 if(bifurcation_type==2)
13177 sigma = this->
dof(this->
ndof()-1);
13187 const unsigned n_copies = eigenfunction.size();
13191 for(
unsigned c=0;c<n_copies;c++)
13208 dynamic_cast<TreeBasedRefineableMeshBase*>(
13212 if(mmesh_pt->is_adaptation_enabled())
13216 = dynamic_cast<TreeBasedRefineableMeshBase*>(this->
mesh_pt(0)))
13218 mmesh_pt->refine_base_mesh_as_in_reference_mesh(original_mesh_pt);
13224 "Info/Warning: Mesh in orginal problem is not refineable." 13230 oomph_info <<
"Info/Warning: Mesh adaptation is disabled in copy." 13236 oomph_info <<
"Info/Warning: Mesh cannot be adapted in copy." 13243 for(
unsigned m=0;m<N_mesh;m++)
13247 dynamic_cast<TreeBasedRefineableMeshBase*>(
13251 if(mmesh_pt->is_adaptation_enabled())
13255 = dynamic_cast<TreeBasedRefineableMeshBase*>(this->
mesh_pt(m)))
13258 refine_base_mesh_as_in_reference_mesh(original_mesh_pt);
13264 "Info/Warning: Mesh in orginal problem is not refineable." 13271 "Info/Warning: Mesh adaptation is disabled in copy." 13277 oomph_info <<
"Info/Warning: Mesh cannot be adapted in copy." 13296 for(
unsigned c=0;c<n_copies;c++)
13303 std::ostringstream error_stream;
13306 "Number of unknowns in the problem copy " << c <<
" " 13307 <<
"not equal to number in the original:\n" 13312 OOMPH_CURRENT_FUNCTION,
13313 OOMPH_EXCEPTION_LOCATION);
13324 if(bifurcation_type==2)
13333 for(
unsigned c=0;c<n_copies;c++)
13339 unsigned n_mesh = base_error.size();
13342 if(n_mesh != eigenfunction_error.size())
13344 std::ostringstream error_stream;
13346 "Problems do not have the same number of meshes\n" 13347 <<
"Base : " << n_mesh
13348 <<
" : Eigenproblem : " 13349 << eigenfunction_error.size() <<
"\n";
13351 OOMPH_CURRENT_FUNCTION,
13352 OOMPH_EXCEPTION_LOCATION);
13356 for(
unsigned m=0;m<n_mesh;m++)
13359 unsigned n_element = base_error[m].size();
13361 if(n_element != eigenfunction_error[m].size())
13363 std::ostringstream error_stream;
13364 error_stream <<
"Mesh " << m <<
13365 " does not have the same number of elements in the two problems:\n" 13366 <<
"Base: " << n_element <<
" : Eigenproblem: " 13367 << eigenfunction_error[m].size() <<
"\n";
13369 OOMPH_CURRENT_FUNCTION,
13370 OOMPH_EXCEPTION_LOCATION);
13374 for(
unsigned e=0;
e<n_element;
e++)
13377 base_error[m][
e] += eigenfunction_error[m][
e];
13387 for(
unsigned c=0;c<n_copies;c++)
13393 if(bifurcation_type==2)
13398 for(
unsigned c=0;c<n_copies;c++)
13405 switch(bifurcation_type)
13416 this->
dof(this->
ndof()-1) = sigma;
13422 eigenfunction[0],eigenfunction[1]);
13426 std::ostringstream error_stream;
13427 error_stream <<
"Bifurcation type " << bifurcation_type <<
" not known\n" 13428 <<
"1: Fold, 2: Pitchfork, 3: Hopf\n";
13430 OOMPH_CURRENT_FUNCTION,
13431 OOMPH_EXCEPTION_LOCATION);
13447 unsigned n_refined, n_unrefined;
13466 double t_start_total = 0.0;
13475 bool continuation_problem =
false;
13485 if(bifurcation_type!=0)
13492 if(continuation_problem)
13497 for(
unsigned c=0;c<2;c++)
13516 dynamic_cast<TreeBasedRefineableMeshBase*>(
13520 if(mmesh_pt->is_adaptation_enabled())
13524 = dynamic_cast<TreeBasedRefineableMeshBase*>(this->
mesh_pt(0)))
13526 if(dynamic_cast<SolidMesh*>(original_mesh_pt)!=0)
13529 <<
"Info/Warning: Adaptive Continuation is broken in " 13530 <<
"SolidElement" << std::endl;
13533 refine_base_mesh_as_in_reference_mesh(original_mesh_pt);
13539 "Info/Warning: Mesh in orginal problem is not refineable." 13545 oomph_info <<
"Info/Warning: Mesh adaptation is disabled in copy." 13550 dynamic_cast<TriangleMeshBase*>(
13554 dynamic_cast<TriangleMeshBase*>(
13557 if(dynamic_cast<SolidMesh*>(original_mesh_pt)!=0)
13560 <<
"Info/Warning: Adaptive Continuation is broken in " 13561 <<
"SolidElement" << std::endl;
13567 std::ofstream tri_dump(
"triangle_mesh.dmp");
13568 original_mesh_pt->dump_triangulateio(tri_dump);
13570 std::ifstream tri_read(
"triangle_mesh.dmp");
13571 tmesh_pt->remesh_from_triangulateio(tri_read);
13578 const unsigned n_node = original_mesh_pt->nnode();
13579 for(
unsigned n=0;n<n_node;++n)
13581 Node*
const nod_pt = original_mesh_pt->node_pt(n);
13582 Node*
const new_node_pt = tmesh_pt->node_pt(n);
13583 unsigned n_dim = nod_pt->
ndim();
13584 for(
unsigned i=0;
i<n_dim;++
i)
13586 new_node_pt->
x(
i) = nod_pt->
x(
i);
13593 <<
"Info/warning: Original Mesh is not TriangleBased\n" 13594 <<
"... but the copy is!" << std::endl;
13599 oomph_info <<
"Info/Warning: Mesh cannot be adapted in copy." 13606 for(
unsigned m=0;m<N_mesh;m++)
13610 dynamic_cast<TreeBasedRefineableMeshBase*>(
13614 if(mmesh_pt->is_adaptation_enabled())
13618 = dynamic_cast<TreeBasedRefineableMeshBase*>(this->
mesh_pt(m)))
13620 if(dynamic_cast<SolidMesh*>(original_mesh_pt)!=0)
13623 <<
"Info/Warning: Adaptive Continuation is broken in " 13624 <<
"SolidElement" << std::endl;
13628 refine_base_mesh_as_in_reference_mesh(original_mesh_pt);
13634 "Info/Warning: Mesh in orginal problem is not refineable." 13641 "Info/Warning: Mesh adaptation is disabled in copy." 13646 dynamic_cast<TriangleMeshBase*>(
13650 dynamic_cast<TriangleMeshBase*>(
13653 if(dynamic_cast<SolidMesh*>(original_mesh_pt)!=0)
13656 <<
"Info/Warning: Adaptive Continuation is broken in " 13657 <<
"SolidElement" << std::endl;
13663 std::ofstream tri_dump(
"triangle_mesh.dmp");
13664 original_mesh_pt->dump_triangulateio(tri_dump);
13666 std::ifstream tri_read(
"triangle_mesh.dmp");
13667 tmesh_pt->remesh_from_triangulateio(tri_read);
13673 const unsigned n_node = original_mesh_pt->nnode();
13674 for(
unsigned n=0;n<n_node;++n)
13676 Node*
const nod_pt = original_mesh_pt->node_pt(n);
13677 Node*
const new_node_pt = tmesh_pt->node_pt(n);
13678 unsigned n_dim = nod_pt->
ndim();
13679 for(
unsigned i=0;
i<n_dim;++
i)
13681 new_node_pt->
x(
i) = nod_pt->
x(
i);
13688 <<
"Info/warning: Original Mesh is not TriangleBased\n" 13689 <<
"... but the copy is!" << std::endl;
13694 oomph_info <<
"Info/Warning: Mesh cannot be adapted in copy." 13720 std::ostringstream error_stream;
13723 "Number of unknowns in the problem copy " 13725 <<
"not equal to number in the original:\n" 13730 OOMPH_CURRENT_FUNCTION,
13731 OOMPH_EXCEPTION_LOCATION);
13739 for(
unsigned i=0;
i<ndof_local;
i++)
13767 for(
unsigned i=0;
i<ndof_local;
i++)
13777 oomph_info <<
"Adapting problem:" << std::endl;
13778 oomph_info <<
"=================" << std::endl;
13780 double t_start = 0.0;
13789 double t_end = 0.0;
13793 oomph_info <<
"Time for actions before adapt: " 13794 << t_end-t_start << std::endl;
13811 dynamic_cast<RefineableMeshBase*>(
mesh_pt(0)))
13813 if (mmesh_pt->is_adaptation_enabled())
13819 spatial_error_estimator_pt();
13822 if (error_estimator_pt==0)
13825 "Error estimator hasn't been set yet",
13826 OOMPH_CURRENT_FUNCTION,
13827 OOMPH_EXCEPTION_LOCATION);
13834 if (mmesh_pt->doc_info_pt()==0)
13841 *mmesh_pt->doc_info_pt());
13845 mmesh_pt->max_error()=
13846 std::fabs(*std::max_element(elemental_error.begin(),
13849 mmesh_pt->min_error()=
13850 std::fabs(*std::min_element(elemental_error.begin(),
13854 << mmesh_pt->max_error() <<
" " 13855 << mmesh_pt->min_error()
13856 << std::endl << std::endl;
13863 << t_end-t_start << std::endl;
13868 mmesh_pt->adapt(elemental_error);
13871 n_refined+=mmesh_pt->nrefined();
13872 n_unrefined+=mmesh_pt->nunrefined();
13877 oomph_info <<
"Time for complete mesh adaptation " 13878 <<
"(but excluding comp of error estimate): " 13879 << t_end-t_start << std::endl;
13886 oomph_info <<
"Info/Warning: Mesh adaptation is disabled." << std::endl;
13891 oomph_info <<
"Info/Warning: Mesh cannot be adapted" << std::endl;
13900 for (
unsigned imesh=0;imesh<Nmesh;imesh++)
13904 dynamic_cast<RefineableMeshBase*>(
mesh_pt(imesh)))
13910 spatial_error_estimator_pt();
13913 if (error_estimator_pt==0)
13916 "Error estimator hasn't been set yet",
13917 OOMPH_CURRENT_FUNCTION,
13918 OOMPH_EXCEPTION_LOCATION);
13922 if (mmesh_pt->is_adaptation_enabled())
13926 if (mmesh_pt->doc_info_pt()==0)
13935 *mmesh_pt->doc_info_pt());
13941 mmesh_pt->max_error()=
13942 std::fabs(*std::max_element(elemental_error.begin(),
13943 elemental_error.end(),
13946 mmesh_pt->min_error()=
13947 std::fabs(*std::min_element(elemental_error.begin(),
13948 elemental_error.end(),
13953 << mmesh_pt->max_error() <<
" " 13954 << mmesh_pt->min_error() << std::endl;
13961 << t_end-t_start << std::endl;
13966 mmesh_pt->adapt(elemental_error);
13969 n_refined+=mmesh_pt->nrefined();
13970 n_unrefined+=mmesh_pt->nunrefined();
13976 oomph_info <<
"Time for complete mesh adaptation " 13977 <<
"(but excluding comp of error estimate): " 13978 << t_end-t_start << std::endl;
13985 oomph_info <<
"Info/Warning: Mesh adaptation is disabled." 13991 oomph_info <<
"Info/Warning: Mesh cannot be adapted." << std::endl;
14005 oomph_info <<
"Total time for actual adaptation " 14006 <<
"(all meshes; incl error estimates): " 14007 << t_end-t_start << std::endl;
14018 oomph_info <<
"Time for actions after adapt: " 14019 << t_end-t_start << std::endl;
14022 oomph_info <<
"About to start re-assigning eqn numbers " 14023 <<
"with Problem::assign_eqn_numbers() at end of " 14024 <<
"Problem::adapt().\n";
14029 << std::endl<< std::endl;
14035 oomph_info <<
"Time for re-assigning eqn numbers with " 14036 <<
"Problem::assign_eqn_numbers() at end of Problem::adapt(): " 14037 << t_end-t_start << std::endl;
14039 << t_end-t_start_total << std::endl;
14057 double t_start_total = 0.0;
14067 if(bifurcation_type!=0)
14075 oomph_info <<
"p-adapting problem:" << std::endl;
14076 oomph_info <<
"===================" << std::endl;
14078 double t_start = 0.0;
14087 double t_end = 0.0;
14091 oomph_info <<
"Time for actions before adapt: " 14092 << t_end-t_start << std::endl;
14109 dynamic_cast<RefineableMeshBase*>(
mesh_pt(0)))
14111 if (mmesh_pt->is_p_adaptation_enabled())
14117 spatial_error_estimator_pt();
14120 if (error_estimator_pt==0)
14123 "Error estimator hasn't been set yet",
14124 OOMPH_CURRENT_FUNCTION,
14125 OOMPH_EXCEPTION_LOCATION);
14132 if (mmesh_pt->doc_info_pt()==0)
14139 *mmesh_pt->doc_info_pt());
14143 mmesh_pt->max_error()=
14144 std::fabs(*std::max_element(elemental_error.begin(),
14147 mmesh_pt->min_error()=
14148 std::fabs(*std::min_element(elemental_error.begin(),
14152 << mmesh_pt->max_error() <<
" " 14153 << mmesh_pt->min_error()
14154 << std::endl << std::endl;
14161 << t_end-t_start << std::endl;
14166 mmesh_pt->p_adapt(elemental_error);
14169 n_refined+=mmesh_pt->nrefined();
14170 n_unrefined+=mmesh_pt->nunrefined();
14175 oomph_info <<
"Time for complete mesh adaptation " 14176 <<
"(but excluding comp of error estimate): " 14177 << t_end-t_start << std::endl;
14184 oomph_info <<
"Info/Warning: Mesh adaptation is disabled." << std::endl;
14189 oomph_info <<
"Info/Warning: Mesh cannot be adapted" << std::endl;
14198 for (
unsigned imesh=0;imesh<Nmesh;imesh++)
14202 dynamic_cast<RefineableMeshBase*>(
mesh_pt(imesh)))
14208 spatial_error_estimator_pt();
14211 if (error_estimator_pt==0)
14214 "Error estimator hasn't been set yet",
14215 OOMPH_CURRENT_FUNCTION,
14216 OOMPH_EXCEPTION_LOCATION);
14220 if (mmesh_pt->is_p_adaptation_enabled())
14224 if (mmesh_pt->doc_info_pt()==0)
14233 *mmesh_pt->doc_info_pt());
14239 mmesh_pt->max_error()=
14240 std::fabs(*std::max_element(elemental_error.begin(),
14241 elemental_error.end(),
14244 mmesh_pt->min_error()=
14245 std::fabs(*std::min_element(elemental_error.begin(),
14246 elemental_error.end(),
14251 << mmesh_pt->max_error() <<
" " 14252 << mmesh_pt->min_error() << std::endl;
14259 << t_end-t_start << std::endl;
14264 mmesh_pt->p_adapt(elemental_error);
14267 n_refined+=mmesh_pt->nrefined();
14268 n_unrefined+=mmesh_pt->nunrefined();
14274 oomph_info <<
"Time for complete mesh adaptation " 14275 <<
"(but excluding comp of error estimate): " 14276 << t_end-t_start << std::endl;
14283 oomph_info <<
"Info/Warning: Mesh adaptation is disabled." 14289 oomph_info <<
"Info/Warning: Mesh cannot be adapted." << std::endl;
14303 oomph_info <<
"Total time for actual adaptation " 14304 <<
"(all meshes; incl error estimates): " 14305 << t_end-t_start << std::endl;
14316 oomph_info <<
"Time for actions after adapt: " 14317 << t_end-t_start << std::endl;
14320 oomph_info <<
"About to start re-assigning eqn numbers " 14321 <<
"with Problem::assign_eqn_numbers() at end of " 14322 <<
"Problem::adapt().\n";
14327 << std::endl<< std::endl;
14333 oomph_info <<
"Time for re-assigning eqn numbers with " 14334 <<
"Problem::assign_eqn_numbers() at end of Problem::adapt(): " 14335 << t_end-t_start << std::endl;
14337 << t_end-t_start_total << std::endl;
14353 unsigned &n_unrefined,
14358 oomph_info <<
"Adapting problem:" << std::endl;
14359 oomph_info <<
"=================" << std::endl;
14379 if (mmesh_pt->is_adaptation_enabled())
14382 mmesh_pt->adapt(elemental_error[0]);
14385 n_refined += mmesh_pt->nrefined();
14386 n_unrefined += mmesh_pt->nunrefined();
14391 oomph_info <<
"Info/Warning: Mesh adaptation is disabled." 14397 oomph_info <<
"Info/Warning: Mesh cannot be adapted" << std::endl;
14407 for (
unsigned imesh=0;imesh<Nmesh;imesh++)
14413 if (mmesh_pt->is_adaptation_enabled())
14416 mmesh_pt->adapt(elemental_error[imesh]);
14419 n_refined += mmesh_pt->nrefined();
14420 n_unrefined += mmesh_pt->nunrefined();
14424 oomph_info <<
"Info/Warning: Mesh adaptation is disabled." 14430 oomph_info <<
"Info/Warning: Mesh cannot be adapted." << std::endl;
14445 << std::endl<< std::endl;
14465 elemental_error.resize(1);
14471 if(mmesh_pt->is_adaptation_enabled())
14475 spatial_error_estimator_pt();
14478 if (error_estimator_pt==0)
14481 "Error estimator hasn't been set yet",
14482 OOMPH_CURRENT_FUNCTION,
14483 OOMPH_EXCEPTION_LOCATION);
14488 elemental_error[0].resize(mmesh_pt->nelement());
14490 if(mmesh_pt->doc_info_pt()==0)
14493 elemental_error[0]);
14498 elemental_error[0],
14499 *mmesh_pt->doc_info_pt());
14503 mmesh_pt->max_error()=
14504 std::fabs(*std::max_element(elemental_error[0].begin(),
14507 mmesh_pt->min_error()=
14508 std::fabs(*std::min_element(elemental_error[0].begin(),
14512 << mmesh_pt->max_error() <<
" " 14513 << mmesh_pt->min_error() << std::endl;
14517 oomph_info <<
"Info/Warning: Mesh adaptation is disabled." 14523 oomph_info <<
"Info/Warning: Mesh cannot be adapted" << std::endl;
14533 elemental_error.resize(Nmesh);
14536 for (
unsigned imesh=0;imesh<Nmesh;imesh++)
14544 spatial_error_estimator_pt();
14547 if (error_estimator_pt==0)
14550 "Error estimator hasn't been set yet",
14551 OOMPH_CURRENT_FUNCTION,
14552 OOMPH_EXCEPTION_LOCATION);
14556 if (mmesh_pt->is_adaptation_enabled())
14559 elemental_error[imesh].resize(mmesh_pt->nelement());
14560 if (mmesh_pt->doc_info_pt()==0)
14563 elemental_error[imesh]);
14568 elemental_error[imesh],
14569 *mmesh_pt->doc_info_pt());
14573 mmesh_pt->max_error()=
14574 std::fabs(*std::max_element(elemental_error[imesh].begin(),
14575 elemental_error[imesh].end(),
14578 mmesh_pt->min_error()=
14579 std::fabs(*std::min_element(elemental_error[imesh].begin(),
14580 elemental_error[imesh].end(),
14584 << mmesh_pt->max_error() <<
" " 14585 << mmesh_pt->min_error() << std::endl;
14589 oomph_info <<
"Info/Warning: Mesh adaptation is disabled." 14595 oomph_info <<
"Info/Warning: Mesh cannot be adapted." << std::endl;
14611 if(bifurcation_type!=0)
14627 dynamic_cast<RefineableMeshBase*>(
mesh_pt(0)))
14632 spatial_error_estimator_pt();
14635 if (error_estimator_pt==0)
14638 "Error estimator hasn't been set yet",
14639 OOMPH_CURRENT_FUNCTION,
14640 OOMPH_EXCEPTION_LOCATION);
14659 mmesh_pt->max_error()=
14660 std::fabs(*std::max_element(elemental_error.begin(),
14663 mmesh_pt->min_error()=
14664 std::fabs(*std::min_element(elemental_error.begin(),
14668 << mmesh_pt->max_error() <<
" " 14669 << mmesh_pt->min_error() << std::endl;
14680 for (
unsigned imesh=0;imesh<Nmesh;imesh++)
14685 dynamic_cast<RefineableMeshBase*>(
mesh_pt(imesh)))
14690 spatial_error_estimator_pt();
14693 if (error_estimator_pt==0)
14696 "Error estimator hasn't been set yet",
14697 OOMPH_CURRENT_FUNCTION,
14698 OOMPH_EXCEPTION_LOCATION);
14704 if (mmesh_pt->doc_info_pt()==0)
14713 *mmesh_pt->doc_info_pt());
14719 mmesh_pt->max_error()=
14720 std::fabs(*std::max_element(elemental_error.begin(),
14723 mmesh_pt->min_error()=
14724 std::fabs(*std::min_element(elemental_error.begin(),
14729 << mmesh_pt->max_error() <<
" " 14730 << mmesh_pt->min_error() << std::endl;
14745 elements_to_be_refined)
14757 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(0)))
14759 mmesh_pt->refine_selected_elements(elements_to_be_refined);
14763 oomph_info <<
"Info/Warning: Mesh cannot be refined " 14770 std::ostringstream error_message;
14771 error_message <<
"Problem::refine_selected_elements(...) only works for\n" 14772 <<
"multiple-mesh problems if you specify the mesh\n" 14773 <<
"number in the function argument before the Vector,\n" 14774 <<
"or a Vector of Vectors for each submesh.\n" 14777 OOMPH_CURRENT_FUNCTION,
14778 OOMPH_EXCEPTION_LOCATION);
14794 elements_to_be_refined_pt)
14806 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(0)))
14808 mmesh_pt->refine_selected_elements(elements_to_be_refined_pt);
14812 oomph_info <<
"Info/Warning: Mesh cannot be refined " 14819 std::ostringstream error_message;
14820 error_message <<
"Problem::refine_selected_elements(...) only works for\n" 14821 <<
"multiple-mesh problems if you specify the mesh\n" 14822 <<
"number in the function argument before the Vector,\n" 14823 <<
"or a Vector of Vectors for each submesh.\n" 14826 OOMPH_CURRENT_FUNCTION,
14827 OOMPH_EXCEPTION_LOCATION);
14844 elements_to_be_refined)
14851 if (i_mesh>=n_mesh)
14853 std::ostringstream error_message;
14855 "Problem only has " << n_mesh <<
" submeshes. Cannot refine submesh " 14856 << i_mesh << std::endl;
14858 OOMPH_CURRENT_FUNCTION,
14859 OOMPH_EXCEPTION_LOCATION);
14864 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(i_mesh)))
14866 mmesh_pt->refine_selected_elements(elements_to_be_refined);
14870 oomph_info <<
"Info/Warning: Mesh cannot be refined " 14895 elements_to_be_refined_pt)
14902 if (i_mesh>=n_mesh)
14904 std::ostringstream error_message;
14906 "Problem only has " << n_mesh <<
" submeshes. Cannot refine submesh " 14907 << i_mesh << std::endl;
14909 OOMPH_CURRENT_FUNCTION,
14910 OOMPH_EXCEPTION_LOCATION);
14915 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(i_mesh)))
14917 mmesh_pt->refine_selected_elements(elements_to_be_refined_pt);
14921 oomph_info <<
"Info/Warning: Mesh cannot be refined " 14945 elements_to_be_refined)
14953 for (
unsigned i_mesh=0; i_mesh<n_mesh; i_mesh++)
14956 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(i_mesh)))
14958 mmesh_pt->refine_selected_elements(elements_to_be_refined[i_mesh]);
14962 oomph_info <<
"Info/Warning: Mesh cannot be refined " 14985 elements_to_be_refined_pt)
14993 for (
unsigned i_mesh=0; i_mesh<n_mesh; i_mesh++)
14996 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(i_mesh)))
14998 mmesh_pt->refine_selected_elements(elements_to_be_refined_pt[i_mesh]);
15002 oomph_info <<
"Info/Warning: Mesh cannot be refined " 15024 elements_to_be_refined)
15036 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(0)))
15038 mmesh_pt->p_refine_selected_elements(elements_to_be_refined);
15042 oomph_info <<
"Info/Warning: Mesh cannot be refined " 15049 std::ostringstream error_message;
15050 error_message <<
"Problem::p_refine_selected_elements(...) only works for\n" 15051 <<
"multiple-mesh problems if you specify the mesh\n" 15052 <<
"number in the function argument before the Vector,\n" 15053 <<
"or a Vector of Vectors for each submesh.\n" 15056 OOMPH_CURRENT_FUNCTION,
15057 OOMPH_EXCEPTION_LOCATION);
15073 elements_to_be_refined_pt)
15085 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(0)))
15087 mmesh_pt->p_refine_selected_elements(elements_to_be_refined_pt);
15091 oomph_info <<
"Info/Warning: Mesh cannot be refined " 15098 std::ostringstream error_message;
15099 error_message <<
"Problem::p_refine_selected_elements(...) only works for\n" 15100 <<
"multiple-mesh problems if you specify the mesh\n" 15101 <<
"number in the function argument before the Vector,\n" 15102 <<
"or a Vector of Vectors for each submesh.\n" 15105 OOMPH_CURRENT_FUNCTION,
15106 OOMPH_EXCEPTION_LOCATION);
15123 elements_to_be_refined)
15126 "p-refinement for multiple submeshes has not yet been tested.",
15127 "Problem::p_refine_selected_elements()",
15128 OOMPH_EXCEPTION_LOCATION);
15135 if (i_mesh>=n_mesh)
15137 std::ostringstream error_message;
15139 "Problem only has " << n_mesh <<
" submeshes. Cannot p-refine submesh " 15140 << i_mesh << std::endl;
15142 OOMPH_CURRENT_FUNCTION,
15143 OOMPH_EXCEPTION_LOCATION);
15148 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(i_mesh)))
15150 mmesh_pt->p_refine_selected_elements(elements_to_be_refined);
15154 oomph_info <<
"Info/Warning: Mesh cannot be refined " 15179 elements_to_be_refined_pt)
15182 "p-refinement for multiple submeshes has not yet been tested.",
15183 "Problem::p_refine_selected_elements()",
15184 OOMPH_EXCEPTION_LOCATION);
15191 if (i_mesh>=n_mesh)
15193 std::ostringstream error_message;
15195 "Problem only has " << n_mesh <<
" submeshes. Cannot p-refine submesh " 15196 << i_mesh << std::endl;
15198 OOMPH_CURRENT_FUNCTION,
15199 OOMPH_EXCEPTION_LOCATION);
15204 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(i_mesh)))
15206 mmesh_pt->p_refine_selected_elements(elements_to_be_refined_pt);
15210 oomph_info <<
"Info/Warning: Mesh cannot be refined " 15234 elements_to_be_refined)
15237 "p-refinement for multiple submeshes has not yet been tested.",
15238 "Problem::p_refine_selected_elements()",
15239 OOMPH_EXCEPTION_LOCATION);
15247 for (
unsigned i_mesh=0; i_mesh<n_mesh; i_mesh++)
15250 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(i_mesh)))
15252 mmesh_pt->p_refine_selected_elements(elements_to_be_refined[i_mesh]);
15256 oomph_info <<
"Info/Warning: Mesh cannot be refined " 15279 elements_to_be_refined_pt)
15282 "p-refinement for multiple submeshes has not yet been tested.",
15283 "Problem::p_refine_selected_elements()",
15284 OOMPH_EXCEPTION_LOCATION);
15292 for (
unsigned i_mesh=0; i_mesh<n_mesh; i_mesh++)
15295 dynamic_cast<TreeBasedRefineableMeshBase*>(
mesh_pt(i_mesh)))
15297 mmesh_pt->p_refine_selected_elements(elements_to_be_refined_pt[i_mesh]);
15301 oomph_info <<
"Info/Warning: Mesh cannot be refined " 15330 double t_start = 0.0;
15338 double t_end = 0.0;
15343 <<
"Time for actions before adapt in Problem::refine_uniformly_aux(): " 15344 << t_end-t_start << std::endl;
15356 dynamic_cast<RefineableMeshBase*>(
mesh_pt(0)))
15358 unsigned nref=nrefine_for_mesh[0];
15359 for (
unsigned i=0;
i<nref;
i++)
15361 mmesh_pt->refine_uniformly(doc_info);
15366 oomph_info <<
"Info/Warning: Mesh cannot be refined uniformly " 15374 for (
unsigned imesh=0;imesh<n_mesh;imesh++)
15378 dynamic_cast<RefineableMeshBase*>(
mesh_pt(imesh)))
15380 unsigned nref=nrefine_for_mesh[imesh];
15381 for (
unsigned i=0;
i<nref;
i++)
15383 mmesh_pt->refine_uniformly(doc_info);
15388 oomph_info <<
"Info/Warning: Cannot refine mesh " << imesh
15400 <<
"Time for mesh-level mesh refinement in " 15401 <<
"Problem::refine_uniformly_aux(): " 15402 << t_end-t_start << std::endl;
15414 <<
"Time for actions after adapt Problem::refine_uniformly_aux(): " 15415 << t_end-t_start << std::endl;
15420 #ifdef OOMPH_HAS_MPI 15434 <<
"Time for Problem::prune_halo_elements_and_nodes() in " 15435 <<
"Problem::refine_uniformly_aux(): " 15436 << t_end-t_start << std::endl;
15443 std::ostringstream error_message;
15445 <<
"Requested pruning in serial build. Ignoring the request.\n";
15447 "Problem::refine_uniformly_aux()",
15448 OOMPH_EXCEPTION_LOCATION);
15453 oomph_info <<
"Number of equations after Problem::refine_uniformly_aux(): " 15460 <<
"Time for Problem::assign_eqn_numbers() in " 15461 <<
"Problem::refine_uniformly_aux(): " 15462 << t_end-t_start << std::endl;
15481 double t_start = 0.0;
15489 double t_end = 0.0;
15494 <<
"Time for actions before adapt in Problem::p_refine_uniformly_aux(): " 15495 << t_end-t_start << std::endl;
15507 dynamic_cast<RefineableMeshBase*>(
mesh_pt(0)))
15509 unsigned nref=nrefine_for_mesh[0];
15510 for (
unsigned i=0;
i<nref;
i++)
15512 mmesh_pt->p_refine_uniformly(doc_info);
15517 oomph_info <<
"Info/Warning: Mesh cannot be p-refined uniformly " 15525 "p-refinement for multiple submeshes has not yet been tested.",
15526 "Problem::p_refine_uniformly_aux()",
15527 OOMPH_EXCEPTION_LOCATION);
15530 for (
unsigned imesh=0;imesh<n_mesh;imesh++)
15534 dynamic_cast<RefineableMeshBase*>(
mesh_pt(imesh)))
15536 unsigned nref=nrefine_for_mesh[imesh];
15537 for (
unsigned i=0;
i<nref;
i++)
15539 mmesh_pt->p_refine_uniformly(doc_info);
15544 oomph_info <<
"Info/Warning: Cannot p-refine mesh " << imesh
15556 <<
"Time for mesh-level mesh refinement in " 15557 <<
"Problem::p_refine_uniformly_aux(): " 15558 << t_end-t_start << std::endl;
15570 <<
"Time for actions after adapt Problem::p_refine_uniformly_aux(): " 15571 << t_end-t_start << std::endl;
15576 #ifdef OOMPH_HAS_MPI 15590 <<
"Time for Problem::prune_halo_elements_and_nodes() in " 15591 <<
"Problem::p_refine_uniformly_aux(): " 15592 << t_end-t_start << std::endl;
15599 std::ostringstream error_message;
15601 <<
"Requested pruning in serial build. Ignoring the request.\n";
15603 "Problem::p_refine_uniformly_aux()",
15604 OOMPH_EXCEPTION_LOCATION);
15609 oomph_info <<
"Number of equations after Problem::p_refine_uniformly_aux(): " 15616 <<
"Time for Problem::assign_eqn_numbers() in " 15617 <<
"Problem::p_refine_uniformly_aux(): " 15618 << t_end-t_start << std::endl;
15637 std::ostringstream error_message;
15638 error_message <<
"imesh " << i_mesh
15639 <<
" is greater than the number of sub meshes " 15643 OOMPH_CURRENT_FUNCTION,
15644 OOMPH_EXCEPTION_LOCATION);
15650 dynamic_cast<RefineableMeshBase*>(
mesh_pt(i_mesh)))
15652 mmesh_pt->refine_uniformly(doc_info);
15656 oomph_info <<
"Info/Warning: Mesh cannot be refined uniformly " 15685 std::ostringstream error_message;
15686 error_message <<
"imesh " << i_mesh
15687 <<
" is greater than the number of sub meshes " 15691 OOMPH_CURRENT_FUNCTION,
15692 OOMPH_EXCEPTION_LOCATION);
15698 dynamic_cast<RefineableMeshBase*>(
mesh_pt(i_mesh)))
15700 mmesh_pt->p_refine_uniformly(doc_info);
15704 oomph_info <<
"Info/Warning: Mesh cannot be refined uniformly " 15733 unsigned success_flag=0;
15743 dynamic_cast<RefineableMeshBase*>(
mesh_pt(0)))
15745 success_flag+=mmesh_pt->unrefine_uniformly();
15749 oomph_info <<
"Info/Warning: Mesh cannot be unrefined uniformly " 15757 for (
unsigned imesh=0;imesh<n_mesh;imesh++)
15761 dynamic_cast<RefineableMeshBase*>(
mesh_pt(imesh)))
15763 success_flag+=mmesh_pt->unrefine_uniformly();
15767 oomph_info <<
"Info/Warning: Cannot unrefine mesh " << imesh
15783 if (success_flag>0)
15805 unsigned success_flag=0;
15811 std::ostringstream error_message;
15812 error_message <<
"imesh " << i_mesh
15813 <<
" is greater than the number of sub meshes " 15817 OOMPH_CURRENT_FUNCTION,
15818 OOMPH_EXCEPTION_LOCATION);
15824 dynamic_cast<RefineableMeshBase*>(
mesh_pt(i_mesh)))
15826 success_flag+=mmesh_pt->unrefine_uniformly();
15830 oomph_info <<
"Info/Warning: Mesh cannot be unrefined uniformly " 15845 if (success_flag>0)
15873 dynamic_cast<RefineableMeshBase*>(
mesh_pt(0)))
15875 mmesh_pt->p_unrefine_uniformly(doc_info);
15879 oomph_info <<
"Info/Warning: Mesh cannot be p-unrefined uniformly " 15887 throw OomphLibError(
"This functionality has not yet been tested.",
15888 OOMPH_CURRENT_FUNCTION,
15889 OOMPH_EXCEPTION_LOCATION);
15891 for (
unsigned imesh=0;imesh<n_mesh;imesh++)
15895 dynamic_cast<RefineableMeshBase*>(
mesh_pt(imesh)))
15897 mmesh_pt->p_unrefine_uniformly(doc_info);
15901 oomph_info <<
"Info/Warning: Cannot p-unrefine mesh " << imesh
15931 std::ostringstream error_message;
15932 error_message <<
"imesh " << i_mesh
15933 <<
" is greater than the number of sub meshes " 15937 OOMPH_CURRENT_FUNCTION,
15938 OOMPH_EXCEPTION_LOCATION);
15944 dynamic_cast<RefineableMeshBase*>(
mesh_pt(i_mesh)))
15946 mmesh_pt->p_unrefine_uniformly(doc_info);
15950 oomph_info <<
"Info/Warning: Mesh cannot be p-unrefined uniformly " 15980 const unsigned &max_adapt,
15981 const bool &first_timestep,
15987 bool shift_it=shift;
15990 if (first_timestep && (!shift)
15995 <<
"\n\n===========================================================\n";
15996 oomph_info <<
" ******** WARNING *********** \n";
15998 <<
"===========================================================\n";
15999 oomph_info <<
"Problem::unsteady_newton_solve() called with " << std::endl;
16000 oomph_info <<
"first_timestep: " << first_timestep << std::endl;
16001 oomph_info <<
"shift: " << shift << std::endl;
16002 oomph_info <<
"This doesn't make sense (shifting does have to be done" 16005 <<
"since we're constantly re-assigning the initial conditions" 16008 <<
"\n===========================================================\n\n";
16016 unsigned max_solve=max_adapt+1;
16020 for (
unsigned isolve=0;isolve<max_solve;isolve++)
16025 unsigned n_refined;
16026 unsigned n_unrefined;
16029 adapt(n_refined,n_unrefined);
16031 #ifdef OOMPH_HAS_MPI 16034 unsigned total_refined=0;
16035 unsigned total_unrefined=0;
16038 MPI_Allreduce(&n_refined,&total_refined,1,MPI_UNSIGNED,MPI_SUM,
16040 n_refined=total_refined;
16041 MPI_Allreduce(&n_unrefined,&total_unrefined,1,MPI_UNSIGNED,MPI_SUM,
16043 n_unrefined=total_unrefined;
16047 oomph_info <<
"---> " << n_refined <<
" elements were refined, and " 16048 << n_unrefined <<
" were unrefined, in total." << std::endl;
16051 if ((n_refined==0)&&(n_unrefined==0))
16053 oomph_info <<
"\n \n Solution is fully converged in " 16054 <<
"Problem::unsteady_newton_solver() \n \n ";
16064 if (first_timestep)
16069 oomph_info <<
"Re-setting initial condition " << std::endl;
16086 if((isolve==0) || (first_timestep))
16097 if (isolve==max_solve-1)
16100 <<
"----------------------------------------------------------" 16102 <<
"Reached max. number of adaptations in \n" 16103 <<
"Problem::unsteady_newton_solver().\n" 16104 <<
"----------------------------------------------------------" 16127 unsigned max_solve=max_adapt+1;
16131 for (
unsigned isolve=0;isolve<max_solve;isolve++)
16138 unsigned n_refined;
16139 unsigned n_unrefined;
16142 adapt(n_refined,n_unrefined);
16144 #ifdef OOMPH_HAS_MPI 16147 unsigned total_refined=0;
16148 unsigned total_unrefined=0;
16151 MPI_Allreduce(&n_refined,&total_refined,1,MPI_UNSIGNED,MPI_SUM,
16153 n_refined=total_refined;
16154 MPI_Allreduce(&n_unrefined,&total_unrefined,1,MPI_UNSIGNED,MPI_SUM,
16156 n_unrefined=total_unrefined;
16160 oomph_info <<
"---> " << n_refined <<
" elements were refined, and " 16162 <<
" were unrefined" 16163 #ifdef OOMPH_HAS_MPI 16164 <<
", in total (over all processors).\n";
16171 if ((n_refined==0)&&(n_unrefined==0))
16173 oomph_info <<
"\n \n Solution is fully converged in " 16174 <<
"Problem::newton_solver(). \n \n ";
16197 <<
"USER-DEFINED ERROR IN NEWTON SOLVER " << std::endl;
16201 oomph_info <<
"MAXIMUM NUMBER OF ITERATIONS (" 16203 <<
") REACHED WITHOUT CONVERGENCE " << std::endl;
16209 <<
"EXCEEDS PREDEFINED MAXIMUM " 16215 std::ostringstream error_stream;
16216 error_stream <<
"Error occured in adaptive Newton solver. " 16219 OOMPH_CURRENT_FUNCTION,
16220 OOMPH_EXCEPTION_LOCATION);
16230 if (isolve==max_solve-1)
16234 <<
"----------------------------------------------------------" 16236 <<
"Reached max. number of adaptations in \n" 16237 <<
"Problem::newton_solver().\n" 16238 <<
"----------------------------------------------------------" 16239 << std::endl << std::endl;
16263 for (
unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
16271 #ifdef OOMPH_HAS_MPI 16292 for(
unsigned imesh=0;imesh<n_mesh;++imesh)
16314 oomph_info <<
"Checking halo schemes on single mesh" << std::endl;
16315 doc_info.
label()=
"_one_and_only_mesh_";
16321 for (
unsigned i_mesh=0; i_mesh<n_mesh; i_mesh++)
16323 oomph_info <<
"Checking halo schemes on submesh " << i_mesh << std::endl;
16324 std::stringstream tmp;
16325 tmp <<
"_mesh" << i_mesh <<
"_";
16326 doc_info.
label()=tmp.str();
16342 bool do_halos=
true;
16343 bool do_external_halos=
false;
16348 do_external_halos=
true;
16364 const bool& do_external_halos)
16367 unsigned n_mesh_loop=1;
16378 if(n_proc==1) {
return;}
16392 for(
int rank=0;rank<n_proc;rank++)
16395 send_displacement[rank] = send_data.size();
16402 Mesh* my_mesh_pt=0;
16405 for (
unsigned imesh=0;imesh<n_mesh_loop;imesh++)
16421 for (
unsigned n=0;n<n_nod;n++)
16431 unsigned nelem_haloed=haloed_elem_pt.size();
16432 for (
unsigned e=0;
e<nelem_haloed;
e++)
16434 haloed_elem_pt[
e]->
16435 add_internal_data_values_to_vector(send_data);
16439 if (do_external_halos)
16444 for (
unsigned n=0;n<n_ext_nod;n++)
16448 add_values_to_vector(send_data);
16453 for (
unsigned e=0;
e<next_elem_haloed;
e++)
16456 add_internal_data_values_to_vector(send_data);
16464 send_n[rank] = send_data.size() - send_displacement[rank];
16473 MPI_Alltoall(&send_n[0],1,MPI_INT,&receive_n[0],1,MPI_INT,
16479 int receive_data_count=0;
16480 for(
int rank=0;rank<n_proc;++rank)
16483 receive_displacement[rank] = receive_data_count;
16484 receive_data_count += receive_n[rank];
16489 if(receive_data_count==0) {++receive_data_count;}
16494 if(send_data.size()==0) {send_data.resize(1);}
16497 MPI_Alltoallv(&send_data[0],&send_n[0],&send_displacement[0],
16499 &receive_data[0],&receive_n[0],
16500 &receive_displacement[0],
16505 for (
int send_rank=0;send_rank<n_proc;send_rank++)
16509 if((send_rank != my_rank) && (receive_n[send_rank] != 0))
16512 unsigned count=receive_displacement[send_rank];
16515 Mesh* my_mesh_pt=0;
16518 for (
unsigned imesh=0;imesh<n_mesh_loop;imesh++)
16533 unsigned n_nod=my_mesh_pt->
nhalo_node(send_rank);
16534 for (
unsigned n=0;n<n_nod;n++)
16538 read_values_from_vector(receive_data,count);
16544 halo_element_pt(send_rank);
16546 unsigned nelem_halo=halo_elem_pt.size();
16547 for (
unsigned e=0;
e<nelem_halo;
e++)
16550 read_internal_data_values_from_vector(receive_data,count);
16554 if (do_external_halos)
16562 for (
unsigned n=0;n<n_ext_nod;n++)
16566 read_values_from_vector(receive_data,count);
16572 for (
unsigned e=0;
e<next_elem_halo;
e++)
16575 read_internal_data_values_from_vector(receive_data,count);
16593 unsigned my_n_eqn =
Dof_pt.size();
16618 unsigned n_send = nproc-my_rank-1;
16620 for (
unsigned p = my_rank+1; p < nproc; p++)
16622 MPI_Isend(&my_n_eqn,1,MPI_UNSIGNED,p,0,
16628 for (
unsigned p = 0; p < my_rank; p++)
16630 MPI_Recv(&n_eqn_on_proc[p],1,MPI_UNSIGNED,p,0,
16634 double t_end = 0.0;
16638 oomph_info <<
"Time for send and receive stuff: " 16639 << t_end-t_start << std::endl;
16645 unsigned my_eqn_num_base = 0;
16646 for (
unsigned p = 0; p < my_rank; p++)
16648 my_eqn_num_base += n_eqn_on_proc[p];
16660 for (
unsigned e=0;
e<nelem;
e++)
16665 for (
unsigned iintern=0;iintern<nintern_data;iintern++)
16668 unsigned nval=int_data_pt->
nvalue();
16669 for (
unsigned ival=0;ival<nval;ival++)
16671 int old_eqn_number=int_data_pt->
eqn_number(ival);
16672 if (old_eqn_number>=0)
16675 int new_eqn_number=old_eqn_number+my_eqn_num_base;
16676 int_data_pt->
eqn_number(ival)=new_eqn_number;
16685 for (
unsigned j=0;j<nnod;j++)
16690 unsigned nval=nod_pt->
nvalue();
16692 for (
unsigned ival=0;ival<nval;ival++)
16694 int old_eqn_number=nod_pt->
eqn_number(ival);
16696 if (old_eqn_number>=0)
16699 int new_eqn_number=old_eqn_number+my_eqn_num_base;
16707 if (solid_nod_pt!=0)
16711 for (
unsigned ival=0;ival<nval;ival++)
16717 if (old_eqn_number>=0)
16720 int new_eqn_number=old_eqn_number+my_eqn_num_base;
16731 << t_end-t_start << std::endl;
16739 bool do_halos=
true;
16740 bool do_external_halos=
false;
16746 oomph_info <<
"Time for copy_haloed_eqn_numbers_helper for halos: " 16747 << t_end-t_start << std::endl;
16753 do_external_halos=
true;
16759 oomph_info <<
"Time for copy_haloed_eqn_numbers_helper for external halos: " 16760 << t_end-t_start << std::endl;
16768 if (assign_local_eqn_numbers)
16780 for (
unsigned i=0;
i<n_sub_mesh;
i++)
16790 oomph_info <<
"Time for assign_local_eqn_numbers in sync: " 16791 << t_end-t_start << std::endl;
16799 MPI_Waitall(n_send,&send_req[0],&send_status[0]);
16806 << t_end-t_start << std::endl;
16827 const bool& do_external_halos)
16830 unsigned n_mesh_loop=1;
16841 if(n_proc==1) {
return;}
16853 for (
int rank=0;rank<n_proc;rank++)
16856 send_displacement[rank] = send_data.size();
16864 Mesh* my_mesh_pt=0;
16867 for (
unsigned imesh=0;imesh<n_mesh_loop;imesh++)
16882 for (
unsigned n=0;n<n_nod;n++)
16885 add_eqn_numbers_to_vector(send_data);
16892 unsigned nelem_haloed=haloed_elem_pt.size();
16893 for (
unsigned e=0;
e<nelem_haloed;
e++)
16895 haloed_elem_pt[
e]->add_internal_eqn_numbers_to_vector(send_data);
16899 if (do_external_halos)
16903 for (
unsigned n=0;n<n_ext_nod;n++)
16906 add_eqn_numbers_to_vector(send_data);
16912 for (
unsigned e=0;
e<next_elem_haloed;
e++)
16916 add_internal_eqn_numbers_to_vector(send_data);
16924 send_n[rank] = send_data.size() - send_displacement[rank];
16931 MPI_Alltoall(&send_n[0],1,MPI_INT,&receive_n[0],1,MPI_INT,
16937 int receive_data_count=0;
16938 for(
int rank=0;rank<n_proc;++rank)
16941 receive_displacement[rank] = receive_data_count;
16942 receive_data_count += receive_n[rank];
16947 if(receive_data_count==0) {++receive_data_count;}
16952 if(send_data.size()==0) {send_data.resize(1);}
16955 MPI_Alltoallv(&send_data[0],&send_n[0],&send_displacement[0],
16957 &receive_data[0],&receive_n[0],
16958 &receive_displacement[0],
16965 for (
int send_rank=0;send_rank<n_proc;send_rank++)
16969 if((send_rank!=my_rank) && (receive_n[send_rank] != 0))
16972 unsigned count = receive_displacement[send_rank];
16975 Mesh* my_mesh_pt=0;
16978 for (
unsigned imesh=0;imesh<n_mesh_loop;imesh++)
16993 unsigned n_nod=my_mesh_pt->
nhalo_node(send_rank);
16994 for (
unsigned n=0;n<n_nod;n++)
16998 read_eqn_numbers_from_vector(receive_data,count);
17004 halo_element_pt(send_rank);
17005 unsigned nelem_halo=halo_elem_pt.size();
17006 for (
unsigned e=0;
e<nelem_halo;
e++)
17009 read_internal_eqn_numbers_from_vector(receive_data,count);
17013 if (do_external_halos)
17018 for (
unsigned n=0;n<n_ext_nod;n++)
17021 read_eqn_numbers_from_vector(receive_data,count);
17027 for (
unsigned e=0;
e<next_elem_halo;
e++)
17030 read_internal_eqn_numbers_from_vector(receive_data,count);
17047 const bool& report_stats,
17049 input_target_domain_for_local_non_halo_element)
17061 std::ostringstream warn_message;
17062 warn_message <<
"WARNING: You've tried to load balance a problem over\n" 17063 <<
"only one processor: ignoring your request.\n";
17065 "Problem::load_balance()",
17066 OOMPH_EXCEPTION_LOCATION);
17076 std::ostringstream error_stream;
17077 error_stream <<
"You have called Problem::load_balance()\n" 17078 <<
"on a non-distributed problem. This doesn't\n" 17079 <<
"make sense -- go distribute your problem first." 17082 OOMPH_CURRENT_FUNCTION,
17083 OOMPH_EXCEPTION_LOCATION);
17087 double t_start=0.0;
double t_metis=0.0;
double t_partition=0.0;
17088 double t_distribute=0.0;
double t_refine=0.0;
double t_copy_solution=0.0;
17097 unsigned old_ndof=
ndof();
17109 old_mesh_pt.resize(1);
17115 old_mesh_pt.resize(n_mesh);
17116 for (
unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
17118 old_mesh_pt[i_mesh]=
mesh_pt(i_mesh);
17137 unsigned local_ntarget=
17138 input_target_domain_for_local_non_halo_element.size();
17139 unsigned global_ntarget=0;
17140 MPI_Allreduce(&local_ntarget,&global_ntarget,1,
17141 MPI_UNSIGNED,MPI_MAX,
17145 if (global_ntarget>0)
17147 target_domain_for_local_non_halo_element=
17148 input_target_domain_for_local_non_halo_element;
17158 unsigned objective=0;
17159 bool bypass_metis=
true;
17162 target_domain_for_local_non_halo_element,
17168 unsigned objective=0;
17171 target_domain_for_local_non_halo_element);
17181 std::map<GeneralisedElement*,unsigned>
17182 target_domain_for_local_non_halo_element_map;
17184 unsigned count_non_halo_el=0;
17185 for (
unsigned e=0;
e<n_elem;
e++)
17190 target_domain_for_local_non_halo_element_map[el_pt]=
17191 target_domain_for_local_non_halo_element[count_non_halo_el];
17192 count_non_halo_el++;
17207 target_domain_for_local_non_halo_element.clear();
17208 target_domain_for_local_non_halo_element.reserve(n_elem);
17209 count_non_halo_el=0;
17210 for (
unsigned e = 0;
e < n_elem;
e++)
17215 target_domain_for_local_non_halo_element.push_back(
17216 target_domain_for_local_non_halo_element_map[el_pt]);
17223 const unsigned n_old_sub_meshes=n_mesh;
17229 target_domain_for_local_non_halo_element_submesh(n_mesh);
17235 unsigned count_td = 0;
17236 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17241 for (
unsigned i = 0;
i < nsub_ele;
i++)
17249 const unsigned target_domain =
17250 target_domain_for_local_non_halo_element[count_td++];
17253 target_domain_for_local_non_halo_element_submesh[i_mesh].
17254 push_back(target_domain);
17262 const unsigned ntarget_domain =
17263 target_domain_for_local_non_halo_element.size();
17264 if (count_td != ntarget_domain)
17266 std::ostringstream error_stream;
17268 <<
"The number of nonhalo elements ("<<count_td<<
") found in (all)\n" 17269 <<
"the (sub)-mesh(es) is different from the number of target domains\n" 17270 <<
"(" << ntarget_domain <<
") for the nonhalo elements.\n" 17271 <<
"Please ensure that you called the rebuild_global_mesh() method " 17272 <<
"after the\npossible deletion of FaceElements in " 17273 <<
"actions_before_distribute()!!!\n\n";
17274 throw OomphLibError(error_stream.str(),
"Problem::load_balance()",
17275 OOMPH_EXCEPTION_LOCATION);
17292 std::vector<bool> is_unstructured_mesh;
17296 bool are_there_unstructured_meshes =
false;
17303 dynamic_cast<TriangleMeshBase*>(old_mesh_pt[0]))
17306 unstructured_mesh_pt.push_back(tri_mesh_pt);
17308 is_unstructured_mesh.push_back(
true);
17311 are_there_unstructured_meshes =
true;
17317 unstructured_mesh_pt.push_back(tri_mesh_pt);
17319 is_unstructured_mesh.push_back(
false);
17326 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17330 dynamic_cast<TriangleMeshBase*>(old_mesh_pt[i_mesh]))
17333 unstructured_mesh_pt.push_back(tri_mesh_pt);
17335 is_unstructured_mesh.push_back(
true);
17338 are_there_unstructured_meshes =
true;
17344 unstructured_mesh_pt.push_back(tri_mesh_pt);
17346 is_unstructured_mesh.push_back(
false);
17372 std::map<unsigned, Vector<unsigned> >
17373 flat_packed_refinement_info_for_root;
17376 unsigned max_refinement_level_overall=0;
17381 target_domain_for_local_non_halo_element_in_structured_mesh;
17385 if (!is_unstructured_mesh[0])
17387 const unsigned nele_mesh =
17388 target_domain_for_local_non_halo_element.size();
17389 for (
unsigned e = 0;
e < nele_mesh;
e++)
17391 const unsigned target_domain =
17392 target_domain_for_local_non_halo_element[
e];
17393 target_domain_for_local_non_halo_element_in_structured_mesh.
17394 push_back(target_domain);
17401 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
17404 if (!is_unstructured_mesh[i_mesh])
17406 const unsigned nele_sub_mesh =
17407 target_domain_for_local_non_halo_element_submesh[i_mesh].size();
17408 for (
unsigned e = 0;
e < nele_sub_mesh;
e++)
17410 const unsigned target_domain =
17411 target_domain_for_local_non_halo_element_submesh[i_mesh][
e];
17412 target_domain_for_local_non_halo_element_in_structured_mesh.
17413 push_back(target_domain);
17423 (target_domain_for_local_non_halo_element_in_structured_mesh,
17427 old_domain_for_base_element,
17428 new_domain_for_base_element,
17429 max_refinement_level_overall);
17433 old_domain_for_base_element,
17434 new_domain_for_base_element,
17435 max_refinement_level_overall,
17436 flat_packed_refinement_info_for_root);
17441 oomph_info <<
"CPU for partition calculation for roots: " 17442 << t_partition-t_metis << std::endl;
17454 Vector<unsigned> pruned_refinement_level(std::max(
int(n_old_sub_meshes),1));
17457 pruned_refinement_level[0]=0;
17460 if (ref_mesh_pt!=0)
17462 pruned_refinement_level[0]=
17471 if (!is_unstructured_mesh[0])
17473 delete old_mesh_pt[0];
17474 old_mesh_pt[0] = 0;
17481 for (
unsigned i_mesh=0;i_mesh<n_old_sub_meshes;i_mesh++)
17483 pruned_refinement_level[i_mesh]=0;
17486 if (ref_mesh_pt!=0)
17488 pruned_refinement_level[i_mesh]=
17497 if (!is_unstructured_mesh[i_mesh])
17499 delete old_mesh_pt[i_mesh];
17500 old_mesh_pt[i_mesh] = 0;
17517 bool some_mesh_has_been_pruned=
false;
17518 unsigned n=pruned_refinement_level.size();
17519 for (
unsigned i=0;
i<n;
i++)
17521 if (pruned_refinement_level[
i]>0) some_mesh_has_been_pruned=
true;
17530 if (some_mesh_has_been_pruned)
17545 if (ref_mesh_pt!=0)
17549 unsigned local_min_ref=0;
17550 unsigned local_max_ref=0;
17557 int int_local_min_ref=local_min_ref;
17560 int_local_min_ref=INT_MAX;
17563 MPI_Allreduce(&int_local_min_ref,&int_min_ref,1,
17568 unsigned min_ref=unsigned(int_min_ref);
17572 unsigned nref=pruned_refinement_level[0]-min_ref;
17573 oomph_info <<
"Refining one-and-only mesh uniformly " 17574 << nref <<
" times\n";
17575 for (
unsigned i=0;
i<nref;
i++)
17583 for (
unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
17587 if (ref_mesh_pt!=0)
17590 unsigned local_min_ref=0;
17591 unsigned local_max_ref=0;
17598 int int_local_min_ref=local_min_ref;
17601 int_local_min_ref=INT_MAX;
17604 MPI_Allreduce(&int_local_min_ref,&int_min_ref,1,
17609 unsigned min_ref=unsigned(int_min_ref);
17613 unsigned nref=pruned_refinement_level[i_mesh]-min_ref;
17614 oomph_info <<
"Refining sub-mesh " << i_mesh <<
" uniformly " 17615 << nref <<
" times\n";
17616 for (
unsigned i=0;
i<nref;
i++)
17657 for (
unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
17660 if (!is_unstructured_mesh[i_mesh])
17664 submesh_element_partition[i_mesh].resize(nsub_ele);
17665 for (
unsigned e=0;
e<nsub_ele;
e++)
17667 submesh_element_partition[i_mesh][
e]=
17668 new_domain_for_base_element[count++];
17674 const unsigned nnew_domain_for_base_element =
17675 new_domain_for_base_element.size();
17676 if (count != nnew_domain_for_base_element)
17678 std::ostringstream error_stream;
17680 <<
"The number of READ target domains for nonhalo elements\n" 17681 <<
" is (" << count <<
"), but the number of target domains for\n" 17682 <<
"nonhalo elements is ("<<nnew_domain_for_base_element<<
")!\n";
17683 throw OomphLibError(error_stream.str(),
"Problem::load_balance()",
17684 OOMPH_EXCEPTION_LOCATION);
17698 if (!is_unstructured_mesh[0])
17703 for (
unsigned e=0;
e<n_ele;
e++)
17716 unsigned nglobal_element = 0;
17717 for (
unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
17720 if (!is_unstructured_mesh[i_mesh])
17730 unsigned counter_base = 0;
17731 for (
unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
17734 if (!is_unstructured_mesh[i_mesh])
17737 for (
unsigned e=0;
e<n_ele;
e++)
17749 if (counter_base != nglobal_element)
17751 std::ostringstream error_stream;
17753 <<
"The number of global elements ("<<nglobal_element
17754 <<
") is not the same as the number of\nadded elements (" 17755 << counter_base <<
") to the Base_mesh_element_pt data " 17756 <<
"structure!!!\n\n";
17758 "Problem::load_balance()",
17759 OOMPH_EXCEPTION_LOCATION);
17761 #endif // #ifdef PARANOID 17776 std::map<unsigned, std::map<int,unsigned> > face_element_number;
17778 for (
unsigned e=0;
e<n_element;
e++)
17785 std::stringstream info;
17786 info <<
"================================================\n";
17787 info <<
"INFO: I've come across a FaceElement while \n";
17788 info <<
" load-balancing a problem. \n";
17789 info <<
"================================================\n";
17797 throw OomphLibError(
"Base_mesh_element_number_plus_one[...]=0",
17798 OOMPH_CURRENT_FUNCTION,
17799 OOMPH_EXCEPTION_LOCATION);
17804 face_element_number[e_bulk][face_index]=
e;
17815 if (!is_unstructured_mesh[0])
17818 if (
mesh_pt()->nelement()!=new_domain_for_base_element.size())
17820 std::ostringstream error_stream;
17821 error_stream <<
"Distributing one-and-only mesh containing " 17823 << new_domain_for_base_element.size()
17826 OOMPH_CURRENT_FUNCTION,
17827 OOMPH_EXCEPTION_LOCATION);
17833 oomph_info <<
"Distributing one and only mesh\n" 17834 <<
"------------------------------" << std::endl;
17839 bool overrule_keep_as_halo_element_status=
false;
17842 new_domain_for_base_element,
17843 deleted_element_pt,
17844 doc_info,report_stats,
17845 overrule_keep_as_halo_element_status);
17854 bool need_to_rebuild_mesh =
false;
17855 for (
unsigned i_mesh=0; i_mesh<n_mesh; i_mesh++)
17859 if (!is_unstructured_mesh[i_mesh])
17864 oomph_info <<
"Distributing submesh " << i_mesh <<
" of " 17865 << n_mesh <<
" in total\n" 17866 <<
"---------------------------------------------" 17871 doc_info.
number()=i_mesh;
17875 bool overrule_keep_as_halo_element_status=
false;
17877 submesh_element_partition[i_mesh],
17878 deleted_element_pt,
17879 doc_info,report_stats,
17880 overrule_keep_as_halo_element_status);
17883 need_to_rebuild_mesh =
true;
17889 if (need_to_rebuild_mesh)
17898 unsigned n_del=deleted_element_pt.size();
17899 for (
unsigned e=0;
e<n_del;
e++)
17909 if (some_mesh_has_been_pruned)
17916 if (ref_mesh_pt!=0)
17919 (deleted_element_pt,doc_info,report_stats);
17924 for (
unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
17928 if (ref_mesh_pt!=0)
17931 (deleted_element_pt,doc_info,report_stats);
17939 unsigned n_del=deleted_element_pt.size();
17940 for (
unsigned e=0;
e<n_del;
e++)
17956 oomph_info <<
"CPU for build and distribution of new mesh(es): " 17957 << t_distribute-t_partition << std::endl;
17977 new_domain_for_base_element,
17978 max_refinement_level_overall,
17979 flat_packed_refinement_info_for_root,
17980 refinement_info_for_root_elements);
17985 max_refinement_level_overall);
17990 oomph_info <<
"CPU for refinement of base mesh: " 17991 << t_refine-t_distribute << std::endl;
18014 send_displacement);
18018 if (are_there_unstructured_meshes)
18031 if (is_unstructured_mesh[0])
18036 this->
mesh_pt() = old_mesh_pt[0];
18041 std::ostringstream error_stream;
18043 <<
"The only one mesh in the problem is not an unstructured mesh,\n" 18044 <<
"but the flag 'are_there_unstructures_meshes' (" 18045 <<are_there_unstructured_meshes<<
") was turned on,\n" 18046 <<
"this is weird. Please check for any condition that may have\n" 18047 <<
"turned on this flag!!!!\n\n";
18048 throw OomphLibError(error_stream.str(),
"Problem::load_balance()",
18049 OOMPH_EXCEPTION_LOCATION);
18053 unstructured_mesh_pt[0]->
18054 load_balance(target_domain_for_local_non_halo_element);
18061 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
18063 if (is_unstructured_mesh[i_mesh])
18070 this->
mesh_pt(i_mesh) = old_mesh_pt[i_mesh];
18083 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
18085 if (is_unstructured_mesh[i_mesh])
18088 const unsigned n_element = old_mesh_pt[i_mesh]->nelement();
18094 if (n_element > 0 && is_unstructured_mesh[i_mesh])
18096 unstructured_mesh_pt[i_mesh]->load_balance(
18097 target_domain_for_local_non_halo_element_submesh[i_mesh]);
18112 oomph_info <<
"CPU for transferring solution to new mesh(es): " 18113 << t_copy_solution-t_refine << std::endl;
18115 << t_copy_solution-t_start << std::endl;
18131 <<
"Total number of elements on this processor after load balance: " 18135 <<
"Number of non-halo elements on this processor after load balance: " 18140 if (n_dof!=old_ndof)
18142 std::ostringstream error_stream;
18144 <<
"Number of dofs in load_balance() has changed from " 18145 << old_ndof <<
" to " << n_dof <<
"\n" 18146 <<
"Check that you've implemented any necessary actions_before/after\n" 18147 <<
"adapt/distribute functions, e.g. to pin redundant pressure dofs" 18150 OOMPH_CURRENT_FUNCTION,
18151 OOMPH_EXCEPTION_LOCATION);
18160 oomph_info <<
"Time for load_balance() [sec] : " 18161 << end_t-start_t << std::endl;
18172 const unsigned& max_refinement_level_overall,
18173 std::map<
unsigned,
Vector<unsigned> >& flat_packed_refinement_info_for_root,
18181 unsigned n_base_element=old_domain_for_base_element.size();
18182 refinement_info_for_root_elements.resize(n_base_element);
18186 std::map<unsigned,Vector<unsigned> > halo_domain_of_haloed_base_element;
18192 std::map<unsigned,Vector<unsigned> > halo_domains;
18196 unsigned max_mesh=std::max(n_sub_mesh,
unsigned(1));
18197 for (
unsigned i_mesh=0;i_mesh<max_mesh;i_mesh++)
18200 Mesh* my_mesh_pt=0;
18213 if (!(sub_mesh_pt!=0))
18218 for (
int p=0;p<n_proc;p++)
18222 unsigned nhaloed=haloed_elem_pt.size();
18223 for (
unsigned h=0;h<nhaloed;h++)
18230 throw OomphLibError(
"Base_mesh_element_number_plus_one[...]=0",
18231 OOMPH_CURRENT_FUNCTION,
18232 OOMPH_EXCEPTION_LOCATION);
18236 halo_domains[
e].push_back(p);
18249 std::map<unsigned, Vector<unsigned> > data_for_proc;
18259 for (
unsigned e=0;
e<n_base_element;
e++)
18268 if (
int(old_domain_for_base_element[
e])==my_rank)
18271 unsigned new_domain=new_domain_for_base_element[
e];
18274 nbase_elements_for_proc[new_domain]++;
18277 if (
int(new_domain)==my_rank)
18281 unsigned nhalo=halo_domains[
e].size();
18282 halo_domain_of_haloed_base_element[
e].resize(nhalo);
18283 for (
unsigned j=0;j<nhalo;j++)
18285 halo_domain_of_haloed_base_element[
e][j]=halo_domains[
e][j];
18289 refinement_info_for_root_elements[
e].
18290 resize(max_refinement_level_overall);
18294 unsigned n_additional_data=
18295 flat_packed_refinement_info_for_root[
e].size();
18299 unsigned n_tree_nodes=flat_packed_refinement_info_for_root[
e][0];
18302 unsigned local_count=1;
18305 for (
unsigned level=0; level<max_refinement_level_overall; level++)
18307 for (
unsigned ee=0; ee<n_tree_nodes; ee++)
18310 if (flat_packed_refinement_info_for_root[e][local_count]==1)
18315 if (flat_packed_refinement_info_for_root[e][local_count]==1)
18317 refinement_info_for_root_elements[
e][level].push_back(2);
18323 refinement_info_for_root_elements[
e][level].push_back(1);
18330 refinement_info_for_root_elements[
e][level].push_back(0);
18337 if (n_additional_data!=local_count)
18339 std::stringstream error_message;
18340 error_message <<
"Number of additional data: " << n_additional_data
18341 <<
" doesn't match that actually send: " << local_count
18344 OOMPH_CURRENT_FUNCTION,
18345 OOMPH_EXCEPTION_LOCATION);
18355 unsigned current_size=data_for_proc[new_domain].size();
18356 unsigned n_additional_data=flat_packed_refinement_info_for_root[
e].
18358 data_for_proc[new_domain].reserve(current_size+n_additional_data+2);
18361 count+=n_additional_data+2;
18364 data_for_proc[new_domain].push_back(e);
18368 data_for_proc[new_domain].push_back(n_additional_data);
18372 for (
unsigned j=0;j<n_additional_data;j++)
18374 data_for_proc[new_domain].push_back(
18375 flat_packed_refinement_info_for_root[e][j]);
18390 send_data.reserve(count);
18396 for(
int rank=0;rank<n_proc;rank++)
18399 send_displacement[rank] = send_data.size();
18406 send_data.push_back(nbase_elements_for_proc[rank]);
18409 unsigned n_data=data_for_proc[rank].size();
18410 for (
unsigned j=0;j<n_data;j++)
18412 send_data.push_back(data_for_proc[rank][j]);
18417 send_n[rank] = send_data.size() - send_displacement[rank];
18424 MPI_Alltoall(&send_n[0],1,MPI_INT,&receive_n[0],1,MPI_INT,
18430 int receive_data_count=0;
18431 for(
int rank=0;rank<n_proc;++rank)
18434 receive_displacement[rank] = receive_data_count;
18435 receive_data_count += receive_n[rank];
18440 if(receive_data_count==0) {++receive_data_count;}
18445 if(send_data.size()==0) {send_data.resize(1);}
18448 MPI_Alltoallv(&send_data[0],&send_n[0],&send_displacement[0],
18450 &receive_data[0],&receive_n[0],
18451 &receive_displacement[0],
18459 for (
int send_rank=0;send_rank<n_proc;send_rank++)
18463 if((send_rank != my_rank) && (receive_n[send_rank] != 0))
18466 unsigned count=receive_displacement[send_rank];
18469 unsigned nbase_element=receive_data[count];
18471 for (
unsigned b=0;b<nbase_element;b++)
18474 unsigned base_element_number=receive_data[count];
18479 unsigned nhalo=halo_domains[base_element_number].size();
18480 halo_domain_of_haloed_base_element[base_element_number].resize(nhalo);
18481 for (
unsigned j=0;j<nhalo;j++)
18483 halo_domain_of_haloed_base_element[base_element_number][j]=
18484 halo_domains[base_element_number][j];
18488 refinement_info_for_root_elements[base_element_number].
18489 resize(max_refinement_level_overall);
18494 unsigned n_additional_data=receive_data[count];
18498 unsigned check_count=0;
18502 unsigned n_tree_nodes=receive_data[count];
18510 for (
unsigned level=0; level<max_refinement_level_overall; level++)
18512 for (
unsigned e=0;
e<n_tree_nodes;
e++)
18515 if (receive_data[count]==1)
18524 if (receive_data[count]==1)
18526 refinement_info_for_root_elements[base_element_number][level].
18537 refinement_info_for_root_elements[base_element_number][level].
18549 refinement_info_for_root_elements[base_element_number][level].
18561 if ( n_additional_data!=check_count)
18563 std::stringstream error_message;
18564 error_message <<
"Number of additional data: " << n_additional_data
18565 <<
" doesn't match that actually send: " << check_count
18568 OOMPH_CURRENT_FUNCTION,
18569 OOMPH_EXCEPTION_LOCATION);
18587 std::map<unsigned, Vector<unsigned> > data_for_proc;
18595 halo_domain_of_haloed_base_element.begin();
18596 it!=halo_domain_of_haloed_base_element.end();it++)
18599 unsigned base_element_number=(*it).first;
18603 unsigned nd=domains.size();
18604 for (
unsigned jd=0;jd<nd;jd++)
18607 unsigned d=domains[jd];
18610 nbase_elements_for_proc[d]++;
18613 data_for_proc[d].push_back(base_element_number);
18616 for (
unsigned level=0;level<max_refinement_level_overall;level++)
18620 refinement_info_for_root_elements[base_element_number][level].size();
18621 data_for_proc[d].push_back(n);
18622 for (
unsigned j=0;j<n;j++)
18624 data_for_proc[d].push_back(
18625 refinement_info_for_root_elements[base_element_number][level][j]);
18640 send_data.reserve(count);
18646 for(
int rank=0;rank<n_proc;rank++)
18649 send_displacement[rank] = send_data.size();
18656 send_data.push_back(nbase_elements_for_proc[rank]);
18659 unsigned n_data=data_for_proc[rank].size();
18660 for (
unsigned j=0;j<n_data;j++)
18662 send_data.push_back(data_for_proc[rank][j]);
18666 send_n[rank] = send_data.size() - send_displacement[rank];
18673 MPI_Alltoall(&send_n[0],1,MPI_INT,&receive_n[0],1,MPI_INT,
18679 int receive_data_count=0;
18680 for(
int rank=0;rank<n_proc;++rank)
18683 receive_displacement[rank] = receive_data_count;
18684 receive_data_count += receive_n[rank];
18689 if(receive_data_count==0) {++receive_data_count;}
18694 if(send_data.size()==0) {send_data.resize(1);}
18697 MPI_Alltoallv(&send_data[0],&send_n[0],&send_displacement[0],
18699 &receive_data[0],&receive_n[0],
18700 &receive_displacement[0],
18708 for (
int send_rank=0;send_rank<n_proc;send_rank++)
18712 if((send_rank != my_rank) && (receive_n[send_rank] != 0))
18715 unsigned count=receive_displacement[send_rank];
18718 unsigned nbase_element=receive_data[count];
18721 for (
unsigned e=0;
e<nbase_element;
e++)
18724 unsigned base_element_number=receive_data[count];
18728 refinement_info_for_root_elements[base_element_number].
18729 resize(max_refinement_level_overall);
18732 for (
unsigned level=0;level<max_refinement_level_overall;level++)
18735 unsigned n=receive_data[count];
18739 for (
unsigned j=0;j<n;j++)
18741 refinement_info_for_root_elements[base_element_number][level].
18743 receive_data[count]);
18769 const int n_proc=comm_pt->nproc();
18775 MPI_Alltoall(&send_n[0],1,MPI_INT,&receive_n[0],1,MPI_INT,
18781 int receive_data_count=0;
18782 for(
int rank=0;rank<n_proc;++rank)
18785 receive_displacement[rank] = receive_data_count;
18786 receive_data_count += receive_n[rank];
18791 if(receive_data_count==0) {++receive_data_count;}
18796 if(send_data.size()==0) {send_data.resize(1);}
18799 MPI_Alltoallv(&send_data[0],&send_n[0],&send_displacement[0],
18801 &receive_data[0],&receive_n[0],
18802 &receive_displacement[0],
18806 unsigned el_count=0;
18812 for (
int send_rank=0;send_rank<n_proc;send_rank++)
18817 if (receive_n[send_rank] != 0)
18820 unsigned count=receive_displacement[send_rank];
18823 unsigned nbatch=unsigned(receive_data[count]);
18827 for (
unsigned b=0;b<nbatch;b++)
18831 unsigned nel=unsigned(receive_data[count]);
18836 unsigned base_el_no=unsigned(receive_data[count]);
18848 if (ref_root_el_pt!=0)
18853 stick_leaves_into_vector(all_leaf_nodes_pt);
18856 unsigned n_leaf=all_leaf_nodes_pt.size();
18861 std::ostringstream error_message;
18863 <<
"Number of leaves: " << n_leaf <<
" " 18864 <<
" doesn't match number of elements sent in batch: " 18867 error_message.str(),
18868 OOMPH_CURRENT_FUNCTION,
18869 OOMPH_EXCEPTION_LOCATION);
18874 batch_el_pt.resize(n_leaf);
18875 for (
unsigned e=0;
e<n_leaf;
e++)
18877 batch_el_pt[
e]=all_leaf_nodes_pt[
e]->object_pt();
18886 std::ostringstream error_message;
18888 <<
"Non-refineable root element should only be associated with" 18889 <<
" one element but nel=" << nel <<
"\n";
18891 error_message.str(),
18892 OOMPH_CURRENT_FUNCTION,
18893 OOMPH_EXCEPTION_LOCATION);
18896 batch_el_pt.push_back(root_el_pt);
18900 for (
unsigned e=0;
e<nel;
e++)
18910 unsigned nnod=fe_pt->
nnode();
18911 for (
unsigned j=0;j<nnod;j++)
18914 if (!node_done[send_rank][nod_pt])
18916 node_done[send_rank][nod_pt]=
true;
18922 unsigned nval=unsigned(receive_data[count]);
18927 if (nval<nod_pt->nvalue())
18929 std::ostringstream error_message;
18931 <<
"Node has more values, namely " << nod_pt->nvalue()
18932 <<
", than we're about to receive, namely " << nval
18933 <<
". Something's wrong!\n";
18935 error_message.str(),
18936 OOMPH_CURRENT_FUNCTION,
18937 OOMPH_EXCEPTION_LOCATION);
18944 unsigned is_boundary_node=unsigned(receive_data[count]);
18956 if (is_boundary_node!=1)
18958 std::ostringstream error_message;
18960 <<
"Local node is boundary node but information sent is\n" 18961 <<
"for non-boundary node\n";
18963 error_message.str(),
18964 OOMPH_CURRENT_FUNCTION,
18965 OOMPH_EXCEPTION_LOCATION);
18970 unsigned n_entry=unsigned(receive_data[count]);
18978 index_of_first_value_assigned_by_face_element_pt()==0)
18981 index_of_first_value_assigned_by_face_element_pt()=
18982 new std::map<unsigned, unsigned>;
18987 std::map<unsigned, unsigned>* map_pt=
18989 index_of_first_value_assigned_by_face_element_pt();
18992 for (
unsigned i=0;
i<n_entry;
i++)
18995 unsigned first=unsigned(receive_data[count]);
18997 unsigned second=unsigned(receive_data[count]);
19001 (*map_pt)[first]=second;
19011 if (is_boundary_node!=0)
19013 std::ostringstream error_message;
19015 <<
"Local node is not a boundary node but information \n" 19016 <<
"sent is for boundary node.\n";
19018 error_message.str(),
19019 OOMPH_CURRENT_FUNCTION,
19020 OOMPH_EXCEPTION_LOCATION);
19029 if (nval>nod_pt->nvalue())
19031 nod_pt->resize(nval);
19035 nod_pt->read_values_from_vector(receive_data,count);
19049 bool do_halos=
true;
19050 bool do_external_halos=
false;
19057 bool do_halos=
false;
19058 bool do_external_halos=
true;
19090 unsigned& max_refinement_level_overall)
19095 const int n_proc=comm_pt->nproc();
19105 std::map<RefineableElement*,bool> root_el_done;
19111 std::map<RefineableElement*,unsigned> target_plus_one_for_root;
19116 unsigned max_refinement_level=0;
19121 std::map<unsigned,Vector<GeneralisedElement*> > element_for_processor;
19128 std::map<unsigned,Vector<unsigned> > nelement_batch_for_processor;
19136 std::map<unsigned,Vector<unsigned> >
19137 base_element_for_element_batch_for_processor;
19148 Vector<int> old_domain_for_base_element_local(n_base_element,-1);
19149 Vector<int> new_domain_for_base_element_local(n_base_element,-1);
19155 unsigned count_non_halo_el=0;
19165 bool are_there_structured_meshes =
false;
19167 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
19172 if (!(sub_mesh_pt!=0))
19180 are_there_structured_meshes =
true;
19183 for (
unsigned e = 0;
e < nele;
e++)
19190 unsigned target_domain=
19191 target_domain_for_local_non_halo_element[count_non_halo_el];
19194 count_non_halo_el++;
19202 element_for_processor[target_domain].push_back(el_pt);
19206 nelement_batch_for_processor[target_domain].push_back(1);
19209 unsigned element_number_in_base_mesh=
19212 if (element_number_in_base_mesh==0)
19214 throw OomphLibError(
"Base_mesh_element_number_plus_one[...]=0",
19215 OOMPH_CURRENT_FUNCTION,
19216 OOMPH_EXCEPTION_LOCATION);
19219 element_number_in_base_mesh-=1;
19220 base_element_for_element_batch_for_processor[target_domain].
19221 push_back(element_number_in_base_mesh);
19224 old_domain_for_base_element_local[element_number_in_base_mesh]=
19226 new_domain_for_base_element_local[element_number_in_base_mesh]=
19239 if (!root_el_done[root_el_pt])
19242 root_el_done[root_el_pt]=
true;
19245 unsigned element_number_in_base_mesh=
19248 if (element_number_in_base_mesh==0)
19250 throw OomphLibError(
"Base_mesh_element_number_plus_one[...]=0",
19251 OOMPH_CURRENT_FUNCTION,
19252 OOMPH_EXCEPTION_LOCATION);
19255 element_number_in_base_mesh-=1;
19258 old_domain_for_base_element_local[element_number_in_base_mesh]=
19260 new_domain_for_base_element_local[element_number_in_base_mesh]=
19267 target_plus_one_for_root[root_el_pt]=target_domain+1;
19272 root_el_pt->tree_pt()->stick_leaves_into_vector(all_leaf_nodes_pt);
19275 unsigned n_leaf=all_leaf_nodes_pt.size();
19279 nelement_batch_for_processor[target_domain].push_back(n_leaf);
19282 base_element_for_element_batch_for_processor[target_domain].
19283 push_back(element_number_in_base_mesh);
19286 for (
unsigned i_leaf=0;i_leaf<n_leaf;i_leaf++)
19290 all_leaf_nodes_pt[i_leaf]->object_pt();
19291 element_for_processor[target_domain].push_back(leaf_el_pt);
19294 unsigned level=all_leaf_nodes_pt[i_leaf]->level();
19295 if (level>max_refinement_level)
19297 max_refinement_level=level;
19309 if ((target_plus_one_for_root[root_el_pt]-1)!=target_domain)
19311 std::ostringstream error_message;
19313 <<
"All elements associated with same root must have " 19314 <<
"same target. during load balancing\n";
19316 error_message.str(),
19317 OOMPH_CURRENT_FUNCTION,
19318 OOMPH_EXCEPTION_LOCATION);
19330 if (target_domain_for_local_non_halo_element.size()!=count_non_halo_el)
19332 std::ostringstream error_message;
19334 <<
"Have processed " << count_non_halo_el <<
" of " 19335 << target_domain_for_local_non_halo_element.size()
19336 <<
" target domains for local non-halo elelemts. \n " 19337 <<
"Very Odd -- we do (now) strip out the information for elements\n" 19338 <<
"that are removed in actions_before_distribute()...\n";
19340 error_message.str(),
19341 OOMPH_CURRENT_FUNCTION,
19342 OOMPH_EXCEPTION_LOCATION);
19352 max_refinement_level_overall=0;
19356 if (are_there_structured_meshes)
19358 MPI_Allreduce(&max_refinement_level,&max_refinement_level_overall,1,
19359 MPI_UNSIGNED,MPI_MAX,comm_pt->mpi_comm());
19364 Vector<int> tmp_old_domain_for_base_element(n_base_element);
19368 if (are_there_structured_meshes)
19370 MPI_Allreduce(&old_domain_for_base_element_local[0],
19371 &tmp_old_domain_for_base_element[0],n_base_element,
19372 MPI_INT,MPI_MAX,comm_pt->mpi_comm());
19375 Vector<int> tmp_new_domain_for_base_element(n_base_element);
19378 if (are_there_structured_meshes)
19380 MPI_Allreduce(&new_domain_for_base_element_local[0],
19381 &tmp_new_domain_for_base_element[0],n_base_element,
19382 MPI_INT,MPI_MAX,comm_pt->mpi_comm());
19386 old_domain_for_base_element.resize(n_base_element);
19387 new_domain_for_base_element.resize(n_base_element);
19388 for(
unsigned j=0;j<n_base_element;j++)
19391 if (tmp_old_domain_for_base_element[j]==-1)
19393 std::ostringstream error_message;
19395 <<
"Old domain for base element " << j
19397 <<
"or its incarnation as refineable el: " 19399 <<
" which is of type " 19401 <<
"appear to have been assigned by any processor\n";
19403 error_message.str(),
19404 OOMPH_CURRENT_FUNCTION,
19405 OOMPH_EXCEPTION_LOCATION);
19408 old_domain_for_base_element[j]=tmp_old_domain_for_base_element[j];
19410 if (tmp_new_domain_for_base_element[j]==-1)
19412 std::ostringstream error_message;
19414 <<
"New domain for base element " << j <<
"which is of type " 19416 <<
"appear to have been assigned by any processor\n";
19418 error_message.str(),
19419 OOMPH_CURRENT_FUNCTION,
19420 OOMPH_EXCEPTION_LOCATION);
19423 new_domain_for_base_element[j]=tmp_new_domain_for_base_element[j];
19439 for(
int rank=0;rank<n_proc;rank++)
19442 send_displacement[rank] = send_data.size();
19447 unsigned total_nel=element_for_processor[rank].size();
19451 unsigned el_count=0;
19454 unsigned nbatch=nelement_batch_for_processor[rank].size();
19457 send_data.push_back(
double(nbatch));
19460 for (
unsigned b=0;b<nbatch;b++)
19463 unsigned nel=nelement_batch_for_processor[rank][b];
19467 unsigned base_el_no=
19468 base_element_for_element_batch_for_processor[rank][b];
19472 send_data.push_back(
double(nel));
19473 send_data.push_back(
double(base_el_no));
19476 for (
unsigned e=0;
e<nel;
e++)
19486 unsigned nnod=fe_pt->
nnode();
19487 for (
unsigned j=0;j<nnod;j++)
19493 unsigned n_value=nod_pt->
nvalue();
19496 unsigned n_dim=nod_pt->
ndim();
19500 for(
unsigned t=0;
t<nt;
t++)
19502 nod_pt->
value(
t,values);
19503 for(
unsigned i=0;
i<n_value;
i++)
19508 for(
unsigned i=0;
i<n_dim;
i++)
19510 nod_pt->
x(
t,
i)=position[
i];
19516 if (!node_done[rank][nod_pt])
19519 node_done[rank][nod_pt]=
true;
19524 send_data.push_back(
double(n_value));
19535 send_data.push_back(
double(0));
19543 send_data.push_back(
double(1));
19547 std::map<unsigned, unsigned>* map_pt=
19553 send_data.push_back(
double(0));
19559 send_data.push_back(
double(map_pt->size()));
19562 for (std::map<unsigned, unsigned>::iterator p=
19564 p!=map_pt->end();p++)
19566 send_data.push_back(
double((*p).first));
19567 send_data.push_back(
double((*p).second));
19573 nod_pt->add_values_to_vector(send_data);
19591 if (total_nel!=el_count)
19593 std::ostringstream error_message;
19595 <<
"total_nel: " << total_nel <<
" " 19596 <<
" doesn't match total number of elements sent in batch: " 19597 << el_count <<
"\n";
19599 error_message.str(),
19600 OOMPH_CURRENT_FUNCTION,
19601 OOMPH_EXCEPTION_LOCATION);
19606 send_n[rank] = send_data.size() - send_displacement[rank];
19633 const unsigned& max_refinement_level_overall,
19634 std::map<
unsigned,
Vector<unsigned> >& flat_packed_refinement_info_for_root)
19637 std::map<RefineableElement*,bool> root_el_done;
19646 for (
unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
19651 if (!(sub_mesh_pt!=0))
19654 for (
unsigned e = 0;
e < nele_submesh;
e++)
19673 "Base_mesh_element_number_plus_one[...]=0",
19674 OOMPH_CURRENT_FUNCTION,
19675 OOMPH_EXCEPTION_LOCATION);
19679 flat_packed_refinement_info_for_root[
e].push_back(0);
19688 if (!root_el_done[root_el_pt])
19691 unsigned root_element_number=
19695 if (root_element_number==0)
19698 "Base_mesh_element_number_plus_one[...]=0",
19699 OOMPH_CURRENT_FUNCTION,
19700 OOMPH_EXCEPTION_LOCATION);
19703 root_element_number-=1;
19707 root_el_pt->tree_pt()->
19708 stick_all_tree_nodes_into_vector(all_tree_nodes_pt);
19711 unsigned n_tree_nodes=all_tree_nodes_pt.size();
19712 flat_packed_refinement_info_for_root[root_element_number].
19713 push_back(n_tree_nodes);
19716 for (
unsigned current_level=0;
19717 current_level<max_refinement_level_overall;
19721 for (
unsigned e=0;
e<n_tree_nodes;
e++)
19724 unsigned level=all_tree_nodes_pt[
e]->level();
19728 if ((level==current_level) ||
19729 ((level<current_level) &&
19730 (all_tree_nodes_pt[
e]->is_leaf())))
19732 flat_packed_refinement_info_for_root[root_element_number].
19737 if ((level==current_level) &&
19738 (!all_tree_nodes_pt[
e]->is_leaf()))
19740 flat_packed_refinement_info_for_root[root_element_number].
19747 flat_packed_refinement_info_for_root[root_element_number].
19755 flat_packed_refinement_info_for_root[root_element_number].
19761 root_el_done[root_el_pt]=
true;
19783 const unsigned& max_level_overall)
19787 unsigned max_mesh=std::max(n_sub_mesh,
unsigned(1));
19788 for (
unsigned i_mesh=0;i_mesh<max_mesh;i_mesh++)
19791 Mesh* my_mesh_pt=0;
19803 unsigned n_el_on_this_proc=my_mesh_pt->
nelement();
19816 for (
unsigned level=0;level<max_level_overall;level++)
19820 for (
unsigned e=0;
e<n_el_on_this_proc;
e++)
19831 "Base_mesh_element_number_plus_one[...]=0",
19832 OOMPH_CURRENT_FUNCTION,
19833 OOMPH_EXCEPTION_LOCATION);
19840 unsigned n_refinements=
19841 refinement_info_for_root_elements[root_el_no].size();
19844 if (level<n_refinements)
19848 refinement_info_for_root_elements[root_el_no][level].size();
19849 for (
unsigned ee=0;ee<n_el;ee++)
19853 if (refinement_info_for_root_elements[root_el_no][level][ee]==2)
19855 to_be_refined_on_this_proc[level].
19856 push_back(el_count_on_this_proc[level]);
19857 el_count_on_this_proc[level]++;
19861 else if(refinement_info_for_root_elements[root_el_no][level][ee]==1)
19863 el_count_on_this_proc[level]++;
19875 if (ref_mesh_pt!=0)
19903 unsigned max_mesh=std::max(n_sub_mesh,
unsigned(1));
19904 for (
unsigned i_mesh=0;i_mesh<max_mesh;i_mesh++)
19907 Mesh* my_mesh_pt=0;
19920 if (!(sub_mesh_pt!=0))
19932 for(
int rank=0;rank<n_proc;rank++)
19935 send_displacement[rank] = send_data.size();
19944 unsigned nel=root_haloed_elements_pt.size();
19947 for (
unsigned e=0;
e<nel;
e++)
19956 send_n[rank] = send_data.size() - send_displacement[rank];
19963 MPI_Alltoall(&send_n[0],1,MPI_INT,&receive_n[0],1,MPI_INT,
19969 int receive_data_count=0;
19970 for(
int rank=0;rank<n_proc;++rank)
19973 receive_displacement[rank] = receive_data_count;
19974 receive_data_count += receive_n[rank];
19979 if(receive_data_count==0) {++receive_data_count;}
19984 if(send_data.size()==0) {send_data.resize(1);}
19987 MPI_Alltoallv(&send_data[0],&send_n[0],&send_displacement[0],
19989 &receive_data[0],&receive_n[0],
19990 &receive_displacement[0],
19996 for (
int send_rank=0;send_rank<n_proc;send_rank++)
20000 if((send_rank != my_rank) && (receive_n[send_rank] != 0))
20003 unsigned count=receive_displacement[send_rank];
20008 unsigned nel=root_halo_elements_pt.size();
20011 for (
unsigned e=0;
e<nel;
e++)
20014 unsigned el_number_plus_one=receive_data[count++];
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 ...
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...
A Generalised Element class.
A class to handle errors in the Newton solver.
void make_steady()
Function to make the time stepper temporarily steady. This is trivially achieved by setting all the w...
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 set_communicator_pt(OomphCommunicator *comm_pt)
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...
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...
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...
Vector< double * > Halo_dof_pt
Storage for the halo degrees of freedom (only required) when accessing via the global equation number...
EigenSolver * Default_eigen_solver_pt
Pointer to the default eigensolver.
Class of matrices containing doubles, and stored as a DenseMatrix<double>, but with solving functiona...
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, element_domain_on_this_proc[e] contains the number of the domain [0,1,...,ndomain-1] to which non-halo element e on THE CURRENT PROCESSOR ONLY has been assigned. The order of the non-halo elements is the same as in the Problem's mesh, with the halo elements being skipped.
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...
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 ...
Vector< double > Max_res
Maximum residuals at start and after each newton iteration.
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...
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. On return the index will be set to the value at the end of the data that has been read in.
bool is_dparameter_calculated_analytically(double *const ¶meter_pt)
Function to determine whether the parameter derivatives are calculated analytically.
void get_dofs(DoubleVector &dofs) const
Return the vector of dofs, i.e. a vector containing the current values of all unknowns.
void newton_solve()
Use Newton method to solve the problem.
unsigned Sparse_assembly_method
Flag to determine which sparse assembly method to use By default we use assembly by vectors of pairs...
double Ds_current
Storage for the current step value.
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...
Vector< TimeStepper * > Time_stepper_pt
The Vector of time steppers (there could be many different ones in multiphysics problems) ...
void delete_all_external_storage()
Wrapper function to delete external storage for each submesh of the problem.
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...
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...
double Relaxation_factor
Relaxation fator for Newton method (only a fractional Newton correction is applied if this is less th...
bool Must_recompute_load_balance_for_assembly
Boolean indicating that the division of elements over processors during the assembly process must be ...
virtual void actions_after_timestep(Problem *problem_pt)
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...
virtual void actions_before_adapt()
Actions that are to be performed before a mesh adaptation. These might include removing any additiona...
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 ~Problem()
Virtual destructor to clean up memory.
void initialise(const T &val)
Initialize all values in the matrix to val.
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 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...
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...
LinearSolver * Linear_solver_pt
Pointer to the linear solver for the problem.
void doc_errors()
Get max and min error for all elements in submeshes.
unsigned nexternal_halo_element()
Total number of external halo elements in this Mesh.
void clear()
wipes the DoubleVector
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 set_default_first_and_last_element_for_assembly()
Set default first and last elements for parallel assembly of non-distributed problem.
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, parameter_pt is a pointer to the parameter that is traded for the arc-length constraint, ds is the desired arc length and max_adapt is the maximum number of spatial adaptations. The pointer to the parameter may be changed if this is called from the Data-based interface.
double Newton_solver_tolerance
The Tolerance below which the Newton Method is deemed to have converged.
bool is_doc_enabled() const
Are we documenting?
void refine_base_mesh(Vector< Vector< unsigned > > &to_be_refined)
Refine base mesh according to specified refinement pattern.
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...
virtual double global_temporal_error_norm()
Function to calculate a global error norm, used in adaptive timestepping to control the change in tim...
virtual void dump(std::ofstream &dump_file) const
Dump refinement pattern of all refineable meshes and all generic Problem data to file for restart...
void redistribute(const LinearAlgebraDistribution *const &dist_pt)
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...
virtual void output(std::ostream &outfile)
Output the element data — typically the values at the nodes in a format suitable for post-processing...
static ContinuationStorageScheme Continuation_time_stepper
Storage for the single static continuation timestorage object.
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 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...
void sum_all_halo_and_haloed_values()
bool First_jacobian_sign_change
Boolean to indicate whether a sign change has occured in the Jacobian.
HangInfo *const & hanging_pt() const
Return pointer to hanging node data (this refers to the geometric hanging node status) (const version...
double * values_pt()
access function to the underlying values
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 ...
unsigned iterations
Max. # of iterations performed when the Newton solver died.
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 ...
Information for documentation of results: Directory and file number to enable output in the form RESL...
unsigned Max_newton_iterations
Maximum number of newton iterations.
virtual unsigned ndt() const =0
Number of timestep increments that are required by the scheme.
void enable_mass_matrix_reuse()
Enable recycling of the mass matrix in explicit timestepping schemes. Useful for timestepping on fixe...
virtual void actions_after_read_unstructured_meshes()
Actions that are to be performed before reading in restart data for problems involving unstructured b...
std::string directory() const
Output directory.
bool Bypass_increase_in_dof_check_during_pruning
Boolean to bypass check of increase in dofs during pruning.
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...
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...
virtual void set_predictor_weights()
Set the weights for the predictor previous timestep (currently empty – overwrite for specific scheme...
int & face_index()
Index of the face (a number that uniquely identifies the face in the element)
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...
Class to keep track of discrete/continous time. It is essential to have a single Time object when usi...
void shift_time_values()
Shift time-dependent data along for next timestep: Deal with nodal Data/positions and the element's i...
unsigned ntime_stepper() const
Return the number of time steppers.
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...
void copy(Problem *orig_problem_pt)
Copy Data values, nodal positions etc from specified problem. Note: This is not a copy constructor...
double DTSF_max_increase
Maximum possible increase of dt between time-steps in adaptive schemes.
virtual void get_refinement_levels(unsigned &min_refinement_level, unsigned &max_refinement_level)
Get max/min refinement levels in mesh.
void set_consistent_pinned_values_for_continuation()
Private helper function that is used to set the appropriate pinned values for continuation.
Vector< Mesh * > Sub_mesh_pt
Vector of pointers to submeshes.
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...
virtual void solve_eigenproblem(Problem *const &problem_pt, const int &n_eval, Vector< std::complex< double > > &eigenvalue, Vector< DoubleVector > &eigenvector)=0
Actual eigensolver. This takes a pointer to a problem and returns a vector of complex numbers represe...
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...
virtual void actions_after_adapt()
Actions that are to be performed after a mesh adaptation.
bool Arc_length_step_taken
Boolean to indicate whether an arc-length step has been taken.
double Max_permitted_error_for_halo_check
Threshold for error throwing in Problem::check_halo_schemes()
bool Discontinuous_element_formulation
Is the problem a discontinuous one, i.e. can the elemental contributions be treated independently...
virtual void read_distributed_info_for_restart(std::istream &restart_file)
OomphCommunicator * communicator_pt() const
const access to the communicator pointer
A class that is used to assemble the residuals in parallel by overloading the get_all_vectors_and_mat...
unsigned nexternal_halo_node()
Total number of external halo nodes in this Mesh.
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...
LinearAlgebraDistribution * Dof_distribution_pt
The distribution of the DOFs in this problem. This object is created in the Problem constructor and s...
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...
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...
std::string & label()
String used (e.g.) for labeling output files.
void shift_dt()
Update all stored values of dt by shifting each value along the array. This function must be called b...
double *& dof_pt(const unsigned &i)
Pointer to i-th dof in the problem.
friend class PitchForkHandler
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...
double & global_value(const unsigned &i)
Direct access to global entry.
A general Finite Element class.
Vector< double > Dof_current
Storage for the present values of the variables.
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...
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...
bool Jacobian_reuse_is_enabled
Is re-use of Jacobian in Newton iteration enabled? Default: false.
LinearAlgebraDistribution *const & dof_distribution_pt() const
Return the pointer to the dof distribution (read-only)
bool Shut_up_in_newton_solve
Boolean to indicate if all output is suppressed in Problem::newton_solve(). Defaults to false...
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 ...
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...
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_...
double const & master_weight(const unsigned &i) const
Return weight for dofs on i-th master node.
A Base class for DGElements.
virtual void synchronise()
Function that is used to perform any synchronisation required during the solution.
Vector< GeneralisedElement * > Base_mesh_element_pt
Vector to store the correspondence between a root element and its element number within the global me...
friend class BlockHopfLinearSolver
virtual void dump_distributed_info_for_restart(std::ostream &dump_file)
bool is_halo() const
Is this element a halo?
bool Use_globally_convergent_newton_method
Use the globally convergent newton method.
Base class for spatial error estimators.
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 ...
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...
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
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...
unsigned nmaster() const
Return the number of master nodes.
double Max_residuals
Maximum desired residual: if the maximum residual exceeds this value, the program will exit...
static OomphCommunicator * communicator_pt()
access to the global oomph-lib communicator
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_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 ...
bool Empty_actions_after_read_unstructured_meshes_has_been_called
Boolean to indicate that empty actions_after_read_unstructured_meshes() function has been called...
unsigned nrow() const
access function to the number of global rows.
Vector< GeneralisedElement * > haloed_element_pt(const unsigned &p)
Return vector of haloed elements in this Mesh whose haloing counterpart is held on processor p...
friend class AugmentedBlockFoldLinearSolver
double Parameter_current
Storage for the present value of the global parameter.
bool Empty_actions_before_read_unstructured_meshes_has_been_called
Boolean to indicate that empty actions_before_read_unstructured_meshes() function has been called...
unsigned first_row() const
access function for the first row on this processor. If not distributed then this is just zero...
Mesh *& mesh_pt()
Return a pointer to the global mesh.
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...
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.
bool distributed() const
access function to the distributed - indicates whether the distribution is serial or distributed ...
bool is_hanging() const
Test whether the node is geometrically hanging.
. SuperLU Project Solver class. This is a combined wrapper for both SuperLU and SuperLU Dist...
long & eqn_number(const unsigned &i)
Return the equation number of the i-th stored variable.
void calculate_predictions()
Calculate predictions.
unsigned nvalue() const
Return number of values stored in data object (incl pinned ones).
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...
void set_dofs(const DoubleVector &dofs)
Set the values of the dofs.
static bool mpi_has_been_initialised()
return true if MPI has been initialised
void disable_mass_matrix_reuse()
Function that disables the reuse of the mass matrix.
void synchronise_all_dofs()
Perform all required synchronisation in solvers.
Distributed_problem_matrix_distribution Dist_problem_matrix_distribution
The distributed matrix distribution method 1 - Automatic - the Problem distribution is employed...
unsigned nnon_halo_element()
Total number of non-halo elements in this mesh (Costly call computes result on the fly) ...
unsigned unrefine_uniformly()
Refine (all) refineable (sub)mesh(es) uniformly and rebuild problem. Return 0 for success...
OomphCommunicator * communicator_pt()
access function to the oomph-lib communicator
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...
bool Doc_comprehensive_timings
Global boolean to switch on comprehensive timing – can probably be declared const false when develop...
double Minimum_dt
Minimum desired dt: if dt falls below this value, exit.
virtual void shift_time_values()
Shift all values along to prepare for next timestep.
void recompute_load_balanced_assembly()
Helper function to re-assign the first and last elements to be assembled by each processor during par...
LinearSolver *& mass_matrix_solver_for_explicit_timestepper_pt()
virtual RefineableElement * root_element_pt()
Pointer to the root element in refinement hierarchy (must be implemented in specific elements that do...
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...
virtual void symmetrise_eigenfunction_for_adaptive_pitchfork_tracking()
Virtual function that is used to symmetrise the problem so that the current solution exactly satisfie...
ExplicitTimeStepper * Explicit_time_stepper_pt
Pointer to a single explicit timestepper.
unsigned & number()
Number used (e.g.) for labeling output files.
void remove_boundary_node(const unsigned &b, Node *const &node_pt)
virtual void get_eigenfunction(Vector< DoubleVector > &eigenfunction)
Return the eigenfunction(s) associated with the bifurcation that has been detected in bifurcation tra...
void p_unrefine_uniformly(DocInfo &doc_info)
p-unrefine (all) p-refineable (sub)mesh(es) uniformly and rebuild problem.
bool Mass_matrix_reuse_is_enabled
Is re-use of the mass matrix in explicit timestepping enabled Default:false.
unsigned long nelement() const
Return number of elements in the mesh.
bool distribution_built() const
bool & use_predictor_values_as_initial_guess()
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 ...
void output(std::ostream &outfile)
Output for all elements.
void assign_initial_values_impulsive()
Assign initial values for an impulsive start.
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...
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Mesh * Mesh_pt
The mesh pointer.
bool Bisect_to_find_bifurcation
Boolean to control wheter bisection is used to located bifurcation.
double Continuation_direction
The direction of the change in parameter that will ensure that a branch is followed in one direction ...
void setup()
Setup terminate helper.
bool linear_solver_error
Error in the linear solver.
void get_gradient(DoubleVector &gradient)
function to access the gradient, provided it has been computed
AssemblyHandler *& assembly_handler_pt()
Return a pointer to the assembly handler object.
Time * Time_pt
Pointer to global time for the problem.
unsigned ndof() const
Return the number of equations/dofs in the element.
void reset_gradient()
function to reset the size of the gradient before each Newton solve
void calculate_continuation_derivatives_helper(const DoubleVector &z)
A function that performs the guts of the continuation derivative calculation in arc length continuati...
unsigned setup_element_count_per_dof()
Function that populates the Element_counter_per_dof vector with the number of elements that contribut...
virtual void get_dvaluesdt(DoubleVector &f)
Get the time derivative of all values (using get_inverse_mass_matrix_times_residuals(..) with all time steppers set to steady) e.g. for use in explicit time steps. The approach used is slighty hacky, beware if you have a residual which is non-linear or implicit in the derivative or if you have overloaded get_jacobian(...).
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...
EigenSolver * Eigen_solver_pt
Pointer to the eigen solver for the problem.
virtual unsigned ndof(GeneralisedElement *const &elem_pt)
Return the number of degrees of freedom in the element elem_pt.
void calculate_predictions()
Calculate predictions for all Data and positions associated with the mesh, usually used in adaptive t...
double Desired_proportion_of_arc_length
Proportion of the arc-length to taken by the parameter.
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Describes the distribution of a distributable linear algebra type object. Typically this is a contain...
A class that contains the information required by Nodes that are located on Mesh boundaries. A BoundaryNode of a particular type is obtained by combining a given Node with this class. By differentiating between Nodes and BoundaryNodes we avoid a lot of un-necessary storage in the bulk Nodes.
void build(const DoubleVector &old_vector)
Just copys the argument DoubleVector.
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 null_external_halo_node(const unsigned &p, Node *nod_pt)
Null out specified external halo node (used when deleting duplicates)
void assign_initial_values_impulsive()
Initialise data and nodal positions to simulate impulsive start from initial configuration/solution.
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.
double & dof(const unsigned &i)
i-th dof in the problem
virtual double * bifurcation_parameter_pt() const
Return a pointer to the bifurcation parameter in bifurcation tracking problems.
unsigned nhalo_node()
Total number of halo nodes in this Mesh.
double & dof_derivative(const unsigned &i)
Access function to the derivative of the i-th (local) dof with respect to the arc length...
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...
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, to get rid of excessively wide halo layers. Note that the current mesh will be now regarded as the base mesh and no unrefinement relative to it will be possible once this function has been called.
OomphCommunicator * Communicator_pt
The communicator for this problem.
void store_current_dof_values()
Store the current values of the degrees of freedom.
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...
std::ostream *& stream_pt()
Access function for the stream pointer.
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
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...
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...
ExplicitTimeStepper * explicit_predictor_pt()
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...
bool is_resolve_enabled() const
Boolean flag indicating if resolves are enabled.
double Theta_squared
Value of the scaling parameter required so that the parameter occupies the desired proportion of the ...
bool is_mesh_distributed() const
Boolean to indicate if Mesh has been distributed.
void copy(SolidNode *orig_node_pt)
Copy nodal positions and associated data from specified node object.
Base class for tree-based refineable meshes.
void update_predicted_time(const double &new_time)
void build_halo_scheme(DoubleVectorHaloScheme *const &halo_scheme_pt)
Construct the halo scheme and storage for the halo data.
double Parameter_derivative
Storage for the derivative of the global parameter wrt arc-length.
bool Doc_time_in_distribute
Protected boolean flag to provide comprehensive timimings during problem distribution. Initialised to false.
virtual void set_weights()=0
Function to set the weights for present timestep (don't need to pass present timestep or previous tim...
void initialise(const double &v)
initialise the whole vector with value v
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...
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...
unsigned nexternal_haloed_element()
Total number of external haloed elements in this Mesh.
void copy(Data *orig_data_pt)
Copy Data values from specified Data object.
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...
void reset_assembly_handler_to_default()
Reset the system to the standard non-augemented state.
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...
void remesh_from_triangulateio(std::istream &restart_file)
Regenerate the mesh from a dumped triangulateio file and dumped boundary coordinates of boundary node...
unsigned nexternal_haloed_node()
Total number of external haloed nodes in this Mesh.
Tree * tree_pt()
Access function: Pointer to quadtree representation of this element.
double Maximum_dt
Maximum desired dt.
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 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...
double * bifurcation_parameter_pt() const
Return pointer to the parameter that is used in the bifurcation detection. If we are not tracking a b...
double & dt(const unsigned &t=0)
Data *& internal_data_pt(const unsigned &i)
Return a pointer to i-th internal data object.
bool Mass_matrix_has_been_computed
Has the mass matrix been computed (and can therefore be reused) Default: false.
virtual void actions_after_distribute()
Actions to be performed after a (mesh) distribution.
unsigned long eqn_number(const unsigned &ieqn_local) const
Return the global equation number corresponding to the ieqn_local-th local equation number...
unsigned nposition_type() const
Number of coordinate types needed in the mapping between local and global coordinates.
virtual void actions_before_timestep(Problem *problem_pt)
void position(Vector< double > &pos) const
Compute Vector of nodal positions either directly or via hanging node representation.
unsigned Nnewton_iter_taken
Actual number of Newton iterations taken during the most recent iteration.
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...
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...
bool predict_by_explicit_step() const
Flag: is adaptivity done by taking a separate step using an ExplicitTimeStepper object?
unsigned nrow_local() const
access function for the num of local rows on this processor. If no MPI then Nrow is returned...
DoubleVectorWithHaloEntries Element_count_per_dof
Counter that records how many elements contribute to each dof. Used to determine the (discrete) arc-l...
virtual void reestablish_distribution_info_for_restart(OomphCommunicator *comm_pt, std::istream &restart_file)
unsigned ndt() const
Return the number of timesteps stored.
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...
Time *& time_pt()
Return a pointer to the global time object.
A class that represents a collection of data; each Data object may contain many different individual ...
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...
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, to get rid of excessively wide halo layers. Note that the current mesh will be now regarded as the base mesh and no unrefinement relative to it will be possible once this function has been called.
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. After a call to this function subsequent calls of the standard solution methods will converge to a fold (limit) point at a particular value of the variable addressed by parameter_pt. The system may not converge if the initial guess is sufficiently poor or, alternatively, if finite differencing is used to calculate the jacobian matrix in the elements. If the boolean flag block_solver is true (the default) then a block factorisation is used to solve the augmented system which is both faster and uses less memory.
double & x_gen(const unsigned &k, const unsigned &i)
Reference to the generalised position x(k,i).
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 ...
virtual void get_residuals(DoubleVector &residuals)
Return the fully-assembled residuals Vector for the problem: Virtual so it can be overloaded in for m...
Data *const & variable_position_pt() const
Pointer to variable_position data (const version)
A class that is used to define the functions used to assemble the elemental contributions to the mass...
bool Pause_at_end_of_sparse_assembly
Protected boolean flag to halt program execution during sparse assemble process to assess peak memory...
TimeStepper *& time_stepper_pt()
Access function for the pointer to the first (presumably only) timestepper.
void setup_dof_halo_scheme()
Function that is used to setup the halo scheme.
Vector< unsigned > First_el_for_assembly
First element to be assembled by given processor for non-distributed problem (only kept up to date wh...
void get_fd_jacobian(DoubleVector &residuals, DenseMatrix< double > &jacobian)
Return the fully-assembled Jacobian and residuals, generated by finite differences.
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...
double & time()
Return the current value of the continuous time.
Node *const & master_node_pt(const unsigned &i) const
Return a pointer to the i-th master node.
virtual int bifurcation_type() const
Return an unsigned integer to indicate whether the handler is a bifurcation tracking handler...
void check_halo_schemes(DocInfo &doc_info, double &max_permitted_error_for_halo_check)
Check halo and shared schemes on the mesh.
LinearSolver * Default_linear_solver_pt
Pointer to the default linear solver.
void p_adapt()
p-adapt problem: Perform mesh adaptation for (all) refineable (sub)mesh(es), based on their own error...
Vector< double > Elemental_assembly_time
Storage for assembly times (used for load balancing)
void p_refine_uniformly()
p-refine (all) p-refineable (sub)mesh(es) uniformly and rebuild problem
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
int Sign_of_jacobian
Storage for the sign of the global Jacobian.
double timer()
returns the time in seconds after some point in past
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 the elemental contributions to the resi...
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 ...
void initialise(const _Tp &__value)
Iterate over all values and set to the desired value.
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...
static bool Suppress_warning_about_actions_before_read_unstructured_meshes
Flag to allow suppression of warning messages re reading in unstructured meshes during restart...
bool Use_continuation_timestepper
Boolean to control original or new storage of dof stuff.
virtual void actions_before_newton_solve()
Any actions that are to be performed before a complete Newton solve (e.g. adjust boundary conditions)...
virtual void enable_resolve()
Enable resolve (i.e. store matrix and/or LU decomposition, say) Virtual so it can be overloaded to pe...
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.
unsigned nhaloed_node()
Total number of haloed nodes in this Mesh.
void disable_mass_matrix_reuse()
Turn off recyling of the mass matrix in explicit timestepping schemes.
Vector< double > * Saved_dof_pt
Pointer to vector for backup of dofs.
Class that contains data for hanging nodes.
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
virtual void get_residuals(GeneralisedElement *const &elem_pt, Vector< double > &residuals)
Return the contribution to the residuals of the element elem_pt.
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 ...
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 ...
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 ...
double Timestep_reduction_factor_after_nonconvergence
What it says: If temporally adaptive Newton solver fails to to converge, reduce timestep by this fact...
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...
void check_halo_schemes()
Check the halo/haloed node/element schemes.
void initialise_dt(const double &dt)
Set all timesteps to the same value, dt, and assign weights for all timesteppers in the problem...
double FD_step_used_in_get_hessian_vector_products
unsigned long ndof() const
Return the number of dofs.
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...
unsigned rank_of_global_row(const unsigned i) const
return the processor rank of the global row number i
unsigned long nnode() const
Return number of nodes in the mesh.
A class for compressed column matrices that store doubles.
unsigned ntstorage() const
Return total number of doubles stored per value to record time history of each value (one for steady ...
virtual void disable_resolve()
Disable resolve (i.e. store matrix and/or LU decomposition, say) This function simply resets an inter...
virtual void undo_make_steady()
Reset the is_steady status of a specific TimeStepper to its default and re-assign the weights...
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...
FiniteElement * finite_element_pt(const unsigned &e) const
Upcast (downcast?) to FiniteElement (needed to access FiniteElement member functions).
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...
virtual void enable_computation_of_gradient()
function to enable the computation of the gradient required for the globally convergent Newton method...
void merge_meshes(const Vector< Mesh *> &sub_mesh_pt)
Merge meshes. Note: This simply merges the meshes' elements and nodes (ignoring duplicates; no bounda...
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...
void copy(Node *orig_node_pt)
Copy all nodal data from specified Node object.
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...
friend class BlockPitchForkLinearSolver
void disable_doc()
Disable documentation.
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...
unsigned ninternal_data() const
Return the number of internal data objects.
double maxres
Max. residual when Newton solver died.
A Class for nodes that deform elastically (i.e. position is an unknown in the problem). The idea is that the Eulerian positions are stored in a Data object and the Lagrangian coordinates are stored in addition. The pointer that addresses the Eulerian positions is set to the pointer to Value in the Data object. Hence, SolidNode uses knowledge of the internal structure of Data and must be a friend of the Data class. In order to allow a mesh to deform via an elastic-style equation in deforming-domain problems, the positions are stored separately from the values, so that elastic problems may be combined with any other type of problem.
void flush_sub_meshes()
Flush the problem's collection of sub-meshes. Must be followed by call to rebuild_global_mesh().
A class that is used to define the functions used when assembling the derivatives of the residuals wi...
Problem()
Constructor: Allocate space for one time stepper and set all pointers to NULL and set defaults for al...
void refine_uniformly(DocInfo &doc_info)
Refine mesh uniformly and doc process.
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...
void initialise_dt(const double &dt_)
Set all timesteps to the same value, dt.
void stick_all_tree_nodes_into_vector(Vector< Tree * > &)
Traverse and stick pointers to all "nodes" into Vector.
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...
Class for the ARPACK eigensolver.
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. ...
unsigned nrow() const
access function to the number of global rows.
bool Bifurcation_detection
Boolean to control bifurcation detection via determinant of Jacobian.
double dot(const DoubleVector &vec) const
compute the dot product of this vector with the vector vec.
bool Use_finite_differences_for_continuation_derivatives
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.
void set_consistent_pinned_values_for_continuation(ContinuationStorageScheme *const &continuation_stepper_pt)
Set consistent values for pinned data in continuation.
void resize(const unsigned &n_dt)
Resize the vector holding the number of previous timesteps and initialise the new values to zero...
bool Default_set_initial_condition_called
Has default set_initial_condition function been called? Default: false.
Time *const & time_pt() const
Access function for the pointer to time (const version)
bool Jacobian_has_been_computed
Has a Jacobian been computed (and can therefore be re-used if required)? Default: false...
void set_consistent_pinned_values(Data *const &data_pt)
Set consistent values of the derivatives and current value when the data is pinned. This must be done by the "timestepper" because only it knows the local storage scheme.
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
Vector< double > Dof_derivative
Storage for the derivative of the problem variables wrt arc-length.
unsigned Max_newton_iterations
Maximum number of Newton iterations.
FiniteElement *& bulk_element_pt()
Pointer to higher-dimensional "bulk" element.
Data *& global_data_pt(const unsigned &i)
Return a pointer to the the i-th global data object.
bool does_pointer_correspond_to_mesh_data(double *const ¶meter_pt)
Does the double pointer correspond to any mesh data.
bool is_pinned(const unsigned &i) const
Test whether the i-th variable is pinned (1: true; 0: false).
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...
void unsteady_newton_solve(const double &dt)
Advance time by dt and solve by Newton's method. This version always shifts time values.
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...
unsigned nglobal_data() const
Return the number of global data values.
virtual void partition_global_mesh(Mesh *&global_mesh_pt, DocInfo &doc_info, Vector< unsigned > &element_domain, const bool &report_stats=false)
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...
bool Use_predictor_values_as_initial_guess
Use values from the time stepper predictor as an initial guess.
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...
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.
void refine_uniformly()
Refine (all) refineable (sub)mesh(es) uniformly and rebuild problem.
virtual void timestep(ExplicitTimeSteppableObject *const &object_pt, const double &dt)=0
Pure virtual function that is used to advance time in the object.
void pause(std::string message)
Pause and display message.
void build_global_mesh()
Build the global mesh by combining the all the submeshes. Note: The nodes boundary information refers...
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...
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...
AssemblyHandler * Default_assembly_handler_pt
Pointer to the default assembly handler.
bool Always_take_one_newton_step
Boolean to indicate whether a Newton step should be taken even if the initial residuals are below the...
void setup_base_mesh_info_after_pruning()
Helper function to re-setup the Base_mesh enumeration (used during load balancing) after pruning...
Vector< double * > Dof_pt
Vector of pointers to dofs.
void load_balance()
Balance the load of a (possibly non-uniformly refined) problem that has already been distributed...
unsigned nrow_local() const
access function for the num of local rows on this processor.
DoubleVectorHaloScheme * Halo_scheme_pt
Pointer to the halo scheme for any global vectors that have the Dof_distribution. ...
virtual void set_initial_condition()
Set initial condition (incl previous timesteps). We need to establish this interface because I...
void enable_mass_matrix_reuse()
Function that allows the reuse of the mass matrix.
virtual void actions_before_newton_convergence_check()
Any actions that are to be performed before the residual is checked in the Newton method...
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...
double DTSF_min_decrease
Minimum allowed decrease of dt between time-steps in adaptive schemes. Lower scaling values will reje...
virtual void actions_before_read_unstructured_meshes()
Actions that are to be performed before reading in restart data for problems involving unstructured b...
bool is_steady() const
Flag to indicate if a timestepper has been made steady (possibly temporarily to switch off time-depen...
unsigned self_test()
Self-test: Check meshes and global data. Return 0 for OK.
bool position_is_pinned(const unsigned &i)
Test whether the i-th coordinate is pinned, 0: false; 1: true.
A vector in the mathematical sense, initially developed for linear algebra type applications. If MPI then this vector can be distributed - its distribution is described by the LinearAlgebraDistribution object at Distribution_pt. Data is stored in a C-style pointer vector (double*)
virtual void actions_before_distribute()
Actions to be performed before a (mesh) distribution.
unsigned long nrow() const
Return the number of rows of the matrix.
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...
bool are_hessian_products_calculated_analytically()
Function to determine whether the hessian products are calculated analytically.
LinearSolver * Mass_matrix_solver_for_explicit_timestepper_pt
bool Problem_is_nonlinear
Boolean flag indicating if we're dealing with a linear or nonlinear Problem – if set to false the Ne...
void get_bifurcation_eigenfunction(Vector< DoubleVector > &eigenfunction)
Return the eigenfunction calculated as part of a bifurcation tracking process. If we are not tracking...
long synchronise_eqn_numbers(const bool &assign_local_eqn_numbers=true)
Classify any non-classified nodes into halo/haloed and synchronise equation numbers. Return the total number of degrees of freedom in the overall problem.
A class that is used to define the functions used to assemble and invert the mass matrix when taking ...
RefineableElement * object_pt() const
Return the pointer to the object (RefineableElement) represented by the tree.
unsigned nsub_mesh() const
Return number of submeshes.
bool Store_local_dof_pt_in_elements
Boolean to indicate whether local dof pointers should be stored in the elements.
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 actions_after_newton_step()
Any actions that are to be performed after each individual Newton step. Most likely to be used for di...
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.
bool use_triangulateio_restart() const
const access for Use_triangulateio_restart.
AssemblyHandler * Assembly_handler_pt
void flush_element_and_node_storage()
Flush storage for elements and nodes by emptying the vectors that store the pointers to them...
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 ...
unsigned Desired_newton_iterations_ds
The desired number of Newton Steps to reach convergence at each step along the arc.
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...
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 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...
ExplicitTimeStepper *& explicit_time_stepper_pt()
Return a pointer to the explicit timestepper.
A Base class for explicit timesteppers.
void deactivate_bifurcation_tracking()
Deactivate all bifuraction tracking, by reseting the assembly handler to the default.
virtual void actions_after_newton_solve()
Any actions that are to be performed after a complete Newton solve, e.g. post processing. CAREFUL: This step should (and if the FD-based LinearSolver FD_LU is used, must) only update values that are pinned!
Vector< Problem * > Copy_of_problem_pt
Vector of pointers to copies of the problem used in adaptive bifurcation tracking problems (ALH: TEMP...
void dump_triangulateio(std::ostream &dump_file)
Dump the triangulateio structure to a dump file and record boundary coordinates of boundary nodes...
unsigned Parallel_sparse_assemble_previous_allocation
The amount of data allocated during the previous parallel sparse assemble. Used to optimise the next ...
void solve_eigenproblem(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...
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.
unsigned nnode() const
Return the number of nodes.
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
void delete_all_external_storage()
Wipe the storage for all externally-based elements.
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 ...
A class for compressed row matrices. This is a distributable object.
bool Problem_has_been_distributed
Has the problem been distributed amongst multiple processors?
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
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.
virtual void actions_after_implicit_timestep()
Actions that should be performed after each implicit time step. This is needed when one wants to solv...
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.
bool Doc_imbalance_in_parallel_assembly
Boolean to switch on assessment of load imbalance in parallel assembly of distributed problem...
unsigned uniform_refinement_level_when_pruned() const
Level to which the mesh was uniformly refined when it was pruned (const version)
virtual void set_error_weights()
Set the weights for the error computation, (currently empty – overwrite for specific scheme) ...
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...
double value(const unsigned &i) const
Return i-th value (dofs or pinned) at this node either directly or via hanging node representation...
void restore_dof_values()
Restore the stored values of the degrees of freedom.
void adapt()
Adapt problem: Perform mesh adaptation for (all) refineable (sub)mesh(es), based on their own error e...
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...
double Minimum_dt_but_still_proceed
If Minimum_dt_but_still_proceed positive, then dt will not be reduced below this value during adaptiv...
TreeRoot *& root_pt()
Return pointer to root of the tree.
void rebuild_global_mesh()
If one of the submeshes has changed (e.g. by mesh adaptation) we need to update the global mesh...
double & time()
Return the current value of continuous time.
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...
virtual void actions_before_implicit_timestep()
Actions that should be performed before each implicit time step. This is needed when one wants to sol...
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)...
bool Scale_arc_length
Boolean to control whether arc-length should be scaled.
double Minimum_ds
Minimum desired value of arc-length.
void add_to_dofs(const double &lambda, const DoubleVector &increment_dofs)
Add lambda x incremenet_dofs[l] to the l-th dof.
virtual void complete_setup_of_dependencies()
Complete the setup of any additional dependencies that the element may have. Empty virtual function t...
double max() const
returns the maximum coefficient
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 ...
virtual void read(std::ifstream &restart_file)
Read solution from restart file.
An oomph-lib wrapper to the MPI_Comm communicator object. Just contains an MPI_Comm object (which is ...
void resize(const unsigned long &n)
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...