oomph::FoldHandler Class Reference

#include <assembly_handler.h>

+ Inheritance diagram for oomph::FoldHandler:

Public Member Functions

 FoldHandler (Problem *const &problem_pt, double *const &parameter_pt)
 
 FoldHandler (Problem *const &problem_pt, double *const &parameter_pt, const DoubleVector &eigenvector)
 Constructor in which initial eigenvector can be passed. More...
 
 FoldHandler (Problem *const &problem_pt, double *const &parameter_pt, const DoubleVector &eigenvector, const DoubleVector &normalisation)
 
 ~FoldHandler ()
 Destructor return the problem to its original (non-augmented) state. More...
 
unsigned ndof (GeneralisedElement *const &elem_pt)
 Get the number of elemental degrees of freedom. More...
 
unsigned long eqn_number (GeneralisedElement *const &elem_pt, const unsigned &ieqn_local)
 Get the global equation number of the local unknown. More...
 
void get_residuals (GeneralisedElement *const &elem_pt, Vector< double > &residuals)
 Get the residuals. More...
 
void get_jacobian (GeneralisedElement *const &elem_pt, Vector< double > &residuals, DenseMatrix< double > &jacobian)
 
void get_dresiduals_dparameter (GeneralisedElement *const &elem_pt, double *const &parameter_pt, Vector< double > &dres_dparam)
 
void get_djacobian_dparameter (GeneralisedElement *const &elem_pt, double *const &parameter_pt, Vector< double > &dres_dparam, DenseMatrix< double > &djac_dparam)
 
void get_hessian_vector_products (GeneralisedElement *const &elem_pt, Vector< double > const &Y, DenseMatrix< double > const &C, DenseMatrix< double > &product)
 
int bifurcation_type () const
 Indicate that we are tracking a fold bifurcation by returning 1. More...
 
doublebifurcation_parameter_pt () const
 
void get_eigenfunction (Vector< DoubleVector > &eigenfunction)
 
void solve_augmented_block_system ()
 Set to solve the augmented block system. More...
 
void solve_block_system ()
 Set to solve the block system. More...
 
void solve_full_system ()
 Solve non-block system. More...
 
- Public Member Functions inherited from oomph::AssemblyHandler
 AssemblyHandler ()
 Empty constructor. More...
 
virtual void dof_vector (GeneralisedElement *const &elem_pt, const unsigned &t, Vector< double > &dof)
 Return vector of dofs at time level t in the element elem_pt. More...
 
virtual void dof_pt_vector (GeneralisedElement *const &elem_pt, Vector< double * > &dof_pt)
 Return vector of pointers to dofs in the element elem_pt. More...
 
virtual doublelocal_problem_dof (Problem *const &problem_pt, const unsigned &t, const unsigned &i)
 
virtual void get_all_vectors_and_matrices (GeneralisedElement *const &elem_pt, Vector< Vector< double >> &vec, Vector< DenseMatrix< double >> &matrix)
 
virtual void get_inner_products (GeneralisedElement *const &elem_pt, Vector< std::pair< unsigned, unsigned >> const &history_index, Vector< double > &inner_product)
 
virtual void get_inner_product_vectors (GeneralisedElement *const &elem_pt, Vector< unsigned > const &history_index, Vector< Vector< double >> &inner_product_vector)
 
virtual ~AssemblyHandler ()
 Empty virtual destructor. More...
 

Private Types

enum  { Full_augmented , Block_J , Block_augmented_J }
 

Private Attributes

unsigned Solve_which_system
 
ProblemProblem_pt
 Pointer to the problem. More...
 
unsigned Ndof
 
Vector< doublePhi
 
Vector< doubleY
 Storage for the null vector. More...
 
Vector< intCount
 
doubleParameter_pt
 Storage for the pointer to the parameter. More...
 

Friends

class AugmentedBlockFoldLinearSolver
 

Detailed Description

A class that is used to assemble the augmented system that defines a fold (saddle-node) or limit point. The "standard" problem must be a function of a global paramter \(\lambda\), and a solution is \(R(u,\lambda) = 0 \) , where \( u \) are the unknowns in the problem. A limit point is formally specified by the augmented system of size \( 2N+1 \)

\[ R(u,\lambda) = 0, \]

\[ Jy = 0, \]

\[\phi\cdot y = 1. \]

In the above \( J \) is the usual Jacobian matrix, \( dR/du \), and \( \phi \) is a constant vector that is chosen to ensure that the null vector, \( y \), is not trivial.

Member Enumeration Documentation

◆ anonymous enum

anonymous enum
private

A little private enum to determine whether we are solving the block system or not

Enumerator
Full_augmented 
Block_J 
Block_augmented_J 
479  {
481  Block_J,
483  };
@ Block_J
Definition: assembly_handler.h:481
@ Full_augmented
Definition: assembly_handler.h:480
@ Block_augmented_J
Definition: assembly_handler.h:482

Constructor & Destructor Documentation

◆ FoldHandler() [1/3]

oomph::FoldHandler::FoldHandler ( Problem *const &  problem_pt,
double *const &  parameter_pt 
)

Constructor: initialise the fold handler, by setting initial guesses for Y, Phi and calculating count. If the system changes, a new fold handler must be constructed

Constructor: Initialise the fold handler, by setting initial guesses for Y, Phi and calculating Count. If the system changes, a new handler must be constructed.

867  {
868  // Set the problem pointer
869  Problem_pt = problem_pt;
870  // Set the number of degrees of freedom
871  Ndof = problem_pt->ndof();
872 
873  // create the linear algebra distribution for this solver
874  // currently only global (non-distributed) distributions are allowed
875  LinearAlgebraDistribution* dist_pt =
876  new LinearAlgebraDistribution(problem_pt->communicator_pt(), Ndof, false);
877 
878  // Resize the vectors of additional dofs and constants
879  Phi.resize(Ndof);
880  Y.resize(Ndof);
881  Count.resize(Ndof, 0);
882 
883  // Loop over all the elements in the problem
884  unsigned n_element = problem_pt->mesh_pt()->nelement();
885  for (unsigned e = 0; e < n_element; e++)
886  {
887  GeneralisedElement* elem_pt = problem_pt->mesh_pt()->element_pt(e);
888  // Loop over the local freedoms in the element
889  unsigned n_var = elem_pt->ndof();
890  for (unsigned n = 0; n < n_var; n++)
891  {
892  // Increase the associated global equation number counter
893  ++Count[elem_pt->eqn_number(n)];
894  }
895  }
896 
897  // Calculate the value Phi by
898  // solving the system JPhi = dF/dlambda
899 
900  // Locally cache the linear solver
901  LinearSolver* const linear_solver_pt = problem_pt->linear_solver_pt();
902 
903  // Save the status before entry to this routine
904  bool enable_resolve = linear_solver_pt->is_resolve_enabled();
905 
906  // We need to do a resolve
907  linear_solver_pt->enable_resolve();
908 
909  // Storage for the solution
910  DoubleVector x(dist_pt, 0.0);
911 
912  // Solve the standard problem, we only want to make sure that
913  // we factorise the matrix, if it has not been factorised. We shall
914  // ignore the return value of x.
915  linear_solver_pt->solve(problem_pt, x);
916 
917  // Get the vector dresiduals/dparameter
918  problem_pt->get_derivative_wrt_global_parameter(parameter_pt, x);
919 
920  // Copy rhs vector into local storage so it doesn't get overwritten
921  // if the linear solver decides to initialise the solution vector, say,
922  // which it's quite entitled to do!
923  DoubleVector input_x(x);
924 
925  // Now resolve the system with the new RHS and overwrite the solution
926  linear_solver_pt->resolve(input_x, x);
927 
928  // Restore the storage status of the linear solver
929  if (enable_resolve)
930  {
931  linear_solver_pt->enable_resolve();
932  }
933  else
934  {
935  linear_solver_pt->disable_resolve();
936  }
937 
938  // Add the global parameter as an unknown to the problem
939  problem_pt->Dof_pt.push_back(parameter_pt);
940 
941 
942  // Normalise the initial guesses for phi
943  double length = 0.0;
944  for (unsigned n = 0; n < Ndof; n++)
945  {
946  length += x[n] * x[n];
947  }
948  length = sqrt(length);
949 
950  // Now add the null space components to the problem unknowns
951  // and initialise them and Phi to the same normalised values
952  for (unsigned n = 0; n < Ndof; n++)
953  {
954  problem_pt->Dof_pt.push_back(&Y[n]);
955  Y[n] = Phi[n] = -x[n] / length;
956  }
957 
958  // delete the dist_pt
959  problem_pt->Dof_distribution_pt->build(
960  problem_pt->communicator_pt(), Ndof * 2 + 1, true);
961  // Remove all previous sparse storage used during Jacobian assembly
963 
964  delete dist_pt;
965  }
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
std::vector< double > DoubleVector
loads clump configuration
Definition: ClumpInput.h:26
Array< double, 1, 3 > e(1./3., 0.5, 2.)
Problem * Problem_pt
Pointer to the problem.
Definition: assembly_handler.h:493
Vector< int > Count
Definition: assembly_handler.h:509
unsigned Solve_which_system
Definition: assembly_handler.h:490
Vector< double > Phi
Definition: assembly_handler.h:501
unsigned Ndof
Definition: assembly_handler.h:497
Vector< double > Y
Storage for the null vector.
Definition: assembly_handler.h:504
double * Parameter_pt
Storage for the pointer to the parameter.
Definition: assembly_handler.h:512
Vector< Vector< unsigned > > Sparse_assemble_with_arrays_previous_allocation
Definition: problem.h:667
list x
Definition: plotDoE.py:28

References oomph::LinearAlgebraDistribution::build(), oomph::Problem::communicator_pt(), Count, oomph::LinearSolver::disable_resolve(), oomph::Problem::Dof_distribution_pt, oomph::Problem::Dof_pt, e(), oomph::Mesh::element_pt(), oomph::LinearSolver::enable_resolve(), oomph::GeneralisedElement::eqn_number(), oomph::Problem::get_derivative_wrt_global_parameter(), oomph::LinearSolver::is_resolve_enabled(), oomph::Problem::linear_solver_pt(), oomph::Problem::mesh_pt(), n, Ndof, oomph::GeneralisedElement::ndof(), oomph::Problem::ndof(), oomph::Mesh::nelement(), Phi, Problem_pt, oomph::LinearSolver::resolve(), oomph::LinearSolver::solve(), oomph::Problem::Sparse_assemble_with_arrays_previous_allocation, sqrt(), plotDoE::x, and Y.

◆ FoldHandler() [2/3]

oomph::FoldHandler::FoldHandler ( Problem *const &  problem_pt,
double *const &  parameter_pt,
const DoubleVector eigenvector 
)

Constructor in which initial eigenvector can be passed.

Constructor in which the eigenvector is passed as an initial guess

974  {
975  // Set the problem pointer
976  Problem_pt = problem_pt;
977  // Set the number of degrees of freedom
978  Ndof = problem_pt->ndof();
979 
980  // create the linear algebra distribution for this solver
981  // currently only global (non-distributed) distributions are allowed
982  LinearAlgebraDistribution* dist_pt =
983  new LinearAlgebraDistribution(problem_pt->communicator_pt(), Ndof, false);
984 
985  // Resize the vectors of additional dofs and constants
986  Phi.resize(Ndof);
987  Y.resize(Ndof);
988  Count.resize(Ndof, 0);
989 
990  // Loop over all the elements in the problem
991  unsigned n_element = problem_pt->mesh_pt()->nelement();
992  for (unsigned e = 0; e < n_element; e++)
993  {
994  GeneralisedElement* elem_pt = problem_pt->mesh_pt()->element_pt(e);
995  // Loop over the local freedoms in the element
996  unsigned n_var = elem_pt->ndof();
997  for (unsigned n = 0; n < n_var; n++)
998  {
999  // Increase the associated global equation number counter
1000  ++Count[elem_pt->eqn_number(n)];
1001  }
1002  }
1003 
1004  // Add the global parameter as an unknown to the problem
1005  problem_pt->Dof_pt.push_back(parameter_pt);
1006 
1007 
1008  // Normalise the initial guesses for the eigenvecor
1009  double length = 0.0;
1010  for (unsigned n = 0; n < Ndof; n++)
1011  {
1012  length += eigenvector[n] * eigenvector[n];
1013  }
1014  length = sqrt(length);
1015 
1016  // Now add the null space components to the problem unknowns
1017  // and initialise them and Phi to the same normalised values
1018  for (unsigned n = 0; n < Ndof; n++)
1019  {
1020  problem_pt->Dof_pt.push_back(&Y[n]);
1021  Y[n] = Phi[n] = eigenvector[n] / length;
1022  }
1023 
1024  // delete the dist_pt
1025  problem_pt->Dof_distribution_pt->build(
1026  problem_pt->communicator_pt(), Ndof * 2 + 1, true);
1027  // Remove all previous sparse storage used during Jacobian assembly
1029 
1030  delete dist_pt;
1031  }

References oomph::LinearAlgebraDistribution::build(), oomph::Problem::communicator_pt(), Count, oomph::Problem::Dof_distribution_pt, oomph::Problem::Dof_pt, e(), oomph::Mesh::element_pt(), oomph::GeneralisedElement::eqn_number(), oomph::Problem::mesh_pt(), n, Ndof, oomph::GeneralisedElement::ndof(), oomph::Problem::ndof(), oomph::Mesh::nelement(), Phi, Problem_pt, oomph::Problem::Sparse_assemble_with_arrays_previous_allocation, sqrt(), and Y.

◆ FoldHandler() [3/3]

oomph::FoldHandler::FoldHandler ( Problem *const &  problem_pt,
double *const &  parameter_pt,
const DoubleVector eigenvector,
const DoubleVector normalisation 
)

Constructor in which initial eigenvector and normalisation can be passed

Constructor in which the eigenvector and normalisation vector are passed as an initial guess

1041  {
1042  // Set the problem pointer
1043  Problem_pt = problem_pt;
1044  // Set the number of degrees of freedom
1045  Ndof = problem_pt->ndof();
1046 
1047  // create the linear algebra distribution for this solver
1048  // currently only global (non-distributed) distributions are allowed
1049  LinearAlgebraDistribution* dist_pt =
1050  new LinearAlgebraDistribution(problem_pt->communicator_pt(), Ndof, false);
1051 
1052  // Resize the vectors of additional dofs and constants
1053  Phi.resize(Ndof);
1054  Y.resize(Ndof);
1055  Count.resize(Ndof, 0);
1056 
1057  // Loop over all the elements in the problem
1058  unsigned n_element = problem_pt->mesh_pt()->nelement();
1059  for (unsigned e = 0; e < n_element; e++)
1060  {
1061  GeneralisedElement* elem_pt = problem_pt->mesh_pt()->element_pt(e);
1062  // Loop over the local freedoms in the element
1063  unsigned n_var = elem_pt->ndof();
1064  for (unsigned n = 0; n < n_var; n++)
1065  {
1066  // Increase the associated global equation number counter
1067  ++Count[elem_pt->eqn_number(n)];
1068  }
1069  }
1070 
1071  // Add the global parameter as an unknown to the problem
1072  problem_pt->Dof_pt.push_back(parameter_pt);
1073 
1074 
1075  // Normalise the initial guesses for the eigenvecor
1076  double length = 0.0;
1077  for (unsigned n = 0; n < Ndof; n++)
1078  {
1079  length += eigenvector[n] * normalisation[n];
1080  }
1081  length = sqrt(length);
1082 
1083  // Now add the null space components to the problem unknowns
1084  // and initialise them and Phi to the same normalised values
1085  for (unsigned n = 0; n < Ndof; n++)
1086  {
1087  problem_pt->Dof_pt.push_back(&Y[n]);
1088  Y[n] = eigenvector[n] / length;
1089  Phi[n] = normalisation[n];
1090  }
1091 
1092  // delete the dist_pt
1093  problem_pt->Dof_distribution_pt->build(
1094  problem_pt->communicator_pt(), Ndof * 2 + 1, true);
1095  // Remove all previous sparse storage used during Jacobian assembly
1097 
1098  delete dist_pt;
1099  }

References oomph::LinearAlgebraDistribution::build(), oomph::Problem::communicator_pt(), Count, oomph::Problem::Dof_distribution_pt, oomph::Problem::Dof_pt, e(), oomph::Mesh::element_pt(), oomph::GeneralisedElement::eqn_number(), oomph::Problem::mesh_pt(), n, Ndof, oomph::GeneralisedElement::ndof(), oomph::Problem::ndof(), oomph::Mesh::nelement(), Phi, Problem_pt, oomph::Problem::Sparse_assemble_with_arrays_previous_allocation, sqrt(), and Y.

◆ ~FoldHandler()

oomph::FoldHandler::~FoldHandler ( )

Destructor return the problem to its original (non-augmented) state.

Destructor, return the problem to its original state before the augmented system was added

1574  {
1575  // If we are using the block solver reset the problem's linear solver
1576  // to the original one
1577  AugmentedBlockFoldLinearSolver* block_fold_solver_pt =
1578  dynamic_cast<AugmentedBlockFoldLinearSolver*>(
1580 
1581  if (block_fold_solver_pt)
1582  {
1583  // Reset the problem's linear solver
1584  Problem_pt->linear_solver_pt() = block_fold_solver_pt->linear_solver_pt();
1585  // Delete the block solver
1586  delete block_fold_solver_pt;
1587  }
1588 
1589  // Resize the number of dofs
1590  Problem_pt->Dof_pt.resize(Ndof);
1592  Problem_pt->communicator_pt(), Ndof, false);
1593  // Remove all previous sparse storage used during Jacobian assembly
1595  }
friend class AugmentedBlockFoldLinearSolver
Definition: assembly_handler.h:474
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
OomphCommunicator * communicator_pt()
access function to the oomph-lib communicator
Definition: problem.h:1246
LinearSolver *& linear_solver_pt()
Return a pointer to the linear solver object.
Definition: problem.h:1466
Vector< double * > Dof_pt
Vector of pointers to dofs.
Definition: problem.h:554
LinearAlgebraDistribution * Dof_distribution_pt
Definition: problem.h:460

References oomph::LinearAlgebraDistribution::build(), oomph::Problem::communicator_pt(), oomph::Problem::Dof_distribution_pt, oomph::Problem::Dof_pt, oomph::Problem::linear_solver_pt(), oomph::AugmentedBlockFoldLinearSolver::linear_solver_pt(), Ndof, Problem_pt, and oomph::Problem::Sparse_assemble_with_arrays_previous_allocation.

Member Function Documentation

◆ bifurcation_parameter_pt()

double* oomph::FoldHandler::bifurcation_parameter_pt ( ) const
inlinevirtual

Return a pointer to the bifurcation parameter in bifurcation tracking problems

Reimplemented from oomph::AssemblyHandler.

585  {
586  return Parameter_pt;
587  }

References Parameter_pt.

◆ bifurcation_type()

int oomph::FoldHandler::bifurcation_type ( ) const
inlinevirtual

Indicate that we are tracking a fold bifurcation by returning 1.

Reimplemented from oomph::AssemblyHandler.

578  {
579  return 1;
580  }

◆ eqn_number()

unsigned long oomph::FoldHandler::eqn_number ( GeneralisedElement *const &  elem_pt,
const unsigned ieqn_local 
)
virtual

Get the global equation number of the local unknown.

Return the global equation number associated with local equation number ieqn_local. We choose to number the unknowns according to the augmented system.

Reimplemented from oomph::AssemblyHandler.

1140  {
1141  // Find the number of non-augmented dofs in the element
1142  unsigned raw_ndof = elem_pt->ndof();
1143  // Storage for the global eqn number
1144  unsigned long global_eqn = 0;
1145  // If we are a "standard" unknown, just return the standard equation number
1146  if (ieqn_local < raw_ndof)
1147  {
1148  global_eqn = elem_pt->eqn_number(ieqn_local);
1149  }
1150  // Otherwise if we are at an unknown corresponding to the bifurcation
1151  // parameter return the global equation number of the parameter
1152  else if (ieqn_local == raw_ndof)
1153  {
1154  global_eqn = Ndof;
1155  }
1156  // Otherwise we are in the unknown corresponding to a null vector
1157  // return the global unknown Ndof + 1 + global unknown of "standard"
1158  // unknown.
1159  else
1160  {
1161  global_eqn = Ndof + 1 + elem_pt->eqn_number(ieqn_local - 1 - raw_ndof);
1162  }
1163 
1164  // Return the global equation number
1165  return global_eqn;
1166  }

References oomph::GeneralisedElement::eqn_number(), Ndof, and oomph::GeneralisedElement::ndof().

Referenced by get_jacobian(), oomph::AugmentedBlockFoldLinearSolver::resolve(), and oomph::AugmentedBlockFoldLinearSolver::solve().

◆ get_djacobian_dparameter()

void oomph::FoldHandler::get_djacobian_dparameter ( GeneralisedElement *const &  elem_pt,
double *const &  parameter_pt,
Vector< double > &  dres_dparam,
DenseMatrix< double > &  djac_dparam 
)
virtual

Overload the derivative of the residuals and jacobian with respect to a parameter so that it breaks

Overload the derivative of the residuals and jacobian with respect to a parameter so that it breaks because it should not be required

Reimplemented from oomph::AssemblyHandler.

1516  {
1517  std::ostringstream error_stream;
1518  error_stream
1519  << "This function has not been implemented because it is not required\n";
1520  error_stream << "in standard problems.\n";
1521  error_stream
1522  << "If you find that you need it, you will have to implement it!\n\n";
1523 
1524  throw OomphLibError(
1525  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1526  }
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86

References OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

◆ get_dresiduals_dparameter()

void oomph::FoldHandler::get_dresiduals_dparameter ( GeneralisedElement *const &  elem_pt,
double *const &  parameter_pt,
Vector< double > &  dres_dparam 
)
virtual

Overload the derivatives of the residuals with respect to a parameter to apply to the augmented system

Formulate the derivatives of the augmented system with respect to a parameter

Reimplemented from oomph::AssemblyHandler.

1446  {
1447  // Need to get raw residuals and jacobian
1448  unsigned raw_ndof = elem_pt->ndof();
1449 
1450  // Find out which system we are solving
1451  switch (Solve_which_system)
1452  {
1453  // If we are solving the standard system
1454  case Block_J:
1455  {
1456  // Get the basic residual derivatives
1457  elem_pt->get_dresiduals_dparameter(parameter_pt, dres_dparam);
1458  }
1459  break;
1460 
1461  // If we are solving the augmented-by-one system
1462  case Block_augmented_J:
1463  {
1464  // Get the basic residual derivatives
1465  elem_pt->get_dresiduals_dparameter(parameter_pt, dres_dparam);
1466 
1467  // Zero the final derivative
1468  dres_dparam[raw_ndof] = 0.0;
1469  }
1470  break;
1471 
1472  // If we are solving the full augmented system
1473  case Full_augmented:
1474  {
1475  DenseMatrix<double> djac_dparam(raw_ndof);
1476  // Get the basic residuals and jacobian derivatives initially
1477  elem_pt->get_djacobian_dparameter(
1478  parameter_pt, dres_dparam, djac_dparam);
1479 
1480  // The normalisation equation does not depend on the parameter
1481  dres_dparam[raw_ndof] = 0.0;
1482 
1483  // Now assemble the equations dJy/dparameter = 0
1484  for (unsigned i = 0; i < raw_ndof; i++)
1485  {
1486  dres_dparam[raw_ndof + 1 + i] = 0.0;
1487  for (unsigned j = 0; j < raw_ndof; j++)
1488  {
1489  dres_dparam[raw_ndof + 1 + i] +=
1490  djac_dparam(i, j) * Y[elem_pt->eqn_number(j)];
1491  }
1492  }
1493  }
1494  break;
1495 
1496  default:
1497  std::ostringstream error_stream;
1498  error_stream
1499  << "The Solve_which_system flag can only take values 0, 1, 2"
1500  << " not " << Solve_which_system << "\n";
1501  throw OomphLibError(
1502  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1503  }
1504  }
int i
Definition: BiCGSTAB_step_by_step.cpp:9
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2

References Block_augmented_J, Block_J, oomph::GeneralisedElement::eqn_number(), Full_augmented, oomph::GeneralisedElement::get_djacobian_dparameter(), oomph::GeneralisedElement::get_dresiduals_dparameter(), i, j, oomph::GeneralisedElement::ndof(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, Solve_which_system, and Y.

◆ get_eigenfunction()

void oomph::FoldHandler::get_eigenfunction ( Vector< DoubleVector > &  eigenfunction)
virtual

Return the eigenfunction(s) associated with the bifurcation that has been detected in bifurcation tracking problems

Reimplemented from oomph::AssemblyHandler.

1556  {
1557  // There is only one (real) null vector
1558  eigenfunction.resize(1);
1559  LinearAlgebraDistribution dist(Problem_pt->communicator_pt(), Ndof, false);
1560  // Rebuild the vector
1561  eigenfunction[0].build(&dist, 0.0);
1562  // Set the value to be the null vector
1563  for (unsigned n = 0; n < Ndof; n++)
1564  {
1565  eigenfunction[0][n] = Y[n];
1566  }
1567  }

References oomph::Problem::communicator_pt(), n, Ndof, Problem_pt, and Y.

◆ get_hessian_vector_products()

void oomph::FoldHandler::get_hessian_vector_products ( GeneralisedElement *const &  elem_pt,
Vector< double > const &  Y,
DenseMatrix< double > const &  C,
DenseMatrix< double > &  product 
)
virtual

Overload the hessian vector product function so that it breaks

Overload the hessian vector product function so that it breaks because it should not be required

Reimplemented from oomph::AssemblyHandler.

1538  {
1539  std::ostringstream error_stream;
1540  error_stream
1541  << "This function has not been implemented because it is not required\n";
1542  error_stream << "in standard problems.\n";
1543  error_stream
1544  << "If you find that you need it, you will have to implement it!\n\n";
1545 
1546  throw OomphLibError(
1547  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1548  }

References OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

◆ get_jacobian()

void oomph::FoldHandler::get_jacobian ( GeneralisedElement *const &  elem_pt,
Vector< double > &  residuals,
DenseMatrix< double > &  jacobian 
)
virtual

Calculate the elemental Jacobian matrix "d equation / d variable".

Calculate the elemental Jacobian matrix "d equation / d variable" for the augmented system

ALICE

ALICE

Reimplemented from oomph::AssemblyHandler.

1247  {
1248  // Find the number of augmented dofs
1249  unsigned augmented_ndof = ndof(elem_pt);
1250  // Find the non-augmented dofs
1251  unsigned raw_ndof = elem_pt->ndof();
1252 
1253  // Which system are we solving
1254  switch (Solve_which_system)
1255  {
1256  // If we are solving the original system
1257  case Block_J:
1258  {
1259  // Just get the raw jacobian and residuals
1260  elem_pt->get_jacobian(residuals, jacobian);
1261  }
1262  break;
1263 
1264  // If we are solving the augmented-by-one system
1265  case Block_augmented_J:
1266  {
1267  // Get the full residuals, we need them
1268  get_residuals(elem_pt, residuals);
1269 
1270  // Need to get the raw jacobian (and raw residuals)
1271  Vector<double> newres(augmented_ndof);
1272  elem_pt->get_jacobian(newres, jacobian);
1273 
1274  // Now do finite differencing stuff
1275  const double FD_step = 1.0e-8;
1276  // Fill in the first lot of finite differences
1277  {
1278  // increase the global parameter
1279  double* unknown_pt = Problem_pt->Dof_pt[Ndof];
1280  double init = *unknown_pt;
1281  *unknown_pt += FD_step;
1282 
1283  // Now do any possible updates
1285 
1286  // Get the new (modified) residuals
1287  get_residuals(elem_pt, newres);
1288 
1289  // The final column is given by the difference
1290  // between the residuals
1291  for (unsigned n = 0; n < raw_ndof; n++)
1292  {
1293  jacobian(n, augmented_ndof - 1) =
1294  (newres[n] - residuals[n]) / FD_step;
1295  }
1296  // Reset the global parameter
1297  *unknown_pt = init;
1298 
1299  // Now do any possible updates
1301  }
1302 
1303  // Fill in the bottom row
1304  for (unsigned n = 0; n < raw_ndof; n++)
1305  {
1306  unsigned local_eqn = elem_pt->eqn_number(n);
1307  jacobian(augmented_ndof - 1, n) = Phi[local_eqn] / Count[local_eqn];
1308  }
1309  }
1310  break;
1311 
1312  // Otherwise solving the full system
1313  case Full_augmented:
1314  {
1315  // Get the residuals for the augmented system
1316  get_residuals(elem_pt, residuals);
1317 
1318  // Need to get the raw residuals and jacobian
1319  Vector<double> newres(raw_ndof);
1320  DenseMatrix<double> newjac(raw_ndof);
1321  elem_pt->get_jacobian(newres, jacobian);
1322 
1323  // Fill in the jacobian on the diagonal sub-block of
1324  // the null-space equations
1325  for (unsigned n = 0; n < raw_ndof; n++)
1326  {
1327  for (unsigned m = 0; m < raw_ndof; m++)
1328  {
1329  jacobian(raw_ndof + 1 + n, raw_ndof + 1 + m) = jacobian(n, m);
1330  }
1331  }
1332 
1333  // Now finite difference wrt the global unknown
1334  const double FD_step = 1.0e-8;
1335  // Fill in the first lot of finite differences
1336  {
1337  // increase the global parameter
1338  double* unknown_pt = Problem_pt->Dof_pt[Ndof];
1339  double init = *unknown_pt;
1340  *unknown_pt += FD_step;
1341  // Need to update the function
1343 
1344  // Get the new raw residuals and jacobian
1345  elem_pt->get_jacobian(newres, newjac);
1346 
1347  // The end of the first row is given by the difference
1348  // between the residuals
1349  for (unsigned n = 0; n < raw_ndof; n++)
1350  {
1351  jacobian(n, raw_ndof) = (newres[n] - residuals[n]) / FD_step;
1352  // The end of the second row is given by the difference multiplied
1353  // by the product
1354  for (unsigned l = 0; l < raw_ndof; l++)
1355  {
1356  jacobian(raw_ndof + 1 + n, raw_ndof) +=
1357  (newjac(n, l) - jacobian(n, l)) * Y[elem_pt->eqn_number(l)] /
1358  FD_step;
1359  }
1360  }
1361  // Reset the global parameter
1362  *unknown_pt = init;
1363 
1364  // Need to update the function
1366  }
1367 
1368  // Now fill in the first column of the second rows
1369  {
1370  for (unsigned n = 0; n < raw_ndof; n++)
1371  {
1372  unsigned long global_eqn = eqn_number(elem_pt, n);
1373  // Increase the first lot
1374  double* unknown_pt = Problem_pt->Dof_pt[global_eqn];
1375  double init = *unknown_pt;
1376  *unknown_pt += FD_step;
1378 
1379  // Get the new jacobian
1380  elem_pt->get_jacobian(newres, newjac);
1381 
1382  // Work out the differences
1383  for (unsigned k = 0; k < raw_ndof; k++)
1384  {
1385  // jacobian(raw_ndof+k,n) = 0.0;
1386  for (unsigned l = 0; l < raw_ndof; l++)
1387  {
1388  jacobian(raw_ndof + 1 + k, n) +=
1389  (newjac(k, l) - jacobian(k, l)) * Y[elem_pt->eqn_number(l)] /
1390  FD_step;
1391  }
1392  }
1393  *unknown_pt = init;
1395  }
1396  }
1397 
1398  // Fill in the row corresponding to the parameter
1399  for (unsigned n = 0; n < raw_ndof; n++)
1400  {
1401  unsigned global_eqn = elem_pt->eqn_number(n);
1402  jacobian(raw_ndof, raw_ndof + 1 + n) =
1403  Phi[global_eqn] / Count[global_eqn];
1404  }
1405 
1406  // //Loop over the dofs
1407  // for(unsigned n=0;n<augmented_ndof;n++)
1408  // {
1409  // unsigned long global_eqn = eqn_number(elem_pt,n);
1410  // double* unknown_pt = Problem_pt->Dof_pt[global_eqn];
1411  // double init = *unknown_pt;
1412  // *unknown_pt += FD_step;
1413 
1414  // //Get the new residuals
1415  // get_residuals(elem_pt,newres);
1416 
1417  // for(unsigned m=0;m<augmented_ndof;m++)
1418  // {
1419  // jacobian(m,n) = (newres[m] - residuals[m])/FD_step;
1420  // }
1421  // //Reset the unknown
1422  // *unknown_pt = init;
1423  // }
1424  }
1425  break;
1426 
1427  default:
1428  std::ostringstream error_stream;
1429  error_stream
1430  << "The Solve_which_system flag can only take values 0, 1, 2"
1431  << " not " << Solve_which_system << "\n";
1432  throw OomphLibError(
1433  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1434  }
1435  }
unsigned long eqn_number(GeneralisedElement *const &elem_pt, const unsigned &ieqn_local)
Get the global equation number of the local unknown.
Definition: assembly_handler.cc:1138
void get_residuals(GeneralisedElement *const &elem_pt, Vector< double > &residuals)
Get the residuals.
Definition: assembly_handler.cc:1171
unsigned ndof(GeneralisedElement *const &elem_pt)
Get the number of elemental degrees of freedom.
Definition: assembly_handler.cc:1105
virtual void actions_after_change_in_bifurcation_parameter()
Definition: problem.h:1151
virtual void actions_before_newton_convergence_check()
Definition: problem.h:1048
int * m
Definition: level2_cplx_impl.h:294
char char char int int * k
Definition: level2_impl.h:374
double FD_step
FD step.
Definition: black_box_newton_solver.cc:54
Definition: TutorialInplaceLU.cpp:2

References oomph::Problem::actions_after_change_in_bifurcation_parameter(), oomph::Problem::actions_before_newton_convergence_check(), Block_augmented_J, Block_J, Count, oomph::Problem::Dof_pt, oomph::GeneralisedElement::eqn_number(), eqn_number(), oomph::BlackBoxFDNewtonSolver::FD_step, Full_augmented, oomph::GeneralisedElement::get_jacobian(), get_residuals(), k, m, n, Ndof, oomph::GeneralisedElement::ndof(), ndof(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, Phi, Problem_pt, Solve_which_system, and Y.

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

◆ get_residuals()

void oomph::FoldHandler::get_residuals ( GeneralisedElement *const &  elem_pt,
Vector< double > &  residuals 
)
virtual

Get the residuals.

Formulate the augmented system.

Reimplemented from oomph::AssemblyHandler.

1173  {
1174  // Need to get raw residuals and jacobian
1175  unsigned raw_ndof = elem_pt->ndof();
1176 
1177  // Find out which system we are solving
1178  switch (Solve_which_system)
1179  {
1180  // If we are solving the standard system
1181  case Block_J:
1182  {
1183  // Get the basic residuals
1184  elem_pt->get_residuals(residuals);
1185  }
1186  break;
1187 
1188  // If we are solving the augmented-by-one system
1189  case Block_augmented_J:
1190  {
1191  // Get the basic residuals
1192  elem_pt->get_residuals(residuals);
1193 
1194  // Zero the final residual
1195  residuals[raw_ndof] = 0.0;
1196  }
1197  break;
1198 
1199  // If we are solving the full augmented system
1200  case Full_augmented:
1201  {
1202  DenseMatrix<double> jacobian(raw_ndof);
1203  // Get the basic residuals and jacobian initially
1204  elem_pt->get_jacobian(residuals, jacobian);
1205 
1206  // The normalisation equation must be initialised to -1.0/number of
1207  // elements
1208  residuals[raw_ndof] = -1.0 / Problem_pt->mesh_pt()->nelement();
1209 
1210  // Now assemble the equations Jy = 0
1211  for (unsigned i = 0; i < raw_ndof; i++)
1212  {
1213  residuals[raw_ndof + 1 + i] = 0.0;
1214  for (unsigned j = 0; j < raw_ndof; j++)
1215  {
1216  residuals[raw_ndof + 1 + i] +=
1217  jacobian(i, j) * Y[elem_pt->eqn_number(j)];
1218  }
1219  // Add the contribution to phi.y=1
1220  // Need to divide by the number of elements that contribute to this
1221  // unknown so that we do get phi.y exactly.
1222  unsigned global_eqn = elem_pt->eqn_number(i);
1223  residuals[raw_ndof] +=
1224  (Phi[global_eqn] * Y[global_eqn]) / Count[global_eqn];
1225  }
1226  }
1227  break;
1228 
1229  default:
1230  std::ostringstream error_stream;
1231  error_stream
1232  << "The Solve_which_system flag can only take values 0, 1, 2"
1233  << " not " << Solve_which_system << "\n";
1234  throw OomphLibError(
1235  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1236  }
1237  }
unsigned long nelement() const
Return number of elements in the mesh.
Definition: mesh.h:590
Mesh *& mesh_pt()
Return a pointer to the global mesh.
Definition: problem.h:1280

References Block_augmented_J, Block_J, Count, oomph::GeneralisedElement::eqn_number(), Full_augmented, oomph::GeneralisedElement::get_jacobian(), oomph::GeneralisedElement::get_residuals(), i, j, oomph::Problem::mesh_pt(), oomph::GeneralisedElement::ndof(), oomph::Mesh::nelement(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, Phi, Problem_pt, Solve_which_system, and Y.

Referenced by get_jacobian().

◆ ndof()

unsigned oomph::FoldHandler::ndof ( GeneralisedElement *const &  elem_pt)
virtual

Get the number of elemental degrees of freedom.

The number of unknowns is 2n+1.

Reimplemented from oomph::AssemblyHandler.

1106  {
1107  unsigned raw_ndof = elem_pt->ndof();
1108  // Return different values depending on the type of block decomposition
1109  switch (Solve_which_system)
1110  {
1111  case Full_augmented:
1112  return (2 * raw_ndof + 1);
1113  break;
1114 
1115  case Block_augmented_J:
1116  return (raw_ndof + 1);
1117  break;
1118 
1119  case Block_J:
1120  return raw_ndof;
1121  break;
1122 
1123  default:
1124  std::ostringstream error_stream;
1125  error_stream
1126  << "The Solve_which_system flag can only take values 0, 1, 2"
1127  << " not " << Solve_which_system << "\n";
1128  throw OomphLibError(
1129  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1130  }
1131  }

References Block_augmented_J, Block_J, Full_augmented, oomph::GeneralisedElement::ndof(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and Solve_which_system.

Referenced by get_jacobian(), oomph::AugmentedBlockFoldLinearSolver::resolve(), and oomph::AugmentedBlockFoldLinearSolver::solve().

◆ solve_augmented_block_system()

void oomph::FoldHandler::solve_augmented_block_system ( )

Set to solve the augmented block system.

Set to solve the augmented-by-one block system.

1601  {
1602  // Only bother to do anything if we haven't already set the flag
1604  {
1605  // If we were solving the system with the original jacobian add the
1606  // parameter
1607  if (Solve_which_system == Block_J)
1608  {
1609  Problem_pt->Dof_pt.push_back(Parameter_pt);
1610  }
1611 
1612  // Restrict the problem to the standard variables and
1613  // the bifurcation parameter only
1614  Problem_pt->Dof_pt.resize(Ndof + 1);
1616  Problem_pt->communicator_pt(), Ndof + 1, false);
1617  // Remove all previous sparse storage used during Jacobian assembly
1619  // Set the solve flag
1621  }
1622  }

References Block_augmented_J, Block_J, oomph::LinearAlgebraDistribution::build(), oomph::Problem::communicator_pt(), oomph::Problem::Dof_distribution_pt, oomph::Problem::Dof_pt, Ndof, Parameter_pt, Problem_pt, Solve_which_system, and oomph::Problem::Sparse_assemble_with_arrays_previous_allocation.

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

◆ solve_block_system()

void oomph::FoldHandler::solve_block_system ( )

Set to solve the block system.

Set to solve the block system. The boolean flag specifies whether the block decomposition should use exactly the same jacobian

1630  {
1631  // Only bother to do anything if we haven't already set the flag
1632  if (Solve_which_system != Block_J)
1633  {
1634  // Restrict the problem to the standard variables
1635  Problem_pt->Dof_pt.resize(Ndof);
1637  Problem_pt->communicator_pt(), Ndof, false);
1638  // Remove all previous sparse storage used during Jacobian assembly
1640 
1641  // Set the solve flag
1643  }
1644  }

References Block_J, oomph::LinearAlgebraDistribution::build(), oomph::Problem::communicator_pt(), oomph::Problem::Dof_distribution_pt, oomph::Problem::Dof_pt, Ndof, Problem_pt, Solve_which_system, and oomph::Problem::Sparse_assemble_with_arrays_previous_allocation.

◆ solve_full_system()

void oomph::FoldHandler::solve_full_system ( )

Solve non-block system.

Set to Solve non-block system.

1650  {
1651  // Only do something if we are not solving the full system
1653  {
1654  // If we were solving the problem without any augmentation,
1655  // add the parameter again
1656  if (Solve_which_system == Block_J)
1657  {
1658  Problem_pt->Dof_pt.push_back(Parameter_pt);
1659  }
1660 
1661  // Always add the additional unknowns back into the problem
1662  for (unsigned n = 0; n < Ndof; n++)
1663  {
1664  Problem_pt->Dof_pt.push_back(&Y[n]);
1665  }
1666 
1667  // update the Dof distribution pt
1669  Problem_pt->communicator_pt(), Ndof * 2 + 1, false);
1670  // Remove all previous sparse storage used during Jacobian assembly
1672 
1674  }
1675  }

References Block_J, oomph::LinearAlgebraDistribution::build(), oomph::Problem::communicator_pt(), oomph::Problem::Dof_distribution_pt, oomph::Problem::Dof_pt, Full_augmented, n, Ndof, Parameter_pt, Problem_pt, Solve_which_system, oomph::Problem::Sparse_assemble_with_arrays_previous_allocation, and Y.

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

Friends And Related Function Documentation

◆ AugmentedBlockFoldLinearSolver

friend class AugmentedBlockFoldLinearSolver
friend

Member Data Documentation

◆ Count

Vector<int> oomph::FoldHandler::Count
private

A vector that is used to determine how many elements contribute to a particular equation. It is used to ensure that the global system is correctly formulated.

Referenced by FoldHandler(), get_jacobian(), and get_residuals().

◆ Ndof

unsigned oomph::FoldHandler::Ndof
private

Store the number of degrees of freedom in the non-augmented problem

Referenced by eqn_number(), FoldHandler(), get_eigenfunction(), get_jacobian(), solve_augmented_block_system(), solve_block_system(), solve_full_system(), and ~FoldHandler().

◆ Parameter_pt

double* oomph::FoldHandler::Parameter_pt
private

Storage for the pointer to the parameter.

Referenced by bifurcation_parameter_pt(), solve_augmented_block_system(), and solve_full_system().

◆ Phi

Vector<double> oomph::FoldHandler::Phi
private

A constant vector used to ensure that the null vector is not trivial

Referenced by FoldHandler(), get_jacobian(), and get_residuals().

◆ Problem_pt

◆ Solve_which_system

unsigned oomph::FoldHandler::Solve_which_system
private

Integer flag to indicate which system should be assembled. There are three possibilities. The full augmented system (0), the non-augmented jacobian system (1), a system in which the jacobian is augmented by 1 row and column to ensure that it is non-singular (2). See the enum above

Referenced by get_dresiduals_dparameter(), get_jacobian(), get_residuals(), ndof(), solve_augmented_block_system(), solve_block_system(), and solve_full_system().

◆ Y


The documentation for this class was generated from the following files: