oomph::Problem Class Reference

#include <problem.h>

+ Inheritance diagram for oomph::Problem:

Public Types

typedef void(* SpatialErrorEstimatorFctPt) (Mesh *&mesh_pt, Vector< double > &elemental_error)
 Function pointer for spatial error estimator. More...
 
typedef void(* SpatialErrorEstimatorWithDocFctPt) (Mesh *&mesh_pt, Vector< double > &elemental_error, DocInfo &doc_info)
 Function pointer for spatial error estimator with doc. More...
 

Public Member Functions

virtual void debug_hook_fct (const unsigned &i)
 
void set_analytic_dparameter (double *const &parameter_pt)
 
void unset_analytic_dparameter (double *const &parameter_pt)
 
bool is_dparameter_calculated_analytically (double *const &parameter_pt)
 
void set_analytic_hessian_products ()
 
void unset_analytic_hessian_products ()
 
bool are_hessian_products_calculated_analytically ()
 
void set_pinned_values_to_zero ()
 
bool distributed () const
 
virtual void actions_before_adapt ()
 
virtual void actions_after_adapt ()
 Actions that are to be performed after a mesh adaptation. More...
 
OomphCommunicatorcommunicator_pt ()
 access function to the oomph-lib communicator More...
 
const OomphCommunicatorcommunicator_pt () const
 access function to the oomph-lib communicator, const version More...
 
 Problem ()
 
 Problem (const Problem &dummy)=delete
 Broken copy constructor. More...
 
void operator= (const Problem &)=delete
 Broken assignment operator. More...
 
virtual ~Problem ()
 Virtual destructor to clean up memory. More...
 
Mesh *& mesh_pt ()
 Return a pointer to the global mesh. More...
 
Mesh *const & mesh_pt () const
 Return a pointer to the global mesh (const version) More...
 
Mesh *& mesh_pt (const unsigned &imesh)
 
Mesh *const & mesh_pt (const unsigned &imesh) const
 Return a pointer to the i-th submesh (const version) More...
 
unsigned nsub_mesh () const
 Return number of submeshes. More...
 
unsigned add_sub_mesh (Mesh *const &mesh_pt)
 
void flush_sub_meshes ()
 
void build_global_mesh ()
 
void rebuild_global_mesh ()
 
LinearSolver *& linear_solver_pt ()
 Return a pointer to the linear solver object. More...
 
LinearSolver *const & linear_solver_pt () const
 Return a pointer to the linear solver object (const version) More...
 
LinearSolver *& mass_matrix_solver_for_explicit_timestepper_pt ()
 
LinearSolvermass_matrix_solver_for_explicit_timestepper_pt () const
 
EigenSolver *& eigen_solver_pt ()
 Return a pointer to the eigen solver object. More...
 
EigenSolver *const & eigen_solver_pt () const
 Return a pointer to the eigen solver object (const version) More...
 
Time *& time_pt ()
 Return a pointer to the global time object. More...
 
Timetime_pt () const
 Return a pointer to the global time object (const version). More...
 
doubletime ()
 Return the current value of continuous time. More...
 
double time () const
 Return the current value of continuous time (const version) More...
 
TimeStepper *& time_stepper_pt ()
 
const TimeSteppertime_stepper_pt () const
 
TimeStepper *& time_stepper_pt (const unsigned &i)
 Return a pointer to the i-th timestepper. More...
 
ExplicitTimeStepper *& explicit_time_stepper_pt ()
 Return a pointer to the explicit timestepper. More...
 
unsigned long set_timestepper_for_all_data (TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data=false)
 
virtual void shift_time_values ()
 Shift all values along to prepare for next timestep. More...
 
AssemblyHandler *& assembly_handler_pt ()
 Return a pointer to the assembly handler object. More...
 
AssemblyHandler *const & assembly_handler_pt () const
 Return a pointer to the assembly handler object (const version) More...
 
doubleminimum_dt ()
 Access function to min timestep in adaptive timestepping. More...
 
doublemaximum_dt ()
 Access function to max timestep in adaptive timestepping. More...
 
unsignedmax_newton_iterations ()
 Access function to max Newton iterations before giving up. More...
 
void problem_is_nonlinear (const bool &prob_lin)
 Access function to Problem_is_nonlinear. More...
 
doublemax_residuals ()
 
booltime_adaptive_newton_crash_on_solve_fail ()
 Access function for Time_adaptive_newton_crash_on_solve_fail. More...
 
doublenewton_solver_tolerance ()
 
void add_time_stepper_pt (TimeStepper *const &time_stepper_pt)
 
void set_explicit_time_stepper_pt (ExplicitTimeStepper *const &explicit_time_stepper_pt)
 
void initialise_dt (const double &dt)
 
void initialise_dt (const Vector< double > &dt)
 
Data *& global_data_pt (const unsigned &i)
 Return a pointer to the the i-th global data object. More...
 
void add_global_data (Data *const &global_data_pt)
 
void flush_global_data ()
 
LinearAlgebraDistribution *const & dof_distribution_pt () const
 Return the pointer to the dof distribution (read-only) More...
 
unsigned long ndof () const
 Return the number of dofs. More...
 
unsigned ntime_stepper () const
 Return the number of time steppers. More...
 
unsigned nglobal_data () const
 Return the number of global data values. More...
 
unsigned self_test ()
 Self-test: Check meshes and global data. Return 0 for OK. More...
 
void enable_store_local_dof_pt_in_elements ()
 
void disable_store_local_dof_pt_in_elements ()
 
unsigned long assign_eqn_numbers (const bool &assign_local_eqn_numbers=true)
 
void describe_dofs (std::ostream &out= *(oomph_info.stream_pt())) const
 
void enable_discontinuous_formulation ()
 
void disable_discontinuous_formulation ()
 
void get_dofs (DoubleVector &dofs) const
 
void get_dofs (const unsigned &t, DoubleVector &dofs) const
 Return vector of the t'th history value of all dofs. More...
 
void set_dofs (const DoubleVector &dofs)
 Set the values of the dofs. More...
 
void set_dofs (const unsigned &t, DoubleVector &dofs)
 Set the history values of the dofs. More...
 
void set_dofs (const unsigned &t, Vector< double * > &dof_pt)
 
void add_to_dofs (const double &lambda, const DoubleVector &increment_dofs)
 Add lambda x incremenet_dofs[l] to the l-th dof. More...
 
doubleglobal_dof_pt (const unsigned &i)
 
doubledof (const unsigned &i)
 i-th dof in the problem More...
 
double dof (const unsigned &i) const
 i-th dof in the problem (const version) More...
 
double *& dof_pt (const unsigned &i)
 Pointer to i-th dof in the problem. More...
 
doubledof_pt (const unsigned &i) const
 Pointer to i-th dof in the problem (const version) More...
 
virtual void get_inverse_mass_matrix_times_residuals (DoubleVector &Mres)
 
virtual void get_dvaluesdt (DoubleVector &f)
 
virtual void get_residuals (DoubleVector &residuals)
 Get the total residuals Vector for the problem. More...
 
virtual void get_jacobian (DoubleVector &residuals, DenseDoubleMatrix &jacobian)
 
virtual void get_jacobian (DoubleVector &residuals, CRDoubleMatrix &jacobian)
 
virtual void get_jacobian (DoubleVector &residuals, CCDoubleMatrix &jacobian)
 
virtual void get_jacobian (DoubleVector &residuals, SumOfMatrices &jacobian)
 
void get_fd_jacobian (DoubleVector &residuals, DenseMatrix< double > &jacobian)
 Get the full Jacobian by finite differencing. More...
 
void get_derivative_wrt_global_parameter (double *const &parameter_pt, DoubleVector &result)
 
void get_hessian_vector_products (DoubleVectorWithHaloEntries const &Y, Vector< DoubleVectorWithHaloEntries > const &C, Vector< DoubleVectorWithHaloEntries > &product)
 
void solve_eigenproblem (const unsigned &n_eval, Vector< std::complex< double >> &eigenvalue, Vector< DoubleVector > &eigenvector, const bool &steady=true)
 Solve the eigenproblem. More...
 
void solve_eigenproblem (const unsigned &n_eval, Vector< std::complex< double >> &eigenvalue, const bool &steady=true)
 
virtual void get_eigenproblem_matrices (CRDoubleMatrix &mass_matrix, CRDoubleMatrix &main_matrix, const double &shift=0.0)
 
void assign_eigenvector_to_dofs (DoubleVector &eigenvector)
 Assign the eigenvector passed to the function to the dofs. More...
 
void add_eigenvector_to_dofs (const double &epsilon, const DoubleVector &eigenvector)
 
void store_current_dof_values ()
 Store the current values of the degrees of freedom. More...
 
void restore_dof_values ()
 Restore the stored values of the degrees of freedom. More...
 
void enable_jacobian_reuse ()
 
void disable_jacobian_reuse ()
 Disable recycling of Jacobian in Newton iteration. More...
 
bool jacobian_reuse_is_enabled ()
 Is recycling of Jacobian in Newton iteration enabled? More...
 
booluse_predictor_values_as_initial_guess ()
 
void newton_solve ()
 Use Newton method to solve the problem. More...
 
void enable_globally_convergent_newton_method ()
 enable globally convergent Newton method More...
 
void disable_globally_convergent_newton_method ()
 disable globally convergent Newton method More...
 
void newton_solve (unsigned const &max_adapt)
 
void steady_newton_solve (unsigned const &max_adapt=0)
 
void copy (Problem *orig_problem_pt)
 
virtual Problemmake_copy ()
 
virtual void read (std::ifstream &restart_file, bool &unsteady_restart)
 
virtual void read (std::ifstream &restart_file)
 
virtual void dump (std::ofstream &dump_file) const
 
void dump (const std::string &dump_file_name) const
 
void delete_all_external_storage ()
 
virtual void symmetrise_eigenfunction_for_adaptive_pitchfork_tracking ()
 
doublebifurcation_parameter_pt () const
 
void get_bifurcation_eigenfunction (Vector< DoubleVector > &eigenfunction)
 
void activate_fold_tracking (double *const &parameter_pt, const bool &block_solve=true)
 
void activate_bifurcation_tracking (double *const &parameter_pt, const DoubleVector &eigenvector, const bool &block_solve=true)
 
void activate_bifurcation_tracking (double *const &parameter_pt, const DoubleVector &eigenvector, const DoubleVector &normalisation, const bool &block_solve=true)
 
void activate_pitchfork_tracking (double *const &parameter_pt, const DoubleVector &symmetry_vector, const bool &block_solve=true)
 
void activate_hopf_tracking (double *const &parameter_pt, const bool &block_solve=true)
 
void activate_hopf_tracking (double *const &parameter_pt, const double &omega, const DoubleVector &null_real, const DoubleVector &null_imag, const bool &block_solve=true)
 
void deactivate_bifurcation_tracking ()
 
void reset_assembly_handler_to_default ()
 Reset the system to the standard non-augemented state. More...
 
double arc_length_step_solve (double *const &parameter_pt, const double &ds, const unsigned &max_adapt=0)
 
double arc_length_step_solve (Data *const &data_pt, const unsigned &data_index, const double &ds, const unsigned &max_adapt=0)
 
void reset_arc_length_parameters ()
 
intsign_of_jacobian ()
 
void explicit_timestep (const double &dt, const bool &shift_values=true)
 Take an explicit timestep of size dt. More...
 
void unsteady_newton_solve (const double &dt)
 
void unsteady_newton_solve (const double &dt, const bool &shift_values)
 
void unsteady_newton_solve (const double &dt, const unsigned &max_adapt, const bool &first, const bool &shift=true)
 
double doubly_adaptive_unsteady_newton_solve (const double &dt, const double &epsilon, const unsigned &max_adapt, const bool &first, const bool &shift=true)
 
double doubly_adaptive_unsteady_newton_solve (const double &dt, const double &epsilon, const unsigned &max_adapt, const unsigned &suppress_resolve_after_spatial_adapt_flag, const bool &first, const bool &shift=true)
 
double adaptive_unsteady_newton_solve (const double &dt_desired, const double &epsilon)
 
double adaptive_unsteady_newton_solve (const double &dt_desired, const double &epsilon, const bool &shift_values)
 
void assign_initial_values_impulsive ()
 
void assign_initial_values_impulsive (const double &dt)
 
void calculate_predictions ()
 Calculate predictions. More...
 
void enable_mass_matrix_reuse ()
 
void disable_mass_matrix_reuse ()
 
bool mass_matrix_reuse_is_enabled ()
 Return whether the mass matrix is being reused. More...
 
void refine_uniformly (const Vector< unsigned > &nrefine_for_mesh)
 
void refine_uniformly (const Vector< unsigned > &nrefine_for_mesh, DocInfo &doc_info)
 
void refine_uniformly_and_prune (const Vector< unsigned > &nrefine_for_mesh)
 
void refine_uniformly_and_prune (const Vector< unsigned > &nrefine_for_mesh, DocInfo &doc_info)
 
void refine_uniformly (DocInfo &doc_info)
 
void refine_uniformly_and_prune (DocInfo &doc_info)
 
void refine_uniformly ()
 
void refine_uniformly (const unsigned &i_mesh, DocInfo &doc_info)
 Do uniform refinement for submesh i_mesh with documentation. More...
 
void refine_uniformly (const unsigned &i_mesh)
 Do uniform refinement for submesh i_mesh without documentation. More...
 
void p_refine_uniformly (const Vector< unsigned > &nrefine_for_mesh)
 
void p_refine_uniformly (const Vector< unsigned > &nrefine_for_mesh, DocInfo &doc_info)
 
void p_refine_uniformly_and_prune (const Vector< unsigned > &nrefine_for_mesh)
 
void p_refine_uniformly_and_prune (const Vector< unsigned > &nrefine_for_mesh, DocInfo &doc_info)
 
void p_refine_uniformly (DocInfo &doc_info)
 
void p_refine_uniformly_and_prune (DocInfo &doc_info)
 
void p_refine_uniformly ()
 
void p_refine_uniformly (const unsigned &i_mesh, DocInfo &doc_info)
 Do uniform p-refinement for submesh i_mesh with documentation. More...
 
void p_refine_uniformly (const unsigned &i_mesh)
 Do uniform p-refinement for submesh i_mesh without documentation. More...
 
void refine_selected_elements (const Vector< unsigned > &elements_to_be_refined)
 
void refine_selected_elements (const Vector< RefineableElement * > &elements_to_be_refined_pt)
 
void refine_selected_elements (const unsigned &i_mesh, const Vector< unsigned > &elements_to_be_refined)
 
void refine_selected_elements (const unsigned &i_mesh, const Vector< RefineableElement * > &elements_to_be_refined_pt)
 
void refine_selected_elements (const Vector< Vector< unsigned >> &elements_to_be_refined)
 
void refine_selected_elements (const Vector< Vector< RefineableElement * >> &elements_to_be_refined_pt)
 
void p_refine_selected_elements (const Vector< unsigned > &elements_to_be_refined)
 
void p_refine_selected_elements (const Vector< PRefineableElement * > &elements_to_be_refined_pt)
 
void p_refine_selected_elements (const unsigned &i_mesh, const Vector< unsigned > &elements_to_be_refined)
 
void p_refine_selected_elements (const unsigned &i_mesh, const Vector< PRefineableElement * > &elements_to_be_refined_pt)
 
void p_refine_selected_elements (const Vector< Vector< unsigned >> &elements_to_be_refined)
 
void p_refine_selected_elements (const Vector< Vector< PRefineableElement * >> &elements_to_be_refined_pt)
 
unsigned unrefine_uniformly ()
 
unsigned unrefine_uniformly (const unsigned &i_mesh)
 
void p_unrefine_uniformly (DocInfo &doc_info)
 
void p_unrefine_uniformly (const unsigned &i_mesh, DocInfo &doc_info)
 Do uniform p-unrefinement for submesh i_mesh without documentation. More...
 
void adapt (unsigned &n_refined, unsigned &n_unrefined)
 
void adapt ()
 
void p_adapt (unsigned &n_refined, unsigned &n_unrefined)
 
void p_adapt ()
 
void adapt_based_on_error_estimates (unsigned &n_refined, unsigned &n_unrefined, Vector< Vector< double >> &elemental_error)
 
void adapt_based_on_error_estimates (Vector< Vector< double >> &elemental_error)
 
void get_all_error_estimates (Vector< Vector< double >> &elemental_error)
 
void doc_errors (DocInfo &doc_info)
 Get max and min error for all elements in submeshes. More...
 
void doc_errors ()
 Get max and min error for all elements in submeshes. More...
 
void enable_info_in_newton_solve ()
 
void disable_info_in_newton_solve ()
 Disable the output of information when in the newton solver. More...
 
- Public Member Functions inherited from oomph::ExplicitTimeSteppableObject
 ExplicitTimeSteppableObject ()
 Empty constructor. More...
 
 ExplicitTimeSteppableObject (const ExplicitTimeSteppableObject &)=delete
 Broken copy constructor. More...
 
void operator= (const ExplicitTimeSteppableObject &)=delete
 Broken assignment operator. More...
 
virtual ~ExplicitTimeSteppableObject ()
 Empty destructor. More...
 
virtual void actions_before_explicit_stage ()
 
virtual void actions_after_explicit_stage ()
 

Public Attributes

bool Shut_up_in_newton_solve
 

Static Public Attributes

static bool Suppress_warning_about_actions_before_read_unstructured_meshes
 

Protected Types

enum  Assembly_method {
  Perform_assembly_using_vectors_of_pairs , Perform_assembly_using_two_vectors , Perform_assembly_using_maps , Perform_assembly_using_lists ,
  Perform_assembly_using_two_arrays
}
 Enumerated flags to determine which sparse assembly method is used. More...
 

Protected Member Functions

unsigned setup_element_count_per_dof ()
 
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)
 
virtual void actions_before_newton_solve ()
 
virtual void actions_after_newton_solve ()
 
virtual void actions_before_newton_convergence_check ()
 
virtual void actions_before_newton_step ()
 
virtual void actions_after_newton_step ()
 
virtual void actions_before_implicit_timestep ()
 
virtual void actions_after_implicit_timestep ()
 
virtual void actions_after_implicit_timestep_and_error_estimation ()
 
virtual void actions_before_explicit_timestep ()
 Actions that should be performed before each explicit time step. More...
 
virtual void actions_after_explicit_timestep ()
 Actions that should be performed after each explicit time step. More...
 
virtual void actions_before_read_unstructured_meshes ()
 
virtual void actions_after_read_unstructured_meshes ()
 
virtual void actions_after_change_in_global_parameter (double *const &parameter_pt)
 
virtual void actions_after_change_in_bifurcation_parameter ()
 
virtual void actions_after_parameter_increase (double *const &parameter_pt)
 
doubledof_derivative (const unsigned &i)
 
doubledof_current (const unsigned &i)
 
virtual void set_initial_condition ()
 
virtual double global_temporal_error_norm ()
 
unsigned newton_solve_continuation (double *const &parameter_pt)
 
unsigned newton_solve_continuation (double *const &parameter_pt, DoubleVector &z)
 
void calculate_continuation_derivatives (double *const &parameter_pt)
 
void calculate_continuation_derivatives (const DoubleVector &z)
 
void calculate_continuation_derivatives_fd (double *const &parameter_pt)
 
bool does_pointer_correspond_to_problem_data (double *const &parameter_pt)
 
void set_consistent_pinned_values_for_continuation ()
 

Protected Attributes

Vector< Problem * > Copy_of_problem_pt
 
std::map< double *, boolCalculate_dparameter_analytic
 
bool Calculate_hessian_products_analytic
 
LinearAlgebraDistributionDof_distribution_pt
 
Vector< double * > Dof_pt
 Vector of pointers to dofs. More...
 
DoubleVectorWithHaloEntries Element_count_per_dof
 
double Relaxation_factor
 
double Newton_solver_tolerance
 
unsigned Max_newton_iterations
 Maximum number of Newton iterations. More...
 
unsigned Nnewton_iter_taken
 
Vector< doubleMax_res
 Maximum residuals at start and after each newton iteration. More...
 
double Max_residuals
 
bool Time_adaptive_newton_crash_on_solve_fail
 
bool Jacobian_reuse_is_enabled
 Is re-use of Jacobian in Newton iteration enabled? Default: false. More...
 
bool Jacobian_has_been_computed
 
bool Problem_is_nonlinear
 
bool Pause_at_end_of_sparse_assembly
 
bool Doc_time_in_distribute
 
unsigned Sparse_assembly_method
 
unsigned Sparse_assemble_with_arrays_initial_allocation
 
unsigned Sparse_assemble_with_arrays_allocation_increment
 
Vector< Vector< unsigned > > Sparse_assemble_with_arrays_previous_allocation
 
double Numerical_zero_for_sparse_assembly
 
double FD_step_used_in_get_hessian_vector_products
 
bool Mass_matrix_reuse_is_enabled
 
bool Mass_matrix_has_been_computed
 
bool Discontinuous_element_formulation
 
double Minimum_dt
 Minimum desired dt: if dt falls below this value, exit. More...
 
double Maximum_dt
 Maximum desired dt. More...
 
double DTSF_max_increase
 
double DTSF_min_decrease
 
double Minimum_dt_but_still_proceed
 
bool Scale_arc_length
 Boolean to control whether arc-length should be scaled. More...
 
double Desired_proportion_of_arc_length
 Proportion of the arc-length to taken by the parameter. More...
 
double Theta_squared
 
int Sign_of_jacobian
 Storage for the sign of the global Jacobian. More...
 
double Continuation_direction
 
double Parameter_derivative
 Storage for the derivative of the global parameter wrt arc-length. More...
 
double Parameter_current
 Storage for the present value of the global parameter. More...
 
bool Use_continuation_timestepper
 Boolean to control original or new storage of dof stuff. More...
 
unsigned Dof_derivative_offset
 
unsigned Dof_current_offset
 
Vector< doubleDof_derivative
 Storage for the derivative of the problem variables wrt arc-length. More...
 
Vector< doubleDof_current
 Storage for the present values of the variables. More...
 
double Ds_current
 Storage for the current step value. More...
 
unsigned Desired_newton_iterations_ds
 
double Minimum_ds
 Minimum desired value of arc-length. More...
 
bool Bifurcation_detection
 Boolean to control bifurcation detection via determinant of Jacobian. More...
 
bool Bisect_to_find_bifurcation
 Boolean to control wheter bisection is used to located bifurcation. More...
 
bool First_jacobian_sign_change
 Boolean to indicate whether a sign change has occured in the Jacobian. More...
 
bool Arc_length_step_taken
 Boolean to indicate whether an arc-length step has been taken. More...
 
bool Use_finite_differences_for_continuation_derivatives
 
OomphCommunicatorCommunicator_pt
 The communicator for this problem. More...
 
bool Always_take_one_newton_step
 
double Timestep_reduction_factor_after_nonconvergence
 
bool Keep_temporal_error_below_tolerance
 

Static Protected Attributes

static ContinuationStorageScheme Continuation_time_stepper
 Storage for the single static continuation timestorage object. More...
 

Private Member Functions

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)
 
void refine_uniformly_aux (const Vector< unsigned > &nrefine_for_mesh, DocInfo &doc_info, const bool &prune)
 
void p_refine_uniformly_aux (const Vector< unsigned > &nrefine_for_mesh, DocInfo &doc_info, const bool &prune)
 
void setup_base_mesh_info_after_pruning ()
 
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)
 
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)
 
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)
 
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)
 
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)
 
void calculate_continuation_derivatives_helper (const DoubleVector &z)
 
void calculate_continuation_derivatives_fd_helper (double *const &parameter_pt)
 
void bifurcation_adapt_helper (unsigned &n_refined, unsigned &n_unrefined, const unsigned &bifurcation_type, const bool &actually_adapt=true)
 
void bifurcation_adapt_doc_errors (const unsigned &bifurcation_type)
 
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. More...
 
double arc_length_step_solve_helper (double *const &parameter_pt, const double &ds, const unsigned &max_adapt)
 

Private Attributes

MeshMesh_pt
 The mesh pointer. More...
 
Vector< Mesh * > Sub_mesh_pt
 Vector of pointers to submeshes. More...
 
LinearSolverLinear_solver_pt
 Pointer to the linear solver for the problem. More...
 
LinearSolverMass_matrix_solver_for_explicit_timestepper_pt
 
EigenSolverEigen_solver_pt
 Pointer to the eigen solver for the problem. More...
 
AssemblyHandlerAssembly_handler_pt
 
LinearSolverDefault_linear_solver_pt
 Pointer to the default linear solver. More...
 
EigenSolverDefault_eigen_solver_pt
 Pointer to the default eigensolver. More...
 
AssemblyHandlerDefault_assembly_handler_pt
 Pointer to the default assembly handler. More...
 
TimeTime_pt
 Pointer to global time for the problem. More...
 
Vector< TimeStepper * > Time_stepper_pt
 
ExplicitTimeStepperExplicit_time_stepper_pt
 Pointer to a single explicit timestepper. More...
 
Vector< double > * Saved_dof_pt
 Pointer to vector for backup of dofs. More...
 
bool Default_set_initial_condition_called
 
bool Use_globally_convergent_newton_method
 Use the globally convergent newton method. More...
 
bool Empty_actions_before_read_unstructured_meshes_has_been_called
 
bool Empty_actions_after_read_unstructured_meshes_has_been_called
 
bool Store_local_dof_pt_in_elements
 
bool Use_predictor_values_as_initial_guess
 Use values from the time stepper predictor as an initial guess. More...
 
Vector< Data * > Global_data_pt
 

Friends

class FoldHandler
 
class PitchForkHandler
 
class HopfHandler
 
template<unsigned NNODE_1D>
class PeriodicOrbitAssemblyHandler
 
class BlockFoldLinearSolver
 
class BlockPitchForkLinearSolver
 
class AugmentedBlockFoldLinearSolver
 
class AugmentedBlockPitchForkLinearSolver
 
class BlockHopfLinearSolver
 

Detailed Description

////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// The Problem class

The main components of a Problem are:

  • a pointer to the (global) Mesh (which provides ordered access to the nodes, elements, etc of all submeshes in the problem – if there are any)
  • pointers to the submeshes (if there are any)
  • pointers to any global Data
  • a pointer to the global Time
  • pointers to the Timestepper used in the problem
  • a pointer to the linear solver that will be used in Newton's method
  • pointers to all DOFs in the problem.

Obviously, at this level in the code hierarchy, many things become very problem-dependent but when setting up a specific problem (as a class that inherits from Problem), the problem constructor will/should typically have a structure similar to this:

// Set up a timestepper
TimeStepper* time_stepper_pt=new Steady;
// Add timestepper to problem
// Build and assign mesh
SomeMesh<ELEMENT_TYPE>(Nelement,time_stepper_pt);
// Set the boundary conditions for this problem: All nodes are
// free by default -- just pin the ones that have Dirichlet conditions
// here (boundary 0 in this example)
unsigned i_bound = 0
unsigned num_nod= mesh_pt()->nboundary_node(ibound);
for (unsigned inod=0;inod<num_nod;inod++)
{
mesh_pt()->boundary_node_pt(ibound,inod)->pin(0);
}
// Complete the build of all elements so they are fully functional
// Setup equation numbering scheme
oomph_info <<"Number of equations: " << assign_eqn_numbers() <<
std::endl;
void pin(const unsigned &i)
Pin the i-th stored variable.
Definition: nodes.h:385
unsigned long nboundary_node(const unsigned &ibound) const
Return number of nodes on a particular boundary.
Definition: mesh.h:833
Node *& boundary_node_pt(const unsigned &b, const unsigned &n)
Return pointer to node n on boundary b.
Definition: mesh.h:493
void add_time_stepper_pt(TimeStepper *const &time_stepper_pt)
Definition: problem.cc:1545
Mesh *& mesh_pt()
Return a pointer to the global mesh.
Definition: problem.h:1280
unsigned long assign_eqn_numbers(const bool &assign_local_eqn_numbers=true)
Definition: problem.cc:1989
TimeStepper *& time_stepper_pt()
Definition: problem.h:1524
bool Steady
Steady flag.
Definition: unstructured_two_d_curved.cc:48
OomphInfo oomph_info
Definition: oomph_definitions.cc:319

For time-dependent problems, we can then use

void assign_initial_values_impulsive()
Definition: problem.cc:11499

to generate an initial guess (for an impulsive start) and the problem can then be solved, e.g. using the steady or unsteady Newton solvers

void newton_solve()
Use Newton method to solve the problem.
Definition: problem.cc:8783

or

void unsteady_newton_solve(const double &dt)
Definition: problem.cc:10953

Member Typedef Documentation

◆ SpatialErrorEstimatorFctPt

typedef void(* oomph::Problem::SpatialErrorEstimatorFctPt) (Mesh *&mesh_pt, Vector< double > &elemental_error)

Function pointer for spatial error estimator.

◆ SpatialErrorEstimatorWithDocFctPt

typedef void(* oomph::Problem::SpatialErrorEstimatorWithDocFctPt) (Mesh *&mesh_pt, Vector< double > &elemental_error, DocInfo &doc_info)

Function pointer for spatial error estimator with doc.

Member Enumeration Documentation

◆ Assembly_method

Enumerated flags to determine which sparse assembly method is used.

Enumerator
Perform_assembly_using_vectors_of_pairs 
Perform_assembly_using_two_vectors 
Perform_assembly_using_maps 
Perform_assembly_using_lists 
Perform_assembly_using_two_arrays 
645  {
651  };
@ Perform_assembly_using_two_arrays
Definition: problem.h:650
@ Perform_assembly_using_maps
Definition: problem.h:648
@ Perform_assembly_using_two_vectors
Definition: problem.h:647
@ Perform_assembly_using_vectors_of_pairs
Definition: problem.h:646
@ Perform_assembly_using_lists
Definition: problem.h:649

Constructor & Destructor Documentation

◆ Problem() [1/2]

Problem::Problem ( )

Constructor: Allocate space for one time stepper and set all pointers to NULL and set defaults for all parameters.

Setup terminate helper

70  : Mesh_pt(0),
71  Time_pt(0),
73  Saved_dof_pt(0),
80 #ifdef OOMPH_HAS_MPI
81  Doc_imbalance_in_parallel_assembly(false),
82  Use_default_partition_in_load_balance(false),
83  Must_recompute_load_balance_for_assembly(true),
84  Halo_scheme_pt(0),
85 #endif
86  Relaxation_factor(1.0),
90  Max_residuals(10.0),
105  Minimum_dt(1.0e-12),
106  Maximum_dt(1.0e12),
107  DTSF_max_increase(4.0),
108  DTSF_min_decrease(0.8),
110  Scale_arc_length(true),
112  Theta_squared(1.0),
113  Sign_of_jacobian(0),
116  Parameter_current(0.0),
120  Ds_current(0.0),
122  Minimum_ds(1.0e-10),
123  Bifurcation_detection(false),
126  Arc_length_step_taken(false),
128 #ifdef OOMPH_HAS_MPI
129  Dist_problem_matrix_distribution(Uniform_matrix_distribution),
130  Parallel_sparse_assemble_previous_allocation(0),
131  Problem_has_been_distributed(false),
132  Bypass_increase_in_dof_check_during_pruning(false),
133  Max_permitted_error_for_halo_check(1.0e-14),
134 #endif
139  {
141 
144 
145  // By default no submeshes:
146  Sub_mesh_pt.resize(0);
147  // No timesteppers
148  Time_stepper_pt.resize(0);
149 
150  // Set the linear solvers, eigensolver and assembly handler
151  Linear_solver_pt = Default_linear_solver_pt = new SuperLUSolver;
153 
155 
156  Assembly_handler_pt = Default_assembly_handler_pt = new AssemblyHandler;
157 
158  // setup the communicator
159 #ifdef OOMPH_HAS_MPI
161  {
162  Communicator_pt = new OomphCommunicator(MPI_Helpers::communicator_pt());
163  }
164  else
165  {
166  Communicator_pt = new OomphCommunicator();
167  }
168 #else
169  Communicator_pt = new OomphCommunicator();
170 #endif
171 
172  // just create an empty linear algebra distribution for the
173  // DOFs
174  // this is setup when assign_eqn_numbers(...) is called.
175  Dof_distribution_pt = new LinearAlgebraDistribution;
176  }
static bool mpi_has_been_initialised()
return true if MPI has been initialised
Definition: oomph_utilities.h:851
static OomphCommunicator * communicator_pt()
access to the global oomph-lib communicator
Definition: oomph_utilities.cc:1046
bool Always_take_one_newton_step
Definition: problem.h:2197
bool Jacobian_reuse_is_enabled
Is re-use of Jacobian in Newton iteration enabled? Default: false.
Definition: problem.h:618
bool Store_local_dof_pt_in_elements
Definition: problem.h:226
bool Bifurcation_detection
Boolean to control bifurcation detection via determinant of Jacobian.
Definition: problem.h:790
double Theta_squared
Definition: problem.h:742
bool Jacobian_has_been_computed
Definition: problem.h:622
double Timestep_reduction_factor_after_nonconvergence
Definition: problem.h:2202
double Desired_proportion_of_arc_length
Proportion of the arc-length to taken by the parameter.
Definition: problem.h:734
EigenSolver * Default_eigen_solver_pt
Pointer to the default eigensolver.
Definition: problem.h:191
unsigned Nnewton_iter_taken
Definition: problem.h:603
bool Time_adaptive_newton_crash_on_solve_fail
Definition: problem.h:615
unsigned Sparse_assembly_method
Definition: problem.h:641
LinearSolver * Linear_solver_pt
Pointer to the linear solver for the problem.
Definition: problem.h:173
bool Doc_time_in_distribute
Definition: problem.h:637
unsigned Max_newton_iterations
Maximum number of Newton iterations.
Definition: problem.h:599
unsigned Dof_current_offset
Definition: problem.h:771
bool Empty_actions_before_read_unstructured_meshes_has_been_called
Definition: problem.h:218
bool Mass_matrix_has_been_computed
Definition: problem.h:695
bool First_jacobian_sign_change
Boolean to indicate whether a sign change has occured in the Jacobian.
Definition: problem.h:796
double Continuation_direction
Definition: problem.h:749
bool Scale_arc_length
Boolean to control whether arc-length should be scaled.
Definition: problem.h:731
bool Empty_actions_after_read_unstructured_meshes_has_been_called
Definition: problem.h:222
double Maximum_dt
Maximum desired dt.
Definition: problem.h:709
bool Use_finite_differences_for_continuation_derivatives
Definition: problem.h:803
bool Arc_length_step_taken
Boolean to indicate whether an arc-length step has been taken.
Definition: problem.h:799
bool Default_set_initial_condition_called
Definition: problem.h:211
double Relaxation_factor
Definition: problem.h:592
double Parameter_current
Storage for the present value of the global parameter.
Definition: problem.h:755
OomphCommunicator * Communicator_pt
The communicator for this problem.
Definition: problem.h:1242
double Newton_solver_tolerance
Definition: problem.h:596
bool Discontinuous_element_formulation
Definition: problem.h:700
Mesh * Mesh_pt
The mesh pointer.
Definition: problem.h:167
double Parameter_derivative
Storage for the derivative of the global parameter wrt arc-length.
Definition: problem.h:752
double DTSF_max_increase
Definition: problem.h:713
bool Keep_temporal_error_below_tolerance
Definition: problem.h:2209
bool Shut_up_in_newton_solve
Definition: problem.h:2191
Vector< Mesh * > Sub_mesh_pt
Vector of pointers to submeshes.
Definition: problem.h:170
EigenSolver * Eigen_solver_pt
Pointer to the eigen solver for the problem.
Definition: problem.h:182
bool Bisect_to_find_bifurcation
Boolean to control wheter bisection is used to located bifurcation.
Definition: problem.h:793
double DTSF_min_decrease
Definition: problem.h:718
double Minimum_dt_but_still_proceed
Definition: problem.h:725
unsigned Desired_newton_iterations_ds
Definition: problem.h:784
bool Calculate_hessian_products_analytic
Definition: problem.h:244
int Sign_of_jacobian
Storage for the sign of the global Jacobian.
Definition: problem.h:745
double Max_residuals
Definition: problem.h:610
bool Use_globally_convergent_newton_method
Use the globally convergent newton method.
Definition: problem.h:214
LinearSolver * Default_linear_solver_pt
Pointer to the default linear solver.
Definition: problem.h:188
double Minimum_ds
Minimum desired value of arc-length.
Definition: problem.h:787
double Numerical_zero_for_sparse_assembly
Definition: problem.h:671
double FD_step_used_in_get_hessian_vector_products
Definition: problem.h:685
unsigned Sparse_assemble_with_arrays_initial_allocation
Definition: problem.h:658
double Ds_current
Storage for the current step value.
Definition: problem.h:780
LinearSolver * Mass_matrix_solver_for_explicit_timestepper_pt
Definition: problem.h:179
double Minimum_dt
Minimum desired dt: if dt falls below this value, exit.
Definition: problem.h:706
bool Use_continuation_timestepper
Boolean to control original or new storage of dof stuff.
Definition: problem.h:758
LinearAlgebraDistribution * Dof_distribution_pt
Definition: problem.h:460
bool Problem_is_nonlinear
Definition: problem.h:628
AssemblyHandler * Default_assembly_handler_pt
Pointer to the default assembly handler.
Definition: problem.h:194
Time * Time_pt
Pointer to global time for the problem.
Definition: problem.h:197
unsigned Sparse_assemble_with_arrays_allocation_increment
Definition: problem.h:663
bool Pause_at_end_of_sparse_assembly
Definition: problem.h:633
Vector< double > * Saved_dof_pt
Pointer to vector for backup of dofs.
Definition: problem.h:207
AssemblyHandler * Assembly_handler_pt
Definition: problem.h:185
unsigned Dof_derivative_offset
Definition: problem.h:766
Vector< TimeStepper * > Time_stepper_pt
Definition: problem.h:201
bool Mass_matrix_reuse_is_enabled
Definition: problem.h:691
ExplicitTimeStepper * Explicit_time_stepper_pt
Pointer to a single explicit timestepper.
Definition: problem.h:204
bool Use_predictor_values_as_initial_guess
Use values from the time stepper predictor as an initial guess.
Definition: problem.h:229
void setup()
Setup terminate helper.
Definition: oomph_definitions.cc:63

References Assembly_handler_pt, oomph::MPI_Helpers::communicator_pt(), Communicator_pt, Default_assembly_handler_pt, Default_eigen_solver_pt, Default_linear_solver_pt, Dof_distribution_pt, Eigen_solver_pt, Linear_solver_pt, Mass_matrix_solver_for_explicit_timestepper_pt, oomph::MPI_Helpers::mpi_has_been_initialised(), oomph::TerminateHelper::setup(), Sub_mesh_pt, Time_stepper_pt, and Use_predictor_values_as_initial_guess.

◆ Problem() [2/2]

oomph::Problem::Problem ( const Problem dummy)
delete

Broken copy constructor.

◆ ~Problem()

Problem::~Problem ( )
virtual

Virtual destructor to clean up memory.

Destructor to clean up memory.

182  {
183  // Delete the memory assigned for the global time
184  // (it's created on the fly in Problem::add_time_stepper_pt()
185  // so we are entitled to delete it.
186  if (Time_pt != 0)
187  {
188  delete Time_pt;
189  Time_pt = 0;
190  }
191 
192  // We're not using the default linear solver,
193  // somebody else must have built it, so that person
194  // must be in charge of killing it.
195  // We can safely delete the defaults, however
197 
200  delete Communicator_pt;
201  delete Dof_distribution_pt;
202 
203  // Delete any copies of the problem that have been created for
204  // use in adaptive bifurcation tracking.
205  // ALH: This will eventually go
206  unsigned n_copies = Copy_of_problem_pt.size();
207  for (unsigned c = 0; c < n_copies; c++)
208  {
209  delete Copy_of_problem_pt[c];
210  }
211 
212  // if this problem has sub meshes then we must delete the Mesh_pt
213  if (Sub_mesh_pt.size() != 0)
214  {
216  delete Mesh_pt;
217  }
218 
219  // Since we called the TerminateHelper setup function in the constructor,
220  // we need to delete anything that was dynamically allocated (as it's
221  // just a namespace and so doesn't have it's own destructor) in the function
223  }
void flush_element_and_node_storage()
Definition: mesh.h:407
Vector< Problem * > Copy_of_problem_pt
Definition: problem.h:234
int c
Definition: calibrate.py:100
void clean_up_memory()
Definition: oomph_definitions.cc:86

References calibrate::c, oomph::TerminateHelper::clean_up_memory(), Communicator_pt, Copy_of_problem_pt, Default_assembly_handler_pt, Default_eigen_solver_pt, Default_linear_solver_pt, Dof_distribution_pt, oomph::Mesh::flush_element_and_node_storage(), Mesh_pt, Sub_mesh_pt, and Time_pt.

Member Function Documentation

◆ actions_after_adapt()

virtual void oomph::Problem::actions_after_adapt ( )
inlinevirtual

Actions that are to be performed after a mesh adaptation.

Reimplemented in MortaringValidationProblem< ELEMENT, NON_MORTAR_ELEMENT >, MortaringValidationProblem< ELEMENT, NON_MORTAR_ELEMENT >, DrivenCavityProblem< ELEMENT, MESH >, RefineableDrivenCavityProblem< ELEMENT >, UnstructuredPoissonProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, RefineableYoungLaplaceProblem< ELEMENT >, RefineableYoungLaplaceProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, RingWithTRibProblem< ELASTICITY_ELEMENT >, AnnularDiskProblem< ELASTICITY_ELEMENT >, FourierDecomposedTimeHarmonicLinearElasticityProblem< ELEMENT >, FourierDecomposedTimeHarmonicLinearElasticityProblem< ELEMENT >, SphericalSpinUpProblem< ELEMENT >, RefineableSphericalSpinUpProblem< ELEMENT >, RefineableSphericalSpinUpProblem< ELEMENT >, RefineableSphericalCouetteProblem< ELEMENT >, UnstructuredSolidProblem< ELEMENT, MESH >, BlockCompressionProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, CantileverProblem< ELEMENT >, ElasticFishProblem< ELEMENT >, SimpleShearProblem< ELEMENT >, DiskShockWaveProblem< ELEMENT, TIMESTEPPER >, CollapsibleChannelProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, CantileverProblem< ELEMENT >, CantileverProblem< ELEMENT >, RefineableActivatorInhibitorProblem< ELEMENT >, oomph::StreamfunctionProblem, PolarNSProblem< ELEMENT >, RefineableTwoMeshFluxPoissonProblem< ELEMENT >, EighthSpherePoissonProblem< ELEMENT >, ElasticAnnulusProblem< ELASTICITY_ELEMENT >, ElasticAnnulusProblem< ELASTICITY_ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RayleighProblem< ELEMENT, TIMESTEPPER >, VorticityRecoveryProblem< ELEMENT >, DropInChannelProblem< ELEMENT >, BubbleInChannelProblem< ELEMENT >, UnstructuredFluidProblem< ELEMENT >, RisingBubbleProblem< ELEMENT >, FallingBlockProblem< ELEMENT >, TwoLayerInterfaceProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, TurekNonFSIProblem< ELEMENT >, EntryFlowProblem< ELEMENT >, SteadyTubeProblem< ELEMENT >, FpTestProblem, FpTestProblem, OscRingNStProblem< ELEMENT >, OscEllipseProblem< ELEMENT, TIMESTEPPER >, RefineableDrivenCavityProblem< ELEMENT >, UnstructuredImmersedEllipseProblem< ELEMENT >, PRefineableDrivenCavityProblem< ELEMENT >, QuarterCircleDrivenCavityProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, EntryFlowProblem< ELEMENT >, SteadyHelicalProblem< ELEMENT >, SteadyCurvedTubeProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, QuarterCircleDrivenCavityProblem2< ELEMENT >, QuarterCircleDrivenCavityProblem< ELEMENT >, ChannelWithLeafletProblem< ELEMENT >, RefineableRotatingCylinderProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, FluxPoissonMGProblem< ELEMENT, MESH >, FluxPoissonMGProblem< ELEMENT, MESH >, PMLHelmholtzMGProblem< ELEMENT >, PMLStructuredCubicHelmholtz< ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, RefineableSphereConvectionProblem< ELEMENT >, RefineableDDConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, FlowAroundHalfCylinderProblem< ELEMENT >, FlowAroundHalfCylinderProblem< ELEMENT >, FlowAroundHalfCylinderProblem< ELEMENT >, FlowAroundHalfCylinderProblem< ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, RectangularDrivenCavityProblem< ELEMENT >, CantileverProblem< ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, FSIRingProblem, FSICollapsibleChannelProblem< ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, RefineableTwoMeshFluxPoissonProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, EntryFlowProblem< ELEMENT >, CantileverProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, PRefineableDrivenCavityProblem< ELEMENT >, PRefineableDrivenCavityProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, QuarterCircleDrivenCavityProblem< ELEMENT >, CantileverProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, UnstructuredSolidProblem< ELEMENT, MESH >, ScatteringProblem< ELEMENT >, MovingBlockProblem< ELEMENT >, UnstructuredPoissonProblem< ELEMENT >, TetmeshPoissonProblem< ELEMENT >, TetmeshPoissonProblem< ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, TwoMeshFluxAdvectionDiffusionProblem< ELEMENT >, RefineablePeriodicLoadProblem< ELEMENT >, UnstructuredFSIProblem< FLUID_ELEMENT, SOLID_ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, OscRingNStProblem< ELEMENT >, OscRingNStProblem< ELEMENT >, FSIRingProblem, FSIRingProblem, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, DeformableFishPoissonProblem< ELEMENT >, DeformableFishPoissonProblem< ELEMENT >, CoatedSphereProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, CoatedDiskProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, CoatedDiskProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, ScatteringProblem< ELEMENT >, ScatteringProblem< ELEMENT >, HelmholtzPointSourceProblem< ELEMENT >, ContactProblem< ELEMENT >, ContactProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatMeltProblem< ELEMENT >, ContactProblem< ELEMENT >, ContactProblem< ELEMENT >, SolarRadiationProblem< ELEMENT >, MeltContactProblem< ELEMENT >, VibratingShellProblem< ELEMENT >, AxisymmetricVibratingShellProblem< ELEMENT >, FourierDecomposedHelmholtzProblem< ELEMENT >, UnstructuredFvKProblem< ELEMENT >, ExtrudedMovingCylinderProblem< TWO_D_ELEMENT, THREE_D_ELEMENT >, MovingBlockProblem< ELEMENT >, RefineablePorousChannelProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, UnstructuredTorusProblem< ELEMENT >, UnstructuredTorusProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, TorusProblem< ELEMENT >, RotatingCylinderProblem< ELEMENT, TIMESTEPPER >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, TwoMeshFluxAdvectionDiffusionProblem< ELEMENT >, and MortaringValidationProblem< ELEMENT, NON_MORTAR_ELEMENT >.

1025 {}

Referenced by adapt(), adapt_based_on_error_estimates(), p_adapt(), p_refine_selected_elements(), p_refine_uniformly(), p_refine_uniformly_aux(), p_unrefine_uniformly(), read(), refine_selected_elements(), refine_uniformly(), refine_uniformly_aux(), oomph::MGSolver< DIM >::setup_mg_hierarchy(), oomph::HelmholtzMGPreconditioner< DIM >::setup_mg_hierarchy(), and unrefine_uniformly().

◆ actions_after_change_in_bifurcation_parameter()

virtual void oomph::Problem::actions_after_change_in_bifurcation_parameter ( )
inlineprotectedvirtual

Actions that are to be performed after a change in the parameter that is being varied as part of the solution of a bifurcation detection problem. The default is to call actions_before_newton_solve(), actions_before_newton_convergence_check() and actions_after_newton_solve(). This could be amazingly inefficient in certain problems and should be overloaded in such cases. An example would be when a remesh is required in general, but the global parameter does not affect the mesh directly.

Reimplemented in RotatingProblem< ELEMENT >, RotatingProblem< ELEMENT >, and RefineablePorousChannelProblem< ELEMENT >.

1152  {
1153  // Default action should cover all possibilities
1157  }
virtual void actions_after_newton_solve()
Definition: problem.h:1038
virtual void actions_before_newton_solve()
Definition: problem.h:1032
virtual void actions_before_newton_convergence_check()
Definition: problem.h:1048

References actions_after_newton_solve(), actions_before_newton_convergence_check(), and actions_before_newton_solve().

Referenced by oomph::FoldHandler::get_jacobian(), oomph::PitchForkHandler::get_jacobian(), oomph::HopfHandler::get_jacobian(), oomph::AugmentedBlockFoldLinearSolver::resolve(), oomph::AugmentedBlockPitchForkLinearSolver::resolve(), oomph::AugmentedBlockFoldLinearSolver::solve(), oomph::AugmentedBlockPitchForkLinearSolver::solve(), oomph::BlockHopfLinearSolver::solve(), and oomph::BlockHopfLinearSolver::solve_for_two_rhs().

◆ actions_after_change_in_global_parameter()

virtual void oomph::Problem::actions_after_change_in_global_parameter ( double *const &  parameter_pt)
inlineprotectedvirtual

Actions that are to be performed when the global parameter addressed by parameter_pt has been changed in the function get_derivative_wrt_global_parameter() The default is to call actions_before_newton_solve(), actions_before_newton_convergence_check() and actions_after_newton_solve(). This could be amazingly inefficient in certain problems and should be overloaded in such cases. An example would be when a remesh is required in general, but the global parameter does not affect the mesh directly.

Reimplemented in AirwayReopeningProblem< ELEMENT >.

1135  {
1136  // Default action should cover all possibilities
1140  }

References actions_after_newton_solve(), actions_before_newton_convergence_check(), and actions_before_newton_solve().

Referenced by get_derivative_wrt_global_parameter().

◆ actions_after_explicit_timestep()

virtual void oomph::Problem::actions_after_explicit_timestep ( )
inlineprotectedvirtual

Actions that should be performed after each explicit time step.

Reimplemented from oomph::ExplicitTimeSteppableObject.

Reimplemented in oomph::MyProblem.

1081 {}

◆ actions_after_implicit_timestep()

virtual void oomph::Problem::actions_after_implicit_timestep ( )
inlineprotectedvirtual

Actions that should be performed after each implicit time step. This is needed when one wants to solve a steady problem before timestepping and needs to distinguish between the two cases

Reimplemented in UnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, RefineableSphericalSpinUpProblem< ELEMENT >, RefineableSphericalSpinUpProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, oomph::MyProblem, OscEllipseProblem< ELEMENT, TIMESTEPPER >, RefineableUnsteadyHeatProblem< ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, UnsteadyHeatProblem< ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, and BaseStateProblem< BASE_ELEMENT >.

1070 {}

Referenced by adaptive_unsteady_newton_solve(), unsteady_newton_solve(), and oomph::SegregatableFSIProblem::unsteady_segregated_solve().

◆ actions_after_implicit_timestep_and_error_estimation()

virtual void oomph::Problem::actions_after_implicit_timestep_and_error_estimation ( )
inlineprotectedvirtual

Actions that should be performed after each implicit time step. This is needed if your actions_after_implicit_timestep() modify the solution in a way that affects the error estimate.

1075 {}

Referenced by adaptive_unsteady_newton_solve(), and unsteady_newton_solve().

◆ actions_after_newton_solve()

virtual void oomph::Problem::actions_after_newton_solve ( )
inlineprotectedvirtual

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!

Reimplemented in OneDPoissonProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, oomph::WomersleyProblem< ELEMENT, DIM >, oomph::SolidICProblem, oomph::BiharmonicFluidProblem< DIM >, oomph::BiharmonicProblem< DIM >, oomph::BiharmonicProblem< 2 >, TestPoissonProblem< ELEMENT >, TestRefineablePoissonProblem< ELEMENT >, TestPoissonProblem< ELEMENT >, TFaceTestProblem< ELEMENT >, TriangleFaceTestProblem< ELEMENT >, QFaceTestProblem< ELEMENT >, QFaceTestProblem< ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, EighthSpherePoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, DrivenCavityProblem< ELEMENT, MESH >, RefineablePoissonProblem< ELEMENT >, ThreeDPoissonProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, RectangularDrivenCavityProblem< ELEMENT >, UnstructuredPoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, EighthSpherePoissonProblem< ELEMENT >, RefineablePoissonProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, YoungLaplaceProblem< ELEMENT >, RefineableYoungLaplaceProblem< ELEMENT >, RefineableYoungLaplaceProblem< ELEMENT >, YoungLaplaceProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, RingWithTRibProblem< ELASTICITY_ELEMENT >, AnnularDiskProblem< ELASTICITY_ELEMENT >, FourierDecomposedTimeHarmonicLinearElasticityProblem< ELEMENT >, FourierDecomposedTimeHarmonicLinearElasticityProblem< ELEMENT >, FourierDecomposedTimeHarmonicLinearElasticityProblem< ELEMENT >, SphericalSteadyRotationProblem< ELEMENT >, SphericalSpinUpProblem< ELEMENT >, SphericalSpinUpProblem< ELEMENT >, RefineableSphericalSpinUpProblem< ELEMENT >, RefineableSphericalSpinUpProblem< ELEMENT >, UnstructuredSolidProblem< ELEMENT, MESH >, UnstructuredSolidProblem< ELEMENT, MESH >, BlockCompressionProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, CantileverProblem< ELEMENT >, ElasticFishProblem< ELEMENT >, SimpleShearProblem< ELEMENT >, SimpleShearProblem< ELEMENT >, DiskShockWaveProblem< ELEMENT, TIMESTEPPER >, CollapsibleChannelProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, DiskOscillationProblem< ELEMENT >, StaticDiskCompressionProblem< ELEMENT >, CompressedSquareProblem< ELEMENT >, CantileverProblem< ELEMENT >, CantileverProblem< ELEMENT >, PlateProblem< ELEMENT >, ShellProblem< ELEMENT >, ShellProblem< ELEMENT >, ShellProblem< ELEMENT >, ShellProblem< ELEMENT >, RefineableActivatorInhibitorProblem< ELEMENT >, RefineableActivatorInhibitorProblem< ELEMENT >, ActivatorInhibitorProblem< ELEMENT >, RefineableTwoDPoissonProblem< ELEMENT >, RefineableTwoMeshFluxPoissonProblem< ELEMENT >, TwoMeshFluxPoissonProblem< ELEMENT >, FluxPoissonProblem< ELEMENT >, RefineablePoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, RefineablePoissonProblem< ELEMENT >, EighthSpherePoissonProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, PRefineableOneDPoissonProblem< ELEMENT >, DemoPoissonProblem, RefineableOneDPoissonProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, SimpleRefineableFishPoissonProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, FishPoissonProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, FishPoissonProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, EighthSpherePoissonProblem< ELEMENT >, EighthSpherePoissonProblem< ELEMENT >, ElasticAnnulusProblem< ELASTICITY_ELEMENT >, ElasticAnnulusProblem< ELASTICITY_ELEMENT >, PMLProblem< ELEMENT >, PMLProblem< ELEMENT >, PMLFourierDecomposedHelmholtzProblem< ELEMENT >, RefineablePoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, RectangularDrivenCavityProblem< ELEMENT >, PoissonProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, RayleighProblem< ELEMENT, TIMESTEPPER >, RayleighProblem< ELEMENT, TIMESTEPPER >, VorticityRecoveryProblem< ELEMENT >, UnstructuredFluidProblem< ELEMENT >, DropInChannelProblem< ELEMENT >, BubbleInChannelProblem< ELEMENT >, UnstructuredFluidProblem< ELEMENT >, RisingBubbleProblem< ELEMENT >, FallingBlockProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, TwoLayerInterfaceProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, TurekNonFSIProblem< ELEMENT >, FreeSurfaceRotationProblem< ELEMENT >, EntryFlowProblem< ELEMENT >, SpikedChannelSpineFlowProblem< ELEMENT >, ChannelSpineFlowProblem< ELEMENT >, ChannelSpineFlowProblem< ELEMENT >, NavierStokesProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, FpTestProblem, FpTestProblem, RayleighTractionProblem< ELEMENT, TIMESTEPPER >, RayleighProblem< ELEMENT, TIMESTEPPER >, OscRingNStProblem< ELEMENT >, OscRingNStProblem< ELEMENT >, OscEllipseProblem< ELEMENT, TIMESTEPPER >, RectangularDrivenCavityProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, PRefineableDrivenCavityProblem< ELEMENT >, QuarterCircleDrivenCavityProblem< ELEMENT >, FreeSurfaceRotationProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, EntryFlowProblem< ELEMENT >, RectangularDrivenCavityProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, QuarterCircleDrivenCavityProblem2< ELEMENT >, QuarterCircleDrivenCavityProblem< ELEMENT >, ChannelWithLeafletProblem< ELEMENT >, BrethertonProblem< ELEMENT >, RefineableRotatingCylinderProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, UnitCubePoissonMGProblem< ELEMENT, MESH >, UnitCubePoissonMGProblem< ELEMENT, MESH >, FluxPoissonMGProblem< ELEMENT, MESH >, FluxPoissonMGProblem< ELEMENT, MESH >, PMLHelmholtzMGProblem< ELEMENT >, PMLStructuredCubicHelmholtz< ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, ThermalProblem< ELEMENT >, AxisymFreeSurfaceNozzleAdvDiffRobinProblem< ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, DDConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, FlowAroundHalfCylinderProblem< ELEMENT >, FlowAroundHalfCylinderProblem< ELEMENT >, FlowAroundHalfCylinderProblem< ELEMENT >, FlowAroundHalfCylinderProblem< ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, MultiPoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, RectangularDrivenCavityProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, CantileverProblem< ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, FSIRingProblem, FSICollapsibleChannelProblem< ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, RefineableTwoMeshFluxPoissonProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, EntryFlowProblem< ELEMENT >, CantileverProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, RefineableTwoDPoissonProblem< ELEMENT >, PRefineableDrivenCavityProblem< ELEMENT >, PRefineableDrivenCavityProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, HarmonicProblem< ELEMENT, EIGEN_SOLVER >, ShellProblem< ELEMENT >, QuarterCircleDrivenCavityProblem< ELEMENT >, RotatingProblem< ELEMENT >, UniformTranspiration< ELEMENT >, CantileverProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, ScatteringProblem< ELEMENT >, MovingBlockProblem< ELEMENT >, PoissonProblem< ELEMENT >, FlowPastBoxProblem< ELEMENT >, PoissonProblem< ELEMENT >, FlowPastBoxProblem< ELEMENT >, PoissonProblem< ELEMENT >, NavierStokesProblem< ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, UnstructuredPoissonProblem< ELEMENT >, UnstructuredPoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, TetmeshPoissonProblem< ELEMENT >, TetmeshPoissonProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, MultiPoissonProblem< ELEMENT >, PeriodicLoadProblem< ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, RectangularDrivenCavityProblem< ELEMENT >, RectangularDrivenCavityProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, TwoMeshFluxAdvectionDiffusionProblem< ELEMENT >, RefineablePeriodicLoadProblem< ELEMENT >, PeriodicLoadProblem< ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, OscRingNStProblem< ELEMENT >, OscRingNStProblem< ELEMENT >, FSIRingProblem, FSIRingProblem, SegregatedFSIDrivenCavityProblem< ELEMENT >, FSIDrivenCavityProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, PreconditionedFSICollapsibleChannelProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, FreeBoundaryPoissonProblem< ELEMENT >, FreeBoundaryPoissonProblem< ELEMENT >, GeomObjectAsGeneralisedElementProblem, DeformableFishPoissonProblem< ELEMENT >, DeformableFishPoissonProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, CoatedSphereProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, CoatedSphereProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, AirwayReopeningProblem< ELEMENT >, CoatedDiskProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, CoatedDiskProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, HomogenisationProblem< ELEMENT >, HomogenisationProblem< ELEMENT >, ScatteringProblem< ELEMENT >, ScatteringProblem< ELEMENT >, HelmholtzPointSourceProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, StefanBoltzmannProblem< ELEMENT >, StefanBoltzmannProblem< ELEMENT >, ContactProblem< ELEMENT >, ContactProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatMeltProblem< ELEMENT >, ContactProblem< ELEMENT >, ContactProblem< ELEMENT >, SolarRadiationProblem< ELEMENT >, MeltContactProblem< ELEMENT >, VibratingShellProblem< ELEMENT >, AxisymmetricVibratingShellProblem< ELEMENT >, FourierDecomposedHelmholtzProblem< ELEMENT >, FourierDecomposedHelmholtzProblem< ELEMENT >, UnstructuredFvKProblem< ELEMENT >, ExtrudedMovingCylinderProblem< TWO_D_ELEMENT, THREE_D_ELEMENT >, MovingBlockProblem< ELEMENT >, ContinuationProblem, OrrSommerfeldProblem< ELEMENT >, RotatingProblem< ELEMENT >, UniformTranspiration< ELEMENT >, ABCProblem< ELEMENT, TIMESTEPPERT >, PredPreyProblem< ELEMENT >, BratuProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, ElasticRingProblem< ELEMENT >, ElasticRingProblem< ELEMENT >, ElasticBeamProblem, ElasticRingProblem< ELEMENT >, ElasticRingProblem< ELEMENT >, AxiPoroProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, RotatingCylinderProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, RotatingProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, MeltSpinningProblem< ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, AxisymmetricLinearElasticityProblem< ELEMENT, TIMESTEPPER >, AxisymFvKProblem< ELEMENT >, AxisymFvKProblem< ELEMENT >, RefineableAdvectionDiffusionPipeProblem< ELEMENT >, UnstructuredFvKProblem< ELEMENT >, UnstructuredFvKProblem< ELEMENT >, AxisymFvKProblem< ELEMENT >, AxisymFvKProblem< ELEMENT >, RefineableAdvectionDiffusionProblem< ELEMENT >, SUPGAdvectionDiffusionProblem< ELEMENT >, TwoMeshFluxAdvectionDiffusionProblem< ELEMENT >, RefineableAdvectionDiffusionProblem< ELEMENT >, RefineableAdvectionDiffusionProblem< ELEMENT >, SheetGlueProblem< ELEMENT >, SheetGlueProblem< ELEMENT >, and BendingCantileverProblem< ELEMENT >.

1038 {}

Referenced by actions_after_change_in_bifurcation_parameter(), actions_after_change_in_global_parameter(), oomph::MyProblem::actions_after_explicit_timestep(), adaptive_unsteady_newton_solve(), get_fd_jacobian(), newton_solve(), and newton_solve_continuation().

◆ actions_after_newton_step()

virtual void oomph::Problem::actions_after_newton_step ( )
inlineprotectedvirtual

Any actions that are to be performed after each individual Newton step. Most likely to be used for diagnostic purposes to doc the solution during a non-converging iteration, say.

Reimplemented in oomph::MyProblem, FpTestProblem, FpTestProblem, and TiltedCavityProblem< ELEMENT >.

1058 {}

Referenced by adaptive_unsteady_newton_solve(), newton_solve(), and newton_solve_continuation().

◆ actions_after_parameter_increase()

virtual void oomph::Problem::actions_after_parameter_increase ( double *const &  parameter_pt)
inlineprotectedvirtual

Empty virtual function; provides hook to perform actions after the increase in the arclength parameter (during continuation)

Reimplemented in NavierStokesProblem< ELEMENT >.

1162  {
1163  }

Referenced by arc_length_step_solve_helper().

◆ actions_after_read_unstructured_meshes()

virtual void oomph::Problem::actions_after_read_unstructured_meshes ( )
inlineprotectedvirtual

Actions that are to be performed before reading in restart data for problems involving unstructured bulk meshes. Typically used to re-attach FaceElements, say, that were stripped out in actions_before_read_unstructured_meshes(). This function is virtual and (practically) empty but toggles a flag to indicate that it has been called. This is used to issue a warning, prompting the user to consider overloading it if the problem is found to contain unstructured bulk meshes during restarts.

References Empty_actions_after_read_unstructured_meshes_has_been_called.

Referenced by read().

◆ actions_before_adapt()

virtual void oomph::Problem::actions_before_adapt ( )
inlinevirtual

Actions that are to be performed before a mesh adaptation. These might include removing any additional elements, such as traction boundary elements before the adaptation.

Reimplemented in MortaringValidationProblem< ELEMENT, NON_MORTAR_ELEMENT >, MortaringValidationProblem< ELEMENT, NON_MORTAR_ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, UnstructuredPoissonProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, RefineableYoungLaplaceProblem< ELEMENT >, RefineableYoungLaplaceProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, RingWithTRibProblem< ELASTICITY_ELEMENT >, AnnularDiskProblem< ELASTICITY_ELEMENT >, FourierDecomposedTimeHarmonicLinearElasticityProblem< ELEMENT >, FourierDecomposedTimeHarmonicLinearElasticityProblem< ELEMENT >, UnstructuredSolidProblem< ELEMENT, MESH >, BlockCompressionProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, CantileverProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, CantileverProblem< ELEMENT >, CantileverProblem< ELEMENT >, RefineableActivatorInhibitorProblem< ELEMENT >, oomph::StreamfunctionProblem, PolarNSProblem< ELEMENT >, RefineableTwoMeshFluxPoissonProblem< ELEMENT >, EighthSpherePoissonProblem< ELEMENT >, ElasticAnnulusProblem< ELASTICITY_ELEMENT >, ElasticAnnulusProblem< ELASTICITY_ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, VorticityRecoveryProblem< ELEMENT >, DropInChannelProblem< ELEMENT >, BubbleInChannelProblem< ELEMENT >, UnstructuredFluidProblem< ELEMENT >, TwoLayerInterfaceProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, OscEllipseProblem< ELEMENT, TIMESTEPPER >, UnstructuredImmersedEllipseProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, RefineableRotatingCylinderProblem< ELEMENT >, FluxPoissonMGProblem< ELEMENT, MESH >, FluxPoissonMGProblem< ELEMENT, MESH >, PMLHelmholtzMGProblem< ELEMENT >, PMLStructuredCubicHelmholtz< ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, ThermalProblem< ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableDDConvectionProblem< NST_ELEMENT, AD_ELEMENT >, DDConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RectangularDrivenCavityProblem< ELEMENT >, CantileverProblem< ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, RefineableTwoMeshFluxPoissonProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, CantileverProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, CantileverProblem< ELEMENT >, UnstructuredSolidProblem< ELEMENT, MESH >, ScatteringProblem< ELEMENT >, UnstructuredPoissonProblem< ELEMENT >, TetmeshPoissonProblem< ELEMENT >, TetmeshPoissonProblem< ELEMENT >, TwoMeshFluxAdvectionDiffusionProblem< ELEMENT >, RefineablePeriodicLoadProblem< ELEMENT >, UnstructuredFSIProblem< FLUID_ELEMENT, SOLID_ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, CoatedSphereProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, CoatedDiskProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, CoatedDiskProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, ScatteringProblem< ELEMENT >, ScatteringProblem< ELEMENT >, HelmholtzPointSourceProblem< ELEMENT >, ContactProblem< ELEMENT >, ContactProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatMeltProblem< ELEMENT >, ContactProblem< ELEMENT >, ContactProblem< ELEMENT >, SolarRadiationProblem< ELEMENT >, MeltContactProblem< ELEMENT >, VibratingShellProblem< ELEMENT >, AxisymmetricVibratingShellProblem< ELEMENT >, FourierDecomposedHelmholtzProblem< ELEMENT >, UnstructuredFvKProblem< ELEMENT >, UnstructuredTorusProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, RefineableAdvectionDiffusionPipeProblem< ELEMENT >, RefineableAdvectionDiffusionProblem< ELEMENT >, TwoMeshFluxAdvectionDiffusionProblem< ELEMENT >, RefineableAdvectionDiffusionProblem< ELEMENT >, and MortaringValidationProblem< ELEMENT, NON_MORTAR_ELEMENT >.

1022 {}

Referenced by adapt(), adapt_based_on_error_estimates(), p_adapt(), p_refine_selected_elements(), p_refine_uniformly(), p_refine_uniformly_aux(), p_unrefine_uniformly(), read(), refine_selected_elements(), refine_uniformly(), refine_uniformly_aux(), oomph::MGSolver< DIM >::setup_mg_hierarchy(), oomph::HelmholtzMGPreconditioner< DIM >::setup_mg_hierarchy(), and unrefine_uniformly().

◆ actions_before_explicit_timestep()

virtual void oomph::Problem::actions_before_explicit_timestep ( )
inlineprotectedvirtual

Actions that should be performed before each explicit time step.

Reimplemented from oomph::ExplicitTimeSteppableObject.

Reimplemented in oomph::MyProblem.

1078 {}

◆ actions_before_implicit_timestep()

virtual void oomph::Problem::actions_before_implicit_timestep ( )
inlineprotectedvirtual

Actions that should be performed before each implicit time step. This is needed when one wants to solve a steady problem before timestepping and needs to distinguish between the two cases

Reimplemented in oomph::WomersleyProblem< ELEMENT, DIM >, CollapsibleChannelProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, SphericalSpinUpProblem< ELEMENT >, SphericalSpinUpProblem< ELEMENT >, RefineableSphericalSpinUpProblem< ELEMENT >, RefineableSphericalSpinUpProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, RayleighProblem< ELEMENT, TIMESTEPPER >, RayleighProblem< ELEMENT, TIMESTEPPER >, oomph::MyProblem, UnstructuredFluidProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, TurekNonFSIProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, RayleighTractionProblem< ELEMENT, TIMESTEPPER >, RayleighProblem< ELEMENT, TIMESTEPPER >, OscRingNStProblem< ELEMENT >, OscEllipseProblem< ELEMENT, TIMESTEPPER >, UnstructuredImmersedEllipseProblem< ELEMENT >, InclinedPlaneProblem< ELEMENT, INTERFACE_ELEMENT >, CollapsibleChannelProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, ChannelWithLeafletProblem< ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, RefineableSphereConvectionProblem< ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableDDConvectionProblem< NST_ELEMENT, AD_ELEMENT >, DDConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, UnstructuredFSIProblem< FLUID_ELEMENT, SOLID_ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, PressureWaveFSIProblem< FLUID_ELEMENT, SOLID_ELEMENT >, PressureWaveFSIProblem< FLUID_ELEMENT, SOLID_ELEMENT >, FSIDrivenCavityProblem< ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, StefanBoltzmannProblem< ELEMENT >, ContactProblem< ELEMENT >, ContactProblem< ELEMENT >, SolarRadiationProblem< ELEMENT >, MeltContactProblem< ELEMENT >, RefineablePorousChannelProblem< ELEMENT >, AxiPoroProblem< ELEMENT, TIMESTEPPER >, UnstructuredTorusProblem< ELEMENT >, UnstructuredTorusProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, TorusProblem< ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, and AxisymmetricLinearElasticityProblem< ELEMENT, TIMESTEPPER >.

1064 {}

Referenced by adaptive_unsteady_newton_solve(), unsteady_newton_solve(), and oomph::SegregatableFSIProblem::unsteady_segregated_solve().

◆ actions_before_newton_convergence_check()

virtual void oomph::Problem::actions_before_newton_convergence_check ( )
inlineprotectedvirtual

Any actions that are to be performed before the residual is checked in the Newton method, e.g. update any boundary conditions that depend upon variables of the problem; update any ‘dependent’ variables; or perform an update of the nodal positions in SpineMeshes etc. CAREFUL: This step should (and if the FD-based LinearSolver FD_LU is used, must) only update values that are pinned!

Reimplemented in CollapsibleChannelProblem< ELEMENT >, PolarNSProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, UnstructuredFluidProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, FreeSurfaceRotationProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, ThreeDimBethertonProblem< ELEMENT >, CapProblem< ELEMENT >, CapProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, OscRingNStProblem< ELEMENT >, UnstructuredImmersedEllipseProblem< ELEMENT >, FreeSurfaceRotationProblem< ELEMENT >, BrethertonProblem< ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, AxisymFreeSurfaceNozzleAdvDiffRobinProblem< ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, PoissonProblem< ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, FSIRingProblem, FSICollapsibleChannelProblem< ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, RotatingProblem< ELEMENT >, ScatteringProblem< ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, UnstructuredFSIProblem< FLUID_ELEMENT, SOLID_ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, OscRingNStProblem< ELEMENT >, OscRingNStProblem< ELEMENT >, FSIRingProblem, FSIRingProblem, SegregatedFSIDrivenCavityProblem< ELEMENT >, FSIDrivenCavityProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, SegregatedFSICollapsibleChannelProblem< ELEMENT >, SegregatedFSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, PreconditionedFSICollapsibleChannelProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, FreeBoundaryPoissonProblem< ELEMENT >, FreeBoundaryPoissonProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, CoatedSphereProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, CoatedSphereProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, AirwayReopeningProblem< ELEMENT >, CoatedDiskProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, ScatteringProblem< ELEMENT >, ScatteringProblem< ELEMENT >, HelmholtzPointSourceProblem< ELEMENT >, SolarRadiationProblem< ELEMENT >, MeltContactProblem< ELEMENT >, VibratingShellProblem< ELEMENT >, AxisymmetricVibratingShellProblem< ELEMENT >, FourierDecomposedHelmholtzProblem< ELEMENT >, FourierDecomposedHelmholtzProblem< ELEMENT >, RotatingProblem< ELEMENT >, ABCProblem< ELEMENT, TIMESTEPPERT >, PredPreyProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, CapProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, MeltSpinningProblem< ELEMENT >, and CapProblem< ELEMENT >.

1048 {}

Referenced by actions_after_change_in_bifurcation_parameter(), actions_after_change_in_global_parameter(), adaptive_unsteady_newton_solve(), oomph::PitchForkHandler::get_dresiduals_dparameter(), get_fd_jacobian(), get_hessian_vector_products(), oomph::FoldHandler::get_jacobian(), oomph::PitchForkHandler::get_jacobian(), newton_solve(), and newton_solve_continuation().

◆ actions_before_newton_solve()

virtual void oomph::Problem::actions_before_newton_solve ( )
inlineprotectedvirtual

Any actions that are to be performed before a complete Newton solve (e.g. adjust boundary conditions). CAREFUL: This step should (and if the FD-based LinearSolver FD_LU is used, must) only update values that are pinned!

Reimplemented in OneDPoissonProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, oomph::WomersleyProblem< ELEMENT, DIM >, oomph::NonLinearElasticitySmoothMesh< ELEMENT >, oomph::SolidICProblem, oomph::BiharmonicFluidProblem< DIM >, oomph::BiharmonicProblem< DIM >, oomph::BiharmonicProblem< 2 >, TestPoissonProblem< ELEMENT >, TestRefineablePoissonProblem< ELEMENT >, TestPoissonProblem< ELEMENT >, TFaceTestProblem< ELEMENT >, TriangleFaceTestProblem< ELEMENT >, QFaceTestProblem< ELEMENT >, QFaceTestProblem< ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, EighthSpherePoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, DrivenCavityProblem< ELEMENT, MESH >, RefineablePoissonProblem< ELEMENT >, ThreeDPoissonProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, RectangularDrivenCavityProblem< ELEMENT >, UnstructuredPoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, EighthSpherePoissonProblem< ELEMENT >, RefineablePoissonProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, YoungLaplaceProblem< ELEMENT >, RefineableYoungLaplaceProblem< ELEMENT >, RefineableYoungLaplaceProblem< ELEMENT >, YoungLaplaceProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, RingWithTRibProblem< ELASTICITY_ELEMENT >, AnnularDiskProblem< ELASTICITY_ELEMENT >, FourierDecomposedTimeHarmonicLinearElasticityProblem< ELEMENT >, FourierDecomposedTimeHarmonicLinearElasticityProblem< ELEMENT >, FourierDecomposedTimeHarmonicLinearElasticityProblem< ELEMENT >, SphericalSteadyRotationProblem< ELEMENT >, SphericalSpinUpProblem< ELEMENT >, SphericalSpinUpProblem< ELEMENT >, RefineableSphericalSpinUpProblem< ELEMENT >, RefineableSphericalSpinUpProblem< ELEMENT >, UnstructuredSolidProblem< ELEMENT, MESH >, UnstructuredSolidProblem< ELEMENT, MESH >, BlockCompressionProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, CantileverProblem< ELEMENT >, ElasticFishProblem< ELEMENT >, SimpleShearProblem< ELEMENT >, SimpleShearProblem< ELEMENT >, DiskShockWaveProblem< ELEMENT, TIMESTEPPER >, CollapsibleChannelProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, DiskOscillationProblem< ELEMENT >, StaticDiskCompressionProblem< ELEMENT >, CompressedSquareProblem< ELEMENT >, CantileverProblem< ELEMENT >, CantileverProblem< ELEMENT >, PlateProblem< ELEMENT >, ShellProblem< ELEMENT >, ShellProblem< ELEMENT >, ShellProblem< ELEMENT >, ShellProblem< ELEMENT >, RefineableActivatorInhibitorProblem< ELEMENT >, RefineableActivatorInhibitorProblem< ELEMENT >, ActivatorInhibitorProblem< ELEMENT >, RefineableTwoDPoissonProblem< ELEMENT >, RefineableTwoMeshFluxPoissonProblem< ELEMENT >, TwoMeshFluxPoissonProblem< ELEMENT >, FluxPoissonProblem< ELEMENT >, RefineablePoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, RefineablePoissonProblem< ELEMENT >, EighthSpherePoissonProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, PRefineableOneDPoissonProblem< ELEMENT >, DemoPoissonProblem, RefineableOneDPoissonProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, SimpleRefineableFishPoissonProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, FishPoissonProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, FishPoissonProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, EighthSpherePoissonProblem< ELEMENT >, EighthSpherePoissonProblem< ELEMENT >, ElasticAnnulusProblem< ELASTICITY_ELEMENT >, ElasticAnnulusProblem< ELASTICITY_ELEMENT >, PMLProblem< ELEMENT >, PMLProblem< ELEMENT >, PMLFourierDecomposedHelmholtzProblem< ELEMENT >, RefineablePoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, RectangularDrivenCavityProblem< ELEMENT >, PoissonProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, RayleighProblem< ELEMENT, TIMESTEPPER >, RayleighProblem< ELEMENT, TIMESTEPPER >, oomph::MyProblem, VorticityRecoveryProblem< ELEMENT >, UnstructuredFluidProblem< ELEMENT >, DropInChannelProblem< ELEMENT >, BubbleInChannelProblem< ELEMENT >, UnstructuredFluidProblem< ELEMENT >, RisingBubbleProblem< ELEMENT >, FallingBlockProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, TwoLayerInterfaceProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, TurekNonFSIProblem< ELEMENT >, FreeSurfaceRotationProblem< ELEMENT >, EntryFlowProblem< ELEMENT >, SteadyTubeProblem< ELEMENT >, SpikedChannelSpineFlowProblem< ELEMENT >, ChannelSpineFlowProblem< ELEMENT >, ChannelSpineFlowProblem< ELEMENT >, NavierStokesProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, FpTestProblem, FpTestProblem, RayleighTractionProblem< ELEMENT, TIMESTEPPER >, RayleighProblem< ELEMENT, TIMESTEPPER >, OscRingNStProblem< ELEMENT >, OscRingNStProblem< ELEMENT >, OscEllipseProblem< ELEMENT, TIMESTEPPER >, RectangularDrivenCavityProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, TiltedCavityProblem< ELEMENT >, PRefineableDrivenCavityProblem< ELEMENT >, QuarterCircleDrivenCavityProblem< ELEMENT >, FreeSurfaceRotationProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, EntryFlowProblem< ELEMENT >, RectangularDrivenCavityProblem< ELEMENT >, SteadyHelicalProblem< ELEMENT >, SteadyCurvedTubeProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, QuarterCircleDrivenCavityProblem2< ELEMENT >, QuarterCircleDrivenCavityProblem< ELEMENT >, ChannelWithLeafletProblem< ELEMENT >, BrethertonProblem< ELEMENT >, RefineableRotatingCylinderProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, UnitCubePoissonMGProblem< ELEMENT, MESH >, UnitCubePoissonMGProblem< ELEMENT, MESH >, FluxPoissonMGProblem< ELEMENT, MESH >, FluxPoissonMGProblem< ELEMENT, MESH >, PMLHelmholtzMGProblem< ELEMENT >, PMLStructuredCubicHelmholtz< ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, ThermalProblem< ELEMENT >, AxisymFreeSurfaceNozzleAdvDiffRobinProblem< ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, DDConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, FlowAroundHalfCylinderProblem< ELEMENT >, FlowAroundHalfCylinderProblem< ELEMENT >, FlowAroundHalfCylinderProblem< ELEMENT >, FlowAroundHalfCylinderProblem< ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, MultiPoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, RectangularDrivenCavityProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, CantileverProblem< ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, FSIRingProblem, FSICollapsibleChannelProblem< ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >, ConvectionProblem< NST_ELEMENT, AD_ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, RefineableTwoMeshFluxPoissonProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, EntryFlowProblem< ELEMENT >, CantileverProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, PrescribedBoundaryDisplacementProblem< ELEMENT >, RefineableTwoDPoissonProblem< ELEMENT >, PRefineableDrivenCavityProblem< ELEMENT >, PRefineableDrivenCavityProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, HarmonicProblem< ELEMENT, EIGEN_SOLVER >, ShellProblem< ELEMENT >, QuarterCircleDrivenCavityProblem< ELEMENT >, RotatingProblem< ELEMENT >, UniformTranspiration< ELEMENT >, CantileverProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, RefineableDrivenCavityProblem< ELEMENT >, ScatteringProblem< ELEMENT >, MovingBlockProblem< ELEMENT >, PoissonProblem< ELEMENT >, FlowPastBoxProblem< ELEMENT >, PoissonProblem< ELEMENT >, FlowPastBoxProblem< ELEMENT >, PoissonProblem< ELEMENT >, NavierStokesProblem< ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, UnstructuredPoissonProblem< ELEMENT >, UnstructuredPoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, TetmeshPoissonProblem< ELEMENT >, TetmeshPoissonProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, MultiPoissonProblem< ELEMENT >, PeriodicLoadProblem< ELEMENT >, PoissonProblem< ELEMENT >, PoissonProblem< ELEMENT >, RectangularDrivenCavityProblem< ELEMENT >, RectangularDrivenCavityProblem< ELEMENT >, OneDPoissonProblem< ELEMENT >, TwoMeshFluxAdvectionDiffusionProblem< ELEMENT >, RefineablePeriodicLoadProblem< ELEMENT >, PeriodicLoadProblem< ELEMENT >, TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, OscRingNStProblem< ELEMENT >, OscRingNStProblem< ELEMENT >, FSIRingProblem, FSIRingProblem, SegregatedFSIDrivenCavityProblem< ELEMENT >, FSIDrivenCavityProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSIChannelWithLeafletProblem< ELEMENT >, SegregatedFSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, PreconditionedFSICollapsibleChannelProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, FreeBoundaryPoissonProblem< ELEMENT >, FreeBoundaryPoissonProblem< ELEMENT >, GeomObjectAsGeneralisedElementProblem, DeformableFishPoissonProblem< ELEMENT >, DeformableFishPoissonProblem< ELEMENT >, RefineableFishPoissonProblem< ELEMENT >, CoatedSphereProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, CoatedSphereProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, AirwayReopeningProblem< ELEMENT >, CoatedDiskProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, CoatedDiskProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >, HomogenisationProblem< ELEMENT >, HomogenisationProblem< ELEMENT >, ScatteringProblem< ELEMENT >, ScatteringProblem< ELEMENT >, HelmholtzPointSourceProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, StefanBoltzmannProblem< ELEMENT >, StefanBoltzmannProblem< ELEMENT >, ContactProblem< ELEMENT >, ContactProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatMeltProblem< ELEMENT >, ContactProblem< ELEMENT >, ContactProblem< ELEMENT >, SolarRadiationProblem< ELEMENT >, MeltContactProblem< ELEMENT >, VibratingShellProblem< ELEMENT >, AxisymmetricVibratingShellProblem< ELEMENT >, FourierDecomposedHelmholtzProblem< ELEMENT >, FourierDecomposedHelmholtzProblem< ELEMENT >, UnstructuredFvKProblem< ELEMENT >, ExtrudedMovingCylinderProblem< TWO_D_ELEMENT, THREE_D_ELEMENT >, MovingBlockProblem< ELEMENT >, ContinuationProblem, OrrSommerfeldProblem< ELEMENT >, DarcyProblem< ELEMENT >, RotatingProblem< ELEMENT >, UniformTranspiration< ELEMENT >, ABCProblem< ELEMENT, TIMESTEPPERT >, PredPreyProblem< ELEMENT >, BratuProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, FlowAroundCylinderProblem< ELEMENT >, ElasticRingProblem< ELEMENT >, ElasticRingProblem< ELEMENT >, ElasticBeamProblem, ElasticRingProblem< ELEMENT >, ElasticRingProblem< ELEMENT >, AxiPoroProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, RotatingCylinderProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, RotatingProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, MeltSpinningProblem< ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, AxisymmetricLinearElasticityProblem< ELEMENT, TIMESTEPPER >, AxisymFvKProblem< ELEMENT >, AxisymFvKProblem< ELEMENT >, RefineableAdvectionDiffusionPipeProblem< ELEMENT >, UnstructuredFvKProblem< ELEMENT >, UnstructuredFvKProblem< ELEMENT >, AxisymFvKProblem< ELEMENT >, AxisymFvKProblem< ELEMENT >, RefineableAdvectionDiffusionProblem< ELEMENT >, SUPGAdvectionDiffusionProblem< ELEMENT >, TwoMeshFluxAdvectionDiffusionProblem< ELEMENT >, RefineableAdvectionDiffusionProblem< ELEMENT >, RefineableAdvectionDiffusionProblem< ELEMENT >, SheetGlueProblem< ELEMENT >, SheetGlueProblem< ELEMENT >, and BendingCantileverProblem< ELEMENT >.

1032 {}

Referenced by actions_after_change_in_bifurcation_parameter(), actions_after_change_in_global_parameter(), get_fd_jacobian(), newton_solve(), and newton_solve_continuation().

◆ actions_before_newton_step()

virtual void oomph::Problem::actions_before_newton_step ( )
inlineprotectedvirtual

Any actions that are to be performed before each individual Newton step. Most likely to be used for diagnostic purposes to doc the solution during a non-converging iteration, say.

Reimplemented in oomph::MyProblem, RectangularDrivenCavityProblem< ELEMENT >, SegregatedFSIDrivenCavityProblem< ELEMENT >, and SegregatedFSICollapsibleChannelProblem< ELEMENT >.

1053 {}

Referenced by newton_solve(), and newton_solve_continuation().

◆ actions_before_read_unstructured_meshes()

virtual void oomph::Problem::actions_before_read_unstructured_meshes ( )
inlineprotectedvirtual

Actions that are to be performed before reading in restart data for problems involving unstructured bulk meshes. If the problem contains such meshes we need to strip out any face elements that are attached to them because restart of unstructured meshes re-creates their elements and nodes from scratch, leading to dangling pointers from the face elements to the old elements and nodes. This function is virtual and (practically) empty but toggles a flag to indicate that it has been called. This is used to issue a warning, prompting the user to consider overloading it if the problem is found to contain unstructured bulk meshes during restarts.

References Empty_actions_before_read_unstructured_meshes_has_been_called.

Referenced by read().

◆ activate_bifurcation_tracking() [1/2]

void Problem::activate_bifurcation_tracking ( double *const &  parameter_pt,
const DoubleVector eigenvector,
const bool block_solve = true 
)

Activate generic bifurcation tracking for a single (real) eigenvalue where the initial guess for the eigenvector can be specified.

Activate the generic bifurcation ///tracking system by changing the assembly handler and initialising it using the parameter addressed by parameter_pt.

10132  {
10133  // Reset the assembly handler to default
10135  // Set the new assembly handler. Note that the constructor actually
10136  // solves the original problem to get some initial conditions, but
10137  // this is OK because the RHS is always evaluated before assignment.
10138  Assembly_handler_pt = new FoldHandler(this, parameter_pt, eigenvector);
10139 
10140  // If we are using a block solver, we must set the linear solver pointer
10141  // to the block fold solver. The present linear solver is
10142  // used by the block solver and so must be passed as an argument.
10143  // The destructor of the Fold handler returns the linear
10144  // solver to the original non-block version.
10145  if (block_solve)
10146  {
10148  }
10149  }
void reset_assembly_handler_to_default()
Reset the system to the standard non-augemented state.
Definition: problem.cc:10275
friend class FoldHandler
Definition: problem.h:153
friend class AugmentedBlockFoldLinearSolver
Definition: problem.h:160

References Assembly_handler_pt, AugmentedBlockFoldLinearSolver, FoldHandler, Linear_solver_pt, and reset_assembly_handler_to_default().

◆ activate_bifurcation_tracking() [2/2]

void Problem::activate_bifurcation_tracking ( double *const &  parameter_pt,
const DoubleVector eigenvector,
const DoubleVector normalisation,
const bool block_solve = true 
)

Activate generic bifurcation tracking for a single (real) eigenvalue where the initial guess for the eigenvector can be specified and the normalisation condition can also be specified.

Activate the generic bifurcation ///tracking system by changing the assembly handler and initialising it using the parameter addressed by parameter_pt.

10161  {
10162  // Reset the assembly handler to default
10164  // Set the new assembly handler. Note that the constructor actually
10165  // solves the original problem to get some initial conditions, but
10166  // this is OK because the RHS is always evaluated before assignment.
10168  new FoldHandler(this, parameter_pt, eigenvector, normalisation);
10169 
10170  // If we are using a block solver, we must set the linear solver pointer
10171  // to the block fold solver. The present linear solver is
10172  // used by the block solver and so must be passed as an argument.
10173  // The destructor of the Fold handler returns the linear
10174  // solver to the original non-block version.
10175  if (block_solve)
10176  {
10178  }
10179  }

References Assembly_handler_pt, AugmentedBlockFoldLinearSolver, FoldHandler, Linear_solver_pt, and reset_assembly_handler_to_default().

◆ activate_fold_tracking()

void Problem::activate_fold_tracking ( double *const &  parameter_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.

Activate the fold tracking system by changing the assembly handler and initialising it using the parameter addressed by parameter_pt.

10105  {
10106  // Reset the assembly handler to default
10108  // Set the new assembly handler. Note that the constructor actually
10109  // solves the original problem to get some initial conditions, but
10110  // this is OK because the RHS is always evaluated before assignment.
10111  Assembly_handler_pt = new FoldHandler(this, parameter_pt);
10112 
10113  // If we are using a block solver, we must set the linear solver pointer
10114  // to the block fold solver. The present linear solver is
10115  // used by the block solver and so must be passed as an argument.
10116  // The destructor of the Fold handler returns the linear
10117  // solver to the original non-block version.
10118  if (block_solve)
10119  {
10121  }
10122  }

References Assembly_handler_pt, AugmentedBlockFoldLinearSolver, FoldHandler, Linear_solver_pt, and reset_assembly_handler_to_default().

Referenced by bifurcation_adapt_helper().

◆ activate_hopf_tracking() [1/2]

void Problem::activate_hopf_tracking ( double *const &  parameter_pt,
const bool block_solve = true 
)

Turn on Hopf bifurcation tracking using the augmented system specified in the HopfHandler class. After a call to this function subsequent calls of the standard solution methods will converge to a Hopf bifuraction 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.

Activate the hopf tracking system by changing the assembly handler and initialising it using the parameter addressed by parameter_pt.

10220  {
10221  // Reset the assembly handler to default
10223  // Set the new assembly handler. Note that the constructor actually
10224  // solves the original problem to get some initial conditions, but
10225  // this is OK because the RHS is always evaluated before assignment.
10226  Assembly_handler_pt = new HopfHandler(this, parameter_pt);
10227 
10228  // If we are using a block solver, we must set the linear solver pointer
10229  // to the block hopf solver. The present linear solver is
10230  // used by the block solver and so must be passed as an argument.
10231  // The destructor of the Hopf handler returns the linear
10232  // solver to the original non-block version.
10233  if (block_solve)
10234  {
10236  }
10237  }
friend class BlockHopfLinearSolver
Definition: problem.h:162
friend class HopfHandler
Definition: problem.h:155

References Assembly_handler_pt, BlockHopfLinearSolver, HopfHandler, Linear_solver_pt, and reset_assembly_handler_to_default().

Referenced by bifurcation_adapt_helper().

◆ activate_hopf_tracking() [2/2]

void Problem::activate_hopf_tracking ( double *const &  parameter_pt,
const double omega,
const DoubleVector null_real,
const DoubleVector null_imag,
const bool block_solve = true 
)

Turn on Hopf bifurcation tracking using the augmented system specified in the HopfHandler class. After a call to this function subsequent calls of the standard solution methods will converge to a Hopf bifuraction 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. This interface allows specification of an inital guess for the frequency and real and imaginary parts of the null vector, such as might be obtained from an eigensolve

Activate the hopf tracking system by changing the assembly handler and initialising it using the parameter addressed by parameter_pt and the frequency and null vectors specified.

10251  {
10252  // Reset the assembly handler to default
10254  // Set the new assembly handler. Note that the constructor actually
10255  // solves the original problem to get some initial conditions, but
10256  // this is OK because the RHS is always evaluated before assignment.
10258  new HopfHandler(this, parameter_pt, omega, null_real, null_imag);
10259 
10260  // If we are using a block solver, we must set the linear solver pointer
10261  // to the block hopf solver. The present linear solver is
10262  // used by the block solver and so must be passed as an argument.
10263  // The destructor of the Hopf handler returns the linear
10264  // solver to the original non-block version.
10265  if (block_solve)
10266  {
10268  }
10269  }
Vector::Scalar omega(const Vector &t, const Vector &s, RealScalar angle)
Definition: IDRS.h:36

References Assembly_handler_pt, BlockHopfLinearSolver, HopfHandler, Linear_solver_pt, Eigen::internal::omega(), and reset_assembly_handler_to_default().

◆ activate_pitchfork_tracking()

void Problem::activate_pitchfork_tracking ( double *const &  parameter_pt,
const DoubleVector symmetry_vector,
const bool block_solve = true 
)

Turn on pitchfork tracking using the augmented system specified in the PitchForkHandler class. After a call to this function subsequent calls of the standard solution methods will converge to a pitchfork bifurcation at a particular value of the variable addressed by parameter_pt. The symmetry that is to be broken must be specified by supplying a symmetry_vector(ndof). The easiest way to determine such a vector is to solve the associated eigenproblem \( Jx = \lambda M x\) and pass in the eigenvector. This is not always necessary however, if the symmetry is easy to construct. 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 requires less memory.

Activate the pitchfork tracking system by changing the assembly handler and initialising it using the parameter addressed by parameter_pt and a symmetry vector. The boolean flag is used to specify whether a block solver is used, default is true.

10191  {
10192  // Reset the assembly handler to default
10194 
10195  // Set the new assembly handler. Note that the constructor actually
10196  // solves the original problem to get some initial conditions, but
10197  // this is OK because the RHS is always evaluated before assignment.
10199  this, this->assembly_handler_pt(), parameter_pt, symmetry_vector);
10200 
10201  // If we are using a block solver, we must set the linear solver pointer
10202  // to the block pitchfork solver. The present linear solver is
10203  // used by the block solver and so must be passed as an argument.
10204  // The destructor of the PitchFork handler returns the linear
10205  // solver to the original non-block version.
10206  if (block_solve)
10207  {
10209  }
10210  }
AssemblyHandler *& assembly_handler_pt()
Return a pointer to the assembly handler object.
Definition: problem.h:1570
friend class PitchForkHandler
Definition: problem.h:154
friend class BlockPitchForkLinearSolver
Definition: problem.h:159

References Assembly_handler_pt, assembly_handler_pt(), BlockPitchForkLinearSolver, Linear_solver_pt, PitchForkHandler, and reset_assembly_handler_to_default().

Referenced by bifurcation_adapt_helper().

◆ adapt() [1/2]

void oomph::Problem::adapt ( )
inline

Adapt problem: Perform mesh adaptation for (all) refineable (sub)mesh(es), based on their own error estimates and the target errors specified in the mesh(es). Following mesh adaptation, update global mesh, and re-assign equation numbers. On return from this function, Problem can immediately be solved again. [Argument-free wrapper]

2860  {
2861  unsigned n_refined, n_unrefined;
2862  adapt(n_refined, n_unrefined);
2863  }
void adapt()
Definition: problem.h:2859

Referenced by UnsteadyHeatProblem< ELEMENT >::adapt(), arc_length_step_solve_helper(), doubly_adaptive_unsteady_newton_solve_helper(), newton_solve(), and unsteady_newton_solve().

◆ adapt() [2/2]

void Problem::adapt ( unsigned n_refined,
unsigned n_unrefined 
)

Adapt problem: Perform mesh adaptation for (all) refineable (sub)mesh(es), based on their own error estimates and the target errors specified in the mesh(es). Following mesh adaptation, update global mesh, and re-assign equation numbers. Return # of refined/unrefined elements. On return from this function, Problem can immediately be solved again.

13667  {
13668  double t_start_total = 0.0;
13670  {
13671  t_start_total = TimingHelpers::timer();
13672  }
13673 
13674  // Get the bifurcation type
13675  int bifurcation_type = this->Assembly_handler_pt->bifurcation_type();
13676 
13677  bool continuation_problem = false;
13678 
13679  // If we have continuation data then we need to project that across to the
13680  // new mesh
13682  {
13683  if (Dof_derivative.size() != 0)
13684  {
13685  continuation_problem = true;
13686  }
13687  }
13688 
13689  // If we are tracking a bifurcation then call the bifurcation adapt function
13690  if (bifurcation_type != 0)
13691  {
13692  this->bifurcation_adapt_helper(n_refined, n_unrefined, bifurcation_type);
13693  // Return immediately
13694  return;
13695  }
13696 
13697  if (continuation_problem)
13698  {
13699  // Create a copy of the problem
13700  Copy_of_problem_pt.resize(2);
13701  // If we don't already have a copy
13702  for (unsigned c = 0; c < 2; c++)
13703  {
13704  if (Copy_of_problem_pt[c] == 0)
13705  {
13706  // Create the copy
13707  Copy_of_problem_pt[c] = this->make_copy();
13708 
13709  // Refine the copy to the same level as the current problem
13710  // Must call actions before adapt
13711  Copy_of_problem_pt[c]->actions_before_adapt();
13712 
13713  // Find number of submeshes
13714  const unsigned N_mesh = Copy_of_problem_pt[c]->nsub_mesh();
13715 
13716  // If there is only one mesh
13717  if (N_mesh == 0)
13718  {
13719  // Can we refine the mesh
13720  if (TreeBasedRefineableMeshBase* mmesh_pt =
13721  dynamic_cast<TreeBasedRefineableMeshBase*>(
13723  {
13724  // Is the adapt flag set
13725  if (mmesh_pt->is_adaptation_enabled())
13726  {
13727  // Now get the original problem's mesh if it's refineable
13728  if (TreeBasedRefineableMeshBase* original_mesh_pt =
13729  dynamic_cast<TreeBasedRefineableMeshBase*>(
13730  this->mesh_pt(0)))
13731  {
13732  if (dynamic_cast<SolidMesh*>(original_mesh_pt) != 0)
13733  {
13734  oomph_info
13735  << "Info/Warning: Adaptive Continuation is broken in "
13736  << "SolidElement" << std::endl;
13737  }
13738  mmesh_pt->refine_base_mesh_as_in_reference_mesh(
13739  original_mesh_pt);
13740  }
13741  else
13742  {
13743  oomph_info << "Info/Warning: Mesh in orginal problem is not "
13744  "refineable."
13745  << std::endl;
13746  }
13747  }
13748  else
13749  {
13750  oomph_info
13751  << "Info/Warning: Mesh adaptation is disabled in copy."
13752  << std::endl;
13753  }
13754  }
13755  else if (TriangleMeshBase* tmesh_pt =
13756  dynamic_cast<TriangleMeshBase*>(
13758  {
13759  if (TriangleMeshBase* original_mesh_pt =
13760  dynamic_cast<TriangleMeshBase*>(this->mesh_pt(0)))
13761  {
13762  if (dynamic_cast<SolidMesh*>(original_mesh_pt) != 0)
13763  {
13764  oomph_info
13765  << "Info/Warning: Adaptive Continuation is broken in "
13766  << "SolidElement" << std::endl;
13767  }
13768 
13769  // Remesh using the triangulateIO of the base mesh
13770  // Done via a file, so a bit hacky but this will be
13771  // superseded very soon
13772  std::ofstream tri_dump("triangle_mesh.dmp");
13773  original_mesh_pt->dump_triangulateio(tri_dump);
13774  tri_dump.close();
13775  std::ifstream tri_read("triangle_mesh.dmp");
13776  tmesh_pt->remesh_from_triangulateio(tri_read);
13777  tri_read.close();
13778 
13779 
13780  // Set the nodes to be at the same positions
13781  // as the original just in case the
13782  // triangulatio is out of sync with the real data
13783  const unsigned n_node = original_mesh_pt->nnode();
13784  for (unsigned n = 0; n < n_node; ++n)
13785  {
13786  Node* const nod_pt = original_mesh_pt->node_pt(n);
13787  Node* const new_node_pt = tmesh_pt->node_pt(n);
13788  unsigned n_dim = nod_pt->ndim();
13789  for (unsigned i = 0; i < n_dim; ++i)
13790  {
13791  new_node_pt->x(i) = nod_pt->x(i);
13792  }
13793  }
13794  }
13795  else
13796  {
13797  oomph_info
13798  << "Info/warning: Original Mesh is not TriangleBased\n"
13799  << "... but the copy is!" << std::endl;
13800  }
13801  }
13802  else
13803  {
13804  oomph_info << "Info/Warning: Mesh cannot be adapted in copy."
13805  << std::endl;
13806  }
13807  } // End of single mesh case
13808  // Otherwise loop over the submeshes
13809  else
13810  {
13811  for (unsigned m = 0; m < N_mesh; m++)
13812  {
13813  // Can we refine the submesh
13814  if (TreeBasedRefineableMeshBase* mmesh_pt =
13815  dynamic_cast<TreeBasedRefineableMeshBase*>(
13817  {
13818  // Is the adapt flag set
13819  if (mmesh_pt->is_adaptation_enabled())
13820  {
13821  // Now get the original problem's mesh
13822  if (TreeBasedRefineableMeshBase* original_mesh_pt =
13823  dynamic_cast<TreeBasedRefineableMeshBase*>(
13824  this->mesh_pt(m)))
13825  {
13826  if (dynamic_cast<SolidMesh*>(original_mesh_pt) != 0)
13827  {
13828  oomph_info
13829  << "Info/Warning: Adaptive Continuation is broken in "
13830  << "SolidElement" << std::endl;
13831  }
13832 
13833  mmesh_pt->refine_base_mesh_as_in_reference_mesh(
13834  original_mesh_pt);
13835  }
13836  else
13837  {
13838  oomph_info << "Info/Warning: Mesh in orginal problem is "
13839  "not refineable."
13840  << std::endl;
13841  }
13842  }
13843  else
13844  {
13845  oomph_info
13846  << "Info/Warning: Mesh adaptation is disabled in copy."
13847  << std::endl;
13848  }
13849  }
13850  else if (TriangleMeshBase* tmesh_pt =
13851  dynamic_cast<TriangleMeshBase*>(
13853  {
13854  if (TriangleMeshBase* original_mesh_pt =
13855  dynamic_cast<TriangleMeshBase*>(this->mesh_pt(m)))
13856  {
13857  if (dynamic_cast<SolidMesh*>(original_mesh_pt) != 0)
13858  {
13859  oomph_info
13860  << "Info/Warning: Adaptive Continuation is broken in "
13861  << "SolidElement" << std::endl;
13862  }
13863 
13864  // Remesh using the triangulateIO of the base mesh
13865  // Done via a file, so a bit hacky but this will be
13866  // superseded very soon
13867  std::ofstream tri_dump("triangle_mesh.dmp");
13868  original_mesh_pt->dump_triangulateio(tri_dump);
13869  tri_dump.close();
13870  std::ifstream tri_read("triangle_mesh.dmp");
13871  tmesh_pt->remesh_from_triangulateio(tri_read);
13872  tri_read.close();
13873 
13874  // Set the nodes to be at the same positions
13875  // as the original just in case the
13876  // triangulatio is out of sync with the real data
13877  const unsigned n_node = original_mesh_pt->nnode();
13878  for (unsigned n = 0; n < n_node; ++n)
13879  {
13880  Node* const nod_pt = original_mesh_pt->node_pt(n);
13881  Node* const new_node_pt = tmesh_pt->node_pt(n);
13882  unsigned n_dim = nod_pt->ndim();
13883  for (unsigned i = 0; i < n_dim; ++i)
13884  {
13885  new_node_pt->x(i) = nod_pt->x(i);
13886  }
13887  }
13888  }
13889  else
13890  {
13891  oomph_info
13892  << "Info/warning: Original Mesh is not TriangleBased\n"
13893  << "... but the copy is!" << std::endl;
13894  }
13895  }
13896  else
13897  {
13898  oomph_info << "Info/Warning: Mesh cannot be adapted in copy."
13899  << std::endl;
13900  }
13901  }
13902 
13903 
13904  // Must call actions after adapt
13905  Copy_of_problem_pt[c]->actions_after_adapt();
13906 
13907  // rebuild the global mesh in the copy
13908  Copy_of_problem_pt[c]->rebuild_global_mesh();
13909 
13910  } // End of multiple mesh case
13911 
13912  // Must call actions after adapt
13913  Copy_of_problem_pt[c]->actions_after_adapt();
13914 
13915  // Assign the equation numbers to the copy (quietly)
13917  }
13918 
13919  // Check that the dofs match for each copy
13920 #ifdef PARANOID
13921  // If the problems don't match then complain
13922  if (Copy_of_problem_pt[c]->ndof() != this->ndof())
13923  {
13924  std::ostringstream error_stream;
13925  error_stream << "Number of unknowns in the problem copy " << c << " "
13926  << "not equal to number in the original:\n"
13927  << this->ndof() << " (original) "
13928  << Copy_of_problem_pt[c]->ndof() << " (copy)\n";
13929 
13930  throw OomphLibError(error_stream.str(),
13933  }
13934 #endif
13935  }
13936 
13937  // Need to set the Dof derivatives to the copied problem
13938  // Assign the eigenfunction(s) to the copied problems
13939  unsigned ndof_local = Dof_distribution_pt->nrow_local();
13940  for (unsigned i = 0; i < ndof_local; i++)
13941  {
13942  Copy_of_problem_pt[0]->dof(i) = this->dof_derivative(i);
13943  Copy_of_problem_pt[1]->dof(i) = this->dof_current(i);
13944  }
13945  // Set all pinned values to zero
13946  Copy_of_problem_pt[0]->set_pinned_values_to_zero();
13947  // Don't need to for the current dofs that are actuall the dofs
13948 
13949  // Now adapt
13950  Vector<Vector<double>> base_error;
13951  this->get_all_error_estimates(base_error);
13952  this->adapt_based_on_error_estimates(n_refined, n_unrefined, base_error);
13953  Copy_of_problem_pt[0]->adapt_based_on_error_estimates(
13954  n_refined, n_unrefined, base_error);
13955  Copy_of_problem_pt[1]->adapt_based_on_error_estimates(
13956  n_refined, n_unrefined, base_error);
13957 
13958  // Now sort out the Dof pointer
13959  ndof_local = Dof_distribution_pt->nrow_local();
13960  if (Dof_derivative.size() != ndof_local)
13961  {
13962  Dof_derivative.resize(ndof_local, 0.0);
13963  }
13964  if (Dof_current.size() != ndof_local)
13965  {
13966  Dof_current.resize(ndof_local, 0.0);
13967  }
13968  for (unsigned i = 0; i < ndof_local; i++)
13969  {
13970  Dof_derivative[i] = Copy_of_problem_pt[0]->dof(i);
13971  Dof_current[i] = Copy_of_problem_pt[1]->dof(i);
13972  }
13973  // Return immediately
13974  return;
13975  }
13976 
13977  oomph_info << std::endl << std::endl;
13978  oomph_info << "Adapting problem:" << std::endl;
13979  oomph_info << "=================" << std::endl;
13980 
13981  double t_start = 0.0;
13983  {
13984  t_start = TimingHelpers::timer();
13985  }
13986 
13987  // Call the actions before adaptation
13989 
13990  double t_end = 0.0;
13992  {
13993  t_end = TimingHelpers::timer();
13994  oomph_info << "Time for actions before adapt: " << t_end - t_start
13995  << std::endl;
13996  t_start = TimingHelpers::timer();
13997  }
13998 
13999  // Initialise counters
14000  n_refined = 0;
14001  n_unrefined = 0;
14002 
14003  // Number of submeshes?
14004  unsigned Nmesh = nsub_mesh();
14005 
14006  // Single mesh:
14007  //------------
14008  if (Nmesh == 0)
14009  {
14010  // Refine single mesh if possible
14011  if (RefineableMeshBase* mmesh_pt =
14012  dynamic_cast<RefineableMeshBase*>(mesh_pt(0)))
14013  {
14014  if (mmesh_pt->is_adaptation_enabled())
14015  {
14016  double t_start = TimingHelpers::timer();
14017 
14018  // Get pointer to error estimator
14019  ErrorEstimator* error_estimator_pt =
14020  mmesh_pt->spatial_error_estimator_pt();
14021 
14022 #ifdef PARANOID
14023  if (error_estimator_pt == 0)
14024  {
14025  throw OomphLibError("Error estimator hasn't been set yet",
14028  }
14029 #endif
14030 
14031  // Get error for all elements
14032  Vector<double> elemental_error(mmesh_pt->nelement());
14033 
14034  if (mmesh_pt->doc_info_pt() == 0)
14035  {
14036  error_estimator_pt->get_element_errors(mesh_pt(0), elemental_error);
14037  }
14038  else
14039  {
14040  error_estimator_pt->get_element_errors(
14041  mesh_pt(0), elemental_error, *mmesh_pt->doc_info_pt());
14042  }
14043 
14044  // Store max./min actual error
14045  mmesh_pt->max_error() = std::fabs(*std::max_element(
14046  elemental_error.begin(), elemental_error.end(), AbsCmp<double>()));
14047 
14048  mmesh_pt->min_error() = std::fabs(*std::min_element(
14049  elemental_error.begin(), elemental_error.end(), AbsCmp<double>()));
14050 
14051  oomph_info << "\n Max/min error: " << mmesh_pt->max_error() << " "
14052  << mmesh_pt->min_error() << std::endl
14053  << std::endl;
14054 
14055 
14057  {
14058  t_end = TimingHelpers::timer();
14059  oomph_info << "Time for error estimation: " << t_end - t_start
14060  << std::endl;
14061  t_start = TimingHelpers::timer();
14062  }
14063 
14064  // Adapt mesh
14065  mmesh_pt->adapt(elemental_error);
14066 
14067  // Add to counters
14068  n_refined += mmesh_pt->nrefined();
14069  n_unrefined += mmesh_pt->nunrefined();
14070 
14072  {
14073  t_end = TimingHelpers::timer();
14074  oomph_info << "Time for complete mesh adaptation "
14075  << "(but excluding comp of error estimate): "
14076  << t_end - t_start << std::endl;
14077  t_start = TimingHelpers::timer();
14078  }
14079  }
14080  else
14081  {
14082  oomph_info << "Info/Warning: Mesh adaptation is disabled."
14083  << std::endl;
14084  }
14085  }
14086  else
14087  {
14088  oomph_info << "Info/Warning: Mesh cannot be adapted" << std::endl;
14089  }
14090  }
14091  // Multiple submeshes
14092  //------------------
14093  else
14094  {
14095  // Loop over submeshes
14096  for (unsigned imesh = 0; imesh < Nmesh; imesh++)
14097  {
14098  // Refine single mesh uniformly if possible
14099  if (RefineableMeshBase* mmesh_pt =
14100  dynamic_cast<RefineableMeshBase*>(mesh_pt(imesh)))
14101  {
14102  double t_start = TimingHelpers::timer();
14103 
14104  // Get pointer to error estimator
14105  ErrorEstimator* error_estimator_pt =
14106  mmesh_pt->spatial_error_estimator_pt();
14107 
14108 #ifdef PARANOID
14109  if (error_estimator_pt == 0)
14110  {
14111  throw OomphLibError("Error estimator hasn't been set yet",
14114  }
14115 #endif
14116 
14117  if (mmesh_pt->is_adaptation_enabled())
14118  {
14119  // Get error for all elements
14120  Vector<double> elemental_error(mmesh_pt->nelement());
14121  if (mmesh_pt->doc_info_pt() == 0)
14122  {
14123  error_estimator_pt->get_element_errors(mesh_pt(imesh),
14124  elemental_error);
14125  }
14126  else
14127  {
14128  error_estimator_pt->get_element_errors(
14129  mesh_pt(imesh), elemental_error, *mmesh_pt->doc_info_pt());
14130  }
14131 
14132  // Store max./min error if the mesh has any elements
14133  if (mesh_pt(imesh)->nelement() > 0)
14134  {
14135  mmesh_pt->max_error() =
14136  std::fabs(*std::max_element(elemental_error.begin(),
14137  elemental_error.end(),
14138  AbsCmp<double>()));
14139 
14140  mmesh_pt->min_error() =
14141  std::fabs(*std::min_element(elemental_error.begin(),
14142  elemental_error.end(),
14143  AbsCmp<double>()));
14144  }
14145 
14146  oomph_info << "\n Max/min error: " << mmesh_pt->max_error() << " "
14147  << mmesh_pt->min_error() << std::endl;
14148 
14149 
14151  {
14152  t_end = TimingHelpers::timer();
14153  oomph_info << "Time for error estimation: " << t_end - t_start
14154  << std::endl;
14155  t_start = TimingHelpers::timer();
14156  }
14157 
14158  // Adapt mesh
14159  mmesh_pt->adapt(elemental_error);
14160 
14161  // Add to counters
14162  n_refined += mmesh_pt->nrefined();
14163  n_unrefined += mmesh_pt->nunrefined();
14164 
14165 
14167  {
14168  t_end = TimingHelpers::timer();
14169  oomph_info << "Time for complete mesh adaptation "
14170  << "(but excluding comp of error estimate): "
14171  << t_end - t_start << std::endl;
14172  t_start = TimingHelpers::timer();
14173  }
14174  }
14175  else
14176  {
14177  oomph_info << "Info/Warning: Mesh adaptation is disabled."
14178  << std::endl;
14179  }
14180  }
14181  else
14182  {
14183  oomph_info << "Info/Warning: Mesh cannot be adapted." << std::endl;
14184  }
14185 
14186  } // End of loop over submeshes
14187 
14188  // Rebuild the global mesh
14190  }
14191 
14192 
14194  {
14195  t_end = TimingHelpers::timer();
14196  oomph_info << "Total time for actual adaptation "
14197  << "(all meshes; incl error estimates): " << t_end - t_start
14198  << std::endl;
14199  t_start = TimingHelpers::timer();
14200  }
14201 
14202  // Any actions after adapt
14204 
14205 
14207  {
14208  t_end = TimingHelpers::timer();
14209  oomph_info << "Time for actions after adapt: " << t_end - t_start
14210  << std::endl;
14211  t_start = TimingHelpers::timer();
14212 
14213  oomph_info << "About to start re-assigning eqn numbers "
14214  << "with Problem::assign_eqn_numbers() at end of "
14215  << "Problem::adapt().\n";
14216  }
14217 
14218  // Attach the boundary conditions to the mesh
14219  oomph_info << "\nNumber of equations: " << assign_eqn_numbers() << std::endl
14220  << std::endl;
14221 
14222 
14224  {
14225  t_end = TimingHelpers::timer();
14226  oomph_info << "Time for re-assigning eqn numbers with "
14227  << "Problem::assign_eqn_numbers() at end of Problem::adapt(): "
14228  << t_end - t_start << std::endl;
14229  oomph_info << "Total time for adapt: " << t_end - t_start_total
14230  << std::endl;
14231  }
14232  }
int i
Definition: BiCGSTAB_step_by_step.cpp:9
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
virtual int bifurcation_type() const
Definition: assembly_handler.h:134
unsigned nrow_local() const
Definition: linear_algebra_distribution.h:193
double & dof_current(const unsigned &i)
Definition: problem.h:1182
Vector< double > Dof_derivative
Storage for the derivative of the problem variables wrt arc-length.
Definition: problem.h:774
virtual Problem * make_copy()
Definition: problem.cc:12011
unsigned long ndof() const
Return the number of dofs.
Definition: problem.h:1674
void rebuild_global_mesh()
Definition: problem.cc:1533
void get_all_error_estimates(Vector< Vector< double >> &elemental_error)
Definition: problem.cc:14627
void adapt_based_on_error_estimates(unsigned &n_refined, unsigned &n_unrefined, Vector< Vector< double >> &elemental_error)
Definition: problem.cc:14528
Vector< double > Dof_current
Storage for the present values of the variables.
Definition: problem.h:777
virtual void actions_before_adapt()
Definition: problem.h:1022
void bifurcation_adapt_helper(unsigned &n_refined, unsigned &n_unrefined, const unsigned &bifurcation_type, const bool &actually_adapt=true)
Definition: problem.cc:13354
unsigned nsub_mesh() const
Return number of submeshes.
Definition: problem.h:1323
double & dof_derivative(const unsigned &i)
Definition: problem.h:1168
virtual void actions_after_adapt()
Actions that are to be performed after a mesh adaptation.
Definition: problem.h:1025
int * m
Definition: level2_cplx_impl.h:294
Z2ErrorEstimator * error_estimator_pt
Definition: MortaringCantileverCompareToNonMortaring.cpp:190
Real fabs(const Real &a)
Definition: boostmultiprec.cpp:117
bool Doc_comprehensive_timings
Definition: oomph_definitions.cc:49
double timer()
returns the time in seconds after some point in past
Definition: oomph_utilities.cc:1295
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86

References actions_after_adapt(), actions_before_adapt(), adapt_based_on_error_estimates(), Assembly_handler_pt, assign_eqn_numbers(), bifurcation_adapt_helper(), oomph::AssemblyHandler::bifurcation_type(), calibrate::c, Copy_of_problem_pt, oomph::Global_timings::Doc_comprehensive_timings, Dof_current, dof_current(), Dof_derivative, dof_derivative(), Dof_distribution_pt, MeshRefinement::error_estimator_pt, boost::multiprecision::fabs(), get_all_error_estimates(), i, m, make_copy(), mesh_pt(), n, oomph::Node::ndim(), ndof(), oomph::LinearAlgebraDistribution::nrow_local(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, rebuild_global_mesh(), oomph::TimingHelpers::timer(), Use_continuation_timestepper, and oomph::Node::x().

Referenced by main().

◆ adapt_based_on_error_estimates() [1/2]

void Problem::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 estimates in elemental_error and the target errors specified in the mesh(es). Following mesh adaptation, update global mesh, and re-assign equation numbers. Return # of refined/unrefined elements. On return from this function, Problem can immediately be solved again.

Perform mesh adaptation for (all) refineable (sub)mesh(es), based on the error estimates in elemental_error and the target errors specified in the mesh(es). Following mesh adaptation, update global mesh, and re-assign equation numbers. Return # of refined/unrefined elements. On return from this function, Problem can immediately be solved again.

14532  {
14533  oomph_info << std::endl << std::endl;
14534  oomph_info << "Adapting problem:" << std::endl;
14535  oomph_info << "=================" << std::endl;
14536 
14537  // Call the actions before adaptation
14539 
14540  // Initialise counters
14541  n_refined = 0;
14542  n_unrefined = 0;
14543 
14544  // Number of submeshes?
14545  unsigned Nmesh = nsub_mesh();
14546 
14547  // Single mesh:
14548  //------------
14549  if (Nmesh == 0)
14550  {
14551  // Refine single mesh uniformly if possible
14552  if (RefineableMeshBase* mmesh_pt =
14553  dynamic_cast<RefineableMeshBase*>(Problem::mesh_pt(0)))
14554  {
14555  if (mmesh_pt->is_adaptation_enabled())
14556  {
14557  // Adapt mesh
14558  mmesh_pt->adapt(elemental_error[0]);
14559 
14560  // Add to counters
14561  n_refined += mmesh_pt->nrefined();
14562  n_unrefined += mmesh_pt->nunrefined();
14563  }
14564  else
14565  {
14566  oomph_info << "Info/Warning: Mesh adaptation is disabled."
14567  << std::endl;
14568  }
14569  }
14570  else
14571  {
14572  oomph_info << "Info/Warning: Mesh cannot be adapted" << std::endl;
14573  }
14574  }
14575 
14576  // Multiple submeshes
14577  //------------------
14578  else
14579  {
14580  // Loop over submeshes
14581  for (unsigned imesh = 0; imesh < Nmesh; imesh++)
14582  {
14583  // Refine single mesh uniformly if possible
14584  if (RefineableMeshBase* mmesh_pt =
14585  dynamic_cast<RefineableMeshBase*>(Problem::mesh_pt(imesh)))
14586  {
14587  if (mmesh_pt->is_adaptation_enabled())
14588  {
14589  // Adapt mesh
14590  mmesh_pt->adapt(elemental_error[imesh]);
14591 
14592  // Add to counters
14593  n_refined += mmesh_pt->nrefined();
14594  n_unrefined += mmesh_pt->nunrefined();
14595  }
14596  else
14597  {
14598  oomph_info << "Info/Warning: Mesh adaptation is disabled."
14599  << std::endl;
14600  }
14601  }
14602  else
14603  {
14604  oomph_info << "Info/Warning: Mesh cannot be adapted." << std::endl;
14605  }
14606 
14607  } // End of loop over submeshes
14608 
14609  // Rebuild the global mesh
14611  }
14612 
14613  // Any actions after adapt
14615 
14616  // Attach the boundary conditions to the mesh
14617  oomph_info << "\nNumber of equations: " << assign_eqn_numbers() << std::endl
14618  << std::endl;
14619  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), oomph::oomph_info, and rebuild_global_mesh().

Referenced by adapt(), adapt_based_on_error_estimates(), and bifurcation_adapt_helper().

◆ adapt_based_on_error_estimates() [2/2]

void oomph::Problem::adapt_based_on_error_estimates ( Vector< Vector< double >> &  elemental_error)
inline

Adapt problem: Perform mesh adaptation for (all) refineable (sub)mesh(es), based on the error estimates in elemental_error and the target errors specified in the mesh(es). Following mesh adaptation, update global mesh, and re-assign equation numbers. Return # of refined/unrefined elements. On return from this function, Problem can immediately be solved again. [Wrapper without n_refined and n_unrefined arguments]

2911  {
2912  unsigned n_refined, n_unrefined;
2913  adapt_based_on_error_estimates(n_refined, n_unrefined, elemental_error);
2914  }

References adapt_based_on_error_estimates().

◆ adaptive_unsteady_newton_solve() [1/2]

double Problem::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 convergence is achieved, or the timestep falls below NewtonSolverParameters::Minimum_time_step. The error control parameter epsilon represents the (approximate) desired magnitude of the global error at each timestep. The routine returns a double that is the suggested next timestep and should be passed as dt_desired the next time the routine is called. This version always shifts the time values.

Attempt to take one timestep forward using dt_desired. The error control parameter, epsilon, is used to specify the desired approximate value of the global error norm per timestep. The routine returns the value an estimate of the next value of dt that should be taken.

11058  {
11059  // We always want to shift the time values
11060  return adaptive_unsteady_newton_solve(dt_desired, epsilon, true);
11061  }
double adaptive_unsteady_newton_solve(const double &dt_desired, const double &epsilon)
Definition: problem.cc:11056
double epsilon
Definition: osc_ring_sarah_asymptotics.h:43

References oomph::SarahBL::epsilon.

Referenced by doubly_adaptive_unsteady_newton_solve_helper().

◆ adaptive_unsteady_newton_solve() [2/2]

double Problem::adaptive_unsteady_newton_solve ( const double dt_desired,
const double epsilon,
const bool shift_values 
)

Attempt to advance timestep by dt_desired. If the solution fails the timestep will be halved until convergence is achieved, or the timestep falls below NewtonSolverParameters::Minimum_time_step. The error control parameter epsilon represents the (approximate) desired magnitude of the global error at each timestep. The routine returns a double that is the suggested next timestep and should be passed as dt_desired the next time the routine is called. Once again the boolean flag, shift_values, is used to control whether the time values are shifted.

Attempt to take one timestep forward using the dt_desired. This is the driver for a number of adaptive solvers. If the solution fails to converge at a given timestep, the routine will automatically halve the time step and try again, until the time step falls below the specified minimum value. The routine returns the value an estimate of the next value of dt that should be taken. Timestep is also rejected if the error estimate post-solve (computed by global_temporal_error_norm()) exceeds epsilon. This behaviour can be over-ruled by setting the protected boolean Problem::Keep_temporal_error_below_tolerance to false.

11079  {
11080  // First, we need to backup the existing dofs, in case the timestep is
11081  // rejected
11082 
11083  // Find total number of dofs on current processor
11084  unsigned n_dof_local = dof_distribution_pt()->nrow_local();
11085 
11086  // Now set up a Vector to hold current values
11087  Vector<double> dofs_current(n_dof_local);
11088 
11089  // Load values into dofs_current
11090  for (unsigned i = 0; i < n_dof_local; i++) dofs_current[i] = dof(i);
11091 
11092  // Store the time
11093  double time_current = time_pt()->time();
11094 
11095  // Flag to detect whether the timestep has been rejected or not
11096  bool reject_timestep = 0;
11097 
11098  // Flag to detect whether any of the timesteppers are adaptive
11099  unsigned adaptive_flag = 0;
11100 
11101  // The value of the actual timestep, by default the same as desired timestep
11102  double dt_actual = dt_desired;
11103 
11104  // Find out whether any of the timesteppers are adaptive
11105  unsigned n_time_steppers = ntime_stepper();
11106  for (unsigned i = 0; i < n_time_steppers; i++)
11107  {
11108  if (time_stepper_pt(i)->adaptive_flag())
11109  {
11110  adaptive_flag = 1;
11111  break;
11112  }
11113  }
11114 
11115  // Shift the time_values according to the control flag
11116  if (shift_values)
11117  {
11119  }
11120 
11121  // This loop surrounds the adaptive time-stepping and will not be broken
11122  // until a timestep is accepted
11123  do
11124  {
11125  // Initially we assume that this step will succeed and that this dt
11126  // value is ok.
11127  reject_timestep = 0;
11128  double dt_rescaling_factor = 1.0;
11129 
11130  // Set the new time and value of dt
11131  time_pt()->time() += dt_actual;
11132  time_pt()->dt() = dt_actual;
11133 
11134  // Loop over all timesteppers and set the weights and predictor weights
11135  for (unsigned i = 0; i < n_time_steppers; i++)
11136  {
11137  // If the time_stepper is non-adaptive, this will be zero
11140  }
11141 
11142  // Now calculate the predicted values for the all data and all positions
11144 
11145  // Run the individual timesteppers actions before timestep. These need to
11146  // be before the problem's actions_before_implicit_timestep so that the
11147  // boundary conditions are set consistently.
11148  for (unsigned i = 0; i < n_time_steppers; i++)
11149  {
11151  }
11152 
11153  // Do any updates/boundary conditions changes here
11155 
11156  // Attempt to solve the non-linear system
11157  try
11158  {
11159  // Solve the non-linear problem at this timestep
11160  newton_solve();
11161  }
11162  // Catch any exceptions thrown
11163  catch (NewtonSolverError& error)
11164  {
11165  // If it's a solver error then die
11166  if (error.linear_solver_error ||
11168  {
11169  std::string error_message = "USER-DEFINED ERROR IN NEWTON SOLVER\n";
11170  error_message += "ERROR IN THE LINEAR SOLVER\n";
11171 
11172  // Die
11173  throw OomphLibError(
11175  }
11176  else
11177  {
11178  // Reject the timestep, if we have an exception
11179  oomph_info << "TIMESTEP REJECTED" << std::endl;
11180  reject_timestep = 1;
11181 
11182  // Half the time step
11183  dt_rescaling_factor = Timestep_reduction_factor_after_nonconvergence;
11184  }
11185  }
11186 
11187  // Run the individual timesteppers actions, these need to be before the
11188  // problem's actions_after_implicit_timestep so that the time step is
11189  // finished before the problem does any auxiliary calculations (e.g. in
11190  // semi-implicit micromagnetics the calculation of magnetostatic field).
11191  for (unsigned i = 0; i < n_time_steppers; i++)
11192  {
11194  }
11195 
11196  // Update anything that needs updating after the timestep
11198 
11199  // If we have an adapative timestepper (and we haven't already failed)
11200  // then calculate the error estimate and rescaling factor.
11201  if (adaptive_flag && !reject_timestep)
11202  {
11203  // Once timestep has been accepted can do fancy error processing
11204  // Set the error weights
11205  for (unsigned i = 0; i < n_time_steppers; i++)
11206  {
11208  }
11209 
11210  // Get a global error norm to use in adaptivity (as specified by the
11211  // problem sub-class writer). Prevent a divide by zero if the solution
11212  // gives very close to zero error. Error norm should never be negative
11213  // but use absolute value just in case.
11215 
11216  // Calculate the scaling factor
11217  dt_rescaling_factor = std::pow(
11218  (epsilon / error), (1.0 / (1.0 + time_stepper_pt()->order())));
11219 
11220  oomph_info << "Timestep scaling factor is " << dt_rescaling_factor
11221  << std::endl;
11222  oomph_info << "Estimated timestepping error is " << error << std::endl;
11223 
11224 
11225  // Do we have to do it again?
11226  if (error > epsilon)
11227  {
11228  oomph_info << "Estimated timestepping error " << error
11229  << " exceeds tolerance " << epsilon << " ";
11231  {
11232  oomph_info << " --> rejecting timestep." << std::endl;
11233  reject_timestep = 1;
11234  }
11235  else
11236  {
11237  oomph_info << " ...but we're not rejecting the timestep"
11238  << std::endl;
11239  }
11240  oomph_info
11241  << "Note: This behaviour can be adjusted by changing the protected "
11242  << "boolean" << std::endl
11243  << std::endl
11244  << " Problem::Keep_temporal_error_below_tolerance" << std::endl;
11245  }
11246 
11247 
11248  } // End of if adaptive flag
11249 
11250 
11251  // Calculate the next time step size and check it's ok
11252  // ============================================================
11253 
11254  // Calculate the possible next time step, if no error conditions
11255  // trigger.
11256  double new_dt_candidate = dt_rescaling_factor * dt_actual;
11257 
11258  // Check that the scaling factor is within the allowed range
11259  if (dt_rescaling_factor > DTSF_max_increase)
11260  {
11261  oomph_info << "Tried to increase dt by the ratio "
11262  << dt_rescaling_factor << " which is above the maximum ("
11264  << "). Attempting to increase by the maximum ratio instead."
11265  << std::endl;
11266  new_dt_candidate = DTSF_max_increase * dt_actual;
11267  }
11268  // If we have already rejected the timestep then don't do this check
11269  // because DTSF will definitely be too small.
11270  else if ((!reject_timestep) && (dt_rescaling_factor <= DTSF_min_decrease))
11271  {
11272  // Handle this special case where we want to continue anyway (usually
11273  // Minimum_dt_but_still_proceed = -1 so this has no effect).
11274  if (new_dt_candidate < Minimum_dt_but_still_proceed)
11275  {
11276  oomph_info
11277  << "Warning: Adaptation of timestep to ensure satisfaction\n"
11278  << " of error bounds during adaptive timestepping\n"
11279  << " would lower dt below \n"
11280  << " Problem::Minimum_dt_but_still_proceed="
11281  << Minimum_dt_but_still_proceed << "\n"
11282  << " ---> We're continuing with present timestep.\n"
11283  << std::endl;
11284  dt_rescaling_factor = 1.0;
11285  // ??ds shouldn't we set new_dt_candidate =
11286  // Minimum_dt_but_still_proceed here, rather than not changing dt at
11287  // all?
11288  }
11289  else
11290  {
11291  // Otherwise reject
11292  oomph_info << "Timestep would decrease by " << dt_rescaling_factor
11293  << " which is less than the minimum scaling factor "
11294  << DTSF_min_decrease << std::endl;
11295  oomph_info << "TIMESTEP REJECTED" << std::endl;
11296  reject_timestep = 1;
11297  }
11298  }
11299 
11300  // Now check that the new dt is within the allowed range
11301  if (new_dt_candidate > Maximum_dt)
11302  {
11303  oomph_info << "Tried to increase dt to " << new_dt_candidate
11304  << " which is above the maximum (" << Maximum_dt
11305  << "). I increased it to the maximum value instead.";
11306  dt_actual = Maximum_dt;
11307  }
11308  else if (new_dt_candidate < Minimum_dt)
11309  {
11310  std::ostringstream err;
11311  err << "Tried to reduce dt to " << new_dt_candidate
11312  << " which is less than the minimum dt (" << Minimum_dt << ")."
11313  << std::endl;
11314  throw OomphLibError(
11316  }
11317  else
11318  {
11319  dt_actual = new_dt_candidate;
11320  }
11321 
11322 
11324 
11325 
11326  // If we are rejecting this attempt then revert the dofs etc.
11327  if (reject_timestep)
11328  {
11329  // Reset the time
11330  time_pt()->time() = time_current;
11331 
11332  // Reload the dofs
11333  unsigned ni = dofs_current.size();
11334  for (unsigned i = 0; i < ni; i++)
11335  {
11336  dof(i) = dofs_current[i];
11337  }
11338 
11339 #ifdef OOMPH_HAS_MPI
11340  // Synchronise the solution on different processors (on each submesh)
11341  this->synchronise_all_dofs();
11342 #endif
11343 
11344  // Call all "after" actions, e.g. to handle mesh updates
11350  }
11351 
11352  }
11353  // Keep this loop going until we accept the timestep
11354  while (reject_timestep);
11355 
11356  // Once the timestep has been accepted, return the time step that should be
11357  // used next time.
11358  return dt_actual;
11359  }
AnnoyingScalar abs(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:135
Array< double, 1, 3 > e(1./3., 0.5, 2.)
virtual void actions_after_implicit_timestep()
Definition: problem.h:1070
LinearAlgebraDistribution *const & dof_distribution_pt() const
Return the pointer to the dof distribution (read-only)
Definition: problem.h:1668
virtual void actions_after_implicit_timestep_and_error_estimation()
Definition: problem.h:1075
virtual void shift_time_values()
Shift all values along to prepare for next timestep.
Definition: problem.cc:11634
Time *& time_pt()
Return a pointer to the global time object.
Definition: problem.h:1504
virtual void actions_before_implicit_timestep()
Definition: problem.h:1064
double & dof(const unsigned &i)
i-th dof in the problem
Definition: problem.h:1813
virtual double global_temporal_error_norm()
Definition: problem.h:1230
void calculate_predictions()
Calculate predictions.
Definition: problem.cc:11656
unsigned ntime_stepper() const
Return the number of time steppers.
Definition: problem.h:1680
virtual void actions_after_newton_step()
Definition: problem.h:1058
virtual void set_weights()=0
virtual void set_predictor_weights()
Definition: timesteppers.h:630
virtual void actions_before_timestep(Problem *problem_pt)
Definition: timesteppers.h:662
virtual void actions_after_timestep(Problem *problem_pt)
Definition: timesteppers.h:666
virtual void set_error_weights()
Definition: timesteppers.h:642
double & dt(const unsigned &t=0)
Definition: timesteppers.h:136
double & time()
Return the current value of the continuous time.
Definition: timesteppers.h:123
#define max(a, b)
Definition: datatypes.h:23
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 pow(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:625
int error
Definition: calibrate.py:297
std::string string(const unsigned &i)
Definition: oomph_definitions.cc:286

References abs(), actions_after_implicit_timestep(), actions_after_implicit_timestep_and_error_estimation(), actions_after_newton_solve(), actions_after_newton_step(), oomph::TimeStepper::actions_after_timestep(), actions_before_implicit_timestep(), actions_before_newton_convergence_check(), oomph::TimeStepper::actions_before_timestep(), calculate_predictions(), dof(), dof_distribution_pt(), oomph::Time::dt(), DTSF_max_increase, DTSF_min_decrease, e(), oomph::SarahBL::epsilon, calibrate::error, global_temporal_error_norm(), i, Keep_temporal_error_below_tolerance, max, Maximum_dt, Minimum_dt, Minimum_dt_but_still_proceed, newton_solve(), oomph::LinearAlgebraDistribution::nrow_local(), ntime_stepper(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, Eigen::bfloat16_impl::pow(), oomph::TimeStepper::set_error_weights(), oomph::TimeStepper::set_predictor_weights(), oomph::TimeStepper::set_weights(), shift_time_values(), oomph::Global_string_for_annotation::string(), oomph::Time::time(), Time_adaptive_newton_crash_on_solve_fail, time_pt(), time_stepper_pt(), and Timestep_reduction_factor_after_nonconvergence.

◆ add_eigenvector_to_dofs()

void Problem::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 so that it can be output by the usual routines

Add the eigenvector passed to the function to the dofs with magnitude epsilon

8749  {
8750  unsigned long n_dof = ndof();
8751  // Check that the eigenvector has the correct size
8752  if (eigenvector.nrow() != n_dof)
8753  {
8754  std::ostringstream error_message;
8755  error_message << "Eigenvector has size " << eigenvector.nrow()
8756  << ", not equal to the number of dofs in the problem,"
8757  << n_dof << std::endl;
8758 
8759  throw OomphLibError(
8760  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8761  }
8762 
8763  // Loop over the dofs and add the eigenvector
8764  // Only use local values
8765  for (unsigned long n = 0; n < eigenvector.nrow_local(); n++)
8766  {
8767  dof(n) += epsilon * eigenvector[n];
8768  }
8769 // Of course we now need to synchronise
8770 #ifdef OOMPH_HAS_MPI
8771  this->synchronise_all_dofs();
8772 #endif
8773  }

References dof(), oomph::SarahBL::epsilon, n, ndof(), oomph::DistributableLinearAlgebraObject::nrow(), oomph::DistributableLinearAlgebraObject::nrow_local(), OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

◆ add_global_data()

void oomph::Problem::add_global_data ( Data *const &  global_data_pt)
inline

Add Data to the Problem's global data – the Problem will perform equation numbering etc. for such Data

1655  {
1656  Global_data_pt.push_back(global_data_pt);
1657  }
Vector< Data * > Global_data_pt
Definition: problem.h:425
Data *& global_data_pt(const unsigned &i)
Return a pointer to the the i-th global data object.
Definition: problem.h:1647

References Global_data_pt, and global_data_pt().

Referenced by CapProblem< ELEMENT >::CapProblem(), ElasticRingProblem< ELEMENT >::ElasticRingProblem(), FreeSurfaceRotationProblem< ELEMENT >::FreeSurfaceRotationProblem(), PseudoSolidCapProblem< ELEMENT >::PseudoSolidCapProblem(), RefineableRotatingCylinderProblem< ELEMENT >::RefineableRotatingCylinderProblem(), and SolidFreeSurfaceRotationProblem< ELEMENT >::SolidFreeSurfaceRotationProblem().

◆ add_sub_mesh()

unsigned oomph::Problem::add_sub_mesh ( Mesh *const &  mesh_pt)
inline

Add a submesh to the problem and return its number, i, by which it can be accessed via mesh_pt(i).

1331  {
1332  Sub_mesh_pt.push_back(mesh_pt);
1333  return Sub_mesh_pt.size() - 1;
1334  }

References mesh_pt(), and Sub_mesh_pt.

Referenced by AxisymFreeSurfaceNozzleAdvDiffRobinProblem< ELEMENT >::AxisymFreeSurfaceNozzleAdvDiffRobinProblem(), oomph::BiharmonicProblem< DIM >::build_global_mesh_and_assign_eqn_numbers(), CapProblem< ELEMENT >::CapProblem(), ConvectionProblem< NST_ELEMENT, AD_ELEMENT >::ConvectionProblem(), ElasticInterfaceProblem< ELEMENT, TIMESTEPPER >::ElasticInterfaceProblem(), FluxPoissonMGProblem< ELEMENT, MESH >::FluxPoissonMGProblem(), FreeSurfaceRotationProblem< ELEMENT >::FreeSurfaceRotationProblem(), FSIChannelWithLeafletProblem< ELEMENT >::FSIChannelWithLeafletProblem(), FSIRingProblem::FSIRingProblem(), oomph::NavierStokesSchurComplementPreconditioner::get_pressure_advection_diffusion_matrix(), HomogenisationProblem< ELEMENT >::HomogenisationProblem(), InterfaceProblem< ELEMENT, TIMESTEPPER >::InterfaceProblem(), MeltSpinningProblem< ELEMENT >::MeltSpinningProblem(), oomph::NonLinearElasticitySmoothMesh< ELEMENT >::operator()(), OscRingNStProblem< ELEMENT >::OscRingNStProblem(), PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >::PerturbedStateProblem(), PseudoSolidCapProblem< ELEMENT >::PseudoSolidCapProblem(), oomph::SegregatableFSIProblem::rebuild_monolithic_mesh(), RefineableFishPoissonProblem< ELEMENT >::RefineableFishPoissonProblem(), RefineableRotatingCylinderProblem< ELEMENT >::RefineableRotatingCylinderProblem(), RefineableTwoMeshFluxPoissonProblem< ELEMENT >::RefineableTwoMeshFluxPoissonProblem(), RefineableUnsteadyHeatProblem< ELEMENT >::RefineableUnsteadyHeatProblem(), SolidFreeSurfaceRotationProblem< ELEMENT >::SolidFreeSurfaceRotationProblem(), SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >::SurfactantProblem(), TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >::TurekProblem(), TwoMeshFluxAdvectionDiffusionProblem< ELEMENT >::TwoMeshFluxAdvectionDiffusionProblem(), TwoMeshFluxPoissonProblem< ELEMENT >::TwoMeshFluxPoissonProblem(), UnsteadyHeatProblem< ELEMENT >::UnsteadyHeatProblem(), UnstructuredFvKProblem< ELEMENT >::UnstructuredFvKProblem(), UnstructuredSolidProblem< ELEMENT, MESH >::UnstructuredSolidProblem(), oomph::SegregatableFSIProblem::use_only_fluid_elements(), and oomph::SegregatableFSIProblem::use_only_solid_elements().

◆ add_time_stepper_pt()

void Problem::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 that it contains the appropriate number of levels of storage.

1546  {
1547  // Add the timestepper to the vector
1548  Time_stepper_pt.push_back(time_stepper_pt);
1549 
1550  // Find the number of timesteps required by the timestepper
1551  unsigned ndt = time_stepper_pt->ndt();
1552 
1553  // If time has not been allocated, create time object with the
1554  // required number of time steps
1555  if (Time_pt == 0)
1556  {
1557  Time_pt = new Time(ndt);
1558  oomph_info << "Created Time with " << ndt << " timesteps" << std::endl;
1559  }
1560  else
1561  {
1562  // If the required number of time steps is greater than currently stored
1563  // resize the time storage
1564  if (ndt > Time_pt->ndt())
1565  {
1566  Time_pt->resize(ndt);
1567  oomph_info << "Resized Time to include " << ndt << " timesteps"
1568  << std::endl;
1569  }
1570  // Otherwise report that we are OK
1571  else
1572  {
1573  oomph_info << "Time object already has storage for " << ndt
1574  << " timesteps" << std::endl;
1575  }
1576  }
1577 
1578  // Pass the pointer to time to the timestepper
1580  }
Allows for timing the algorithms; accurate up to 0.01 sec.
Definition: MercuryTime.h:25
virtual unsigned ndt() const =0
Number of timestep increments that are required by the scheme.
Time *const & time_pt() const
Access function for the pointer to time (const version)
Definition: timesteppers.h:572
unsigned ndt() const
Return the number of timesteps stored.
Definition: timesteppers.h:129
void resize(const unsigned &n_dt)
Definition: timesteppers.h:93

References oomph::Time::ndt(), oomph::TimeStepper::ndt(), oomph::oomph_info, oomph::Time::resize(), Time_pt, oomph::TimeStepper::time_pt(), Time_stepper_pt, and time_stepper_pt().

Referenced by arc_length_step_solve(), ConvectionProblem< NST_ELEMENT, AD_ELEMENT >::ConvectionProblem(), ElasticInterfaceProblem< ELEMENT, TIMESTEPPER >::ElasticInterfaceProblem(), ElasticRingProblem< ELEMENT >::ElasticRingProblem(), FlowAroundCylinderProblem< ELEMENT >::FlowAroundCylinderProblem(), FSIChannelWithLeafletProblem< ELEMENT >::FSIChannelWithLeafletProblem(), FSIRingProblem::FSIRingProblem(), HomogenisationProblem< ELEMENT >::HomogenisationProblem(), InterfaceProblem< ELEMENT, TIMESTEPPER >::InterfaceProblem(), LinearWaveProblem< ELEMENT, TIMESTEPPER >::LinearWaveProblem(), OscRingNStProblem< ELEMENT >::OscRingNStProblem(), PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >::PerturbedStateProblem(), RayleighProblem< ELEMENT, TIMESTEPPER >::RayleighProblem(), RefineableActivatorInhibitorProblem< ELEMENT >::RefineableActivatorInhibitorProblem(), RefineableRotatingCylinderProblem< ELEMENT >::RefineableRotatingCylinderProblem(), RefineableUnsteadyHeatProblem< ELEMENT >::RefineableUnsteadyHeatProblem(), SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >::SurfactantProblem(), TurekNonFSIProblem< ELEMENT >::TurekNonFSIProblem(), TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >::TurekProblem(), UnsteadyHeatProblem< ELEMENT >::UnsteadyHeatProblem(), and oomph::WomersleyProblem< ELEMENT, DIM >::WomersleyProblem().

◆ add_to_dofs()

void Problem::add_to_dofs ( const double lambda,
const DoubleVector increment_dofs 
)
virtual

Add lambda x incremenet_dofs[l] to the l-th dof.

Function that adds the values to the dofs.

Reimplemented from oomph::ExplicitTimeSteppableObject.

3566  {
3567  const unsigned long n_dof = this->ndof();
3568  for (unsigned long l = 0; l < n_dof; l++)
3569  {
3570  *Dof_pt[l] += lambda * increment_dofs[l];
3571  }
3572  }
cout<< "The eigenvalues of A are:"<< endl<< ces.eigenvalues()<< endl;cout<< "The matrix of eigenvectors, V, is:"<< endl<< ces.eigenvectors()<< endl<< endl;complex< float > lambda
Definition: ComplexEigenSolver_compute.cpp:9
Vector< double * > Dof_pt
Vector of pointers to dofs.
Definition: problem.h:554

References Dof_pt, lambda, and ndof().

◆ arc_length_step_solve() [1/2]

double Problem::arc_length_step_solve ( Data *const &  data_pt,
const unsigned data_index,
const double ds,
const unsigned max_adapt = 0 
)

Solve a steady problem using arc-length continuation, when the variable corresponding to the arc-length constraint equation is already stored in data used in the problem: data_pt is a pointer to the appropriate data object, data_index is the index of the value that will be traded for the constriant, ds is the desired arc_length and max_adapt is the maximum number of spatial adaptations (default zero, no adaptation). Note that the value must be pinned in order for this formulation to work

This function takes one step of length ds in pseudo-arclength.The argument data_pt is a pointer to the data that holds the parameter (global variable) that is being traded for arc-length. The exact value is located at the location given by data_index. The function returns the next desired arc-length according to criteria based upon the desired number of Newton Iterations per solve.

10386  {
10387  // Firstly check that the data is pinned
10388  if (!data_pt->is_pinned(data_index))
10389  {
10390  std::ostringstream error_stream;
10391  error_stream << "The value at index " << data_index
10392  << " in the data object to be used for continuation\n"
10393  << "is not pinned, which means that it is already a\n"
10394  << "variable in the problem "
10395  << "and cannot be used for continuation.\n\n"
10396  << "Please correct your formulation by either:\n"
10397  << "A. Pinning the value"
10398  << "\n or \n"
10399  << "B. Using a different parameter for continuation"
10400  << std::endl;
10401  throw OomphLibError(
10402  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
10403  }
10404 
10405 
10406  // If we are using the continuation timestepper
10408  {
10409  // Has the timestepper already been added to the problem
10410  bool continuation_time_stepper_added = false;
10411  const unsigned n_time_steppers = this->ntime_stepper();
10412  for (unsigned i = 0; i < n_time_steppers; i++)
10413  {
10415  {
10416  continuation_time_stepper_added = true;
10417  break;
10418  }
10419  }
10420 
10421  // If not add it
10422  if (!continuation_time_stepper_added)
10423  {
10424  oomph_info << "Adding the continuation time stepper\n";
10426  }
10427 
10428  // Need to treat case of eigenproblems and bifurcation detection/tracking
10429  // here
10430 
10431 
10432  // Backup the current timesteppers for each mesh!
10433 
10434 
10435  // If an arc length step has not been taken then set the timestepper
10436  if (!Arc_length_step_taken)
10437  {
10438  // Set the continuation timestepper for all data in the problem
10441  << " equation numbers allocated for continuation\n";
10442  }
10443 
10444 
10445  } // End of continuation time stepper case
10446 
10447 
10448  // Now make a pointer to the (newly allocated) data object
10449  double* parameter_pt = data_pt->value_pt(data_index);
10450  // Call the helper function, this will change the parameter_pt if
10451  // the data storage is changed (if the timestepper has to be changed,
10452  // which happens if this is the first time that a continuation step is
10453  // taken)
10454  // ALH: Don't think this is true because it has happened above....
10455  return arc_length_step_solve_helper(parameter_pt, ds, max_adapt);
10456  }
static ContinuationStorageScheme Continuation_time_stepper
Storage for the single static continuation timestorage object.
Definition: problem.h:761
unsigned long set_timestepper_for_all_data(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data=false)
Definition: problem.cc:11572
double arc_length_step_solve_helper(double *const &parameter_pt, const double &ds, const unsigned &max_adapt)
Definition: problem.cc:10515

References add_time_stepper_pt(), arc_length_step_solve_helper(), Arc_length_step_taken, Continuation_time_stepper, i, oomph::Data::is_pinned(), ntime_stepper(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, set_timestepper_for_all_data(), time_stepper_pt(), Use_continuation_timestepper, and oomph::Data::value_pt().

◆ arc_length_step_solve() [2/2]

double Problem::arc_length_step_solve ( double *const &  parameter_pt,
const double ds,
const unsigned max_adapt = 0 
)

Solve a steady problem using arc-length continuation, when the parameter that becomes a variable corresponding to the arc-length constraint equation is an external double: parameter_pt is a pointer to that double, ds is the desired arc_length and max_adapt is the maximum number of spatial adaptations (default zero, no adaptation).

This function takes one step of length ds in pseudo-arclength.The argument parameter_pt is a pointer to the parameter (global variable) that is being traded for arc-length. The function returns the next desired arc-length according to criteria based upon the desired number of Newton Iterations per solve.

10297  {
10298  // First check that we shouldn't use the other interface
10299  // by checking that the parameter isn't already stored as data
10300  if (does_pointer_correspond_to_problem_data(parameter_pt))
10301  {
10302  std::ostringstream error_message;
10303  error_message
10304  << "The parameter addressed by " << parameter_pt << " with the value "
10305  << *parameter_pt
10306  << "\n is supposed to be used for arc-length contiunation,\n"
10307  << " but it is stored in a Data object used by the problem.\n\n"
10308  << "This is bad for two reasons:\n"
10309  << "1. If it's a variable in the problem, it must already have an\n"
10310  "associated equation, so it can't be used for continuation;\n"
10311  << "2. The problem data will be reorganised in memory during "
10312  "continuation,\n"
10313  << " which means that the pointer will become invalid.\n\n"
10314  << "If you are sure that this is what you want to do you must:\n"
10315  << "A. Ensure that the value is pinned (don't worry we'll shout again "
10316  "if not)\n"
10317  << "B. Use the alternative interface\n"
10318  << " Problem::arc_length_step_solve(Data*,unsigned,...)\n"
10319  << " which uses a pointer to the data object and not the raw double "
10320  "pointer."
10321  << std::endl;
10322  throw OomphLibError(
10323  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
10324  }
10325 
10326 
10327  // If we are using the continuation timestepper
10329  {
10330  // Has the timestepper already been added to the problem
10331  bool continuation_time_stepper_added = false;
10332  const unsigned n_time_steppers = this->ntime_stepper();
10333  for (unsigned i = 0; i < n_time_steppers; i++)
10334  {
10336  {
10337  continuation_time_stepper_added = true;
10338  break;
10339  }
10340  }
10341 
10342  // If not add it
10343  if (!continuation_time_stepper_added)
10344  {
10345  oomph_info << "Adding the continuation time stepper\n";
10347  }
10348 
10349  // Need to treat case of eigenproblems and bifurcation detection/tracking
10350  // here
10351 
10352  // Backup the current timesteppers for each mesh!
10353 
10354 
10355  // If an arc length step has not been taken then set the timestepper
10356  if (!Arc_length_step_taken)
10357  {
10358  // Set the continuation timestepper for all data in the problem
10361  << " equation numbers allocated for continuation\n";
10362  }
10363 
10364  } // End of continuation time stepper case
10365 
10366 
10367  // Just call the helper function (parameter is not from data)
10368  return arc_length_step_solve_helper(parameter_pt, ds, max_adapt);
10369  }
bool does_pointer_correspond_to_problem_data(double *const &parameter_pt)
Definition: problem.cc:9846

References add_time_stepper_pt(), arc_length_step_solve_helper(), Arc_length_step_taken, Continuation_time_stepper, does_pointer_correspond_to_problem_data(), i, ntime_stepper(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, set_timestepper_for_all_data(), time_stepper_pt(), and Use_continuation_timestepper.

Referenced by ContinuationProblem::solve().

◆ arc_length_step_solve_helper()

double Problem::arc_length_step_solve_helper ( double *const &  parameter_pt,
const double ds,
const unsigned max_adapt 
)
private

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

This function takes one step of length ds in pseudo-arclength.The argument parameter_pt is a pointer to the parameter (global variable) that is being traded for arc-length. The function returns the next desired arc-length according to criteria based upon the desired number of Newton Iterations per solve.

end of adaptation loop

10518  {
10519  //----------------------MAKE THE PROBLEM STEADY-----------------------
10520  // Loop over the timesteppers and make them (temporarily) steady.
10521  // We can only do continuation for steady problems!
10522  unsigned n_time_steppers = ntime_stepper();
10523  // Vector of bools to store the is_steady status of the various
10524  // timesteppers when we came in here
10525  std::vector<bool> was_steady(n_time_steppers);
10526 
10527  // Loop over them all and make them (temporarily) static
10528  for (unsigned i = 0; i < n_time_steppers; i++)
10529  {
10530  was_steady[i] = time_stepper_pt(i)->is_steady();
10532  }
10533 
10534 
10535  // Max number of solves
10536  unsigned max_solve = max_adapt + 1;
10537  // Storage for newton steps in each adaptation
10538  unsigned max_count_in_adapt_loop = 0;
10539 
10540 
10541  //----SET UP MEMORY FOR QUANTITIES THAT ARE REQUIRED OUTSIDE THE LOOP----
10542 
10543  // Assign memory for solutions of the equations Jz = du/dparameter
10544  // This is needed here (outside the loop), so that we can save on
10545  // one linear solve when calculating the derivatives wrt the arc-length
10546  DoubleVector z;
10547 
10548 
10549  // Store sign of the Jacobian, used for bifurcation detection
10550  // If this is the first time that we are calling the arc-length solver,
10551  // this should not be used.
10552  int previous_sign = Sign_of_jacobian;
10553 
10554  // Flag to indicate a sign change
10555  bool SIGN_CHANGE = false;
10556 
10557 
10558  // Adaptation loop
10559  for (unsigned isolve = 0; isolve < max_solve; ++isolve)
10560  {
10561  // Only adapt after the first solve has been done
10562  if (isolve > 0)
10563  {
10564  unsigned n_refined;
10565  unsigned n_unrefined;
10566 
10567  // Adapt problem
10568  adapt(n_refined, n_unrefined);
10569 
10570 #ifdef OOMPH_HAS_MPI
10571  // Adaptation only converges if ALL the processes have no
10572  // refinement or unrefinement to perform
10573  unsigned total_refined = 0;
10574  unsigned total_unrefined = 0;
10575  if (Problem_has_been_distributed)
10576  {
10577  MPI_Allreduce(&n_refined,
10578  &total_refined,
10579  1,
10580  MPI_UNSIGNED,
10581  MPI_SUM,
10582  this->communicator_pt()->mpi_comm());
10583  n_refined = total_refined;
10584  MPI_Allreduce(&n_unrefined,
10585  &total_unrefined,
10586  1,
10587  MPI_UNSIGNED,
10588  MPI_SUM,
10589  this->communicator_pt()->mpi_comm());
10590  n_unrefined = total_unrefined;
10591  }
10592 #endif
10593 
10594  oomph_info << "---> " << n_refined << " elements were refined, and "
10595  << n_unrefined << " were unrefined"
10596 #ifdef OOMPH_HAS_MPI
10597  << ", in total (over all processors).\n";
10598 #else
10599  << ".\n";
10600 #endif
10601 
10602 
10603  // Check convergence of adaptation cycle
10604  if ((n_refined == 0) && (n_unrefined == 0))
10605  {
10606  oomph_info << "\n \n Solution is fully converged in "
10607  << "Problem::newton_solver(). \n \n ";
10608  break;
10609  }
10610  }
10611 
10612  //----------SAVE THE INITIAL VALUES, IN CASE THE STEP FAILS-----------
10613 
10614  // Find the number of local dofs
10615  unsigned ndof_local = Dof_distribution_pt->nrow_local();
10616 
10617  // Only need to do this in the first loop
10618  if (isolve == 0)
10619  {
10621  {
10622  // Safety check, set up the array of dof derivatives, if necessary
10623  // The distribution is the same as the (natural) distribution of the
10624  // dofs
10625  if (Dof_derivative.size() != ndof_local)
10626  {
10627  Dof_derivative.resize(ndof_local, 0.0);
10628  }
10629 
10630  // Safety check, set up the array of curren values, if necessary
10631  // Again the distribution reflects the (natural) distribution of the
10632  // dofs
10633  if (Dof_current.size() != ndof_local)
10634  {
10635  Dof_current.resize(ndof_local);
10636  }
10637  }
10638 
10639  // Save the current value of the parameter
10640  Parameter_current = *parameter_pt;
10641 
10642  // Save the current values of the degrees of freedom
10643  for (unsigned long l = 0; l < ndof_local; l++)
10644  {
10645  dof_current(l) = *Dof_pt[l];
10646  }
10647 
10648  // Set the value of ds_current
10649  Ds_current = ds;
10650  }
10651 
10652  // Counter for the number of newton steps
10653  unsigned count = 0;
10654 
10655  // Flag to indicate a successful step
10656  bool STEP_REJECTED = false;
10657 
10658 
10659  // Set the appropriate initial conditions for the pinned data
10661  {
10663  }
10664 
10665  // Loop around the step in arc-length
10666  do
10667  {
10668  // Check that the step has not fallen below the minimum tolerance
10670  {
10671  std::ostringstream error_message;
10672  error_message << "DESIRED ARC-LENGTH STEP " << Ds_current
10673  << " HAS FALLEN BELOW MINIMUM TOLERANCE, " << Minimum_ds
10674  << std::endl;
10675 
10676  throw OomphLibError(error_message.str(),
10679  }
10680 
10681  // Assume that we shall accept the step
10682  STEP_REJECTED = false;
10683 
10684  // Set initial value of the parameter
10686 
10687  // Perform any actions...
10688  actions_after_parameter_increase(parameter_pt);
10689 
10690  Ds_current = (*parameter_pt - Parameter_current) / Parameter_derivative;
10691 
10692  // Loop over the (local) variables and set their initial values
10693  for (unsigned long l = 0; l < ndof_local; l++)
10694  {
10695  *Dof_pt[l] = dof_current(l) + dof_derivative(l) * Ds_current;
10696  }
10697 
10698  // Actually do the newton solve stage for the continuation problem
10699  try
10700  {
10701  count = newton_solve_continuation(parameter_pt, z);
10702  }
10703  // Catch any exceptions thrown in the Newton solver
10704  catch (NewtonSolverError& error)
10705  {
10706  // Check whether it's the linear solver
10707  if (error.linear_solver_error)
10708  {
10709  std::ostringstream error_stream;
10710  error_stream << std::endl
10711  << "USER-DEFINED ERROR IN NEWTON SOLVER " << std::endl;
10712  oomph_info << "ERROR IN THE LINEAR SOLVER" << std::endl;
10713  throw OomphLibError(error_stream.str(),
10716  }
10717  // Otherwise mark the step as having failed
10718  else
10719  {
10720  oomph_info << "STEP REJECTED --- TRYING AGAIN" << std::endl;
10721  STEP_REJECTED = true;
10722  // Let's take a smaller step
10723  Ds_current *= (2.0 / 3.0);
10724  }
10725  }
10726  } while (STEP_REJECTED); // continue until a step is accepted
10727 
10728  // Set the maximum count
10729  if (count > max_count_in_adapt_loop)
10730  {
10731  max_count_in_adapt_loop = count;
10732  }
10733  }
10734 
10735  // Only recalculate the derivatives if there has been a Newton solve
10736  // If not, the previous values should be close enough
10737  if (max_count_in_adapt_loop > 0)
10738  {
10739  //--------------------CHECK FOR POTENTIAL BIFURCATIONS-------------
10741  {
10742  // If the sign of the jacobian is zero issue a warning
10743  if (Sign_of_jacobian == 0)
10744  {
10745  std::string error_message =
10746  "The sign of the jacobian is zero after a linear solve\n";
10747  error_message += "Either the matrix is singular (unlikely),\n";
10748  error_message += "or the linear solver cannot compute the "
10749  "determinant of the matrix;\n";
10750  error_message += "e.g. an iterative linear solver.\n";
10751  error_message +=
10752  "If the latter, bifurcation detection must be via an eigensolver\n";
10753  OomphLibWarning(error_message,
10754  "Problem::arc_length_step_solve",
10756  }
10757  // If this is the first step, we cannot rely on the previous value
10758  // of the jacobian so set the previous sign to the present sign
10759  if (!Arc_length_step_taken)
10760  {
10761  previous_sign = Sign_of_jacobian;
10762  }
10763  // If we have detected a sign change in the last converged Jacobian,
10764  // it must be a turning point or bifurcation
10765  if (Sign_of_jacobian != previous_sign)
10766  {
10767  // There has been, at least, one sign change
10769 
10770  // The sign has changed this time
10771  SIGN_CHANGE = true;
10772 
10773  // Calculate the dot product of the approximate null vector
10774  // of the Jacobian matrix ((badly) approximated by z)
10775  // and the vectors of derivatives of the residuals wrt the
10776  // global parameter
10777  // If this is small it is a bifurcation rather than a turning point.
10778  // Get the derivative wrt global parameter
10779  // DoubleVector dparam;
10780  // get_derivative_wrt_global_parameter(parameter_pt,dparam);
10781  // Calculate the dot product
10782  // double dot=0.0;
10783  // for(unsigned long n=0;n<n_dofs;++n) {dot += dparam[n]*z[n];}
10784  // z.dot(dparam);
10785 
10786  // Write the output message
10787  std::ostringstream message;
10788  message
10789  << "-----------------------------------------------------------";
10790  message << std::endl
10791  << "SIGN CHANGE IN DETERMINANT OF JACOBIAN: " << std::endl;
10792  message << "BIFURCATION OR TURNING POINT DETECTED BETWEEN "
10793  << Parameter_current << " AND " << *parameter_pt << std::endl;
10794  // message << "APPROXIMATE DOT PRODUCT : " << dot << "," << std::endl;
10795  // message << "IF CLOSE TO ZERO WE HAVE A BIFURCATION; ";
10796  // message << "OTHERWISE A TURNING POINT" << std::endl;
10797  message
10798  << "-----------------------------------------------------------"
10799  << std::endl;
10800 
10801  // Write the message to standard output
10802  oomph_info << message.str();
10803 
10804  // Open the information file for appending
10805  std::ofstream bifurcation_info("bifurcation_info",
10806  std::ios_base::app);
10807  // Write the message to the file
10808  bifurcation_info << message.str();
10809  bifurcation_info.close();
10810  }
10811  }
10812 
10813  // Calculate the derivatives required for the next stage of continuation
10814  // In this we pass the last value of z (i.e. approximation)
10816  {
10818  }
10819  // Or use finite differences
10820  else
10821  {
10823  }
10824 
10825  // If it's the first step then the value of the next step should
10826  // be the change in parameter divided by the parameter derivative
10827  // to obtain approximately the same parameter change
10828  if (!Arc_length_step_taken)
10829  {
10830  Ds_current = (*parameter_pt - Parameter_current) / Parameter_derivative;
10831  }
10832 
10833  // We have taken our first step
10834  Arc_length_step_taken = true;
10835  }
10836  // If there has not been a newton step then we still need to estimate
10837  // the derivatives in the arc length direction
10838  else
10839  {
10840  // Default is to calculate the continuation derivatives by solving the
10841  // linear system. We must do this to ensure that the derivatives are in
10842  // sync It could lead to problems near turning points when we should
10843  // really be solving an eigenproblem, but seems OK so far!
10844 
10845  // Save the current sign of the jacobian
10846  int temp_sign = Sign_of_jacobian;
10847 
10848  // Calculate the continuation derivatives, which includes a solve
10849  // of the linear system if not using finite differences
10851  {
10852  calculate_continuation_derivatives(parameter_pt);
10853  }
10854  // Otherwise use finite differences
10855  else
10856  {
10858  }
10859 
10860  // Reset the sign of the jacobian, just in case the sign has changed when
10861  // solving the continuation derivatives. The sign change will be picked
10862  // up on the next continuation step.
10863  Sign_of_jacobian = temp_sign;
10864  }
10865 
10866  // Reset the is_steady status of all timesteppers that
10867  // weren't already steady when we came in here and reset their
10868  // weights
10869  for (unsigned i = 0; i < n_time_steppers; i++)
10870  {
10871  if (!was_steady[i])
10872  {
10874  }
10875  }
10876 
10877  // If we are trying to find a bifurcation and the first sign change
10878  // has occured, use bisection
10881  {
10882  // If there has been a sign change we need to half the step size
10883  // and reverse the direction
10884  if (SIGN_CHANGE)
10885  {
10886  Ds_current *= -0.5;
10887  }
10888  // Otherwise
10889  else
10890  {
10891  // The size of the bracketed interval is always
10892  // 2ds - Ds_current (this will work even if the original step failed)
10893  // We want our new step size to be half this
10894  Ds_current = ds - 0.5 * Ds_current;
10895  }
10896  // Return the desired value of the step
10897  return Ds_current;
10898  }
10899 
10900  // If fewer than the desired number of Newton Iterations, increase the step
10901  if (max_count_in_adapt_loop < Desired_newton_iterations_ds)
10902  {
10903  return Ds_current * 1.5;
10904  }
10905  // If more than the desired number of Newton Iterations, reduce the step
10906  if (max_count_in_adapt_loop > Desired_newton_iterations_ds)
10907  {
10908  return Ds_current * (2.0 / 3.0);
10909  }
10910  // Otherwise return the step just taken
10911  return Ds_current;
10912  }
std::vector< double > DoubleVector
loads clump configuration
Definition: ClumpInput.h:26
unsigned newton_solve_continuation(double *const &parameter_pt)
Definition: problem.cc:9376
virtual void actions_after_parameter_increase(double *const &parameter_pt)
Definition: problem.h:1161
OomphCommunicator * communicator_pt()
access function to the oomph-lib communicator
Definition: problem.h:1246
void calculate_continuation_derivatives(double *const &parameter_pt)
Definition: problem.cc:9715
void calculate_continuation_derivatives_fd(double *const &parameter_pt)
Definition: problem.cc:9818
void set_consistent_pinned_values_for_continuation()
Definition: problem.cc:10466
void make_steady()
Definition: timesteppers.h:374
virtual void undo_make_steady()
Definition: timesteppers.h:482
bool is_steady() const
Definition: timesteppers.h:389

References actions_after_parameter_increase(), adapt(), Arc_length_step_taken, Bifurcation_detection, Bisect_to_find_bifurcation, calculate_continuation_derivatives(), calculate_continuation_derivatives_fd(), communicator_pt(), Desired_newton_iterations_ds, Dof_current, dof_current(), Dof_derivative, dof_derivative(), Dof_distribution_pt, Dof_pt, Ds_current, calibrate::error, boost::multiprecision::fabs(), First_jacobian_sign_change, i, oomph::TimeStepper::is_steady(), oomph::TimeStepper::make_steady(), Minimum_ds, newton_solve_continuation(), oomph::LinearAlgebraDistribution::nrow_local(), ntime_stepper(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, Parameter_current, Parameter_derivative, set_consistent_pinned_values_for_continuation(), Sign_of_jacobian, oomph::Global_string_for_annotation::string(), time_stepper_pt(), oomph::TimeStepper::undo_make_steady(), Use_continuation_timestepper, and Use_finite_differences_for_continuation_derivatives.

Referenced by arc_length_step_solve().

◆ are_hessian_products_calculated_analytically()

bool oomph::Problem::are_hessian_products_calculated_analytically ( )
inline

Function to determine whether the hessian products are calculated analytically

304  {
306  }

References Calculate_hessian_products_analytic.

Referenced by get_hessian_vector_products().

◆ assembly_handler_pt() [1/2]

◆ assembly_handler_pt() [2/2]

AssemblyHandler* const& oomph::Problem::assembly_handler_pt ( ) const
inline

Return a pointer to the assembly handler object (const version)

1577  {
1578  return Assembly_handler_pt;
1579  }

References Assembly_handler_pt.

◆ assign_eigenvector_to_dofs()

void Problem::assign_eigenvector_to_dofs ( DoubleVector eigenvector)

Assign the eigenvector passed to the function to the dofs.

Assign the eigenvector passed to the function to the dofs in the problem so that it can be output by the usual routines.

8717  {
8718  unsigned long n_dof = ndof();
8719  // Check that the eigenvector has the correct size
8720  if (eigenvector.nrow() != n_dof)
8721  {
8722  std::ostringstream error_message;
8723  error_message << "Eigenvector has size " << eigenvector.nrow()
8724  << ", not equal to the number of dofs in the problem,"
8725  << n_dof << std::endl;
8726 
8727  throw OomphLibError(
8728  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8729  }
8730 
8731  // Loop over the dofs and assign the eigenvector
8732  for (unsigned long n = 0; n < eigenvector.nrow_local(); n++)
8733  {
8734  dof(n) = eigenvector[n];
8735  }
8736 // Of course we now need to synchronise
8737 #ifdef OOMPH_HAS_MPI
8738  this->synchronise_all_dofs();
8739 #endif
8740  }

References dof(), n, ndof(), oomph::DistributableLinearAlgebraObject::nrow(), oomph::DistributableLinearAlgebraObject::nrow_local(), OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

◆ assign_eqn_numbers()

unsigned long Problem::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 elements) and then does the equation numbering for the elements. Virtual so it can be overloaded in MPI problems. Bool argument can be set to false to ignore assigning local equation numbers (found to be necessary in the parallel implementation of locate_zeta between multiple meshes).

Assign all equation numbers for problem: Deals with global data (= data that isn't attached to any elements) and then does the equation numbering for the elements. Bool argument can be set to false to ignore assigning local equation numbers (necessary in the parallel implementation of locate_zeta between multiple meshes).

1991  {
1992  // Check that the global mesh has been build
1993 #ifdef PARANOID
1994  if (Mesh_pt == 0)
1995  {
1996  std::ostringstream error_stream;
1997  error_stream << "Global mesh does not exist, so equation numbers cannot "
1998  "be assigned.\n";
1999  // Check for sub meshes
2000  if (nsub_mesh() == 0)
2001  {
2002  error_stream << "There aren't even any sub-meshes in the Problem.\n"
2003  << "You can set the global mesh directly by using\n"
2004  << "Problem::mesh_pt() = my_mesh_pt;\n"
2005  << "OR you can use Problem::add_sub_mesh(mesh_pt); "
2006  << "to add a sub mesh.\n";
2007  }
2008  else
2009  {
2010  error_stream << "There are " << nsub_mesh() << " sub-meshes.\n";
2011  }
2012  error_stream << "You need to call Problem::build_global_mesh() to create "
2013  "a global mesh\n"
2014  << "from the sub-meshes.\n\n";
2015 
2016  throw OomphLibError(
2017  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2018  }
2019 #endif
2020 
2021  // Number of submeshes
2022  unsigned n_sub_mesh = Sub_mesh_pt.size();
2023 
2024 #ifdef OOMPH_HAS_MPI
2025 
2026  // Storage for number of processors
2027  int n_proc = this->communicator_pt()->nproc();
2028 
2029 
2030  if (n_proc > 1)
2031  {
2032  // Force re-analysis of time spent on assembly each
2033  // elemental Jacobian
2034  Must_recompute_load_balance_for_assembly = true;
2035  Elemental_assembly_time.clear();
2036  }
2037  else
2038  {
2039  Must_recompute_load_balance_for_assembly = false;
2040  }
2041 
2042  // Re-distribution of elements over processors during assembly
2043  // must be recomputed
2044  if (!Problem_has_been_distributed)
2045  {
2046  // Set default first and last elements for parallel assembly
2047  // of non-distributed problem.
2048  set_default_first_and_last_element_for_assembly();
2049  }
2050 
2051 #endif
2052 
2053 
2054  double t_start = 0.0;
2056  {
2057  t_start = TimingHelpers::timer();
2058  }
2059 
2060  // Loop over all elements in the mesh and set up any additional
2061  // dependencies that they may have (e.g. storing the geometric
2062  // Data, i.e. Data that affects an element's shape in elements
2063  // with algebraic node-update functions
2064  unsigned nel = Mesh_pt->nelement();
2065  for (unsigned e = 0; e < nel; e++)
2066  {
2068  }
2069 
2070 #ifdef OOMPH_HAS_MPI
2071  // Complete setup of dependencies for external halo elements too
2072  unsigned n_mesh = this->nsub_mesh();
2073  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
2074  {
2075  for (int iproc = 0; iproc < n_proc; iproc++)
2076  {
2077  unsigned n_ext_halo_el = mesh_pt(i_mesh)->nexternal_halo_element(iproc);
2078  for (unsigned e = 0; e < n_ext_halo_el; e++)
2079  {
2080  mesh_pt(i_mesh)
2081  ->external_halo_element_pt(iproc, e)
2082  ->complete_setup_of_dependencies();
2083  }
2084  }
2085  }
2086 #endif
2087 
2088 
2089  double t_end = 0.0;
2091  {
2092  t_end = TimingHelpers::timer();
2093  oomph_info
2094  << "Time for complete setup of dependencies in assign_eqn_numbers: "
2095  << t_end - t_start << std::endl;
2096  }
2097 
2098 
2099  // Initialise number of dofs for reserve below
2100  unsigned n_dof = 0;
2101 
2102  // Potentially loop over remainder of routine, possible re-visiting all
2103  // those parts that must be redone, following the removal of duplicate
2104  // external halo data.
2105  for (unsigned loop_count = 0; loop_count < 2; loop_count++)
2106  {
2107  //(Re)-set the dof pointer to zero length because entries are
2108  // pushed back onto it -- if it's not reset here then we get into
2109  // trouble during mesh refinement when we reassign all dofs
2110  Dof_pt.resize(0);
2111 
2112  // Reserve from previous allocation if we're going around again
2113  Dof_pt.reserve(n_dof);
2114 
2115  // Reset the equation number
2116  unsigned long equation_number = 0;
2117 
2118  // Now set equation numbers for the global Data
2119  unsigned Nglobal_data = nglobal_data();
2120  for (unsigned i = 0; i < Nglobal_data; i++)
2121  {
2122  Global_data_pt[i]->assign_eqn_numbers(equation_number, Dof_pt);
2123  }
2124 
2126  {
2127  t_start = TimingHelpers::timer();
2128  }
2129 
2130  // Call assign equation numbers on the global mesh
2132 
2133  // Deal with the spine meshes additional numbering
2134  // If there is only one mesh
2135  if (n_sub_mesh == 0)
2136  {
2137  if (SpineMesh* const spine_mesh_pt = dynamic_cast<SpineMesh*>(Mesh_pt))
2138  {
2139  n_dof = spine_mesh_pt->assign_global_spine_eqn_numbers(Dof_pt);
2140  }
2141  }
2142  // Otherwise loop over the sub meshes
2143  else
2144  {
2145  // Assign global equation numbers first
2146  for (unsigned i = 0; i < n_sub_mesh; i++)
2147  {
2148  if (SpineMesh* const spine_mesh_pt =
2149  dynamic_cast<SpineMesh*>(Sub_mesh_pt[i]))
2150  {
2151  n_dof = spine_mesh_pt->assign_global_spine_eqn_numbers(Dof_pt);
2152  }
2153  }
2154  }
2155 
2157  {
2158  t_end = TimingHelpers::timer();
2159  oomph_info
2160  << "Time for assign_global_eqn_numbers in assign_eqn_numbers: "
2161  << t_end - t_start << std::endl;
2162  t_start = TimingHelpers::timer();
2163  }
2164 
2165 
2166 #ifdef OOMPH_HAS_MPI
2167 
2168  // reset previous allocation
2169  Parallel_sparse_assemble_previous_allocation = 0;
2170 
2171  // Only synchronise if the problem has actually been
2172  // distributed.
2173  if (Problem_has_been_distributed)
2174  {
2175  // Synchronise the equation numbers and return the total
2176  // number of degrees of freedom in the overall problem
2177  // Do not assign local equation numbers -- we're doing this
2178  // below.
2179  n_dof = synchronise_eqn_numbers(false);
2180  }
2181  // ..else just setup the Dof_distribution_pt
2182  // NOTE: this is setup by synchronise_eqn_numbers(...)
2183  // if Problem_has_been_distributed
2184  else
2185 #endif
2186  {
2187  Dof_distribution_pt->build(Communicator_pt, n_dof, false);
2188  }
2189 
2191  {
2192  t_end = TimingHelpers::timer();
2193  oomph_info << "Time for Problem::synchronise_eqn_numbers in "
2194  << "Problem::assign_eqn_numbers: " << t_end - t_start
2195  << std::endl;
2196  }
2197 
2198 
2199 #ifdef OOMPH_HAS_MPI
2200 
2201 
2202  // Now remove duplicate data in external halo elements
2203  if (Problem_has_been_distributed)
2204  {
2206  {
2207  t_start = TimingHelpers::timer();
2208  }
2209 
2210  // Monitor if we've actually changed anything
2211  bool actually_removed_some_data = false;
2212 
2213  // Only do it once!
2214  if (loop_count == 0)
2215  {
2216  if (n_sub_mesh == 0)
2217  {
2218  remove_duplicate_data(Mesh_pt, actually_removed_some_data);
2219  }
2220  else
2221  {
2222  for (unsigned i = 0; i < n_sub_mesh; i++)
2223  {
2224  bool tmp_actually_removed_some_data = false;
2225  remove_duplicate_data(Sub_mesh_pt[i],
2226  tmp_actually_removed_some_data);
2227  if (tmp_actually_removed_some_data)
2228  actually_removed_some_data = true;
2229  }
2230  }
2231  }
2232 
2233 
2235  {
2236  t_end = TimingHelpers::timer();
2237  std::stringstream tmp;
2238  tmp << "Time for calls to Problem::remove_duplicate_data in "
2239  << "Problem::assign_eqn_numbers: " << t_end - t_start
2240  << " ; have ";
2241  if (!actually_removed_some_data)
2242  {
2243  tmp << " not ";
2244  }
2245  tmp << " removed some/any data.\n";
2246  oomph_info << tmp.str();
2247  t_start = TimingHelpers::timer();
2248  }
2249 
2250  // Break out of the loop if we haven't done anything here.
2251  unsigned status = 0;
2252  if (actually_removed_some_data) status = 1;
2253 
2254  // Allreduce to check if anyone has removed any data
2255  unsigned overall_status = 0;
2256  MPI_Allreduce(&status,
2257  &overall_status,
2258  1,
2259  MPI_UNSIGNED,
2260  MPI_MAX,
2261  this->communicator_pt()->mpi_comm());
2262 
2263 
2265  {
2266  t_end = TimingHelpers::timer();
2267  std::stringstream tmp;
2268  tmp
2269  << "Time for MPI_Allreduce after Problem::remove_duplicate_data in "
2270  << "Problem::assign_eqn_numbers: " << t_end - t_start << std::endl;
2271  oomph_info << tmp.str();
2272  t_start = TimingHelpers::timer();
2273  }
2274 
2275  // Bail out if we haven't done anything here
2276  if (overall_status != 1)
2277  {
2278  break;
2279  }
2280 
2281  // Big tidy up: Remove null pointers from halo/haloed node storage
2282  // for all meshes (this involves comms and therefore must be
2283  // performed outside loop over meshes so the all-to-all is only
2284  // done once)
2285  remove_null_pointers_from_external_halo_node_storage();
2286 
2287  // Time it...
2289  {
2290  double t_end = TimingHelpers::timer();
2291  oomph_info << "Total time for "
2292  << "Problem::remove_null_pointers_from_external_halo_node_"
2293  "storage(): "
2294  << t_end - t_start << std::endl;
2295  }
2296  }
2297  else
2298  {
2299  // Problem not distributed; no need for another loop
2300  break;
2301  }
2302 
2303 #else
2304 
2305  // Serial run: Again no need for a second loop
2306  break;
2307 
2308 #endif
2309 
2310  } // end of loop over fcts that need to be re-executed if
2311  // we've removed duplicate external data
2312 
2313 
2314  // Resize the sparse assemble with arrays previous allocation
2316 
2317 
2319  {
2320  t_start = TimingHelpers::timer();
2321  }
2322 
2323  // Finally assign local equations
2324  if (assign_local_eqn_numbers)
2325  {
2326  if (n_sub_mesh == 0)
2327  {
2329  }
2330  else
2331  {
2332  for (unsigned i = 0; i < n_sub_mesh; i++)
2333  {
2334  Sub_mesh_pt[i]->assign_local_eqn_numbers(
2336  }
2337  }
2338  }
2339 
2341  {
2342  t_end = TimingHelpers::timer();
2343  oomph_info << "Total time for all Mesh::assign_local_eqn_numbers in "
2344  << "Problem::assign_eqn_numbers: " << t_end - t_start
2345  << std::endl;
2346  }
2347 
2348 
2349  // and return the total number of DOFs
2350  return n_dof;
2351  }
virtual void complete_setup_of_dependencies()
Definition: elements.h:974
void build(const OomphCommunicator *const comm_pt, const unsigned &first_row, const unsigned &nrow_local, const unsigned &nrow=0)
Definition: linear_algebra_distribution.cc:35
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition: mesh.h:448
void assign_local_eqn_numbers(const bool &store_local_dof_pt)
Assign local equation numbers in all elements.
Definition: mesh.cc:765
unsigned long assign_global_eqn_numbers(Vector< double * > &Dof_pt)
Assign (global) equation numbers to the nodes.
Definition: mesh.cc:677
unsigned long nelement() const
Return number of elements in the mesh.
Definition: mesh.h:590
int nproc() const
number of processors
Definition: communicator.h:157
Vector< Vector< unsigned > > Sparse_assemble_with_arrays_previous_allocation
Definition: problem.h:667
unsigned nglobal_data() const
Return the number of global data values.
Definition: problem.h:1686
Eigen::Matrix< Scalar, Dynamic, Dynamic, ColMajor > tmp
Definition: level3_impl.h:365

References oomph::Mesh::assign_global_eqn_numbers(), oomph::Mesh::assign_local_eqn_numbers(), oomph::LinearAlgebraDistribution::build(), Communicator_pt, communicator_pt(), oomph::GeneralisedElement::complete_setup_of_dependencies(), oomph::Global_timings::Doc_comprehensive_timings, Dof_distribution_pt, Dof_pt, e(), oomph::Mesh::element_pt(), Global_data_pt, i, Mesh_pt, mesh_pt(), oomph::Mesh::nelement(), nglobal_data(), oomph::OomphCommunicator::nproc(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, Sparse_assemble_with_arrays_previous_allocation, Store_local_dof_pt_in_elements, Sub_mesh_pt, oomph::TimingHelpers::timer(), and tmp.

Referenced by adapt(), adapt_based_on_error_estimates(), oomph::PeriodicOrbitAssemblyHandler< NNODE_1D >::adapt_temporal_mesh(), AxisymFreeSurfaceNozzleAdvDiffRobinProblem< ELEMENT >::AxisymFreeSurfaceNozzleAdvDiffRobinProblem(), bifurcation_adapt_helper(), oomph::ODEProblem::build(), oomph::BiharmonicProblem< DIM >::build_global_mesh_and_assign_eqn_numbers(), CapProblem< ELEMENT >::CapProblem(), ContinuationProblem::ContinuationProblem(), ConvectionProblem< NST_ELEMENT, AD_ELEMENT >::ConvectionProblem(), EighthSpherePoissonProblem< ELEMENT >::EighthSpherePoissonProblem(), ElasticBeamProblem::ElasticBeamProblem(), ElasticInterfaceProblem< ELEMENT, TIMESTEPPER >::ElasticInterfaceProblem(), ElasticRingProblem< ELEMENT >::ElasticRingProblem(), EntryFlowProblem< ELEMENT >::EntryFlowProblem(), ExtrudedMovingCylinderProblem< TWO_D_ELEMENT, THREE_D_ELEMENT >::ExtrudedMovingCylinderProblem(), FlowAroundCylinderProblem< ELEMENT >::FlowAroundCylinderProblem(), FluxPoissonMGProblem< ELEMENT, MESH >::FluxPoissonMGProblem(), FluxPoissonProblem< ELEMENT >::FluxPoissonProblem(), FreeSurfaceRotationProblem< ELEMENT >::FreeSurfaceRotationProblem(), FSIChannelWithLeafletProblem< ELEMENT >::FSIChannelWithLeafletProblem(), FSIRingProblem::FSIRingProblem(), oomph::FpPressureAdvectionDiffusionProblem< ELEMENT >::get_pressure_advection_diffusion_jacobian(), HomogenisationProblem< ELEMENT >::HomogenisationProblem(), InterfaceProblem< ELEMENT, TIMESTEPPER >::InterfaceProblem(), LinearWaveProblem< ELEMENT, TIMESTEPPER >::LinearWaveProblem(), main(), MeltSpinningProblem< ELEMENT >::MeltSpinningProblem(), NavierStokesProblem< ELEMENT >::NavierStokesProblem(), OneDPoissonProblem< ELEMENT >::OneDPoissonProblem(), oomph::NonLinearElasticitySmoothMesh< ELEMENT >::operator()(), oomph::LinearElasticitySmoothMesh< LINEAR_ELASTICITY_ELEMENT >::operator()(), oomph::PoissonSmoothMesh< POISSON_ELEMENT >::operator()(), OrrSommerfeldProblem< ELEMENT >::OrrSommerfeldProblem(), OscRingNStProblem< ELEMENT >::OscRingNStProblem(), PolarNSProblem< ELEMENT >::output_streamfunction(), p_adapt(), p_refine_selected_elements(), p_refine_uniformly(), p_refine_uniformly_aux(), p_unrefine_uniformly(), PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >::PerturbedStateProblem(), PoissonProblem< ELEMENT >::PoissonProblem(), PRefineableOneDPoissonProblem< ELEMENT >::PRefineableOneDPoissonProblem(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::project(), PseudoSolidCapProblem< ELEMENT >::PseudoSolidCapProblem(), QuarterCircleDrivenCavityProblem< ELEMENT >::QuarterCircleDrivenCavityProblem(), QuarterCircleDrivenCavityProblem2< ELEMENT >::QuarterCircleDrivenCavityProblem2(), RayleighProblem< ELEMENT, TIMESTEPPER >::RayleighProblem(), read(), refine_selected_elements(), refine_uniformly(), refine_uniformly_aux(), RefineableActivatorInhibitorProblem< ELEMENT >::RefineableActivatorInhibitorProblem(), RefineableAdvectionDiffusionProblem< ELEMENT >::RefineableAdvectionDiffusionProblem(), RefineableFishPoissonProblem< ELEMENT >::RefineableFishPoissonProblem(), RefineableOneDPoissonProblem< ELEMENT >::RefineableOneDPoissonProblem(), RefineablePoissonProblem< ELEMENT >::RefineablePoissonProblem(), RefineableRotatingCylinderProblem< ELEMENT >::RefineableRotatingCylinderProblem(), RefineableTwoDPoissonProblem< ELEMENT >::RefineableTwoDPoissonProblem(), RefineableTwoMeshFluxPoissonProblem< ELEMENT >::RefineableTwoMeshFluxPoissonProblem(), RefineableUnsteadyHeatProblem< ELEMENT >::RefineableUnsteadyHeatProblem(), RotatingProblem< ELEMENT >::RotatingProblem(), oomph::SegregatableFSIProblem::segregated_solve(), oomph::SolidICProblem::set_newmark_initial_condition_consistently(), oomph::SolidICProblem::set_newmark_initial_condition_directly(), oomph::SolidICProblem::set_static_initial_condition(), set_timestepper_for_all_data(), oomph::MGSolver< DIM >::setup_mg_hierarchy(), oomph::HelmholtzMGPreconditioner< DIM >::setup_mg_hierarchy(), oomph::SolidICProblem::setup_problem(), SimpleShearProblem< ELEMENT >::SimpleShearProblem(), SolidFreeSurfaceRotationProblem< ELEMENT >::SolidFreeSurfaceRotationProblem(), SphericalSteadyRotationProblem< ELEMENT >::SphericalSteadyRotationProblem(), SteadyCurvedTubeProblem< ELEMENT >::SteadyCurvedTubeProblem(), SteadyHelicalProblem< ELEMENT >::SteadyHelicalProblem(), SteadyTubeProblem< ELEMENT >::SteadyTubeProblem(), oomph::StreamfunctionProblem::StreamfunctionProblem(), SUPGAdvectionDiffusionProblem< ELEMENT >::SUPGAdvectionDiffusionProblem(), SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >::SurfactantProblem(), ContactProblem< ELEMENT >::switch_to_force_control(), TestRefineablePoissonProblem< ELEMENT >::TestRefineablePoissonProblem(), ThreeDPoissonProblem< ELEMENT >::ThreeDPoissonProblem(), TurekNonFSIProblem< ELEMENT >::TurekNonFSIProblem(), TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >::TurekProblem(), TwoMeshFluxAdvectionDiffusionProblem< ELEMENT >::TwoMeshFluxAdvectionDiffusionProblem(), TwoMeshFluxPoissonProblem< ELEMENT >::TwoMeshFluxPoissonProblem(), UniformTranspiration< ELEMENT >::UniformTranspiration(), UnitCubePoissonMGProblem< ELEMENT, MESH >::UnitCubePoissonMGProblem(), unrefine_uniformly(), UnsteadyHeatProblem< ELEMENT >::UnsteadyHeatProblem(), UnstructuredFvKProblem< ELEMENT >::UnstructuredFvKProblem(), UnstructuredSolidProblem< ELEMENT, MESH >::UnstructuredSolidProblem(), oomph::FpPressureAdvectionDiffusionProblem< ELEMENT >::validate(), and oomph::WomersleyProblem< ELEMENT, DIM >::WomersleyProblem().

◆ assign_initial_values_impulsive() [1/2]

void Problem::assign_initial_values_impulsive ( )

Initialise data and nodal positions to simulate impulsive start from initial configuration/solution

Initialise the previous values of the variables for time stepping corresponding to an impulsive start. Previous history for all data is generated by the appropriate timesteppers. Previous nodal positions are simply copied backwards.

11500  {
11501  // Assign the impulsive values in the "master" mesh
11503 
11504  // Loop over global data
11505  unsigned Nglobal = Global_data_pt.size();
11506  for (unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
11507  {
11508  Global_data_pt[iglobal]
11509  ->time_stepper_pt()
11510  ->assign_initial_values_impulsive(Global_data_pt[iglobal]);
11511  }
11512  }
void assign_initial_values_impulsive()
Assign initial values for an impulsive start.
Definition: mesh.cc:2288

References oomph::Mesh::assign_initial_values_impulsive(), Global_data_pt, and Mesh_pt.

Referenced by assign_initial_values_impulsive(), oomph::SolidICProblem::set_static_initial_condition(), steady_newton_solve(), and oomph::SegregatableFSIProblem::steady_segregated_solve().

◆ assign_initial_values_impulsive() [2/2]

void Problem::assign_initial_values_impulsive ( const double dt)

Initialise data and nodal positions to simulate an impulsive start and also set the initial and previous values of dt

Assign the values for an impulsive start and also set the initial values of the previous dts to both be dt

11520  {
11521  // First initialise the dts and set the weights
11522  initialise_dt(dt);
11523  // Now call assign_initial_values_impulsive
11525  }
void initialise_dt(const double &dt)
Definition: problem.cc:13231

References assign_initial_values_impulsive(), and initialise_dt().

◆ bifurcation_adapt_doc_errors()

void Problem::bifurcation_adapt_doc_errors ( const unsigned bifurcation_type)
private

A function that is used to document the errors used in the adaptive solution of bifurcation problems.

A function that is used to document the errors when adapting a bifurcation-tracking problem, which requires separate interpolation of the associated eigenfunction. The error measure is chosen to be a suitable combination of the errors in the base flow and the eigenfunction. The bifurcation type is passed as an argument

13649  {
13650  // Dummy arguments
13651  unsigned n_refined, n_unrefined;
13652  // Just call the bifurcation helper without actually adapting
13653  bifurcation_adapt_helper(n_refined, n_unrefined, bifurcation_type, false);
13654  }

References bifurcation_adapt_helper().

Referenced by doc_errors().

◆ bifurcation_adapt_helper()

void Problem::bifurcation_adapt_helper ( unsigned n_refined,
unsigned n_unrefined,
const unsigned bifurcation_type,
const bool actually_adapt = true 
)
private

A function that is used to adapt a bifurcation-tracking problem, which requires separate interpolation of the associated eigenfunction. The error measure is chosen to be a suitable combination of the errors in the base flow and the eigenfunction

A function that is used to adapt a bifurcation-tracking problem, which requires separate interpolation of the associated eigenfunction. The error measure is chosen to be a suitable combination of the errors in the base flow and the eigenfunction. The bifurcation type is passed as an argument

13358  {
13359  // Storage for eigenfunction from the problem
13360  Vector<DoubleVector> eigenfunction;
13361  // Get the eigenfunction from the problem
13362  this->get_bifurcation_eigenfunction(eigenfunction);
13363 
13364  // Get the bifurcation parameter
13365  double* parameter_pt = this->bifurcation_parameter_pt();
13366 
13367  // Get the frequency parameter if tracking a Hopf bifurcation
13368  double omega = 0.0;
13369  // If we're tracking a Hopf then also get the frequency
13370  if (bifurcation_type == 3)
13371  {
13372  omega = dynamic_cast<HopfHandler*>(assembly_handler_pt())->omega();
13373  }
13374 
13375  // If we're tracking a Pitchfork get the slack parameter (Hack)
13376  double sigma = 0.0;
13377  if (bifurcation_type == 2)
13378  {
13379  sigma = this->dof(this->ndof() - 1);
13380  }
13381 
13382  // We can now deactivate the bifurcation tracking in the problem
13383  // to restore the degrees of freedom to the unaugmented value
13385 
13386  // Next, we create copies of the present problem
13387  // The number of copies depends on the number of eigenfunctions
13388  // One copy for each eigenfunction
13389  const unsigned n_copies = eigenfunction.size();
13390  Copy_of_problem_pt.resize(n_copies);
13391 
13392  // Loop over the number of copies
13393  for (unsigned c = 0; c < n_copies; c++)
13394  {
13395  // If we don't already have a copy
13396  if (Copy_of_problem_pt[c] == 0)
13397  {
13398  // Create the copy
13399  Copy_of_problem_pt[c] = this->make_copy();
13400 
13401  // Refine the copy to the same level as the current problem
13402 
13403  // Find number of submeshes
13404  const unsigned N_mesh = Copy_of_problem_pt[c]->nsub_mesh();
13405  // If there is only one mesh
13406  if (N_mesh == 0)
13407  {
13408  // Can we refine the mesh
13409  if (TreeBasedRefineableMeshBase* mmesh_pt =
13410  dynamic_cast<TreeBasedRefineableMeshBase*>(
13412  {
13413  // Is the adapt flag set
13414  if (mmesh_pt->is_adaptation_enabled())
13415  {
13416  // Now get the original problem's mesh if it's refineable
13417  if (TreeBasedRefineableMeshBase* original_mesh_pt =
13418  dynamic_cast<TreeBasedRefineableMeshBase*>(
13419  this->mesh_pt(0)))
13420  {
13421  mmesh_pt->refine_base_mesh_as_in_reference_mesh(
13422  original_mesh_pt);
13423  }
13424  else
13425  {
13426  oomph_info
13427  << "Info/Warning: Mesh in orginal problem is not refineable."
13428  << std::endl;
13429  }
13430  }
13431  else
13432  {
13433  oomph_info << "Info/Warning: Mesh adaptation is disabled in copy."
13434  << std::endl;
13435  }
13436  }
13437  else
13438  {
13439  oomph_info << "Info/Warning: Mesh cannot be adapted in copy."
13440  << std::endl;
13441  }
13442  } // End of single mesh case
13443  // Otherwise loop over the submeshes
13444  else
13445  {
13446  for (unsigned m = 0; m < N_mesh; m++)
13447  {
13448  // Can we refine the submesh
13449  if (TreeBasedRefineableMeshBase* mmesh_pt =
13450  dynamic_cast<TreeBasedRefineableMeshBase*>(
13452  {
13453  // Is the adapt flag set
13454  if (mmesh_pt->is_adaptation_enabled())
13455  {
13456  // Now get the original problem's mesh
13457  if (TreeBasedRefineableMeshBase* original_mesh_pt =
13458  dynamic_cast<TreeBasedRefineableMeshBase*>(
13459  this->mesh_pt(m)))
13460  {
13461  mmesh_pt->refine_base_mesh_as_in_reference_mesh(
13462  original_mesh_pt);
13463  }
13464  else
13465  {
13466  oomph_info << "Info/Warning: Mesh in orginal problem is not "
13467  "refineable."
13468  << std::endl;
13469  }
13470  }
13471  else
13472  {
13473  oomph_info
13474  << "Info/Warning: Mesh adaptation is disabled in copy."
13475  << std::endl;
13476  }
13477  }
13478  else
13479  {
13480  oomph_info << "Info/Warning: Mesh cannot be adapted in copy."
13481  << std::endl;
13482  }
13483  }
13484  // rebuild the global mesh in the copy
13485  Copy_of_problem_pt[c]->rebuild_global_mesh();
13486 
13487  } // End of multiple mesh case
13488 
13489  // Must call actions after adapt
13490  Copy_of_problem_pt[c]->actions_after_adapt();
13491 
13492  // Assign the equation numbers to the copy (quietly)
13494  }
13495  } // End of creation of copies
13496 
13497 
13498  // Now check some numbers
13499  for (unsigned c = 0; c < n_copies; c++)
13500  {
13501  // Check that the dofs match for each copy
13502 #ifdef PARANOID
13503  // If the problems don't match then complain
13504  if (Copy_of_problem_pt[c]->ndof() != this->ndof())
13505  {
13506  std::ostringstream error_stream;
13507  error_stream << "Number of unknowns in the problem copy " << c << " "
13508  << "not equal to number in the original:\n"
13509  << this->ndof() << " (original) "
13510  << Copy_of_problem_pt[c]->ndof() << " (copy)\n";
13511 
13512  throw OomphLibError(
13513  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13514  }
13515 #endif
13516 
13517  // Assign the eigenfunction(s) to the copied problems
13518  Copy_of_problem_pt[c]->assign_eigenvector_to_dofs(eigenfunction[c]);
13519  // Set all pinned values to zero
13520  Copy_of_problem_pt[c]->set_pinned_values_to_zero();
13521  }
13522 
13523  // Symmetrise the problem if we are solving a pitchfork
13524  if (bifurcation_type == 2)
13525  {
13527  ->symmetrise_eigenfunction_for_adaptive_pitchfork_tracking();
13528  }
13529 
13530  // Find error estimates based on current problem and eigenproblem
13531  // Now we need to get the error estimates for both problems.
13532  Vector<Vector<double>> base_error, eigenfunction_error;
13533  this->get_all_error_estimates(base_error);
13534  // Loop over the copies
13535  for (unsigned c = 0; c < n_copies; c++)
13536  {
13537  // Get the error estimates for the copy
13538  Copy_of_problem_pt[c]->get_all_error_estimates(eigenfunction_error);
13539 
13540  // Find the number of meshes
13541  unsigned n_mesh = base_error.size();
13542 
13543 #ifdef PARANOID
13544  if (n_mesh != eigenfunction_error.size())
13545  {
13546  std::ostringstream error_stream;
13547  error_stream << "Problems do not have the same number of meshes\n"
13548  << "Base : " << n_mesh
13549  << " : Eigenproblem : " << eigenfunction_error.size()
13550  << "\n";
13551  throw OomphLibError(
13552  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13553  }
13554 #endif
13555 
13556  for (unsigned m = 0; m < n_mesh; m++)
13557  {
13558  // Check the number of elements is the same
13559  unsigned n_element = base_error[m].size();
13560 #ifdef PARANOID
13561  if (n_element != eigenfunction_error[m].size())
13562  {
13563  std::ostringstream error_stream;
13564  error_stream << "Mesh " << m
13565  << " does not have the same number of elements in the "
13566  "two problems:\n"
13567  << "Base: " << n_element
13568  << " : Eigenproblem: " << eigenfunction_error[m].size()
13569  << "\n";
13570  throw OomphLibError(error_stream.str(),
13573  }
13574 #endif
13575  // Now add all the error esimates together
13576  for (unsigned e = 0; e < n_element; e++)
13577  {
13578  // Add the error estimates (lazy)
13579  base_error[m][e] += eigenfunction_error[m][e];
13580  }
13581  }
13582  } // End of loop over copies
13583 
13584  // Then refine all problems based on the combined measure
13585  // if we are actually adapting (not just estimating the errors)
13586  if (actually_adapt)
13587  {
13588  this->adapt_based_on_error_estimates(n_refined, n_unrefined, base_error);
13589  for (unsigned c = 0; c < n_copies; c++)
13590  {
13591  Copy_of_problem_pt[c]->adapt_based_on_error_estimates(
13592  n_refined, n_unrefined, base_error);
13593  }
13594  // Symmetrise the problem (again) if we are solving for a pitchfork
13595  if (bifurcation_type == 2)
13596  {
13598  ->symmetrise_eigenfunction_for_adaptive_pitchfork_tracking();
13599  }
13600 
13601  // Now get the refined guess for the eigenvector
13602  for (unsigned c = 0; c < n_copies; c++)
13603  {
13604  Copy_of_problem_pt[c]->get_dofs(eigenfunction[c]);
13605  }
13606  }
13607 
13608  // Reactivate the tracking
13609  switch (bifurcation_type)
13610  {
13611  // Fold tracking
13612  case 1:
13613  this->activate_fold_tracking(parameter_pt);
13614  break;
13615 
13616  // Pitchfork
13617  case 2:
13618  this->activate_pitchfork_tracking(parameter_pt, eigenfunction[0]);
13619  // reset the slack parameter
13620  this->dof(this->ndof() - 1) = sigma;
13621  break;
13622 
13623  // Hopf
13624  case 3:
13625  this->activate_hopf_tracking(
13626  parameter_pt, omega, eigenfunction[0], eigenfunction[1]);
13627  break;
13628 
13629  default:
13630  std::ostringstream error_stream;
13631  error_stream << "Bifurcation type " << bifurcation_type
13632  << " not known\n"
13633  << "1: Fold, 2: Pitchfork, 3: Hopf\n";
13634  throw OomphLibError(
13635  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13636  }
13637  }
Scalar Scalar int size
Definition: benchVecAdd.cpp:17
void activate_hopf_tracking(double *const &parameter_pt, const bool &block_solve=true)
Definition: problem.cc:10218
void activate_pitchfork_tracking(double *const &parameter_pt, const DoubleVector &symmetry_vector, const bool &block_solve=true)
Definition: problem.cc:10188
void get_bifurcation_eigenfunction(Vector< DoubleVector > &eigenfunction)
Definition: problem.cc:10091
double * bifurcation_parameter_pt() const
Definition: problem.cc:10081
void activate_fold_tracking(double *const &parameter_pt, const bool &block_solve=true)
Definition: problem.cc:10103
void deactivate_bifurcation_tracking()
Definition: problem.h:2353
int sigma
Definition: calibrate.py:179

References activate_fold_tracking(), activate_hopf_tracking(), activate_pitchfork_tracking(), adapt_based_on_error_estimates(), assembly_handler_pt(), assign_eqn_numbers(), bifurcation_parameter_pt(), calibrate::c, Copy_of_problem_pt, deactivate_bifurcation_tracking(), dof(), e(), get_all_error_estimates(), get_bifurcation_eigenfunction(), m, make_copy(), mesh_pt(), ndof(), Eigen::internal::omega(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, calibrate::sigma, and size.

Referenced by adapt(), bifurcation_adapt_doc_errors(), and p_adapt().

◆ bifurcation_parameter_pt()

double * Problem::bifurcation_parameter_pt ( ) const

Return pointer to the parameter that is used in the bifurcation detection. If we are not tracking a bifurcation then an error will be thrown by the AssemblyHandler

10082  {
10084  }
virtual double * bifurcation_parameter_pt() const
Definition: assembly_handler.cc:168

References Assembly_handler_pt, and oomph::AssemblyHandler::bifurcation_parameter_pt().

Referenced by bifurcation_adapt_helper().

◆ build_global_mesh()

void Problem::build_global_mesh ( )

Build the global mesh by combining the all the submeshes. Note: The nodes boundary information refers to the boundary numbers within the submesh!

Build a single (global) mesh from a number of submeshes which are passed as a vector of pointers to the submeshes. The ordering is not necessarily optimal.

1494  {
1495 #ifdef PARANOID
1496  // Has a global mesh already been built
1497  if (Mesh_pt != 0)
1498  {
1499  std::string error_message = "Problem::build_global_mesh() called,\n";
1500  error_message += " but a global mesh has already been built:\n";
1501  error_message += "Problem::Mesh_pt is not zero!\n";
1502 
1503  throw OomphLibError(
1505  }
1506  // Check that there are submeshes
1507  if (Sub_mesh_pt.size() == 0)
1508  {
1509  std::string error_message = "Problem::build_global_mesh() called,\n";
1510  error_message += " but there are no submeshes:\n";
1511  error_message += "Problem::Sub_mesh_pt has no entries\n";
1512 
1513  throw OomphLibError(
1515  }
1516 #endif
1517 
1518  // Create an empty mesh
1519  Mesh_pt = new Mesh();
1520 
1521  // Call the rebuild function to construct the mesh
1523  }

References Mesh_pt, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, rebuild_global_mesh(), oomph::Global_string_for_annotation::string(), and Sub_mesh_pt.

Referenced by AxisymFreeSurfaceNozzleAdvDiffRobinProblem< ELEMENT >::AxisymFreeSurfaceNozzleAdvDiffRobinProblem(), oomph::ODEProblem::build(), oomph::BiharmonicProblem< DIM >::build_global_mesh_and_assign_eqn_numbers(), CapProblem< ELEMENT >::CapProblem(), ConvectionProblem< NST_ELEMENT, AD_ELEMENT >::ConvectionProblem(), ElasticInterfaceProblem< ELEMENT, TIMESTEPPER >::ElasticInterfaceProblem(), FluxPoissonMGProblem< ELEMENT, MESH >::FluxPoissonMGProblem(), FreeSurfaceRotationProblem< ELEMENT >::FreeSurfaceRotationProblem(), FSIChannelWithLeafletProblem< ELEMENT >::FSIChannelWithLeafletProblem(), FSIRingProblem::FSIRingProblem(), HomogenisationProblem< ELEMENT >::HomogenisationProblem(), InterfaceProblem< ELEMENT, TIMESTEPPER >::InterfaceProblem(), MeltSpinningProblem< ELEMENT >::MeltSpinningProblem(), oomph::NonLinearElasticitySmoothMesh< ELEMENT >::operator()(), OscRingNStProblem< ELEMENT >::OscRingNStProblem(), PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >::PerturbedStateProblem(), PseudoSolidCapProblem< ELEMENT >::PseudoSolidCapProblem(), RefineableFishPoissonProblem< ELEMENT >::RefineableFishPoissonProblem(), RefineableRotatingCylinderProblem< ELEMENT >::RefineableRotatingCylinderProblem(), RefineableTwoMeshFluxPoissonProblem< ELEMENT >::RefineableTwoMeshFluxPoissonProblem(), RefineableUnsteadyHeatProblem< ELEMENT >::RefineableUnsteadyHeatProblem(), SolidFreeSurfaceRotationProblem< ELEMENT >::SolidFreeSurfaceRotationProblem(), SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >::SurfactantProblem(), TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >::TurekProblem(), TwoMeshFluxAdvectionDiffusionProblem< ELEMENT >::TwoMeshFluxAdvectionDiffusionProblem(), TwoMeshFluxPoissonProblem< ELEMENT >::TwoMeshFluxPoissonProblem(), UnsteadyHeatProblem< ELEMENT >::UnsteadyHeatProblem(), UnstructuredFvKProblem< ELEMENT >::UnstructuredFvKProblem(), and UnstructuredSolidProblem< ELEMENT, MESH >::UnstructuredSolidProblem().

◆ calculate_continuation_derivatives() [1/2]

void Problem::calculate_continuation_derivatives ( const DoubleVector z)
protected

A function to calculate the derivatives with respect to the arc-length required for continuation. The arguments is the solution of the linear system, Jz = dR/dparameter, that gives du/dparameter and the direction output from the newton_solve_continuation function. The derivatives are stored in the ContinuationParameters namespace.

9793  {
9794  // Calculate the continuation derivatives
9796 
9797  // Scale the value of theta if the control flag is set
9798  if (Scale_arc_length)
9799  {
9800  // Don't divide by zero!
9801  if (Parameter_derivative != 1.0)
9802  {
9807 
9808  // Recalculate the continuation derivatives with the new scaled values
9810  }
9811  }
9812  }
void calculate_continuation_derivatives_helper(const DoubleVector &z)
Definition: problem.cc:9912

References calculate_continuation_derivatives_helper(), Desired_proportion_of_arc_length, Parameter_derivative, Scale_arc_length, and Theta_squared.

◆ calculate_continuation_derivatives() [2/2]

void Problem::calculate_continuation_derivatives ( double *const &  parameter_pt)
protected

A function to calculate the derivatives wrt the arc-length. This version of the function actually does a linear solve so that the derivatives are calculated "exactly" rather than using the values at the Newton step just before convergence. This is necessary in spatially adaptive problems, in which the number of degrees of freedom changes and so the appropriate derivatives must be calculated for the new variables. This function is called if no Newton steps were taken in the continuation routine ... i.e. the initial residuals were sufficiently small.

A function to calculate the derivatives wrt the arc-length. This version of the function actually does a linear solve so that the derivatives are calculated "exactly" rather than using the values at the Newton step just before convergence. This is only necessary in spatially adaptive problems, in which the number of degrees of freedom changes and so the appropriate derivatives must be calculated for the new variables.

9716  {
9717  // Find the number of degrees of freedom in the problem
9718  const unsigned long n_dofs = ndof();
9719 
9720  // create a non-distributed z vector
9721  LinearAlgebraDistribution dist(Communicator_pt, n_dofs, false);
9722 
9723  // Assign memory for solutions of the equations
9724  DoubleVector z(&dist, 0.0);
9725 
9726  // If it's the block hopf solver need to solve for both RHS
9727  // at once, but this would all be alleviated if we have the solve
9728  // for the non-residuals RHS.
9729  if (dynamic_cast<BlockHopfLinearSolver*>(Linear_solver_pt))
9730  {
9731  // Get the vector dresiduals/dparameter
9732  get_derivative_wrt_global_parameter(parameter_pt, z);
9733 
9734  // Copy rhs vector into local storage so it doesn't get overwritten
9735  // if the linear solver decides to initialise the solution vector, say,
9736  // which it's quite entitled to do!
9737  DoubleVector dummy(&dist, 0.0), input_z(z);
9738 
9739  // Solve for the two RHSs
9740  dynamic_cast<BlockHopfLinearSolver*>(Linear_solver_pt)
9741  ->solve_for_two_rhs(this, dummy, input_z, z);
9742  }
9743  // Otherwise we can use the normal resolve
9744  else
9745  {
9746  // Save the status before entry to this routine
9747  bool enable_resolve = Linear_solver_pt->is_resolve_enabled();
9748 
9749  // We need to do resolves
9751 
9752  // Solve the standard problem, we only want to make sure that
9753  // we factorise the matrix, if it has not been factorised. We shall
9754  // ignore the return value of z.
9755  Linear_solver_pt->solve(this, z);
9756 
9757  // Get the vector dresiduals/dparameter
9758  get_derivative_wrt_global_parameter(parameter_pt, z);
9759 
9760 
9761  // Copy rhs vector into local storage so it doesn't get overwritten
9762  // if the linear solver decides to initialise the solution vector, say,
9763  // which it's quite entitled to do!
9764  DoubleVector input_z(z);
9765 
9766  // Now resolve the system with the new RHS and overwrite the solution
9767  Linear_solver_pt->resolve(input_z, z);
9768 
9769  // Restore the storage status of the linear solver
9770  if (enable_resolve)
9771  {
9773  }
9774  else
9775  {
9777  }
9778  }
9779 
9780  // Now, we can calculate the derivatives, etc
9782  }
virtual void solve(Problem *const &problem_pt, DoubleVector &result)=0
virtual void enable_resolve()
Definition: linear_solver.h:135
virtual void resolve(const DoubleVector &rhs, DoubleVector &result)
Definition: linear_solver.h:225
virtual void disable_resolve()
Definition: linear_solver.h:144
bool is_resolve_enabled() const
Boolean flag indicating if resolves are enabled.
Definition: linear_solver.h:128
void get_derivative_wrt_global_parameter(double *const &parameter_pt, DoubleVector &result)
Definition: problem.cc:7887

References Communicator_pt, oomph::LinearSolver::disable_resolve(), oomph::LinearSolver::enable_resolve(), get_derivative_wrt_global_parameter(), oomph::LinearSolver::is_resolve_enabled(), Linear_solver_pt, ndof(), oomph::LinearSolver::resolve(), and oomph::LinearSolver::solve().

Referenced by arc_length_step_solve_helper().

◆ calculate_continuation_derivatives_fd()

void Problem::calculate_continuation_derivatives_fd ( double *const &  parameter_pt)
protected

A function to calculate the derivatives with respect to the arc-length required for continuation by finite differences, using the previous values of the solution. The derivatives are stored in the ContinuationParameters namespace.

A function to calculate the derivatives with respect to the arc-length required for continuation using finite differences.

9820  {
9821  // Calculate the continuation derivatives
9823 
9824  // Scale the value of theta if the control flag is set
9825  if (Scale_arc_length)
9826  {
9827  // Don't divide by zero!
9828  if (Parameter_derivative != 1.0)
9829  {
9834 
9835  // Recalculate the continuation derivatives with the new scaled values
9837  }
9838  }
9839  }
void calculate_continuation_derivatives_fd_helper(double *const &parameter_pt)
Definition: problem.cc:10004

References calculate_continuation_derivatives_fd_helper(), Desired_proportion_of_arc_length, Parameter_derivative, Scale_arc_length, and Theta_squared.

Referenced by arc_length_step_solve_helper().

◆ calculate_continuation_derivatives_fd_helper()

void Problem::calculate_continuation_derivatives_fd_helper ( double *const &  parameter_pt)
private

A function that performs the guts of the continuation derivative calculation in arc-length continuation problems using finite differences

A private helper function to calculate the derivatives with respect to the arc-length required for continuation using finite differences.

10006  {
10007  // Find the number of values
10008  // const unsigned long n_dofs = this->ndof();
10009  // Find the number of local dofs in the problem
10010  const unsigned long ndof_local = Dof_distribution_pt->nrow_local();
10011 
10012  // Temporary storage for the finite-difference approximation to the helper
10013  Vector<double> z(ndof_local);
10014  double length = 0.0;
10015  // Calculate the change in values and contribution to total length
10016  for (unsigned long l = 0; l < ndof_local; l++)
10017  {
10018  z[l] = (*Dof_pt[l] - Dof_current[l]) / Ds_current;
10019  length += Theta_squared * z[l] * z[l];
10020  }
10021 
10022  // Reduce if parallel
10023 #ifdef OOMPH_HAS_MPI
10024  double length2 = length;
10025  if ((Dof_distribution_pt->distributed()) &&
10027  {
10028  MPI_Allreduce(&length,
10029  &length2,
10030  1,
10031  MPI_DOUBLE,
10032  MPI_SUM,
10033  Dof_distribution_pt->communicator_pt()->mpi_comm());
10034  }
10035  length = length2;
10036 #endif
10037 
10038  // Calculate change in parameter
10039  double Z = (*parameter_pt - Parameter_current) / Ds_current;
10040  length += Z * Z;
10041 
10042  // Scale the approximations to the derivatives
10043  length = sqrt(length);
10044  for (unsigned long l = 0; l < ndof_local; l++)
10045  {
10046  dof_derivative(l) = z[l] / length;
10047  }
10048  Parameter_derivative = Z / length;
10049  }
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
bool distributed() const
Definition: linear_algebra_distribution.h:329
OomphCommunicator * communicator_pt() const
const access to the communicator pointer
Definition: linear_algebra_distribution.h:335
#define Z
Definition: icosphere.cpp:21

References oomph::LinearAlgebraDistribution::communicator_pt(), oomph::LinearAlgebraDistribution::distributed(), Dof_current, dof_derivative(), Dof_distribution_pt, Dof_pt, Ds_current, oomph::OomphCommunicator::nproc(), oomph::LinearAlgebraDistribution::nrow_local(), Parameter_current, Parameter_derivative, sqrt(), Theta_squared, and Z.

Referenced by calculate_continuation_derivatives_fd().

◆ calculate_continuation_derivatives_helper()

void Problem::calculate_continuation_derivatives_helper ( const DoubleVector z)
private

A function that performs the guts of the continuation derivative calculation in arc length continuation problems.

A private helper function to calculate the derivatives with respect to the arc-length required for continuation. The arguments is the solution of the linear system, Jz = dR/dparameter, that gives du/dparameter and the direction output from the newton_solve_continuation function. The derivatives are stored in the ContinuationParameters namespace.

9913  {
9914  // Find the number of degrees of freedom in the problem
9915  // unsigned long n_dofs = ndof();
9916  // Find the number of local dofs in the problem
9917  const unsigned long ndof_local = Dof_distribution_pt->nrow_local();
9918 
9919  // Work out the continuation direction
9920  // The idea is that (du/ds)_{old} . (du/ds)_{new} >= 0
9921  // if the direction is to remain the same.
9922  // du/ds_{new} = [dlambda/ds; du/ds] = [dlambda/ds ; - dlambda/ds z]
9923  // so (du/ds)_{new} . (du/ds)_{old}
9924  // = dlambda/ds [1 ; - z] . [ Parameter_derivative ; Dof_derivatives]
9925  // = dlambda/ds (Parameter_derivative - Dof_derivative . z)
9926 
9927  // Create a local copy of z that can be redistributed without breaking
9928  // the constness of z
9929  DoubleVector local_z(z);
9930 
9931  // Redistribute z so that it has the (natural) dof distribution
9932  local_z.redistribute(Dof_distribution_pt);
9933 
9934  // Calculate the local contribution to the Continuation direction
9935  Continuation_direction = 0.0;
9936  // Cache the pointer to z
9937  double* const local_z_pt = local_z.values_pt();
9938  for (unsigned long l = 0; l < ndof_local; l++)
9939  {
9940  Continuation_direction -= dof_derivative(l) * local_z_pt[l];
9941  }
9942 
9943  // Now reduce if we have been distributed
9944 #ifdef OOMPH_HAS_MPI
9945  double cont_dir2 = Continuation_direction;
9946  if ((Dof_distribution_pt->distributed()) &&
9948  {
9949  MPI_Allreduce(&Continuation_direction,
9950  &cont_dir2,
9951  1,
9952  MPI_DOUBLE,
9953  MPI_SUM,
9954  Dof_distribution_pt->communicator_pt()->mpi_comm());
9955  }
9956  Continuation_direction = cont_dir2;
9957 #endif
9958 
9959  // Add parameter derivative
9961 
9962  // Calculate the magnitude of the du/ds Vector
9963 
9964  // Note that actually, we are usually approximating by using the value at
9965  // newton step just before convergence, which saves one additional
9966  // Newton solve.
9967 
9968  // First calculate the magnitude of du/dparameter, chi
9969  double chi = local_z.dot(local_z);
9970 
9971  // Calculate the current derivative of the parameter wrt the arc-length
9972  Parameter_derivative = 1.0 / sqrt(1.0 + Theta_squared * chi);
9973 
9974  // If the dot product of the current derivative wrt the Direction
9975  // is less than zero, switch the sign of the derivative to ensure
9976  // smooth continuation
9978  {
9979  Parameter_derivative *= -1.0;
9980  }
9981 
9982  // Resize the derivatives array, if necessary
9984  {
9985  if (Dof_derivative.size() != ndof_local)
9986  {
9987  Dof_derivative.resize(ndof_local, 0.0);
9988  }
9989  }
9990  // Calculate the new derivatives wrt the arc-length
9991  for (unsigned long l = 0; l < ndof_local; l++)
9992  {
9993  // This comes from the formulation J u_dot + dr/dlambda lambda_dot = 0
9994  // on the curve and then it follows that.
9995  dof_derivative(l) = -Parameter_derivative * local_z_pt[l];
9996  }
9997  }

References oomph::LinearAlgebraDistribution::communicator_pt(), Continuation_direction, oomph::LinearAlgebraDistribution::distributed(), Dof_derivative, dof_derivative(), Dof_distribution_pt, oomph::DoubleVector::dot(), oomph::OomphCommunicator::nproc(), oomph::LinearAlgebraDistribution::nrow_local(), Parameter_derivative, oomph::DoubleVector::redistribute(), sqrt(), Theta_squared, Use_continuation_timestepper, and oomph::DoubleVector::values_pt().

Referenced by calculate_continuation_derivatives().

◆ calculate_predictions()

void Problem::calculate_predictions ( )

Calculate predictions.

Calculate the predictions of all variables in problem.

11657  {
11658 // Check that if we have multiple time steppers none of them want to
11659 // predict by calling an explicit timestepper (as opposed to doing
11660 // something like an explicit step by combining known history values, as
11661 // done in BDF).
11662 #ifdef PARANOID
11663  if (Time_stepper_pt.size() != 1)
11664  {
11665  for (unsigned j = 0; j < Time_stepper_pt.size(); j++)
11666  {
11667  if (time_stepper_pt()->predict_by_explicit_step())
11668  {
11669  std::string err = "Prediction by explicit step only works for "
11670  "problems with a simple time";
11671  err += "stepper. I think implementing anything more general will";
11672  err += "require a rewrite of explicit time steppers. - David";
11673  throw OomphLibError(
11675  }
11676  }
11677  }
11678 #endif
11679 
11680 
11681  // Predict using an explicit timestepper (don't do it if adaptive = false
11682  // because pointers probably aren't set up).
11683  if (time_stepper_pt()->predict_by_explicit_step() &&
11684  time_stepper_pt()->adaptive_flag())
11685  {
11686  // Copy the time stepper's predictor pt into problem's explicit time
11687  // stepper pt (unless problem already has its own explicit time
11688  // stepper).
11689  ExplicitTimeStepper* ets_pt = time_stepper_pt()->explicit_predictor_pt();
11690 #ifdef PARANOID
11691  if (ets_pt == 0)
11692  {
11693  std::string err = "Requested predictions by explicit step but explicit";
11694  err += " predictor pt is null.";
11695  throw OomphLibError(
11697  }
11698 
11699  if ((explicit_time_stepper_pt() != ets_pt) &&
11700  (explicit_time_stepper_pt() != 0))
11701  {
11702  throw OomphLibError("Problem has explicit time stepper other than "
11703  "predictor, not sure how to handle this yet ??ds",
11706  }
11707 #endif
11708  explicit_time_stepper_pt() = ets_pt;
11709 
11710  // Backup dofs and time
11712 
11713 #ifdef PARANOID
11714  double backup_time = time();
11715 #endif
11716 
11717  // Move time back so that we are at the start of the timestep (as
11718  // explicit_timestep functions expect). This is needed because the
11719  // predictor calculations are done after unsteady newton solve has
11720  // started, and it has already moved time forwards.
11721  double dt = time_pt()->dt();
11722  time() -= dt;
11723 
11724  // Explicit step
11725  this->explicit_timestep(dt, false);
11726 
11727  // Copy predicted dofs and time to their storage slots.
11728  set_dofs(time_stepper_pt()->predictor_storage_index(), Dof_pt);
11730 
11731  // Check we got the times right
11732 #ifdef PARANOID
11733  if (std::abs(time() - backup_time) > 1e-12)
11734  {
11735  using namespace StringConversion;
11736  std::string err = "Predictor landed at the wrong time!";
11737  err += " Expected time " + to_string(backup_time, 14) + " but got ";
11738  err += to_string(time(), 14);
11739  throw OomphLibError(
11741  }
11742 #endif
11743 
11744  // Restore dofs and time
11746  }
11747 
11748  // Otherwise we can do predictions in a more object oriented way using
11749  // whatever timestepper the data provides (this is the normal case).
11750  else
11751  {
11752  // Calculate all predictions in the "master" mesh
11754 
11755  // Calculate predictions for global data with their own timesteppers
11756  unsigned Nglobal = Global_data_pt.size();
11757  for (unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
11758  {
11759  Global_data_pt[iglobal]->time_stepper_pt()->calculate_predicted_values(
11760  Global_data_pt[iglobal]);
11761  }
11762  }
11763 
11764  // If requested then copy the predicted value into the current time data
11765  // slots, ready for the newton solver to use as an initial guess.
11767  {
11768  // Not sure I know enough about distributed problems to implement
11769  // this. Probably you just need to loop over ndof_local or something,
11770  // but I can't really test it...
11771 #ifdef OOMPH_HAS_MPI
11772  if (distributed())
11773  {
11774  throw OomphLibError("Not yet implemented for distributed problems",
11777  }
11778 #endif
11779 
11780  // With multiple time steppers this is much more complex becuase you
11781  // need to check the time stepper for each data to get the
11782  // predictor_storage_index(). Do-able if you need it though.
11783  if (Time_stepper_pt.size() != 1)
11784  {
11785  std::string err = "Not implemented for multiple time steppers";
11786  throw OomphLibError(
11788  }
11789 
11790  // Get predicted values
11791  DoubleVector predicted_dofs;
11792  get_dofs(time_stepper_pt()->predictor_storage_index(), predicted_dofs);
11793 
11794  // Update dofs at current step
11795  for (unsigned i = 0; i < ndof(); i++)
11796  {
11797  dof(i) = predicted_dofs[i];
11798  }
11799  }
11800  }
void calculate_predictions()
Definition: mesh.cc:2366
void set_dofs(const DoubleVector &dofs)
Set the values of the dofs.
Definition: problem.cc:3411
void get_dofs(DoubleVector &dofs) const
Definition: problem.cc:2479
void explicit_timestep(const double &dt, const bool &shift_values=true)
Take an explicit timestep of size dt.
Definition: problem.cc:10918
void restore_dof_values()
Restore the stored values of the degrees of freedom.
Definition: problem.cc:8653
bool & use_predictor_values_as_initial_guess()
Definition: problem.h:1994
ExplicitTimeStepper *& explicit_time_stepper_pt()
Return a pointer to the explicit timestepper.
Definition: problem.h:1555
void store_current_dof_values()
Store the current values of the degrees of freedom.
Definition: problem.cc:8607
bool distributed() const
Definition: problem.h:808
double & time()
Return the current value of continuous time.
Definition: problem.cc:11531
ExplicitTimeStepper * explicit_predictor_pt()
Definition: timesteppers.h:403
void update_predicted_time(const double &new_time)
Definition: timesteppers.h:417
std::string to_string(T object, unsigned float_precision=8)
Definition: oomph_utilities.h:189
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2

References abs(), oomph::Mesh::calculate_predictions(), distributed(), dof(), Dof_pt, oomph::Time::dt(), e(), oomph::TimeStepper::explicit_predictor_pt(), explicit_time_stepper_pt(), explicit_timestep(), get_dofs(), Global_data_pt, i, j, Mesh_pt, ndof(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, restore_dof_values(), set_dofs(), store_current_dof_values(), oomph::Global_string_for_annotation::string(), time(), time_pt(), Time_stepper_pt, time_stepper_pt(), oomph::StringConversion::to_string(), oomph::TimeStepper::update_predicted_time(), and use_predictor_values_as_initial_guess().

Referenced by adaptive_unsteady_newton_solve().

◆ communicator_pt() [1/2]

OomphCommunicator* oomph::Problem::communicator_pt ( )
inline

access function to the oomph-lib communicator

1247  {
1248  return Communicator_pt;
1249  }

References Communicator_pt.

Referenced by oomph::PeriodicOrbitAssemblyHandler< NNODE_1D >::adapt_temporal_mesh(), arc_length_step_solve_helper(), assign_eqn_numbers(), oomph::Multi_domain_functions::aux_setup_multi_domain_interaction(), doubly_adaptive_unsteady_newton_solve_helper(), dump(), oomph::FoldHandler::FoldHandler(), oomph::Multi_domain_functions::get_dim_helper(), oomph::FoldHandler::get_eigenfunction(), oomph::HopfHandler::get_eigenfunction(), get_hessian_vector_products(), get_inverse_mass_matrix_times_residuals(), get_jacobian(), get_residuals(), oomph::HopfHandler::HopfHandler(), newton_solve(), parallel_test(), oomph::PitchForkHandler::PitchForkHandler(), read(), oomph::BlockPitchForkLinearSolver::resolve(), oomph::AugmentedBlockPitchForkLinearSolver::resolve(), oomph::SolidICProblem::set_static_initial_condition(), setup_element_count_per_dof(), oomph::AugmentedBlockFoldLinearSolver::solve(), oomph::BlockPitchForkLinearSolver::solve(), oomph::AugmentedBlockPitchForkLinearSolver::solve(), oomph::BlockHopfLinearSolver::solve(), oomph::HSL_MA42::solve(), oomph::GS< MATRIX >::solve(), oomph::GS< CRDoubleMatrix >::solve(), oomph::DampedJacobi< MATRIX >::solve(), oomph::GMRES< MATRIX >::solve(), oomph::AugmentedProblemGMRES::solve(), oomph::SuperLUSolver::solve(), oomph::MumpsSolver::solve(), oomph::HelmholtzGMRESMG< MATRIX >::solve(), oomph::HelmholtzFGMRESMG< MATRIX >::solve(), oomph::FoldHandler::solve_augmented_block_system(), oomph::PitchForkHandler::solve_augmented_block_system(), oomph::FoldHandler::solve_block_system(), oomph::HopfHandler::solve_complex_system(), oomph::ARPACK::solve_eigenproblem(), oomph::LAPACK_QZ::solve_eigenproblem(), oomph::BlockHopfLinearSolver::solve_for_two_rhs(), oomph::FoldHandler::solve_full_system(), oomph::PitchForkHandler::solve_full_system(), oomph::HopfHandler::solve_full_system(), oomph::HopfHandler::solve_standard_system(), oomph::SuperLUSolver::solve_transpose(), unsteady_newton_solve(), oomph::FoldHandler::~FoldHandler(), and oomph::HopfHandler::~HopfHandler().

◆ communicator_pt() [2/2]

const OomphCommunicator* oomph::Problem::communicator_pt ( ) const
inline

access function to the oomph-lib communicator, const version

1253  {
1254  return Communicator_pt;
1255  }

References Communicator_pt.

◆ copy()

void Problem::copy ( Problem orig_problem_pt)

Copy Data values, nodal positions etc from specified problem. Note: This is not a copy constructor. We assume that the current and the "original" problem have both been created by calling the same problem constructor so that all Data objects, time steppers etc. in the two problems are completely independent. This function copies the nodal, internal and global values, and the time parameters from the original problem into "this" one. This functionality is required, e.g. for multigrid computations.

Copy Data values, nodal positions etc from specified problem. Note: This is not a copy constructor. We assume that the current and the "original" problem have both been created by calling the same problem constructor so that all Data objects, time steppers etc. in the two problems are completely independent. This function copies the nodal, internal and global values and the time parameters from the original problem into "this" one. This functionality is required, e.g. for multigrid computations.

11866  {
11867  // Copy time
11868  //----------
11869 
11870  // Flag to indicate that orig problem is unsteady problem
11871  bool unsteady_flag = (orig_problem_pt->time_pt() != 0);
11872 
11873  // Copy current time and previous time increments for proper unsteady run
11874  if (unsteady_flag)
11875  {
11876  oomph_info << "Copying an unsteady problem." << std::endl;
11877  // Current time
11878  this->time_pt()->time() = orig_problem_pt->time_pt()->time();
11879  // Timesteps
11880  unsigned n_dt = orig_problem_pt->time_pt()->ndt();
11881  time_pt()->resize(n_dt);
11882  for (unsigned i = 0; i < n_dt; i++)
11883  {
11884  time_pt()->dt(i) = orig_problem_pt->time_pt()->dt(i);
11885  }
11886 
11887  // Find out how many timesteppers there are
11888  unsigned n_time_steppers = ntime_stepper();
11889 
11890  // Loop over them all and set the weights
11891  for (unsigned i = 0; i < n_time_steppers; i++)
11892  {
11894  }
11895  }
11896 
11897  // Copy nodes
11898  //-----------
11899 
11900  // Loop over submeshes:
11901  unsigned nmesh = nsub_mesh();
11902  if (nmesh == 0) nmesh = 1;
11903  for (unsigned m = 0; m < nmesh; m++)
11904  {
11905  // Find number of nodes in present mesh
11906  unsigned long n_node = mesh_pt(m)->nnode();
11907 
11908  // Check # of nodes:
11909  unsigned long n_node_orig = orig_problem_pt->mesh_pt(m)->nnode();
11910  if (n_node != n_node_orig)
11911  {
11912  std::ostringstream error_message;
11913  error_message << "Number of nodes in copy " << n_node
11914  << " not equal to the number in the original "
11915  << n_node_orig << std::endl;
11916 
11917  throw OomphLibError(error_message.str(),
11920  }
11921 
11922  // Loop over the nodes
11923  for (unsigned long i = 0; i < n_node; i++)
11924  {
11925  // Try to cast to elastic node
11926  SolidNode* el_node_pt =
11927  dynamic_cast<SolidNode*>(mesh_pt(m)->node_pt(i));
11928  if (el_node_pt != 0)
11929  {
11930  SolidNode* el_node_orig_pt =
11931  dynamic_cast<SolidNode*>(orig_problem_pt->mesh_pt(m)->node_pt(i));
11932  el_node_pt->copy(el_node_orig_pt);
11933  }
11934  else
11935  {
11936  mesh_pt(m)->node_pt(i)->copy(orig_problem_pt->mesh_pt(m)->node_pt(i));
11937  }
11938  }
11939  }
11940 
11941 
11942  // Copy global data:
11943  //------------------
11944 
11945  // Number of global data
11946  unsigned n_global = Global_data_pt.size();
11947 
11948  // Check # of nodes in orig problem
11949  unsigned long n_global_orig = orig_problem_pt->nglobal_data();
11950  if (n_global != n_global_orig)
11951  {
11952  std::ostringstream error_message;
11953  error_message << "Number of global data in copy " << n_global
11954  << " not equal to the number in the original "
11955  << n_global_orig << std::endl;
11956 
11957  throw OomphLibError(
11958  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
11959  }
11960 
11961  for (unsigned iglobal = 0; iglobal < n_global; iglobal++)
11962  {
11963  Global_data_pt[iglobal]->copy(orig_problem_pt->global_data_pt(iglobal));
11964  }
11965 
11966 
11967  // Copy internal data of elements:
11968  //--------------------------------
11969 
11970  // Loop over submeshes:
11971  for (unsigned m = 0; m < nmesh; m++)
11972  {
11973  // Loop over elements and deal with internal data
11974  unsigned n_element = mesh_pt(m)->nelement();
11975  for (unsigned e = 0; e < n_element; e++)
11976  {
11977  GeneralisedElement* el_pt = mesh_pt(m)->element_pt(e);
11978  unsigned n_internal = el_pt->ninternal_data();
11979  if (n_internal > 0)
11980  {
11981  // Check # of internals :
11982  unsigned long n_internal_orig =
11983  orig_problem_pt->mesh_pt(m)->element_pt(e)->ninternal_data();
11984  if (n_internal != n_internal_orig)
11985  {
11986  std::ostringstream error_message;
11987  error_message << "Number of internal data in copy " << n_internal
11988  << " not equal to the number in the original "
11989  << n_internal_orig << std::endl;
11990 
11991  throw OomphLibError(error_message.str(),
11994  }
11995  for (unsigned i = 0; i < n_internal; i++)
11996  {
11997  el_pt->internal_data_pt(i)->copy(
11998  orig_problem_pt->mesh_pt(m)->element_pt(e)->internal_data_pt(i));
11999  }
12000  }
12001  }
12002  }
12003  }
unsigned ninternal_data() const
Return the number of internal data objects.
Definition: elements.h:823
unsigned long nnode() const
Return number of nodes in the mesh.
Definition: mesh.h:596
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
Definition: mesh.h:436
void copy(Node *orig_node_pt)
Copy all nodal data from specified Node object.
Definition: nodes.cc:1916

References oomph::Data::copy(), oomph::Node::copy(), oomph::SolidNode::copy(), oomph::Time::dt(), e(), oomph::Mesh::element_pt(), Global_data_pt, global_data_pt(), i, oomph::GeneralisedElement::internal_data_pt(), m, mesh_pt(), oomph::Time::ndt(), oomph::Mesh::nelement(), nglobal_data(), oomph::GeneralisedElement::ninternal_data(), oomph::Mesh::nnode(), oomph::Mesh::node_pt(), nsub_mesh(), ntime_stepper(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, oomph::Time::resize(), oomph::TimeStepper::set_weights(), oomph::Time::time(), time_pt(), and time_stepper_pt().

◆ deactivate_bifurcation_tracking()

void oomph::Problem::deactivate_bifurcation_tracking ( )
inline

Deactivate all bifuraction tracking, by reseting the assembly handler to the default

2354  {
2356  }

References reset_assembly_handler_to_default().

Referenced by bifurcation_adapt_helper().

◆ debug_hook_fct()

virtual void oomph::Problem::debug_hook_fct ( const unsigned i)
inlinevirtual

Hook for debugging. Can be overloaded in driver code; argument allows identification of where we're coming from

250  {
251  oomph_info << "Called empty hook fct with i=" << i << std::endl;
252  }

References i, and oomph::oomph_info.

◆ delete_all_external_storage()

void Problem::delete_all_external_storage ( )

Wrapper function to delete external storage for each submesh of the problem

Delete any external storage for any submeshes NB this would ordinarily take place within the adaptation procedure for each submesh (See RefineableMesh::adapt_mesh(...)), but there are instances where the actions_before/after_adapt routines are used and no adaptive routines are called in between (e.g. when doc-ing errors at the end of an adaptive newton solver)

16356  {
16357  // Number of submeshes
16358  unsigned n_mesh = nsub_mesh();
16359 
16360  // External storage will only exist if there is more than one (sub)mesh
16361  if (n_mesh > 1)
16362  {
16363  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
16364  {
16366  }
16367  }
16368  }
void delete_all_external_storage()
Wipe the storage for all externally-based elements.
Definition: mesh.cc:9190

References oomph::Mesh::delete_all_external_storage(), mesh_pt(), and nsub_mesh().

◆ describe_dofs()

void Problem::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 value of a Node; value in a Data object; value of internal Data in an element; etc) is the unknown with a certain global equation number. Output stream defaults to oomph_info.

2360  {
2361  // Check that the global mesh has been build
2362 #ifdef PARANOID
2363  if (Mesh_pt == 0)
2364  {
2365  std::ostringstream error_stream;
2366  error_stream
2367  << "Global mesh does not exist, so equation numbers cannot be found.\n";
2368  // Check for sub meshes
2369  if (nsub_mesh() == 0)
2370  {
2371  error_stream << "There aren't even any sub-meshes in the Problem.\n"
2372  << "You can set the global mesh directly by using\n"
2373  << "Problem::mesh_pt() = my_mesh_pt;\n"
2374  << "OR you can use Problem::add_sub_mesh(mesh_pt); "
2375  << "to add a sub mesh.\n";
2376  }
2377  else
2378  {
2379  error_stream << "There are " << nsub_mesh() << " sub-meshes.\n";
2380  }
2381  error_stream << "You need to call Problem::build_global_mesh() to create "
2382  "a global mesh\n"
2383  << "from the sub-meshes.\n\n";
2384 
2385  throw OomphLibError(
2386  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2387  }
2388 #endif
2389 
2390  out
2391  << "Although this program will describe the degrees of freedom in the \n"
2392  << "problem, it will do so using the typedef for the elements. This is \n"
2393  << "not neccesarily human readable, but there is a solution.\n"
2394  << "Pipe your program's output through c++filt, with the argument -t.\n"
2395  << "e.g. \"./two_d_multi_poisson | c++filt -t > ReadableOutput.txt\".\n "
2396  << "(Disregarding the quotes)\n\n\n";
2397 
2398  out << "Classifying Global Equation Numbers" << std::endl;
2399  out << std::string(80, '-') << std::endl;
2400 
2401  // Number of submeshes
2402  unsigned n_sub_mesh = Sub_mesh_pt.size();
2403 
2404  // Classify Global dofs
2405  unsigned Nglobal_data = nglobal_data();
2406  for (unsigned i = 0; i < Nglobal_data; i++)
2407  {
2408  std::stringstream conversion;
2409  conversion << " in Global Data " << i << ".";
2410  std::string in(conversion.str());
2411  Global_data_pt[i]->describe_dofs(out, in);
2412  }
2413 
2414  // Put string in limiting scope.
2415  {
2416  // Descend into assignment for mesh.
2417  std::string in(" in Problem's Only Mesh.");
2418  Mesh_pt->describe_dofs(out, in);
2419  }
2420 
2421  // Deal with the spine meshes additional numbering:
2422  // If there is only one mesh:
2423  if (n_sub_mesh == 0)
2424  {
2425  if (SpineMesh* const spine_mesh_pt = dynamic_cast<SpineMesh*>(Mesh_pt))
2426  {
2427  std::string in(" in Problem's Only SpineMesh.");
2428  spine_mesh_pt->describe_spine_dofs(out, in);
2429  }
2430  }
2431  // Otherwise loop over the sub meshes
2432  else
2433  {
2434  // Assign global equation numbers first
2435  for (unsigned i = 0; i < n_sub_mesh; i++)
2436  {
2437  if (SpineMesh* const spine_mesh_pt =
2438  dynamic_cast<SpineMesh*>(Sub_mesh_pt[i]))
2439  {
2440  std::stringstream conversion;
2441  conversion << " in Sub-SpineMesh " << i << ".";
2442  std::string in(conversion.str());
2443  spine_mesh_pt->describe_spine_dofs(out, in);
2444  } // end if.
2445  } // end for.
2446  } // end else.
2447 
2448 
2449  out << std::string(80, '\\') << std::endl;
2450  out << std::string(80, '\\') << std::endl;
2451  out << std::string(80, '\\') << std::endl;
2452  out << "Classifying global eqn numbers in terms of elements." << std::endl;
2453  out << std::string(80, '-') << std::endl;
2454  out << "Eqns | Source" << std::endl;
2455  out << std::string(80, '-') << std::endl;
2456 
2457  if (n_sub_mesh == 0)
2458  {
2459  std::string in(" in Problem's Only Mesh.");
2461  }
2462  else
2463  {
2464  for (unsigned i = 0; i < n_sub_mesh; i++)
2465  {
2466  std::stringstream conversion;
2467  conversion << " in Sub-Mesh " << i << ".";
2468  std::string in(conversion.str());
2469  Sub_mesh_pt[i]->describe_local_dofs(out, in);
2470  } // End for
2471  } // End else
2472  } // End problem::describe_dofs(...)
void describe_local_dofs(std::ostream &out, const std::string &current_string) const
Definition: mesh.cc:746
void describe_dofs(std::ostream &out, const std::string &current_string) const
Definition: mesh.cc:711
std::ofstream out("Result.txt")

References oomph::Mesh::describe_dofs(), oomph::Mesh::describe_local_dofs(), Global_data_pt, i, Mesh_pt, nglobal_data(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, out(), oomph::Global_string_for_annotation::string(), and Sub_mesh_pt.

◆ disable_discontinuous_formulation()

void oomph::Problem::disable_discontinuous_formulation ( )
inline

Disable the use of a discontinuous-element formulation. Note that the methods will all still work even if the elements are discontinuous, we will just be assembling a larger system matrix than necessary.

1737  {
1739  }

References Discontinuous_element_formulation.

◆ disable_globally_convergent_newton_method()

void oomph::Problem::disable_globally_convergent_newton_method ( )
inline

disable globally convergent Newton method

2010  {
2012  }

References Use_globally_convergent_newton_method.

◆ disable_info_in_newton_solve()

void oomph::Problem::disable_info_in_newton_solve ( )
inline

Disable the output of information when in the newton solver.

2942  {
2943  Shut_up_in_newton_solve = true;
2944  }

References Shut_up_in_newton_solve.

Referenced by PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >::PerturbedStateProblem(), and oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::project().

◆ disable_jacobian_reuse()

void oomph::Problem::disable_jacobian_reuse ( )
inline

Disable recycling of Jacobian in Newton iteration.

1983  {
1984  Jacobian_reuse_is_enabled = false;
1986  }

References Jacobian_has_been_computed, and Jacobian_reuse_is_enabled.

◆ disable_mass_matrix_reuse()

void Problem::disable_mass_matrix_reuse ( )

Turn off recyling of the mass matrix in explicit timestepping schemes

Turn off the recyling of the mass matrix in explicit time-stepping schemes

11833  {
11836 
11837  // If we have a discontinuous formulation set the element-level
11838  // function
11840  {
11841  const unsigned n_element = Problem::mesh_pt()->nelement();
11842  // Loop over the other elements
11843  for (unsigned e = 0; e < n_element; e++)
11844  {
11845  // Cache the element
11846  DGElement* const elem_pt =
11847  dynamic_cast<DGElement*>(Problem::mesh_pt()->element_pt(e));
11848  elem_pt->disable_mass_matrix_reuse();
11849  }
11850  }
11851  }

References oomph::DGElement::disable_mass_matrix_reuse(), Discontinuous_element_formulation, e(), oomph::Mesh::element_pt(), Mass_matrix_has_been_computed, Mass_matrix_reuse_is_enabled, mesh_pt(), and oomph::Mesh::nelement().

◆ disable_store_local_dof_pt_in_elements()

void oomph::Problem::disable_store_local_dof_pt_in_elements ( )
inline

Insist that local dof pointers are NOT set up in each element when equation numbering takes place (the default)

1704  {
1706  }

References Store_local_dof_pt_in_elements.

◆ distributed()

bool oomph::Problem::distributed ( ) const
inline

If we have MPI return the "problem has been distributed" flag, otherwise it can't be distributed so return false.

809  {
810 #ifdef OOMPH_HAS_MPI
811  return Problem_has_been_distributed;
812 #else
813  return false;
814 #endif
815  }

Referenced by calculate_predictions(), get_dofs(), oomph::NavierStokesSchurComplementPreconditioner::get_pressure_advection_diffusion_matrix(), oomph::PitchForkHandler::PitchForkHandler(), oomph::BlockPitchForkLinearSolver::resolve(), set_dofs(), and oomph::BlockPitchForkLinearSolver::solve().

◆ doc_errors() [1/2]

void oomph::Problem::doc_errors ( )
inline

Get max and min error for all elements in submeshes.

2927  {
2928  DocInfo tmp_doc_info;
2929  tmp_doc_info.disable_doc();
2930  doc_errors(tmp_doc_info);
2931  }
void doc_errors()
Get max and min error for all elements in submeshes.
Definition: problem.h:2926

References oomph::DocInfo::disable_doc().

◆ doc_errors() [2/2]

void Problem::doc_errors ( DocInfo doc_info)

Get max and min error for all elements in submeshes.

14775  {
14776  // Get the bifurcation type
14777  int bifurcation_type = this->Assembly_handler_pt->bifurcation_type();
14778  // If we are tracking a bifurcation then call the bifurcation adapt function
14779  if (bifurcation_type != 0)
14780  {
14781  this->bifurcation_adapt_doc_errors(bifurcation_type);
14782  // Return immediately
14783  return;
14784  }
14785 
14786  // Number of submeshes?
14787  unsigned Nmesh = nsub_mesh();
14788 
14789  // Single mesh:
14790  //------------
14791  if (Nmesh == 0)
14792  {
14793  // Is the single mesh refineable?
14794  if (RefineableMeshBase* mmesh_pt =
14795  dynamic_cast<RefineableMeshBase*>(mesh_pt(0)))
14796  {
14797  // Get pointer to error estimator
14798  ErrorEstimator* error_estimator_pt =
14799  mmesh_pt->spatial_error_estimator_pt();
14800 
14801 #ifdef PARANOID
14802  if (error_estimator_pt == 0)
14803  {
14804  throw OomphLibError("Error estimator hasn't been set yet",
14807  }
14808 #endif
14809 
14810  // Get error for all elements
14811  Vector<double> elemental_error(mmesh_pt->nelement());
14812  if (!doc_info.is_doc_enabled())
14813  {
14814  error_estimator_pt->get_element_errors(mesh_pt(0), elemental_error);
14815  }
14816  else
14817  {
14818  error_estimator_pt->get_element_errors(
14819  mesh_pt(0), elemental_error, doc_info);
14820  }
14821 
14822  // Store max./min actual error
14823  mmesh_pt->max_error() = std::fabs(*std::max_element(
14824  elemental_error.begin(), elemental_error.end(), AbsCmp<double>()));
14825 
14826  mmesh_pt->min_error() = std::fabs(*std::min_element(
14827  elemental_error.begin(), elemental_error.end(), AbsCmp<double>()));
14828 
14829  oomph_info << "\n Max/min error: " << mmesh_pt->max_error() << " "
14830  << mmesh_pt->min_error() << std::endl;
14831  }
14832  }
14833 
14834  // Multiple submeshes
14835  //------------------
14836  else
14837  {
14838  // Loop over submeshes
14839  for (unsigned imesh = 0; imesh < Nmesh; imesh++)
14840  {
14841  // Is the single mesh refineable?
14842  if (RefineableMeshBase* mmesh_pt =
14843  dynamic_cast<RefineableMeshBase*>(mesh_pt(imesh)))
14844  {
14845  // Get pointer to error estimator
14846  ErrorEstimator* error_estimator_pt =
14847  mmesh_pt->spatial_error_estimator_pt();
14848 
14849 #ifdef PARANOID
14850  if (error_estimator_pt == 0)
14851  {
14852  throw OomphLibError("Error estimator hasn't been set yet",
14855  }
14856 #endif
14857 
14858  // Get error for all elements
14859  Vector<double> elemental_error(mmesh_pt->nelement());
14860  if (mmesh_pt->doc_info_pt() == 0)
14861  {
14862  error_estimator_pt->get_element_errors(mesh_pt(imesh),
14863  elemental_error);
14864  }
14865  else
14866  {
14867  error_estimator_pt->get_element_errors(
14868  mesh_pt(imesh), elemental_error, *mmesh_pt->doc_info_pt());
14869  }
14870 
14871  // Store max./min error if the mesh has any elements
14872  if (mesh_pt(imesh)->nelement() > 0)
14873  {
14874  mmesh_pt->max_error() =
14875  std::fabs(*std::max_element(elemental_error.begin(),
14876  elemental_error.end(),
14877  AbsCmp<double>()));
14878 
14879  mmesh_pt->min_error() =
14880  std::fabs(*std::min_element(elemental_error.begin(),
14881  elemental_error.end(),
14882  AbsCmp<double>()));
14883  }
14884 
14885  oomph_info << "\n Max/min error: " << mmesh_pt->max_error() << " "
14886  << mmesh_pt->min_error() << std::endl;
14887  }
14888 
14889  } // End of loop over submeshes
14890  }
14891  }
void bifurcation_adapt_doc_errors(const unsigned &bifurcation_type)
Definition: problem.cc:13648

References Assembly_handler_pt, bifurcation_adapt_doc_errors(), oomph::AssemblyHandler::bifurcation_type(), MeshRefinement::error_estimator_pt, boost::multiprecision::fabs(), oomph::DocInfo::is_doc_enabled(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and oomph::oomph_info.

◆ does_pointer_correspond_to_problem_data()

bool Problem::does_pointer_correspond_to_problem_data ( double *const &  parameter_pt)
protected

Return a boolean flag to indicate whether the pointer parameter_pt refers to values stored in a Data object that is contained within the problem

Function that returns a boolean flag to indicate whether the pointer parameter_pt refers to memory that is a value in a Data object used within the problem

9848  {
9849  // Firstly check the global data
9850  const unsigned n_global = Global_data_pt.size();
9851  for (unsigned i = 0; i < n_global; ++i)
9852  {
9853  // If we find it then return true
9854  if (Global_data_pt[i]->does_pointer_correspond_to_value(parameter_pt))
9855  {
9856  return true;
9857  }
9858  }
9859 
9860  // If we find the pointer in the mesh data return true
9861  if (Mesh_pt->does_pointer_correspond_to_mesh_data(parameter_pt))
9862  {
9863  return true;
9864  }
9865 
9866  // Loop over the submeshes to handle the case of spine data
9867  const unsigned n_sub_mesh = this->nsub_mesh();
9868  // If there is only one mesh
9869  if (n_sub_mesh == 0)
9870  {
9871  if (SpineMesh* const spine_mesh_pt = dynamic_cast<SpineMesh*>(Mesh_pt))
9872  {
9873  if (spine_mesh_pt->does_pointer_correspond_to_spine_data(parameter_pt))
9874  {
9875  return true;
9876  }
9877  }
9878  }
9879  // Otherwise loop over the sub meshes
9880  else
9881  {
9882  // Assign global equation numbers first
9883  for (unsigned i = 0; i < n_sub_mesh; i++)
9884  {
9885  if (SpineMesh* const spine_mesh_pt =
9886  dynamic_cast<SpineMesh*>(Sub_mesh_pt[i]))
9887  {
9888  if (spine_mesh_pt->does_pointer_correspond_to_spine_data(
9889  parameter_pt))
9890  {
9891  return true;
9892  }
9893  }
9894  }
9895  }
9896 
9897  // If we have got here then the data is not stored in the problem, so return
9898  // false
9899  return false;
9900  }
bool does_pointer_correspond_to_mesh_data(double *const &parameter_pt)
Does the double pointer correspond to any mesh data.
Definition: mesh.cc:2471

References oomph::Mesh::does_pointer_correspond_to_mesh_data(), Global_data_pt, i, Mesh_pt, nsub_mesh(), and Sub_mesh_pt.

Referenced by arc_length_step_solve().

◆ dof() [1/2]

◆ dof() [2/2]

double oomph::Problem::dof ( const unsigned i) const
inline

i-th dof in the problem (const version)

1820  {
1821  return *(Dof_pt[i]);
1822  }

References Dof_pt, and i.

◆ dof_current()

double& oomph::Problem::dof_current ( const unsigned i)
inlineprotected

Access function to the current value of the i-th (local) dof at the start of a continuation step

1183  {
1185  {
1186  return Dof_current[i];
1187  }
1188  else
1189  {
1190  return (*(Dof_pt[i] + Dof_current_offset));
1191  }
1192  }

References Dof_current, Dof_current_offset, Dof_pt, i, and Use_continuation_timestepper.

Referenced by adapt(), arc_length_step_solve_helper(), and newton_solve_continuation().

◆ dof_derivative()

double& oomph::Problem::dof_derivative ( const unsigned i)
inlineprotected

Access function to the derivative of the i-th (local) dof with respect to the arc length, used in continuation

1169  {
1171  {
1172  return Dof_derivative[i];
1173  }
1174  else
1175  {
1176  return (*(Dof_pt[i] + Dof_derivative_offset));
1177  }
1178  }

References Dof_derivative, Dof_derivative_offset, Dof_pt, i, and Use_continuation_timestepper.

Referenced by adapt(), arc_length_step_solve_helper(), calculate_continuation_derivatives_fd_helper(), calculate_continuation_derivatives_helper(), and newton_solve_continuation().

◆ dof_distribution_pt()

LinearAlgebraDistribution* const& oomph::Problem::dof_distribution_pt ( ) const
inline

Return the pointer to the dof distribution (read-only)

1669  {
1670  return Dof_distribution_pt;
1671  }

References Dof_distribution_pt.

Referenced by adaptive_unsteady_newton_solve(), oomph::ProblemBasedShiftInvertOperator::ProblemBasedShiftInvertOperator(), and oomph::ANASAZI::solve_eigenproblem().

◆ dof_pt() [1/2]

double*& oomph::Problem::dof_pt ( const unsigned i)
inline

Pointer to i-th dof in the problem.

1826  {
1827  return Dof_pt[i];
1828  }

References Dof_pt, and i.

Referenced by oomph::AssemblyHandler::local_problem_dof(), and set_dofs().

◆ dof_pt() [2/2]

double* oomph::Problem::dof_pt ( const unsigned i) const
inline

Pointer to i-th dof in the problem (const version)

1832  {
1833  return Dof_pt[i];
1834  }

References Dof_pt, and i.

◆ doubly_adaptive_unsteady_newton_solve() [1/2]

double oomph::Problem::doubly_adaptive_unsteady_newton_solve ( const double dt,
const double epsilon,
const unsigned max_adapt,
const bool first,
const bool shift = true 
)
inline

Unsteady "doubly" adaptive Newton solve: Does temporal adaptation first, i.e. we try to do a timestep with an increment of dt, and adjusting dt until the solution on the given mesh satisfies the temporal error measure with tolerance epsilon. Following this, we do up to max_adapt spatial adaptions (without re-examining the temporal error). If first==true, the initial conditions are re-assigned after the mesh adaptations. Shifting of time can be suppressed by overwriting the default value of shift (true). [Shifting must be done if first_timestep==true because we're constantly re-assigning the initial conditions; if first_timestep==true and shift==false shifting is performed anyway and a warning is issued.

2476  {
2477  // Call helper function with default setting (do re-solve after
2478  // spatial adaptation)
2479  unsigned suppress_resolve_after_spatial_adapt_flag = 0;
2481  dt,
2482  epsilon,
2483  max_adapt,
2484  suppress_resolve_after_spatial_adapt_flag,
2485  first,
2486  shift);
2487  }
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)
Definition: problem.cc:11379

References doubly_adaptive_unsteady_newton_solve_helper(), and oomph::SarahBL::epsilon.

◆ doubly_adaptive_unsteady_newton_solve() [2/2]

double oomph::Problem::doubly_adaptive_unsteady_newton_solve ( const double dt,
const double epsilon,
const unsigned max_adapt,
const unsigned suppress_resolve_after_spatial_adapt_flag,
const bool first,
const bool shift = true 
)
inline

Unsteady "doubly" adaptive Newton solve: Does temporal adaptation first, i.e. we try to do a timestep with an increment of dt, and adjusting dt until the solution on the given mesh satisfies the temporal error measure with tolerance epsilon. Following this, we do up to max_adapt spatial adaptions (without re-examining the temporal error). If first==true, the initial conditions are re-assigned after the mesh adaptations. Shifting of time can be suppressed by overwriting the default value of shift (true). [Shifting must be done if first_timestep==true because we're constantly re-assigning the initial conditions; if first_timestep==true and shift==false shifting is performed anyway and a warning is issued. Pseudo-Boolean flag suppress_resolve_after_spatial_adapt [0: false; 1: true] does what it says.]

2511  {
2512  // Call helper function
2514  dt,
2515  epsilon,
2516  max_adapt,
2517  suppress_resolve_after_spatial_adapt_flag,
2518  first,
2519  shift);
2520  }

References doubly_adaptive_unsteady_newton_solve_helper(), and oomph::SarahBL::epsilon.

◆ doubly_adaptive_unsteady_newton_solve_helper()

double Problem::doubly_adaptive_unsteady_newton_solve_helper ( const double dt_desired,
const double epsilon,
const unsigned max_adapt,
const unsigned suppress_resolve_after_spatial_adapt_flag,
const bool first,
const bool shift_values = true 
)
private

Private helper function that actually performs the unsteady "doubly" adaptive Newton solve. See actual (non-helper) functions for description of parameters.

Private helper function to perform unsteady "doubly" adaptive Newton solve: Does temporal adaptation first, i.e. we try to do a timestep with an increment of dt, and adjusting dt until the solution on the given mesh satisfies the temporal error measure with tolerance epsilon. Following this, we do up to max_adapt spatial adaptions (without re-examining the temporal error). If first==true, the initial conditions are re-assigned after the mesh adaptations. Shifting of time can be suppressed by overwriting the default value of shift (true). [Shifting must be done if first_timestep==true because we're constantly re-assigning the initial conditions; if first_timestep==true and shift==false shifting is performed anyway and a warning is issued. Pseudo-Boolean flag suppress_resolve_after_spatial_adapt [0: false; 1: true] does what it says.]

11386  {
11387  // Store the initial time
11388  double initial_time = time_pt()->time();
11389 
11390  // Take adaptive timestep, adjusting dt until tolerance is satisfied
11391  double new_dt =
11392  adaptive_unsteady_newton_solve(dt_desired, epsilon, shift_values);
11393  double dt_taken = time_pt()->dt();
11394  oomph_info << "Accepted solution taken with timestep: " << dt_taken
11395  << std::endl;
11396 
11397 
11398  // Bail out straightaway if no spatial adaptation allowed
11399  if (max_adapt == 0)
11400  {
11401  oomph_info << "No spatial refinement allowed; max_adapt=0\n";
11402  return new_dt;
11403  }
11404 
11405  // Adapt problem/mesh
11406  unsigned n_refined = 0;
11407  unsigned n_unrefined = 0;
11408  adapt(n_refined, n_unrefined);
11409 
11410  // Check if mesh has been adapted on other processors
11411  Vector<int> total_ref_count(2);
11412  total_ref_count[0] = n_refined;
11413  total_ref_count[1] = n_unrefined;
11414 
11415 
11416 #ifdef OOMPH_HAS_MPI
11417  if (Problem_has_been_distributed)
11418  {
11419  // Sum n_refine across all processors
11420  Vector<int> ref_count(2);
11421  ref_count[0] = n_refined;
11422  ref_count[1] = n_unrefined;
11423  MPI_Allreduce(&ref_count[0],
11424  &total_ref_count[0],
11425  2,
11426  MPI_INT,
11427  MPI_SUM,
11428  communicator_pt()->mpi_comm());
11429  }
11430 #endif
11431 
11432 
11433  // Re-solve the problem if the adaptation has changed anything
11434  if ((total_ref_count[0] != 0) || (total_ref_count[1] != 0))
11435  {
11436  if (suppress_resolve_after_spatial_adapt_flag == 1)
11437  {
11438  oomph_info << "Mesh was adapted but re-solve has been suppressed."
11439  << std::endl;
11440  }
11441  else
11442  {
11443  oomph_info
11444  << "Mesh was adapted --> we'll re-solve for current timestep."
11445  << std::endl;
11446 
11447  // Reset time to what it was when we entered here
11448  // because it will be incremented again by dt_taken.
11449  time_pt()->time() = initial_time;
11450 
11451  // Shift the timesteps? No! They've been shifted already when we
11452  // called the solve with pure temporal adaptivity...
11453  bool shift = false;
11454 
11455  // Reset the inital condition on refined meshes
11456  if (first)
11457  {
11458  // Reset default set_initial_condition has been called flag to false
11460 
11461  // Reset the initial conditions
11462  oomph_info << "Re-assigning initial condition at time="
11463  << time_pt()->time() << std::endl;
11465 
11466  // This is the first timestep so shifting
11467  // has to be done following the assignment of initial conditions,
11468  // providing the default set_initial_condition function has not
11469  // been called.
11470  // In fact, unsteady_newton_solve(...) does that automatically.
11471  // We're changing the flag here to avoid warning messages.
11473  {
11474  shift = true;
11475  }
11476  }
11477 
11478  // Now take the step again on the refined mesh, using the same
11479  // timestep as used before.
11480  unsteady_newton_solve(dt_taken, max_adapt, first, shift);
11481  }
11482  }
11483  else
11484  {
11485  oomph_info << "Mesh wasn't adapted --> we'll accept spatial refinement."
11486  << std::endl;
11487  }
11488 
11489  return new_dt;
11490  }
virtual void set_initial_condition()
Definition: problem.h:1198

References adapt(), adaptive_unsteady_newton_solve(), communicator_pt(), Default_set_initial_condition_called, oomph::Time::dt(), oomph::SarahBL::epsilon, oomph::oomph_info, set_initial_condition(), oomph::Time::time(), time_pt(), and unsteady_newton_solve().

Referenced by doubly_adaptive_unsteady_newton_solve().

◆ dump() [1/2]

void oomph::Problem::dump ( const std::string &  dump_file_name) const
inline

Dump refinement pattern of all refineable meshes and all generic Problem data to file for restart.

2079  {
2080  std::ofstream dump_stream(dump_file_name.c_str());
2081 #ifdef PARANOID
2082  if (!dump_stream.is_open())
2083  {
2084  std::string err = "Couldn't open file " + dump_file_name;
2085  throw OomphLibError(
2087  }
2088 #endif
2089  dump(dump_stream);
2090  }
virtual void dump(std::ofstream &dump_file) const
Definition: problem.cc:12029

References dump(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and oomph::Global_string_for_annotation::string().

◆ dump() [2/2]

void Problem::dump ( std::ofstream &  dump_file) const
virtual

Dump refinement pattern of all refineable meshes and all generic Problem data to file for restart.

Reimplemented in oomph::MyProblem, and AirwayReopeningProblem< ELEMENT >.

12030  {
12031  // Number of submeshes?
12032  unsigned n_mesh = nsub_mesh();
12033 
12034  dump_file << std::max(unsigned(1), n_mesh) << " # number of (sub)meshes "
12035  << std::endl;
12036 
12037  // Single mesh:
12038  //------------
12039  if (n_mesh == 0)
12040  {
12041  // Dump level of refinement before pruning
12042  if (TreeBasedRefineableMeshBase* mmesh_pt =
12043  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(0)))
12044  {
12045  dump_file << mmesh_pt->uniform_refinement_level_when_pruned()
12046  << " # uniform refinement when pruned " << std::endl;
12047  }
12048  else
12049  {
12050  dump_file << 0 << " # (fake) uniform refinement when pruned "
12051  << std::endl;
12052  }
12053  dump_file << 9999 << " # test flag for end of sub-meshes " << std::endl;
12054  }
12055 
12056  // Multiple submeshes
12057  //------------------
12058  else
12059  {
12060  // Loop over submeshes to dump level of refinement before pruning
12061  for (unsigned imesh = 0; imesh < n_mesh; imesh++)
12062  {
12063  if (TreeBasedRefineableMeshBase* mmesh_pt =
12064  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(imesh)))
12065  {
12066  dump_file << mmesh_pt->uniform_refinement_level_when_pruned()
12067  << " # uniform refinement when pruned " << std::endl;
12068  }
12069  else
12070  {
12071  dump_file << 0 << " # (fake) uniform refinement when pruned "
12072  << std::endl;
12073  }
12074  }
12075  dump_file << 9999 << " # test flag for end of sub-meshes " << std::endl;
12076  }
12077 
12078 #ifdef OOMPH_HAS_MPI
12079 
12080  const int my_rank = this->communicator_pt()->my_rank();
12081 
12082  // Record destination of all base elements
12083  unsigned n = Base_mesh_element_pt.size();
12084  Vector<int> local_base_element_processor(n, -1);
12085  Vector<int> base_element_processor(n, -1);
12086  for (unsigned e = 0; e < n; e++)
12087  {
12088  GeneralisedElement* el_pt = Base_mesh_element_pt[e];
12089  if (el_pt != 0)
12090  {
12091  if (!el_pt->is_halo())
12092  {
12093  local_base_element_processor[e] = my_rank;
12094  }
12095  }
12096  }
12097 
12098 
12099  // Get target for all base elements by reduction
12100  if (Problem_has_been_distributed)
12101  {
12102  // Check that the base elements have been associated to a processor
12103  // (the Base_mesh_elemen_pt is only used for structured meshes,
12104  // therefore, if there are no ustructured meshes as part of the
12105  // problem this container will be empty)
12106  if (n > 0)
12107  {
12108  MPI_Allreduce(&local_base_element_processor[0],
12109  &base_element_processor[0],
12110  n,
12111  MPI_INT,
12112  MPI_MAX,
12113  this->communicator_pt()->mpi_comm());
12114  }
12115  }
12116  else
12117  {
12118  // All the same...
12119  base_element_processor = local_base_element_processor;
12120  }
12121 
12122 
12123  dump_file << n << " # Number of base elements; partitioning follows.\n";
12124  for (unsigned e = 0; e < n; e++)
12125  {
12126  dump_file << base_element_processor[e] << "\n";
12127  }
12128  dump_file << "8888 #test flag for end of base element distribution\n";
12129 
12130 #endif
12131 
12132  // Single mesh:
12133  //------------
12134  if (n_mesh == 0)
12135  {
12136  // Dump single mesh refinement pattern (if mesh is refineable)
12137  if (TreeBasedRefineableMeshBase* mmesh_pt =
12138  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(0)))
12139  {
12140  mmesh_pt->dump_refinement(dump_file);
12141  }
12142 #ifdef OOMPH_HAS_TRIANGLE_LIB
12143  // Dump triangle mesh TriangulateIO which represents mesh topology
12144  TriangleMeshBase* mmesh_pt = dynamic_cast<TriangleMeshBase*>(mesh_pt(0));
12145  if (mmesh_pt != 0 && mmesh_pt->use_triangulateio_restart())
12146  {
12147 #ifdef OOMPH_HAS_MPI
12148  // Check if the mesh is distributed, if that is the case then
12149  // additional info. needs to be saved
12150  if (mmesh_pt->is_mesh_distributed())
12151  {
12152  // Dump the info. related with the distribution of the mesh
12153  mmesh_pt->dump_distributed_info_for_restart(dump_file);
12154  }
12155 #endif
12156  mmesh_pt->dump_triangulateio(dump_file);
12157  }
12158 #endif
12159  }
12160 
12161  // Multiple submeshes
12162  //------------------
12163  else
12164  {
12165  // Loop over submeshes
12166  for (unsigned imesh = 0; imesh < n_mesh; imesh++)
12167  {
12168  // Dump single mesh refinement pattern (if mesh is refineable)
12169  if (TreeBasedRefineableMeshBase* mmesh_pt =
12170  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(imesh)))
12171  {
12172  mmesh_pt->dump_refinement(dump_file);
12173  }
12174 #ifdef OOMPH_HAS_TRIANGLE_LIB
12175  // Dump triangle mesh TriangulateIO which represents mesh topology
12176  TriangleMeshBase* mmesh_pt =
12177  dynamic_cast<TriangleMeshBase*>(mesh_pt(imesh));
12178  if (mmesh_pt != 0 && mmesh_pt->use_triangulateio_restart())
12179  {
12180 #ifdef OOMPH_HAS_MPI
12181  // Check if the mesh is distributed, if that is the case then
12182  // additional info. needs to be saved
12183  if (mmesh_pt->is_mesh_distributed())
12184  {
12185  // Dump the info. related with the distribution of the mesh
12186  mmesh_pt->dump_distributed_info_for_restart(dump_file);
12187  }
12188 #endif
12189  mmesh_pt->dump_triangulateio(dump_file);
12190  }
12191 #endif
12192  } // End of loop over submeshes
12193  }
12194 
12195 
12196  // Dump time
12197  // ---------
12198 
12199  // Flag to indicate unsteady run
12200  bool unsteady_flag = (time_pt() != 0);
12201  dump_file << unsteady_flag << " # bool flag for unsteady" << std::endl;
12202 
12203  // Current time and previous time increments for proper unsteady run
12204  if (unsteady_flag)
12205  {
12206  // Current time
12207  dump_file << time_pt()->time() << " # Time " << std::endl;
12208  // Timesteps
12209  unsigned n_dt = time_pt()->ndt();
12210  dump_file << n_dt << " # Number of timesteps " << std::endl;
12211  for (unsigned i = 0; i < n_dt; i++)
12212  {
12213  dump_file << time_pt()->dt(i) << " # dt " << std::endl;
12214  }
12215  }
12216  // Dummy time and previous time increments for steady run
12217  else
12218  {
12219  // Current time
12220  dump_file << "0.0 # Dummy time from steady run " << std::endl;
12221  // Timesteps
12222  dump_file << "0 # Dummy number of timesteps from steady run" << std::endl;
12223  }
12224 
12225  // Loop over submeshes and dump their data
12226  unsigned nmesh = nsub_mesh();
12227  if (nmesh == 0) nmesh = 1;
12228  for (unsigned m = 0; m < nmesh; m++)
12229  {
12230  mesh_pt(m)->dump(dump_file);
12231  }
12232 
12233  // Dump global data
12234 
12235  // Loop over global data
12236  unsigned Nglobal = Global_data_pt.size();
12237  dump_file << Nglobal << " # number of global Data items " << std::endl;
12238  for (unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
12239  {
12240  Global_data_pt[iglobal]->dump(dump_file);
12241  dump_file << std::endl;
12242  }
12243  }
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.
Definition: mesh.cc:1088
int my_rank() const
my rank
Definition: communicator.h:176

References communicator_pt(), oomph::Time::dt(), oomph::Mesh::dump(), e(), Global_data_pt, i, oomph::Mesh::is_mesh_distributed(), m, max, mesh_pt(), oomph::OomphCommunicator::my_rank(), n, oomph::Time::ndt(), nsub_mesh(), oomph::Time::time(), and time_pt().

Referenced by dump(), and oomph::MyProblem::dump().

◆ eigen_solver_pt() [1/2]

EigenSolver*& oomph::Problem::eigen_solver_pt ( )
inline

Return a pointer to the eigen solver object.

1493  {
1494  return Eigen_solver_pt;
1495  }

References Eigen_solver_pt.

Referenced by FlowAroundCylinderProblem< ELEMENT >::FlowAroundCylinderProblem(), and OrrSommerfeldProblem< ELEMENT >::OrrSommerfeldProblem().

◆ eigen_solver_pt() [2/2]

EigenSolver* const& oomph::Problem::eigen_solver_pt ( ) const
inline

Return a pointer to the eigen solver object (const version)

1499  {
1500  return Eigen_solver_pt;
1501  }

References Eigen_solver_pt.

◆ enable_discontinuous_formulation()

void oomph::Problem::enable_discontinuous_formulation ( )
inline

Indicate that the problem involves discontinuous elements This allows for a more efficiently assembly and inversion of the mass matrix

1728  {
1730  }

References Discontinuous_element_formulation.

◆ enable_globally_convergent_newton_method()

void oomph::Problem::enable_globally_convergent_newton_method ( )
inline

enable globally convergent Newton method

2004  {
2006  }

References Use_globally_convergent_newton_method.

◆ enable_info_in_newton_solve()

void oomph::Problem::enable_info_in_newton_solve ( )
inline

Enable the output of information when in the newton solver (Default)

2936  {
2937  Shut_up_in_newton_solve = false;
2938  }

References Shut_up_in_newton_solve.

◆ enable_jacobian_reuse()

void oomph::Problem::enable_jacobian_reuse ( )
inline

Enable recycling of Jacobian in Newton iteration (if the linear solver allows it). Useful for linear problems with constant Jacobians or nonlinear problems where you're willing to risk the trade-off between faster solve times and degraded Newton convergence rate

1976  {
1979  }

References Jacobian_has_been_computed, and Jacobian_reuse_is_enabled.

◆ enable_mass_matrix_reuse()

void Problem::enable_mass_matrix_reuse ( )

Enable recycling of the mass matrix in explicit timestepping schemes. Useful for timestepping on fixed meshes when you want to avoid the linear solve phase.

11808  {
11811 
11812  // If we have a discontinuous formulation set the elements to reuse
11813  // their own mass matrices
11815  {
11816  const unsigned n_element = Problem::mesh_pt()->nelement();
11817  // Loop over the other elements
11818  for (unsigned e = 0; e < n_element; e++)
11819  {
11820  // Cache the element
11821  DGElement* const elem_pt =
11822  dynamic_cast<DGElement*>(Problem::mesh_pt()->element_pt(e));
11823  elem_pt->enable_mass_matrix_reuse();
11824  }
11825  }
11826  }

References Discontinuous_element_formulation, e(), oomph::Mesh::element_pt(), oomph::DGElement::enable_mass_matrix_reuse(), Mass_matrix_has_been_computed, Mass_matrix_reuse_is_enabled, mesh_pt(), and oomph::Mesh::nelement().

◆ enable_store_local_dof_pt_in_elements()

void oomph::Problem::enable_store_local_dof_pt_in_elements ( )
inline

Insist that local dof pointers are set up in each element when equation numbering takes place

1697  {
1699  }

References Store_local_dof_pt_in_elements.

◆ explicit_time_stepper_pt()

ExplicitTimeStepper*& oomph::Problem::explicit_time_stepper_pt ( )
inline

Return a pointer to the explicit timestepper.

1556  {
1557  return Explicit_time_stepper_pt;
1558  }

References Explicit_time_stepper_pt.

Referenced by calculate_predictions(), explicit_timestep(), and set_explicit_time_stepper_pt().

◆ explicit_timestep()

void Problem::explicit_timestep ( const double dt,
const bool shift_values = true 
)

Take an explicit timestep of size dt.

Take an explicit timestep of size dt and optionally shift any stored values of the time history

10919  {
10920 #ifdef PARANOID
10921  if (this->explicit_time_stepper_pt() == 0)
10922  {
10923  throw OomphLibError("Explicit time stepper pointer is null in problem.",
10926  }
10927 #endif
10928 
10929  // Firstly we shift the time values
10930  if (shift_values)
10931  {
10933  }
10934  // Set the current value of dt, if we can
10935  if (time_pt()->ndt() > 0)
10936  {
10937  time_pt()->dt() = dt;
10938  }
10939 
10940  // Take the explicit step
10941  this->explicit_time_stepper_pt()->timestep(this, dt);
10942  }
virtual void timestep(ExplicitTimeSteppableObject *const &object_pt, const double &dt)=0
Pure virtual function that is used to advance time in the object.

References oomph::Time::dt(), explicit_time_stepper_pt(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, shift_time_values(), time_pt(), and oomph::ExplicitTimeStepper::timestep().

Referenced by calculate_predictions().

◆ flush_global_data()

void oomph::Problem::flush_global_data ( )
inline

Flush the Problem's global data – resizes container to zero. Data objects are not deleted!

1663  {
1664  Global_data_pt.resize(0);
1665  }

References Global_data_pt.

Referenced by CapProblem< ELEMENT >::CapProblem().

◆ flush_sub_meshes()

void oomph::Problem::flush_sub_meshes ( )
inline

◆ get_all_error_estimates()

void Problem::get_all_error_estimates ( Vector< Vector< double >> &  elemental_error)

Return the error estimates computed by (all) refineable (sub)mesh(es) in the elemental_error structure, which consists of a vector of vectors of elemental errors, one vector for each (sub)mesh.

Return the error estimates computed by (all) refineable (sub)mesh(es) in the elemental_error structure, which consists of a vector of elemental errors for each (sub)mesh.

14628  {
14629  // Number of submeshes?
14630  const unsigned Nmesh = nsub_mesh();
14631 
14632  // Single mesh:
14633  //------------
14634  if (Nmesh == 0)
14635  {
14636  // There is only one mesh
14637  elemental_error.resize(1);
14638  // Refine single mesh uniformly if possible
14639  if (RefineableMeshBase* mmesh_pt =
14640  dynamic_cast<RefineableMeshBase*>(Problem::mesh_pt(0)))
14641  {
14642  // If we can adapt the mesh
14643  if (mmesh_pt->is_adaptation_enabled())
14644  {
14645  // Get pointer to error estimator
14646  ErrorEstimator* error_estimator_pt =
14647  mmesh_pt->spatial_error_estimator_pt();
14648 
14649 #ifdef PARANOID
14650  if (error_estimator_pt == 0)
14651  {
14652  throw OomphLibError("Error estimator hasn't been set yet",
14655  }
14656 #endif
14657 
14658  // Get error for all elements
14659  elemental_error[0].resize(mmesh_pt->nelement());
14660  // Are we documenting the errors or not
14661  if (mmesh_pt->doc_info_pt() == 0)
14662  {
14663  error_estimator_pt->get_element_errors(Problem::mesh_pt(0),
14664  elemental_error[0]);
14665  }
14666  else
14667  {
14668  error_estimator_pt->get_element_errors(Problem::mesh_pt(0),
14669  elemental_error[0],
14670  *mmesh_pt->doc_info_pt());
14671  }
14672 
14673  // Store max./min actual error
14674  mmesh_pt->max_error() =
14675  std::fabs(*std::max_element(elemental_error[0].begin(),
14676  elemental_error[0].end(),
14677  AbsCmp<double>()));
14678 
14679  mmesh_pt->min_error() =
14680  std::fabs(*std::min_element(elemental_error[0].begin(),
14681  elemental_error[0].end(),
14682  AbsCmp<double>()));
14683 
14684  oomph_info << "\n Max/min error: " << mmesh_pt->max_error() << " "
14685  << mmesh_pt->min_error() << std::endl;
14686  }
14687  else
14688  {
14689  oomph_info << "Info/Warning: Mesh adaptation is disabled."
14690  << std::endl;
14691  }
14692  }
14693  else
14694  {
14695  oomph_info << "Info/Warning: Mesh cannot be adapted" << std::endl;
14696  }
14697  }
14698 
14699  // Multiple submeshes
14700  //------------------
14701  else
14702  {
14703  // Resize to the number of submeshes
14704  elemental_error.resize(Nmesh);
14705 
14706  // Loop over submeshes
14707  for (unsigned imesh = 0; imesh < Nmesh; imesh++)
14708  {
14709  // Refine single mesh uniformly if possible
14710  if (RefineableMeshBase* mmesh_pt =
14711  dynamic_cast<RefineableMeshBase*>(Problem::mesh_pt(imesh)))
14712  {
14713  // Get pointer to error estimator
14714  ErrorEstimator* error_estimator_pt =
14715  mmesh_pt->spatial_error_estimator_pt();
14716 
14717 #ifdef PARANOID
14718  if (error_estimator_pt == 0)
14719  {
14720  throw OomphLibError("Error estimator hasn't been set yet",
14723  }
14724 #endif
14725  // If we can adapt the mesh
14726  if (mmesh_pt->is_adaptation_enabled())
14727  {
14728  // Get error for all elements
14729  elemental_error[imesh].resize(mmesh_pt->nelement());
14730  if (mmesh_pt->doc_info_pt() == 0)
14731  {
14732  error_estimator_pt->get_element_errors(Problem::mesh_pt(imesh),
14733  elemental_error[imesh]);
14734  }
14735  else
14736  {
14737  error_estimator_pt->get_element_errors(Problem::mesh_pt(imesh),
14738  elemental_error[imesh],
14739  *mmesh_pt->doc_info_pt());
14740  }
14741 
14742  // Store max./min error
14743  mmesh_pt->max_error() =
14744  std::fabs(*std::max_element(elemental_error[imesh].begin(),
14745  elemental_error[imesh].end(),
14746  AbsCmp<double>()));
14747 
14748  mmesh_pt->min_error() =
14749  std::fabs(*std::min_element(elemental_error[imesh].begin(),
14750  elemental_error[imesh].end(),
14751  AbsCmp<double>()));
14752 
14753  oomph_info << "\n Max/min error: " << mmesh_pt->max_error() << " "
14754  << mmesh_pt->min_error() << std::endl;
14755  }
14756  else
14757  {
14758  oomph_info << "Info/Warning: Mesh adaptation is disabled."
14759  << std::endl;
14760  }
14761  }
14762  else
14763  {
14764  oomph_info << "Info/Warning: Mesh cannot be adapted." << std::endl;
14765  }
14766 
14767  } // End of loop over submeshes
14768  }
14769  }
static constexpr lastp1_t end
Definition: IndexedViewHelper.h:79

References Eigen::placeholders::end, MeshRefinement::error_estimator_pt, boost::multiprecision::fabs(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and oomph::oomph_info.

Referenced by adapt(), and bifurcation_adapt_helper().

◆ get_bifurcation_eigenfunction()

void Problem::get_bifurcation_eigenfunction ( Vector< DoubleVector > &  eigenfunction)

Return the eigenfunction calculated as part of a bifurcation tracking process. If we are not tracking a bifurcation then an error will be thrown by the AssemblyHandler

10093  {
10094  // Simply call the appropriate assembly handler function
10095  Assembly_handler_pt->get_eigenfunction(eigenfunction);
10096  }
virtual void get_eigenfunction(Vector< DoubleVector > &eigenfunction)
Definition: assembly_handler.cc:188

References Assembly_handler_pt, and oomph::AssemblyHandler::get_eigenfunction().

Referenced by bifurcation_adapt_helper().

◆ get_derivative_wrt_global_parameter()

void Problem::get_derivative_wrt_global_parameter ( double *const &  parameter_pt,
DoubleVector result 
)

Get the derivative of the entire residuals vector wrt a global parameter, used in continuation problems

Get derivative of the residuals vector wrt a global parameter This is required in continuation problems

7889  {
7890  // If we are doing the calculation analytically then call the appropriate
7891  // handler and then calling get_residuals
7892  if (is_dparameter_calculated_analytically(parameter_pt))
7893  {
7894  // Locally cache pointer to assembly handler
7895  AssemblyHandler* const old_assembly_handler_pt = Assembly_handler_pt;
7896  // Create a new assembly handler that replaces get_residuals by
7897  // get_dresiduals_dparameter for each element
7899  new ParameterDerivativeHandler(old_assembly_handler_pt, parameter_pt);
7900  // Get the residuals, which will be dresiduals by dparameter
7901  this->get_residuals(result);
7902  // Delete the parameter derivative handler
7903  delete Assembly_handler_pt;
7904  // Reset the assembly handler to the original handler
7905  Assembly_handler_pt = old_assembly_handler_pt;
7906 
7907  /*AssemblyHandler* const assembly_handler_pt = Assembly_handler_pt;
7908  //Loop over all the elements
7909  unsigned long Element_pt_range = Mesh_pt->nelement();
7910  for(unsigned long e=0;e<Element_pt_range;e++)
7911  {
7912  //Get the pointer to the element
7913  GeneralisedElement* elem_pt = Mesh_pt->element_pt(e);
7914  //Find number of dofs in the element
7915  unsigned n_element_dofs = assembly_handler_pt->ndof(elem_pt);
7916  //Set up an array
7917  Vector<double> element_residuals(n_element_dofs);
7918  //Fill the array
7919  assembly_handler_pt->get_dresiduals_dparameter(elem_pt,parameter_pt,
7920  element_residuals);
7921  //Now loop over the dofs and assign values to global Vector
7922  for(unsigned l=0;l<n_element_dofs;l++)
7923  {
7924  result[assembly_handler_pt->eqn_number(elem_pt,l)]
7925  += element_residuals[l];
7926  }
7927  }*/
7928 
7929  // for(unsigned n=0;n<n_dof;n++)
7930  // {std::cout << "BLA " << n << " " << result[n] << "\n";}
7931  }
7932  // Otherwise use the finite difference default
7933  else
7934  {
7935  // Get the (global) residuals and store in the result vector
7936  get_residuals(result);
7937 
7938  // Storage for the new residuals
7939  DoubleVector newres;
7940 
7941  // Increase the global parameter
7942  const double FD_step = 1.0e-8;
7943 
7944  // Store the current value of the parameter
7945  double param_value = *parameter_pt;
7946 
7947  // Increase the parameter
7948  *parameter_pt += FD_step;
7949 
7950  // Do any possible updates
7952 
7953  // Get the new residuals
7954  get_residuals(newres);
7955 
7956  // Find the number of local rows
7957  //(I think it's a global vector, so that should be fine)
7958  const unsigned ndof_local = result.nrow_local();
7959 
7960  // Do the finite differencing in the local variables
7961  for (unsigned n = 0; n < ndof_local; ++n)
7962  {
7963  result[n] = (newres[n] - result[n]) / FD_step;
7964  }
7965 
7966  // Reset the value of the parameter
7967  *parameter_pt = param_value;
7968 
7969  // Do any possible updates
7971  }
7972  }
virtual void get_residuals(DoubleVector &residuals)
Get the total residuals Vector for the problem.
Definition: problem.cc:3714
virtual void actions_after_change_in_global_parameter(double *const &parameter_pt)
Definition: problem.h:1133
bool is_dparameter_calculated_analytically(double *const &parameter_pt)
Definition: problem.h:277
double FD_step
FD step.
Definition: black_box_newton_solver.cc:54

References actions_after_change_in_global_parameter(), Assembly_handler_pt, oomph::BlackBoxFDNewtonSolver::FD_step, get_residuals(), is_dparameter_calculated_analytically(), n, and oomph::DistributableLinearAlgebraObject::nrow_local().

Referenced by calculate_continuation_derivatives(), oomph::FoldHandler::FoldHandler(), oomph::HopfHandler::HopfHandler(), newton_solve_continuation(), and oomph::BlockPitchForkLinearSolver::solve().

◆ get_dofs() [1/2]

void Problem::get_dofs ( const unsigned t,
DoubleVector dofs 
) const
virtual

Return vector of the t'th history value of all dofs.

Get history values of dofs in a double vector.

Reimplemented from oomph::ExplicitTimeSteppableObject.

2496  {
2497 #ifdef PARANOID
2498  if (distributed())
2499  {
2500  throw OomphLibError("Not designed for distributed problems",
2503  // might work, not sure
2504  }
2505 #endif
2506 
2507  // Resize the vector
2508  dofs.build(Dof_distribution_pt, 0.0);
2509 
2510  // First deal with global data
2511  unsigned Nglobal_data = nglobal_data();
2512  for (unsigned i = 0; i < Nglobal_data; i++)
2513  {
2514  for (unsigned j = 0, nj = Global_data_pt[i]->nvalue(); j < nj; j++)
2515  {
2516  // For each data get the equation number and copy out the value.
2517  int eqn_number = Global_data_pt[i]->eqn_number(j);
2518  if (eqn_number >= 0)
2519  {
2520  dofs[eqn_number] = Global_data_pt[i]->value(t, j);
2521  }
2522  }
2523  }
2524 
2525  // Next element internal data
2526  for (unsigned i = 0, ni = mesh_pt()->nelement(); i < ni; i++)
2527  {
2528  GeneralisedElement* ele_pt = mesh_pt()->element_pt(i);
2529  for (unsigned j = 0, nj = ele_pt->ninternal_data(); j < nj; j++)
2530  {
2531  Data* d_pt = ele_pt->internal_data_pt(j);
2532  for (unsigned k = 0, nk = d_pt->nvalue(); k < nk; k++)
2533  {
2534  int eqn_number = d_pt->eqn_number(k);
2535  if (eqn_number >= 0)
2536  {
2537  dofs[eqn_number] = d_pt->value(t, k);
2538  }
2539  }
2540  }
2541  }
2542 
2543  // Now the nodes
2544  for (unsigned i = 0, ni = mesh_pt()->nnode(); i < ni; i++)
2545  {
2546  Node* node_pt = mesh_pt()->node_pt(i);
2547  for (unsigned j = 0, nj = node_pt->nvalue(); j < nj; j++)
2548  {
2549  // For each node get the equation number and copy out the value.
2550  int eqn_number = node_pt->eqn_number(j);
2551  if (eqn_number >= 0)
2552  {
2553  dofs[eqn_number] = node_pt->value(t, j);
2554  }
2555  }
2556  }
2557  }
long & eqn_number(const unsigned &i)
Return the equation number of the i-th stored variable.
Definition: nodes.h:367
Data *& internal_data_pt(const unsigned &i)
Return a pointer to i-th internal data object.
Definition: elements.h:622
char char char int int * k
Definition: level2_impl.h:374
t
Definition: plotPSD.py:36

References oomph::DoubleVector::build(), distributed(), Dof_distribution_pt, oomph::Mesh::element_pt(), oomph::Data::eqn_number(), Global_data_pt, i, oomph::GeneralisedElement::internal_data_pt(), j, k, mesh_pt(), nglobal_data(), oomph::GeneralisedElement::ninternal_data(), oomph::Mesh::node_pt(), oomph::Data::nvalue(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, plotPSD::t, oomph::Data::value(), and oomph::Node::value().

◆ get_dofs() [2/2]

void Problem::get_dofs ( DoubleVector dofs) const
virtual

Return the vector of dofs, i.e. a vector containing the current values of all unknowns.

Get the vector of dofs, i.e. a vector containing the current values of all unknowns.

Reimplemented from oomph::ExplicitTimeSteppableObject.

2480  {
2481  // Find number of dofs
2482  const unsigned long n_dof = ndof();
2483 
2484  // Resize the vector
2485  dofs.build(Dof_distribution_pt, 0.0);
2486 
2487  // Copy dofs into vector
2488  for (unsigned long l = 0; l < n_dof; l++)
2489  {
2490  dofs[l] = *Dof_pt[l];
2491  }
2492  }

References oomph::DoubleVector::build(), Dof_distribution_pt, Dof_pt, and ndof().

Referenced by oomph::IMRByBDF::actions_after_timestep(), oomph::IMRByBDF::actions_before_timestep(), and calculate_predictions().

◆ get_dvaluesdt()

void Problem::get_dvaluesdt ( DoubleVector f)
virtual

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(...).

Reimplemented from oomph::ExplicitTimeSteppableObject.

3685  {
3686  // Loop over timesteppers: make them (temporarily) steady and store their
3687  // is_steady status.
3688  unsigned n_time_steppers = this->ntime_stepper();
3689  std::vector<bool> was_steady(n_time_steppers);
3690  for (unsigned i = 0; i < n_time_steppers; i++)
3691  {
3692  was_steady[i] = time_stepper_pt(i)->is_steady();
3694  }
3695 
3696  // Calculate f using the residual/jacobian machinary.
3698 
3699  // Reset the is_steady status of all timesteppers that weren't already
3700  // steady when we came in here and reset their weights
3701  for (unsigned i = 0; i < n_time_steppers; i++)
3702  {
3703  if (!was_steady[i])
3704  {
3706  }
3707  }
3708  }
virtual void get_inverse_mass_matrix_times_residuals(DoubleVector &Mres)
Definition: problem.cc:3579
static int f(const TensorMap< Tensor< int, 3 > > &tensor)
Definition: cxx11_tensor_map.cpp:237

References f(), get_inverse_mass_matrix_times_residuals(), i, oomph::TimeStepper::is_steady(), oomph::TimeStepper::make_steady(), ntime_stepper(), time_stepper_pt(), and oomph::TimeStepper::undo_make_steady().

Referenced by oomph::TR::setup_initial_derivative().

◆ get_eigenproblem_matrices()

void Problem::get_eigenproblem_matrices ( CRDoubleMatrix mass_matrix,
CRDoubleMatrix main_matrix,
const double shift = 0.0 
)
virtual

Get the matrices required by a eigensolver. If the shift parameter is non-zero the second matrix will be shifted

Get the matrices required to solve an eigenproblem WARNING: temporarily this method only works with non-distributed matrices

8371  {
8372  // Three different cases again here:
8373  // 1) Compiled with MPI, but run in serial
8374  // 2) Compiled with MPI, but MPI not initialised in driver
8375  // 3) Serial version
8376 
8377 
8378 #ifdef PARANOID
8379  if (mass_matrix.distribution_built() && main_matrix.distribution_built())
8380  {
8381  // Check that the distribution of the mass matrix and jacobian match
8382  if (!(*mass_matrix.distribution_pt() == *main_matrix.distribution_pt()))
8383  {
8384  std::ostringstream error_stream;
8385  error_stream
8386  << "The distributions of the jacobian and mass matrix are\n"
8387  << "not the same and they must be.\n";
8388  throw OomphLibError(
8389  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8390  }
8391 
8392  if (mass_matrix.nrow() != this->ndof())
8393  {
8394  std::ostringstream error_stream;
8395  error_stream
8396  << "mass_matrix has a distribution, but the number of rows is not "
8397  << "equal to the number of degrees of freedom in the problem.";
8398  throw OomphLibError(
8399  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8400  }
8401 
8402  if (main_matrix.nrow() != this->ndof())
8403  {
8404  std::ostringstream error_stream;
8405  error_stream
8406  << "main_matrix has a distribution, but the number of rows is not "
8407  << "equal to the number of degrees of freedom in the problem.";
8408  throw OomphLibError(
8409  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8410  }
8411  }
8412  // If the distributions are not the same, then complain
8413  else if (main_matrix.distribution_built() !=
8414  mass_matrix.distribution_built())
8415  {
8416  std::ostringstream error_stream;
8417  error_stream << "The distribution of the jacobian and mass matrix must "
8418  << "both be setup or both not setup";
8419  throw OomphLibError(
8420  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8421  }
8422 #endif
8423 
8424  // Store the old assembly handler
8425  AssemblyHandler* old_assembly_handler_pt = Assembly_handler_pt;
8426  // Now setup the eigenproblem handler, pass in the value of the shift
8427  Assembly_handler_pt = new EigenProblemHandler(shift);
8428 
8429  // Prepare the storage formats.
8430  Vector<int*> column_or_row_index(2);
8431  Vector<int*> row_or_column_start(2);
8432  Vector<double*> value(2);
8433  Vector<unsigned> nnz(2);
8434  // Allocate pointer to residuals, although not used in these problems
8435  Vector<double*> residuals_vectors(0);
8436 
8437  // total number of rows in each matrix
8438  unsigned nrow = this->ndof();
8439 
8440  // determine the distribution for the jacobian (main matrix)
8441  // IF the jacobian has distribution setup then use that
8442  // ELSE determine the distribution based on the
8443  // distributed_matrix_distribution enum
8444  LinearAlgebraDistribution* dist_pt = 0;
8445  if (main_matrix.distribution_built())
8446  {
8447  dist_pt = new LinearAlgebraDistribution(main_matrix.distribution_pt());
8448  }
8449  else
8450  {
8451 #ifdef OOMPH_HAS_MPI
8452  // if problem is only one one processor
8453  if (Communicator_pt->nproc() == 1)
8454  {
8455  dist_pt = new LinearAlgebraDistribution(Communicator_pt, nrow, false);
8456  }
8457  // if the problem is not distributed then assemble the matrices with
8458  // a uniform distributed distribution
8459  else if (!Problem_has_been_distributed)
8460  {
8461  dist_pt = new LinearAlgebraDistribution(Communicator_pt, nrow, true);
8462  }
8463  // otherwise the problem is a distributed problem
8464  else
8465  {
8466  switch (Dist_problem_matrix_distribution)
8467  {
8468  case Uniform_matrix_distribution:
8469  dist_pt =
8470  new LinearAlgebraDistribution(Communicator_pt, nrow, true);
8471  break;
8472  case Problem_matrix_distribution:
8473  dist_pt = new LinearAlgebraDistribution(Dof_distribution_pt);
8474  break;
8475  case Default_matrix_distribution:
8476  LinearAlgebraDistribution* uniform_dist_pt =
8477  new LinearAlgebraDistribution(Communicator_pt, nrow, true);
8478  bool use_problem_dist = true;
8479  unsigned nproc = Communicator_pt->nproc();
8480  for (unsigned p = 0; p < nproc; p++)
8481  {
8482  if ((double)Dof_distribution_pt->nrow_local(p) >
8483  ((double)uniform_dist_pt->nrow_local(p)) * 1.1)
8484  {
8485  use_problem_dist = false;
8486  }
8487  }
8488  if (use_problem_dist)
8489  {
8490  dist_pt = new LinearAlgebraDistribution(Dof_distribution_pt);
8491  }
8492  else
8493  {
8494  dist_pt = new LinearAlgebraDistribution(uniform_dist_pt);
8495  }
8496  delete uniform_dist_pt;
8497  break;
8498  }
8499  }
8500 #else
8501  dist_pt = new LinearAlgebraDistribution(Communicator_pt, nrow, false);
8502 #endif
8503  }
8504 
8505 
8506  // The matrix is in compressed row format
8507  bool compressed_row_flag = true;
8508 
8509 #ifdef OOMPH_HAS_MPI
8510  //
8511  if (Communicator_pt->nproc() == 1)
8512  {
8513 #endif
8514 
8515  sparse_assemble_row_or_column_compressed(column_or_row_index,
8516  row_or_column_start,
8517  value,
8518  nnz,
8519  residuals_vectors,
8520  compressed_row_flag);
8521 
8522  // The main matrix is the first entry
8523  main_matrix.build(dist_pt);
8524  main_matrix.build_without_copy(dist_pt->nrow(),
8525  nnz[0],
8526  value[0],
8527  column_or_row_index[0],
8528  row_or_column_start[0]);
8529  // The mass matrix is the second entry
8530  mass_matrix.build(dist_pt);
8531  mass_matrix.build_without_copy(dist_pt->nrow(),
8532  nnz[1],
8533  value[1],
8534  column_or_row_index[1],
8535  row_or_column_start[1]);
8536 #ifdef OOMPH_HAS_MPI
8537  }
8538  else
8539  {
8540  if (dist_pt->distributed())
8541  {
8542  parallel_sparse_assemble(dist_pt,
8543  column_or_row_index,
8544  row_or_column_start,
8545  value,
8546  nnz,
8547  residuals_vectors);
8548  // The main matrix is the first entry
8549  main_matrix.build(dist_pt);
8550  main_matrix.build_without_copy(dist_pt->nrow(),
8551  nnz[0],
8552  value[0],
8553  column_or_row_index[0],
8554  row_or_column_start[0]);
8555  // The mass matrix is the second entry
8556  mass_matrix.build(dist_pt);
8557  mass_matrix.build_without_copy(dist_pt->nrow(),
8558  nnz[1],
8559  value[1],
8560  column_or_row_index[1],
8561  row_or_column_start[1]);
8562  }
8563  else
8564  {
8565  LinearAlgebraDistribution* temp_dist_pt =
8566  new LinearAlgebraDistribution(Communicator_pt, dist_pt->nrow(), true);
8567  parallel_sparse_assemble(temp_dist_pt,
8568  column_or_row_index,
8569  row_or_column_start,
8570  value,
8571  nnz,
8572  residuals_vectors);
8573  // The main matrix is the first entry
8574  main_matrix.build(temp_dist_pt);
8575  main_matrix.build_without_copy(dist_pt->nrow(),
8576  nnz[0],
8577  value[0],
8578  column_or_row_index[0],
8579  row_or_column_start[0]);
8580  main_matrix.redistribute(dist_pt);
8581  // The mass matrix is the second entry
8582  mass_matrix.build(temp_dist_pt);
8583  mass_matrix.build_without_copy(dist_pt->nrow(),
8584  nnz[1],
8585  value[1],
8586  column_or_row_index[1],
8587  row_or_column_start[1]);
8588  mass_matrix.redistribute(dist_pt);
8589  delete temp_dist_pt;
8590  }
8591  }
8592 #endif
8593 
8594  // clean up dist_pt and residuals_vector pt
8595  delete dist_pt;
8596 
8597  // Delete the eigenproblem handler
8598  delete Assembly_handler_pt;
8599  // Reset the assembly handler to the original handler
8600  Assembly_handler_pt = old_assembly_handler_pt;
8601  }
float * p
Definition: Tutorial_Map_using.cpp:9
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)
Definition: problem.cc:4484
squared absolute value
Definition: GlobalFunctions.h:87

References Assembly_handler_pt, oomph::CRDoubleMatrix::build(), oomph::CRDoubleMatrix::build_without_copy(), Communicator_pt, oomph::LinearAlgebraDistribution::distributed(), oomph::DistributableLinearAlgebraObject::distribution_built(), oomph::DistributableLinearAlgebraObject::distribution_pt(), Dof_distribution_pt, ndof(), oomph::OomphCommunicator::nproc(), oomph::LinearAlgebraDistribution::nrow(), oomph::CRDoubleMatrix::nrow(), oomph::LinearAlgebraDistribution::nrow_local(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, p, oomph::CRDoubleMatrix::redistribute(), sparse_assemble_row_or_column_compressed(), and Eigen::value.

Referenced by oomph::ProblemBasedShiftInvertOperator::ProblemBasedShiftInvertOperator(), oomph::ARPACK::solve_eigenproblem(), and oomph::LAPACK_QZ::solve_eigenproblem().

◆ get_fd_jacobian()

void Problem::get_fd_jacobian ( DoubleVector residuals,
DenseMatrix< double > &  jacobian 
)

Get the full Jacobian by finite differencing.

Return the fully-assembled Jacobian and residuals, generated by finite differences

7825  {
7826 #ifdef OOMPH_HAS_MPI
7827 
7828  if (Problem_has_been_distributed)
7829  {
7830  OomphLibWarning("This is unlikely to work with a distributed problem",
7831  " Problem::get_fd_jacobian()",
7833  }
7834 #endif
7835 
7836 
7837  // Find number of dofs
7838  const unsigned long n_dof = ndof();
7839 
7840  // Advanced residuals
7841  DoubleVector residuals_pls;
7842 
7843  // Get reference residuals
7844  get_residuals(residuals);
7845 
7846  const double FD_step = 1.0e-8;
7847 
7848  // Make sure the Jacobian is the right size (since we don't care about
7849  // speed).
7850  jacobian.resize(n_dof, n_dof);
7851 
7852  // Loop over all dofs
7853  for (unsigned long jdof = 0; jdof < n_dof; jdof++)
7854  {
7855  double backup = *Dof_pt[jdof];
7856  *Dof_pt[jdof] += FD_step;
7857 
7858  // We're checking if the new values for Dof_pt[] actually
7859  // solve the entire problem --> update as if problem had
7860  // been solved
7864 
7865  // Get advanced residuals
7866  get_residuals(residuals_pls);
7867 
7868  for (unsigned long ieqn = 0; ieqn < n_dof; ieqn++)
7869  {
7870  jacobian(ieqn, jdof) =
7871  (residuals_pls[ieqn] - residuals[ieqn]) / FD_step;
7872  }
7873 
7874  *Dof_pt[jdof] = backup;
7875  }
7876 
7877  // Reset problem to state it was in
7881  }
void resize(const unsigned long &n)
Definition: matrices.h:498

References actions_after_newton_solve(), actions_before_newton_convergence_check(), actions_before_newton_solve(), Dof_pt, oomph::BlackBoxFDNewtonSolver::FD_step, get_residuals(), ndof(), OOMPH_EXCEPTION_LOCATION, and oomph::DenseMatrix< T >::resize().

Referenced by oomph::FD_LU::solve().

◆ get_hessian_vector_products()

void Problem::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) with an eigenvector, Y, and any number of other specified vectors C (d(J_{ij})/d u_{k}) Y_{j} C_{k}. This function is used in assembling and solving the augmented systems associated with bifurcation tracking. The default implementation is to use finite differences at the global level.

Alice: My bifurcation tracking converges better with this FD_step as 1.0e-5. The default value remains at 1.0e-8.

7989  {
7990  // How many vector products must we construct
7991  const unsigned n_vec = C.size();
7992 
7993  // currently only global (non-distributed) distributions are allowed
7994  // LinearAlgebraDistribution* dist_pt = new
7995  // LinearAlgebraDistribution(Communicator_pt,n_dof,false);
7996 
7997  // Cache the assembly hander
7998  AssemblyHandler* const assembly_handler_pt = Assembly_handler_pt;
7999 
8000  // Rebuild the results vectors and initialise to zero
8001  // use the same distribution of the vector Y
8002  for (unsigned i = 0; i < n_vec; i++)
8003  {
8004  product[i].build(Y.distribution_pt(), 0.0);
8005  product[i].initialise(0.0);
8006  }
8007 
8008 // Setup the halo schemes for the result
8009 #ifdef OOMPH_HAS_MPI
8010  if (Problem_has_been_distributed)
8011  {
8012  for (unsigned i = 0; i < n_vec; i++)
8013  {
8014  product[i].build_halo_scheme(this->Halo_scheme_pt);
8015  }
8016  }
8017 #endif
8018 
8019  // If we are doing the calculation analytically then call the appropriate
8020  // handler
8021  // A better way to do this is probably to hook into the get_residuals
8022  // framework but with a different member function of the assembly
8023  // handler
8025  {
8026  // Loop over all the elements
8027  unsigned long Element_pt_range = Mesh_pt->nelement();
8028  for (unsigned long e = 0; e < Element_pt_range; e++)
8029  {
8030  // Get the pointer to the element
8031  GeneralisedElement* elem_pt = Mesh_pt->element_pt(e);
8032 // Do not loop over halo elements
8033 #ifdef OOMPH_HAS_MPI
8034  if (!elem_pt->is_halo())
8035  {
8036 #endif
8037  // Find number of dofs in the element
8038  unsigned n_var = assembly_handler_pt->ndof(elem_pt);
8039  // Set up a matrix for the input and output
8040  Vector<double> Y_local(n_var);
8041  DenseMatrix<double> C_local(n_vec, n_var);
8042  DenseMatrix<double> product_local(n_vec, n_var);
8043 
8044  // Translate the global input vectors into the local storage
8045  // Probably horribly inefficient, but otherwise things get really
8046  // messy at the elemental level
8047  for (unsigned l = 0; l < n_var; l++)
8048  {
8049  // Cache the global equation number
8050  const unsigned long eqn_number =
8051  assembly_handler_pt->eqn_number(elem_pt, l);
8052 
8053  Y_local[l] = Y.global_value(eqn_number);
8054  for (unsigned i = 0; i < n_vec; i++)
8055  {
8056  C_local(i, l) = C[i].global_value(eqn_number);
8057  }
8058  }
8059 
8060  // Fill the array
8062  elem_pt, Y_local, C_local, product_local);
8063 
8064  // Assign the local results to the global vector
8065  for (unsigned l = 0; l < n_var; l++)
8066  {
8067  const unsigned long eqn_number =
8068  assembly_handler_pt->eqn_number(elem_pt, l);
8069 
8070  for (unsigned i = 0; i < n_vec; i++)
8071  {
8072  product[i].global_value(eqn_number) += product_local(i, l);
8073  // std::cout << "BLA " << e << " " << i << " "
8074  // << l << " " << product_local(i,l) << "\n";
8075  }
8076  }
8077 #ifdef OOMPH_HAS_MPI
8078  }
8079 #endif
8080  }
8081  }
8082  // Otherwise calculate using finite differences by
8083  // perturbing the jacobian along a particular direction
8084  else
8085  {
8086  // Cache the finite difference step
8090 
8091  // We can now construct our multipliers
8092  const unsigned n_dof_local = this->Dof_distribution_pt->nrow_local();
8093  // Prepare to scale
8094  double dof_length = 0.0;
8095  Vector<double> C_length(n_vec, 0.0);
8096 
8097  for (unsigned n = 0; n < n_dof_local; n++)
8098  {
8099  if (std::fabs(this->dof(n)) > dof_length)
8100  {
8101  dof_length = std::fabs(this->dof(n));
8102  }
8103  }
8104 
8105  // C is assumed to have the same distribution as the dofs
8106  for (unsigned i = 0; i < n_vec; i++)
8107  {
8108  for (unsigned n = 0; n < n_dof_local; n++)
8109  {
8110  if (std::fabs(C[i][n]) > C_length[i])
8111  {
8112  C_length[i] = std::fabs(C[i][n]);
8113  }
8114  }
8115  }
8116 
8117  // Now broadcast the information, if distributed
8118 #ifdef OOMPH_HAS_MPI
8119  if (Problem_has_been_distributed)
8120  {
8121  const unsigned n_length = n_vec + 1;
8122  double all_length[n_length];
8123  all_length[0] = dof_length;
8124  for (unsigned i = 0; i < n_vec; i++)
8125  {
8126  all_length[i + 1] = C_length[i];
8127  }
8128 
8129  // Do the MPI call
8130  double all_length_reduce[n_length];
8131  MPI_Allreduce(all_length,
8132  all_length_reduce,
8133  n_length,
8134  MPI_DOUBLE,
8135  MPI_MAX,
8136  this->communicator_pt()->mpi_comm());
8137 
8138  // Read out the information
8139  dof_length = all_length_reduce[0];
8140  for (unsigned i = 0; i < n_vec; i++)
8141  {
8142  C_length[i] = all_length_reduce[i + 1];
8143  }
8144  }
8145 #endif
8146 
8147  // Form the multipliers
8148  Vector<double> C_mult(n_vec, 0.0);
8149  for (unsigned i = 0; i < n_vec; i++)
8150  {
8151  C_mult[i] = dof_length / C_length[i];
8152  C_mult[i] += FD_step;
8153  C_mult[i] *= FD_step;
8154  }
8155 
8156 
8157  // Dummy vector to stand in the place of the residuals
8158  Vector<double> dummy_res;
8159 
8160  // Calculate the product of the jacobian matrices, etc by looping over the
8161  // elements
8162  const unsigned long n_element = this->mesh_pt()->nelement();
8163  for (unsigned long e = 0; e < n_element; e++)
8164  {
8165  GeneralisedElement* elem_pt = this->mesh_pt()->element_pt(e);
8166  // Ignore halo's of course
8167 #ifdef OOMPH_HAS_MPI
8168  if (!elem_pt->is_halo())
8169  {
8170 #endif
8171  // Loop over the ndofs in each element
8172  unsigned n_var = assembly_handler_pt->ndof(elem_pt);
8173  // Resize the dummy residuals vector
8174  dummy_res.resize(n_var);
8175  // Allocate storage for the unperturbed jacobian matrix
8176  DenseMatrix<double> jac(n_var);
8177  // Get unperturbed jacobian
8178  assembly_handler_pt->get_jacobian(elem_pt, dummy_res, jac);
8179 
8180  // Backup the dofs
8181  Vector<double> dof_bac(n_var);
8182  for (unsigned n = 0; n < n_var; n++)
8183  {
8184  unsigned eqn_number = assembly_handler_pt->eqn_number(elem_pt, n);
8185  dof_bac[n] = *this->global_dof_pt(eqn_number);
8186  }
8187 
8188  // Now loop over all vectors C
8189  for (unsigned i = 0; i < n_vec; i++)
8190  {
8191  // Perturb the dofs by the appropriate vector
8192  for (unsigned n = 0; n < n_var; n++)
8193  {
8194  unsigned eqn_number = assembly_handler_pt->eqn_number(elem_pt, n);
8195  // Perturb by vector C[i]
8196  *this->global_dof_pt(eqn_number) +=
8197  C_mult[i] * C[i].global_value(eqn_number);
8198  }
8200 
8201  // Allocate storage for the perturbed jacobian
8202  DenseMatrix<double> jac_C(n_var);
8203 
8204  // Now get the new jacobian
8205  assembly_handler_pt->get_jacobian(elem_pt, dummy_res, jac_C);
8206 
8207  // Reset the dofs
8208  for (unsigned n = 0; n < n_var; n++)
8209  {
8210  unsigned eqn_number = assembly_handler_pt->eqn_number(elem_pt, n);
8211  *this->global_dof_pt(eqn_number) = dof_bac[n];
8212  }
8214 
8215  // Now work out the products
8216  for (unsigned n = 0; n < n_var; n++)
8217  {
8218  unsigned eqn_number = assembly_handler_pt->eqn_number(elem_pt, n);
8219  double prod_c = 0.0;
8220  for (unsigned m = 0; m < n_var; m++)
8221  {
8222  unsigned unknown = assembly_handler_pt->eqn_number(elem_pt, m);
8223  prod_c += (jac_C(n, m) - jac(n, m)) * Y.global_value(unknown);
8224  }
8225  // std::cout << "FD " << e << " " << i << " "
8226  // << n << " " << prod_c/C_mult[i] << "\n";
8227  product[i].global_value(eqn_number) += prod_c / C_mult[i];
8228  }
8229  }
8230 #ifdef OOMPH_HAS_MPI
8231  }
8232 #endif
8233  } // End of loop over elements
8234  }
8235 
8236  // If we have a distributed problem then gather all
8237  // values
8238 #ifdef OOMPH_HAS_MPI
8239  if (Problem_has_been_distributed)
8240  {
8241  // Sum all values if distributed
8242  for (unsigned i = 0; i < n_vec; i++)
8243  {
8244  product[i].sum_all_halo_and_haloed_values();
8245  }
8246  }
8247 #endif
8248  }
virtual unsigned ndof(GeneralisedElement *const &elem_pt)
Return the number of degrees of freedom in the element elem_pt.
Definition: assembly_handler.cc:42
virtual void get_hessian_vector_products(GeneralisedElement *const &elem_pt, Vector< double > const &Y, DenseMatrix< double > const &C, DenseMatrix< double > &product)
Definition: assembly_handler.cc:153
virtual unsigned long eqn_number(GeneralisedElement *const &elem_pt, const unsigned &ieqn_local)
Definition: assembly_handler.cc:82
virtual void get_jacobian(GeneralisedElement *const &elem_pt, Vector< double > &residuals, DenseMatrix< double > &jacobian)
Definition: assembly_handler.cc:102
Definition: matrices.h:74
double * global_dof_pt(const unsigned &i)
Definition: problem.h:1764
bool are_hessian_products_calculated_analytically()
Definition: problem.h:303
void product(const MatrixType &m)
Definition: product.h:42
const char Y
Definition: test/EulerAngles.cpp:32

References actions_before_newton_convergence_check(), are_hessian_products_calculated_analytically(), Assembly_handler_pt, assembly_handler_pt(), communicator_pt(), dof(), Dof_distribution_pt, e(), oomph::Mesh::element_pt(), oomph::AssemblyHandler::eqn_number(), boost::multiprecision::fabs(), oomph::BlackBoxFDNewtonSolver::FD_step, FD_step_used_in_get_hessian_vector_products, oomph::AssemblyHandler::get_hessian_vector_products(), oomph::AssemblyHandler::get_jacobian(), global_dof_pt(), i, m, Mesh_pt, mesh_pt(), n, oomph::AssemblyHandler::ndof(), oomph::Mesh::nelement(), oomph::LinearAlgebraDistribution::nrow_local(), product(), and Y.

Referenced by oomph::BlockPitchForkLinearSolver::resolve(), and oomph::BlockPitchForkLinearSolver::solve().

◆ get_inverse_mass_matrix_times_residuals()

void Problem::get_inverse_mass_matrix_times_residuals ( DoubleVector Mres)
virtual

Return the residual vector multiplied by the inverse mass matrix Virtual so that it can be overloaded for mpi problems

3580  {
3581  // This function does not make sense for assembly handlers other than the
3582  // default, so complain if we try to call it with another handler
3583 
3584 #ifdef PARANOID
3585  // If we are not the default, then complain
3587  {
3588  std::ostringstream error_stream;
3589  error_stream << "The function get_inverse_mass_matrix_times_residuals() "
3590  "can only be\n"
3591  << "used with the default assembly handler\n\n";
3592  throw OomphLibError(
3593  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3594  }
3595 #endif
3596 
3597  // Find the number of degrees of freedom in the problem
3598  const unsigned n_dof = this->ndof();
3599 
3600  // Resize the vector
3601  LinearAlgebraDistribution dist(this->communicator_pt(), n_dof, false);
3602  Mres.build(&dist, 0.0);
3603 
3604  // If we have discontinuous formulation
3605  // We can invert the mass matrix element by element
3607  {
3608  // Loop over the elements and get their residuals
3609  const unsigned n_element = Problem::mesh_pt()->nelement();
3610  Vector<double> element_Mres;
3611  for (unsigned e = 0; e < n_element; e++)
3612  {
3613  // Cache the element
3614  DGElement* const elem_pt =
3615  dynamic_cast<DGElement*>(Problem::mesh_pt()->element_pt(e));
3616 
3617  // Find the elemental inverse mass matrix times residuals
3618  const unsigned n_el_dofs = elem_pt->ndof();
3619  elem_pt->get_inverse_mass_matrix_times_residuals(element_Mres);
3620 
3621  // Add contribution to global matrix
3622  for (unsigned i = 0; i < n_el_dofs; i++)
3623  {
3624  Mres[elem_pt->eqn_number(i)] = element_Mres[i];
3625  }
3626  }
3627  }
3628  // Otherwise it's continous and we must invert the full
3629  // mass matrix via a global linear solve.
3630  else
3631  {
3632  // Now do the linear solve -- recycling Mass matrix if requested
3633  // If we already have the factorised mass matrix, then resolve
3635  {
3637  {
3638  oomph_info << "Not recomputing Mass Matrix " << std::endl;
3639  }
3640 
3641  // Get the residuals
3642  DoubleVector residuals(&dist, 0.0);
3643  this->get_residuals(residuals);
3644 
3645  // Resolve the linear system
3647  residuals, Mres);
3648  }
3649  // Otherwise solve for the first time
3650  else
3651  {
3652  // If we wish to reuse the mass matrix, then enable resolve
3654  {
3656  {
3657  oomph_info << "Enabling resolve in explicit timestep" << std::endl;
3658  }
3660  ->enable_resolve();
3661  }
3662 
3663  // Use a custom assembly handler to assemble and invert the mass matrix
3664 
3665  // Store the old assembly handler
3666  AssemblyHandler* old_assembly_handler_pt = this->assembly_handler_pt();
3667  // Set the assembly handler to the explicit timestep handler
3668  this->assembly_handler_pt() = new ExplicitTimeStepHandler;
3669 
3670  // Solve the linear system
3672  Mres);
3673  // The mass matrix has now been computed
3675 
3676  // Delete the Explicit Timestep handler
3677  delete this->assembly_handler_pt();
3678  // Reset the assembly handler to the original handler
3679  this->assembly_handler_pt() = old_assembly_handler_pt;
3680  }
3681  }
3682  }
LinearSolver *& mass_matrix_solver_for_explicit_timestepper_pt()
Definition: problem.h:1479

References assembly_handler_pt(), oomph::DoubleVector::build(), communicator_pt(), Default_assembly_handler_pt, Discontinuous_element_formulation, e(), oomph::Mesh::element_pt(), oomph::LinearSolver::enable_resolve(), oomph::GeneralisedElement::eqn_number(), oomph::DGElement::get_inverse_mass_matrix_times_residuals(), get_residuals(), i, Mass_matrix_has_been_computed, Mass_matrix_reuse_is_enabled, mass_matrix_solver_for_explicit_timestepper_pt(), mesh_pt(), oomph::GeneralisedElement::ndof(), ndof(), oomph::Mesh::nelement(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, oomph::LinearSolver::resolve(), Shut_up_in_newton_solve, and oomph::LinearSolver::solve().

Referenced by get_dvaluesdt().

◆ get_jacobian() [1/4]

void Problem::get_jacobian ( DoubleVector residuals,
CCDoubleMatrix jacobian 
)
virtual

Return the fully-assembled Jacobian and residuals for the problem. Interface for the case when the Jacobian is in column-compressed storage format. This is virtual so, if we feel like it (e.g. for testing iterative solvers with specific test matrices), we can bypass the default assembly procedure for the Jacobian and the residual vector.

Return the fully-assembled Jacobian and residuals for the problem, in the case when the jacobian matrix is in column-compressed storage format.

4186  {
4187  // Three different cases; if MPI_Helpers::MPI_has_been_initialised=true
4188  // this means MPI_Helpers::setup() has been called. This could happen on a
4189  // code compiled with MPI but run serially; in this instance the
4190  // get_residuals function still works on one processor.
4191  //
4192  // Secondly, if a code has been compiled with MPI, but MPI_Helpers::setup()
4193  // has not been called, then MPI_Helpers::MPI_has_been_initialised=false
4194  // and the code calls...
4195  //
4196  // Thirdly, the serial version (compiled by all, but only run when compiled
4197  // with MPI if MPI_Helpers::MPI_has_been_5Binitialised=false
4198  //
4199  // The only case where an MPI code cannot run serially at present
4200  // is one where the distribute function is used (i.e. METIS is called)
4201 
4202  // get the number of degrees of freedom
4203  unsigned n_dof = ndof();
4204 
4205 #ifdef PARANOID
4206  // PARANOID checks : if the distribution of residuals is setup then it must
4207  // must not be distributed, have the right number of rows, and the same
4208  // communicator as the problem
4209  if (residuals.built())
4210  {
4211  if (residuals.distribution_pt()->distributed())
4212  {
4213  std::ostringstream error_stream;
4214  error_stream
4215  << "If the DoubleVector residuals is setup then it must not "
4216  << "be distributed.";
4217  throw OomphLibError(
4218  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4219  }
4220  if (residuals.distribution_pt()->nrow() != n_dof)
4221  {
4222  std::ostringstream error_stream;
4223  error_stream
4224  << "If the DoubleVector residuals is setup then it must have"
4225  << " the correct number of rows";
4226  throw OomphLibError(
4227  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4228  }
4229  if (!(*Communicator_pt ==
4230  *residuals.distribution_pt()->communicator_pt()))
4231  {
4232  std::ostringstream error_stream;
4233  error_stream
4234  << "If the DoubleVector residuals is setup then it must have"
4235  << " the same communicator as the problem.";
4236  throw OomphLibError(
4237  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4238  }
4239  }
4240 #endif
4241 
4242  // Allocate storage for the matrix entries
4243  // The generalised Vector<Vector<>> structure is required
4244  // for the most general interface to sparse_assemble() which allows
4245  // the assembly of multiple matrices at once.
4246  Vector<int*> row_index(1);
4247  Vector<int*> column_start(1);
4248  Vector<double*> value(1);
4249 
4250  // Allocate generalised storage format for passing to sparse_assemble()
4251  Vector<double*> res(1);
4252 
4253  // allocate storage for the number of non-zeros in each matrix
4254  Vector<unsigned> nnz(1);
4255 
4256  // The matrix is in compressed column format
4257  bool compressed_row_flag = false;
4258 
4259  // get the distribution for the residuals
4260  LinearAlgebraDistribution* dist_pt;
4261  if (!residuals.built())
4262  {
4263  dist_pt =
4264  new LinearAlgebraDistribution(Communicator_pt, this->ndof(), false);
4265  }
4266  else
4267  {
4268  dist_pt = new LinearAlgebraDistribution(residuals.distribution_pt());
4269  }
4270 
4271 #ifdef OOMPH_HAS_MPI
4272  if (communicator_pt()->nproc() == 1)
4273  {
4274 #endif
4276  row_index, column_start, value, nnz, res, compressed_row_flag);
4277  jacobian.build_without_copy(
4278  value[0], row_index[0], column_start[0], nnz[0], n_dof, n_dof);
4279  residuals.build(dist_pt, 0.0);
4280  residuals.set_external_values(res[0], true);
4281 #ifdef OOMPH_HAS_MPI
4282  }
4283  else
4284  {
4285  std::ostringstream error_stream;
4286  error_stream << "Cannot assemble a CCDoubleMatrix Jacobian on more "
4287  << "than one processor.";
4288  throw OomphLibError(
4289  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4290  }
4291 #endif
4292 
4293  // clean up
4294  delete dist_pt;
4295  }
cout<< "Here is the matrix m:"<< endl<< m<< endl;Matrix< ptrdiff_t, 3, 1 > res
Definition: PartialRedux_count.cpp:3

References oomph::DoubleVector::build(), oomph::CCMatrix< T >::build_without_copy(), oomph::DoubleVector::built(), oomph::LinearAlgebraDistribution::communicator_pt(), Communicator_pt, communicator_pt(), oomph::LinearAlgebraDistribution::distributed(), oomph::DistributableLinearAlgebraObject::distribution_pt(), ndof(), oomph::LinearAlgebraDistribution::nrow(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, res, oomph::DoubleVector::set_external_values(), sparse_assemble_row_or_column_compressed(), and Eigen::value.

◆ get_jacobian() [2/4]

void Problem::get_jacobian ( DoubleVector residuals,
CRDoubleMatrix jacobian 
)
virtual

Return the fully-assembled Jacobian and residuals for the problem. Interface for the case when the Jacobian is in row-compressed storage format. This is virtual so, if we feel like it (e.g. for testing iterative solvers with specific test matrices), we can bypass the default assembly procedure for the Jacobian and the residual vector.

Return the fully-assembled Jacobian and residuals for the problem, in the case where the Jacobian matrix is in a distributable row compressed storage format.

  1. If the distribution of the jacobian and residuals is setup then, they will be returned with that distribution. Note. the jacobian and residuals must have the same distribution.
  2. If the distribution of the jacobian and residuals are not setup then their distribution will computed based on: Distributed_problem_matrix_distribution.
3998  {
3999  // Three different cases; if MPI_Helpers::MPI_has_been_initialised=true
4000  // this means MPI_Helpers::setup() has been called. This could happen on a
4001  // code compiled with MPI but run serially; in this instance the
4002  // get_residuals function still works on one processor.
4003  //
4004  // Secondly, if a code has been compiled with MPI, but MPI_Helpers::setup()
4005  // has not been called, then MPI_Helpers::MPI_has_been_initialised=false
4006  // and the code calls...
4007  //
4008  // Thirdly, the serial version (compiled by all, but only run when compiled
4009  // with MPI if MPI_Helpers::MPI_has_been_initialised=false
4010  //
4011  // The only case where an MPI code cannot run serially at present
4012  // is one where the distribute function is used (i.e. METIS is called)
4013 
4014  // Allocate storage for the matrix entries
4015  // The generalised Vector<Vector<>> structure is required
4016  // for the most general interface to sparse_assemble() which allows
4017  // the assembly of multiple matrices at once.
4018  Vector<int*> column_index(1);
4019  Vector<int*> row_start(1);
4020  Vector<double*> value(1);
4021  Vector<unsigned> nnz(1);
4022 
4023 #ifdef PARANOID
4024  // PARANOID checks that the distribution of the jacobian matches that of the
4025  // residuals (if they are setup) and that they have the right number of rows
4026  if (residuals.built() && jacobian.distribution_built())
4027  {
4028  if (!(*residuals.distribution_pt() == *jacobian.distribution_pt()))
4029  {
4030  std::ostringstream error_stream;
4031  error_stream << "The distribution of the residuals must "
4032  << "be the same as the distribution of the jacobian.";
4033  throw OomphLibError(
4034  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4035  }
4036  if (jacobian.distribution_pt()->nrow() != this->ndof())
4037  {
4038  std::ostringstream error_stream;
4039  error_stream
4040  << "The distribution of the jacobian and residuals does not"
4041  << "have the correct number of global rows.";
4042  throw OomphLibError(
4043  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4044  }
4045  }
4046  else if (residuals.built() != jacobian.distribution_built())
4047  {
4048  std::ostringstream error_stream;
4049  error_stream << "The distribution of the jacobian and residuals must "
4050  << "both be setup or both not setup";
4051  throw OomphLibError(
4052  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4053  }
4054 #endif
4055 
4056 
4057  // Allocate generalised storage format for passing to sparse_assemble()
4058  Vector<double*> res(1);
4059 
4060  // number of rows
4061  unsigned nrow = this->ndof();
4062 
4063  // determine the distribution for the jacobian.
4064  // IF the jacobian has distribution setup then use that
4065  // ELSE determine the distribution based on the
4066  // distributed_matrix_distribution enum
4067  LinearAlgebraDistribution* dist_pt = 0;
4068  if (jacobian.distribution_built())
4069  {
4070  dist_pt = new LinearAlgebraDistribution(jacobian.distribution_pt());
4071  }
4072  else
4073  {
4074 #ifdef OOMPH_HAS_MPI
4075  // if problem is only one one processor
4076  if (Communicator_pt->nproc() == 1)
4077  {
4078  dist_pt = new LinearAlgebraDistribution(Communicator_pt, nrow, false);
4079  }
4080  // if the problem is not distributed then assemble the jacobian with
4081  // a uniform distributed distribution
4082  else if (!Problem_has_been_distributed)
4083  {
4084  dist_pt = new LinearAlgebraDistribution(Communicator_pt, nrow, true);
4085  }
4086  // otherwise the problem is a distributed problem
4087  else
4088  {
4089  switch (Dist_problem_matrix_distribution)
4090  {
4091  case Uniform_matrix_distribution:
4092  dist_pt =
4093  new LinearAlgebraDistribution(Communicator_pt, nrow, true);
4094  break;
4095  case Problem_matrix_distribution:
4096  dist_pt = new LinearAlgebraDistribution(Dof_distribution_pt);
4097  break;
4098  case Default_matrix_distribution:
4099  LinearAlgebraDistribution* uniform_dist_pt =
4100  new LinearAlgebraDistribution(Communicator_pt, nrow, true);
4101  bool use_problem_dist = true;
4102  unsigned nproc = Communicator_pt->nproc();
4103  for (unsigned p = 0; p < nproc; p++)
4104  {
4105  if ((double)Dof_distribution_pt->nrow_local(p) >
4106  ((double)uniform_dist_pt->nrow_local(p)) * 1.1)
4107  {
4108  use_problem_dist = false;
4109  }
4110  }
4111  if (use_problem_dist)
4112  {
4113  dist_pt = new LinearAlgebraDistribution(Dof_distribution_pt);
4114  }
4115  else
4116  {
4117  dist_pt = new LinearAlgebraDistribution(uniform_dist_pt);
4118  }
4119  delete uniform_dist_pt;
4120  break;
4121  }
4122  }
4123 #else
4124  dist_pt = new LinearAlgebraDistribution(Communicator_pt, nrow, false);
4125 #endif
4126  }
4127 
4128 
4129  // The matrix is in compressed row format
4130  bool compressed_row_flag = true;
4131 
4132 #ifdef OOMPH_HAS_MPI
4133  //
4134  if (Communicator_pt->nproc() == 1)
4135  {
4136 #endif
4138  column_index, row_start, value, nnz, res, compressed_row_flag);
4139  jacobian.build(dist_pt);
4140  jacobian.build_without_copy(
4141  dist_pt->nrow(), nnz[0], value[0], column_index[0], row_start[0]);
4142  residuals.build(dist_pt, 0.0);
4143  residuals.set_external_values(res[0], true);
4144 #ifdef OOMPH_HAS_MPI
4145  }
4146  else
4147  {
4148  if (dist_pt->distributed())
4149  {
4150  parallel_sparse_assemble(
4151  dist_pt, column_index, row_start, value, nnz, res);
4152  jacobian.build(dist_pt);
4153  jacobian.build_without_copy(
4154  dist_pt->nrow(), nnz[0], value[0], column_index[0], row_start[0]);
4155  residuals.build(dist_pt, 0.0);
4156  residuals.set_external_values(res[0], true);
4157  }
4158  else
4159  {
4160  LinearAlgebraDistribution* temp_dist_pt =
4161  new LinearAlgebraDistribution(Communicator_pt, dist_pt->nrow(), true);
4162  parallel_sparse_assemble(
4163  temp_dist_pt, column_index, row_start, value, nnz, res);
4164  jacobian.build(temp_dist_pt);
4165  jacobian.build_without_copy(
4166  dist_pt->nrow(), nnz[0], value[0], column_index[0], row_start[0]);
4167  jacobian.redistribute(dist_pt);
4168  residuals.build(temp_dist_pt, 0.0);
4169  residuals.set_external_values(res[0], true);
4170  residuals.redistribute(dist_pt);
4171  delete temp_dist_pt;
4172  }
4173  }
4174 #endif
4175 
4176  // clean up dist_pt and residuals_vector pt
4177  delete dist_pt;
4178  }

References oomph::DoubleVector::build(), oomph::CRDoubleMatrix::build(), oomph::CRDoubleMatrix::build_without_copy(), oomph::DoubleVector::built(), Communicator_pt, oomph::LinearAlgebraDistribution::distributed(), oomph::DistributableLinearAlgebraObject::distribution_built(), oomph::DistributableLinearAlgebraObject::distribution_pt(), Dof_distribution_pt, ndof(), oomph::OomphCommunicator::nproc(), oomph::LinearAlgebraDistribution::nrow(), oomph::LinearAlgebraDistribution::nrow_local(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, p, oomph::DoubleVector::redistribute(), oomph::CRDoubleMatrix::redistribute(), res, oomph::DoubleVector::set_external_values(), sparse_assemble_row_or_column_compressed(), and Eigen::value.

◆ get_jacobian() [3/4]

void Problem::get_jacobian ( DoubleVector residuals,
DenseDoubleMatrix jacobian 
)
virtual

Return the fully-assembled Jacobian and residuals for the problem Interface for the case when the Jacobian matrix is dense. This is virtual so, if we feel like it (e.g. for testing iterative solvers with specific test matrices, we can bypass the default assembly procedure for the Jacobian and the residual vector.

Get the fully assembled residual vector and Jacobian matrix in dense storage. The DoubleVector residuals returned will be non-distributed. If on calling this method the DoubleVector residuals is setup then it must be non-distributed and of the correct length. The matrix type DenseDoubleMatrix is not distributable and therefore the residual vector is also assumed to be non distributable.

3892  {
3893  // get the number of degrees of freedom
3894  unsigned n_dof = ndof();
3895 
3896 #ifdef PARANOID
3897  // PARANOID checks : if the distribution of residuals is setup then it must
3898  // must not be distributed, have the right number of rows, and the same
3899  // communicator as the problem
3900  if (residuals.built())
3901  {
3902  if (residuals.distribution_pt()->distributed())
3903  {
3904  std::ostringstream error_stream;
3905  error_stream
3906  << "If the DoubleVector residuals is setup then it must not "
3907  << "be distributed.";
3908  throw OomphLibError(
3909  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3910  }
3911  if (residuals.distribution_pt()->nrow() != n_dof)
3912  {
3913  std::ostringstream error_stream;
3914  error_stream
3915  << "If the DoubleVector residuals is setup then it must have"
3916  << " the correct number of rows";
3917  throw OomphLibError(
3918  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3919  }
3920  if (!(*Communicator_pt ==
3921  *residuals.distribution_pt()->communicator_pt()))
3922  {
3923  std::ostringstream error_stream;
3924  error_stream
3925  << "If the DoubleVector residuals is setup then it must have"
3926  << " the same communicator as the problem.";
3927  throw OomphLibError(
3928  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3929  }
3930  }
3931 #endif
3932 
3933  // set the residuals distribution if it is not setup
3934  if (!residuals.built())
3935  {
3936  LinearAlgebraDistribution dist(Communicator_pt, n_dof, false);
3937  residuals.build(&dist, 0.0);
3938  }
3939  // else just zero the residuals
3940  else
3941  {
3942  residuals.initialise(0.0);
3943  }
3944 
3945  // Resize the matrices -- this cannot always be done externally
3946  // because get_jacobian exists in many different versions for
3947  // different storage formats -- resizing a CC or CR matrix doesn't
3948  // make sense.
3949 
3950  // resize the jacobian
3951  jacobian.resize(n_dof, n_dof);
3952  jacobian.initialise(0.0);
3953 
3954  // Locally cache pointer to assembly handler
3955  AssemblyHandler* const assembly_handler_pt = Assembly_handler_pt;
3956 
3957  // Loop over all the elements
3958  unsigned long n_element = Mesh_pt->nelement();
3959  for (unsigned long e = 0; e < n_element; e++)
3960  {
3961  // Get the pointer to the element
3962  GeneralisedElement* elem_pt = Mesh_pt->element_pt(e);
3963  // Find number of dofs in the element
3964  unsigned n_element_dofs = assembly_handler_pt->ndof(elem_pt);
3965  // Set up an array
3966  Vector<double> element_residuals(n_element_dofs);
3967  // Set up a matrix
3968  DenseMatrix<double> element_jacobian(n_element_dofs);
3969  // Fill the array
3971  elem_pt, element_residuals, element_jacobian);
3972  // Now loop over the dofs and assign values to global Vector
3973  for (unsigned l = 0; l < n_element_dofs; l++)
3974  {
3975  unsigned long eqn_number = assembly_handler_pt->eqn_number(elem_pt, l);
3976  residuals[eqn_number] += element_residuals[l];
3977  for (unsigned l2 = 0; l2 < n_element_dofs; l2++)
3978  {
3979  jacobian(eqn_number, assembly_handler_pt->eqn_number(elem_pt, l2)) +=
3980  element_jacobian(l, l2);
3981  }
3982  }
3983  }
3984  }

References Assembly_handler_pt, assembly_handler_pt(), oomph::DoubleVector::build(), oomph::DoubleVector::built(), oomph::LinearAlgebraDistribution::communicator_pt(), Communicator_pt, oomph::LinearAlgebraDistribution::distributed(), oomph::DistributableLinearAlgebraObject::distribution_pt(), e(), oomph::Mesh::element_pt(), oomph::AssemblyHandler::eqn_number(), oomph::AssemblyHandler::get_jacobian(), oomph::DoubleVector::initialise(), oomph::DenseMatrix< T >::initialise(), Mesh_pt, ndof(), oomph::AssemblyHandler::ndof(), oomph::Mesh::nelement(), oomph::LinearAlgebraDistribution::nrow(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and oomph::DenseMatrix< T >::resize().

Referenced by oomph::FpPressureAdvectionDiffusionProblem< ELEMENT >::get_pressure_advection_diffusion_jacobian(), oomph::NavierStokesSchurComplementPreconditioner::get_pressure_advection_diffusion_matrix(), main(), oomph::CG< MATRIX >::solve(), oomph::BiCGStab< MATRIX >::solve(), oomph::GS< MATRIX >::solve(), oomph::GS< CRDoubleMatrix >::solve(), oomph::DampedJacobi< MATRIX >::solve(), oomph::GMRES< MATRIX >::solve(), oomph::AugmentedProblemGMRES::solve(), oomph::DenseLU::solve(), oomph::SuperLUSolver::solve(), oomph::MumpsSolver::solve(), oomph::HelmholtzGMRESMG< MATRIX >::solve(), oomph::HelmholtzFGMRESMG< MATRIX >::solve(), oomph::HypreSolver::solve(), oomph::TrilinosAztecOOSolver::solve(), and oomph::SuperLUSolver::solve_transpose().

◆ get_jacobian() [4/4]

virtual void oomph::Problem::get_jacobian ( DoubleVector residuals,
SumOfMatrices jacobian 
)
inlinevirtual

Dummy virtual function that must be overloaded by the problem to specify which matrices should be summed to give the final Jacobian.

1880  {
1881  std::ostringstream error_stream;
1882  error_stream
1883  << "You must overload this function in your problem class to specify\n"
1884  << "which matrices should be summed to give the final Jacobian.";
1885  throw OomphLibError(
1886  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1887  }

References OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

◆ get_residuals()

void Problem::get_residuals ( DoubleVector residuals)
virtual

Get the total residuals Vector for the problem.

Return the fully-assembled residuals Vector for the problem: Virtual so it can be overloaded in for mpi problems

3715  {
3716  // Three different cases; if MPI_Helpers::MPI_has_been_initialised=true
3717  // this means MPI_Helpers::init() has been called. This could happen on a
3718  // code compiled with MPI but run serially; in this instance the
3719  // get_residuals function still works on one processor.
3720  //
3721  // Secondly, if a code has been compiled with MPI, but MPI_Helpers::init()
3722  // has not been called, then MPI_Helpers::MPI_has_been_initialised=false
3723  // and the code calls...
3724  //
3725  // Thirdly, the serial version (compiled by all, but only run when compiled
3726  // with MPI if MPI_Helpers::MPI_has_been_initialised=false
3727 
3728  // Check that the residuals has the correct number of rows if it has been
3729  // setup
3730 #ifdef PARANOID
3731  if (residuals.built())
3732  {
3733  if (residuals.distribution_pt()->nrow() != this->ndof())
3734  {
3735  std::ostringstream error_stream;
3736  error_stream << "The distribution of the residuals vector does not "
3737  "have the correct\n"
3738  << "number of global rows\n";
3739 
3740  throw OomphLibError(
3741  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3742  }
3743  }
3744 #endif
3745 
3746  // Find the number of rows
3747  const unsigned nrow = this->ndof();
3748 
3749  // Determine the distribution for the residuals vector
3750  // IF the vector has distribution setup then use that
3751  // ELSE determine the distribution based on the
3752  // distributed_matrix_distribution enum
3753  LinearAlgebraDistribution* dist_pt = 0;
3754  if (residuals.built())
3755  {
3756  dist_pt = new LinearAlgebraDistribution(residuals.distribution_pt());
3757  }
3758  else
3759  {
3760 #ifdef OOMPH_HAS_MPI
3761  // if problem is only one one processor assemble non-distributed
3762  // distribution
3763  if (Communicator_pt->nproc() == 1)
3764  {
3765  dist_pt = new LinearAlgebraDistribution(Communicator_pt, nrow, false);
3766  }
3767  // if the problem is not distributed then assemble the jacobian with
3768  // a uniform distributed distribution
3769  else if (!Problem_has_been_distributed)
3770  {
3771  dist_pt = new LinearAlgebraDistribution(Communicator_pt, nrow, true);
3772  }
3773  // otherwise the problem is a distributed problem
3774  else
3775  {
3776  switch (Dist_problem_matrix_distribution)
3777  {
3778  case Uniform_matrix_distribution:
3779  dist_pt =
3780  new LinearAlgebraDistribution(Communicator_pt, nrow, true);
3781  break;
3782  case Problem_matrix_distribution:
3783  dist_pt = new LinearAlgebraDistribution(Dof_distribution_pt);
3784  break;
3785  case Default_matrix_distribution:
3786  LinearAlgebraDistribution* uniform_dist_pt =
3787  new LinearAlgebraDistribution(Communicator_pt, nrow, true);
3788  bool use_problem_dist = true;
3789  unsigned nproc = Communicator_pt->nproc();
3790  for (unsigned p = 0; p < nproc; p++)
3791  {
3792  if ((double)Dof_distribution_pt->nrow_local(p) >
3793  ((double)uniform_dist_pt->nrow_local(p)) * 1.1)
3794  {
3795  use_problem_dist = false;
3796  }
3797  }
3798  if (use_problem_dist)
3799  {
3800  dist_pt = new LinearAlgebraDistribution(Dof_distribution_pt);
3801  }
3802  else
3803  {
3804  dist_pt = new LinearAlgebraDistribution(uniform_dist_pt);
3805  }
3806  delete uniform_dist_pt;
3807  break;
3808  }
3809  }
3810 #else
3811  dist_pt = new LinearAlgebraDistribution(Communicator_pt, nrow, false);
3812 #endif
3813  }
3814 
3815  // Locally cache pointer to assembly handler
3816  AssemblyHandler* const assembly_handler_pt = Assembly_handler_pt;
3817 
3818  // Build and zero the residuals
3819  residuals.build(dist_pt, 0.0);
3820 
3821  // Serial (or one processor case)
3822 #ifdef OOMPH_HAS_MPI
3823  if (this->communicator_pt()->nproc() == 1)
3824  {
3825 #endif // OOMPH_HAS_MPI
3826  // Loop over all the elements
3827  unsigned long Element_pt_range = Mesh_pt->nelement();
3828  for (unsigned long e = 0; e < Element_pt_range; e++)
3829  {
3830  // Get the pointer to the element
3831  GeneralisedElement* elem_pt = Mesh_pt->element_pt(e);
3832  // Find number of dofs in the element
3833  unsigned n_element_dofs = assembly_handler_pt->ndof(elem_pt);
3834  // Set up an array
3835  Vector<double> element_residuals(n_element_dofs);
3836  // Fill the array
3837  assembly_handler_pt->get_residuals(elem_pt, element_residuals);
3838  // Now loop over the dofs and assign values to global Vector
3839  for (unsigned l = 0; l < n_element_dofs; l++)
3840  {
3841  residuals[assembly_handler_pt->eqn_number(elem_pt, l)] +=
3842  element_residuals[l];
3843  }
3844  }
3845  // Otherwise parallel case
3846 #ifdef OOMPH_HAS_MPI
3847  }
3848  else
3849  {
3850  // Store the current assembly handler
3851  AssemblyHandler* const old_assembly_handler_pt = Assembly_handler_pt;
3852  // Create a new assembly handler that only assembles the residuals
3854  new ParallelResidualsHandler(old_assembly_handler_pt);
3855 
3856  // Setup memory for parallel sparse assemble
3857  // No matrix so all size zero
3858  Vector<int*> column_index;
3859  Vector<int*> row_start;
3860  Vector<double*> value;
3861  Vector<unsigned> nnz;
3862  // One set of residuals of sizer one
3863  Vector<double*> res(1);
3864 
3865  // Call the parallel sparse assemble, that should only assemble residuals
3866  parallel_sparse_assemble(
3867  dist_pt, column_index, row_start, value, nnz, res);
3868  // Fill in the residuals data
3869  residuals.set_external_values(res[0], true);
3870 
3871  // Delete new assembly handler
3872  delete Assembly_handler_pt;
3873  // Reset the assembly handler to the original
3874  Assembly_handler_pt = old_assembly_handler_pt;
3875  }
3876 #endif
3877 
3878  // Delete the distribution
3879  delete dist_pt;
3880  }
virtual void get_residuals(GeneralisedElement *const &elem_pt, Vector< double > &residuals)
Return the contribution to the residuals of the element elem_pt.
Definition: assembly_handler.cc:92

References Assembly_handler_pt, assembly_handler_pt(), oomph::DoubleVector::build(), oomph::DoubleVector::built(), Communicator_pt, communicator_pt(), oomph::DistributableLinearAlgebraObject::distribution_pt(), Dof_distribution_pt, e(), oomph::Mesh::element_pt(), oomph::AssemblyHandler::eqn_number(), oomph::AssemblyHandler::get_residuals(), Mesh_pt, ndof(), oomph::AssemblyHandler::ndof(), oomph::Mesh::nelement(), oomph::OomphCommunicator::nproc(), oomph::LinearAlgebraDistribution::nrow(), oomph::LinearAlgebraDistribution::nrow_local(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, p, res, oomph::DoubleVector::set_external_values(), and Eigen::value.

Referenced by get_derivative_wrt_global_parameter(), get_fd_jacobian(), get_inverse_mass_matrix_times_residuals(), globally_convergent_line_search(), newton_solve(), newton_solve_continuation(), oomph::UnsteadyHeatFluxPseudoMeltElement< ELEMENT >::plot_residual_landscape(), oomph::SegregatableFSIProblem::segregated_solve(), oomph::SolidICProblem::set_newmark_initial_condition_consistently(), oomph::BlockHopfLinearSolver::solve(), and oomph::BlockHopfLinearSolver::solve_for_two_rhs().

◆ global_data_pt()

Data*& oomph::Problem::global_data_pt ( const unsigned i)
inline

Return a pointer to the the i-th global data object.

1648  {
1649  return Global_data_pt[i];
1650  }

References Global_data_pt, and i.

Referenced by oomph::IMRByBDF::actions_after_timestep(), oomph::PeriodicOrbitAssemblyHandler< NNODE_1D >::adapt_temporal_mesh(), add_global_data(), CapProblem< ELEMENT >::CapProblem(), and copy().

◆ global_dof_pt()

double* oomph::Problem::global_dof_pt ( const unsigned i)
inline

Return a pointer to the dof, indexed by global equation number which may be haloed or stored locally. If it is haloed, a local copy must have been requested on this processor in the Halo_scheme_pt.

1765  {
1766 #ifdef OOMPH_HAS_MPI
1767  // If the problem is distributed I have to do something different
1768  if (Problem_has_been_distributed)
1769  {
1770 #ifdef PARANOID
1771  if (Halo_scheme_pt == 0)
1772  {
1773  std::ostringstream error_stream;
1774  error_stream
1775  << "Direct access to global dofs in a distributed problem is only\n"
1776  << "possible if the function setup_dof_halo_scheme() has been "
1777  "called.\n"
1778  << "You can access local dofs via Problem::dof(i).\n";
1779  throw OomphLibError(error_stream.str(),
1782  }
1783 #endif
1784 
1785  // Work out the local coordinate of the dof
1786  // based on the original distribution stored in the Halo_scheme
1787  const unsigned first_row_local =
1788  Halo_scheme_pt->distribution_pt()->first_row();
1789  const unsigned n_row_local =
1790  Halo_scheme_pt->distribution_pt()->nrow_local();
1791 
1792  // If we are in range then just call the local value
1793  if ((i >= first_row_local) && (i < first_row_local + n_row_local))
1794  {
1795  return this->Dof_pt[i - first_row_local];
1796  }
1797  // Otherwise the entry is not stored in the local processor
1798  // and we must have haloed it
1799  else
1800  {
1801  return Halo_dof_pt[Halo_scheme_pt->local_index(i)];
1802  }
1803  }
1804  // Otherwise just return the dof
1805  else
1806 #endif
1807  {
1808  return this->Dof_pt[i];
1809  }
1810  }

References oomph::DoubleVectorHaloScheme::distribution_pt(), oomph::LinearAlgebraDistribution::first_row(), i, oomph::DoubleVectorHaloScheme::local_index(), oomph::LinearAlgebraDistribution::nrow_local(), OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

Referenced by get_hessian_vector_products(), oomph::PitchForkHandler::get_jacobian(), and oomph::PitchForkHandler::get_residuals().

◆ global_temporal_error_norm()

virtual double oomph::Problem::global_temporal_error_norm ( )
inlineprotectedvirtual

Function to calculate a global error norm, used in adaptive timestepping to control the change in timestep. Individual errors for each data object can be obtained via the data timestepper's temporal_error_in_value or temporal_error_in_position functions and should be combined to construct a global norm. For example, in fluids problems a suitable norm is usually the weighted sum of the errors in the velocities; for moving mesh problems is it usually better to use the weighted sum of the errors in position.

Reimplemented in UnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, oomph::ODEProblem, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, RefineableUnsteadyHeatProblem< ELEMENT >, ContactProblem< ELEMENT >, UnsteadyHeatMeltProblem< ELEMENT >, SolarRadiationProblem< ELEMENT >, MeltContactProblem< ELEMENT >, VibratingShellProblem< ELEMENT >, and AxisymmetricVibratingShellProblem< ELEMENT >.

1231  {
1232  std::string error_message =
1233  "The global_temporal_error_norm function will be problem-specific:\n";
1234  error_message += "Please write your own in your Problem class";
1235 
1236  throw OomphLibError(
1238  return 0.0;
1239  }

References OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and oomph::Global_string_for_annotation::string().

Referenced by adaptive_unsteady_newton_solve().

◆ globally_convergent_line_search()

void Problem::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 
)
private

Line search helper for globally convergent Newton method.

Helper function for the globally convergent Newton solver.

9153  {
9154  const double min_fct_decrease = 1.0e-4;
9155  double convergence_tol_on_x = 1.0e-16;
9156  double f_aux = 0.0;
9157  double lambda_aux = 0.0;
9158  double proposed_lambda;
9159  unsigned long n_dof = ndof();
9160  double sum = 0.0;
9161  for (unsigned i = 0; i < n_dof; i++)
9162  {
9163  sum += newton_dir[i] * newton_dir[i];
9164  }
9165  sum = sqrt(sum);
9166  if (sum > stpmax)
9167  {
9168  for (unsigned i = 0; i < n_dof; i++)
9169  {
9170  newton_dir[i] *= stpmax / sum;
9171  }
9172  }
9173  double slope = 0.0;
9174  for (unsigned i = 0; i < n_dof; i++)
9175  {
9176  slope += gradient[i] * newton_dir[i];
9177  }
9178  if (slope >= 0.0)
9179  {
9180  std::ostringstream warn_message;
9181  warn_message << "WARNING: Non-negative slope, probably due to a "
9182  << " roundoff \nproblem in the linesearch: slope=" << slope
9183  << "\n";
9184  OomphLibWarning(warn_message.str(),
9185  "Problem::globally_convergent_line_search()",
9187  }
9188  double test = 0.0;
9189  for (unsigned i = 0; i < n_dof; i++)
9190  {
9191  double temp =
9192  std::fabs(newton_dir[i]) / std::max(std::fabs(x_old[i]), 1.0);
9193  if (temp > test) test = temp;
9194  }
9195  double lambda_min = convergence_tol_on_x / test;
9196  double lambda = 1.0;
9197  while (true)
9198  {
9199  for (unsigned i = 0; i < n_dof; i++)
9200  {
9201  *Dof_pt[i] = x_old[i] + lambda * newton_dir[i];
9202  }
9203 
9204  // Evaluate current residuals
9205  DoubleVector residuals;
9206  get_residuals(residuals);
9207  half_residual_squared = 0.0;
9208  for (unsigned i = 0; i < n_dof; i++)
9209  {
9210  half_residual_squared += residuals[i] * residuals[i];
9211  }
9212  half_residual_squared *= 0.5;
9213 
9214  if (lambda < lambda_min)
9215  {
9216  for (unsigned i = 0; i < n_dof; i++) *Dof_pt[i] = x_old[i];
9217 
9218  std::ostringstream warn_message;
9219  warn_message << "WARNING: Line search converged on x only!\n";
9220  OomphLibWarning(warn_message.str(),
9221  "Problem::globally_convergent_line_search()",
9223  return;
9224  }
9225  else if (half_residual_squared <=
9226  half_residual_squared_old + min_fct_decrease * lambda * slope)
9227  {
9228  oomph_info << "Returning from linesearch with lambda=" << lambda
9229  << std::endl;
9230  return;
9231  }
9232  else
9233  {
9234  if (lambda == 1.0)
9235  {
9236  proposed_lambda =
9237  -slope /
9238  (2.0 * (half_residual_squared - half_residual_squared_old - slope));
9239  }
9240  else
9241  {
9242  double r1 =
9243  half_residual_squared - half_residual_squared_old - lambda * slope;
9244  double r2 = f_aux - half_residual_squared_old - lambda_aux * slope;
9245  double a_poly =
9246  (r1 / (lambda * lambda) - r2 / (lambda_aux * lambda_aux)) /
9247  (lambda - lambda_aux);
9248  double b_poly = (-lambda_aux * r1 / (lambda * lambda) +
9249  lambda * r2 / (lambda_aux * lambda_aux)) /
9250  (lambda - lambda_aux);
9251  if (a_poly == 0.0)
9252  {
9253  proposed_lambda = -slope / (2.0 * b_poly);
9254  }
9255  else
9256  {
9257  double discriminant = b_poly * b_poly - 3.0 * a_poly * slope;
9258  if (discriminant < 0.0)
9259  {
9260  proposed_lambda = 0.5 * lambda;
9261  }
9262  else if (b_poly <= 0.0)
9263  {
9264  proposed_lambda = (-b_poly + sqrt(discriminant)) / (3.0 * a_poly);
9265  }
9266  else
9267  {
9268  proposed_lambda = -slope / (b_poly + sqrt(discriminant));
9269  }
9270  }
9271  if (proposed_lambda > 0.5 * lambda)
9272  {
9273  proposed_lambda = 0.5 * lambda;
9274  }
9275  }
9276  }
9277  lambda_aux = lambda;
9278  f_aux = half_residual_squared;
9279  lambda = std::max(proposed_lambda, 0.1 * lambda);
9280  }
9281  }
squared absolute sa ArrayBase::abs2 DOXCOMMA MatrixBase::cwiseAbs2 sa Eigen::abs2 DOXCOMMA Eigen::pow DOXCOMMA ArrayBase::square nearest sa Eigen::floor DOXCOMMA Eigen::ceil DOXCOMMA ArrayBase::round nearest integer not less than the given sa Eigen::floor DOXCOMMA ArrayBase::ceil not a number test
Definition: GlobalFunctions.h:109
Definition: indexed_view.cpp:20

References Dof_pt, boost::multiprecision::fabs(), get_residuals(), i, lambda, max, ndof(), OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, sqrt(), and Eigen::test.

Referenced by newton_solve().

◆ initialise_dt() [1/2]

void Problem::initialise_dt ( const double dt)

Set all timesteps to the same value, dt, and assign weights for all timesteppers in the problem

Set all timesteps to the same value, dt, and assign weights for all timesteppers in the problem.

13232  {
13233  // Initialise the timesteps in the Problem's time object
13234  Time_pt->initialise_dt(dt);
13235 
13236  // Find out how many timesteppers there are
13237  unsigned n_time_steppers = ntime_stepper();
13238 
13239  // Loop over them all and set the weights
13240  for (unsigned i = 0; i < n_time_steppers; i++)
13241  {
13243  if (time_stepper_pt(i)->adaptive_flag())
13244  {
13246  }
13247  }
13248  }
void initialise_dt(const double &dt_)
Set all timesteps to the same value, dt.
Definition: timesteppers.h:99

References i, oomph::Time::initialise_dt(), ntime_stepper(), oomph::TimeStepper::set_error_weights(), oomph::TimeStepper::set_weights(), Time_pt, and time_stepper_pt().

Referenced by assign_initial_values_impulsive(), FSIRingProblem::dynamic_run(), main(), OscRingNStProblem< ELEMENT >::OscRingNStProblem(), and read().

◆ initialise_dt() [2/2]

void Problem::initialise_dt ( const Vector< double > &  dt)

Set the value of the timesteps to be equal to the values passed in a vector and assign weights for all timesteppers in the problem

13255  {
13256  // Initialise the timesteps in the Problem's time object
13257  Time_pt->initialise_dt(dt);
13258 
13259  // Find out how many timesteppers there are
13260  unsigned n_time_steppers = ntime_stepper();
13261 
13262  // Loop over them all and set the weights
13263  for (unsigned i = 0; i < n_time_steppers; i++)
13264  {
13266  if (time_stepper_pt(i)->adaptive_flag())
13267  {
13269  }
13270  }
13271  }

References i, oomph::Time::initialise_dt(), ntime_stepper(), oomph::TimeStepper::set_error_weights(), oomph::TimeStepper::set_weights(), Time_pt, and time_stepper_pt().

◆ is_dparameter_calculated_analytically()

bool oomph::Problem::is_dparameter_calculated_analytically ( double *const &  parameter_pt)
inline

Function to determine whether the parameter derivatives are calculated analytically

279  {
280  // If the entry is found then the iterator returned from the find
281  // command will NOT be equal to the end and the expression will
282  // return true, otherwise it will return false
283  return (Calculate_dparameter_analytic.find(parameter_pt) !=
285  }
std::map< double *, bool > Calculate_dparameter_analytic
Definition: problem.h:239

References Calculate_dparameter_analytic.

Referenced by get_derivative_wrt_global_parameter().

◆ jacobian_reuse_is_enabled()

bool oomph::Problem::jacobian_reuse_is_enabled ( )
inline

Is recycling of Jacobian in Newton iteration enabled?

1990  {
1992  }

References Jacobian_reuse_is_enabled.

◆ linear_solver_pt() [1/2]

◆ linear_solver_pt() [2/2]

LinearSolver* const& oomph::Problem::linear_solver_pt ( ) const
inline

Return a pointer to the linear solver object (const version)

1473  {
1474  return Linear_solver_pt;
1475  }

References Linear_solver_pt.

◆ make_copy()

Problem * Problem::make_copy ( )
virtual

Make and return a pointer to the copy of the problem. A virtual function that must be filled in by the user is they wish to perform adaptive refinement in bifurcation tracking or in multigrid problems. ALH: WILL NOT BE NECESSARY IN BIFURCATION TRACKING IN LONG RUN...

Reimplemented in ABCProblem< ELEMENT, TIMESTEPPERT >, RefineablePorousChannelProblem< ELEMENT >, and FlowAroundCylinderProblem< ELEMENT >.

12012  {
12013  std::ostringstream error_stream;
12014  error_stream
12015  << "This function must be overloaded in your specific problem, and must\n"
12016  << "create an exact copy of your problem. Usually this will be achieved\n"
12017  << "by a call to the constructor with exactly the same arguments as "
12018  "used\n";
12019 
12020  throw OomphLibError(
12021  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
12022  }

References OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

Referenced by adapt(), and bifurcation_adapt_helper().

◆ mass_matrix_reuse_is_enabled()

bool oomph::Problem::mass_matrix_reuse_is_enabled ( )
inline

Return whether the mass matrix is being reused.

2569  {
2571  }

References Mass_matrix_reuse_is_enabled.

◆ mass_matrix_solver_for_explicit_timestepper_pt() [1/2]

LinearSolver*& oomph::Problem::mass_matrix_solver_for_explicit_timestepper_pt ( )
inline

Return a pointer to the linear solver object used for explicit time stepping.

1480  {
1482  }

References Mass_matrix_solver_for_explicit_timestepper_pt.

Referenced by get_inverse_mass_matrix_times_residuals().

◆ mass_matrix_solver_for_explicit_timestepper_pt() [2/2]

LinearSolver* oomph::Problem::mass_matrix_solver_for_explicit_timestepper_pt ( ) const
inline

Return a pointer to the linear solver object used for explicit time stepping (const version).

1487  {
1489  }

References Mass_matrix_solver_for_explicit_timestepper_pt.

◆ max_newton_iterations()

unsigned& oomph::Problem::max_newton_iterations ( )
inline

Access function to max Newton iterations before giving up.

1595  {
1596  return Max_newton_iterations;
1597  }

References Max_newton_iterations.

◆ max_residuals()

double& oomph::Problem::max_residuals ( )
inline

Access function to max residuals in Newton iterations before giving up.

1609  {
1610  return Max_residuals;
1611  }

References Max_residuals.

◆ maximum_dt()

double& oomph::Problem::maximum_dt ( )
inline

Access function to max timestep in adaptive timestepping.

1589  {
1590  return Maximum_dt;
1591  }

References Maximum_dt.

◆ mesh_pt() [1/4]

Mesh*& oomph::Problem::mesh_pt ( )
inline

Return a pointer to the global mesh.

1281  {
1282  return Mesh_pt;
1283  }

References Mesh_pt.

Referenced by oomph::IMRByBDF::actions_after_timestep(), oomph::RefineableTetgenMesh< ELEMENT >::adapt(), oomph::RefineableGmshTetMesh< ELEMENT >::adapt(), adapt(), adapt_based_on_error_estimates(), oomph::PeriodicOrbitAssemblyHandler< NNODE_1D >::adapt_temporal_mesh(), add_sub_mesh(), assign_eqn_numbers(), oomph::SolidICProblem::backup_original_state(), bifurcation_adapt_helper(), BoussinesqPreconditioner::BoussinesqPreconditioner(), AdvectionProblem::compute_error(), TwoDDGProblem< ELEMENT >::compute_error(), ContinuationProblem::ContinuationProblem(), ContProblem< ELEMENT >::ContProblem(), copy(), delete_all_external_storage(), DGProblem< ELEMENT >::DGProblem(), disable_mass_matrix_reuse(), doc_errors(), oomph::FpPressureAdvectionDiffusionProblem< ELEMENT >::doc_solution(), dump(), oomph::ODEProblem::element_pt(), enable_mass_matrix_reuse(), oomph::ODEProblem::exact_solution(), oomph::SegregatableFSIProblem::extrapolate_solid_data(), FluxPoissonProblem< ELEMENT >::FluxPoissonProblem(), oomph::FoldHandler::FoldHandler(), oomph::FpPressureAdvectionDiffusionProblem< ELEMENT >::FpPressureAdvectionDiffusionProblem(), get_all_error_estimates(), get_dofs(), get_hessian_vector_products(), get_inverse_mass_matrix_times_residuals(), oomph::NavierStokesSchurComplementPreconditioner::get_pressure_advection_diffusion_matrix(), oomph::FoldHandler::get_residuals(), oomph::HopfHandler::get_residuals(), oomph::ODEProblem::global_temporal_error_norm(), oomph::HopfHandler::HopfHandler(), InterfaceProblem< ELEMENT, TIMESTEPPER >::InterfaceProblem(), FlowAroundCylinderProblem< ELEMENT >::mesh_pt(), RefineablePorousChannelProblem< ELEMENT >::mesh_pt(), TwoDDGProblem< ELEMENT >::mesh_pt(), RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >::mesh_pt(), ConvectionProblem< NST_ELEMENT, AD_ELEMENT >::mesh_pt(), ThermalProblem< ELEMENT >::mesh_pt(), oomph::StreamfunctionProblem::mesh_pt(), TestPoissonProblem< ELEMENT >::mesh_pt(), TestRefineablePoissonProblem< ELEMENT >::mesh_pt(), oomph::ODEProblem::my_set_initial_condition(), OneDPoissonProblem< ELEMENT >::OneDPoissonProblem(), oomph::LinearElasticitySmoothMesh< LINEAR_ELASTICITY_ELEMENT >::operator()(), oomph::PoissonSmoothMesh< POISSON_ELEMENT >::operator()(), oomph::PeriodicOrbitAssemblyHandler< NNODE_1D >::orbit_output(), OrrSommerfeldProblem< ELEMENT >::OrrSommerfeldProblem(), p_adapt(), p_refine_selected_elements(), p_refine_uniformly(), p_refine_uniformly_aux(), p_unrefine_uniformly(), oomph::METIS::partition_mesh(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::pin_all(), oomph::FpPressureAdvectionDiffusionProblem< ELEMENT >::pin_all_non_pressure_dofs(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::pin_dofs_of_coordinate(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::pin_dofs_of_field(), oomph::PitchForkHandler::PitchForkHandler(), print_connectivity_matrix(), print_elemental_jacobian(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::project(), QFaceTestProblem< ELEMENT >::QFaceTestProblem(), QuarterCircleDrivenCavityProblem< ELEMENT >::QuarterCircleDrivenCavityProblem(), QuarterCircleDrivenCavityProblem2< ELEMENT >::QuarterCircleDrivenCavityProblem2(), read(), refine_selected_elements(), refine_uniformly(), refine_uniformly_aux(), RefineablePorousChannelProblem< ELEMENT >::RefineablePorousChannelProblem(), oomph::HSL_MA42::reorder_elements(), oomph::SolidICProblem::reset_original_state(), oomph::FpPressureAdvectionDiffusionProblem< ELEMENT >::reset_pin_status(), oomph::AugmentedBlockFoldLinearSolver::resolve(), oomph::AugmentedBlockPitchForkLinearSolver::resolve(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::restore_positions(), self_test(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::set_coordinate_for_projection(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::set_current_field_for_projection(), set_dofs(), AdvectionProblem::set_initial_conditions(), EulerProblem::set_initial_conditions(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::set_lagrangian_coordinate_for_projection(), oomph::SolidICProblem::set_newmark_initial_condition_consistently(), oomph::SolidICProblem::set_newmark_initial_condition_directly(), oomph::SolidICProblem::set_static_initial_condition(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::set_time_level_for_projection(), setup_element_count_per_dof(), oomph::SolidICProblem::setup_problem(), oomph::SegregatableFSIProblem::setup_segregated_solver(), oomph::SolidICProblem::SolidICProblem(), oomph::ODEProblem::solution(), oomph::AugmentedBlockFoldLinearSolver::solve(), oomph::AugmentedBlockPitchForkLinearSolver::solve(), oomph::BlockHopfLinearSolver::solve(), oomph::HSL_MA42::solve(), oomph::MGSolver< DIM >::solve(), oomph::HelmholtzGMRESMG< MATRIX >::solve(), oomph::HelmholtzFGMRESMG< MATRIX >::solve(), oomph::HSL_MA42::solve_for_one_dof(), oomph::BlockHopfLinearSolver::solve_for_two_rhs(), sparse_assemble_row_or_column_compressed_with_lists(), sparse_assemble_row_or_column_compressed_with_maps(), sparse_assemble_row_or_column_compressed_with_two_arrays(), sparse_assemble_row_or_column_compressed_with_two_vectors(), sparse_assemble_row_or_column_compressed_with_vectors_of_pairs(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::store_positions(), oomph::StreamfunctionProblem::StreamfunctionProblem(), TFaceTestProblem< ELEMENT >::TFaceTestProblem(), ThermalProblem< ELEMENT >::ThermalProblem(), TriangleFaceTestProblem< ELEMENT >::TriangleFaceTestProblem(), TurekProblem< FLUID_ELEMENT, SOLID_ELEMENT >::TurekProblem(), TwoDDGProblem< ELEMENT >::TwoDDGProblem(), oomph::METIS::uniform_partition_mesh(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::unpin_all(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::unpin_dofs_of_coordinate(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::unpin_dofs_of_field(), unrefine_uniformly(), oomph::FpPressureAdvectionDiffusionProblem< ELEMENT >::validate(), oomph::WomersleyProblem< ELEMENT, DIM >::WomersleyProblem(), AdvectionProblem::~AdvectionProblem(), EulerProblem::~EulerProblem(), RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >::~RefineableConvectionProblem(), and TwoDDGProblem< ELEMENT >::~TwoDDGProblem().

◆ mesh_pt() [2/4]

Mesh* const& oomph::Problem::mesh_pt ( ) const
inline

Return a pointer to the global mesh (const version)

1287  {
1288  return Mesh_pt;
1289  }

References Mesh_pt.

◆ mesh_pt() [3/4]

Mesh*& oomph::Problem::mesh_pt ( const unsigned imesh)
inline

Return a pointer to the i-th submesh. If there are no submeshes, the 0-th submesh is the global mesh itself.

1294  {
1295  // If there are no submeshes then the zero-th submesh is the
1296  // mesh itself
1297  if ((Sub_mesh_pt.size() == 0) && (imesh == 0))
1298  {
1299  return Mesh_pt;
1300  }
1301  else
1302  {
1303  return Sub_mesh_pt[imesh];
1304  }
1305  }

References Mesh_pt, and Sub_mesh_pt.

◆ mesh_pt() [4/4]

Mesh* const& oomph::Problem::mesh_pt ( const unsigned imesh) const
inline

Return a pointer to the i-th submesh (const version)

1309  {
1310  // If there are no submeshes then the zero-th submesh is the
1311  // mesh itself
1312  if ((Sub_mesh_pt.size() == 0) && (imesh == 0))
1313  {
1314  return Mesh_pt;
1315  }
1316  else
1317  {
1318  return Sub_mesh_pt[imesh];
1319  }
1320  }

References Mesh_pt, and Sub_mesh_pt.

◆ minimum_dt()

double& oomph::Problem::minimum_dt ( )
inline

Access function to min timestep in adaptive timestepping.

1583  {
1584  return Minimum_dt;
1585  }

References Minimum_dt.

◆ ndof()

unsigned long oomph::Problem::ndof ( ) const
inline

Return the number of dofs.

1675  {
1676  return Dof_distribution_pt->nrow();
1677  }
unsigned nrow() const
access function to the number of global rows.
Definition: linear_algebra_distribution.h:186

References Dof_distribution_pt, and oomph::LinearAlgebraDistribution::nrow().

Referenced by oomph::IMRByBDF::actions_after_timestep(), oomph::IMRByBDF::actions_before_timestep(), adapt(), add_eigenvector_to_dofs(), add_to_dofs(), assign_eigenvector_to_dofs(), bifurcation_adapt_helper(), oomph::ODEProblem::build(), calculate_continuation_derivatives(), calculate_predictions(), oomph::FoldHandler::FoldHandler(), get_dofs(), get_eigenproblem_matrices(), get_fd_jacobian(), get_inverse_mass_matrix_times_residuals(), get_jacobian(), get_residuals(), globally_convergent_line_search(), oomph::HopfHandler::HopfHandler(), newton_solve(), parallel_test(), oomph::PitchForkHandler::PitchForkHandler(), oomph::MGPreconditioner< DIM >::preconditioner_solve(), oomph::HSL_MA42::reorder_elements(), oomph::AugmentedBlockFoldLinearSolver::resolve(), oomph::AugmentedBlockPitchForkLinearSolver::resolve(), restore_dof_values(), set_dofs(), oomph::AugmentedBlockFoldLinearSolver::solve(), oomph::AugmentedBlockPitchForkLinearSolver::solve(), oomph::BlockHopfLinearSolver::solve(), oomph::HSL_MA42::solve(), oomph::GS< MATRIX >::solve(), oomph::GS< CRDoubleMatrix >::solve(), oomph::DampedJacobi< MATRIX >::solve(), oomph::GMRES< MATRIX >::solve(), oomph::AugmentedProblemGMRES::solve(), oomph::DenseLU::solve(), oomph::FD_LU::solve(), oomph::SuperLUSolver::solve(), oomph::MumpsSolver::solve(), oomph::HelmholtzGMRESMG< MATRIX >::solve(), oomph::HelmholtzFGMRESMG< MATRIX >::solve(), oomph::ARPACK::solve_eigenproblem(), oomph::LAPACK_QZ::solve_eigenproblem(), oomph::HSL_MA42::solve_for_one_dof(), oomph::BlockHopfLinearSolver::solve_for_two_rhs(), oomph::SuperLUSolver::solve_transpose(), sparse_assemble_row_or_column_compressed_with_lists(), sparse_assemble_row_or_column_compressed_with_maps(), sparse_assemble_row_or_column_compressed_with_two_arrays(), sparse_assemble_row_or_column_compressed_with_two_vectors(), sparse_assemble_row_or_column_compressed_with_vectors_of_pairs(), and store_current_dof_values().

◆ newton_solve() [1/2]

void Problem::newton_solve ( )

Use Newton method to solve the problem.

General Newton solver. Requires only a convergence tolerance. The linear solver takes a pointer to the problem (which defines the Jacobian J and the residual Vector r) and returns the solution x of the system

\[ {\bf J} {\bf x} = - \bf{r} \]

.

8784  {
8785  // Initialise timers
8786  double total_linear_solver_time = 0.0;
8787  double t_start = TimingHelpers::timer();
8788  Max_res.clear();
8789 
8790  // Find total number of dofs
8791  unsigned long n_dofs = ndof();
8792 
8793  // Set up the Vector to hold the solution
8794  DoubleVector dx;
8795 
8796  //-----Variables for the globally convergent Newton method------
8797 
8798  // Set up the vector to hold the gradient
8799  DoubleVector gradient;
8800 
8801  // Other variables
8802  double half_residual_squared = 0.0;
8803  double max_step = 0.0;
8804 
8805  //--------------------------------------------------------------
8806 
8807  // Set the counter
8808  unsigned count = 0;
8809  // Set the loop flag
8810  unsigned LOOP_FLAG = 1;
8811 
8813  {
8814 #ifdef OOMPH_HAS_MPI
8815  // Break if running in parallel
8817  {
8818  std::ostringstream error_stream;
8819  error_stream << "Globally convergent Newton method has not been "
8820  << "implemented in parallel yet!" << std::endl;
8821  throw OomphLibError(
8822  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
8823  }
8824 #endif
8825 
8826  // Get gradient
8828  // Reset the gradient (clear it), since the number of dofs and
8829  // hence the size of the DoubleVector might have changed
8831  }
8832 
8833  // Update anything that needs updating
8835 
8836  // Reset number of Newton iterations taken
8837  Nnewton_iter_taken = 0;
8838 
8839  // Now do the Newton loop
8840  do
8841  {
8842  count++;
8843 
8844  // Do any updates that are required
8846 
8847 
8848  // No degrees of freedom? What are you solving for?
8849  if (n_dofs == 0)
8850  {
8851  oomph_info << std::endl << std::endl << std::endl;
8852  oomph_info << "This is a bit bizarre: The problem has no dofs."
8853  << std::endl;
8854  oomph_info
8855  << "I'll just return from the Newton solver without doing anything."
8856  << std::endl;
8857 
8858  // Do any updates that would have been performed
8863 
8864  oomph_info << "I hope this is what you intended me to do..."
8865  << std::endl;
8866  oomph_info << std::endl
8867  << "Note: All actions_...() functions were called"
8868  << std::endl;
8869  oomph_info << std::endl << " before returning." << std::endl;
8870  oomph_info << std::endl << std::endl << std::endl;
8871  return;
8872  }
8873 
8874  // Calculate initial residuals
8875  if (count == 1)
8876  {
8877  // Is the problem nonlinear? If not ignore the pre-iteration
8878  // convergence check.
8880  {
8881 #ifdef OOMPH_HAS_MPI
8882  // Synchronise the solution on different processors (on each submesh)
8883  this->synchronise_all_dofs();
8884 #endif
8885 
8887  dx.clear();
8888  get_residuals(dx);
8889 
8890  // Get half of squared residual and find maximum step length
8891  // for step length control
8893  {
8894  half_residual_squared = 0.0;
8895  double sum = 0.0;
8896  for (unsigned i = 0; i < n_dofs; i++)
8897  {
8898  sum += (*Dof_pt[i]) * (*Dof_pt[i]);
8899  half_residual_squared += dx[i] * dx[i];
8900  }
8901  half_residual_squared *= 0.5;
8902  max_step = 100.0 * std::max(sqrt(sum), double(n_dofs));
8903  }
8904 
8905  // Get maximum residuals
8906  double maxres = dx.max();
8907  Max_res.push_back(maxres);
8908 
8910  {
8911  // Let's output the residuals
8912  // unsigned n_row_local = dx.distribution_pt()->nrow_local();
8913  // unsigned first_row = dx.distribution_pt()->first_row();
8914  // for(unsigned n=0;n<n_row_local;n++)
8915  //{
8916  // oomph_info << "residual: " << n + first_row << " " << dx[n] <<
8917  // "\n";
8918  //}
8919 
8920  oomph_info << "\nInitial Maximum residuals " << maxres << std::endl;
8921  }
8922 
8923  if ((maxres < Newton_solver_tolerance) &&
8925  {
8926  LOOP_FLAG = 0;
8927  continue;
8928  }
8929  }
8930  else
8931  {
8933  {
8934  oomph_info
8935  << "Linear problem -- convergence in one iteration assumed."
8936  << std::endl;
8937  }
8938  }
8939  }
8940 
8941 
8942  // Increment number of Newton iterations taken
8944 
8945  // Initialise timer for linear solver
8946  double t_solver_start = TimingHelpers::timer();
8947 
8948  // Now do the linear solve -- recycling Jacobian if requested
8950  {
8952  {
8953  oomph_info << "Not recomputing Jacobian! " << std::endl;
8954  }
8955 
8956  // If we're doing the first iteration and the problem is nonlinear,
8957  // the residuals have already been computed above during the
8958  // initial convergence check. Otherwise compute them here.
8959  if ((count != 1) || (!Problem_is_nonlinear)) get_residuals(dx);
8960 
8961  // Backup residuals
8962  DoubleVector resid(dx);
8963 
8964  // Resolve
8965  Linear_solver_pt->resolve(resid, dx);
8966  }
8967  else
8968  {
8970  {
8972  {
8973  oomph_info << "Enabling resolve" << std::endl;
8974  }
8976  }
8977  Linear_solver_pt->solve(this, dx);
8979  }
8980 
8981  // End of linear solver
8982  double t_solver_end = TimingHelpers::timer();
8983  total_linear_solver_time += t_solver_end - t_solver_start;
8984 
8986  {
8987  oomph_info << std::endl;
8988  oomph_info << "Time for linear solver (ndof=" << n_dofs << "): "
8990  t_solver_end - t_solver_start)
8991  << std::endl
8992  << std::endl;
8993  }
8994 
8995  // Subtract the new values from the true dofs
8996  dx.redistribute(Dof_distribution_pt);
8997  double* dx_pt = dx.values_pt();
8998  unsigned ndof_local = Dof_distribution_pt->nrow_local();
8999 
9001  {
9002  // Get the gradient
9003  Linear_solver_pt->get_gradient(gradient);
9004 
9005  for (unsigned i = 0; i < ndof_local; i++)
9006  {
9007  dx_pt[i] *= -1.0;
9008  }
9009 
9010  // Update with steplength control
9011  Vector<double> unknowns_old(ndof_local);
9012 
9013  for (unsigned i = 0; i < ndof_local; i++)
9014  {
9015  unknowns_old[i] = *Dof_pt[i];
9016  }
9017 
9018  double half_residual_squared_old = half_residual_squared;
9019  globally_convergent_line_search(unknowns_old,
9020  half_residual_squared_old,
9021  gradient,
9022  dx,
9023  half_residual_squared,
9024  max_step);
9025  }
9026  // direct Newton update
9027  else
9028  {
9029  for (unsigned l = 0; l < ndof_local; l++)
9030  {
9031  *Dof_pt[l] -= Relaxation_factor * dx_pt[l];
9032  }
9033  }
9034 #ifdef OOMPH_HAS_MPI
9035  // Synchronise the solution on different processors (on each submesh)
9036  this->synchronise_all_dofs();
9037 #endif
9038 
9039  // Do any updates that are required
9042 
9043  // Maximum residuals
9044  double maxres = 0.0;
9045  // If the user has declared that the Problem is linear
9046  // we ignore the convergence check
9048  {
9049  // Get the maximum residuals
9050  // maxres = std::fabs(*std::max_element(dx.begin(),dx.end(),
9051  // AbsCmp<double>()));
9052  // oomph_info << "Maxres correction " << maxres << "\n";
9053 
9054  // Calculate the new residuals
9055  dx.clear();
9056  get_residuals(dx);
9057 
9058  // Get the maximum residuals
9059  maxres = dx.max();
9060  Max_res.push_back(maxres);
9061 
9063  {
9064  oomph_info << "Newton Step " << count << ": Maximum residuals "
9065  << maxres << std::endl
9066  << std::endl;
9067  }
9068  }
9069 
9070  // If we have converged jump straight to the test at the end of the loop
9071  if (maxres < Newton_solver_tolerance)
9072  {
9073  LOOP_FLAG = 0;
9074  continue;
9075  }
9076 
9077  // This section will not be reached if we have converged already
9078  // If the maximum number of residuals is too high or the maximum number
9079  // of iterations has been reached
9080  if ((maxres > Max_residuals) || (count == Max_newton_iterations))
9081  {
9082  // Print a warning -- regardless of what the throw does
9083  if (maxres > Max_residuals)
9084  {
9085  oomph_info << "Max. residual (" << Max_residuals
9086  << ") has been exceeded in Newton solver." << std::endl;
9087  }
9088  if (count == Max_newton_iterations)
9089  {
9090  oomph_info << "Reached max. number of iterations ("
9091  << Max_newton_iterations << ") in Newton solver."
9092  << std::endl;
9093  }
9094  // Now throw...
9095  throw NewtonSolverError(count, maxres);
9096  }
9097 
9098  } while (LOOP_FLAG);
9099 
9100  // Now update anything that needs updating
9102 
9103  // Finalise/doc timings
9105  {
9106  oomph_info << std::endl;
9107  oomph_info << "Total time for linear solver (ndof=" << n_dofs << "): "
9109  total_linear_solver_time)
9110  << std::endl;
9111  }
9112 
9113  double t_end = TimingHelpers::timer();
9114  double total_time = t_end - t_start;
9115 
9117  {
9118  oomph_info << "Total time for Newton solver (ndof=" << n_dofs << "): "
9120  << std::endl;
9121  }
9122  if (total_time > 0.0)
9123  {
9125  {
9126  oomph_info << "Time outside linear solver : "
9127  << (total_time - total_linear_solver_time) / total_time *
9128  100.0
9129  << " %" << std::endl;
9130  }
9131  }
9132  else
9133  {
9135  {
9136  oomph_info << "Time outside linear solver : "
9137  << "[too fast]" << std::endl;
9138  }
9139  }
9140  if (!Shut_up_in_newton_solve) oomph_info << std::endl;
9141  }
virtual void enable_computation_of_gradient()
Definition: linear_solver.h:282
void get_gradient(DoubleVector &gradient)
function to access the gradient, provided it has been computed
Definition: linear_solver.h:306
void reset_gradient()
Definition: linear_solver.h:300
virtual void actions_before_newton_step()
Definition: problem.h:1053
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.
Definition: problem.cc:9146
Vector< double > Max_res
Maximum residuals at start and after each newton iteration.
Definition: problem.h:606
std::string convert_secs_to_formatted_string(const double &time_in_sec)
Definition: oomph_utilities.cc:1316

References actions_after_newton_solve(), actions_after_newton_step(), actions_before_newton_convergence_check(), actions_before_newton_solve(), actions_before_newton_step(), Always_take_one_newton_step, oomph::DoubleVector::clear(), oomph::TimingHelpers::convert_secs_to_formatted_string(), Dof_distribution_pt, Dof_pt, oomph::LinearSolver::enable_computation_of_gradient(), oomph::LinearSolver::enable_resolve(), oomph::LinearSolver::get_gradient(), get_residuals(), globally_convergent_line_search(), i, Jacobian_has_been_computed, Jacobian_reuse_is_enabled, Linear_solver_pt, oomph::DoubleVector::max(), max, Max_newton_iterations, Max_res, Max_residuals, oomph::MPI_Helpers::mpi_has_been_initialised(), ndof(), Newton_solver_tolerance, Nnewton_iter_taken, oomph::LinearAlgebraDistribution::nrow_local(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, Problem_is_nonlinear, oomph::DoubleVector::redistribute(), Relaxation_factor, oomph::LinearSolver::reset_gradient(), oomph::LinearSolver::resolve(), Shut_up_in_newton_solve, oomph::LinearSolver::solve(), sqrt(), oomph::TimingHelpers::timer(), Use_globally_convergent_newton_method, and oomph::DoubleVector::values_pt().

Referenced by adaptive_unsteady_newton_solve(), main(), newton_solve(), oomph::NonLinearElasticitySmoothMesh< ELEMENT >::operator()(), oomph::LinearElasticitySmoothMesh< LINEAR_ELASTICITY_ELEMENT >::operator()(), oomph::PoissonSmoothMesh< POISSON_ELEMENT >::operator()(), PolarNSProblem< ELEMENT >::output_streamfunction(), parallel_test(), ElasticBeamProblem::parameter_study(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::project(), oomph::SegregatableFSIProblem::segregated_solve(), oomph::SolidICProblem::set_newmark_initial_condition_consistently(), oomph::SolidICProblem::set_newmark_initial_condition_directly(), oomph::SolidICProblem::set_static_initial_condition(), steady_newton_solve(), unsteady_newton_solve(), and oomph::FpPressureAdvectionDiffusionProblem< ELEMENT >::validate().

◆ newton_solve() [2/2]

void Problem::newton_solve ( unsigned const &  max_adapt)

Adaptive Newton solve: up to max_adapt adaptations of all refineable submeshes are performed to achieve the the error targets specified in the refineable submeshes.

Adaptive Newton solver. The linear solver takes a pointer to the problem (which defines the Jacobian J and the residual Vector r) and returns the solution x of the system

\[ {\bf J} {\bf x} = - \bf{r} \]

. Performs at most max_adapt adaptations on all meshes.

16224  {
16225  // Max number of solves
16226  unsigned max_solve = max_adapt + 1;
16227 
16228  // Adaptation loop
16229  //----------------
16230  for (unsigned isolve = 0; isolve < max_solve; isolve++)
16231  {
16232  // Only adapt after the first solve has been done!
16233  if (isolve > 0)
16234  {
16235  unsigned n_refined;
16236  unsigned n_unrefined;
16237 
16238  // Adapt problem
16239  adapt(n_refined, n_unrefined);
16240 
16241 #ifdef OOMPH_HAS_MPI
16242  // Adaptation only converges if ALL the processes have no
16243  // refinement or unrefinement to perform
16244  unsigned total_refined = 0;
16245  unsigned total_unrefined = 0;
16246  if (Problem_has_been_distributed)
16247  {
16248  MPI_Allreduce(&n_refined,
16249  &total_refined,
16250  1,
16251  MPI_UNSIGNED,
16252  MPI_SUM,
16253  this->communicator_pt()->mpi_comm());
16254  n_refined = total_refined;
16255  MPI_Allreduce(&n_unrefined,
16256  &total_unrefined,
16257  1,
16258  MPI_UNSIGNED,
16259  MPI_SUM,
16260  this->communicator_pt()->mpi_comm());
16261  n_unrefined = total_unrefined;
16262  }
16263 #endif
16264 
16265  oomph_info << "---> " << n_refined << " elements were refined, and "
16266  << n_unrefined << " were unrefined"
16267 #ifdef OOMPH_HAS_MPI
16268  << ", in total (over all processors).\n";
16269 #else
16270  << ".\n";
16271 #endif
16272 
16273 
16274  // Check convergence of adaptation cycle
16275  if ((n_refined == 0) && (n_unrefined == 0))
16276  {
16277  oomph_info << "\n \n Solution is fully converged in "
16278  << "Problem::newton_solver(). \n \n ";
16279  break;
16280  }
16281  }
16282 
16283 
16284  // Do actual solve
16285  //----------------
16286  {
16287  // Now update anything that needs updating
16288  // NOT NEEDED -- IS CALLED IN newton_solve BELOW! #
16289  // actions_before_newton_solve();
16290 
16291  try
16292  {
16293  // Solve the non-linear problem for this timestep with Newton's method
16294  newton_solve();
16295  }
16296  // Catch any exceptions thrown in the Newton solver
16297  catch (NewtonSolverError& error)
16298  {
16299  oomph_info << std::endl
16300  << "USER-DEFINED ERROR IN NEWTON SOLVER " << std::endl;
16301  // Check to see whether we have reached Max_iterations
16302  if (error.iterations == Max_newton_iterations)
16303  {
16304  oomph_info << "MAXIMUM NUMBER OF ITERATIONS (" << error.iterations
16305  << ") REACHED WITHOUT CONVERGENCE " << std::endl;
16306  }
16307  // If not, it must be that we have exceeded the maximum residuals
16308  else
16309  {
16310  oomph_info << "MAXIMUM RESIDUALS: " << error.maxres
16311  << "EXCEEDS PREDEFINED MAXIMUM " << Max_residuals
16312  << std::endl;
16313  }
16314 
16315  // Die horribly!!
16316  std::ostringstream error_stream;
16317  error_stream << "Error occured in adaptive Newton solver. "
16318  << std::endl;
16319  throw OomphLibError(error_stream.str(),
16322  }
16323 
16324  // Now update anything that needs updating
16325  // NOT NEEDED -- WAS CALLED IN newton_solve ABOVE
16326  // !actions_after_newton_solve();
16327 
16328  } // End of solve block
16329 
16330 
16331  if (isolve == max_solve - 1)
16332  {
16333  oomph_info
16334  << std::endl
16335  << "----------------------------------------------------------"
16336  << std::endl
16337  << "Reached max. number of adaptations in \n"
16338  << "Problem::newton_solver().\n"
16339  << "----------------------------------------------------------"
16340  << std::endl
16341  << std::endl;
16342  }
16343 
16344  } // End of adaptation loop
16345  }

References adapt(), communicator_pt(), calibrate::error, Max_newton_iterations, Max_residuals, newton_solve(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and oomph::oomph_info.

◆ newton_solve_continuation() [1/2]

unsigned Problem::newton_solve_continuation ( double *const &  parameter_pt)
protected

Perform a basic arc-length continuation step using Newton's method. Returns number of Newton steps taken.

Perform a basic continuation step using Newton's method. The governing parameter of the problem is passed as a pointer to the routine. The number of Newton steps taken is returned

9377  {
9378  // Set up memory for z
9379  // unsigned long n_dofs = ndof();
9380  // LinearAlgebraDistribution dist(Communicator_pt,n_dofs,false);
9381  // DoubleVector z(&dist,0.0);
9382  DoubleVector z;
9383  // Call the solver
9384  return newton_solve_continuation(parameter_pt, z);
9385  }

Referenced by arc_length_step_solve_helper().

◆ newton_solve_continuation() [2/2]

unsigned Problem::newton_solve_continuation ( double *const &  parameter_pt,
DoubleVector z 
)
protected

This function performs a basic continuation step using the Newton method. The number of Newton steps taken is returned, to be used in any external step-size control routines. The governing parameter of the problem is passed as a pointer to the routine, as is a vector in which to store the derivatives wrt the parameter, if required.

This function performs a basic continuation step using the Newton method. The number of Newton steps taken is returned, to be used in any external step-size control routines. The governing parameter of the problem is passed as a pointer to the routine, as is the sign of the Jacobian and a Vector in which to store the derivatives wrt the parameter, if required.

9398  {
9399  // Find the total number of dofs
9400  // unsigned long n_dofs = ndof();
9401 
9402  // Find the local number of dofs
9403  unsigned ndof_local = Dof_distribution_pt->nrow_local();
9404 
9405  // create the distribution (not distributed)
9406  // LinearAlgebraDistribution dist(this->communicator_pt(),n_dofs,false);
9407 
9408  // Assign memory for solutions of the equations
9409  // DoubleVector y(&dist,0.0);
9410  DoubleVector y;
9411 
9412  // Assign memory for the dot products of the uderivatives and y and z
9413  double uderiv_dot_y = 0.0, uderiv_dot_z = 0.0;
9414  // Set and initialise the counter
9415  unsigned count = 0;
9416  // Set the loop flag
9417  unsigned LOOP_FLAG = 1;
9418 
9419  // Update anything that needs updating
9421 
9422  // Check the arc-length constraint
9423  double arc_length_constraint_residual = 0.0;
9424 
9425  // Are we storing the matrix in the linear solve
9426  bool enable_resolve = Linear_solver_pt->is_resolve_enabled();
9427 
9428  // For this problem, we must store the residuals
9430 
9431  // Now do the Newton loop
9432  do
9433  {
9434  count++;
9435 
9436  // Do any updates that are required
9438 
9439  // Calculate initial residuals
9440  if (count == 1)
9441  {
9442 #ifdef OOMPH_HAS_MPI
9443  // Synchronise the solution on different processors (on each submesh)
9444  this->synchronise_all_dofs();
9445 #endif
9446 
9448  y.clear();
9449  get_residuals(y);
9450  // Get maximum residuals, using our own abscmp function
9451  double maxres = y.max();
9452 
9453  // Assemble the residuals for the arc-length step
9454  arc_length_constraint_residual = 0.0;
9455  // Add the variables
9456  for (unsigned long l = 0; l < ndof_local; l++)
9457  {
9458  arc_length_constraint_residual +=
9459  dof_derivative(l) * (*Dof_pt[l] - dof_current(l));
9460  }
9461 
9462  // Now reduce if we have been distributed
9463 #ifdef OOMPH_HAS_MPI
9464  double arc_length_cons_res2 = arc_length_constraint_residual;
9465  if ((Dof_distribution_pt->distributed()) &&
9467  {
9468  MPI_Allreduce(&arc_length_constraint_residual,
9469  &arc_length_cons_res2,
9470  1,
9471  MPI_DOUBLE,
9472  MPI_SUM,
9473  Dof_distribution_pt->communicator_pt()->mpi_comm());
9474  }
9475  arc_length_constraint_residual = arc_length_cons_res2;
9476 #endif
9477 
9478  arc_length_constraint_residual *= Theta_squared;
9479  arc_length_constraint_residual +=
9480  Parameter_derivative * (*parameter_pt - Parameter_current) -
9481  Ds_current;
9482 
9483  // Is it the max
9484  if (std::fabs(arc_length_constraint_residual) > maxres)
9485  {
9486  maxres = std::fabs(arc_length_constraint_residual);
9487  }
9488 
9489  // Find the max
9491  {
9492  oomph_info << "Initial Maximum residuals " << maxres << std::endl;
9493  }
9494 
9495  // If we are below the Tolerance, then return immediately
9496  if ((maxres < Newton_solver_tolerance) &&
9498  {
9499  LOOP_FLAG = 0;
9500  count = 0;
9501  continue;
9502  }
9503  }
9504 
9505  // If it's the block hopf solver we need to solve for both rhs's
9506  // simultaneously. This is because the block decomposition involves
9507  // solves with two different matrices and storing both at once to
9508  // allow general resolves would be more expensive than necessary.
9509  if (dynamic_cast<BlockHopfLinearSolver*>(Linear_solver_pt))
9510  {
9511  // Get the vector dresiduals/dparameter
9512  z.clear();
9513  get_derivative_wrt_global_parameter(parameter_pt, z);
9514 
9515  // Copy rhs vector into local storage so it doesn't get overwritten
9516  // if the linear solver decides to initialise the solution vector, say,
9517  // which it's quite entitled to do!
9518  DoubleVector input_z(z);
9519 
9520  // Solve the system for the two right-hand sides.
9521  dynamic_cast<BlockHopfLinearSolver*>(Linear_solver_pt)
9522  ->solve_for_two_rhs(this, y, input_z, z);
9523  }
9524  // Otherwise
9525  else
9526  {
9527  // Solve the standard problem
9528  Linear_solver_pt->solve(this, y);
9529 
9530  // Get the vector dresiduals/dparameter
9531  z.clear();
9532  get_derivative_wrt_global_parameter(parameter_pt, z);
9533 
9534  // Copy rhs vector into local storage so it doesn't get overwritten
9535  // if the linear solver decides to initialise the solution vector, say,
9536  // which it's quite entitled to do!
9537  DoubleVector input_z(z);
9538 
9539  // Redistribute the RHS to match the linear solver
9540  // input_z.redistribute(Linear_solver_pt->distribution_pt());
9541  // Do not clear z because we assume that it has dR/dparam
9542  z.clear();
9543  // Now resolve the system with the new RHS
9544  Linear_solver_pt->resolve(input_z, z);
9545  }
9546 
9547  // Redistribute the results into the natural distribution
9548  y.redistribute(Dof_distribution_pt);
9549  z.redistribute(Dof_distribution_pt);
9550 
9551  // Now we need to calculate dparam, for which we must calculate the
9552  // dot product of the derivatives and y and z
9553  // Reset these values to zero
9554  uderiv_dot_y = 0.0;
9555  uderiv_dot_z = 0.0;
9556  // Now calculate the dot products of the derivative and the solutions
9557  // of the linear system
9558  // Cache pointers to the data in the distributed vectors
9559  double* const y_pt = y.values_pt();
9560  double* const z_pt = z.values_pt();
9561  for (unsigned long l = 0; l < ndof_local; l++)
9562  {
9563  uderiv_dot_y += dof_derivative(l) * y_pt[l];
9564  uderiv_dot_z += dof_derivative(l) * z_pt[l];
9565  }
9566 
9567  // Now reduce if we have been distributed
9568 #ifdef OOMPH_HAS_MPI
9569  // Create send and receive arrays of size two
9570  double uderiv_dot[2];
9571  double uderiv_dot2[2];
9572  uderiv_dot[0] = uderiv_dot_y;
9573  uderiv_dot[1] = uderiv_dot_z;
9574  uderiv_dot2[0] = uderiv_dot_y;
9575  uderiv_dot2[1] = uderiv_dot_z;
9576  // Now reduce both together
9577  if ((Dof_distribution_pt->distributed()) &&
9579  {
9580  MPI_Allreduce(uderiv_dot,
9581  uderiv_dot2,
9582  2,
9583  MPI_DOUBLE,
9584  MPI_SUM,
9585  Dof_distribution_pt->communicator_pt()->mpi_comm());
9586  }
9587  uderiv_dot_y = uderiv_dot2[0];
9588  uderiv_dot_z = uderiv_dot2[1];
9589 #endif
9590 
9591  // Now scale the results
9592  uderiv_dot_y *= Theta_squared;
9593  uderiv_dot_z *= Theta_squared;
9594 
9595  // The set the change in the parameter, given by the pseudo-arclength
9596  // equation. Note that here we are assuming that the arc-length
9597  // equation is always exactly zero,
9598  // which seems to work OK, and saves on some storage.
9599  // In fact, it's more subtle than that. If we include this
9600  // proper residual then we will have to solve the eigenproblem.
9601  // This will make the solver more robust and *should* be done
9602  // ... at some point.
9603  double dparam = (arc_length_constraint_residual - uderiv_dot_y) /
9604  (Parameter_derivative - uderiv_dot_z);
9605 
9606  // Set the new value of the parameter
9607  *parameter_pt -= dparam;
9608 
9609  // Update the values of the other degrees of freedom
9610  for (unsigned long l = 0; l < ndof_local; l++)
9611  {
9612  *Dof_pt[l] -= y_pt[l] - dparam * z_pt[l];
9613  }
9614 
9615  // Calculate the new residuals
9616 #ifdef OOMPH_HAS_MPI
9617  // Synchronise the solution on different processors (on each submesh)
9618  this->synchronise_all_dofs();
9619 #endif
9620 
9621  // Do any updates that are required
9624 
9625  y.clear();
9626  get_residuals(y);
9627 
9628  // Get the maximum residuals
9629  double maxres = y.max();
9630 
9631  // Assemble the residuals for the arc-length step
9632  arc_length_constraint_residual = 0.0;
9633  // Add the variables
9634  for (unsigned long l = 0; l < ndof_local; l++)
9635  {
9636  arc_length_constraint_residual +=
9637  dof_derivative(l) * (*Dof_pt[l] - dof_current(l));
9638  }
9639 
9640  // Now reduce if we have been distributed
9641 #ifdef OOMPH_HAS_MPI
9642  double arc_length_cons_res2 = arc_length_constraint_residual;
9643  if ((Dof_distribution_pt->distributed()) &&
9645  {
9646  MPI_Allreduce(&arc_length_constraint_residual,
9647  &arc_length_cons_res2,
9648  1,
9649  MPI_DOUBLE,
9650  MPI_SUM,
9651  Dof_distribution_pt->communicator_pt()->mpi_comm());
9652  }
9653  arc_length_constraint_residual = arc_length_cons_res2;
9654 #endif
9655 
9656  arc_length_constraint_residual *= Theta_squared;
9657  arc_length_constraint_residual +=
9658  Parameter_derivative * (*parameter_pt - Parameter_current) - Ds_current;
9659 
9660  // Is it the max
9661  if (std::fabs(arc_length_constraint_residual) > maxres)
9662  {
9663  maxres = std::fabs(arc_length_constraint_residual);
9664  }
9665 
9667  {
9668  oomph_info << "Continuation Step " << count << ": Maximum residuals "
9669  << maxres << "\n";
9670  }
9671 
9672  // If we have converged jump straight to the test at the end of the loop
9673  if (maxres < Newton_solver_tolerance)
9674  {
9675  LOOP_FLAG = 0;
9676  continue;
9677  }
9678 
9679  // This section will not be reached if we have converged already
9680  // If the maximum number of residuals is too high or the maximum number
9681  // of iterations has been reached
9682  if ((maxres > Max_residuals) || (count == Max_newton_iterations))
9683  {
9684  throw NewtonSolverError(count, maxres);
9685  }
9686 
9687  } while (LOOP_FLAG);
9688 
9689  // Now update anything that needs updating
9691 
9692  // Reset the storage of the matrix on the linear solver to what it was
9693  // on entry to this routine
9694  if (enable_resolve)
9695  {
9697  }
9698  else
9699  {
9701  }
9702 
9703  // Return the number of Newton Steps taken
9704  return count;
9705  }
Scalar * y
Definition: level1_cplx_impl.h:128

References actions_after_newton_solve(), actions_after_newton_step(), actions_before_newton_convergence_check(), actions_before_newton_solve(), actions_before_newton_step(), Always_take_one_newton_step, oomph::DoubleVector::clear(), oomph::LinearAlgebraDistribution::communicator_pt(), oomph::LinearSolver::disable_resolve(), oomph::LinearAlgebraDistribution::distributed(), dof_current(), dof_derivative(), Dof_distribution_pt, Dof_pt, Ds_current, oomph::LinearSolver::enable_resolve(), boost::multiprecision::fabs(), get_derivative_wrt_global_parameter(), get_residuals(), oomph::LinearSolver::is_resolve_enabled(), Linear_solver_pt, Max_newton_iterations, Max_residuals, Newton_solver_tolerance, oomph::OomphCommunicator::nproc(), oomph::LinearAlgebraDistribution::nrow_local(), oomph::oomph_info, Parameter_current, Parameter_derivative, oomph::DoubleVector::redistribute(), oomph::LinearSolver::resolve(), Shut_up_in_newton_solve, oomph::LinearSolver::solve(), Theta_squared, oomph::DoubleVector::values_pt(), and y.

◆ newton_solver_tolerance()

double& oomph::Problem::newton_solver_tolerance ( )
inline

Access function to tolererance of the Newton solver, i.e. the maximum value of the residuals that will be accepted.

1622  {
1623  return Newton_solver_tolerance;
1624  }

References Newton_solver_tolerance.

◆ nglobal_data()

unsigned oomph::Problem::nglobal_data ( ) const
inline

◆ nsub_mesh()

◆ ntime_stepper()

◆ operator=()

void oomph::Problem::operator= ( const Problem )
delete

Broken assignment operator.

◆ p_adapt() [1/2]

void oomph::Problem::p_adapt ( )
inline

p-adapt problem: Perform mesh adaptation for (all) refineable (sub)mesh(es), based on their own error estimates and the target errors specified in the mesh(es). Following mesh adaptation, update global mesh, and re-assign equation numbers. On return from this function, Problem can immediately be solved again. [Argument-free wrapper]

2882  {
2883  unsigned n_refined, n_unrefined;
2884  p_adapt(n_refined, n_unrefined);
2885  }
void p_adapt()
Definition: problem.h:2881

◆ p_adapt() [2/2]

void Problem::p_adapt ( unsigned n_refined,
unsigned n_unrefined 
)

p-adapt problem: Perform mesh adaptation for (all) refineable (sub)mesh(es), based on their own error estimates and the target errors specified in the mesh(es). Following mesh adaptation, update global mesh, and re-assign equation numbers. Return # of refined/unrefined elements. On return from this function, Problem can immediately be solved again.

14244  {
14245  double t_start_total = 0.0;
14247  {
14248  t_start_total = TimingHelpers::timer();
14249  }
14250 
14251  // Get the bifurcation type
14252  int bifurcation_type = this->Assembly_handler_pt->bifurcation_type();
14253 
14254  // If we are tracking a bifurcation then call the bifurcation adapt function
14255  if (bifurcation_type != 0)
14256  {
14257  this->bifurcation_adapt_helper(n_refined, n_unrefined, bifurcation_type);
14258  // Return immediately
14259  return;
14260  }
14261 
14262  oomph_info << std::endl << std::endl;
14263  oomph_info << "p-adapting problem:" << std::endl;
14264  oomph_info << "===================" << std::endl;
14265 
14266  double t_start = 0.0;
14268  {
14269  t_start = TimingHelpers::timer();
14270  }
14271 
14272  // Call the actions before adaptation
14274 
14275  double t_end = 0.0;
14277  {
14278  t_end = TimingHelpers::timer();
14279  oomph_info << "Time for actions before adapt: " << t_end - t_start
14280  << std::endl;
14281  t_start = TimingHelpers::timer();
14282  }
14283 
14284  // Initialise counters
14285  n_refined = 0;
14286  n_unrefined = 0;
14287 
14288  // Number of submeshes?
14289  unsigned Nmesh = nsub_mesh();
14290 
14291  // Single mesh:
14292  //------------
14293  if (Nmesh == 0)
14294  {
14295  // Refine single mesh if possible
14296  if (RefineableMeshBase* mmesh_pt =
14297  dynamic_cast<RefineableMeshBase*>(mesh_pt(0)))
14298  {
14299  if (mmesh_pt->is_p_adaptation_enabled())
14300  {
14301  double t_start = TimingHelpers::timer();
14302 
14303  // Get pointer to error estimator
14304  ErrorEstimator* error_estimator_pt =
14305  mmesh_pt->spatial_error_estimator_pt();
14306 
14307 #ifdef PARANOID
14308  if (error_estimator_pt == 0)
14309  {
14310  throw OomphLibError("Error estimator hasn't been set yet",
14313  }
14314 #endif
14315 
14316  // Get error for all elements
14317  Vector<double> elemental_error(mmesh_pt->nelement());
14318 
14319  if (mmesh_pt->doc_info_pt() == 0)
14320  {
14321  error_estimator_pt->get_element_errors(mesh_pt(0), elemental_error);
14322  }
14323  else
14324  {
14325  error_estimator_pt->get_element_errors(
14326  mesh_pt(0), elemental_error, *mmesh_pt->doc_info_pt());
14327  }
14328 
14329  // Store max./min actual error
14330  mmesh_pt->max_error() = std::fabs(*std::max_element(
14331  elemental_error.begin(), elemental_error.end(), AbsCmp<double>()));
14332 
14333  mmesh_pt->min_error() = std::fabs(*std::min_element(
14334  elemental_error.begin(), elemental_error.end(), AbsCmp<double>()));
14335 
14336  oomph_info << "\n Max/min error: " << mmesh_pt->max_error() << " "
14337  << mmesh_pt->min_error() << std::endl
14338  << std::endl;
14339 
14340 
14342  {
14343  t_end = TimingHelpers::timer();
14344  oomph_info << "Time for error estimation: " << t_end - t_start
14345  << std::endl;
14346  t_start = TimingHelpers::timer();
14347  }
14348 
14349  // Adapt mesh
14350  mmesh_pt->p_adapt(elemental_error);
14351 
14352  // Add to counters
14353  n_refined += mmesh_pt->nrefined();
14354  n_unrefined += mmesh_pt->nunrefined();
14355 
14357  {
14358  t_end = TimingHelpers::timer();
14359  oomph_info << "Time for complete mesh adaptation "
14360  << "(but excluding comp of error estimate): "
14361  << t_end - t_start << std::endl;
14362  t_start = TimingHelpers::timer();
14363  }
14364  }
14365  else
14366  {
14367  oomph_info << "Info/Warning: Mesh adaptation is disabled."
14368  << std::endl;
14369  }
14370  }
14371  else
14372  {
14373  oomph_info << "Info/Warning: Mesh cannot be adapted" << std::endl;
14374  }
14375  }
14376  // Multiple submeshes
14377  //------------------
14378  else
14379  {
14380  // Loop over submeshes
14381  for (unsigned imesh = 0; imesh < Nmesh; imesh++)
14382  {
14383  // Refine single mesh uniformly if possible
14384  if (RefineableMeshBase* mmesh_pt =
14385  dynamic_cast<RefineableMeshBase*>(mesh_pt(imesh)))
14386  {
14387  double t_start = TimingHelpers::timer();
14388 
14389  // Get pointer to error estimator
14390  ErrorEstimator* error_estimator_pt =
14391  mmesh_pt->spatial_error_estimator_pt();
14392 
14393 #ifdef PARANOID
14394  if (error_estimator_pt == 0)
14395  {
14396  throw OomphLibError("Error estimator hasn't been set yet",
14399  }
14400 #endif
14401 
14402  if (mmesh_pt->is_p_adaptation_enabled())
14403  {
14404  // Get error for all elements
14405  Vector<double> elemental_error(mmesh_pt->nelement());
14406  if (mmesh_pt->doc_info_pt() == 0)
14407  {
14408  error_estimator_pt->get_element_errors(mesh_pt(imesh),
14409  elemental_error);
14410  }
14411  else
14412  {
14413  error_estimator_pt->get_element_errors(
14414  mesh_pt(imesh), elemental_error, *mmesh_pt->doc_info_pt());
14415  }
14416 
14417  // Store max./min error if the mesh has any elements
14418  if (mesh_pt(imesh)->nelement() > 0)
14419  {
14420  mmesh_pt->max_error() =
14421  std::fabs(*std::max_element(elemental_error.begin(),
14422  elemental_error.end(),
14423  AbsCmp<double>()));
14424 
14425  mmesh_pt->min_error() =
14426  std::fabs(*std::min_element(elemental_error.begin(),
14427  elemental_error.end(),
14428  AbsCmp<double>()));
14429  }
14430 
14431  oomph_info << "\n Max/min error: " << mmesh_pt->max_error() << " "
14432  << mmesh_pt->min_error() << std::endl;
14433 
14434 
14436  {
14437  t_end = TimingHelpers::timer();
14438  oomph_info << "Time for error estimation: " << t_end - t_start
14439  << std::endl;
14440  t_start = TimingHelpers::timer();
14441  }
14442 
14443  // Adapt mesh
14444  mmesh_pt->p_adapt(elemental_error);
14445 
14446  // Add to counters
14447  n_refined += mmesh_pt->nrefined();
14448  n_unrefined += mmesh_pt->nunrefined();
14449 
14450 
14452  {
14453  t_end = TimingHelpers::timer();
14454  oomph_info << "Time for complete mesh adaptation "
14455  << "(but excluding comp of error estimate): "
14456  << t_end - t_start << std::endl;
14457  t_start = TimingHelpers::timer();
14458  }
14459  }
14460  else
14461  {
14462  oomph_info << "Info/Warning: Mesh adaptation is disabled."
14463  << std::endl;
14464  }
14465  }
14466  else
14467  {
14468  oomph_info << "Info/Warning: Mesh cannot be adapted." << std::endl;
14469  }
14470 
14471  } // End of loop over submeshes
14472 
14473  // Rebuild the global mesh
14475  }
14476 
14477 
14479  {
14480  t_end = TimingHelpers::timer();
14481  oomph_info << "Total time for actual adaptation "
14482  << "(all meshes; incl error estimates): " << t_end - t_start
14483  << std::endl;
14484  t_start = TimingHelpers::timer();
14485  }
14486 
14487  // Any actions after adapt
14489 
14490 
14492  {
14493  t_end = TimingHelpers::timer();
14494  oomph_info << "Time for actions after adapt: " << t_end - t_start
14495  << std::endl;
14496  t_start = TimingHelpers::timer();
14497 
14498  oomph_info << "About to start re-assigning eqn numbers "
14499  << "with Problem::assign_eqn_numbers() at end of "
14500  << "Problem::adapt().\n";
14501  }
14502 
14503  // Attach the boundary conditions to the mesh
14504  oomph_info << "\nNumber of equations: " << assign_eqn_numbers() << std::endl
14505  << std::endl;
14506 
14507 
14509  {
14510  t_end = TimingHelpers::timer();
14511  oomph_info << "Time for re-assigning eqn numbers with "
14512  << "Problem::assign_eqn_numbers() at end of Problem::adapt(): "
14513  << t_end - t_start << std::endl;
14514  oomph_info << "Total time for adapt: " << t_end - t_start_total
14515  << std::endl;
14516  }
14517  }

References actions_after_adapt(), actions_before_adapt(), Assembly_handler_pt, assign_eqn_numbers(), bifurcation_adapt_helper(), oomph::AssemblyHandler::bifurcation_type(), oomph::Global_timings::Doc_comprehensive_timings, MeshRefinement::error_estimator_pt, boost::multiprecision::fabs(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, rebuild_global_mesh(), and oomph::TimingHelpers::timer().

Referenced by main().

◆ p_refine_selected_elements() [1/6]

void Problem::p_refine_selected_elements ( const unsigned i_mesh,
const Vector< PRefineableElement * > &  elements_to_be_refined_pt 
)

p-refine specified submesh by refining the elements identified by their pointers, then rebuild the problem.

15308  {
15309  OomphLibWarning(
15310  "p-refinement for multiple submeshes has not yet been tested.",
15311  "Problem::p_refine_selected_elements()",
15313 
15315 
15316  // Number of submeshes?
15317  unsigned n_mesh = nsub_mesh();
15318 
15319  if (i_mesh >= n_mesh)
15320  {
15321  std::ostringstream error_message;
15322  error_message << "Problem only has " << n_mesh
15323  << " submeshes. Cannot p-refine submesh " << i_mesh
15324  << std::endl;
15325  throw OomphLibError(
15326  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15327  }
15328 
15329  // Refine single mesh if possible
15330  if (TreeBasedRefineableMeshBase* mmesh_pt =
15331  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(i_mesh)))
15332  {
15333  mmesh_pt->p_refine_selected_elements(elements_to_be_refined_pt);
15334  }
15335  else
15336  {
15337  oomph_info << "Info/Warning: Mesh cannot be refined " << std::endl;
15338  }
15339 
15340  if (n_mesh > 1)
15341  {
15342  // Rebuild the global mesh
15344  }
15345 
15346  // Any actions after the adapatation phase
15348 
15349  // Do equation numbering
15350  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
15351  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, and rebuild_global_mesh().

◆ p_refine_selected_elements() [2/6]

void Problem::p_refine_selected_elements ( const unsigned i_mesh,
const Vector< unsigned > &  elements_to_be_refined 
)

p-refine specified submesh by refining the elements identified by their numbers relative to the submesh, then rebuild the problem.

p-refine specified submesh by refining the elements identified by their numbers relative to the specified mesh, then rebuild the problem.

15255  {
15256  OomphLibWarning(
15257  "p-refinement for multiple submeshes has not yet been tested.",
15258  "Problem::p_refine_selected_elements()",
15260 
15262 
15263  // Number of submeshes?
15264  unsigned n_mesh = nsub_mesh();
15265 
15266  if (i_mesh >= n_mesh)
15267  {
15268  std::ostringstream error_message;
15269  error_message << "Problem only has " << n_mesh
15270  << " submeshes. Cannot p-refine submesh " << i_mesh
15271  << std::endl;
15272  throw OomphLibError(
15273  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15274  }
15275 
15276  // Refine single mesh if possible
15277  if (TreeBasedRefineableMeshBase* mmesh_pt =
15278  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(i_mesh)))
15279  {
15280  mmesh_pt->p_refine_selected_elements(elements_to_be_refined);
15281  }
15282  else
15283  {
15284  oomph_info << "Info/Warning: Mesh cannot be refined " << std::endl;
15285  }
15286 
15287  if (n_mesh > 1)
15288  {
15289  // Rebuild the global mesh
15291  }
15292 
15293  // Any actions after the adapatation phase
15295 
15296  // Do equation numbering
15297  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
15298  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, and rebuild_global_mesh().

◆ p_refine_selected_elements() [3/6]

void Problem::p_refine_selected_elements ( const Vector< PRefineableElement * > &  elements_to_be_refined_pt)

p-refine (one and only!) mesh by refining the elements identified by their pointers, then rebuild the problem.

15208  {
15210 
15211  // Number of submeshes?
15212  unsigned Nmesh = nsub_mesh();
15213 
15214  // Single mesh:
15215  if (Nmesh == 0)
15216  {
15217  // Refine single mesh if possible
15218  if (TreeBasedRefineableMeshBase* mmesh_pt =
15219  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(0)))
15220  {
15221  mmesh_pt->p_refine_selected_elements(elements_to_be_refined_pt);
15222  }
15223  else
15224  {
15225  oomph_info << "Info/Warning: Mesh cannot be refined " << std::endl;
15226  }
15227  }
15228  // Multiple submeshes
15229  else
15230  {
15231  std::ostringstream error_message;
15232  error_message
15233  << "Problem::p_refine_selected_elements(...) only works for\n"
15234  << "multiple-mesh problems if you specify the mesh\n"
15235  << "number in the function argument before the Vector,\n"
15236  << "or a Vector of Vectors for each submesh.\n"
15237  << std::endl;
15238  throw OomphLibError(
15239  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15240  }
15241 
15242  // Any actions after the adapatation phase
15244 
15245  // Do equation numbering
15246  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
15247  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and oomph::oomph_info.

◆ p_refine_selected_elements() [4/6]

void Problem::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 problems' only mesh, then rebuild the problem.

15161  {
15163 
15164  // Number of submeshes?
15165  unsigned Nmesh = nsub_mesh();
15166 
15167  // Single mesh:
15168  if (Nmesh == 0)
15169  {
15170  // Refine single mesh if possible
15171  if (TreeBasedRefineableMeshBase* mmesh_pt =
15172  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(0)))
15173  {
15174  mmesh_pt->p_refine_selected_elements(elements_to_be_refined);
15175  }
15176  else
15177  {
15178  oomph_info << "Info/Warning: Mesh cannot be refined " << std::endl;
15179  }
15180  }
15181  // Multiple submeshes
15182  else
15183  {
15184  std::ostringstream error_message;
15185  error_message
15186  << "Problem::p_refine_selected_elements(...) only works for\n"
15187  << "multiple-mesh problems if you specify the mesh\n"
15188  << "number in the function argument before the Vector,\n"
15189  << "or a Vector of Vectors for each submesh.\n"
15190  << std::endl;
15191  throw OomphLibError(
15192  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15193  }
15194 
15195  // Any actions after the adapatation phase
15197 
15198  // Attach the boundary conditions to the mesh
15199  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
15200  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and oomph::oomph_info.

◆ p_refine_selected_elements() [5/6]

void Problem::p_refine_selected_elements ( const Vector< Vector< PRefineableElement * >> &  elements_to_be_refined_pt)

p-refine all submeshes by refining the elements identified by their pointers within each submesh in a Vector of Vectors, then rebuild the problem.

15402  {
15403  OomphLibWarning(
15404  "p-refinement for multiple submeshes has not yet been tested.",
15405  "Problem::p_refine_selected_elements()",
15407 
15409 
15410  // Number of submeshes?
15411  unsigned n_mesh = nsub_mesh();
15412 
15413  // Refine all submeshes if possible
15414  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
15415  {
15416  if (TreeBasedRefineableMeshBase* mmesh_pt =
15417  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(i_mesh)))
15418  {
15419  mmesh_pt->p_refine_selected_elements(elements_to_be_refined_pt[i_mesh]);
15420  }
15421  else
15422  {
15423  oomph_info << "Info/Warning: Mesh cannot be refined " << std::endl;
15424  }
15425  }
15426 
15427  // Rebuild the global mesh
15429 
15430  // Any actions after the adapatation phase
15432 
15433  // Do equation numbering
15434  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
15435  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, and rebuild_global_mesh().

◆ p_refine_selected_elements() [6/6]

void Problem::p_refine_selected_elements ( const Vector< Vector< unsigned >> &  elements_to_be_refined)

p-refine all submeshes by refining the elements identified by their numbers relative to each submesh in a Vector of Vectors, then rebuild the problem.

15360  {
15361  OomphLibWarning(
15362  "p-refinement for multiple submeshes has not yet been tested.",
15363  "Problem::p_refine_selected_elements()",
15365 
15367 
15368  // Number of submeshes?
15369  unsigned n_mesh = nsub_mesh();
15370 
15371  // Refine all submeshes if possible
15372  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
15373  {
15374  if (TreeBasedRefineableMeshBase* mmesh_pt =
15375  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(i_mesh)))
15376  {
15377  mmesh_pt->p_refine_selected_elements(elements_to_be_refined[i_mesh]);
15378  }
15379  else
15380  {
15381  oomph_info << "Info/Warning: Mesh cannot be refined " << std::endl;
15382  }
15383  }
15384 
15385  // Rebuild the global mesh
15387 
15388  // Any actions after the adapatation phase
15390 
15391  // Do equation numbering
15392  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
15393  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, and rebuild_global_mesh().

◆ p_refine_uniformly() [1/6]

void oomph::Problem::p_refine_uniformly ( )
inline

p-refine (all) p-refineable (sub)mesh(es) uniformly and rebuild problem

2738  {
2739  DocInfo doc_info;
2740  doc_info.disable_doc();
2741  p_refine_uniformly(doc_info);
2742  }
void p_refine_uniformly()
Definition: problem.h:2737

References oomph::DocInfo::disable_doc().

Referenced by p_refine_uniformly().

◆ p_refine_uniformly() [2/6]

void oomph::Problem::p_refine_uniformly ( const unsigned i_mesh)
inline

Do uniform p-refinement for submesh i_mesh without documentation.

2749  {
2750  DocInfo doc_info;
2751  doc_info.disable_doc();
2752  p_refine_uniformly(i_mesh, doc_info);
2753  }

References oomph::DocInfo::disable_doc(), and p_refine_uniformly().

◆ p_refine_uniformly() [3/6]

void Problem::p_refine_uniformly ( const unsigned i_mesh,
DocInfo doc_info 
)

Do uniform p-refinement for submesh i_mesh with documentation.

p-refine submesh i_mesh uniformly and rebuild problem; doc refinement process.

15785  {
15787 
15788 #ifdef PARANOID
15789  // Number of submeshes?
15790  if (i_mesh >= nsub_mesh())
15791  {
15792  std::ostringstream error_message;
15793  error_message << "imesh " << i_mesh
15794  << " is greater than the number of sub meshes "
15795  << nsub_mesh() << std::endl;
15796 
15797  throw OomphLibError(
15798  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15799  }
15800 #endif
15801 
15802  // Refine single mesh uniformly if possible
15803  if (RefineableMeshBase* mmesh_pt =
15804  dynamic_cast<RefineableMeshBase*>(mesh_pt(i_mesh)))
15805  {
15806  mmesh_pt->p_refine_uniformly(doc_info);
15807  }
15808  else
15809  {
15810  oomph_info << "Info/Warning: Mesh cannot be refined uniformly "
15811  << std::endl;
15812  }
15813 
15814  // Rebuild the global mesh
15816 
15817  // Any actions after the adaptation phase
15819 
15820  // Do equation numbering
15821  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
15822  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, and rebuild_global_mesh().

◆ p_refine_uniformly() [4/6]

void oomph::Problem::p_refine_uniformly ( const Vector< unsigned > &  nrefine_for_mesh)
inline

p-refine p-refineable sub-meshes, each as many times as specified in the vector and rebuild problem

2661  {
2662  DocInfo doc_info;
2663  doc_info.disable_doc();
2664  bool prune = false;
2665  p_refine_uniformly_aux(nrefine_for_mesh, doc_info, prune);
2666  }
void p_refine_uniformly_aux(const Vector< unsigned > &nrefine_for_mesh, DocInfo &doc_info, const bool &prune)
Definition: problem.cc:15592

References oomph::DocInfo::disable_doc(), and p_refine_uniformly_aux().

Referenced by main().

◆ p_refine_uniformly() [5/6]

void oomph::Problem::p_refine_uniformly ( const Vector< unsigned > &  nrefine_for_mesh,
DocInfo doc_info 
)
inline

p-refine p-refineable sub-meshes, each as many times as specified in the vector and rebuild problem; doc refinement process

2672  {
2673  bool prune = false;
2674  p_refine_uniformly_aux(nrefine_for_mesh, doc_info, prune);
2675  }

References p_refine_uniformly_aux().

◆ p_refine_uniformly() [6/6]

void oomph::Problem::p_refine_uniformly ( DocInfo doc_info)
inline

p-refine (all) p-refineable (sub)mesh(es) uniformly and rebuild problem; doc refinement process.

2708  {
2709  // Number of (sub)meshes
2710  unsigned nmesh = std::max(unsigned(1), nsub_mesh());
2711 
2712  // Refine each mesh once
2713  Vector<unsigned> nrefine_for_mesh(nmesh, 1);
2714  p_refine_uniformly(nrefine_for_mesh);
2715  }

References max, nsub_mesh(), and p_refine_uniformly().

◆ p_refine_uniformly_and_prune() [1/3]

void oomph::Problem::p_refine_uniformly_and_prune ( const Vector< unsigned > &  nrefine_for_mesh)
inline

p-refine p-refineable sub-meshes, each as many times as specified in the vector and rebuild problem. Prune after refinements

2681  {
2682  // Not tested:
2683  throw OomphLibWarning("This functionality has not yet been tested.",
2684  "Problem::p_refine_uniformly_and_prune()",
2686  DocInfo doc_info;
2687  doc_info.disable_doc();
2688  bool prune = true;
2689  p_refine_uniformly_aux(nrefine_for_mesh, doc_info, prune);
2690  }

References oomph::DocInfo::disable_doc(), OOMPH_EXCEPTION_LOCATION, and p_refine_uniformly_aux().

Referenced by p_refine_uniformly_and_prune().

◆ p_refine_uniformly_and_prune() [2/3]

void oomph::Problem::p_refine_uniformly_and_prune ( const Vector< unsigned > &  nrefine_for_mesh,
DocInfo doc_info 
)
inline

p-refine p-refineable sub-meshes, each as many times as specified in the vector and rebuild problem; doc refinement process

2696  {
2697  // Not tested:
2698  throw OomphLibWarning("This functionality has not yet been tested.",
2699  "Problem::p_refine_uniformly_and_prune()",
2701  bool prune = true;
2702  p_refine_uniformly_aux(nrefine_for_mesh, doc_info, prune);
2703  }

References OOMPH_EXCEPTION_LOCATION, and p_refine_uniformly_aux().

◆ p_refine_uniformly_and_prune() [3/3]

void oomph::Problem::p_refine_uniformly_and_prune ( DocInfo doc_info)
inline

p-refine (all) p-refineable (sub)mesh(es) uniformly and rebuild problem; doc refinement process.

2721  {
2722  // Not tested:
2723  throw OomphLibWarning("This functionality has not yet been tested.",
2724  "Problem::p_refine_uniformly_and_prune()",
2726  // Number of (sub)meshes
2727  unsigned nmesh = std::max(unsigned(1), nsub_mesh());
2728 
2729  // Refine each mesh once
2730  Vector<unsigned> nrefine_for_mesh(nmesh, 1);
2731  p_refine_uniformly_and_prune(nrefine_for_mesh);
2732  }
void p_refine_uniformly_and_prune(const Vector< unsigned > &nrefine_for_mesh)
Definition: problem.h:2680

References max, nsub_mesh(), OOMPH_EXCEPTION_LOCATION, and p_refine_uniformly_and_prune().

◆ p_refine_uniformly_aux()

void Problem::p_refine_uniformly_aux ( const Vector< unsigned > &  nrefine_for_mesh,
DocInfo doc_info,
const bool prune 
)
private

Helper function to do compund p-refinement of (all) p-refineable (sub)mesh(es) uniformly as many times as specified in vector and rebuild problem; doc refinement process. Set boolean argument to true if you want to prune immediately after refining the meshes individually.

15595  {
15596  double t_start = 0.0;
15598  {
15599  t_start = TimingHelpers::timer();
15600  }
15601 
15603 
15604  double t_end = 0.0;
15606  {
15607  t_end = TimingHelpers::timer();
15608  oomph_info << "Time for actions before adapt in "
15609  "Problem::p_refine_uniformly_aux(): "
15610  << t_end - t_start << std::endl;
15611  t_start = TimingHelpers::timer();
15612  }
15613 
15614  // Number of submeshes?
15615  unsigned n_mesh = nsub_mesh();
15616 
15617  // Single mesh:
15618  if (n_mesh == 0)
15619  {
15620  // Refine single mesh uniformly if possible
15621  if (RefineableMeshBase* mmesh_pt =
15622  dynamic_cast<RefineableMeshBase*>(mesh_pt(0)))
15623  {
15624  unsigned nref = nrefine_for_mesh[0];
15625  for (unsigned i = 0; i < nref; i++)
15626  {
15627  mmesh_pt->p_refine_uniformly(doc_info);
15628  }
15629  }
15630  else
15631  {
15632  oomph_info << "Info/Warning: Mesh cannot be p-refined uniformly "
15633  << std::endl;
15634  }
15635  }
15636  // Multiple submeshes
15637  else
15638  {
15639  OomphLibWarning(
15640  "p-refinement for multiple submeshes has not yet been tested.",
15641  "Problem::p_refine_uniformly_aux()",
15643 
15644  // Loop over submeshes
15645  for (unsigned imesh = 0; imesh < n_mesh; imesh++)
15646  {
15647  // Refine i-th submesh uniformly if possible
15648  if (RefineableMeshBase* mmesh_pt =
15649  dynamic_cast<RefineableMeshBase*>(mesh_pt(imesh)))
15650  {
15651  unsigned nref = nrefine_for_mesh[imesh];
15652  for (unsigned i = 0; i < nref; i++)
15653  {
15654  mmesh_pt->p_refine_uniformly(doc_info);
15655  }
15656  }
15657  else
15658  {
15659  oomph_info << "Info/Warning: Cannot p-refine mesh " << imesh
15660  << std::endl;
15661  }
15662  }
15663  // Rebuild the global mesh
15665  }
15666 
15668  {
15669  t_end = TimingHelpers::timer();
15670  oomph_info << "Time for mesh-level mesh refinement in "
15671  << "Problem::p_refine_uniformly_aux(): " << t_end - t_start
15672  << std::endl;
15673  t_start = TimingHelpers::timer();
15674  }
15675 
15676  // Any actions after the adaptation phase
15678 
15679 
15681  {
15682  t_end = TimingHelpers::timer();
15683  oomph_info
15684  << "Time for actions after adapt Problem::p_refine_uniformly_aux(): "
15685  << t_end - t_start << std::endl;
15686  t_start = TimingHelpers::timer();
15687  }
15688 
15689 
15690 #ifdef OOMPH_HAS_MPI
15691 
15692  // Prune it?
15693  if (prune)
15694  {
15695  // Note: This calls assign eqn numbers already...
15696  Bypass_increase_in_dof_check_during_pruning = true;
15697  prune_halo_elements_and_nodes();
15698  Bypass_increase_in_dof_check_during_pruning = false;
15699 
15701  {
15702  t_end = TimingHelpers::timer();
15703  oomph_info << "Time for Problem::prune_halo_elements_and_nodes() in "
15704  << "Problem::p_refine_uniformly_aux(): " << t_end - t_start
15705  << std::endl;
15706  }
15707  }
15708  else
15709 #else
15710  if (prune)
15711  {
15712  std::ostringstream error_message;
15713  error_message
15714  << "Requested pruning in serial build. Ignoring the request.\n";
15715  OomphLibWarning(error_message.str(),
15716  "Problem::p_refine_uniformly_aux()",
15718  }
15719 #endif
15720  {
15721  // Do equation numbering
15722  oomph_info
15723  << "Number of equations after Problem::p_refine_uniformly_aux(): "
15724  << assign_eqn_numbers() << std::endl;
15725 
15727  {
15728  t_end = TimingHelpers::timer();
15729  oomph_info << "Time for Problem::assign_eqn_numbers() in "
15730  << "Problem::p_refine_uniformly_aux(): " << t_end - t_start
15731  << std::endl;
15732  }
15733  }
15734  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), oomph::Global_timings::Doc_comprehensive_timings, i, mesh_pt(), nsub_mesh(), OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, rebuild_global_mesh(), and oomph::TimingHelpers::timer().

Referenced by p_refine_uniformly(), and p_refine_uniformly_and_prune().

◆ p_unrefine_uniformly() [1/2]

void Problem::p_unrefine_uniformly ( const unsigned i_mesh,
DocInfo doc_info 
)

Do uniform p-unrefinement for submesh i_mesh without documentation.

p-unrefine submesh i_mesh uniformly and rebuild problem; doc refinement process.

16020  {
16022 
16023 #ifdef PARANOID
16024  // Number of submeshes?
16025  if (i_mesh >= nsub_mesh())
16026  {
16027  std::ostringstream error_message;
16028  error_message << "imesh " << i_mesh
16029  << " is greater than the number of sub meshes "
16030  << nsub_mesh() << std::endl;
16031 
16032  throw OomphLibError(
16033  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
16034  }
16035 #endif
16036 
16037  // Refine single mesh uniformly if possible
16038  if (RefineableMeshBase* mmesh_pt =
16039  dynamic_cast<RefineableMeshBase*>(mesh_pt(i_mesh)))
16040  {
16041  mmesh_pt->p_unrefine_uniformly(doc_info);
16042  }
16043  else
16044  {
16045  oomph_info << "Info/Warning: Mesh cannot be p-unrefined uniformly "
16046  << std::endl;
16047  }
16048 
16049  // Rebuild the global mesh
16051 
16052  // Any actions after the adaptation phase
16054 
16055  // Do equation numbering
16056  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
16057  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, and rebuild_global_mesh().

◆ p_unrefine_uniformly() [2/2]

void Problem::p_unrefine_uniformly ( DocInfo doc_info)

p-unrefine (all) p-refineable (sub)mesh(es) uniformly and rebuild problem.

p-unrefine (all) p-refineable (sub)mesh(es) uniformly and rebuild problem; doc refinement process.

15961  {
15963 
15964  // Number of submeshes?
15965  unsigned n_mesh = nsub_mesh();
15966 
15967  // Single mesh:
15968  if (n_mesh == 0)
15969  {
15970  // Unrefine single mesh uniformly if possible
15971  if (RefineableMeshBase* mmesh_pt =
15972  dynamic_cast<RefineableMeshBase*>(mesh_pt(0)))
15973  {
15974  mmesh_pt->p_unrefine_uniformly(doc_info);
15975  }
15976  else
15977  {
15978  oomph_info << "Info/Warning: Mesh cannot be p-unrefined uniformly "
15979  << std::endl;
15980  }
15981  }
15982  // Multiple submeshes
15983  else
15984  {
15985  // Not tested:
15986  throw OomphLibError("This functionality has not yet been tested.",
15989  // Loop over submeshes
15990  for (unsigned imesh = 0; imesh < n_mesh; imesh++)
15991  {
15992  // Unrefine i-th submesh uniformly if possible
15993  if (RefineableMeshBase* mmesh_pt =
15994  dynamic_cast<RefineableMeshBase*>(mesh_pt(imesh)))
15995  {
15996  mmesh_pt->p_unrefine_uniformly(doc_info);
15997  }
15998  else
15999  {
16000  oomph_info << "Info/Warning: Cannot p-unrefine mesh " << imesh
16001  << std::endl;
16002  }
16003  }
16004  // Rebuild the global mesh
16006  }
16007 
16008  // Any actions after the adaptation phase
16010 
16011  // Do equation numbering
16012  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
16013  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, and rebuild_global_mesh().

◆ problem_is_nonlinear()

void oomph::Problem::problem_is_nonlinear ( const bool prob_lin)
inline

Access function to Problem_is_nonlinear.

1601  {
1602  Problem_is_nonlinear = prob_lin;
1603  }

References Problem_is_nonlinear.

◆ read() [1/2]

virtual void oomph::Problem::read ( std::ifstream &  restart_file)
inlinevirtual

Read refinement pattern of all refineable meshes and refine them accordingly, then read all Data and nodal position info from file for restart.

Reimplemented in oomph::MyProblem, and AirwayReopeningProblem< ELEMENT >.

2067  {
2068  bool unsteady_restart;
2069  read(restart_file, unsteady_restart);
2070  }
virtual void read(std::ifstream &restart_file, bool &unsteady_restart)
Definition: problem.cc:12251

References read().

◆ read() [2/2]

void Problem::read ( std::ifstream &  restart_file,
bool unsteady_restart 
)
virtual

Read refinement pattern of all refineable meshes and refine them accordingly, then read all Data and nodal position info from file for restart. Return flag to indicate if the restart was from steady or unsteady solution

Read refinement pattern of all refineable meshes and refine them accordingly, then read all Data and nodal position info from file for restart. Return flag to indicate if the restart was from steady or unsteady solution.

12252  {
12253  // Check if the file is actually open as it won't be if it doesn't
12254  // exist! In that case we're almost certainly restarting the run on
12255  // a larger number of processors than the restart data was produced.
12256  // Say so and return
12257  bool restart_file_is_open = true;
12258  if (!restart_file.is_open())
12259  {
12260  std::ostringstream warn_message;
12261  warn_message << "Restart file isn't open -- I'm assuming that this is\n";
12262  warn_message << "because we're restarting on a larger number of\n";
12263  warn_message << "processor than were in use when the restart data was \n";
12264  warn_message << "dumped.\n";
12265  OomphLibWarning(
12266  warn_message.str(), "Problem::read()", OOMPH_EXCEPTION_LOCATION);
12267  restart_file_is_open = false;
12268  }
12269 
12270  // Number of (sub)meshes?
12271  unsigned n_mesh = std::max(unsigned(1), nsub_mesh());
12272 
12273  std::string input_string;
12274 
12275  // Read line up to termination sign
12276  getline(restart_file, input_string, '#');
12277 
12278  // Ignore rest of line
12279  restart_file.ignore(80, '\n');
12280 
12281  // Read in number of sub-meshes
12282  unsigned n_submesh_read;
12283  n_submesh_read = std::atoi(input_string.c_str());
12284 
12285 #ifdef PARANOID
12286  if (restart_file_is_open)
12287  {
12288  if (n_submesh_read != n_mesh)
12289  {
12290  std::ostringstream error_message;
12291  error_message
12292  << "Number of sub-meshes specified in restart file, "
12293  << n_submesh_read << " doesn't \n match the my number of sub-meshes,"
12294  << n_mesh << std::endl
12295  << "Make sure all sub-meshes have been added to the global mesh\n"
12296  << "when calling the Problem::dump() function.\n";
12297  throw OomphLibError(error_message.str(),
12300  }
12301  }
12302 #else
12303  // Suppress comiler warnings about non-used variable
12304  n_submesh_read++;
12305  n_submesh_read--;
12306 #endif
12307 
12308 
12309  // Read levels of refinement before pruning
12310 #ifdef OOMPH_HAS_MPI
12311  bool refine_and_prune_required = false;
12312 #endif
12313  Vector<unsigned> nrefinement_for_mesh(n_mesh);
12314  for (unsigned i = 0; i < n_mesh; i++)
12315  {
12316  // Read line up to termination sign
12317  getline(restart_file, input_string, '#');
12318 
12319  // Ignore rest of line
12320  restart_file.ignore(80, '\n');
12321 
12322  // Convert
12323  nrefinement_for_mesh[i] = std::atoi(input_string.c_str());
12324 
12325  // Get pointer to sub-mesh in incarnation as tree-based refineable mesh
12326  TreeBasedRefineableMeshBase* ref_mesh_pt =
12327  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(i));
12328 
12329  // If it's not a tree-based refineable mesh, ignore the following
12330  if (ref_mesh_pt == 0)
12331  {
12332  if (nrefinement_for_mesh[i] != 0)
12333  {
12334  std::ostringstream error_stream;
12335  error_stream << "Nonzero uniform-refinement-when-pruned specified\n"
12336  << "even though mesh is not tree-based. Odd. May want\n"
12337  << "to check this carefully before disabling this \n"
12338  << "warning/error -- most likely if/when we start to\n"
12339  << "prune unstructured meshes [though I can't see why\n"
12340  << "we would want to do this, given that they are \n"
12341  << "currently totally re-generated...]\n";
12342  throw OomphLibError(error_stream.str(),
12345  }
12346  }
12347  else
12348  {
12349  // Get min and max refinement level
12350  unsigned local_min_ref = 0;
12351  unsigned local_max_ref = 0;
12352  ref_mesh_pt->get_refinement_levels(local_min_ref, local_max_ref);
12353 
12354  // Overall min refinement level over all meshes
12355  unsigned min_ref = local_min_ref;
12356 
12357 #ifdef OOMPH_HAS_MPI
12358  if (Problem_has_been_distributed)
12359  {
12360  // Reconcile between processors: If (e.g. following
12361  // distribution/pruning) the mesh has no elements on this
12362  // processor) then ignore its contribution to the poll of
12363  // max/min refinement levels
12364  int int_local_min_ref = local_min_ref;
12365  if (ref_mesh_pt->nelement() == 0)
12366  {
12367  int_local_min_ref = INT_MAX;
12368  }
12369  int int_min_ref = 0;
12370  MPI_Allreduce(&int_local_min_ref,
12371  &int_min_ref,
12372  1,
12373  MPI_INT,
12374  MPI_MIN,
12375  Communicator_pt->mpi_comm());
12376 
12377  // Overall min refinement level over all meshes
12378  min_ref = unsigned(int_min_ref);
12379  }
12380 #endif
12381 
12382  // Need to refine less
12383  if (nrefinement_for_mesh[i] >= min_ref)
12384  {
12385  nrefinement_for_mesh[i] -= min_ref;
12386  }
12387  }
12388 
12389 #ifdef OOMPH_HAS_MPI
12390  if (nrefinement_for_mesh[i] > 0)
12391  {
12392  refine_and_prune_required = true;
12393  }
12394 #endif
12395  }
12396 
12397 
12398  // Reconcile overall need to refine and prune (even empty
12399  // processors have to participate in some communication!)
12400 #ifdef OOMPH_HAS_MPI
12401  if (Problem_has_been_distributed)
12402  {
12403  unsigned local_req_flag = 0;
12404  unsigned req_flag = 0;
12405  if (refine_and_prune_required)
12406  {
12407  local_req_flag = 1;
12408  }
12409  MPI_Allreduce(&local_req_flag,
12410  &req_flag,
12411  1,
12412  MPI_UNSIGNED,
12413  MPI_MAX,
12414  Communicator_pt->mpi_comm());
12415  refine_and_prune_required = false;
12416  if (req_flag == 1)
12417  {
12418  refine_and_prune_required = true;
12419  }
12420 
12421  // If refine and prune is required make number of uniform
12422  // refinements for each mesh consistent otherwise code
12423  // hangs on "empty" processors for which no restart file exists
12424  if (refine_and_prune_required)
12425  {
12426  // This is what we have locally
12427  Vector<unsigned> local_nrefinement_for_mesh(nrefinement_for_mesh);
12428  // Synchronise over all processors with max operation
12429  MPI_Allreduce(&local_nrefinement_for_mesh[0],
12430  &nrefinement_for_mesh[0],
12431  n_mesh,
12432  MPI_UNSIGNED,
12433  MPI_MAX,
12434  Communicator_pt->mpi_comm());
12435 
12436 #ifdef PARANOID
12437  // Check it: Reconciliation should only be required for
12438  // for processors on which no restart file was opened and
12439  // for which the meshes are therefore empty
12440  bool fail = false;
12441  std::ostringstream error_message;
12442  error_message << "Number of uniform refinements was not consistent \n"
12443  << "for following meshes during restart on processor \n"
12444  << "on which restart file could be opened:\n";
12445  for (unsigned i = 0; i < n_mesh; i++)
12446  {
12447  if ((local_nrefinement_for_mesh[i] != nrefinement_for_mesh[i]) &&
12448  restart_file_is_open)
12449  {
12450  fail = true;
12451  error_message << "Sub-mesh: " << i << "; local nrefinement: "
12452  << local_nrefinement_for_mesh[i] << " "
12453  << "; global/synced nrefinement: "
12454  << nrefinement_for_mesh[i] << "\n";
12455  }
12456  }
12457  if (fail)
12458  {
12459  OomphLibWarning(
12460  error_message.str(), "Problem::read()", OOMPH_EXCEPTION_LOCATION);
12461  }
12462 #endif
12463  }
12464  }
12465 #endif
12466 
12467  // Read line up to termination sign
12468  getline(restart_file, input_string, '#');
12469 
12470  // Ignore rest of line
12471  restart_file.ignore(80, '\n');
12472 
12473  // Check flag that indicates that we've read the final data
12474  unsigned tmp;
12475  tmp = std::atoi(input_string.c_str());
12476 
12477 #ifdef PARANOID
12478  if (restart_file_is_open)
12479  {
12480  if (tmp != 9999)
12481  {
12482  std::ostringstream error_message;
12483  error_message
12484  << "Error in reading restart data: Uniform refinement when pruned \n"
12485  << "flags should be followed by 9999.\n";
12486  throw OomphLibError(error_message.str(),
12489  }
12490  }
12491 
12492 #else
12493  // Suppress comiler warnings about non-used variable
12494  tmp++;
12495  tmp--;
12496 #endif
12497 
12498 
12499 #ifdef OOMPH_HAS_MPI
12500 
12501  // Refine and prune if required
12502  if (refine_and_prune_required)
12503  {
12504  refine_uniformly(nrefinement_for_mesh);
12505  prune_halo_elements_and_nodes();
12506  }
12507 
12508  // target_domain_for_local_non_halo_element[e] contains the number
12509  // of the domain [0,1,...,nproc-1] to which non-halo element e on THE
12510  // CURRENT PROCESSOR ONLY has been assigned. The order of the non-halo
12511  // elements is the same as in the Problem's mesh, with the halo
12512  // elements being skipped.
12513  Vector<unsigned> target_domain_for_local_non_halo_element;
12514 
12515  // If a restart file has been generated using code compiled without MPI
12516  // then it will not have any of the base element data.
12517  // If we try to read in that file with code that has been compied using
12518  // MPI, even if running only one processor, then it will fail here.
12519  // The ideal fix is to edit the restart file so that it contains the two
12520  // lines
12521  //
12522  // 0 # Number of base elements; partitioning follows.
12523  // 8888 # Test flag for end of base element distribution
12524  //
12525  // after the end of the sub-meshes, but before the number of elements
12526  // However, we can determine that this is the problem if n_base = 0,
12527  // so there is a little bit of logic below to catch this case
12528 
12529  // Store current location in the file (before we are about to read
12530  // in either the base mesh or number of elements of the first mesh)
12531  std::streampos position_before_base_element = restart_file.tellg();
12532  // Boolean flag used to set whether to read in base element info
12533  bool read_in_base_element_info = true;
12534 
12535  // Read line up to termination sign
12536  getline(restart_file, input_string, '#');
12537 
12538  // Ignore rest of line
12539  restart_file.ignore(80, '\n');
12540 
12541  // Get number of base elements as recorded
12542  unsigned n_base_element_read_in = atoi(input_string.c_str());
12543  unsigned nbase = Base_mesh_element_pt.size();
12544  if (restart_file_is_open)
12545  {
12546  if (n_base_element_read_in != nbase)
12547  {
12548  // If we have zero base elements the problem could be that the
12549  // restart file was generated without MPI. Issue a warning
12550  // and continue anyway
12551  if (nbase == 0)
12552  {
12553  std::ostringstream warn_message;
12554  warn_message
12555  << "The number of base elements in the mesh is 0,\n"
12556  << " but the restart file indicates that there are "
12557  << n_base_element_read_in << ".\n"
12558  << "This could be because the restart file was \n"
12559  << "generated by using code without MPI.\n"
12560  << "\n"
12561  << "The best fix is to include two additional lines\n"
12562  << "in the restart file: \n\n"
12563  << "0 # Number of base elements; partitioning follows.\n"
12564  << "8888 # Test flag for end of base element distribution\n"
12565  << "\n"
12566  << "These lines go after the flag 9999 that indicates\n"
12567  << "the end of the submesh information.\n"
12568  << "\n"
12569  << "The file will now continue to be read assuming that\n"
12570  << "the base element information is not present.\n"
12571  << "If you get strange results then please look carefully\n"
12572  << "at the restart file. The safest thing to do is to \n"
12573  << "ensure that the restart file was generated by code\n"
12574  << "compiled and run with the same parallel options.\n";
12575  OomphLibWarning(warn_message.str(),
12578  // Set the skip flag to true
12579  // and rewind the file pointer
12580  read_in_base_element_info = false;
12581  restart_file.seekg(position_before_base_element);
12582  }
12583  // Otherwise throw a hard error
12584  else
12585  {
12586  std::ostringstream error_message;
12587  error_message << "About to read " << n_base_element_read_in
12588  << " base elements \n"
12589  << "though we only have " << nbase
12590  << " base elements in mesh.\n";
12591  throw OomphLibError(error_message.str(),
12594  }
12595  }
12596  }
12597 
12598  // Read in the remaning base element information, if necessary
12599  if (read_in_base_element_info == true)
12600  {
12601  // Read in target_domain_for_base_element[e] for all base elements
12602  Vector<unsigned> target_domain_for_base_element(nbase);
12603  for (unsigned e = 0; e < nbase; e++)
12604  {
12605  // Read line
12606  getline(restart_file, input_string);
12607 
12608  // Get target domain
12609  target_domain_for_base_element[e] = atoi(input_string.c_str());
12610  }
12611 
12612  // Read line up to termination sign
12613  getline(restart_file, input_string, '#');
12614 
12615  // Ignore rest of line
12616  restart_file.ignore(80, '\n');
12617 
12618  // Check flag that indicates that we've read the final data
12619  tmp = std::atoi(input_string.c_str());
12620 
12621 
12622 #ifdef PARANOID
12623  if (restart_file_is_open)
12624  {
12625  if (tmp != 8888)
12626  {
12627  std::ostringstream error_message;
12628  error_message
12629  << "Error in reading restart data: Target proc for base elements \n"
12630  << "should be followed by 8888.\n";
12631  throw OomphLibError(error_message.str(),
12634  }
12635  }
12636 #endif
12637 
12638  // Loop over all elements (incl. any FaceElements) and assign
12639  // target domain for all local non-halo elements and check if
12640  // load balancing is required -- no need to do this if problem is
12641  // not distributed.
12642  unsigned load_balance_required_flag = 0;
12643  if (Problem_has_been_distributed)
12644  {
12645  // Working with TreeBasedRefineableMeshBase mesh
12646  unsigned local_load_balance_required_flag = 0;
12647  if (dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(0)))
12648  {
12649  const int my_rank = this->communicator_pt()->my_rank();
12650  unsigned nel = mesh_pt()->nelement();
12651  for (unsigned e = 0; e < nel; e++)
12652  {
12653  GeneralisedElement* el_pt = mesh_pt()->element_pt(e);
12654  if (!el_pt->is_halo())
12655  {
12656  // Get element number (plus one) in base element enumeration
12657  unsigned el_number_in_base_mesh_plus_one =
12658  Base_mesh_element_number_plus_one[el_pt];
12659 
12660  // If it's zero then we haven't found it, it may be a FaceElement
12661  // (in which case we move it to the same processor as its bulk
12662  // element
12663  if (el_number_in_base_mesh_plus_one == 0)
12664  {
12665  FaceElement* face_el_pt = dynamic_cast<FaceElement*>(el_pt);
12666  if (face_el_pt != 0)
12667  {
12668  // Get corresponding bulk element
12669  FiniteElement* bulk_el_pt = face_el_pt->bulk_element_pt();
12670 
12671  // Use its element number (plus one) in base element
12672  // enumeration
12673  el_number_in_base_mesh_plus_one =
12674  Base_mesh_element_number_plus_one[bulk_el_pt];
12675 
12676  // If this is zero too we have a problem
12677  if (el_number_in_base_mesh_plus_one == 0)
12678  {
12679  throw OomphLibError(
12680  "el_number_in_base_mesh_plus_one=0 for bulk",
12681  "Problem::read()",
12683  }
12684  }
12685  }
12686 
12687  // If we've made it here then we're not dealing with a
12688  // FaceElement but with an element that doesn't exist locally
12689  // --> WTF?
12690  if (el_number_in_base_mesh_plus_one == 0)
12691  {
12692  throw OomphLibError("el_number_in_base_mesh_plus_one=0",
12695  }
12696 
12697  // Assign target domain for next local non-halo element in
12698  // the order in which it's encountered in the global mesh
12699  target_domain_for_local_non_halo_element.push_back(
12700  target_domain_for_base_element[el_number_in_base_mesh_plus_one -
12701  1]);
12702 
12703  // Do elements on this processor to be moved elsewhere?
12704  if (int(target_domain_for_base_element
12705  [el_number_in_base_mesh_plus_one - 1]) != my_rank)
12706  {
12707  local_load_balance_required_flag = 1;
12708  }
12709  }
12710  }
12711 
12712  } // if (working with TreeBasedRefineableMeshBase mesh)
12713 
12714  // Get overall need to load balance by max
12715  MPI_Allreduce(&local_load_balance_required_flag,
12716  &load_balance_required_flag,
12717  1,
12718  MPI_UNSIGNED,
12719  MPI_MAX,
12720  this->communicator_pt()->mpi_comm());
12721  }
12722 
12723  // Do we need to load balance?
12724  if (load_balance_required_flag == 1)
12725  {
12726  oomph_info << "Doing load balancing after pruning\n";
12727  DocInfo doc_info;
12728  doc_info.disable_doc();
12729  bool report_stats = false;
12730  load_balance(
12731  doc_info, report_stats, target_domain_for_local_non_halo_element);
12732  oomph_info << "Done load balancing after pruning\n";
12733  }
12734  else
12735  {
12736  oomph_info << "No need for load balancing after pruning\n";
12737  }
12738  } // End of read in base element information
12739 #endif
12740 
12741 
12742  // Boolean to record if any unstructured bulk meshes have
12743  // been read in (and therefore completely re-generated, with new
12744  // elements and nodes) from disk
12745  bool have_read_unstructured_mesh = false;
12746 
12747  // Call the actions before adaptation
12749 
12750  // If there are unstructured meshes in the problem we need
12751  // to strip out any face elements that are attached to them
12752  // because restart of unstructured meshes re-creates their elements
12753  // and nodes from scratch, leading to dangling pointers from the
12754  // face elements to the old elements and nodes. This function is
12755  // virtual and (practically) empty in the Problem base class
12756  // but toggles a flag to indicate that it has been called. We can then
12757  // issue a warning below, prompting the user to consider overloading it
12758  // if the problem is found to contain unstructured bulk meshes.
12759  // Warning can be ignored if the bulk mesh is not associated with any
12760  // face elements.
12763 
12764  // Update number of submeshes
12765  n_mesh = nsub_mesh();
12766 
12767  // Single mesh:
12768  //------------
12769  if (n_mesh == 0)
12770  {
12771  // Refine single mesh (if it's refineable)
12772  if (TreeBasedRefineableMeshBase* mmesh_pt =
12773  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(0)))
12774  {
12775  // When we get in here the problem has been constructed
12776  // by the constructor and the mesh is its original unrefined
12777  // form.
12778  // RefineableMeshBase::refine(...) reads the refinement pattern from the
12779  // specified file and performs refinements until the mesh has
12780  // reached the same level of refinement as the mesh that existed
12781  // when the problem was dumped to disk.
12782  mmesh_pt->refine(restart_file);
12783  }
12784 #ifdef OOMPH_HAS_TRIANGLE_LIB
12785  // Regenerate mesh from triangulate IO if it's a triangular mesh
12786  TriangleMeshBase* mmesh_pt = dynamic_cast<TriangleMeshBase*>(mesh_pt(0));
12787  if (mmesh_pt != 0 && mmesh_pt->use_triangulateio_restart())
12788  {
12789 #ifdef OOMPH_HAS_MPI
12790  // Check if the mesh is distributed, if that is the case then
12791  // additional info. needs to be read
12792  if (mmesh_pt->is_mesh_distributed())
12793  {
12794  // Dump the info. related with the distribution of the mesh
12795  mmesh_pt->read_distributed_info_for_restart(restart_file);
12796  }
12797 #endif
12798  // The function reads the TriangulateIO data structure from the dump
12799  // file and then completely regenerates the mesh using the
12800  // data structure
12801  mmesh_pt->remesh_from_triangulateio(restart_file);
12802  have_read_unstructured_mesh = true;
12803 #ifdef OOMPH_HAS_MPI
12804  // Check if the mesh is distributed, if that is the case then we
12805  // need to re-establish the halo/haloed scheme (similar as in the
12806  // RefineableTriangleMesh::adapt() method)
12807  if (mmesh_pt->is_mesh_distributed())
12808  {
12809  mmesh_pt->reestablish_distribution_info_for_restart(
12810  this->communicator_pt(), restart_file);
12811  }
12812 #endif
12813  // Still left to update the polylines representation, that is performed
12814  // later since the nodes positions may still change when reading info.
12815  // for the mesh, see below
12816  }
12817 #endif
12818  }
12819 
12820  // Multiple submeshes
12821  //------------------
12822  else
12823  {
12824  // Loop over submeshes
12825  for (unsigned imesh = 0; imesh < n_mesh; imesh++)
12826  {
12827  // Refine single mesh (if its refineable)
12828  if (TreeBasedRefineableMeshBase* mmesh_pt =
12829  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(imesh)))
12830  {
12831  // When we get in here the problem has been constructed
12832  // by the constructor and the mesh is its original unrefined
12833  // form.
12834  // RefineableMeshBase::refine(...) reads the refinement pattern from
12835  // the specified file and performs refinements until the mesh has
12836  // reached the same level of refinement as the mesh that existed
12837  // when the problem was dumped to disk.
12838  mmesh_pt->refine(restart_file);
12839  }
12840 #ifdef OOMPH_HAS_TRIANGLE_LIB
12841  // Regenerate mesh from triangulate IO if it's a triangular mesh
12842  TriangleMeshBase* mmesh_pt =
12843  dynamic_cast<TriangleMeshBase*>(mesh_pt(imesh));
12844  if (mmesh_pt != 0 && mmesh_pt->use_triangulateio_restart())
12845  {
12846 #ifdef OOMPH_HAS_MPI
12847  // Check if the mesh is distributed, if that is the case then
12848  // additional info. needs to be read
12849  if (mmesh_pt->is_mesh_distributed())
12850  {
12851  // Dump the info. related with the distribution of the mesh
12852  mmesh_pt->read_distributed_info_for_restart(restart_file);
12853  }
12854 #endif
12855  // The function reads the TriangulateIO data structure from the dump
12856  // file and then completely regenerates the mesh using the
12857  // data structure
12858  mmesh_pt->remesh_from_triangulateio(restart_file);
12859  have_read_unstructured_mesh = true;
12860 
12861 #ifdef OOMPH_HAS_MPI
12862  // Check if the mesh is distributed, if that is the case then we
12863  // need to re-establish the halo/haloed scheme (similar as in the
12864  // RefineableTriangleMesh::adapt() method)
12865  if (mmesh_pt->is_mesh_distributed())
12866  {
12867  mmesh_pt->reestablish_distribution_info_for_restart(
12868  this->communicator_pt(), restart_file);
12869  }
12870 #endif
12871  // Still left to update the polylines representation, that is
12872  // performed later since the nodes positions may still change when
12873  // reading info. for the mesh, see below
12874  }
12875 #endif
12876  } // End of loop over submeshes
12877 
12878 
12879  // Rebuild the global mesh
12881  }
12882 
12883  // Any actions after adapt
12885 
12886  // Re-attach face elements (or whatever else needs to be done
12887  // following the total re-generation of the unstructured meshes
12890 
12891 
12892  // Issue warning:
12894  {
12895  if (have_read_unstructured_mesh)
12896  {
12899  {
12900  std::ostringstream warn_message;
12901  warn_message
12902  << "I've just read in some unstructured meshes and have, in\n"
12903  << "the process, totally re-generated their nodes and elements.\n"
12904  << "This may create dangling pointers that still point to the\n"
12905  << "old nodes and elements, e.g. because FaceElements were\n"
12906  << "attached to these meshes or pointers to nodes and elements\n"
12907  << "were stored somewhere. FaceElements should therefore be\n"
12908  << "removed before reading in these meshes, using an overloaded\n"
12909  << "version of the function\n\n"
12910  << " Problem::actions_before_read_unstructured_meshes()\n\n"
12911  << "and then re-attached using an overloaded version of\n\n"
12912  << " Problem::actions_after_read_unstructured_meshes().\n\n"
12913  << "The required content of these functions is likely to be "
12914  "similar\n"
12915  << "to the Problem::actions_before_adapt() and \n"
12916  << "Problem::actions_after_adapt() that would be required in\n"
12917  << "a spatially adaptive computation. If these functions already\n"
12918  << "exist and perform the required actions, the \n"
12919  << "actions_before/after_read_unstructured_meshes() functions\n"
12920  << "can remain empty because the former are called automatically.\n"
12921  << "In this case, this warning my be suppressed by setting the\n"
12922  << "public boolean\n\n"
12923  << " "
12924  "Problem::Suppress_warning_about_actions_before_read_"
12925  "unstructured_meshes\n\n"
12926  << "to true." << std::endl;
12927  OomphLibWarning(warn_message.str(),
12930  }
12931  }
12932  }
12933 
12934  // Setup equation numbering scheme
12935  oomph_info << "\nNumber of equations in Problem::read(): "
12936  << assign_eqn_numbers() << std::endl
12937  << std::endl;
12938  // Read time info
12939  //---------------
12940  unsigned local_unsteady_restart_flag = 0;
12941  double local_time = -DBL_MAX;
12942  unsigned local_n_dt = 0;
12943 #ifdef OOMPH_HAS_MPI
12944  unsigned local_sync_needed_flag = 0;
12945 #endif
12946  Vector<double> local_dt;
12947 
12948  if (restart_file.is_open())
12949  {
12950  oomph_info << "Restart file exists" << std::endl;
12951 #ifdef OOMPH_HAS_MPI
12952  local_sync_needed_flag = 0;
12953 #endif
12954  // Read line up to termination sign
12955  getline(restart_file, input_string, '#');
12956 
12957  // Ignore rest of line
12958  restart_file.ignore(80, '\n');
12959 
12960  // Is the restart data from an unsteady run?
12961  local_unsteady_restart_flag = atoi(input_string.c_str());
12962 
12963  // Read line up to termination sign
12964  getline(restart_file, input_string, '#');
12965 
12966  // Ignore rest of line
12967  restart_file.ignore(80, '\n');
12968 
12969  // Read in initial time and set
12970  local_time = atof(input_string.c_str());
12971 
12972  // Read line up to termination sign
12973  getline(restart_file, input_string, '#');
12974 
12975  // Ignore rest of line
12976  restart_file.ignore(80, '\n');
12977 
12978  // Read & set number of timesteps
12979  local_n_dt = atoi(input_string.c_str());
12980  local_dt.resize(local_n_dt);
12981 
12982  // Read in timesteps:
12983  for (unsigned i = 0; i < local_n_dt; i++)
12984  {
12985  // Read line up to termination sign
12986  getline(restart_file, input_string, '#');
12987 
12988  // Ignore rest of line
12989  restart_file.ignore(80, '\n');
12990 
12991  // Read in initial time and set
12992  double prev_dt = atof(input_string.c_str());
12993  local_dt[i] = prev_dt;
12994  }
12995  }
12996  else
12997  {
12998  oomph_info << "Restart file does not exist" << std::endl;
12999 #ifdef OOMPH_HAS_MPI
13000  local_sync_needed_flag = 1;
13001 #endif
13002  }
13003 
13004 
13005  // No prepare global values, possibly via sync
13006  Vector<double> dt;
13007 
13008  // Do we need to sync?
13009  unsigned sync_needed_flag = 0;
13010 
13011 #ifdef OOMPH_HAS_MPI
13012  if (Problem_has_been_distributed)
13013  {
13014  // Get need to sync by max
13015  MPI_Allreduce(&local_sync_needed_flag,
13016  &sync_needed_flag,
13017  1,
13018  MPI_UNSIGNED,
13019  MPI_MAX,
13020  this->communicator_pt()->mpi_comm());
13021  }
13022 #endif
13023 
13024  // Synchronise
13025  if (sync_needed_flag == 1)
13026  {
13027 #ifdef OOMPH_HAS_MPI
13028 
13029 
13030 #ifdef PARANOID
13031  if (!Problem_has_been_distributed)
13032  {
13033  std::ostringstream error_message;
13034  error_message << "Synchronisation of temporal restart data \n"
13035  << "required even though Problem hasn't been distributed "
13036  "-- very odd!\n";
13037  throw OomphLibError(error_message.str(),
13040  }
13041 #endif
13042 
13043  // Get unsteady restart flag by max-based reduction
13044  unsigned unsteady_restart_flag = 0;
13045  MPI_Allreduce(&local_unsteady_restart_flag,
13046  &unsteady_restart_flag,
13047  1,
13048  MPI_UNSIGNED,
13049  MPI_MAX,
13050  this->communicator_pt()->mpi_comm());
13051 
13052  // So, is it an unsteady restart?
13053  unsteady_restart = false;
13054  if (unsteady_restart_flag == 1)
13055  {
13056  unsteady_restart = true;
13057 
13058  // Get time by max
13059  double time = -DBL_MAX;
13060  MPI_Allreduce(&local_time,
13061  &time,
13062  1,
13063  MPI_DOUBLE,
13064  MPI_MAX,
13065  this->communicator_pt()->mpi_comm());
13066  time_pt()->time() = time;
13067 
13068  // Get number of timesteps by max-based reduction
13069  unsigned n_dt = 0;
13070  MPI_Allreduce(&local_n_dt,
13071  &n_dt,
13072  1,
13073  MPI_UNSIGNED,
13074  MPI_MAX,
13075  this->communicator_pt()->mpi_comm());
13076 
13077  // Resize whatever needs resizing
13078  time_pt()->resize(n_dt);
13079  dt.resize(n_dt);
13080  if (local_dt.size() == 0)
13081  {
13082  local_dt.resize(n_dt, -DBL_MAX);
13083  }
13084 
13085  // Get timesteps increments by max-based reduction
13086  MPI_Allreduce(&local_dt[0],
13087  &dt[0],
13088  n_dt,
13089  MPI_DOUBLE,
13090  MPI_MAX,
13091  this->communicator_pt()->mpi_comm());
13092  }
13093 
13094 #else
13095 
13096  std::ostringstream error_message;
13097  error_message
13098  << "Synchronisation of temporal restart data \n"
13099  << "required even though we don't have mpi support -- very odd!\n";
13100  throw OomphLibError(
13101  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13102 
13103 #endif
13104  }
13105  // No sync needed -- just copy across
13106  else
13107  {
13108  unsteady_restart = false;
13109  if (local_unsteady_restart_flag == 1)
13110  {
13111  unsteady_restart = true;
13112  time_pt()->time() = local_time;
13113  time_pt()->resize(local_n_dt);
13114  dt.resize(local_n_dt);
13115  for (unsigned i = 0; i < local_n_dt; i++)
13116  {
13117  dt[i] = local_dt[i];
13118  }
13119  }
13120  }
13121 
13122  // Initialise timestep -- also sets the weights for all timesteppers
13123  // in the problem.
13124  if (unsteady_restart) initialise_dt(dt);
13125 
13126  // Loop over submeshes:
13127  unsigned nmesh = nsub_mesh();
13128  if (nmesh == 0) nmesh = 1;
13129  for (unsigned m = 0; m < nmesh; m++)
13130  {
13131  // //---------------------------------------------------------
13132  // // Keep this commented out code around to debug restarts
13133  // //---------------------------------------------------------
13134  // std::ofstream some_file;
13135  // char filename[100];
13136  // sprintf(filename,"read_mesh%i_on_proc%i.dat",m,
13137  // this->communicator_pt()->my_rank());
13138  // some_file.open(filename);
13139  // mesh_pt(m)->output(some_file);
13140  // some_file.close();
13141 
13142  // sprintf(filename,"read_mesh%i_with_haloes_on_proc%i.dat",m,
13143  // this->communicator_pt()->my_rank());
13144  // mesh_pt(m)->enable_output_of_halo_elements();
13145  // some_file.open(filename);
13146  // mesh_pt(m)->output(some_file);
13147  // mesh_pt(m)->disable_output_of_halo_elements();
13148  // some_file.close();
13149  // oomph_info << "Doced mesh " << m << " before reading\n";
13150 
13151  // sprintf(filename,"read_nodes_mesh%i_on_proc%i.dat",m,
13152  // this->communicator_pt()->my_rank());
13153  // some_file.open(filename);
13154  // unsigned nnod=mesh_pt(m)->nnode();
13155  // for (unsigned j=0;j<nnod;j++)
13156  // {
13157  // Node* nod_pt=mesh_pt(m)->node_pt(j);
13158  // unsigned n=nod_pt->ndim();
13159  // for (unsigned i=0;i<n;i++)
13160  // {
13161  // some_file << nod_pt->x(i) << " ";
13162  // }
13163  // some_file << nod_pt->is_halo() << " "
13164  // << nod_pt->nvalue() << " "
13165  // << nod_pt->hang_code() << "\n";
13166  // }
13167  // some_file.close();
13168  // oomph_info << "Doced mesh " << m << " before reading\n";
13169  // //---------------------------------------------------------
13170  // // End keep this commented out code around to debug restarts
13171  // //---------------------------------------------------------
13172 
13173  mesh_pt(m)->read(restart_file);
13174 
13175 #ifdef OOMPH_HAS_TRIANGLE_LIB
13176  // Here update the polyline representation if working with
13177  // triangle base meshes
13178  if (TriangleMeshBase* mmesh_pt =
13179  dynamic_cast<TriangleMeshBase*>(mesh_pt(m)))
13180  {
13181  // In charge of updating the polylines representation to the
13182  // current refinement/unrefinement level after restart, it
13183  // also update the shared boundaries in case of working with a
13184  // distributed mesh
13185  mmesh_pt->update_polyline_representation_from_restart();
13186  }
13187 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
13188  }
13189 
13190  // Read global data:
13191  //------------------
13192 
13193  // Number of global data
13194  unsigned Nglobal = Global_data_pt.size();
13195 
13196  // Read line up to termination sign
13197  getline(restart_file, input_string, '#');
13198 
13199  // Ignore rest of line
13200  restart_file.ignore(80, '\n');
13201 
13202  // Check # of nodes:
13203  unsigned long check_nglobal = atoi(input_string.c_str());
13204 
13205 
13206  if (restart_file_is_open)
13207  {
13208  if (check_nglobal != Nglobal)
13209  {
13210  std::ostringstream error_message;
13211  error_message << "The number of global data " << Nglobal
13212  << " is not equal to that specified in the input file "
13213  << check_nglobal << std::endl;
13214 
13215  throw OomphLibError(error_message.str(),
13218  }
13219  }
13220 
13221  for (unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
13222  {
13223  Global_data_pt[iglobal]->read(restart_file);
13224  }
13225  }
virtual void read(std::ifstream &restart_file)
Read solution from restart file.
Definition: mesh.cc:1130
static bool Suppress_warning_about_actions_before_read_unstructured_meshes
Definition: problem.h:317
virtual void actions_after_read_unstructured_meshes()
Definition: problem.h:1109
void refine_uniformly()
Definition: problem.h:2640
virtual void actions_before_read_unstructured_meshes()
Definition: problem.h:1095

References actions_after_adapt(), actions_after_read_unstructured_meshes(), actions_before_adapt(), actions_before_read_unstructured_meshes(), assign_eqn_numbers(), oomph::FaceElement::bulk_element_pt(), Communicator_pt, communicator_pt(), oomph::DocInfo::disable_doc(), e(), oomph::Mesh::element_pt(), Empty_actions_after_read_unstructured_meshes_has_been_called, Empty_actions_before_read_unstructured_meshes_has_been_called, oomph::TreeBasedRefineableMeshBase::get_refinement_levels(), Global_data_pt, i, initialise_dt(), oomph::Mesh::is_mesh_distributed(), m, max, mesh_pt(), oomph::OomphCommunicator::my_rank(), oomph::Mesh::nelement(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, oomph::Mesh::read(), rebuild_global_mesh(), refine_uniformly(), oomph::Time::resize(), oomph::Global_string_for_annotation::string(), Suppress_warning_about_actions_before_read_unstructured_meshes, time(), oomph::Time::time(), time_pt(), and tmp.

Referenced by oomph::MyProblem::read(), and read().

◆ rebuild_global_mesh()

void Problem::rebuild_global_mesh ( )

If one of the submeshes has changed (e.g. by mesh adaptation) we need to update the global mesh. Note: The nodes boundary information refers to the boundary numbers within the submesh!

If one of the submeshes has changed (e.g. by mesh adaptation) we need to update the global mesh. Note: The nodes boundary information refers to the boundary numbers within the submesh! N.B. This is essentially the same function as the Mesh constructor that assembles a single global mesh from submeshes

1534  {
1535  // Use the function in mesh to merge the submeshes into this one
1537  }
void merge_meshes(const Vector< Mesh * > &sub_mesh_pt)
Definition: mesh.cc:65

References oomph::Mesh::merge_meshes(), Mesh_pt, and Sub_mesh_pt.

Referenced by ContactProblem< ELEMENT >::actions_after_adapt(), ContactProblem< ELEMENT >::actions_before_adapt(), adapt(), adapt_based_on_error_estimates(), build_global_mesh(), main(), p_adapt(), p_refine_selected_elements(), p_refine_uniformly(), p_refine_uniformly_aux(), p_unrefine_uniformly(), read(), oomph::SegregatableFSIProblem::rebuild_monolithic_mesh(), refine_selected_elements(), refine_uniformly(), refine_uniformly_aux(), unrefine_uniformly(), oomph::SegregatableFSIProblem::use_only_fluid_elements(), and oomph::SegregatableFSIProblem::use_only_solid_elements().

◆ refine_selected_elements() [1/6]

void Problem::refine_selected_elements ( const unsigned i_mesh,
const Vector< RefineableElement * > &  elements_to_be_refined_pt 
)

Refine specified submesh by splitting the elements identified by their pointers, then rebuild the problem.

15040  {
15042 
15043  // Number of submeshes?
15044  unsigned n_mesh = nsub_mesh();
15045 
15046  if (i_mesh >= n_mesh)
15047  {
15048  std::ostringstream error_message;
15049  error_message << "Problem only has " << n_mesh
15050  << " submeshes. Cannot refine submesh " << i_mesh
15051  << std::endl;
15052  throw OomphLibError(
15053  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15054  }
15055 
15056  // Refine single mesh if possible
15057  if (TreeBasedRefineableMeshBase* mmesh_pt =
15058  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(i_mesh)))
15059  {
15060  mmesh_pt->refine_selected_elements(elements_to_be_refined_pt);
15061  }
15062  else
15063  {
15064  oomph_info << "Info/Warning: Mesh cannot be refined " << std::endl;
15065  }
15066 
15067  if (n_mesh > 1)
15068  {
15069  // Rebuild the global mesh
15071  }
15072 
15073  // Any actions after the adapatation phase
15075 
15076  // Do equation numbering
15077  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
15078  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, and rebuild_global_mesh().

◆ refine_selected_elements() [2/6]

void Problem::refine_selected_elements ( const unsigned i_mesh,
const Vector< unsigned > &  elements_to_be_refined 
)

Refine specified submesh by splitting the elements identified by their numbers relative to the submesh, then rebuild the problem.

Refine specified submesh by splitting the elements identified by their numbers relative to the specified mesh, then rebuild the problem.

14992  {
14994 
14995  // Number of submeshes?
14996  unsigned n_mesh = nsub_mesh();
14997 
14998  if (i_mesh >= n_mesh)
14999  {
15000  std::ostringstream error_message;
15001  error_message << "Problem only has " << n_mesh
15002  << " submeshes. Cannot refine submesh " << i_mesh
15003  << std::endl;
15004  throw OomphLibError(
15005  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15006  }
15007 
15008  // Refine single mesh if possible
15009  if (TreeBasedRefineableMeshBase* mmesh_pt =
15010  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(i_mesh)))
15011  {
15012  mmesh_pt->refine_selected_elements(elements_to_be_refined);
15013  }
15014  else
15015  {
15016  oomph_info << "Info/Warning: Mesh cannot be refined " << std::endl;
15017  }
15018 
15019  if (n_mesh > 1)
15020  {
15021  // Rebuild the global mesh
15023  }
15024 
15025  // Any actions after the adapatation phase
15027 
15028  // Do equation numbering
15029  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
15030  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, and rebuild_global_mesh().

◆ refine_selected_elements() [3/6]

void Problem::refine_selected_elements ( const Vector< RefineableElement * > &  elements_to_be_refined_pt)

Refine (one and only!) mesh by splitting the elements identified by their pointers, then rebuild the problem.

14946  {
14948 
14949  // Number of submeshes?
14950  unsigned Nmesh = nsub_mesh();
14951 
14952  // Single mesh:
14953  if (Nmesh == 0)
14954  {
14955  // Refine single mesh if possible
14956  if (TreeBasedRefineableMeshBase* mmesh_pt =
14957  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(0)))
14958  {
14959  mmesh_pt->refine_selected_elements(elements_to_be_refined_pt);
14960  }
14961  else
14962  {
14963  oomph_info << "Info/Warning: Mesh cannot be refined " << std::endl;
14964  }
14965  }
14966  // Multiple submeshes
14967  else
14968  {
14969  std::ostringstream error_message;
14970  error_message << "Problem::refine_selected_elements(...) only works for\n"
14971  << "multiple-mesh problems if you specify the mesh\n"
14972  << "number in the function argument before the Vector,\n"
14973  << "or a Vector of Vectors for each submesh.\n"
14974  << std::endl;
14975  throw OomphLibError(
14976  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
14977  }
14978 
14979  // Any actions after the adapatation phase
14981 
14982  // Do equation numbering
14983  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
14984  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and oomph::oomph_info.

◆ refine_selected_elements() [4/6]

void Problem::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 problems' only mesh, then rebuild the problem.

14900  {
14902 
14903  // Number of submeshes?
14904  unsigned Nmesh = nsub_mesh();
14905 
14906  // Single mesh:
14907  if (Nmesh == 0)
14908  {
14909  // Refine single mesh if possible
14910  if (TreeBasedRefineableMeshBase* mmesh_pt =
14911  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(0)))
14912  {
14913  mmesh_pt->refine_selected_elements(elements_to_be_refined);
14914  }
14915  else
14916  {
14917  oomph_info << "Info/Warning: Mesh cannot be refined " << std::endl;
14918  }
14919  }
14920  // Multiple submeshes
14921  else
14922  {
14923  std::ostringstream error_message;
14924  error_message << "Problem::refine_selected_elements(...) only works for\n"
14925  << "multiple-mesh problems if you specify the mesh\n"
14926  << "number in the function argument before the Vector,\n"
14927  << "or a Vector of Vectors for each submesh.\n"
14928  << std::endl;
14929  throw OomphLibError(
14930  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
14931  }
14932 
14933  // Any actions after the adapatation phase
14935 
14936  // Attach the boundary conditions to the mesh
14937  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
14938  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and oomph::oomph_info.

◆ refine_selected_elements() [5/6]

void Problem::refine_selected_elements ( const Vector< Vector< RefineableElement * >> &  elements_to_be_refined_pt)

Refine all submeshes by splitting the elements identified by their pointers within each submesh in a Vector of Vectors, then rebuild the problem.

15124  {
15126 
15127  // Number of submeshes?
15128  unsigned n_mesh = nsub_mesh();
15129 
15130  // Refine all submeshes if possible
15131  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
15132  {
15133  if (TreeBasedRefineableMeshBase* mmesh_pt =
15134  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(i_mesh)))
15135  {
15136  mmesh_pt->refine_selected_elements(elements_to_be_refined_pt[i_mesh]);
15137  }
15138  else
15139  {
15140  oomph_info << "Info/Warning: Mesh cannot be refined " << std::endl;
15141  }
15142  }
15143 
15144  // Rebuild the global mesh
15146 
15147  // Any actions after the adapatation phase
15149 
15150  // Do equation numbering
15151  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
15152  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), oomph::oomph_info, and rebuild_global_mesh().

◆ refine_selected_elements() [6/6]

void Problem::refine_selected_elements ( const Vector< Vector< unsigned >> &  elements_to_be_refined)

Refine all submeshes by splitting the elements identified by their numbers relative to each submesh in a Vector of Vectors, then rebuild the problem.

15087  {
15089 
15090  // Number of submeshes?
15091  unsigned n_mesh = nsub_mesh();
15092 
15093  // Refine all submeshes if possible
15094  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
15095  {
15096  if (TreeBasedRefineableMeshBase* mmesh_pt =
15097  dynamic_cast<TreeBasedRefineableMeshBase*>(mesh_pt(i_mesh)))
15098  {
15099  mmesh_pt->refine_selected_elements(elements_to_be_refined[i_mesh]);
15100  }
15101  else
15102  {
15103  oomph_info << "Info/Warning: Mesh cannot be refined " << std::endl;
15104  }
15105  }
15106 
15107  // Rebuild the global mesh
15109 
15110  // Any actions after the adapatation phase
15112 
15113  // Do equation numbering
15114  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
15115  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), oomph::oomph_info, and rebuild_global_mesh().

◆ refine_uniformly() [1/6]

void oomph::Problem::refine_uniformly ( )
inline

◆ refine_uniformly() [2/6]

void oomph::Problem::refine_uniformly ( const unsigned i_mesh)
inline

Do uniform refinement for submesh i_mesh without documentation.

2652  {
2653  DocInfo doc_info;
2654  doc_info.disable_doc();
2655  refine_uniformly(i_mesh, doc_info);
2656  }

References oomph::DocInfo::disable_doc(), and refine_uniformly().

◆ refine_uniformly() [3/6]

void Problem::refine_uniformly ( const unsigned i_mesh,
DocInfo doc_info 
)

Do uniform refinement for submesh i_mesh with documentation.

Refine submesh i_mesh uniformly and rebuild problem; doc refinement process.

15741  {
15743 
15744 #ifdef PARANOID
15745  // Number of submeshes?
15746  if (i_mesh >= nsub_mesh())
15747  {
15748  std::ostringstream error_message;
15749  error_message << "imesh " << i_mesh
15750  << " is greater than the number of sub meshes "
15751  << nsub_mesh() << std::endl;
15752 
15753  throw OomphLibError(
15754  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15755  }
15756 #endif
15757 
15758  // Refine single mesh uniformly if possible
15759  if (RefineableMeshBase* mmesh_pt =
15760  dynamic_cast<RefineableMeshBase*>(mesh_pt(i_mesh)))
15761  {
15762  mmesh_pt->refine_uniformly(doc_info);
15763  }
15764  else
15765  {
15766  oomph_info << "Info/Warning: Mesh cannot be refined uniformly "
15767  << std::endl;
15768  }
15769 
15770  // Rebuild the global mesh
15772 
15773  // Any actions after the adaptation phase
15775 
15776  // Do equation numbering
15777  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
15778  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, and rebuild_global_mesh().

◆ refine_uniformly() [4/6]

void oomph::Problem::refine_uniformly ( const Vector< unsigned > &  nrefine_for_mesh)
inline

Refine refineable sub-meshes, each as many times as specified in the vector and rebuild problem

2576  {
2577  DocInfo doc_info;
2578  doc_info.disable_doc();
2579  bool prune = false;
2580  refine_uniformly_aux(nrefine_for_mesh, doc_info, prune);
2581  }
void refine_uniformly_aux(const Vector< unsigned > &nrefine_for_mesh, DocInfo &doc_info, const bool &prune)
Definition: problem.cc:15445

References oomph::DocInfo::disable_doc(), and refine_uniformly_aux().

Referenced by main(), and parallel_test().

◆ refine_uniformly() [5/6]

void oomph::Problem::refine_uniformly ( const Vector< unsigned > &  nrefine_for_mesh,
DocInfo doc_info 
)
inline

Refine refineable sub-meshes, each as many times as specified in the vector and rebuild problem; doc refinement process

2587  {
2588  bool prune = false;
2589  refine_uniformly_aux(nrefine_for_mesh, doc_info, prune);
2590  }

References refine_uniformly_aux().

◆ refine_uniformly() [6/6]

void oomph::Problem::refine_uniformly ( DocInfo doc_info)
inline

Refine (all) refineable (sub)mesh(es) uniformly and rebuild problem; doc refinement process.

2615  {
2616  // Number of (sub)meshes
2617  unsigned nmesh = std::max(unsigned(1), nsub_mesh());
2618 
2619  // Refine each mesh once
2620  Vector<unsigned> nrefine_for_mesh(nmesh, 1);
2621  refine_uniformly(nrefine_for_mesh);
2622  }

References max, nsub_mesh(), and refine_uniformly().

◆ refine_uniformly_and_prune() [1/3]

void oomph::Problem::refine_uniformly_and_prune ( const Vector< unsigned > &  nrefine_for_mesh)
inline

Refine refineable sub-meshes, each as many times as specified in the vector and rebuild problem. Prune after refinements

2596  {
2597  DocInfo doc_info;
2598  doc_info.disable_doc();
2599  bool prune = true;
2600  refine_uniformly_aux(nrefine_for_mesh, doc_info, prune);
2601  }

References oomph::DocInfo::disable_doc(), and refine_uniformly_aux().

Referenced by refine_uniformly_and_prune().

◆ refine_uniformly_and_prune() [2/3]

void oomph::Problem::refine_uniformly_and_prune ( const Vector< unsigned > &  nrefine_for_mesh,
DocInfo doc_info 
)
inline

Refine refineable sub-meshes, each as many times as specified in the vector and rebuild problem; doc refinement process

2607  {
2608  bool prune = true;
2609  refine_uniformly_aux(nrefine_for_mesh, doc_info, prune);
2610  }

References refine_uniformly_aux().

◆ refine_uniformly_and_prune() [3/3]

void oomph::Problem::refine_uniformly_and_prune ( DocInfo doc_info)
inline

Refine (all) refineable (sub)mesh(es) uniformly and rebuild problem; doc refinement process.

2628  {
2629  // Number of (sub)meshes
2630  unsigned nmesh = std::max(unsigned(1), nsub_mesh());
2631 
2632  // Refine each mesh once
2633  Vector<unsigned> nrefine_for_mesh(nmesh, 1);
2634  refine_uniformly_and_prune(nrefine_for_mesh);
2635  }
void refine_uniformly_and_prune(const Vector< unsigned > &nrefine_for_mesh)
Definition: problem.h:2595

References max, nsub_mesh(), and refine_uniformly_and_prune().

◆ refine_uniformly_aux()

void Problem::refine_uniformly_aux ( const Vector< unsigned > &  nrefine_for_mesh,
DocInfo doc_info,
const bool prune 
)
private

Helper function to do compund refinement of (all) refineable (sub)mesh(es) uniformly as many times as specified in vector and rebuild problem; doc refinement process. Set boolean argument to true if you want to prune immediately after refining the meshes individually.

15448  {
15449  double t_start = 0.0;
15451  {
15452  t_start = TimingHelpers::timer();
15453  }
15454 
15456 
15457  double t_end = 0.0;
15459  {
15460  t_end = TimingHelpers::timer();
15461  oomph_info
15462  << "Time for actions before adapt in Problem::refine_uniformly_aux(): "
15463  << t_end - t_start << std::endl;
15464  t_start = TimingHelpers::timer();
15465  }
15466 
15467  // Number of submeshes?
15468  unsigned n_mesh = nsub_mesh();
15469 
15470  // Single mesh:
15471  if (n_mesh == 0)
15472  {
15473  // Refine single mesh uniformly if possible
15474  if (RefineableMeshBase* mmesh_pt =
15475  dynamic_cast<RefineableMeshBase*>(mesh_pt(0)))
15476  {
15477  unsigned nref = nrefine_for_mesh[0];
15478  for (unsigned i = 0; i < nref; i++)
15479  {
15480  mmesh_pt->refine_uniformly(doc_info);
15481  }
15482  }
15483  else
15484  {
15485  oomph_info << "Info/Warning: Mesh cannot be refined uniformly "
15486  << std::endl;
15487  }
15488  }
15489  // Multiple submeshes
15490  else
15491  {
15492  // Loop over submeshes
15493  for (unsigned imesh = 0; imesh < n_mesh; imesh++)
15494  {
15495  // Refine i-th submesh uniformly if possible
15496  if (RefineableMeshBase* mmesh_pt =
15497  dynamic_cast<RefineableMeshBase*>(mesh_pt(imesh)))
15498  {
15499  unsigned nref = nrefine_for_mesh[imesh];
15500  for (unsigned i = 0; i < nref; i++)
15501  {
15502  mmesh_pt->refine_uniformly(doc_info);
15503  }
15504  }
15505  else
15506  {
15507  oomph_info << "Info/Warning: Cannot refine mesh " << imesh
15508  << std::endl;
15509  }
15510  }
15511  // Rebuild the global mesh
15513  }
15514 
15516  {
15517  t_end = TimingHelpers::timer();
15518  oomph_info << "Time for mesh-level mesh refinement in "
15519  << "Problem::refine_uniformly_aux(): " << t_end - t_start
15520  << std::endl;
15521  t_start = TimingHelpers::timer();
15522  }
15523 
15524  // Any actions after the adaptation phase
15526 
15527 
15529  {
15530  t_end = TimingHelpers::timer();
15531  oomph_info
15532  << "Time for actions after adapt Problem::refine_uniformly_aux(): "
15533  << t_end - t_start << std::endl;
15534  t_start = TimingHelpers::timer();
15535  }
15536 
15537 
15538 #ifdef OOMPH_HAS_MPI
15539 
15540  // Prune it?
15541  if (prune)
15542  {
15543  // Note: This calls assign eqn numbers already...
15544  Bypass_increase_in_dof_check_during_pruning = true;
15545  prune_halo_elements_and_nodes();
15546  Bypass_increase_in_dof_check_during_pruning = false;
15547 
15549  {
15550  t_end = TimingHelpers::timer();
15551  oomph_info << "Time for Problem::prune_halo_elements_and_nodes() in "
15552  << "Problem::refine_uniformly_aux(): " << t_end - t_start
15553  << std::endl;
15554  }
15555  }
15556  else
15557 #else
15558  if (prune)
15559  {
15560  std::ostringstream error_message;
15561  error_message
15562  << "Requested pruning in serial build. Ignoring the request.\n";
15563  OomphLibWarning(error_message.str(),
15564  "Problem::refine_uniformly_aux()",
15566  }
15567 #endif
15568  {
15569  // Do equation numbering
15570  oomph_info
15571  << "Number of equations after Problem::refine_uniformly_aux(): "
15572  << assign_eqn_numbers() << std::endl;
15573 
15575  {
15576  t_end = TimingHelpers::timer();
15577  oomph_info << "Time for Problem::assign_eqn_numbers() in "
15578  << "Problem::refine_uniformly_aux(): " << t_end - t_start
15579  << std::endl;
15580  }
15581  }
15582  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), oomph::Global_timings::Doc_comprehensive_timings, i, mesh_pt(), nsub_mesh(), OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, rebuild_global_mesh(), and oomph::TimingHelpers::timer().

Referenced by refine_uniformly(), and refine_uniformly_and_prune().

◆ reset_arc_length_parameters()

void oomph::Problem::reset_arc_length_parameters ( )
inline

Reset the "internal" arc-length continuation parameters, so as to allow continuation in another parameter. N.B. The parameters that are reset are the "minimum" that are required, others should perhaps be reset, depending upon the application.

2410  {
2411  Theta_squared = 1.0;
2412  Sign_of_jacobian = 0;
2413  Continuation_direction = 1.0;
2414  Parameter_derivative = 1.0;
2416  Arc_length_step_taken = false;
2417  Dof_derivative.resize(0);
2418  }

References Arc_length_step_taken, Continuation_direction, Dof_derivative, First_jacobian_sign_change, Parameter_derivative, Sign_of_jacobian, and Theta_squared.

◆ reset_assembly_handler_to_default()

void Problem::reset_assembly_handler_to_default ( )

Reset the system to the standard non-augemented state.

Reset the assembly handler to default.

10276  {
10277  // If we have a non-default handler
10279  {
10280  // Delete the current assembly handler
10281  delete Assembly_handler_pt;
10282  // Reset the assembly handler
10284  }
10285  }

References Assembly_handler_pt, and Default_assembly_handler_pt.

Referenced by activate_bifurcation_tracking(), activate_fold_tracking(), activate_hopf_tracking(), activate_pitchfork_tracking(), and deactivate_bifurcation_tracking().

◆ restore_dof_values()

void Problem::restore_dof_values ( )

Restore the stored values of the degrees of freedom.

Restore the saved dofs.

8654  {
8655  // Check that we can do this
8656  if (Saved_dof_pt == 0)
8657  {
8658  throw OomphLibError(
8659  "There are no stored values, use store_current_dof_values()\n",
8662  }
8663 
8664 
8665 #ifdef OOMPH_HAS_MPI
8666  // If the problem is distributed I have to do something different
8667  if (Problem_has_been_distributed)
8668  {
8669  // How many entries do we store locally?
8670  const unsigned n_row_local = Dof_distribution_pt->nrow_local();
8671 
8672  if (Saved_dof_pt->size() != n_row_local)
8673  {
8674  throw OomphLibError("The number of stored values is not equal to the "
8675  "current number of dofs\n",
8678  }
8679 
8680  // Transfer the values over
8681  for (unsigned long n = 0; n < n_row_local; n++)
8682  {
8683  *(this->Dof_pt[n]) = (*Saved_dof_pt)[n];
8684  }
8685  }
8686  // Otherwise just restore all the dofs
8687  else
8688 #endif
8689  {
8690  // Find the number of dofs
8691  unsigned long n_dof = ndof();
8692 
8693  if (Saved_dof_pt->size() != n_dof)
8694  {
8695  throw OomphLibError("The number of stored values is not equal to the "
8696  "current number of dofs\n",
8699  }
8700 
8701  // Transfer the values over
8702  for (unsigned long n = 0; n < n_dof; n++)
8703  {
8704  dof(n) = (*Saved_dof_pt)[n];
8705  }
8706  }
8707 
8708  // Delete the memory
8709  delete Saved_dof_pt;
8710  Saved_dof_pt = 0;
8711  }

References dof(), Dof_distribution_pt, Dof_pt, n, ndof(), oomph::LinearAlgebraDistribution::nrow_local(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and Saved_dof_pt.

Referenced by calculate_predictions().

◆ self_test()

unsigned Problem::self_test ( )

Self-test: Check meshes and global data. Return 0 for OK.

13277  {
13278  // Initialise
13279  bool passed = true;
13280 
13281  // Are there any submeshes?
13282  unsigned Nmesh = nsub_mesh();
13283 
13284  // Just one mesh: Check it
13285  if (Nmesh == 0)
13286  {
13287  if (mesh_pt()->self_test() != 0)
13288  {
13289  passed = false;
13290  oomph_info
13291  << "\n ERROR: Failed Mesh::self_test() for single mesh in problem"
13292  << std::endl;
13293  }
13294  }
13295  // Loop over all submeshes and check them
13296  else
13297  {
13298  for (unsigned imesh = 0; imesh < Nmesh; imesh++)
13299  {
13300  if (mesh_pt(imesh)->self_test() != 0)
13301  {
13302  passed = false;
13303  oomph_info << "\n ERROR: Failed Mesh::self_test() for mesh imesh"
13304  << imesh << std::endl;
13305  }
13306  }
13307  }
13308 
13309 
13310  // Check global data
13311  unsigned Nglobal = Global_data_pt.size();
13312  for (unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
13313  {
13314  if (Global_data_pt[iglobal]->self_test() != 0)
13315  {
13316  passed = false;
13317  oomph_info
13318  << "\n ERROR: Failed Data::self_test() for global data iglobal"
13319  << iglobal << std::endl;
13320  }
13321  }
13322 
13323 
13324 #ifdef OOMPH_HAS_MPI
13325 
13326  if (Problem_has_been_distributed)
13327  {
13328  // Note: This throws an error if it fails so no return is required.
13329  DocInfo tmp_doc_info;
13330  tmp_doc_info.disable_doc();
13331  check_halo_schemes(tmp_doc_info);
13332  }
13333 
13334 #endif
13335 
13336  // Return verdict
13337  if (passed)
13338  {
13339  return 0;
13340  }
13341  else
13342  {
13343  return 1;
13344  }
13345  }
unsigned self_test()
Self-test: Check meshes and global data. Return 0 for OK.
Definition: problem.cc:13276

References oomph::DocInfo::disable_doc(), Global_data_pt, mesh_pt(), nsub_mesh(), and oomph::oomph_info.

Referenced by oomph::BiharmonicProblem< DIM >::actions_before_newton_solve(), oomph::BiharmonicFluidProblem< DIM >::actions_before_newton_solve(), and main().

◆ set_analytic_dparameter()

void oomph::Problem::set_analytic_dparameter ( double *const &  parameter_pt)
inline

Function to turn on analytic calculation of the parameter derivatives in continuation and bifurcation detection problems

257  {
258  Calculate_dparameter_analytic[parameter_pt] = true;
259  }

References Calculate_dparameter_analytic.

◆ set_analytic_hessian_products()

void oomph::Problem::set_analytic_hessian_products ( )
inline

Function to turn on analytic calculation of the parameter derivatives in continuation and bifurcation detection problems

290  {
292  }

References Calculate_hessian_products_analytic.

◆ set_consistent_pinned_values_for_continuation()

void Problem::set_consistent_pinned_values_for_continuation ( )
protected

Private helper function that is used to set the appropriate pinned values for continuation.

Private helper function that is used to set the appropriate pinned values for continuation. If the data is pinned, the its current value is always the same as the original value and the derivative is always zero. If these are not set properly then interpolation and projection in spatial adaptivity will not give the best answers.

10467  {
10468  // Set the consistent values for the global mesh
10471 
10472  // Deal with the spine meshes additional numbering separately
10473  const unsigned n_sub_mesh = this->nsub_mesh();
10474  // If there is only one mesh
10475  if (n_sub_mesh == 0)
10476  {
10477  if (SpineMesh* const spine_mesh_pt = dynamic_cast<SpineMesh*>(Mesh_pt))
10478  {
10479  spine_mesh_pt->set_consistent_pinned_spine_values_for_continuation(
10481  }
10482  // If it's a triangle mesh the we need to set the
10483  }
10484  // Otherwise loop over the sub meshes
10485  else
10486  {
10487  // Assign global equation numbers first
10488  for (unsigned i = 0; i < n_sub_mesh; i++)
10489  {
10490  if (SpineMesh* const spine_mesh_pt =
10491  dynamic_cast<SpineMesh*>(Sub_mesh_pt[i]))
10492  {
10493  spine_mesh_pt->set_consistent_pinned_spine_values_for_continuation(
10495  }
10496  }
10497  }
10498 
10499  // Also set time stepper for global data
10500  const unsigned n_global = Global_data_pt.size();
10501  for (unsigned i = 0; i < n_global; ++i)
10502  {
10504  }
10505  }
void set_consistent_pinned_values(Data *const &data_pt)
Definition: generalised_timesteppers.h:221
void set_consistent_pinned_values_for_continuation(ContinuationStorageScheme *const &continuation_stepper_pt)
Set consistent values for pinned data in continuation.
Definition: mesh.cc:2436

References Continuation_time_stepper, Global_data_pt, i, Mesh_pt, nsub_mesh(), oomph::ContinuationStorageScheme::set_consistent_pinned_values(), oomph::Mesh::set_consistent_pinned_values_for_continuation(), and Sub_mesh_pt.

Referenced by arc_length_step_solve_helper().

◆ set_dofs() [1/3]

void Problem::set_dofs ( const DoubleVector dofs)
virtual

Set the values of the dofs.

Function that sets the values of the dofs in the object.

Reimplemented from oomph::ExplicitTimeSteppableObject.

3412  {
3413  const unsigned long n_dof = this->ndof();
3414 #ifdef PARANOID
3415  if (n_dof != dofs.nrow())
3416  {
3417  std::ostringstream error_stream;
3418  error_stream << "Number of degrees of freedom in vector argument "
3419  << dofs.nrow() << "\n"
3420  << "does not equal number of degrees of freedom in problem "
3421  << n_dof;
3422  throw OomphLibError(
3423  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3424  }
3425 #endif
3426  for (unsigned long l = 0; l < n_dof; l++)
3427  {
3428  *Dof_pt[l] = dofs[l];
3429  }
3430  }

References Dof_pt, ndof(), oomph::DistributableLinearAlgebraObject::nrow(), OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

Referenced by calculate_predictions(), and oomph::TR::setup_initial_derivative().

◆ set_dofs() [2/3]

void Problem::set_dofs ( const unsigned t,
DoubleVector dofs 
)

Set the history values of the dofs.

Set history values of dofs.

3434  {
3435 #ifdef PARANOID
3436  if (distributed())
3437  {
3438  throw OomphLibError("Not designed for distributed problems",
3441  // might work if the dofs vector is distributed in the right way...
3442  }
3443 #endif
3444 
3445  // First deal with global data
3446  unsigned Nglobal_data = nglobal_data();
3447  for (unsigned i = 0; i < Nglobal_data; i++)
3448  {
3449  for (unsigned j = 0, nj = Global_data_pt[i]->nvalue(); j < nj; j++)
3450  {
3451  // For each data get the equation number and copy out the value.
3452  int eqn_number = Global_data_pt[i]->eqn_number(j);
3453  if (eqn_number >= 0)
3454  {
3455  Global_data_pt[i]->set_value(t, j, dofs[eqn_number]);
3456  }
3457  }
3458  }
3459 
3460  // Next element internal data
3461  for (unsigned i = 0, ni = mesh_pt()->nelement(); i < ni; i++)
3462  {
3463  GeneralisedElement* ele_pt = mesh_pt()->element_pt(i);
3464  for (unsigned j = 0, nj = ele_pt->ninternal_data(); j < nj; j++)
3465  {
3466  Data* d_pt = ele_pt->internal_data_pt(j);
3467  for (unsigned k = 0, nk = d_pt->nvalue(); k < nk; k++)
3468  {
3469  int eqn_number = d_pt->eqn_number(k);
3470  if (eqn_number >= 0)
3471  {
3472  d_pt->set_value(t, k, dofs[eqn_number]);
3473  }
3474  }
3475  }
3476  }
3477 
3478  // Now the nodes
3479  for (unsigned i = 0, ni = mesh_pt()->nnode(); i < ni; i++)
3480  {
3481  Node* node_pt = mesh_pt()->node_pt(i);
3482  for (unsigned j = 0, nj = node_pt->nvalue(); j < nj; j++)
3483  {
3484  // For each node get the equation number and copy out the value.
3485  int eqn_number = node_pt->eqn_number(j);
3486  if (eqn_number >= 0)
3487  {
3488  node_pt->set_value(t, j, dofs[eqn_number]);
3489  }
3490  }
3491  }
3492  }

References distributed(), oomph::Mesh::element_pt(), oomph::Data::eqn_number(), Global_data_pt, i, oomph::GeneralisedElement::internal_data_pt(), j, k, mesh_pt(), nglobal_data(), oomph::GeneralisedElement::ninternal_data(), oomph::Mesh::node_pt(), oomph::Data::nvalue(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::Data::set_value(), and plotPSD::t.

◆ set_dofs() [3/3]

void Problem::set_dofs ( const unsigned t,
Vector< double * > &  dof_pt 
)

Set history values of dofs from the type of vector stored in problem::Dof_pt.

3498  {
3499 #ifdef PARANOID
3500  if (distributed())
3501  {
3502  throw OomphLibError("Not implemented for distributed problems!",
3505  }
3506 #endif
3507 
3508  // If we have any spine meshes I think there might be more degrees
3509  // of freedom there. I don't use them though so I'll let someone who
3510  // knows what they are doing handle it. --David Shepherd
3511 
3512  // First deal with global data
3513  unsigned Nglobal_data = nglobal_data();
3514  for (unsigned i = 0; i < Nglobal_data; i++)
3515  {
3516  for (unsigned j = 0, nj = Global_data_pt[i]->nvalue(); j < nj; j++)
3517  {
3518  // For each data get the equation number and copy in the value.
3519  int eqn_number = Global_data_pt[i]->eqn_number(j);
3520  if (eqn_number >= 0)
3521  {
3522  Global_data_pt[i]->set_value(t, j, *(dof_pt[eqn_number]));
3523  }
3524  }
3525  }
3526 
3527  // Now the mesh data
3528  // nodes
3529  for (unsigned i = 0, ni = mesh_pt()->nnode(); i < ni; i++)
3530  {
3531  Node* node_pt = mesh_pt()->node_pt(i);
3532  for (unsigned j = 0, nj = node_pt->nvalue(); j < nj; j++)
3533  {
3534  // For each node get the equation number and copy in the value.
3535  int eqn_number = node_pt->eqn_number(j);
3536  if (eqn_number >= 0)
3537  {
3538  node_pt->set_value(t, j, *(dof_pt[eqn_number]));
3539  }
3540  }
3541  }
3542 
3543  // and non-nodal data inside elements
3544  for (unsigned i = 0, ni = mesh_pt()->nelement(); i < ni; i++)
3545  {
3546  GeneralisedElement* ele_pt = mesh_pt()->element_pt(i);
3547  for (unsigned j = 0, nj = ele_pt->ninternal_data(); j < nj; j++)
3548  {
3549  Data* data_pt = ele_pt->internal_data_pt(j);
3550  // For each node get the equation number and copy in the value.
3551  int eqn_number = data_pt->eqn_number(j);
3552  if (eqn_number >= 0)
3553  {
3554  data_pt->set_value(t, j, *(dof_pt[eqn_number]));
3555  }
3556  }
3557  }
3558  }
double *& dof_pt(const unsigned &i)
Pointer to i-th dof in the problem.
Definition: problem.h:1825

References distributed(), dof_pt(), oomph::Mesh::element_pt(), oomph::Data::eqn_number(), Global_data_pt, i, oomph::GeneralisedElement::internal_data_pt(), j, mesh_pt(), nglobal_data(), oomph::GeneralisedElement::ninternal_data(), oomph::Mesh::node_pt(), oomph::Data::nvalue(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::Data::set_value(), and plotPSD::t.

◆ set_explicit_time_stepper_pt()

void Problem::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 Time object so that it contains the appropriate number of levels of storage

Set the explicit time stepper for the problem and also ensure that a time object has been created.

1588  {
1589  // Set the explicit time stepper
1591 
1592  // If time has not been allocated, create time object with the
1593  // required number of time steps
1594  if (Time_pt == 0)
1595  {
1596  Time_pt = new Time(0);
1597  oomph_info << "Created Time with storage for no previous timestep"
1598  << std::endl;
1599  }
1600  else
1601  {
1602  oomph_info << "Time object already exists " << std::endl;
1603  }
1604  }

References Explicit_time_stepper_pt, explicit_time_stepper_pt(), oomph::oomph_info, and Time_pt.

◆ set_initial_condition()

virtual void oomph::Problem::set_initial_condition ( )
inlineprotectedvirtual

Set initial condition (incl previous timesteps). We need to establish this interface because I.C. needs to be reset when problem is adapted during the first timestep.

Reimplemented in CollapsibleChannelProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, RefineableSphericalSpinUpProblem< ELEMENT >, RefineableSphericalSpinUpProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, RefineableActivatorInhibitorProblem< ELEMENT >, RefineableActivatorInhibitorProblem< ELEMENT >, RefineableOneDAdvectionDiffusionReactionProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, RayleighProblem< ELEMENT, TIMESTEPPER >, RayleighProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, TwoLayerInterfaceProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, RayleighTractionProblem< ELEMENT, TIMESTEPPER >, RayleighProblem< ELEMENT, TIMESTEPPER >, OscRingNStProblem< ELEMENT >, OscRingNStProblem< ELEMENT >, OscEllipseProblem< ELEMENT, TIMESTEPPER >, CollapsibleChannelProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, CollapsibleChannelProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, FSIRingProblem, FSICollapsibleChannelProblem< ELEMENT >, RefineableUnsteadyHeatProblem< ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, LinearWaveProblem< ELEMENT, TIMESTEPPER >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >, OscRingNStProblem< ELEMENT >, OscRingNStProblem< ELEMENT >, FSIRingProblem, FSIRingProblem, FSIDrivenCavityProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, FSICollapsibleChannelProblem< ELEMENT >, UnsteadyHeatProblem< ELEMENT >, AxiPoroProblem< ELEMENT, TIMESTEPPER >, UnstructuredTorusProblem< ELEMENT >, UnstructuredTorusProblem< ELEMENT >, InterfaceProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, TorusProblem< ELEMENT >, RotatingCylinderProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, InterfaceProblem< ELEMENT, TIMESTEPPER >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, PerturbedStateProblem< BASE_ELEMENT, PERTURBED_ELEMENT >, BaseStateProblem< BASE_ELEMENT >, and RefineableAdvectionDiffusionPipeProblem< ELEMENT >.

1199  {
1200  std::ostringstream warn_message;
1201  warn_message
1202  << "Warning: We're using the default (empty) set_initial_condition().\n"
1203  << "If the initial conditions isn't re-assigned after a mesh adaption "
1204  "\n"
1205  << "the initial conditions will represent the interpolation of the \n"
1206  << "initial conditions that were assigned on the original coarse "
1207  "mesh.\n";
1208  OomphLibWarning(warn_message.str(),
1209  "Problem::set_initial_condition()",
1211 
1212  // Indicate that this function has been called. This flag is set so
1213  // that the unsteady_newton_solve routine can be instructed whether
1214  // or not to shift the history values. If set_initial_condition() has
1215  // been overloaded than this (default) function won't be called, and
1216  // so this flag will remain false (its default value). If
1217  // set_initial_condition() has not been overloaded then this function
1218  // will be called and the flag set to true.
1220  }

References Default_set_initial_condition_called, and OOMPH_EXCEPTION_LOCATION.

Referenced by doubly_adaptive_unsteady_newton_solve_helper(), and unsteady_newton_solve().

◆ set_pinned_values_to_zero()

void Problem::set_pinned_values_to_zero ( )

Set all pinned values to zero. Used to set boundary conditions to be homogeneous in the copy of the problem used in adaptive bifurcation tracking (ALH: TEMPORARY HACK, WILL BE FIXED)

4305  {
4306  // NOTE THIS DOES NOT ZERO ANY SPINE DATA, but otherwise everything else
4307  // should be zeroed
4308 
4309  // Zero any pinned global Data
4310  const unsigned n_global_data = nglobal_data();
4311  for (unsigned i = 0; i < n_global_data; i++)
4312  {
4313  Data* const local_data_pt = Global_data_pt[i];
4314  const unsigned n_value = local_data_pt->nvalue();
4315  for (unsigned j = 0; j < n_value; j++)
4316  {
4317  // If the data value is pinned set the value to zero
4318  if (local_data_pt->is_pinned(j))
4319  {
4320  local_data_pt->set_value(j, 0.0);
4321  }
4322  }
4323  }
4324 
4325  // Loop over the submeshes:
4326  const unsigned n_sub_mesh = Sub_mesh_pt.size();
4327  if (n_sub_mesh == 0)
4328  {
4329  // Loop over the nodes in the element
4330  const unsigned n_node = Mesh_pt->nnode();
4331  for (unsigned n = 0; n < n_node; n++)
4332  {
4333  Node* const local_node_pt = Mesh_pt->node_pt(n);
4334  const unsigned n_value = local_node_pt->nvalue();
4335  for (unsigned j = 0; j < n_value; j++)
4336  {
4337  // If the data value is pinned set the value to zero
4338  if (local_node_pt->is_pinned(j))
4339  {
4340  local_node_pt->set_value(j, 0.0);
4341  }
4342  }
4343 
4344  // Try to cast to a solid node
4345  SolidNode* const local_solid_node_pt =
4346  dynamic_cast<SolidNode*>(local_node_pt);
4347  // If we are successful
4348  if (local_solid_node_pt)
4349  {
4350  // Find the dimension of the node
4351  const unsigned n_dim = local_solid_node_pt->ndim();
4352  // Find number of positions
4353  const unsigned n_position_type =
4354  local_solid_node_pt->nposition_type();
4355 
4356  for (unsigned k = 0; k < n_position_type; k++)
4357  {
4358  for (unsigned i = 0; i < n_dim; i++)
4359  {
4360  // If the generalised position is pinned,
4361  // set the value to zero
4362  if (local_solid_node_pt->position_is_pinned(k, i))
4363  {
4364  local_solid_node_pt->x_gen(k, i) = 0.0;
4365  }
4366  }
4367  }
4368  }
4369  }
4370 
4371  // Now loop over the element's and zero the internal data
4372  const unsigned n_element = Mesh_pt->nelement();
4373  for (unsigned e = 0; e < n_element; e++)
4374  {
4375  GeneralisedElement* const local_element_pt = Mesh_pt->element_pt(e);
4376  const unsigned n_internal = local_element_pt->ninternal_data();
4377  for (unsigned i = 0; i < n_internal; i++)
4378  {
4379  Data* const local_data_pt = local_element_pt->internal_data_pt(i);
4380  const unsigned n_value = local_data_pt->nvalue();
4381  for (unsigned j = 0; j < n_value; j++)
4382  {
4383  // If the data value is pinned set the value to zero
4384  if (local_data_pt->is_pinned(j))
4385  {
4386  local_data_pt->set_value(j, 0.0);
4387  }
4388  }
4389  }
4390  } // End of loop over elements
4391  }
4392  else
4393  {
4394  // Alternatively loop over all sub meshes
4395  for (unsigned m = 0; m < n_sub_mesh; m++)
4396  {
4397  // Loop over the nodes in the element
4398  const unsigned n_node = Sub_mesh_pt[m]->nnode();
4399  for (unsigned n = 0; n < n_node; n++)
4400  {
4401  Node* const local_node_pt = Sub_mesh_pt[m]->node_pt(n);
4402  const unsigned n_value = local_node_pt->nvalue();
4403  for (unsigned j = 0; j < n_value; j++)
4404  {
4405  // If the data value is pinned set the value to zero
4406  if (local_node_pt->is_pinned(j))
4407  {
4408  local_node_pt->set_value(j, 0.0);
4409  }
4410  }
4411 
4412  // Try to cast to a solid node
4413  SolidNode* const local_solid_node_pt =
4414  dynamic_cast<SolidNode*>(local_node_pt);
4415  // If we are successful
4416  if (local_solid_node_pt)
4417  {
4418  // Find the dimension of the node
4419  const unsigned n_dim = local_solid_node_pt->ndim();
4420  // Find number of positions
4421  const unsigned n_position_type =
4422  local_solid_node_pt->nposition_type();
4423 
4424  for (unsigned k = 0; k < n_position_type; k++)
4425  {
4426  for (unsigned i = 0; i < n_dim; i++)
4427  {
4428  // If the generalised position is pinned,
4429  // set the value to zero
4430  if (local_solid_node_pt->position_is_pinned(k, i))
4431  {
4432  local_solid_node_pt->x_gen(k, i) = 0.0;
4433  }
4434  }
4435  }
4436  }
4437  }
4438 
4439  // Now loop over the element's and zero the internal data
4440  const unsigned n_element = Sub_mesh_pt[m]->nelement();
4441  for (unsigned e = 0; e < n_element; e++)
4442  {
4443  GeneralisedElement* const local_element_pt =
4444  Sub_mesh_pt[m]->element_pt(e);
4445  const unsigned n_internal = local_element_pt->ninternal_data();
4446  for (unsigned i = 0; i < n_internal; i++)
4447  {
4448  Data* const local_data_pt = local_element_pt->internal_data_pt(i);
4449  const unsigned n_value = local_data_pt->nvalue();
4450  for (unsigned j = 0; j < n_value; j++)
4451  {
4452  // If the data value is pinned set the value to zero
4453  if (local_data_pt->is_pinned(j))
4454  {
4455  local_data_pt->set_value(j, 0.0);
4456  }
4457  }
4458  }
4459  } // End of loop over elements
4460  }
4461  }
4462  }
unsigned nvalue() const
Return number of values stored in data object (incl pinned ones).
Definition: nodes.h:483

References e(), oomph::Mesh::element_pt(), Global_data_pt, i, oomph::GeneralisedElement::internal_data_pt(), oomph::Data::is_pinned(), j, k, m, Mesh_pt, n, oomph::Node::ndim(), oomph::Mesh::nelement(), nglobal_data(), oomph::GeneralisedElement::ninternal_data(), oomph::Mesh::nnode(), oomph::Mesh::node_pt(), oomph::Node::nposition_type(), oomph::Data::nvalue(), oomph::SolidNode::position_is_pinned(), oomph::Data::set_value(), Sub_mesh_pt, and oomph::Node::x_gen().

◆ set_timestepper_for_all_data()

unsigned long Problem::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 the problem

Set all problem data to have the same timestepper (timestepper_pt). This is mainly used in continuation and bifurcation detection problems in which case the total number of unknowns may change and the changes to the underlying memory layout means that the Dof_pt must be reallocated. Thus, the function calls assign_eqn_numbers() and returns the number of new equation numbers.

11574  {
11575  // Set the timestepper for the master mesh's nodal and elemental data
11576  // to be the
11577  // continuation time stepper. This will wipe all storage other than
11578  // the 0th (present time) value at all the data objects
11580  preserve_existing_data);
11581 
11582  // Deal with the any additional mesh level timestepper data separately
11583  const unsigned n_sub_mesh = this->nsub_mesh();
11584  // If there is only one mesh
11585  if (n_sub_mesh == 0)
11586  {
11588  preserve_existing_data);
11589  }
11590  // Otherwise loop over the sub meshes
11591  else
11592  {
11593  // Assign global equation numbers first
11594  for (unsigned i = 0; i < n_sub_mesh; i++)
11595  {
11596  this->Sub_mesh_pt[i]->set_mesh_level_time_stepper(
11597  time_stepper_pt, preserve_existing_data);
11598  }
11599  }
11600 
11601  // Also set time stepper for global data
11602  const unsigned n_global = Global_data_pt.size();
11603  for (unsigned i = 0; i < n_global; ++i)
11604  {
11605  Global_data_pt[i]->set_time_stepper(time_stepper_pt,
11606  preserve_existing_data);
11607  }
11608 
11609  // We now need to reassign equations numbers because the Dof pointer
11610  // will be inappropriate because memory has been reallocated
11611 
11612 #ifdef OOMPH_HAS_MPI
11613  if (Problem_has_been_distributed)
11614  {
11615  std::ostringstream warning_stream;
11616  warning_stream << "This has not been comprehensively tested for "
11617  "distributed problems.\n"
11618  << "I'm sure that I need to worry about external halo and "
11619  "external elements."
11620  << std::endl;
11621  OomphLibWarning(
11622  warning_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
11623  }
11624 
11625 #endif
11626 
11627  return (this->assign_eqn_numbers());
11628  }
virtual void set_mesh_level_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Definition: mesh.cc:2402
void set_nodal_and_elemental_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Definition: mesh.h:1032

References assign_eqn_numbers(), Global_data_pt, i, Mesh_pt, nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::Mesh::set_mesh_level_time_stepper(), oomph::Mesh::set_nodal_and_elemental_time_stepper(), Sub_mesh_pt, and time_stepper_pt().

Referenced by arc_length_step_solve().

◆ setup_base_mesh_info_after_pruning()

void oomph::Problem::setup_base_mesh_info_after_pruning ( )
private

Helper function to re-setup the Base_mesh enumeration (used during load balancing) after pruning

◆ setup_element_count_per_dof()

unsigned Problem::setup_element_count_per_dof ( )
protected

Function that populates the Element_counter_per_dof vector with the number of elements that contribute to each dof. For example, with linear elements in 1D each dof contains contributions from two elements apart from those on the boundary. Returns the total number of elements in the problem

Setup the count vector that records how many elements contribute to each degree of freedom. Returns the total number of elements in the problem

231  {
232  // Now set the element counter to have the current Dof distribution
234  // We need to use the halo scheme (assuming it has been setup)
235 #ifdef OOMPH_HAS_MPI
236  Element_count_per_dof.build_halo_scheme(this->Halo_scheme_pt);
237 #endif
238 
239  // Loop over the elements and count the entries
240  // and number of (non-halo) elements
241  const unsigned n_element = this->mesh_pt()->nelement();
242  unsigned n_non_halo_element_local = 0;
243  for (unsigned e = 0; e < n_element; e++)
244  {
245  GeneralisedElement* elem_pt = this->mesh_pt()->element_pt(e);
246 #ifdef OOMPH_HAS_MPI
247  // Ignore halo elements
248  if (!elem_pt->is_halo())
249  {
250 #endif
251  // Increment the number of non halo elements
252  ++n_non_halo_element_local;
253  // Now count the number of times the element contributes to a value
254  // using the current assembly handler
255  unsigned n_var = this->Assembly_handler_pt->ndof(elem_pt);
256  for (unsigned n = 0; n < n_var; n++)
257  {
259  this->Assembly_handler_pt->eqn_number(elem_pt, n));
260  }
261 #ifdef OOMPH_HAS_MPI
262  }
263 #endif
264  }
265 
266  // Storage for the total number of elements
267  unsigned Nelement = 0;
268 
269  // Add together all the counts if we are in parallel
270 #ifdef OOMPH_HAS_MPI
272 
273  // If distributed, find the total number of elements in the problem
274  if (this->Problem_has_been_distributed)
275  {
276  // Need to gather the total number of non halo elements
277  MPI_Allreduce(&n_non_halo_element_local,
278  &Nelement,
279  1,
280  MPI_UNSIGNED,
281  MPI_SUM,
282  this->communicator_pt()->mpi_comm());
283  }
284  // Otherwise the total number is the same on each processor
285  else
286 #endif
287  {
288  Nelement = n_non_halo_element_local;
289  }
290 
291  return Nelement;
292  }
void build_halo_scheme(DoubleVectorHaloScheme *const &halo_scheme_pt)
Construct the halo scheme and storage for the halo data.
Definition: double_vector_with_halo.cc:379
void sum_all_halo_and_haloed_values()
Definition: double_vector_with_halo.cc:323
double & global_value(const unsigned &i)
Direct access to global entry.
Definition: double_vector_with_halo.h:221
void build(const DoubleVector &old_vector)
Just copys the argument DoubleVector.
Definition: double_vector.cc:35
DoubleVectorWithHaloEntries Element_count_per_dof
Definition: problem.h:560

References Assembly_handler_pt, oomph::DoubleVector::build(), oomph::DoubleVectorWithHaloEntries::build_halo_scheme(), communicator_pt(), Dof_distribution_pt, e(), Element_count_per_dof, oomph::Mesh::element_pt(), oomph::AssemblyHandler::eqn_number(), oomph::DoubleVectorWithHaloEntries::global_value(), mesh_pt(), n, oomph::AssemblyHandler::ndof(), oomph::Mesh::nelement(), and oomph::DoubleVectorWithHaloEntries::sum_all_halo_and_haloed_values().

◆ shift_time_values()

void Problem::shift_time_values ( )
virtual

Shift all values along to prepare for next timestep.

Shift all time-dependent data along for next timestep.

11635  {
11636  // Move the values of dt in the Time object
11637  Time_pt->shift_dt();
11638 
11639  // Only shift time values in the "master" mesh, otherwise things will
11640  // get shifted twice in complex problems
11642 
11643  // Shift global data with their own timesteppers
11644  unsigned Nglobal = Global_data_pt.size();
11645  for (unsigned iglobal = 0; iglobal < Nglobal; iglobal++)
11646  {
11647  Global_data_pt[iglobal]->time_stepper_pt()->shift_time_values(
11648  Global_data_pt[iglobal]);
11649  }
11650  }
void shift_time_values()
Definition: mesh.cc:2326
void shift_dt()
Definition: timesteppers.h:174

References Global_data_pt, Mesh_pt, oomph::Time::shift_dt(), oomph::Mesh::shift_time_values(), and Time_pt.

Referenced by adaptive_unsteady_newton_solve(), explicit_timestep(), unsteady_newton_solve(), and oomph::SegregatableFSIProblem::unsteady_segregated_solve().

◆ sign_of_jacobian()

int& oomph::Problem::sign_of_jacobian ( )
inline

Access function for the sign of the global jacobian matrix. This will be set by the linear solver, if possible (direct solver). If not alternative methods must be used to detect bifurcations (solving the associated eigenproblem).

2425  {
2426  return Sign_of_jacobian;
2427  }

References Sign_of_jacobian.

Referenced by oomph::AugmentedBlockFoldLinearSolver::solve(), oomph::BlockPitchForkLinearSolver::solve(), oomph::AugmentedBlockPitchForkLinearSolver::solve(), oomph::BlockHopfLinearSolver::solve(), oomph::HSL_MA42::solve(), oomph::DenseLU::solve(), oomph::FD_LU::solve(), oomph::SuperLUSolver::solve(), oomph::HSL_MA42::solve_for_one_dof(), oomph::BlockHopfLinearSolver::solve_for_two_rhs(), and oomph::SuperLUSolver::solve_transpose().

◆ solve_eigenproblem() [1/2]

void oomph::Problem::solve_eigenproblem ( const unsigned n_eval,
Vector< std::complex< double >> &  eigenvalue,
const bool steady = true 
)
inline

Solve an eigenproblem as assembled by EigenElements, but only return the eigenvalues, not the eigenvectors. The boolean flag (default true) is used to specify whether the weighted mass-matrix terms from the timestepping scheme should be included in the jacobian.

1940  {
1941  // Create temporary storage for the eigenvectors (potentially wasteful)
1942  Vector<DoubleVector> eigenvector;
1943  solve_eigenproblem(n_eval, eigenvalue, eigenvector, steady);
1944  }
void solve_eigenproblem(const unsigned &n_eval, Vector< std::complex< double >> &eigenvalue, Vector< DoubleVector > &eigenvector, const bool &steady=true)
Solve the eigenproblem.
Definition: problem.cc:8313

References solve_eigenproblem().

◆ solve_eigenproblem() [2/2]

void Problem::solve_eigenproblem ( const unsigned n_eval,
Vector< std::complex< double >> &  eigenvalue,
Vector< DoubleVector > &  eigenvector,
const bool steady = true 
)

Solve the eigenproblem.

Get derivative of an element in the problem wrt a global parameter, used in continuation problems Solve an eigenproblem as assembled by EigenElements calculate n_eval eigenvalues and return the corresponding eigenvectors. The boolean flag (default true) specifies whether the steady jacobian should be assembled. If the flag is false then the weighted mass-matrix terms from the timestepper will be included in the jacobian — this is almost certainly never wanted.

Get derivative of an element in the problem wrt a global parameter, to be used in continuation problems

8317  {
8318  // If the boolean flag is steady, then make all the timesteppers steady
8319  // before solving the eigenproblem. This will "switch off" the
8320  // time-derivative terms in the jacobian matrix
8321  if (steady)
8322  {
8323  // Find out how many timesteppers there are
8324  const unsigned n_time_steppers = ntime_stepper();
8325 
8326  // Vector of bools to store the is_steady status of the various
8327  // timesteppers when we came in here
8328  std::vector<bool> was_steady(n_time_steppers);
8329 
8330  // Loop over them all and make them (temporarily) static
8331  for (unsigned i = 0; i < n_time_steppers; i++)
8332  {
8333  was_steady[i] = time_stepper_pt(i)->is_steady();
8335  }
8336 
8337  // Call the Eigenproblem for the eigensolver
8339  this, n_eval, eigenvalue, eigenvector);
8340 
8341  // Reset the is_steady status of all timesteppers that
8342  // weren't already steady when we came in here and reset their
8343  // weights
8344  for (unsigned i = 0; i < n_time_steppers; i++)
8345  {
8346  if (!was_steady[i])
8347  {
8349  }
8350  }
8351  }
8352  // Otherwise if we don't want to make the problem steady, just
8353  // assemble and solve the eigensystem
8354  else
8355  {
8356  // Call the Eigenproblem for the eigensolver
8358  this, n_eval, eigenvalue, eigenvector);
8359  }
8360  }
virtual void solve_eigenproblem(Problem *const &problem_pt, const int &n_eval, Vector< std::complex< double >> &eigenvalue, Vector< DoubleVector > &eigenvector)=0

References Eigen_solver_pt, i, oomph::TimeStepper::is_steady(), oomph::TimeStepper::make_steady(), ntime_stepper(), oomph::EigenSolver::solve_eigenproblem(), time_stepper_pt(), and oomph::TimeStepper::undo_make_steady().

Referenced by solve_eigenproblem().

◆ sparse_assemble_row_or_column_compressed()

void Problem::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 * > &  residuals,
bool  compressed_row_flag 
)
protectedvirtual

Protected helper function that is used to assemble the Jacobian matrix in the case when the storage is row or column compressed. The boolean Flag indicates if we want compressed row format (true) or compressed column.

This is a (private) helper function that is used to assemble system matrices in compressed row or column format and compute residual vectors. The default action is to assemble the jacobian matrix and residuals for the Newton method. The action can be overloaded at an elemental level by changing the default behaviour of the function Element::get_all_vectors_and_matrices(). column_or_row_index: Column [or row] index of given entry row_or_column_start: Index of first entry for given row [or column] value : Vector of nonzero entries residuals : Residual vector compressed_row_flag: Bool flag to indicate if storage format is compressed row [if false interpretation of arguments is as stated in square brackets]. We provide four different assembly methods, each with different memory requirements/execution speeds. The method is set by the public flag Problem::Sparse_assembly_method.

4491  {
4492  // Choose the actual method
4493  switch (Sparse_assembly_method)
4494  {
4496 
4498  column_or_row_index,
4499  row_or_column_start,
4500  value,
4501  nnz,
4502  residuals,
4503  compressed_row_flag);
4504 
4505  break;
4506 
4508 
4510  column_or_row_index,
4511  row_or_column_start,
4512  value,
4513  nnz,
4514  residuals,
4515  compressed_row_flag);
4516 
4517  break;
4518 
4520 
4522  row_or_column_start,
4523  value,
4524  nnz,
4525  residuals,
4526  compressed_row_flag);
4527 
4528  break;
4529 
4531 
4533  column_or_row_index,
4534  row_or_column_start,
4535  value,
4536  nnz,
4537  residuals,
4538  compressed_row_flag);
4539 
4540  break;
4541 
4543 
4545  column_or_row_index,
4546  row_or_column_start,
4547  value,
4548  nnz,
4549  residuals,
4550  compressed_row_flag);
4551 
4552  break;
4553 
4554  default:
4555 
4556  std::ostringstream error_stream;
4557  error_stream
4558  << "Error: Incorrect value for Problem::Sparse_assembly_method"
4559  << Sparse_assembly_method << std::endl
4560  << "It should be one of the enumeration Problem::Assembly_method"
4561  << std::endl;
4562  throw OomphLibError(
4563  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4564  }
4565  }
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)
Definition: problem.cc:6061
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)
Definition: problem.cc:5698
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)
Definition: problem.cc:4584
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)
Definition: problem.cc:5345
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)
Definition: problem.cc:4930

References OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, Perform_assembly_using_lists, Perform_assembly_using_maps, Perform_assembly_using_two_arrays, Perform_assembly_using_two_vectors, Perform_assembly_using_vectors_of_pairs, sparse_assemble_row_or_column_compressed_with_lists(), sparse_assemble_row_or_column_compressed_with_maps(), sparse_assemble_row_or_column_compressed_with_two_arrays(), sparse_assemble_row_or_column_compressed_with_two_vectors(), sparse_assemble_row_or_column_compressed_with_vectors_of_pairs(), Sparse_assembly_method, and Eigen::value.

Referenced by get_eigenproblem_matrices(), and get_jacobian().

◆ sparse_assemble_row_or_column_compressed_with_lists()

void Problem::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 * > &  residuals,
bool  compressed_row_flag 
)
privatevirtual

Private helper function that is used to assemble the Jacobian matrix in the case when the storage is row or column compressed. The boolean Flag indicates if we want compressed row format (true) or compressed column. This version uses lists

This is a (private) helper function that is used to assemble system matrices in compressed row or column format and compute residual vectors using lists The default action is to assemble the jacobian matrix and residuals for the Newton method. The action can be overloaded at an elemental level by chaging the default behaviour of the function Element::get_all_vectors_and_matrices(). column_or_row_index: Column [or row] index of given entry row_or_column_start: Index of first entry for given row [or column] value : Vector of nonzero entries residuals : Residual vector compressed_row_flag: Bool flag to indicate if storage format is compressed row [if false interpretation of arguments is as stated in square brackets].

4937  {
4938  // Total number of elements
4939  const unsigned long n_elements = mesh_pt()->nelement();
4940 
4941  // Default range of elements for distributed problems
4942  unsigned long el_lo = 0;
4943  unsigned long el_hi = n_elements - 1;
4944 
4945 #ifdef OOMPH_HAS_MPI
4946  // Otherwise just loop over a fraction of the elements
4947  // (This will either have been initialised in
4948  // Problem::set_default_first_and_last_element_for_assembly() or
4949  // will have been re-assigned during a previous assembly loop
4950  // Note that following the re-assignment only the entries
4951  // for the current processor are relevant.
4952  if (!Problem_has_been_distributed)
4953  {
4954  el_lo = First_el_for_assembly[Communicator_pt->my_rank()];
4955  el_hi = Last_el_plus_one_for_assembly[Communicator_pt->my_rank()] - 1;
4956  }
4957 #endif
4958 
4959  // number of dofs
4960  unsigned ndof = this->ndof();
4961 
4962  // Find the number of vectors to be assembled
4963  const unsigned n_vector = residuals.size();
4964 
4965  // Find the number of matrices to be assembled
4966  const unsigned n_matrix = column_or_row_index.size();
4967 
4968  // Locally cache pointer to assembly handler
4969  AssemblyHandler* const assembly_handler_pt = Assembly_handler_pt;
4970 
4971 #ifdef OOMPH_HAS_MPI
4972  bool doing_residuals = false;
4973  if (dynamic_cast<ParallelResidualsHandler*>(Assembly_handler_pt) != 0)
4974  {
4975  doing_residuals = true;
4976  }
4977 #endif
4978 
4979 // Error check dimensions
4980 #ifdef PARANOID
4981  if (row_or_column_start.size() != n_matrix)
4982  {
4983  std::ostringstream error_stream;
4984  error_stream << "Error: " << std::endl
4985  << "row_or_column_start.size() "
4986  << row_or_column_start.size() << " does not equal "
4987  << "column_or_row_index.size() "
4988  << column_or_row_index.size() << std::endl;
4989  throw OomphLibError(
4990  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4991  }
4992 
4993  if (value.size() != n_matrix)
4994  {
4995  std::ostringstream error_stream;
4996  error_stream
4997  << "Error in Problem::sparse_assemble_row_or_column_compressed "
4998  << std::endl
4999  << "value.size() " << value.size() << " does not equal "
5000  << "column_or_row_index.size() " << column_or_row_index.size()
5001  << std::endl
5002  << std::endl
5003  << std::endl;
5004  throw OomphLibError(
5005  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5006  }
5007 #endif
5008 
5009  // The idea behind this sparse assembly routine is to use a vector of
5010  // lists for the entries in each row or column of the complete matrix.
5011  // The lists contain pairs of entries (global row/column number, value).
5012  // All non-zero contributions from each element are added to the lists.
5013  // We then sort each list by global row/column number and then combine
5014  // the entries corresponding to each row/column before adding to the
5015  // vectors column_or_row_index and value.
5016 
5017  // Note the trade off for "fast assembly" is that we will require
5018  // more memory during the assembly phase. Then again, if we can
5019  // only just assemble the sparse matrix, we're in real trouble.
5020 
5021  // Set up a vector of lists of paired entries of
5022  //(row/column index, jacobian matrix entry).
5023  // The entries of the vector correspond to all the rows or columns.
5024  // The use of the list storage scheme, should give fast insertion
5025  // and fast sorts later.
5026  Vector<Vector<std::list<std::pair<unsigned, double>>>> matrix_data_list(
5027  n_matrix);
5028  // Loop over the number of matrices and resize
5029  for (unsigned m = 0; m < n_matrix; m++)
5030  {
5031  matrix_data_list[m].resize(ndof);
5032  }
5033 
5034  // Resize the residuals vectors
5035  for (unsigned v = 0; v < n_vector; v++)
5036  {
5037  residuals[v] = new double[ndof];
5038  for (unsigned i = 0; i < ndof; i++)
5039  {
5040  residuals[v][i] = 0;
5041  }
5042  }
5043 
5044 #ifdef OOMPH_HAS_MPI
5045 
5046 
5047  // Storage for assembly time for elements
5048  double t_assemble_start = 0.0;
5049 
5050  // Storage for assembly times
5051  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
5052  {
5053  Elemental_assembly_time.resize(n_elements);
5054  }
5055 
5056 #endif
5057 
5058  //------------Assemble and populate the lists-----------------------
5059  {
5060  // Allocate local storage for the element's contribution to the
5061  // residuals vectors and system matrices of the size of the maximum
5062  // number of dofs in any element.
5063  // This means that the stored is only allocated (and deleted) once
5064  Vector<Vector<double>> el_residuals(n_vector);
5065  Vector<DenseMatrix<double>> el_jacobian(n_matrix);
5066 
5067 
5068  // Pointer to a single list to be used during the assembly
5069  std::list<std::pair<unsigned, double>>* list_pt;
5070 
5071  // Loop over the all elements
5072  for (unsigned long e = el_lo; e <= el_hi; e++)
5073  {
5074 #ifdef OOMPH_HAS_MPI
5075  // Time it?
5076  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
5077  {
5078  t_assemble_start = TimingHelpers::timer();
5079  }
5080 #endif
5081 
5082  // Get the pointer to the element
5083  GeneralisedElement* elem_pt = mesh_pt()->element_pt(e);
5084 
5085 #ifdef OOMPH_HAS_MPI
5086  // Ignore halo elements
5087  if (!elem_pt->is_halo())
5088  {
5089 #endif
5090 
5091  // Find number of degrees of freedom in the element
5092  const unsigned nvar = assembly_handler_pt->ndof(elem_pt);
5093 
5094  // Resize the storage for the elemental jacobian and residuals
5095  for (unsigned v = 0; v < n_vector; v++)
5096  {
5097  el_residuals[v].resize(nvar);
5098  }
5099  for (unsigned m = 0; m < n_matrix; m++)
5100  {
5101  el_jacobian[m].resize(nvar);
5102  }
5103 
5104  // Now get the residuals and jacobian for the element
5106  elem_pt, el_residuals, el_jacobian);
5107 
5108  //---------------- Insert the values into the lists -----------
5109 
5110  // Loop over the first index of local variables
5111  for (unsigned i = 0; i < nvar; i++)
5112  {
5113  // Get the local equation number
5114  unsigned eqn_number = assembly_handler_pt->eqn_number(elem_pt, i);
5115 
5116  // Add the contribution to the residuals
5117  for (unsigned v = 0; v < n_vector; v++)
5118  {
5119  // Fill in the residuals vector
5120  residuals[v][eqn_number] += el_residuals[v][i];
5121  }
5122 
5123  // Now loop over the other index
5124  for (unsigned j = 0; j < nvar; j++)
5125  {
5126  // Get the number of the unknown
5127  unsigned unknown = assembly_handler_pt->eqn_number(elem_pt, j);
5128 
5129  // Loop over the matrices
5130  for (unsigned m = 0; m < n_matrix; m++)
5131  {
5132  // Get the value of the matrix at this point
5133  double value = el_jacobian[m](i, j);
5134  // Only add to theif it's non-zero
5136  {
5137  // If it's compressed row storage, then our vector is indexed
5138  // by row (the equation number)
5139  if (compressed_row_flag)
5140  {
5141  // Find the list that corresponds to the desired row
5142  list_pt = &matrix_data_list[m][eqn_number];
5143  // Insert the data into the list, the first entry
5144  // in the pair is the unknown (column index),
5145  // the second is the value itself.
5146  list_pt->insert(list_pt->end(),
5147  std::make_pair(unknown, value));
5148  }
5149  // Otherwise it's compressed column storage, and our
5150  // vector is indexed by column (the unknown)
5151  else
5152  {
5153  // Find the list that corresponds to the desired column
5154  list_pt = &matrix_data_list[m][unknown];
5155  // Insert the data into the list, the first entry
5156  // in the pair is the equation number (row index),
5157  // the second is the value itself.
5158  list_pt->insert(list_pt->end(),
5159  std::make_pair(eqn_number, value));
5160  }
5161  }
5162  }
5163  }
5164  }
5165 
5166 #ifdef OOMPH_HAS_MPI
5167  } // endif halo element
5168 #endif
5169 
5170 
5171 #ifdef OOMPH_HAS_MPI
5172  // Time it?
5173  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
5174  {
5175  Elemental_assembly_time[e] =
5176  TimingHelpers::timer() - t_assemble_start;
5177  }
5178 #endif
5179 
5180  } // End of loop over the elements
5181 
5182  } // list_pt goes out of scope
5183 
5184 
5185 #ifdef OOMPH_HAS_MPI
5186 
5187  // Postprocess timing information and re-allocate distribution of
5188  // elements during subsequent assemblies.
5189  if ((!doing_residuals) && (!Problem_has_been_distributed) &&
5190  Must_recompute_load_balance_for_assembly)
5191  {
5192  recompute_load_balanced_assembly();
5193  }
5194 
5195  // We have determined load balancing for current setup.
5196  // This can remain the same until assign_eqn_numbers() is called
5197  // again -- the flag is re-set to true there.
5198  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
5199  {
5200  Must_recompute_load_balance_for_assembly = false;
5201  }
5202 
5203 #endif
5204 
5205 
5206  //----Finally we need to convert the beautiful list storage scheme---
5207  //----------to the containers required by SuperLU--------------------
5208 
5209  // Loop over the number of matrices
5210  for (unsigned m = 0; m < n_matrix; m++)
5211  {
5212  // Set the number of rows or columns
5213  row_or_column_start[m] = new int[ndof + 1];
5214  // Counter for the total number of entries in the storage scheme
5215  unsigned long entry_count = 0;
5216  // The first entry is 0
5217  row_or_column_start[m][0] = entry_count;
5218 
5219  // first we compute the number of non-zeros
5220  nnz[m] = 0;
5221  for (unsigned long i_global = 0; i_global < ndof; i_global++)
5222  {
5223  nnz[m] += matrix_data_list[m][i_global].size();
5224  }
5225 
5226  // and then resize the storage
5227  column_or_row_index[m] = new int[nnz[m]];
5228  value[m] = new double[nnz[m]];
5229 
5230  // Now we merely loop over the number of rows or columns
5231  for (unsigned long i_global = 0; i_global < ndof; i_global++)
5232  {
5233  // Start index for the present row is the number of entries so far
5234  row_or_column_start[m][i_global] = entry_count;
5235  // If there are no entries in the list then skip the loop
5236  if (matrix_data_list[m][i_global].empty())
5237  {
5238  continue;
5239  }
5240 
5241  // Sort the list corresponding to this row or column by the
5242  // column or row index (first entry in the pair).
5243  // This might be inefficient, but we only have to do the sort ONCE
5244  // for each list. This is faster than using a map storage scheme, where
5245  // we are sorting for every insertion (although the map structure
5246  // is cleaner and more memory efficient)
5247  matrix_data_list[m][i_global].sort();
5248 
5249  // Set up an iterator for start of the list
5250  std::list<std::pair<unsigned, double>>::iterator it =
5251  matrix_data_list[m][i_global].begin();
5252 
5253  // Get the first row or column index in the list...
5254  unsigned current_index = it->first;
5255  //...and the corresponding value
5256  double current_value = it->second;
5257 
5258  // Loop over all the entries in the sorted list
5259  // Increase the iterator so that we start at the second entry
5260  for (++it; it != matrix_data_list[m][i_global].end(); ++it)
5261  {
5262  // If the index has not changed, then we must add the contribution
5263  // of the present entry to the value.
5264  // Additionally check that the entry is non-zero
5265  if ((it->first == current_index) &&
5267  {
5268  current_value += it->second;
5269  }
5270  // Otherwise, we have added all the contributions to the index
5271  // to current_value, so add it to the SuperLU data structure
5272  else
5273  {
5274  // Add the row or column index to the vector
5275  column_or_row_index[m][entry_count] = current_index;
5276  // Add the actual value to the vector
5277  value[m][entry_count] = current_value;
5278  // Increase the counter for the number of entries in each vector
5279  entry_count++;
5280 
5281  // Set the index and value to be those of the current entry in the
5282  // list
5283  current_index = it->first;
5284  current_value = it->second;
5285  }
5286  } // End of loop over all list entries for this global row or column
5287 
5288  // There are TWO special cases to consider.
5289  // If there is only one equation number in the list, then it
5290  // will NOT have been added. We test this case by comparing the
5291  // number of entries with those stored in row_or_column_start[i_global]
5292  // Otherwise
5293  // If the final entry in the list has the same index as the penultimate
5294  // entry, then it will NOT have been added to the SuperLU storage scheme
5295  // Check this by comparing the current_index with the final index
5296  // stored in the SuperLU scheme. If they are not the same, then
5297  // add the current_index and value.
5298 
5299  // If single equation number in list
5300  if ((static_cast<int>(entry_count) == row_or_column_start[m][i_global])
5301  // If we have a single equation number, this will not be evaluated.
5302  // If we don't then we do the test to check that the final
5303  // entry is added
5304  || (static_cast<int>(current_index) !=
5305  column_or_row_index[m][entry_count - 1]))
5306  {
5307  // Add the row or column index to the vector
5308  column_or_row_index[m][entry_count] = current_index;
5309  // Add the actual value to the vector
5310  value[m][entry_count] = current_value;
5311  // Increase the counter for the number of entries in each vector
5312  entry_count++;
5313  }
5314 
5315  } // End of loop over the rows or columns of the entire matrix
5316 
5317  // Final entry in the row/column start vector
5318  row_or_column_start[m][ndof] = entry_count;
5319  } // End of loop over matrices
5320 
5322  {
5323  oomph_info << "Pausing at end of sparse assembly." << std::endl;
5324  pause("Check memory usage now.");
5325  }
5326  }
Array< int, Dynamic, 1 > v
Definition: Array_initializer_list_vector_cxx11.cpp:1
virtual void get_all_vectors_and_matrices(GeneralisedElement *const &elem_pt, Vector< Vector< double >> &vec, Vector< DenseMatrix< double >> &matrix)
Definition: assembly_handler.cc:113
void pause(std::string message)
Pause and display message.
Definition: oomph_utilities.cc:1265

References Assembly_handler_pt, assembly_handler_pt(), Communicator_pt, e(), oomph::Mesh::element_pt(), oomph::AssemblyHandler::eqn_number(), boost::multiprecision::fabs(), oomph::AssemblyHandler::get_all_vectors_and_matrices(), i, j, m, mesh_pt(), oomph::OomphCommunicator::my_rank(), ndof(), oomph::AssemblyHandler::ndof(), oomph::Mesh::nelement(), Numerical_zero_for_sparse_assembly, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, oomph::pause(), Pause_at_end_of_sparse_assembly, oomph::TimingHelpers::timer(), v, and Eigen::value.

Referenced by sparse_assemble_row_or_column_compressed().

◆ sparse_assemble_row_or_column_compressed_with_maps()

void Problem::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 * > &  residuals,
bool  compressed_row_flag 
)
privatevirtual

Private helper function that is used to assemble the Jacobian matrix in the case when the storage is row or column compressed. The boolean Flag indicates if we want compressed row format (true) or compressed column. This version uses maps

This is a (private) helper function that is used to assemble system matrices in compressed row or column format and compute residual vectors, using maps The default action is to assemble the jacobian matrix and residuals for the Newton method. The action can be overloaded at an elemental level by chaging the default behaviour of the function Element::get_all_vectors_and_matrices(). column_or_row_index: Column [or row] index of given entry row_or_column_start: Index of first entry for given row [or column] value : Vector of nonzero entries residuals : Residual vector compressed_row_flag: Bool flag to indicate if storage format is compressed row [if false interpretation of arguments is as stated in square brackets].

4591  {
4592  // Total number of elements
4593  const unsigned long n_elements = mesh_pt()->nelement();
4594 
4595  // Default range of elements for distributed problems
4596  unsigned long el_lo = 0;
4597  unsigned long el_hi = n_elements - 1;
4598 
4599 #ifdef OOMPH_HAS_MPI
4600  // Otherwise just loop over a fraction of the elements
4601  // (This will either have been initialised in
4602  // Problem::set_default_first_and_last_element_for_assembly() or
4603  // will have been re-assigned during a previous assembly loop
4604  // Note that following the re-assignment only the entries
4605  // for the current processor are relevant.
4606  if (!Problem_has_been_distributed)
4607  {
4608  el_lo = First_el_for_assembly[Communicator_pt->my_rank()];
4609  el_hi = Last_el_plus_one_for_assembly[Communicator_pt->my_rank()] - 1;
4610  }
4611 #endif
4612 
4613  // number of dofs
4614  unsigned ndof = this->ndof();
4615 
4616  // Find the number of vectors to be assembled
4617  const unsigned n_vector = residuals.size();
4618 
4619  // Find the number of matrices to be assembled
4620  const unsigned n_matrix = column_or_row_index.size();
4621 
4622  // Locally cache pointer to assembly handler
4623  AssemblyHandler* const assembly_handler_pt = Assembly_handler_pt;
4624 
4625 #ifdef OOMPH_HAS_MPI
4626  bool doing_residuals = false;
4627  if (dynamic_cast<ParallelResidualsHandler*>(Assembly_handler_pt) != 0)
4628  {
4629  doing_residuals = true;
4630  }
4631 #endif
4632 
4633 // Error check dimensions
4634 #ifdef PARANOID
4635  if (row_or_column_start.size() != n_matrix)
4636  {
4637  std::ostringstream error_stream;
4638  error_stream << "Error: " << std::endl
4639  << "row_or_column_start.size() "
4640  << row_or_column_start.size() << " does not equal "
4641  << "column_or_row_index.size() "
4642  << column_or_row_index.size() << std::endl;
4643  throw OomphLibError(
4644  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4645  }
4646 
4647  if (value.size() != n_matrix)
4648  {
4649  std::ostringstream error_stream;
4650  error_stream
4651  << "Error in Problem::sparse_assemble_row_or_column_compressed "
4652  << std::endl
4653  << "value.size() " << value.size() << " does not equal "
4654  << "column_or_row_index.size() " << column_or_row_index.size()
4655  << std::endl
4656  << std::endl
4657  << std::endl;
4658  throw OomphLibError(
4659  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4660  }
4661 #endif
4662 
4663 
4664  // The idea behind this sparse assembly routine is to use a vector of
4665  // maps for the entries in each row or column of the complete matrix.
4666  // The key for each map is the global row or column number and
4667  // the default comparison operator for integers means that each map
4668  // is ordered by the global row or column number. Thus, we need not
4669  // sort the maps, that happens at each insertion of a new entry. The
4670  // price we pay is that for large maps, inseration is not a
4671  // cheap operation. Hash maps can be used to increase the speed, but then
4672  // the ordering is lost and we would have to sort anyway. The solution if
4673  // speed is required is to use lists, see below.
4674 
4675 
4676  // Set up a vector of vectors of maps of entries of each matrix,
4677  // indexed by either the column or row. The entries of the vector for
4678  // each matrix correspond to all the rows or columns of that matrix.
4679  // The use of the map storage
4680  // scheme, with its implicit ordering on the first index, gives
4681  // a sparse ordered list of the entries in the given row or column.
4682  Vector<Vector<std::map<unsigned, double>>> matrix_data_map(n_matrix);
4683  // Loop over the number of matrices being assembled and resize
4684  // each vector of maps to the number of rows or columns of the matrix
4685  for (unsigned m = 0; m < n_matrix; m++)
4686  {
4687  matrix_data_map[m].resize(ndof);
4688  }
4689 
4690  // Resize the residuals vectors
4691  for (unsigned v = 0; v < n_vector; v++)
4692  {
4693  residuals[v] = new double[ndof];
4694  for (unsigned i = 0; i < ndof; i++)
4695  {
4696  residuals[v][i] = 0;
4697  }
4698  }
4699 
4700 
4701 #ifdef OOMPH_HAS_MPI
4702 
4703 
4704  // Storage for assembly time for elements
4705  double t_assemble_start = 0.0;
4706 
4707  // Storage for assembly times
4708  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
4709  {
4710  Elemental_assembly_time.resize(n_elements);
4711  }
4712 
4713 #endif
4714 
4715  //----------------Assemble and populate the maps-------------------------
4716  {
4717  // Allocate local storage for the element's contribution to the
4718  // residuals vectors and system matrices of the size of the maximum
4719  // number of dofs in any element.
4720  // This means that the storage is only allocated (and deleted) once
4721  Vector<Vector<double>> el_residuals(n_vector);
4722  Vector<DenseMatrix<double>> el_jacobian(n_matrix);
4723 
4724  // Loop over the elements for this processor
4725  for (unsigned long e = el_lo; e <= el_hi; e++)
4726  {
4727 #ifdef OOMPH_HAS_MPI
4728  // Time it?
4729  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
4730  {
4731  t_assemble_start = TimingHelpers::timer();
4732  }
4733 #endif
4734 
4735  // Get the pointer to the element
4736  GeneralisedElement* elem_pt = mesh_pt()->element_pt(e);
4737 
4738 #ifdef OOMPH_HAS_MPI
4739  // Ignore halo elements
4740  if (!elem_pt->is_halo())
4741  {
4742 #endif
4743 
4744  // Find number of degrees of freedom in the element
4745  const unsigned nvar = assembly_handler_pt->ndof(elem_pt);
4746 
4747  // Resize the storage for elemental jacobian and residuals
4748  for (unsigned v = 0; v < n_vector; v++)
4749  {
4750  el_residuals[v].resize(nvar);
4751  }
4752  for (unsigned m = 0; m < n_matrix; m++)
4753  {
4754  el_jacobian[m].resize(nvar);
4755  }
4756 
4757  // Now get the residuals and jacobian for the element
4759  elem_pt, el_residuals, el_jacobian);
4760 
4761  //---------------Insert the values into the maps--------------
4762 
4763  // Loop over the first index of local variables
4764  for (unsigned i = 0; i < nvar; i++)
4765  {
4766  // Get the local equation number
4767  unsigned eqn_number = assembly_handler_pt->eqn_number(elem_pt, i);
4768 
4769  // Add the contribution to the residuals
4770  for (unsigned v = 0; v < n_vector; v++)
4771  {
4772  // Fill in each residuals vector
4773  residuals[v][eqn_number] += el_residuals[v][i];
4774  }
4775 
4776  // Now loop over the other index
4777  for (unsigned j = 0; j < nvar; j++)
4778  {
4779  // Get the number of the unknown
4780  unsigned unknown = assembly_handler_pt->eqn_number(elem_pt, j);
4781 
4782  // Loop over the matrices
4783  for (unsigned m = 0; m < n_matrix; m++)
4784  {
4785  // Get the value of the matrix at this point
4786  double value = el_jacobian[m](i, j);
4787  // Only bother to add to the map if it's non-zero
4789  {
4790  // If it's compressed row storage, then our vector of maps
4791  // is indexed by row (equation number)
4792  if (compressed_row_flag)
4793  {
4794  // Add the data into the map using the unknown as the map
4795  // key
4796  matrix_data_map[m][eqn_number][unknown] += value;
4797  }
4798  // Otherwise it's compressed column storage and our vector is
4799  // indexed by column (the unknown)
4800  else
4801  {
4802  // Add the data into the map using the eqn_numbe as the map
4803  // key
4804  matrix_data_map[m][unknown][eqn_number] += value;
4805  }
4806  }
4807  } // End of loop over matrices
4808  }
4809  }
4810 
4811 #ifdef OOMPH_HAS_MPI
4812  } // endif halo element
4813 #endif
4814 
4815 
4816 #ifdef OOMPH_HAS_MPI
4817  // Time it?
4818  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
4819  {
4820  Elemental_assembly_time[e] =
4821  TimingHelpers::timer() - t_assemble_start;
4822  }
4823 #endif
4824 
4825  } // End of loop over the elements
4826 
4827  } // End of map assembly
4828 
4829 
4830 #ifdef OOMPH_HAS_MPI
4831 
4832  // Postprocess timing information and re-allocate distribution of
4833  // elements during subsequent assemblies.
4834  if ((!doing_residuals) && (!Problem_has_been_distributed) &&
4835  Must_recompute_load_balance_for_assembly)
4836  {
4837  recompute_load_balanced_assembly();
4838  }
4839 
4840  // We have determined load balancing for current setup.
4841  // This can remain the same until assign_eqn_numbers() is called
4842  // again -- the flag is re-set to true there.
4843  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
4844  {
4845  Must_recompute_load_balance_for_assembly = false;
4846  }
4847 
4848 #endif
4849 
4850 
4851  //-----------Finally we need to convert the beautiful map storage scheme
4852  //------------------------to the containers required by SuperLU
4853 
4854  // Loop over the number of matrices
4855  for (unsigned m = 0; m < n_matrix; m++)
4856  {
4857  // Set the number of rows or columns
4858  row_or_column_start[m] = new int[ndof + 1];
4859  // Counter for the total number of entries in the storage scheme
4860  unsigned long entry_count = 0;
4861  row_or_column_start[m][0] = entry_count;
4862 
4863  // first we compute the number of non-zeros
4864  nnz[m] = 0;
4865  for (unsigned long i_global = 0; i_global < ndof; i_global++)
4866  {
4867  nnz[m] += matrix_data_map[m][i_global].size();
4868  }
4869 
4870  // and then resize the storage
4871  column_or_row_index[m] = new int[nnz[m]];
4872  value[m] = new double[nnz[m]];
4873 
4874  // Now we merely loop over the number of rows or columns
4875  for (unsigned long i_global = 0; i_global < ndof; i_global++)
4876  {
4877  // Start index for the present row
4878  row_or_column_start[m][i_global] = entry_count;
4879  // If there are no entries in the map then skip the rest of the loop
4880  if (matrix_data_map[m][i_global].empty())
4881  {
4882  continue;
4883  }
4884 
4885  // Loop over all the entries in the map corresponding to the given
4886  // row or column. It will be ordered
4887 
4888  for (std::map<unsigned, double>::iterator it =
4889  matrix_data_map[m][i_global].begin();
4890  it != matrix_data_map[m][i_global].end();
4891  ++it)
4892  {
4893  // The first value is the column or row index
4894  column_or_row_index[m][entry_count] = it->first;
4895  // The second value is the actual data value
4896  value[m][entry_count] = it->second;
4897  // Increase the value of the counter
4898  entry_count++;
4899  }
4900  }
4901 
4902  // Final entry in the row/column start vector
4903  row_or_column_start[m][ndof] = entry_count;
4904  } // End of the loop over the matrices
4905 
4907  {
4908  oomph_info << "Pausing at end of sparse assembly." << std::endl;
4909  pause("Check memory usage now.");
4910  }
4911  }

References Assembly_handler_pt, assembly_handler_pt(), Communicator_pt, e(), oomph::Mesh::element_pt(), oomph::AssemblyHandler::eqn_number(), boost::multiprecision::fabs(), oomph::AssemblyHandler::get_all_vectors_and_matrices(), i, j, m, mesh_pt(), oomph::OomphCommunicator::my_rank(), ndof(), oomph::AssemblyHandler::ndof(), oomph::Mesh::nelement(), Numerical_zero_for_sparse_assembly, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, oomph::pause(), Pause_at_end_of_sparse_assembly, oomph::TimingHelpers::timer(), v, and Eigen::value.

Referenced by sparse_assemble_row_or_column_compressed().

◆ sparse_assemble_row_or_column_compressed_with_two_arrays()

void Problem::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 * > &  residuals,
bool  compressed_row_flag 
)
privatevirtual

Private helper function that is used to assemble the Jacobian matrix in the case when the storage is row or column compressed. The boolean Flag indicates if we want compressed row format (true) or compressed column. This version uses lists

This is a (private) helper function that is used to assemble system matrices in compressed row or column format and compute residual vectors using two vectors. The default action is to assemble the jacobian matrix and residuals for the Newton method. The action can be overloaded at an elemental level by chaging the default behaviour of the function Element::get_all_vectors_and_matrices(). column_or_row_index: Column [or row] index of given entry row_or_column_start: Index of first entry for given row [or column] value : Vector of nonzero entries residuals : Residual vector compressed_row_flag: Bool flag to indicate if storage format is compressed row [if false interpretation of arguments is as stated in square brackets].

6068  {
6069  // Total number of elements
6070  const unsigned long n_elements = mesh_pt()->nelement();
6071 
6072  // Default range of elements for distributed problems
6073  unsigned long el_lo = 0;
6074  unsigned long el_hi = n_elements - 1;
6075 
6076 
6077 #ifdef OOMPH_HAS_MPI
6078  // Otherwise just loop over a fraction of the elements
6079  // (This will either have been initialised in
6080  // Problem::set_default_first_and_last_element_for_assembly() or
6081  // will have been re-assigned during a previous assembly loop
6082  // Note that following the re-assignment only the entries
6083  // for the current processor are relevant.
6084  if (!Problem_has_been_distributed)
6085  {
6086  el_lo = First_el_for_assembly[Communicator_pt->my_rank()];
6087  el_hi = Last_el_plus_one_for_assembly[Communicator_pt->my_rank()] - 1;
6088  }
6089 #endif
6090 
6091  // number of local eqns
6092  unsigned ndof = this->ndof();
6093 
6094  // Find the number of vectors to be assembled
6095  const unsigned n_vector = residuals.size();
6096 
6097  // Find the number of matrices to be assembled
6098  const unsigned n_matrix = column_or_row_index.size();
6099 
6100  // Locally cache pointer to assembly handler
6101  AssemblyHandler* const assembly_handler_pt = Assembly_handler_pt;
6102 
6103 #ifdef OOMPH_HAS_MPI
6104  bool doing_residuals = false;
6105  if (dynamic_cast<ParallelResidualsHandler*>(Assembly_handler_pt) != 0)
6106  {
6107  doing_residuals = true;
6108  }
6109 #endif
6110 
6111 // Error check dimensions
6112 #ifdef PARANOID
6113  if (row_or_column_start.size() != n_matrix)
6114  {
6115  std::ostringstream error_stream;
6116  error_stream << "Error: " << std::endl
6117  << "row_or_column_start.size() "
6118  << row_or_column_start.size() << " does not equal "
6119  << "column_or_row_index.size() "
6120  << column_or_row_index.size() << std::endl;
6121  throw OomphLibError(
6122  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
6123  }
6124 
6125  if (value.size() != n_matrix)
6126  {
6127  std::ostringstream error_stream;
6128  error_stream << "Error: " << std::endl
6129  << "value.size() " << value.size() << " does not equal "
6130  << "column_or_row_index.size() "
6131  << column_or_row_index.size() << std::endl
6132  << std::endl
6133  << std::endl;
6134  throw OomphLibError(
6135  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
6136  }
6137 #endif
6138 
6139  // The idea behind this sparse assembly routine is to use Vectors of
6140  // Vectors for the entries in each complete matrix. And a second
6141  // Vector of Vectors stores the global row (or column) indeces. This
6142  // will not have the memory overheads associated with the methods using
6143  // lists or maps, but insertion will be more costly.
6144 
6145  // Set up two vector of vectors to store the entries of each matrix,
6146  // indexed by either the column or row. The entries of the vector for
6147  // each matrix correspond to all the rows or columns of that matrix.
6148  Vector<unsigned**> matrix_row_or_col_indices(n_matrix);
6149  Vector<double**> matrix_values(n_matrix);
6150 
6151  // Loop over the number of matrices being assembled and resize
6152  // each vector of vectors to the number of rows or columns of the matrix
6153  for (unsigned m = 0; m < n_matrix; m++)
6154  {
6155  matrix_row_or_col_indices[m] = new unsigned*[ndof];
6156  matrix_values[m] = new double*[ndof];
6157  }
6158 
6159  // Resize the residuals vectors
6160  for (unsigned v = 0; v < n_vector; v++)
6161  {
6162  residuals[v] = new double[ndof];
6163  for (unsigned i = 0; i < ndof; i++)
6164  {
6165  residuals[v][i] = 0;
6166  }
6167  }
6168 
6169 #ifdef OOMPH_HAS_MPI
6170 
6171  // Storage for assembly time for elements
6172  double t_assemble_start = 0.0;
6173 
6174  // Storage for assembly times
6175  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
6176  {
6177  Elemental_assembly_time.resize(n_elements);
6178  }
6179 
6180 #endif
6181 
6182  // number of coefficients in each row
6183  Vector<Vector<unsigned>> ncoef(n_matrix);
6184  for (unsigned m = 0; m < n_matrix; m++)
6185  {
6186  ncoef[m].resize(ndof, 0);
6187  }
6188 
6190  {
6192  for (unsigned m = 0; m < n_matrix; m++)
6193  {
6195  }
6196  }
6197 
6198  //----------------Assemble and populate the vector storage scheme-------
6199  {
6200  // Allocate local storage for the element's contribution to the
6201  // residuals vectors and system matrices of the size of the maximum
6202  // number of dofs in any element
6203  // This means that the storage will only be allocated (and deleted) once
6204  Vector<Vector<double>> el_residuals(n_vector);
6205  Vector<DenseMatrix<double>> el_jacobian(n_matrix);
6206 
6207  // Loop over the elements
6208  for (unsigned long e = el_lo; e <= el_hi; e++)
6209  {
6210 #ifdef OOMPH_HAS_MPI
6211  // Time it?
6212  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
6213  {
6214  t_assemble_start = TimingHelpers::timer();
6215  }
6216 #endif
6217 
6218  // Get the pointer to the element
6219  GeneralisedElement* elem_pt = mesh_pt()->element_pt(e);
6220 
6221 #ifdef OOMPH_HAS_MPI
6222  // Ignore halo elements
6223  if (!elem_pt->is_halo())
6224  {
6225 #endif
6226 
6227  // Find number of degrees of freedom in the element
6228  const unsigned nvar = assembly_handler_pt->ndof(elem_pt);
6229 
6230  // Resize the storage for elemental jacobian and residuals
6231  for (unsigned v = 0; v < n_vector; v++)
6232  {
6233  el_residuals[v].resize(nvar);
6234  }
6235  for (unsigned m = 0; m < n_matrix; m++)
6236  {
6237  el_jacobian[m].resize(nvar);
6238  }
6239 
6240  // Now get the residuals and jacobian for the element
6242  elem_pt, el_residuals, el_jacobian);
6243 
6244  //---------------Insert the values into the vectors--------------
6245 
6246  // Loop over the first index of local variables
6247  for (unsigned i = 0; i < nvar; i++)
6248  {
6249  // Get the local equation number
6250  unsigned eqn_number = assembly_handler_pt->eqn_number(elem_pt, i);
6251 
6252  // Add the contribution to the residuals
6253  for (unsigned v = 0; v < n_vector; v++)
6254  {
6255  // Fill in each residuals vector
6256  residuals[v][eqn_number] += el_residuals[v][i];
6257  }
6258 
6259  // Now loop over the other index
6260  for (unsigned j = 0; j < nvar; j++)
6261  {
6262  // Get the number of the unknown
6263  unsigned unknown = assembly_handler_pt->eqn_number(elem_pt, j);
6264 
6265  // Loop over the matrices
6266  // If it's compressed row storage, then our vector of maps
6267  // is indexed by row (equation number)
6268  for (unsigned m = 0; m < n_matrix; m++)
6269  {
6270  // Get the value of the matrix at this point
6271  double value = el_jacobian[m](i, j);
6272  // Only bother to add to the vector if it's non-zero
6274  {
6275  // number of entrys in this row
6276  const unsigned size = ncoef[m][eqn_number];
6277 
6278  // if no data has been allocated for this row then allocate
6279  if (size == 0)
6280  {
6281  // do we have previous allocation data
6283  [m][eqn_number] != 0)
6284  {
6285  matrix_row_or_col_indices[m][eqn_number] = new unsigned
6287  [m][eqn_number]];
6288  matrix_values[m][eqn_number] = new double
6290  [m][eqn_number]];
6291  }
6292  else
6293  {
6294  matrix_row_or_col_indices[m][eqn_number] = new unsigned
6296  matrix_values[m][eqn_number] = new double
6299  [m][eqn_number] =
6301  }
6302  }
6303 
6304  // If it's compressed row storage, then our vector of maps
6305  // is indexed by row (equation number)
6306  if (compressed_row_flag)
6307  {
6308  // next add the data
6309  for (unsigned k = 0; k <= size; k++)
6310  {
6311  if (k == size)
6312  {
6313  // do we need to allocate more storage
6315  [m][eqn_number] == ncoef[m][eqn_number])
6316  {
6317  unsigned new_allocation =
6318  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++)
6323  {
6324  new_values[c] = matrix_values[m][eqn_number][c];
6325  new_indices[c] =
6326  matrix_row_or_col_indices[m][eqn_number][c];
6327  }
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] =
6332  new_indices;
6334  [m][eqn_number] = new_allocation;
6335  }
6336  // and now add the data
6337  unsigned entry = ncoef[m][eqn_number];
6338  ncoef[m][eqn_number]++;
6339  matrix_row_or_col_indices[m][eqn_number][entry] =
6340  unknown;
6341  matrix_values[m][eqn_number][entry] = value;
6342  break;
6343  }
6344  else if (matrix_row_or_col_indices[m][eqn_number][k] ==
6345  unknown)
6346  {
6347  matrix_values[m][eqn_number][k] += value;
6348  break;
6349  }
6350  }
6351  }
6352  // Otherwise it's compressed column storage and our vector is
6353  // indexed by column (the unknown)
6354  else
6355  {
6356  // Add the data into the vectors in the correct position
6357  for (unsigned k = 0; k <= size; k++)
6358  {
6359  if (k == size)
6360  {
6361  // do we need to allocate more storage
6363  [m][unknown] == ncoef[m][unknown])
6364  {
6365  unsigned new_allocation =
6366  ncoef[m][unknown] +
6368  double* new_values = new double[new_allocation];
6369  unsigned* new_indices = new unsigned[new_allocation];
6370  for (unsigned c = 0; c < ncoef[m][unknown]; c++)
6371  {
6372  new_values[c] = matrix_values[m][unknown][c];
6373  new_indices[c] =
6374  matrix_row_or_col_indices[m][unknown][c];
6375  }
6376  delete[] matrix_values[m][unknown];
6377  delete[] matrix_row_or_col_indices[m][unknown];
6379  [m][unknown] = new_allocation;
6380  }
6381  // and now add the data
6382  unsigned entry = ncoef[m][unknown];
6383  ncoef[m][unknown]++;
6384  matrix_row_or_col_indices[m][unknown][entry] =
6385  eqn_number;
6386  matrix_values[m][unknown][entry] = value;
6387  break;
6388  }
6389  else if (matrix_row_or_col_indices[m][unknown][k] ==
6390  eqn_number)
6391  {
6392  matrix_values[m][unknown][k] += value;
6393  break;
6394  }
6395  }
6396  }
6397  }
6398  } // End of loop over matrices
6399  }
6400  }
6401 
6402 #ifdef OOMPH_HAS_MPI
6403  } // endif halo element
6404 #endif
6405 
6406 
6407 #ifdef OOMPH_HAS_MPI
6408  // Time it?
6409  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
6410  {
6411  Elemental_assembly_time[e] =
6412  TimingHelpers::timer() - t_assemble_start;
6413  }
6414 #endif
6415 
6416  } // End of loop over the elements
6417 
6418  } // End of vector assembly
6419 
6420 
6421 #ifdef OOMPH_HAS_MPI
6422 
6423  // Postprocess timing information and re-allocate distribution of
6424  // elements during subsequent assemblies.
6425  if ((!doing_residuals) && (!Problem_has_been_distributed) &&
6426  Must_recompute_load_balance_for_assembly)
6427  {
6428  recompute_load_balanced_assembly();
6429  }
6430 
6431  // We have determined load balancing for current setup.
6432  // This can remain the same until assign_eqn_numbers() is called
6433  // again -- the flag is re-set to true there.
6434  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
6435  {
6436  Must_recompute_load_balance_for_assembly = false;
6437  }
6438 
6439 #endif
6440 
6441  //-----------Finally we need to convert this lousy vector storage scheme
6442  //------------------------to the containers required by SuperLU
6443 
6444  // Loop over the number of matrices
6445  for (unsigned m = 0; m < n_matrix; m++)
6446  {
6447  // Set the number of rows or columns
6448  row_or_column_start[m] = new int[ndof + 1];
6449 
6450  // fill row_or_column_start and find the number of entries
6451  row_or_column_start[m][0] = 0;
6452  for (unsigned long i = 0; i < ndof; i++)
6453  {
6454  row_or_column_start[m][i + 1] = row_or_column_start[m][i] + ncoef[m][i];
6456  }
6457  const unsigned entries = row_or_column_start[m][ndof];
6458 
6459  // resize vectors
6460  column_or_row_index[m] = new int[entries];
6461  value[m] = new double[entries];
6462  nnz[m] = entries;
6463 
6464  // Now we merely loop over the number of rows or columns
6465  for (unsigned long i_global = 0; i_global < ndof; i_global++)
6466  {
6467  // If there are no entries in the vector then skip the rest of the loop
6468  if (ncoef[m][i_global] == 0)
6469  {
6470  continue;
6471  }
6472 
6473  // Loop over all the entries in the vectors corresponding to the given
6474  // row or column. It will NOT be ordered
6475  unsigned p = 0;
6476  for (int j = row_or_column_start[m][i_global];
6477  j < row_or_column_start[m][i_global + 1];
6478  j++)
6479  {
6480  column_or_row_index[m][j] = matrix_row_or_col_indices[m][i_global][p];
6481  value[m][j] = matrix_values[m][i_global][p];
6482  ++p;
6483  }
6484 
6485  // and delete
6486  delete[] matrix_row_or_col_indices[m][i_global];
6487  delete[] matrix_values[m][i_global];
6488  }
6489 
6490  //
6491  delete[] matrix_row_or_col_indices[m];
6492  delete[] matrix_values[m];
6493  } // End of the loop over the matrices
6494 
6496  {
6497  oomph_info << "Pausing at end of sparse assembly." << std::endl;
6498  pause("Check memory usage now.");
6499  }
6500  }

References Assembly_handler_pt, assembly_handler_pt(), calibrate::c, Communicator_pt, e(), oomph::Mesh::element_pt(), oomph::AssemblyHandler::eqn_number(), boost::multiprecision::fabs(), oomph::AssemblyHandler::get_all_vectors_and_matrices(), i, j, k, m, mesh_pt(), oomph::OomphCommunicator::my_rank(), ndof(), oomph::AssemblyHandler::ndof(), oomph::Mesh::nelement(), Numerical_zero_for_sparse_assembly, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, p, oomph::pause(), Pause_at_end_of_sparse_assembly, size, Sparse_assemble_with_arrays_allocation_increment, Sparse_assemble_with_arrays_initial_allocation, Sparse_assemble_with_arrays_previous_allocation, oomph::TimingHelpers::timer(), v, and Eigen::value.

Referenced by sparse_assemble_row_or_column_compressed().

◆ sparse_assemble_row_or_column_compressed_with_two_vectors()

void Problem::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 * > &  residuals,
bool  compressed_row_flag 
)
privatevirtual

Private helper function that is used to assemble the Jacobian matrix in the case when the storage is row or column compressed. The boolean Flag indicates if we want compressed row format (true) or compressed column. This version uses two vectors.

This is a (private) helper function that is used to assemble system matrices in compressed row or column format and compute residual vectors using two vectors. The default action is to assemble the jacobian matrix and residuals for the Newton method. The action can be overloaded at an elemental level by chaging the default behaviour of the function Element::get_all_vectors_and_matrices(). column_or_row_index: Column [or row] index of given entry row_or_column_start: Index of first entry for given row [or column] value : Vector of nonzero entries residuals : Residual vector compressed_row_flag: Bool flag to indicate if storage format is compressed row [if false interpretation of arguments is as stated in square brackets].

5705  {
5706  // Total number of elements
5707  const unsigned long n_elements = mesh_pt()->nelement();
5708 
5709  // Default range of elements for distributed problems
5710  unsigned long el_lo = 0;
5711  unsigned long el_hi = n_elements - 1;
5712 
5713 
5714 #ifdef OOMPH_HAS_MPI
5715  // Otherwise just loop over a fraction of the elements
5716  // (This will either have been initialised in
5717  // Problem::set_default_first_and_last_element_for_assembly() or
5718  // will have been re-assigned during a previous assembly loop
5719  // Note that following the re-assignment only the entries
5720  // for the current processor are relevant.
5721  if (!Problem_has_been_distributed)
5722  {
5723  el_lo = First_el_for_assembly[Communicator_pt->my_rank()];
5724  el_hi = Last_el_plus_one_for_assembly[Communicator_pt->my_rank()] - 1;
5725  }
5726 #endif
5727 
5728  // number of local eqns
5729  unsigned ndof = this->ndof();
5730 
5731  // Find the number of vectors to be assembled
5732  const unsigned n_vector = residuals.size();
5733 
5734  // Find the number of matrices to be assembled
5735  const unsigned n_matrix = column_or_row_index.size();
5736 
5737  // Locally cache pointer to assembly handler
5738  AssemblyHandler* const assembly_handler_pt = Assembly_handler_pt;
5739 
5740 #ifdef OOMPH_HAS_MPI
5741  bool doing_residuals = false;
5742  if (dynamic_cast<ParallelResidualsHandler*>(Assembly_handler_pt) != 0)
5743  {
5744  doing_residuals = true;
5745  }
5746 #endif
5747 
5748 // Error check dimensions
5749 #ifdef PARANOID
5750  if (row_or_column_start.size() != n_matrix)
5751  {
5752  std::ostringstream error_stream;
5753  error_stream << "Error: " << std::endl
5754  << "row_or_column_start.size() "
5755  << row_or_column_start.size() << " does not equal "
5756  << "column_or_row_index.size() "
5757  << column_or_row_index.size() << std::endl;
5758  throw OomphLibError(
5759  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5760  }
5761 
5762  if (value.size() != n_matrix)
5763  {
5764  std::ostringstream error_stream;
5765  error_stream << "Error: " << std::endl
5766  << "value.size() " << value.size() << " does not equal "
5767  << "column_or_row_index.size() "
5768  << column_or_row_index.size() << std::endl
5769  << std::endl
5770  << std::endl;
5771  throw OomphLibError(
5772  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5773  }
5774 #endif
5775 
5776  // The idea behind this sparse assembly routine is to use Vectors of
5777  // Vectors for the entries in each complete matrix. And a second
5778  // Vector of Vectors stores the global row (or column) indeces. This
5779  // will not have the memory overheads associated with the methods using
5780  // lists or maps, but insertion will be more costly.
5781 
5782  // Set up two vector of vectors to store the entries of each matrix,
5783  // indexed by either the column or row. The entries of the vector for
5784  // each matrix correspond to all the rows or columns of that matrix.
5785  Vector<Vector<Vector<unsigned>>> matrix_row_or_col_indices(n_matrix);
5786  Vector<Vector<Vector<double>>> matrix_values(n_matrix);
5787 
5788  // Loop over the number of matrices being assembled and resize
5789  // each vector of vectors to the number of rows or columns of the matrix
5790  for (unsigned m = 0; m < n_matrix; m++)
5791  {
5792  matrix_row_or_col_indices[m].resize(ndof);
5793  matrix_values[m].resize(ndof);
5794  }
5795 
5796  // Resize the residuals vectors
5797  for (unsigned v = 0; v < n_vector; v++)
5798  {
5799  residuals[v] = new double[ndof];
5800  for (unsigned i = 0; i < ndof; i++)
5801  {
5802  residuals[v][i] = 0;
5803  }
5804  }
5805 
5806 #ifdef OOMPH_HAS_MPI
5807 
5808  // Storage for assembly time for elements
5809  double t_assemble_start = 0.0;
5810 
5811  // Storage for assembly times
5812  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
5813  {
5814  Elemental_assembly_time.resize(n_elements);
5815  }
5816 
5817 #endif
5818 
5819 
5820  //----------------Assemble and populate the vector storage scheme-------
5821  {
5822  // Allocate local storage for the element's contribution to the
5823  // residuals vectors and system matrices of the size of the maximum
5824  // number of dofs in any element
5825  // This means that the storage will only be allocated (and deleted) once
5826  Vector<Vector<double>> el_residuals(n_vector);
5827  Vector<DenseMatrix<double>> el_jacobian(n_matrix);
5828 
5829  // Loop over the elements
5830  for (unsigned long e = el_lo; e <= el_hi; e++)
5831  {
5832 #ifdef OOMPH_HAS_MPI
5833  // Time it?
5834  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
5835  {
5836  t_assemble_start = TimingHelpers::timer();
5837  }
5838 #endif
5839 
5840  // Get the pointer to the element
5841  GeneralisedElement* elem_pt = mesh_pt()->element_pt(e);
5842 
5843 #ifdef OOMPH_HAS_MPI
5844  // Ignore halo elements
5845  if (!elem_pt->is_halo())
5846  {
5847 #endif
5848 
5849  // Find number of degrees of freedom in the element
5850  const unsigned nvar = assembly_handler_pt->ndof(elem_pt);
5851 
5852  // Resize the storage for elemental jacobian and residuals
5853  for (unsigned v = 0; v < n_vector; v++)
5854  {
5855  el_residuals[v].resize(nvar);
5856  }
5857  for (unsigned m = 0; m < n_matrix; m++)
5858  {
5859  el_jacobian[m].resize(nvar);
5860  }
5861 
5862  // Now get the residuals and jacobian for the element
5864  elem_pt, el_residuals, el_jacobian);
5865 
5866  //---------------Insert the values into the vectors--------------
5867 
5868  // Loop over the first index of local variables
5869  for (unsigned i = 0; i < nvar; i++)
5870  {
5871  // Get the local equation number
5872  unsigned eqn_number = assembly_handler_pt->eqn_number(elem_pt, i);
5873 
5874  // Add the contribution to the residuals
5875  for (unsigned v = 0; v < n_vector; v++)
5876  {
5877  // Fill in each residuals vector
5878  residuals[v][eqn_number] += el_residuals[v][i];
5879  }
5880 
5881  // Now loop over the other index
5882  for (unsigned j = 0; j < nvar; j++)
5883  {
5884  // Get the number of the unknown
5885  unsigned unknown = assembly_handler_pt->eqn_number(elem_pt, j);
5886 
5887  // Loop over the matrices
5888  // If it's compressed row storage, then our vector of maps
5889  // is indexed by row (equation number)
5890  for (unsigned m = 0; m < n_matrix; m++)
5891  {
5892  // Get the value of the matrix at this point
5893  double value = el_jacobian[m](i, j);
5894  // Only bother to add to the vector if it's non-zero
5896  {
5897  // If it's compressed row storage, then our vector of maps
5898  // is indexed by row (equation number)
5899  if (compressed_row_flag)
5900  {
5901  // Find the correct position and add the data into the
5902  // vectors
5903  const unsigned size =
5904  matrix_row_or_col_indices[m][eqn_number].size();
5905 
5906  for (unsigned k = 0; k <= size; k++)
5907  {
5908  if (k == size)
5909  {
5910  matrix_row_or_col_indices[m][eqn_number].push_back(
5911  unknown);
5912  matrix_values[m][eqn_number].push_back(value);
5913  break;
5914  }
5915  else if (matrix_row_or_col_indices[m][eqn_number][k] ==
5916  unknown)
5917  {
5918  matrix_values[m][eqn_number][k] += value;
5919  break;
5920  }
5921  }
5922  }
5923  // Otherwise it's compressed column storage and our vector is
5924  // indexed by column (the unknown)
5925  else
5926  {
5927  // Add the data into the vectors in the correct position
5928  const unsigned size =
5929  matrix_row_or_col_indices[m][unknown].size();
5930  for (unsigned k = 0; k <= size; k++)
5931  {
5932  if (k == size)
5933  {
5934  matrix_row_or_col_indices[m][unknown].push_back(
5935  eqn_number);
5936  matrix_values[m][unknown].push_back(value);
5937  break;
5938  }
5939  else if (matrix_row_or_col_indices[m][unknown][k] ==
5940  eqn_number)
5941  {
5942  matrix_values[m][unknown][k] += value;
5943  break;
5944  }
5945  }
5946  }
5947  }
5948  } // End of loop over matrices
5949  }
5950  }
5951 
5952 #ifdef OOMPH_HAS_MPI
5953  } // endif halo element
5954 #endif
5955 
5956 
5957 #ifdef OOMPH_HAS_MPI
5958  // Time it?
5959  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
5960  {
5961  Elemental_assembly_time[e] =
5962  TimingHelpers::timer() - t_assemble_start;
5963  }
5964 #endif
5965 
5966  } // End of loop over the elements
5967 
5968  } // End of vector assembly
5969 
5970 
5971 #ifdef OOMPH_HAS_MPI
5972 
5973  // Postprocess timing information and re-allocate distribution of
5974  // elements during subsequent assemblies.
5975  if ((!doing_residuals) && (!Problem_has_been_distributed) &&
5976  Must_recompute_load_balance_for_assembly)
5977  {
5978  recompute_load_balanced_assembly();
5979  }
5980 
5981  // We have determined load balancing for current setup.
5982  // This can remain the same until assign_eqn_numbers() is called
5983  // again -- the flag is re-set to true there.
5984  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
5985  {
5986  Must_recompute_load_balance_for_assembly = false;
5987  }
5988 
5989 #endif
5990 
5991  //-----------Finally we need to convert this lousy vector storage scheme
5992  //------------------------to the containers required by SuperLU
5993 
5994  // Loop over the number of matrices
5995  for (unsigned m = 0; m < n_matrix; m++)
5996  {
5997  // Set the number of rows or columns
5998  row_or_column_start[m] = new int[ndof + 1];
5999 
6000  // fill row_or_column_start and find the number of entries
6001  row_or_column_start[m][0] = 0;
6002  for (unsigned long i = 0; i < ndof; i++)
6003  {
6004  row_or_column_start[m][i + 1] =
6005  row_or_column_start[m][i] + matrix_values[m][i].size();
6006  }
6007  const unsigned entries = row_or_column_start[m][ndof];
6008 
6009  // resize vectors
6010  column_or_row_index[m] = new int[entries];
6011  value[m] = new double[entries];
6012  nnz[m] = entries;
6013 
6014  // Now we merely loop over the number of rows or columns
6015  for (unsigned long i_global = 0; i_global < ndof; i_global++)
6016  {
6017  // If there are no entries in the vector then skip the rest of the loop
6018  if (matrix_values[m][i_global].empty())
6019  {
6020  continue;
6021  }
6022 
6023  // Loop over all the entries in the vectors corresponding to the given
6024  // row or column. It will NOT be ordered
6025  unsigned p = 0;
6026  for (int j = row_or_column_start[m][i_global];
6027  j < row_or_column_start[m][i_global + 1];
6028  j++)
6029  {
6030  column_or_row_index[m][j] = matrix_row_or_col_indices[m][i_global][p];
6031  value[m][j] = matrix_values[m][i_global][p];
6032  ++p;
6033  }
6034  }
6035  } // End of the loop over the matrices
6036 
6038  {
6039  oomph_info << "Pausing at end of sparse assembly." << std::endl;
6040  pause("Check memory usage now.");
6041  }
6042  }

References Assembly_handler_pt, assembly_handler_pt(), Communicator_pt, e(), oomph::Mesh::element_pt(), oomph::AssemblyHandler::eqn_number(), boost::multiprecision::fabs(), oomph::AssemblyHandler::get_all_vectors_and_matrices(), i, j, k, m, mesh_pt(), oomph::OomphCommunicator::my_rank(), ndof(), oomph::AssemblyHandler::ndof(), oomph::Mesh::nelement(), Numerical_zero_for_sparse_assembly, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, p, oomph::pause(), Pause_at_end_of_sparse_assembly, size, oomph::TimingHelpers::timer(), v, and Eigen::value.

Referenced by sparse_assemble_row_or_column_compressed().

◆ sparse_assemble_row_or_column_compressed_with_vectors_of_pairs()

void Problem::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 * > &  residuals,
bool  compressed_row_flag 
)
privatevirtual

Private helper function that is used to assemble the Jacobian matrix in the case when the storage is row or column compressed. The boolean Flag indicates if we want compressed row format (true) or compressed column. This version uses vectors of pairs.

This is a (private) helper function that is used to assemble system matrices in compressed row or column format and compute residual vectors using vectors of pairs The default action is to assemble the jacobian matrix and residuals for the Newton method. The action can be overloaded at an elemental level by chaging the default behaviour of the function Element::get_all_vectors_and_matrices(). column_or_row_index: Column [or row] index of given entry row_or_column_start: Index of first entry for given row [or column] value : Vector of nonzero entries residuals : Residual vector compressed_row_flag: Bool flag to indicate if storage format is compressed row [if false interpretation of arguments is as stated in square brackets].

5352  {
5353  // Total number of elements
5354  const unsigned long n_elements = mesh_pt()->nelement();
5355 
5356  // Default range of elements for distributed problems
5357  unsigned long el_lo = 0;
5358  unsigned long el_hi = n_elements - 1;
5359 
5360 #ifdef OOMPH_HAS_MPI
5361  // Otherwise just loop over a fraction of the elements
5362  // (This will either have been initialised in
5363  // Problem::set_default_first_and_last_element_for_assembly() or
5364  // will have been re-assigned during a previous assembly loop
5365  // Note that following the re-assignment only the entries
5366  // for the current processor are relevant.
5367  if (!Problem_has_been_distributed)
5368  {
5369  el_lo = First_el_for_assembly[Communicator_pt->my_rank()];
5370  el_hi = Last_el_plus_one_for_assembly[Communicator_pt->my_rank()] - 1;
5371  }
5372 #endif
5373 
5374  // number of local eqns
5375  unsigned ndof = this->ndof();
5376 
5377  // Find the number of vectors to be assembled
5378  const unsigned n_vector = residuals.size();
5379 
5380  // Find the number of matrices to be assembled
5381  const unsigned n_matrix = column_or_row_index.size();
5382 
5383  // Locally cache pointer to assembly handler
5384  AssemblyHandler* const assembly_handler_pt = Assembly_handler_pt;
5385 
5386 #ifdef OOMPH_HAS_MPI
5387  bool doing_residuals = false;
5388  if (dynamic_cast<ParallelResidualsHandler*>(Assembly_handler_pt) != 0)
5389  {
5390  doing_residuals = true;
5391  }
5392 #endif
5393 
5394 // Error check dimensions
5395 #ifdef PARANOID
5396  if (row_or_column_start.size() != n_matrix)
5397  {
5398  std::ostringstream error_stream;
5399  error_stream << "Error: " << std::endl
5400  << "row_or_column_start.size() "
5401  << row_or_column_start.size() << " does not equal "
5402  << "column_or_row_index.size() "
5403  << column_or_row_index.size() << std::endl;
5404  throw OomphLibError(
5405  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5406  }
5407 
5408  if (value.size() != n_matrix)
5409  {
5410  std::ostringstream error_stream;
5411  error_stream << "Error: " << std::endl
5412  << "value.size() " << value.size() << " does not equal "
5413  << "column_or_row_index.size() "
5414  << column_or_row_index.size() << std::endl
5415  << std::endl
5416  << std::endl;
5417  throw OomphLibError(
5418  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
5419  }
5420 #endif
5421 
5422 
5423  // The idea behind this sparse assembly routine is to use a Vector of
5424  // Vectors of pairs for each complete matrix.
5425  // Each inner Vector stores pairs and holds the row (or column) index
5426  // and the value of the matrix entry.
5427 
5428  // Set up Vector of Vectors to store the entries of each matrix,
5429  // indexed by either the column or row.
5430  Vector<Vector<Vector<std::pair<unsigned, double>>>> matrix_data(n_matrix);
5431 
5432  // Loop over the number of matrices being assembled and resize
5433  // each Vector of Vectors to the number of rows or columns of the matrix
5434  for (unsigned m = 0; m < n_matrix; m++)
5435  {
5436  matrix_data[m].resize(ndof);
5437  }
5438 
5439  // Resize the residuals vectors
5440  for (unsigned v = 0; v < n_vector; v++)
5441  {
5442  residuals[v] = new double[ndof];
5443  for (unsigned i = 0; i < ndof; i++)
5444  {
5445  residuals[v][i] = 0;
5446  }
5447  }
5448 
5449 #ifdef OOMPH_HAS_MPI
5450 
5451  // Storage for assembly time for elements
5452  double t_assemble_start = 0.0;
5453 
5454  // Storage for assembly times
5455  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
5456  {
5457  Elemental_assembly_time.resize(n_elements);
5458  }
5459 
5460 #endif
5461 
5462  //----------------Assemble and populate the vector storage scheme--------
5463  {
5464  // Allocate local storage for the element's contribution to the
5465  // residuals vectors and system matrices of the size of the maximum
5466  // number of dofs in any element
5467  // This means that the storage is only allocated (and deleted) once
5468  Vector<Vector<double>> el_residuals(n_vector);
5469  Vector<DenseMatrix<double>> el_jacobian(n_matrix);
5470 
5471  // Loop over the elements
5472  for (unsigned long e = el_lo; e <= el_hi; e++)
5473  {
5474 #ifdef OOMPH_HAS_MPI
5475  // Time it?
5476  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
5477  {
5478  t_assemble_start = TimingHelpers::timer();
5479  }
5480 #endif
5481 
5482  // Get the pointer to the element
5483  GeneralisedElement* elem_pt = mesh_pt()->element_pt(e);
5484 
5485 #ifdef OOMPH_HAS_MPI
5486  // Ignore halo elements
5487  if (!elem_pt->is_halo())
5488  {
5489 #endif
5490 
5491  // Find number of degrees of freedom in the element
5492  const unsigned nvar = assembly_handler_pt->ndof(elem_pt);
5493 
5494  // Resize the storage for elemental jacobian and residuals
5495  for (unsigned v = 0; v < n_vector; v++)
5496  {
5497  el_residuals[v].resize(nvar);
5498  }
5499  for (unsigned m = 0; m < n_matrix; m++)
5500  {
5501  el_jacobian[m].resize(nvar);
5502  }
5503 
5504  // Now get the residuals and jacobian for the element
5506  elem_pt, el_residuals, el_jacobian);
5507 
5508  //---------------Insert the values into the vectors--------------
5509 
5510  // Loop over the first index of local variables
5511  for (unsigned i = 0; i < nvar; i++)
5512  {
5513  // Get the local equation number
5514  unsigned eqn_number = assembly_handler_pt->eqn_number(elem_pt, i);
5515 
5516  // Add the contribution to the residuals
5517  for (unsigned v = 0; v < n_vector; v++)
5518  {
5519  // Fill in each residuals vector
5520  residuals[v][eqn_number] += el_residuals[v][i];
5521  }
5522 
5523  // Now loop over the other index
5524  for (unsigned j = 0; j < nvar; j++)
5525  {
5526  // Get the number of the unknown
5527  unsigned unknown = assembly_handler_pt->eqn_number(elem_pt, j);
5528 
5529  // Loop over the matrices
5530  // If it's compressed row storage, then our vector of maps
5531  // is indexed by row (equation number)
5532  for (unsigned m = 0; m < n_matrix; m++)
5533  {
5534  // Get the value of the matrix at this point
5535  double value = el_jacobian[m](i, j);
5536  // Only bother to add to the vector if it's non-zero
5538  {
5539  // If it's compressed row storage, then our vector of maps
5540  // is indexed by row (equation number)
5541  if (compressed_row_flag)
5542  {
5543  // Find the correct position and add the data into the
5544  // vectors
5545  const unsigned size = matrix_data[m][eqn_number].size();
5546  for (unsigned k = 0; k <= size; k++)
5547  {
5548  if (k == size)
5549  {
5550  matrix_data[m][eqn_number].push_back(
5551  std::make_pair(unknown, value));
5552  break;
5553  }
5554  else if (matrix_data[m][eqn_number][k].first == unknown)
5555  {
5556  matrix_data[m][eqn_number][k].second += value;
5557  break;
5558  }
5559  }
5560  }
5561  // Otherwise it's compressed column storage and our vector is
5562  // indexed by column (the unknown)
5563  else
5564  {
5565  // Add the data into the vectors in the correct position
5566  const unsigned size = matrix_data[m][unknown].size();
5567  for (unsigned k = 0; k <= size; k++)
5568  {
5569  if (k == size)
5570  {
5571  matrix_data[m][unknown].push_back(
5572  std::make_pair(eqn_number, value));
5573  break;
5574  }
5575  else if (matrix_data[m][unknown][k].first == eqn_number)
5576  {
5577  matrix_data[m][unknown][k].second += value;
5578  break;
5579  }
5580  }
5581  }
5582  }
5583  } // End of loop over matrices
5584  }
5585  }
5586 
5587 #ifdef OOMPH_HAS_MPI
5588  } // endif halo element
5589 #endif
5590 
5591 
5592 #ifdef OOMPH_HAS_MPI
5593  // Time it?
5594  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
5595  {
5596  Elemental_assembly_time[e] =
5597  TimingHelpers::timer() - t_assemble_start;
5598  }
5599 #endif
5600 
5601  } // End of loop over the elements
5602 
5603 
5604  } // End of vector assembly
5605 
5606 
5607 #ifdef OOMPH_HAS_MPI
5608 
5609  // Postprocess timing information and re-allocate distribution of
5610  // elements during subsequent assemblies.
5611  if ((!doing_residuals) && (!Problem_has_been_distributed) &&
5612  Must_recompute_load_balance_for_assembly)
5613  {
5614  recompute_load_balanced_assembly();
5615  }
5616 
5617  // We have determined load balancing for current setup.
5618  // This can remain the same until assign_eqn_numbers() is called
5619  // again -- the flag is re-set to true there.
5620  if ((!doing_residuals) && Must_recompute_load_balance_for_assembly)
5621  {
5622  Must_recompute_load_balance_for_assembly = false;
5623  }
5624 
5625 #endif
5626 
5627 
5628  //-----------Finally we need to convert this vector storage scheme
5629  //------------------------to the containers required by SuperLU
5630 
5631  // Loop over the number of matrices
5632  for (unsigned m = 0; m < n_matrix; m++)
5633  {
5634  // Set the number of rows or columns
5635  row_or_column_start[m] = new int[ndof + 1];
5636 
5637  // fill row_or_column_start and find the number of entries
5638  row_or_column_start[m][0] = 0;
5639  for (unsigned long i = 0; i < ndof; i++)
5640  {
5641  row_or_column_start[m][i + 1] =
5642  row_or_column_start[m][i] + matrix_data[m][i].size();
5643  }
5644  const unsigned entries = row_or_column_start[m][ndof];
5645 
5646  // resize vectors
5647  column_or_row_index[m] = new int[entries];
5648  value[m] = new double[entries];
5649  nnz[m] = entries;
5650 
5651  // Now we merely loop over the number of rows or columns
5652  for (unsigned long i_global = 0; i_global < ndof; i_global++)
5653  {
5654  // If there are no entries in the vector then skip the rest of the loop
5655  if (matrix_data[m][i_global].empty())
5656  {
5657  continue;
5658  }
5659 
5660  // Loop over all the entries in the vectors corresponding to the given
5661  // row or column. It will NOT be ordered
5662  unsigned p = 0;
5663  for (int j = row_or_column_start[m][i_global];
5664  j < row_or_column_start[m][i_global + 1];
5665  j++)
5666  {
5667  column_or_row_index[m][j] = matrix_data[m][i_global][p].first;
5668  value[m][j] = matrix_data[m][i_global][p].second;
5669  ++p;
5670  }
5671  }
5672  } // End of the loop over the matrices
5673 
5675  {
5676  oomph_info << "Pausing at end of sparse assembly." << std::endl;
5677  pause("Check memory usage now.");
5678  }
5679  }

References Assembly_handler_pt, assembly_handler_pt(), Communicator_pt, e(), oomph::Mesh::element_pt(), oomph::AssemblyHandler::eqn_number(), boost::multiprecision::fabs(), oomph::AssemblyHandler::get_all_vectors_and_matrices(), i, j, k, m, mesh_pt(), oomph::OomphCommunicator::my_rank(), ndof(), oomph::AssemblyHandler::ndof(), oomph::Mesh::nelement(), Numerical_zero_for_sparse_assembly, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, p, oomph::pause(), Pause_at_end_of_sparse_assembly, size, oomph::TimingHelpers::timer(), v, and Eigen::value.

Referenced by sparse_assemble_row_or_column_compressed().

◆ steady_newton_solve()

void Problem::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 problem, perhaps to determine an initial condition. This is achieved by setting the weights in the timesteppers to be zero which has the effect of rendering them steady timesteppers. The optional argument max_adapt specifies the max. number of adaptations of all refineable submeshes are performed to achieve the the error targets specified in the refineable submeshes.

Solve a steady problem, in the context of an overall unsteady problem. This is achieved by setting the weights in the timesteppers to be zero which has the effect of rendering them steady timesteppers The optional argument max_adapt specifies the max. number of adaptations of all refineable submeshes are performed to achieve the the error targets specified in the refineable submeshes.

9293  {
9294  // Find out how many timesteppers there are
9295  unsigned n_time_steppers = ntime_stepper();
9296 
9297  // Vector of bools to store the is_steady status of the various
9298  // timesteppers when we came in here
9299  std::vector<bool> was_steady(n_time_steppers);
9300 
9301  // Loop over them all and make them (temporarily) static
9302  for (unsigned i = 0; i < n_time_steppers; i++)
9303  {
9304  was_steady[i] = time_stepper_pt(i)->is_steady();
9306  }
9307 
9308  try
9309  {
9310  // Solve the non-linear problem with Newton's method
9311  if (max_adapt == 0)
9312  {
9313  newton_solve();
9314  }
9315  else
9316  {
9317  newton_solve(max_adapt);
9318  }
9319  }
9320  // Catch any exceptions thrown in the Newton solver
9321  catch (NewtonSolverError& error)
9322  {
9323  oomph_info << std::endl
9324  << "USER-DEFINED ERROR IN NEWTON SOLVER " << std::endl;
9325  // Check whether it's the linear solver
9326  if (error.linear_solver_error)
9327  {
9328  oomph_info << "ERROR IN THE LINEAR SOLVER" << std::endl;
9329  }
9330  // Check to see whether we have reached Max_iterations
9331  else if (error.iterations == Max_newton_iterations)
9332  {
9333  oomph_info << "MAXIMUM NUMBER OF ITERATIONS (" << error.iterations
9334  << ") REACHED WITHOUT CONVERGENCE " << std::endl;
9335  }
9336  // If not, it must be that we have exceeded the maximum residuals
9337  else
9338  {
9339  oomph_info << "MAXIMUM RESIDUALS: " << error.maxres
9340  << " EXCEEDS PREDEFINED MAXIMUM " << Max_residuals
9341  << std::endl;
9342  }
9343 
9344  // Die horribly!!
9345  std::ostringstream error_stream;
9346  error_stream << "Error occured in Newton solver. " << std::endl;
9347  throw OomphLibError(
9348  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
9349  }
9350 
9351 
9352  // Reset the is_steady status of all timesteppers that
9353  // weren't already steady when we came in here and reset their
9354  // weights
9355  for (unsigned i = 0; i < n_time_steppers; i++)
9356  {
9357  if (!was_steady[i])
9358  {
9360  }
9361  }
9362 
9363  // Since we performed a steady solve, the history values
9364  // now have to be set as if we had performed an impulsive start from
9365  // the current solution. This ensures that the time-derivatives
9366  // evaluate to zero even now that the timesteppers have been
9367  // reactivated.
9369  }

References assign_initial_values_impulsive(), calibrate::error, i, oomph::TimeStepper::is_steady(), oomph::TimeStepper::make_steady(), Max_newton_iterations, Max_residuals, newton_solve(), ntime_stepper(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, time_stepper_pt(), and oomph::TimeStepper::undo_make_steady().

◆ store_current_dof_values()

void Problem::store_current_dof_values ( )

Store the current values of the degrees of freedom.

Stored the current values of the dofs.

8608  {
8609  // If memory has not been allocated, then allocated memory for the saved
8610  // dofs
8611  if (Saved_dof_pt == 0)
8612  {
8613  Saved_dof_pt = new Vector<double>;
8614  }
8615 
8616 #ifdef OOMPH_HAS_MPI
8617  // If the problem is distributed I have to do something different
8618  if (Problem_has_been_distributed)
8619  {
8620  // How many entries do we store locally?
8621  const unsigned n_row_local = Dof_distribution_pt->nrow_local();
8622 
8623  // Resize the vector
8624  Saved_dof_pt->resize(n_row_local);
8625 
8626  // Back 'em up
8627  for (unsigned i = 0; i < n_row_local; i++)
8628  {
8629  (*Saved_dof_pt)[i] = *(this->Dof_pt[i]);
8630  }
8631  }
8632  // Otherwise just store all the dofs
8633  else
8634 #endif
8635  {
8636  // Find the number of dofs
8637  unsigned long n_dof = ndof();
8638 
8639  // Resize the vector
8640  Saved_dof_pt->resize(n_dof);
8641 
8642  // Transfer the values over
8643  for (unsigned long n = 0; n < n_dof; n++)
8644  {
8645  (*Saved_dof_pt)[n] = dof(n);
8646  }
8647  }
8648  }

References dof(), Dof_distribution_pt, Dof_pt, i, n, ndof(), oomph::LinearAlgebraDistribution::nrow_local(), and Saved_dof_pt.

Referenced by calculate_predictions().

◆ symmetrise_eigenfunction_for_adaptive_pitchfork_tracking()

void Problem::symmetrise_eigenfunction_for_adaptive_pitchfork_tracking ( )
virtual

Virtual function that is used to symmetrise the problem so that the current solution exactly satisfies any symmetries within the system. Used when adpativly solving pitchfork detection problems when small asymmetries in the coarse solution can be magnified leading to very inaccurate answers on the fine mesh. This is always problem-specific and must be filled in by the user The default issues a warning

Reimplemented in RefineablePorousChannelProblem< ELEMENT >.

10060  {
10061  std::ostringstream warn_message;
10062  warn_message
10063  << "Warning: This function is called after spatially adapting the\n"
10064  << "eigenfunction associated with a pitchfork bifurcation and should\n"
10065  << "ensure that the exact (anti-)symmetries of problem are enforced\n"
10066  << "within that eigenfunction. It is problem specific and must be\n"
10067  << "filled in by the user if required.\n"
10068  << "A sign of problems is if the slack paramter gets too large and\n"
10069  << "if the solution at the Pitchfork is not symmetric.\n";
10070  OomphLibWarning(
10071  warn_message.str(),
10072  "Problem::symmetrise_eigenfunction_for_adaptive_pitchfork_tracking()",
10074  }

References OOMPH_EXCEPTION_LOCATION.

◆ time() [1/2]

double & Problem::time ( )
virtual

Return the current value of continuous time.

Return the current value of continuous time. If not Time object has been assigned, then throw an error

Reimplemented from oomph::ExplicitTimeSteppableObject.

11532  {
11533  if (Time_pt == 0)
11534  {
11535  throw OomphLibError("Time object has not been set",
11538  }
11539  else
11540  {
11541  return Time_pt->time();
11542  }
11543  }

References OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::Time::time(), and Time_pt.

Referenced by oomph::WomersleyProblem< ELEMENT, DIM >::actions_before_implicit_timestep(), calculate_predictions(), FSIRingProblem::dynamic_run(), oomph::ODEProblem::exact_solution(), oomph::ODEProblem::get_error_norm(), oomph::ODEProblem::my_set_initial_condition(), read(), oomph::SolidICProblem::set_static_initial_condition(), oomph::SegregatableFSIProblem::t_spent_on_actual_solve(), and oomph::ODEProblem::write_additional_trace_data().

◆ time() [2/2]

double Problem::time ( ) const

Return the current value of continuous time (const version)

Return the current value of continuous time. If not Time object has been assigned, then throw an error. Const version.

11550  {
11551  if (Time_pt == 0)
11552  {
11553  throw OomphLibError("Time object has not been set",
11556  }
11557  else
11558  {
11559  return Time_pt->time();
11560  }
11561  }

References OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::Time::time(), and Time_pt.

◆ time_adaptive_newton_crash_on_solve_fail()

bool& oomph::Problem::time_adaptive_newton_crash_on_solve_fail ( )
inline

Access function for Time_adaptive_newton_crash_on_solve_fail.

1615  {
1617  }

References Time_adaptive_newton_crash_on_solve_fail.

◆ time_pt() [1/2]

◆ time_pt() [2/2]

Time* oomph::Problem::time_pt ( ) const
inlinevirtual

Return a pointer to the global time object (const version).

Reimplemented from oomph::ExplicitTimeSteppableObject.

1511  {
1512  return Time_pt;
1513  }

References Time_pt.

◆ time_stepper_pt() [1/3]

TimeStepper*& oomph::Problem::time_stepper_pt ( )
inline

Access function for the pointer to the first (presumably only) timestepper

1525  {
1526  if (Time_stepper_pt.size() == 0)
1527  {
1528  throw OomphLibError("No timestepper allocated yet\n",
1531  }
1532  return Time_stepper_pt[0];
1533  }

References OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and Time_stepper_pt.

Referenced by adaptive_unsteady_newton_solve(), add_time_stepper_pt(), arc_length_step_solve(), arc_length_step_solve_helper(), calculate_predictions(), ConvectionProblem< NST_ELEMENT, AD_ELEMENT >::ConvectionProblem(), copy(), ElasticInterfaceProblem< ELEMENT, TIMESTEPPER >::ElasticInterfaceProblem(), FlowAroundCylinderProblem< ELEMENT >::FlowAroundCylinderProblem(), get_dvaluesdt(), HomogenisationProblem< ELEMENT >::HomogenisationProblem(), initialise_dt(), InterfaceProblem< ELEMENT, TIMESTEPPER >::InterfaceProblem(), LinearWaveProblem< ELEMENT, TIMESTEPPER >::LinearWaveProblem(), oomph::ODEProblem::my_set_initial_condition(), OscRingNStProblem< ELEMENT >::OscRingNStProblem(), RayleighProblem< ELEMENT, TIMESTEPPER >::RayleighProblem(), RefineableUnsteadyHeatProblem< ELEMENT >::RefineableUnsteadyHeatProblem(), set_timestepper_for_all_data(), solve_eigenproblem(), steady_newton_solve(), oomph::SegregatableFSIProblem::steady_segregated_solve(), SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >::SurfactantProblem(), TurekNonFSIProblem< ELEMENT >::TurekNonFSIProblem(), unsteady_newton_solve(), oomph::SegregatableFSIProblem::unsteady_segregated_solve(), UnsteadyHeatProblem< ELEMENT >::UnsteadyHeatProblem(), and oomph::WomersleyProblem< ELEMENT, DIM >::WomersleyProblem().

◆ time_stepper_pt() [2/3]

const TimeStepper* oomph::Problem::time_stepper_pt ( ) const
inline

Access function for the pointer to the first (presumably only) timestepper

1538  {
1539  if (Time_stepper_pt.size() == 0)
1540  {
1541  throw OomphLibError("No timestepper allocated yet\n",
1544  }
1545  return Time_stepper_pt[0];
1546  }

References OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and Time_stepper_pt.

◆ time_stepper_pt() [3/3]

TimeStepper*& oomph::Problem::time_stepper_pt ( const unsigned i)
inline

Return a pointer to the i-th timestepper.

1550  {
1551  return Time_stepper_pt[i];
1552  }

References i, and Time_stepper_pt.

◆ unrefine_uniformly() [1/2]

unsigned Problem::unrefine_uniformly ( )

Refine (all) refineable (sub)mesh(es) uniformly and rebuild problem. Return 0 for success, 1 for failure (if unrefinement has reached the coarsest permitted level)

Unrefine (all) refineable (sub)mesh(es) uniformly and rebuild problem. Return 0 for success, 1 for failure (if unrefinement has reached the coarsest permitted level)

15832  {
15833  // Call actions_before_adapt()
15835 
15836  // Has unrefinement been successful?
15837  unsigned success_flag = 0;
15838 
15839  // Number of submeshes?
15840  unsigned n_mesh = nsub_mesh();
15841 
15842  // Single mesh:
15843  if (n_mesh == 0)
15844  {
15845  // Unrefine single mesh uniformly if possible
15846  if (RefineableMeshBase* mmesh_pt =
15847  dynamic_cast<RefineableMeshBase*>(mesh_pt(0)))
15848  {
15849  success_flag += mmesh_pt->unrefine_uniformly();
15850  }
15851  else
15852  {
15853  oomph_info << "Info/Warning: Mesh cannot be unrefined uniformly "
15854  << std::endl;
15855  }
15856  }
15857  // Multiple submeshes
15858  else
15859  {
15860  // Loop over submeshes
15861  for (unsigned imesh = 0; imesh < n_mesh; imesh++)
15862  {
15863  // Unrefine i-th submesh uniformly if possible
15864  if (RefineableMeshBase* mmesh_pt =
15865  dynamic_cast<RefineableMeshBase*>(mesh_pt(imesh)))
15866  {
15867  success_flag += mmesh_pt->unrefine_uniformly();
15868  }
15869  else
15870  {
15871  oomph_info << "Info/Warning: Cannot unrefine mesh " << imesh
15872  << std::endl;
15873  }
15874  }
15875  // Rebuild the global mesh
15877  }
15878 
15879  // Any actions after the adaptation phase
15881 
15882  // Do equation numbering
15883  oomph_info << " Number of equations: " << assign_eqn_numbers() << std::endl;
15884 
15885  // Judge success
15886  if (success_flag > 0)
15887  {
15888  return 1;
15889  }
15890  else
15891  {
15892  return 0;
15893  }
15894  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), oomph::oomph_info, and rebuild_global_mesh().

Referenced by parallel_test().

◆ unrefine_uniformly() [2/2]

unsigned Problem::unrefine_uniformly ( const unsigned i_mesh)

Do uniform refinement for submesh i_mesh without documentation. Return 0 for success, 1 for failure (if unrefinement has reached the coarsest permitted level)

Unrefine submesh i_mesh uniformly and rebuild problem. Return 0 for success, 1 for failure (if unrefinement has reached the coarsest permitted level)

15903  {
15905 
15906  // Has unrefinement been successful?
15907  unsigned success_flag = 0;
15908 
15909 #ifdef PARANOID
15910  // Number of submeshes?
15911  if (i_mesh >= nsub_mesh())
15912  {
15913  std::ostringstream error_message;
15914  error_message << "imesh " << i_mesh
15915  << " is greater than the number of sub meshes "
15916  << nsub_mesh() << std::endl;
15917 
15918  throw OomphLibError(
15919  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15920  }
15921 #endif
15922 
15923  // Unrefine single mesh uniformly if possible
15924  if (RefineableMeshBase* mmesh_pt =
15925  dynamic_cast<RefineableMeshBase*>(mesh_pt(i_mesh)))
15926  {
15927  success_flag += mmesh_pt->unrefine_uniformly();
15928  }
15929  else
15930  {
15931  oomph_info << "Info/Warning: Mesh cannot be unrefined uniformly "
15932  << std::endl;
15933  }
15934 
15935  // Rebuild the global mesh
15937 
15938  // Any actions after the adaptation phase
15940 
15941  // Do equation numbering
15942  oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
15943 
15944  // Judge success
15945  if (success_flag > 0)
15946  {
15947  return 1;
15948  }
15949  else
15950  {
15951  return 0;
15952  }
15953  }

References actions_after_adapt(), actions_before_adapt(), assign_eqn_numbers(), mesh_pt(), nsub_mesh(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, and rebuild_global_mesh().

◆ unset_analytic_dparameter()

void oomph::Problem::unset_analytic_dparameter ( double *const &  parameter_pt)
inline

Function to turn off analytic calculation of the parameter derivatives in continuation and bifurcation detection problems

264  {
265  // Find the iterator to the parameter
266  std::map<double*, bool>::iterator it =
267  Calculate_dparameter_analytic.find(parameter_pt);
268  // If the parameter has been found, erase it
269  if (it != Calculate_dparameter_analytic.end())
270  {
272  }
273  }

References Calculate_dparameter_analytic.

◆ unset_analytic_hessian_products()

void oomph::Problem::unset_analytic_hessian_products ( )
inline

Function to turn off analytic calculation of the parameter derivatives in continuation and bifurcation detection problems

297  {
299  }

References Calculate_hessian_products_analytic.

◆ unsteady_newton_solve() [1/3]

void Problem::unsteady_newton_solve ( const double dt)

Advance time by dt and solve by Newton's method. This version always shifts time values

Do one timestep of size dt using Newton's method with the specified tolerance and linear solver defined as member data of the Problem class. This will be the most commonly used version of unsteady_newton_solve, in which the time values are always shifted This does not include any kind of adaptativity. If the solution fails to converge the program will end.

10954  {
10955  // We shift the values, so shift_values is true
10956  unsteady_newton_solve(dt, true);
10957  }

Referenced by doubly_adaptive_unsteady_newton_solve_helper(), FSIRingProblem::dynamic_run(), and unsteady_newton_solve().

◆ unsteady_newton_solve() [2/3]

void Problem::unsteady_newton_solve ( const double dt,
const bool shift_values 
)

Advance time by dt and solve the system, using Newton's method. The boolean flag is used to control whether the time values should be shifted. If it is true the current data values will be shifted (copied to the locations where there are stored as previous timesteps) before solution.

Do one timestep forward of size dt using Newton's method with the specified tolerance and linear solver defined via member data of the Problem class. The boolean flag shift_values is used to control whether the time values should be shifted or not.

10968  {
10969  // Shift the time values and the dts, according to the control flag
10970  if (shift_values)
10971  {
10973  }
10974 
10975  // Advance global time and set current value of dt
10976  time_pt()->time() += dt;
10977  time_pt()->dt() = dt;
10978 
10979  // Find out how many timesteppers there are
10980  unsigned n_time_steppers = ntime_stepper();
10981 
10982  // Loop over them all and set the weights
10983  for (unsigned i = 0; i < n_time_steppers; i++)
10984  {
10986  }
10987 
10988  // Run the individual timesteppers actions before timestep. These need to
10989  // be before the problem's actions_before_implicit_timestep so that the
10990  // boundary conditions are set consistently.
10991  for (unsigned i = 0; i < n_time_steppers; i++)
10992  {
10994  }
10995 
10996  // Now update anything that needs updating before the timestep
10997  // This could be time-dependent boundary conditions, for example.
10999 
11000  try
11001  {
11002  // Solve the non-linear problem for this timestep with Newton's method
11003  newton_solve();
11004  }
11005  // Catch any exceptions thrown in the Newton solver
11006  catch (NewtonSolverError& error)
11007  {
11008  oomph_info << std::endl
11009  << "USER-DEFINED ERROR IN NEWTON SOLVER " << std::endl;
11010  // Check whether it's the linear solver
11011  if (error.linear_solver_error)
11012  {
11013  oomph_info << "ERROR IN THE LINEAR SOLVER" << std::endl;
11014  }
11015  // Check to see whether we have reached Max_iterations
11016  else if (error.iterations == Max_newton_iterations)
11017  {
11018  oomph_info << "MAXIMUM NUMBER OF ITERATIONS (" << error.iterations
11019  << ") REACHED WITHOUT CONVERGENCE " << std::endl;
11020  }
11021  // If not, it must be that we have exceeded the maximum residuals
11022  else
11023  {
11024  oomph_info << "MAXIMUM RESIDUALS: " << error.maxres
11025  << " EXCEEDS PREDEFINED MAXIMUM " << Max_residuals
11026  << std::endl;
11027  }
11028  // Die horribly!!
11029  std::ostringstream error_stream;
11030  error_stream << "Error occured in unsteady Newton solver. " << std::endl;
11031  throw OomphLibError(
11032  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
11033  }
11034 
11035  // Run the individual timesteppers actions, these need to be before the
11036  // problem's actions_after_implicit_timestep so that the time step is
11037  // finished before the problem does any auxiliary calculations (e.g. in
11038  // semi-implicit micromagnetics the calculation of magnetostatic field).
11039  for (unsigned i = 0; i < n_time_steppers; i++)
11040  {
11042  }
11043 
11044 
11045  // Now update anything that needs updating after the timestep
11048  }

References actions_after_implicit_timestep(), actions_after_implicit_timestep_and_error_estimation(), oomph::TimeStepper::actions_after_timestep(), actions_before_implicit_timestep(), oomph::TimeStepper::actions_before_timestep(), oomph::Time::dt(), calibrate::error, i, Max_newton_iterations, Max_residuals, newton_solve(), ntime_stepper(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, oomph::TimeStepper::set_weights(), shift_time_values(), oomph::Time::time(), time_pt(), and time_stepper_pt().

◆ unsteady_newton_solve() [3/3]

void Problem::unsteady_newton_solve ( const double dt,
const unsigned max_adapt,
const bool first_timestep,
const bool shift = true 
)

Unsteady adaptive Newton solve: up to max_adapt adaptations of all refineable submeshes are performed to achieve the the error targets specified in the refineable submeshes. If first==true, the initial conditions are re-assigned after the mesh adaptations. Shifting of time can be suppressed by overwriting the default value of shift (true). [Shifting must be done if first_timestep==true because we're constantly re-assigning the initial conditions; if first_timestep==true and shift==false shifting is performed anyway and a warning is issued.

Do one timestep, dt, forward using Newton's method with specified tolerance and linear solver specified via member data. Keep adapting on all meshes to criteria specified in these meshes (up to max_adapt adaptations are performed). If first_timestep==true, re-set initial conditions after mesh adaptation. Shifting of time can be suppressed by overwriting the default value of shift (true). [Shifting must be done if first_timestep==true because we're constantly re-assigning the initial conditions; if first_timestep==true and shift==false shifting is performed anyway and a warning is issued.

16076  {
16077  // Do shifting or not?
16078  bool shift_it = shift;
16079 
16080  // Warning:
16081  if (first_timestep && (!shift) && (!Default_set_initial_condition_called))
16082  {
16083  shift_it = true;
16084  oomph_info
16085  << "\n\n===========================================================\n";
16086  oomph_info << " ******** WARNING *********** \n";
16087  oomph_info
16088  << "===========================================================\n";
16089  oomph_info << "Problem::unsteady_newton_solve() called with "
16090  << std::endl;
16091  oomph_info << "first_timestep: " << first_timestep << std::endl;
16092  oomph_info << "shift: " << shift << std::endl;
16093  oomph_info << "This doesn't make sense (shifting does have to be done"
16094  << std::endl;
16095  oomph_info << "since we're constantly re-assigning the initial conditions"
16096  << std::endl;
16097  oomph_info
16098  << "\n===========================================================\n\n";
16099  }
16100 
16101 
16102  // Find the initial time
16103  double initial_time = time_pt()->time();
16104 
16105  // Max number of solves
16106  unsigned max_solve = max_adapt + 1;
16107 
16108  // Adaptation loop
16109  //----------------
16110  for (unsigned isolve = 0; isolve < max_solve; isolve++)
16111  {
16112  // Only adapt after the first solve has been done!
16113  if (isolve > 0)
16114  {
16115  unsigned n_refined;
16116  unsigned n_unrefined;
16117 
16118  // Adapt problem
16119  adapt(n_refined, n_unrefined);
16120 
16121 #ifdef OOMPH_HAS_MPI
16122  // Adaptation only converges if ALL the processes have no
16123  // refinement or unrefinement to perform
16124  unsigned total_refined = 0;
16125  unsigned total_unrefined = 0;
16126  if (Problem_has_been_distributed)
16127  {
16128  MPI_Allreduce(&n_refined,
16129  &total_refined,
16130  1,
16131  MPI_UNSIGNED,
16132  MPI_SUM,
16133  this->communicator_pt()->mpi_comm());
16134  n_refined = total_refined;
16135  MPI_Allreduce(&n_unrefined,
16136  &total_unrefined,
16137  1,
16138  MPI_UNSIGNED,
16139  MPI_SUM,
16140  this->communicator_pt()->mpi_comm());
16141  n_unrefined = total_unrefined;
16142  }
16143 #endif
16144 
16145  oomph_info << "---> " << n_refined << " elements were refined, and "
16146  << n_unrefined << " were unrefined, in total." << std::endl;
16147 
16148  // Check convergence of adaptation cycle
16149  if ((n_refined == 0) && (n_unrefined == 0))
16150  {
16151  oomph_info << "\n \n Solution is fully converged in "
16152  << "Problem::unsteady_newton_solver() \n \n ";
16153  break;
16154  }
16155 
16156  // Reset the time
16157  time_pt()->time() = initial_time;
16158 
16159  // Reset the inital condition on refined meshes. Note that because we
16160  // have reset the global time to the initial time, the initial
16161  // conditions are reset at time t=0 rather than at time t=dt
16162  if (first_timestep)
16163  {
16164  // Reset default set_initial_condition has been called flag to false
16166 
16167  oomph_info << "Re-setting initial condition " << std::endl;
16169 
16170  // If the default set_initial_condition function has been called,
16171  // we must not shift the timevalues on the first timestep, as we
16172  // will NOT be constantly re-assigning the initial condition
16174  {
16175  shift_it = false;
16176  }
16177  }
16178  }
16179 
16180  // Now do the actual unsteady timestep
16181  // If it's the first time around the loop, or the first timestep
16182  // shift the timevalues, otherwise don't
16183  // Note: we need to shift if it's the first timestep because
16184  // we're constantly re-assigning the initial condition above!
16185  // The only exception to this is if the default set_initial_condition
16186  // function has been called, in which case we must NOT shift!
16187  if ((isolve == 0) || (first_timestep))
16188  {
16189  Problem::unsteady_newton_solve(dt, shift_it);
16190  }
16191  // Subsequent solve: Have shifted already -- don't do it again.
16192  else
16193  {
16194  shift_it = false;
16195  Problem::unsteady_newton_solve(dt, shift_it);
16196  }
16197 
16198  if (isolve == max_solve - 1)
16199  {
16200  oomph_info
16201  << std::endl
16202  << "----------------------------------------------------------"
16203  << std::endl
16204  << "Reached max. number of adaptations in \n"
16205  << "Problem::unsteady_newton_solver().\n"
16206  << "----------------------------------------------------------"
16207  << std::endl
16208  << std::endl;
16209  }
16210 
16211  } // End of adaptation loop
16212  }

References adapt(), communicator_pt(), Default_set_initial_condition_called, oomph::oomph_info, set_initial_condition(), oomph::Time::time(), time_pt(), and unsteady_newton_solve().

◆ use_predictor_values_as_initial_guess()

bool& oomph::Problem::use_predictor_values_as_initial_guess ( )
inline

Friends And Related Function Documentation

◆ AugmentedBlockFoldLinearSolver

◆ AugmentedBlockPitchForkLinearSolver

◆ BlockFoldLinearSolver

friend class BlockFoldLinearSolver
friend

◆ BlockHopfLinearSolver

friend class BlockHopfLinearSolver
friend

Referenced by activate_hopf_tracking().

◆ BlockPitchForkLinearSolver

friend class BlockPitchForkLinearSolver
friend

◆ FoldHandler

friend class FoldHandler
friend

◆ HopfHandler

friend class HopfHandler
friend

Referenced by activate_hopf_tracking().

◆ PeriodicOrbitAssemblyHandler

template<unsigned NNODE_1D>
friend class PeriodicOrbitAssemblyHandler
friend

◆ PitchForkHandler

friend class PitchForkHandler
friend

Member Data Documentation

◆ Always_take_one_newton_step

bool oomph::Problem::Always_take_one_newton_step
protected

Boolean to indicate whether a Newton step should be taken even if the initial residuals are below the required tolerance

Referenced by newton_solve(), and newton_solve_continuation().

◆ Arc_length_step_taken

bool oomph::Problem::Arc_length_step_taken
protected

Boolean to indicate whether an arc-length step has been taken.

Referenced by arc_length_step_solve(), arc_length_step_solve_helper(), and reset_arc_length_parameters().

◆ Assembly_handler_pt

◆ Bifurcation_detection

bool oomph::Problem::Bifurcation_detection
protected

Boolean to control bifurcation detection via determinant of Jacobian.

Referenced by arc_length_step_solve_helper().

◆ Bisect_to_find_bifurcation

bool oomph::Problem::Bisect_to_find_bifurcation
protected

Boolean to control wheter bisection is used to located bifurcation.

Referenced by arc_length_step_solve_helper().

◆ Calculate_dparameter_analytic

std::map<double*, bool> oomph::Problem::Calculate_dparameter_analytic
protected

Map used to determine whether the derivatives with respect to a parameter should be finite differenced. The default is that finite differences should be used

Referenced by is_dparameter_calculated_analytically(), set_analytic_dparameter(), and unset_analytic_dparameter().

◆ Calculate_hessian_products_analytic

bool oomph::Problem::Calculate_hessian_products_analytic
protected

Map used to determine whether the hessian products should be computed using finite differences. The default is that finite differences will be used

Referenced by are_hessian_products_calculated_analytically(), set_analytic_hessian_products(), and unset_analytic_hessian_products().

◆ Communicator_pt

◆ Continuation_direction

double oomph::Problem::Continuation_direction
protected

The direction of the change in parameter that will ensure that a branch is followed in one direction only

Referenced by calculate_continuation_derivatives_helper(), and reset_arc_length_parameters().

◆ Continuation_time_stepper

ContinuationStorageScheme Problem::Continuation_time_stepper
staticprotected

Storage for the single static continuation timestorage object.

The continuation timestepper object.

Referenced by arc_length_step_solve(), and set_consistent_pinned_values_for_continuation().

◆ Copy_of_problem_pt

Vector<Problem*> oomph::Problem::Copy_of_problem_pt
protected

Vector of pointers to copies of the problem used in adaptive bifurcation tracking problems (ALH: TEMPORARY HACK, WILL BE FIXED)

Referenced by adapt(), bifurcation_adapt_helper(), and ~Problem().

◆ Default_assembly_handler_pt

AssemblyHandler* oomph::Problem::Default_assembly_handler_pt
private

Pointer to the default assembly handler.

Referenced by get_inverse_mass_matrix_times_residuals(), Problem(), reset_assembly_handler_to_default(), and ~Problem().

◆ Default_eigen_solver_pt

EigenSolver* oomph::Problem::Default_eigen_solver_pt
private

Pointer to the default eigensolver.

Referenced by Problem(), and ~Problem().

◆ Default_linear_solver_pt

LinearSolver* oomph::Problem::Default_linear_solver_pt
private

Pointer to the default linear solver.

Referenced by Problem(), and ~Problem().

◆ Default_set_initial_condition_called

bool oomph::Problem::Default_set_initial_condition_called
private

Has default set_initial_condition function been called? Default: false

Referenced by doubly_adaptive_unsteady_newton_solve_helper(), set_initial_condition(), and unsteady_newton_solve().

◆ Desired_newton_iterations_ds

unsigned oomph::Problem::Desired_newton_iterations_ds
protected

The desired number of Newton Steps to reach convergence at each step along the arc

Referenced by arc_length_step_solve_helper().

◆ Desired_proportion_of_arc_length

double oomph::Problem::Desired_proportion_of_arc_length
protected

Proportion of the arc-length to taken by the parameter.

Referenced by calculate_continuation_derivatives(), and calculate_continuation_derivatives_fd().

◆ Discontinuous_element_formulation

bool oomph::Problem::Discontinuous_element_formulation
protected

Is the problem a discontinuous one, i.e. can the elemental contributions be treated independently. Default: false

Referenced by disable_discontinuous_formulation(), disable_mass_matrix_reuse(), enable_discontinuous_formulation(), enable_mass_matrix_reuse(), and get_inverse_mass_matrix_times_residuals().

◆ Doc_time_in_distribute

bool oomph::Problem::Doc_time_in_distribute
protected

Protected boolean flag to provide comprehensive timimings during problem distribution. Initialised to false.

◆ Dof_current

Vector<double> oomph::Problem::Dof_current
protected

Storage for the present values of the variables.

Referenced by adapt(), arc_length_step_solve_helper(), calculate_continuation_derivatives_fd_helper(), and dof_current().

◆ Dof_current_offset

unsigned oomph::Problem::Dof_current_offset
protected

Storage for the offset for the current values of dofs from the original dofs (default is 2, but this will be differnet when continuing bifurcations and periodic orbits)

Referenced by dof_current().

◆ Dof_derivative

Vector<double> oomph::Problem::Dof_derivative
protected

Storage for the derivative of the problem variables wrt arc-length.

Referenced by adapt(), arc_length_step_solve_helper(), calculate_continuation_derivatives_helper(), dof_derivative(), and reset_arc_length_parameters().

◆ Dof_derivative_offset

unsigned oomph::Problem::Dof_derivative_offset
protected

Storage for the offset for the continuation derivatives from the original dofs (default is 1, but this will be differnet when continuing bifurcations and periodic orbits)

Referenced by dof_derivative().

◆ Dof_distribution_pt

LinearAlgebraDistribution* oomph::Problem::Dof_distribution_pt
protected

The distribution of the DOFs in this problem. This object is created in the Problem constructor and setup when assign_eqn_numbers(...) is called. If this problem is distributed then this distribution will match the distribution of the equation numbers. If this problem is not distributed then this distribution will be uniform over all processors.

Referenced by adapt(), oomph::PeriodicOrbitAssemblyHandler< NNODE_1D >::adapt_temporal_mesh(), arc_length_step_solve_helper(), assign_eqn_numbers(), calculate_continuation_derivatives_fd_helper(), calculate_continuation_derivatives_helper(), dof_distribution_pt(), oomph::FoldHandler::FoldHandler(), get_dofs(), get_eigenproblem_matrices(), get_hessian_vector_products(), get_jacobian(), get_residuals(), oomph::HopfHandler::HopfHandler(), ndof(), newton_solve(), newton_solve_continuation(), oomph::PitchForkHandler::PitchForkHandler(), Problem(), restore_dof_values(), setup_element_count_per_dof(), oomph::FoldHandler::solve_augmented_block_system(), oomph::PitchForkHandler::solve_augmented_block_system(), oomph::FoldHandler::solve_block_system(), oomph::PitchForkHandler::solve_block_system(), oomph::HopfHandler::solve_complex_system(), oomph::FoldHandler::solve_full_system(), oomph::PitchForkHandler::solve_full_system(), oomph::HopfHandler::solve_full_system(), oomph::HopfHandler::solve_standard_system(), store_current_dof_values(), oomph::FoldHandler::~FoldHandler(), oomph::HopfHandler::~HopfHandler(), oomph::PitchForkHandler::~PitchForkHandler(), and ~Problem().

◆ Dof_pt

◆ Ds_current

double oomph::Problem::Ds_current
protected

◆ DTSF_max_increase

double oomph::Problem::DTSF_max_increase
protected

Maximum possible increase of dt between time-steps in adaptive schemes

Referenced by adaptive_unsteady_newton_solve().

◆ DTSF_min_decrease

double oomph::Problem::DTSF_min_decrease
protected

Minimum allowed decrease of dt between time-steps in adaptive schemes. Lower scaling values will reject the time-step (and retry with a smaller dt).

Referenced by adaptive_unsteady_newton_solve().

◆ Eigen_solver_pt

EigenSolver* oomph::Problem::Eigen_solver_pt
private

Pointer to the eigen solver for the problem.

Referenced by eigen_solver_pt(), Problem(), and solve_eigenproblem().

◆ Element_count_per_dof

DoubleVectorWithHaloEntries oomph::Problem::Element_count_per_dof
protected

Counter that records how many elements contribute to each dof. Used to determine the (discrete) arc-length automatically. It really should be an integer, but is a double so that the distribution information can be used for distributed problems

Referenced by setup_element_count_per_dof().

◆ Empty_actions_after_read_unstructured_meshes_has_been_called

bool oomph::Problem::Empty_actions_after_read_unstructured_meshes_has_been_called
private

Boolean to indicate that empty actions_after_read_unstructured_meshes() function has been called.

Referenced by actions_after_read_unstructured_meshes(), and read().

◆ Empty_actions_before_read_unstructured_meshes_has_been_called

bool oomph::Problem::Empty_actions_before_read_unstructured_meshes_has_been_called
private

Boolean to indicate that empty actions_before_read_unstructured_meshes() function has been called.

Referenced by actions_before_read_unstructured_meshes(), and read().

◆ Explicit_time_stepper_pt

ExplicitTimeStepper* oomph::Problem::Explicit_time_stepper_pt
private

Pointer to a single explicit timestepper.

Referenced by explicit_time_stepper_pt(), and set_explicit_time_stepper_pt().

◆ FD_step_used_in_get_hessian_vector_products

double oomph::Problem::FD_step_used_in_get_hessian_vector_products
protected

◆ First_jacobian_sign_change

bool oomph::Problem::First_jacobian_sign_change
protected

Boolean to indicate whether a sign change has occured in the Jacobian.

Referenced by arc_length_step_solve_helper(), and reset_arc_length_parameters().

◆ Global_data_pt

Vector<Data*> oomph::Problem::Global_data_pt
private

Vector of global data: "Nobody" (i.e. none of the elements etc.) is "in charge" of this Data so it would be overlooked when it comes to equation-numbering, timestepping etc. Including (pointers) to such Data in here, puts the Problem itself "in charge" of these tasks.

Referenced by add_global_data(), assign_eqn_numbers(), assign_initial_values_impulsive(), calculate_predictions(), copy(), describe_dofs(), does_pointer_correspond_to_problem_data(), dump(), flush_global_data(), get_dofs(), global_data_pt(), nglobal_data(), read(), self_test(), set_consistent_pinned_values_for_continuation(), set_dofs(), set_pinned_values_to_zero(), set_timestepper_for_all_data(), and shift_time_values().

◆ Jacobian_has_been_computed

bool oomph::Problem::Jacobian_has_been_computed
protected

Has a Jacobian been computed (and can therefore be re-used if required)? Default: false

Referenced by disable_jacobian_reuse(), enable_jacobian_reuse(), and newton_solve().

◆ Jacobian_reuse_is_enabled

bool oomph::Problem::Jacobian_reuse_is_enabled
protected

Is re-use of Jacobian in Newton iteration enabled? Default: false.

Referenced by disable_jacobian_reuse(), enable_jacobian_reuse(), jacobian_reuse_is_enabled(), and newton_solve().

◆ Keep_temporal_error_below_tolerance

bool oomph::Problem::Keep_temporal_error_below_tolerance
protected

Boolean to decide if a timestep is to be rejected if the error estimate post-solve (computed by global_temporal_error_norm()) exceeds the tolerance required in the call to adaptive_unsteady_newton_solve(...). Defaults to true.

Referenced by adaptive_unsteady_newton_solve(), and SurfactantProblem< ELEMENT, INTERFACE_ELEMENT >::SurfactantProblem().

◆ Linear_solver_pt

◆ Mass_matrix_has_been_computed

bool oomph::Problem::Mass_matrix_has_been_computed
protected

Has the mass matrix been computed (and can therefore be reused) Default: false

Referenced by disable_mass_matrix_reuse(), enable_mass_matrix_reuse(), and get_inverse_mass_matrix_times_residuals().

◆ Mass_matrix_reuse_is_enabled

bool oomph::Problem::Mass_matrix_reuse_is_enabled
protected

Is re-use of the mass matrix in explicit timestepping enabled Default:false

Referenced by disable_mass_matrix_reuse(), enable_mass_matrix_reuse(), get_inverse_mass_matrix_times_residuals(), and mass_matrix_reuse_is_enabled().

◆ Mass_matrix_solver_for_explicit_timestepper_pt

LinearSolver* oomph::Problem::Mass_matrix_solver_for_explicit_timestepper_pt
private

Pointer to the linear solver used for explicit time steps (this is likely to be different to the linear solver for newton solves because explicit time steps only involve inverting a mass matrix. This can be done very efficiently by, e.g. CG with a diagonal predconditioner).

Referenced by mass_matrix_solver_for_explicit_timestepper_pt(), and Problem().

◆ Max_newton_iterations

◆ Max_res

Vector<double> oomph::Problem::Max_res
protected

Maximum residuals at start and after each newton iteration.

Referenced by newton_solve().

◆ Max_residuals

◆ Maximum_dt

double oomph::Problem::Maximum_dt
protected

Maximum desired dt.

Referenced by adaptive_unsteady_newton_solve(), and maximum_dt().

◆ Mesh_pt

◆ Minimum_ds

double oomph::Problem::Minimum_ds
protected

Minimum desired value of arc-length.

Referenced by arc_length_step_solve_helper(), and OrrSommerfeldProblem< ELEMENT >::OrrSommerfeldProblem().

◆ Minimum_dt

double oomph::Problem::Minimum_dt
protected

Minimum desired dt: if dt falls below this value, exit.

Referenced by adaptive_unsteady_newton_solve(), and minimum_dt().

◆ Minimum_dt_but_still_proceed

double oomph::Problem::Minimum_dt_but_still_proceed
protected

If Minimum_dt_but_still_proceed positive, then dt will not be reduced below this value during adaptive timestepping and the computation will continue with this value, accepting the larger errors that this will incur). Note: This option is disabled by default as this value is initialised to -1.0.

Referenced by adaptive_unsteady_newton_solve().

◆ Newton_solver_tolerance

◆ Nnewton_iter_taken

unsigned oomph::Problem::Nnewton_iter_taken
protected

Actual number of Newton iterations taken during the most recent iteration

Referenced by newton_solve().

◆ Numerical_zero_for_sparse_assembly

double oomph::Problem::Numerical_zero_for_sparse_assembly
protected

◆ Parameter_current

double oomph::Problem::Parameter_current
protected

Storage for the present value of the global parameter.

Referenced by arc_length_step_solve_helper(), calculate_continuation_derivatives_fd_helper(), and newton_solve_continuation().

◆ Parameter_derivative

◆ Pause_at_end_of_sparse_assembly

bool oomph::Problem::Pause_at_end_of_sparse_assembly
protected

◆ Problem_is_nonlinear

bool oomph::Problem::Problem_is_nonlinear
protected

Boolean flag indicating if we're dealing with a linear or nonlinear Problem – if set to false the Newton solver will not check the residual before or after the linear solve. Set to true by default; can be over-written in specific Problem class.

Referenced by AxiPoroProblem< ELEMENT, TIMESTEPPER >::AxiPoroProblem(), BiharmonicTestProblem1::BiharmonicTestProblem1(), BiharmonicTestProblem2::BiharmonicTestProblem2(), newton_solve(), problem_is_nonlinear(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::project(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::ProjectionProblem(), and oomph::WomersleyProblem< ELEMENT, DIM >::WomersleyProblem().

◆ Relaxation_factor

double oomph::Problem::Relaxation_factor
protected

Relaxation fator for Newton method (only a fractional Newton correction is applied if this is less than 1; default 1).

Referenced by newton_solve().

◆ Saved_dof_pt

Vector<double>* oomph::Problem::Saved_dof_pt
private

Pointer to vector for backup of dofs.

Referenced by restore_dof_values(), and store_current_dof_values().

◆ Scale_arc_length

bool oomph::Problem::Scale_arc_length
protected

Boolean to control whether arc-length should be scaled.

Referenced by calculate_continuation_derivatives(), and calculate_continuation_derivatives_fd().

◆ Shut_up_in_newton_solve

bool oomph::Problem::Shut_up_in_newton_solve

◆ Sign_of_jacobian

int oomph::Problem::Sign_of_jacobian
protected

Storage for the sign of the global Jacobian.

Referenced by arc_length_step_solve_helper(), reset_arc_length_parameters(), and sign_of_jacobian().

◆ Sparse_assemble_with_arrays_allocation_increment

unsigned oomph::Problem::Sparse_assemble_with_arrays_allocation_increment
protected

the number of elements to add to a matrix row when the initial allocation is exceeded within the sparse_assemble_with_two_arrays(...) method.

Referenced by sparse_assemble_row_or_column_compressed_with_two_arrays().

◆ Sparse_assemble_with_arrays_initial_allocation

unsigned oomph::Problem::Sparse_assemble_with_arrays_initial_allocation
protected

the number of elements to initially allocate for a matrix row within the sparse_assembly_with_two_arrays(...) method (if a matrix of this size has not been assembled already). If a matrix of this size has been assembled then the number of elements in each row in that matrix is used as the initial allocation

Referenced by sparse_assemble_row_or_column_compressed_with_two_arrays().

◆ Sparse_assemble_with_arrays_previous_allocation

◆ Sparse_assembly_method

unsigned oomph::Problem::Sparse_assembly_method
protected

Flag to determine which sparse assembly method to use By default we use assembly by vectors of pairs.

Referenced by sparse_assemble_row_or_column_compressed().

◆ Store_local_dof_pt_in_elements

bool oomph::Problem::Store_local_dof_pt_in_elements
private

Boolean to indicate whether local dof pointers should be stored in the elements

Referenced by assign_eqn_numbers(), disable_store_local_dof_pt_in_elements(), and enable_store_local_dof_pt_in_elements().

◆ Sub_mesh_pt

◆ Suppress_warning_about_actions_before_read_unstructured_meshes

bool Problem::Suppress_warning_about_actions_before_read_unstructured_meshes
static
Initial value:
=
false

Flag to allow suppression of warning messages re reading in unstructured meshes during restart.

Instantiation of public flag to allow suppression of warning messages re reading in unstructured meshes during restart.

Referenced by read().

◆ Theta_squared

double oomph::Problem::Theta_squared
protected

Value of the scaling parameter required so that the parameter occupies the desired proportion of the arc length. NOTE: If you wish to change this then make sure to set the value of Scale_arc_length to false to ensure the value of this isn't overwritten during the arc-length process. Instead of changing this variable, it's better to actually update the Desired_proportion_of_arc_length value.

Referenced by calculate_continuation_derivatives(), calculate_continuation_derivatives_fd(), calculate_continuation_derivatives_fd_helper(), calculate_continuation_derivatives_helper(), newton_solve_continuation(), and reset_arc_length_parameters().

◆ Time_adaptive_newton_crash_on_solve_fail

bool oomph::Problem::Time_adaptive_newton_crash_on_solve_fail
protected

Bool to specify what to do if a Newton solve fails within a time adaptive solve. Default (false) is to half the step and try again. If true then crash instead.

Referenced by adaptive_unsteady_newton_solve(), and time_adaptive_newton_crash_on_solve_fail().

◆ Time_pt

Time* oomph::Problem::Time_pt
private

◆ Time_stepper_pt

Vector<TimeStepper*> oomph::Problem::Time_stepper_pt
private

The Vector of time steppers (there could be many different ones in multiphysics problems)

Referenced by add_time_stepper_pt(), calculate_predictions(), ntime_stepper(), Problem(), and time_stepper_pt().

◆ Timestep_reduction_factor_after_nonconvergence

double oomph::Problem::Timestep_reduction_factor_after_nonconvergence
protected

What it says: If temporally adaptive Newton solver fails to to converge, reduce timestep by this factor and try again; defaults to 1/2; can be over-written by user in derived problem.

Referenced by adaptive_unsteady_newton_solve().

◆ Use_continuation_timestepper

bool oomph::Problem::Use_continuation_timestepper
protected

Boolean to control original or new storage of dof stuff.

Referenced by adapt(), arc_length_step_solve(), arc_length_step_solve_helper(), calculate_continuation_derivatives_helper(), dof_current(), and dof_derivative().

◆ Use_finite_differences_for_continuation_derivatives

bool oomph::Problem::Use_finite_differences_for_continuation_derivatives
protected

Boolean to specify which scheme to use to calculate the continuation derivatievs

Referenced by arc_length_step_solve_helper().

◆ Use_globally_convergent_newton_method

bool oomph::Problem::Use_globally_convergent_newton_method
private

Use the globally convergent newton method.

Referenced by disable_globally_convergent_newton_method(), enable_globally_convergent_newton_method(), and newton_solve().

◆ Use_predictor_values_as_initial_guess

bool oomph::Problem::Use_predictor_values_as_initial_guess
private

Use values from the time stepper predictor as an initial guess.

Referenced by Problem(), and use_predictor_values_as_initial_guess().


The documentation for this class was generated from the following files: