oomph::BlockPitchForkLinearSolver Class Reference

#include <assembly_handler.h>

+ Inheritance diagram for oomph::BlockPitchForkLinearSolver:

Public Member Functions

 BlockPitchForkLinearSolver (LinearSolver *const linear_solver_pt)
 Constructor, inherits the original linear solver. More...
 
 ~BlockPitchForkLinearSolver ()
 Destructor: clean up the allocated memory. More...
 
void solve (Problem *const &problem_pt, DoubleVector &result)
 The solve function uses the block factorisation. More...
 
void solve (DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &result)
 
void solve (DoubleMatrixBase *const &matrix_pt, const Vector< double > &rhs, Vector< double > &result)
 
void resolve (const DoubleVector &rhs, DoubleVector &result)
 The resolve function also uses the block factorisation. More...
 
LinearSolverlinear_solver_pt () const
 Access function to the original linear solver. More...
 
- Public Member Functions inherited from oomph::LinearSolver
 LinearSolver ()
 Empty constructor, initialise the member data. More...
 
 LinearSolver (const LinearSolver &dummy)=delete
 Broken copy constructor. More...
 
void operator= (const LinearSolver &)=delete
 Broken assignment operator. More...
 
virtual ~LinearSolver ()
 Empty virtual destructor. More...
 
void enable_doc_time ()
 Enable documentation of solve times. More...
 
void disable_doc_time ()
 Disable documentation of solve times. More...
 
bool is_doc_time_enabled () const
 Is documentation of solve times enabled? More...
 
bool is_resolve_enabled () const
 Boolean flag indicating if resolves are enabled. More...
 
virtual void enable_resolve ()
 
virtual void disable_resolve ()
 
virtual void solve_transpose (Problem *const &problem_pt, DoubleVector &result)
 
virtual void solve_transpose (DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &result)
 
virtual void solve_transpose (DoubleMatrixBase *const &matrix_pt, const Vector< double > &rhs, Vector< double > &result)
 
virtual void resolve_transpose (const DoubleVector &rhs, DoubleVector &result)
 
virtual void clean_up_memory ()
 
virtual double jacobian_setup_time () const
 
virtual double linear_solver_solution_time () const
 
virtual void enable_computation_of_gradient ()
 
void disable_computation_of_gradient ()
 
void reset_gradient ()
 
void get_gradient (DoubleVector &gradient)
 function to access the gradient, provided it has been computed More...
 
- Public Member Functions inherited from oomph::DistributableLinearAlgebraObject
 DistributableLinearAlgebraObject ()
 Default constructor - create a distribution. More...
 
 DistributableLinearAlgebraObject (const DistributableLinearAlgebraObject &matrix)=delete
 Broken copy constructor. More...
 
void operator= (const DistributableLinearAlgebraObject &)=delete
 Broken assignment operator. More...
 
virtual ~DistributableLinearAlgebraObject ()
 Destructor. More...
 
LinearAlgebraDistributiondistribution_pt () const
 access to the LinearAlgebraDistribution More...
 
unsigned nrow () const
 access function to the number of global rows. More...
 
unsigned nrow_local () const
 access function for the num of local rows on this processor. More...
 
unsigned nrow_local (const unsigned &p) const
 access function for the num of local rows on this processor. More...
 
unsigned first_row () const
 access function for the first row on this processor More...
 
unsigned first_row (const unsigned &p) const
 access function for the first row on this processor More...
 
bool distributed () const
 distribution is serial or distributed More...
 
bool distribution_built () const
 
void build_distribution (const LinearAlgebraDistribution *const dist_pt)
 
void build_distribution (const LinearAlgebraDistribution &dist)
 

Private Attributes

LinearSolverLinear_solver_pt
 Pointer to the original linear solver. More...
 
ProblemProblem_pt
 Pointer to the problem, used in the resolve. More...
 
DoubleVectorB_pt
 Pointer to the storage for the vector b. More...
 
DoubleVectorC_pt
 Pointer to the storage for the vector c. More...
 
DoubleVectorD_pt
 Pointer to the storage for the vector d. More...
 
DoubleVectordJy_dparam_pt
 

Additional Inherited Members

- Protected Member Functions inherited from oomph::DistributableLinearAlgebraObject
void clear_distribution ()
 
- Protected Attributes inherited from oomph::LinearSolver
bool Enable_resolve
 
bool Doc_time
 Boolean flag that indicates whether the time taken. More...
 
bool Compute_gradient
 
bool Gradient_has_been_computed
 flag that indicates whether the gradient was computed or not More...
 
DoubleVector Gradient_for_glob_conv_newton_solve
 

Detailed Description

A custom linear solver class that is used to solve a block-factorised version of the PitchFork bifurcation detection problem.

Constructor & Destructor Documentation

◆ BlockPitchForkLinearSolver()

oomph::BlockPitchForkLinearSolver::BlockPitchForkLinearSolver ( LinearSolver *const  linear_solver_pt)
inline

Constructor, inherits the original linear solver.

633  Problem_pt(0),
634  B_pt(0),
635  C_pt(0),
636  D_pt(0),
637  dJy_dparam_pt(0)
638  {
639  }
DoubleVector * D_pt
Pointer to the storage for the vector d.
Definition: assembly_handler.h:623
LinearSolver * linear_solver_pt() const
Access function to the original linear solver.
Definition: assembly_handler.h:676
DoubleVector * dJy_dparam_pt
Definition: assembly_handler.h:627
DoubleVector * B_pt
Pointer to the storage for the vector b.
Definition: assembly_handler.h:617
Problem * Problem_pt
Pointer to the problem, used in the resolve.
Definition: assembly_handler.h:614
DoubleVector * C_pt
Pointer to the storage for the vector c.
Definition: assembly_handler.h:620
LinearSolver * Linear_solver_pt
Pointer to the original linear solver.
Definition: assembly_handler.h:611

◆ ~BlockPitchForkLinearSolver()

oomph::BlockPitchForkLinearSolver::~BlockPitchForkLinearSolver ( )

Destructor: clean up the allocated memory.

Clean up the memory that may have been allocated by the solver.

1682  {
1683  if (B_pt != 0)
1684  {
1685  delete B_pt;
1686  }
1687  if (C_pt != 0)
1688  {
1689  delete C_pt;
1690  }
1691  if (D_pt != 0)
1692  {
1693  delete D_pt;
1694  }
1695  if (dJy_dparam_pt != 0)
1696  {
1697  delete dJy_dparam_pt;
1698  }
1699  }

References B_pt, C_pt, D_pt, and dJy_dparam_pt.

Member Function Documentation

◆ linear_solver_pt()

LinearSolver* oomph::BlockPitchForkLinearSolver::linear_solver_pt ( ) const
inline

Access function to the original linear solver.

677  {
678  return Linear_solver_pt;
679  }

References Linear_solver_pt.

Referenced by oomph::PitchForkHandler::~PitchForkHandler().

◆ resolve()

void oomph::BlockPitchForkLinearSolver::resolve ( const DoubleVector rhs,
DoubleVector result 
)
virtual

The resolve function also uses the block factorisation.

Reimplemented from oomph::LinearSolver.

2009  {
2010  std::cout << "Block pitchfork resolve" << std::endl;
2011  // Check that the factors have been stored
2012  if (B_pt == 0)
2013  {
2014  throw OomphLibError("The required vectors have not been stored",
2017  }
2018 
2019 
2020  // Cache pointer to the problem
2021  Problem* const problem_pt = Problem_pt;
2022 
2023  // Locally cache pointer to the handler
2024  PitchForkHandler* handler_pt =
2025  static_cast<PitchForkHandler*>(problem_pt->assembly_handler_pt());
2026 
2027  // Get the augmented distribution from the handler
2028  LinearAlgebraDistribution aug_dist =
2029  handler_pt->Augmented_dof_distribution_pt;
2030  // this->build_distribution(aug_dist);
2031 
2032  // Find the number of dofs of the augmented system
2033  // const unsigned n_aug_dof = problem_pt->ndof();
2034 
2035  // Storage for the result distribution
2036  LinearAlgebraDistribution result_dist;
2037 
2038  // if the result vector is not setup then rebuild with distribution
2039  // = natural distribution of augmented solver
2040  if (!result.built())
2041  {
2042  result.build(&aug_dist, 0.0);
2043  }
2044  // Otherwise store the incoming distribution and redistribute
2045  else
2046  {
2047  result_dist.build(result.distribution_pt());
2048  result.redistribute(&aug_dist);
2049  }
2050 
2051 
2052  // Locally cache a pointer to the parameter
2053  // double* const parameter_pt = handler_pt->Parameter_pt;
2054 
2055  // Switch things to our block solver
2056  handler_pt->solve_block_system();
2057  // We need to find out the number of dofs
2058  // unsigned n_dof = problem_pt->ndof();
2059 
2060  // create the linear algebra distribution for this solver
2061  // currently only global (non-distributed) distributions are allowed
2062  // LinearAlgebraDistribution
2063  // dist(problem_pt->communicator_pt(),n_dof,false);
2064  // this->build_distribution(dist);
2065 
2066  // if the result vector is not setup then rebuild with distribution = global
2067  // if (!result.built())
2068  // {
2069  // result.build(this->distribution_pt(),0.0);
2070  // }
2071 
2072 
2073  // Copy the rhs into local storage
2074  DoubleVector rhs_local = rhs;
2075  // and redistribute into the augmented distribution
2076  rhs_local.redistribute(&aug_dist);
2077 
2078  // Setup storage for output
2081 
2082  // Create input for RHS with the natural distribution
2083  DoubleVector input_x1(handler_pt->Dof_distribution_pt);
2084  const unsigned n_dof_local = input_x1.nrow_local();
2085 
2086  // Set the values of the a vector
2087  for (unsigned n = 0; n < n_dof_local; n++)
2088  {
2089  input_x1[n] = rhs_local[n];
2090  }
2091  // Need to redistribute into the linear algebra distribution
2092  input_x1.redistribute(Linear_solver_pt->distribution_pt());
2093 
2094  // We want to resolve, of course
2096  // Now solve for the first vector
2097  Linear_solver_pt->resolve(input_x1, x1);
2098 
2099  // Get the symmetry vector from the handler
2100  DoubleVector psi = handler_pt->Psi;
2101  // redistribute local copy
2102  psi.redistribute(Linear_solver_pt->distribution_pt());
2103 
2104  // We can now construct various dot products
2105  double psi_d = psi.dot(*D_pt);
2106  double psi_c = psi.dot(*C_pt);
2107  double psi_x1 = psi.dot(x1);
2108 
2109  // Calculate another intermediate constant
2110  const double Psi = psi_d / psi_c;
2111 
2112  // Construct the second intermediate value,
2113  // assumption is that rhs has been set to the current value of the residuals
2114  double parameter_residual = rhs_local[n_dof_local];
2115 #ifdef OOMPH_HAS_MPI
2116  // Broadcast to all others, if we have a distributed problem
2117  if (problem_pt->distributed())
2118  {
2119  MPI_Bcast(&parameter_residual,
2120  1,
2121  MPI_DOUBLE,
2122  0,
2123  problem_pt->communicator_pt()->mpi_comm());
2124  }
2125 #endif
2126 
2127  double x2 = (psi_x1 - parameter_residual) / psi_c;
2128 
2129  // Now construct the vectors that multiply the jacobian terms
2130  // Vector<double> X1(n_dof/*+1*/);
2131  Vector<DoubleVectorWithHaloEntries> X1(1);
2132  X1[0].build(Linear_solver_pt->distribution_pt(), 0.0);
2133 
2134  const unsigned n_dof_local_linear_solver =
2136  for (unsigned n = 0; n < n_dof_local_linear_solver; n++)
2137  {
2138  X1[0][n] = x1[n] - x2 * (*C_pt)[n];
2139  }
2140 
2141  // Local storage for the product term
2142  Vector<DoubleVectorWithHaloEntries> Jprod_X1(1);
2143 
2144  // Redistribute the inputs to have the Dof distribution pt
2145  X1[0].redistribute(handler_pt->Dof_distribution_pt);
2146 
2147  // Set up the halo scheme
2148 #ifdef OOMPH_HAS_MPI
2149  X1[0].build_halo_scheme(problem_pt->Halo_scheme_pt);
2150 #endif
2151 
2152  // Get the product from the problem
2153  problem_pt->get_hessian_vector_products(handler_pt->Y, X1, Jprod_X1);
2154 
2155  // In standard cases the offset here will be one
2156  unsigned offset = 1;
2157 #ifdef OOMPH_HAS_MPI
2158  // If we are distributed and not on the first processor
2159  // then there is no offset and the eigenfunction is
2160  // directly after the standard dofs
2161  int my_rank = problem_pt->communicator_pt()->my_rank();
2162  if ((problem_pt->distributed()) && (my_rank != 0))
2163  {
2164  offset = 0;
2165  }
2166 #endif
2167 
2168  // OK, now we can formulate the next vectors
2169  //(again assuming result contains residuals)
2170  // Local storage for the product terms
2171  DoubleVector Mod_Jprod_X1(handler_pt->Dof_distribution_pt, 0.0);
2172 
2173  for (unsigned n = 0; n < n_dof_local; n++)
2174  {
2175  Mod_Jprod_X1[n] = rhs_local[n_dof_local + offset + n] - Jprod_X1[0][n] -
2176  x2 * (*dJy_dparam_pt)[n];
2177  }
2178 
2179  // Redistribute back to the linear solver distribution
2180  Mod_Jprod_X1.redistribute(Linear_solver_pt->distribution_pt());
2181 
2182  // Liner solve to get x3
2183  Linear_solver_pt->resolve(Mod_Jprod_X1, x3);
2184 
2185  // Construst a couple of additional products
2186  double l_x3 = psi.dot(x3);
2187  double l_b = psi.dot(*B_pt);
2188 
2189  // get the last intermediate variable
2190  // The required parameter is that corresponding to the dof, which
2191  // is only stored on the root processor
2192  double sigma_residual = rhs_local[2 * (n_dof_local + offset) - 1];
2193 #ifdef OOMPH_HAS_MPI
2194  // Broadcast to all others, if we have a distributed problem
2195  if (problem_pt->distributed())
2196  {
2197  MPI_Bcast(&sigma_residual,
2198  1,
2199  MPI_DOUBLE,
2200  0,
2201  problem_pt->communicator_pt()->mpi_comm());
2202  }
2203 #endif
2204 
2205  // get the last intermediate variable
2206  const double delta_sigma = (l_x3 - sigma_residual) / l_b;
2207  const double delta_lambda = x2 - delta_sigma * Psi;
2208 
2209  // Create temporary DoubleVectors to hold the results
2212 
2213  for (unsigned n = 0; n < n_dof_local_linear_solver; n++)
2214  {
2215  res1[n] = x1[n] - delta_lambda * (*C_pt)[n] - delta_sigma * (*D_pt)[n];
2216  res2[n] = x3[n] - delta_sigma * (*B_pt)[n];
2217  }
2218 
2219  // Now redistribute these into the Dof distribution pointer
2220  res1.redistribute(handler_pt->Dof_distribution_pt);
2221  res2.redistribute(handler_pt->Dof_distribution_pt);
2222 
2223  // Now can copy over into results into the result vector
2224  for (unsigned n = 0; n < n_dof_local; n++)
2225  {
2226  result[n] = res1[n];
2227  result[n_dof_local + offset + n] = res2[n];
2228  }
2229 
2230  // Add the final contributions to the residuals
2231  // only on the root processor if we have a distributed problem
2232 #ifdef OOMPH_HAS_MPI
2233  if ((!problem_pt->distributed()) || (my_rank == 0))
2234 #endif
2235  {
2236  result[n_dof_local] = delta_lambda;
2237  result[2 * n_dof_local + 1] = delta_sigma;
2238  }
2239 
2240  // Redistribute the result into its incoming distribution (if it had one)
2241  if (result_dist.built())
2242  {
2243  result.redistribute(&result_dist);
2244  }
2245 
2247 
2248  // Switch things to our block solver
2249  handler_pt->solve_full_system();
2250  }
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
std::vector< double > DoubleVector
loads clump configuration
Definition: ClumpInput.h:26
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
Definition: linear_algebra_distribution.h:457
unsigned nrow_local() const
Definition: linear_algebra_distribution.h:193
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
Vector< double > x1(const Vector< double > &coord)
Cartesian coordinates centered at the point (0.5,1)
Definition: poisson/poisson_with_singularity/two_d_poisson.cc:86
Vector< double > x2(const Vector< double > &coord)
Cartesian coordinates centered at the point (1.5,1)
Definition: poisson/poisson_with_singularity/two_d_poisson.cc:102
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86

References oomph::Problem::assembly_handler_pt(), oomph::PitchForkHandler::Augmented_dof_distribution_pt, B_pt, oomph::DoubleVector::build(), oomph::LinearAlgebraDistribution::build(), oomph::DoubleVector::built(), oomph::LinearAlgebraDistribution::built(), C_pt, oomph::Problem::communicator_pt(), D_pt, oomph::LinearSolver::disable_resolve(), oomph::Problem::distributed(), oomph::DistributableLinearAlgebraObject::distribution_pt(), oomph::PitchForkHandler::Dof_distribution_pt, oomph::DoubleVector::dot(), oomph::LinearSolver::enable_resolve(), oomph::Problem::get_hessian_vector_products(), Linear_solver_pt, oomph::OomphCommunicator::my_rank(), n, oomph::LinearAlgebraDistribution::nrow_local(), oomph::DistributableLinearAlgebraObject::nrow_local(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, Problem_pt, oomph::PitchForkHandler::Psi, oomph::DoubleVector::redistribute(), oomph::LinearSolver::resolve(), oomph::PitchForkHandler::solve_block_system(), oomph::PitchForkHandler::solve_full_system(), Global_parameters::x1(), Global_parameters::x2(), and oomph::PitchForkHandler::Y.

◆ solve() [1/3]

void oomph::BlockPitchForkLinearSolver::solve ( DoubleMatrixBase *const &  matrix_pt,
const DoubleVector rhs,
DoubleVector result 
)
inlinevirtual

The linear-algebra-type solver does not make sense. The interface is deliberately broken

Reimplemented from oomph::LinearSolver.

652  {
653  throw OomphLibError(
654  "Linear-algebra interface does not make sense for this linear solver\n",
657  }

References OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

◆ solve() [2/3]

void oomph::BlockPitchForkLinearSolver::solve ( DoubleMatrixBase *const &  matrix_pt,
const Vector< double > &  rhs,
Vector< double > &  result 
)
inlinevirtual

The linear-algebra-type solver does not make sense. The interface is deliberately broken

Reimplemented from oomph::LinearSolver.

664  {
665  throw OomphLibError(
666  "Linear-algebra interface does not make sense for this linear solver\n",
669  }

References OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

◆ solve() [3/3]

void oomph::BlockPitchForkLinearSolver::solve ( Problem *const &  problem_pt,
DoubleVector result 
)
virtual

The solve function uses the block factorisation.

Use a block factorisation to solve the augmented system associated with a PitchFork bifurcation.

Implements oomph::LinearSolver.

1707  {
1708  std::cout << "Block pitchfork solve" << std::endl;
1709  // Locally cache the pointer to the handler.
1710  PitchForkHandler* handler_pt =
1711  static_cast<PitchForkHandler*>(problem_pt->assembly_handler_pt());
1712 
1713  // Get the augmented distribution from the handler and use it as
1714  // the distribution of the linear solver
1715  LinearAlgebraDistribution aug_dist =
1716  handler_pt->Augmented_dof_distribution_pt;
1717  this->build_distribution(aug_dist);
1718 
1719  // If the result vector is not setup then die
1720  if (!result.built())
1721  {
1722  throw OomphLibError("Result vector must be built\n",
1725  }
1726 
1727  // Store the distribution of the result, which is probably not in
1728  // the natural distribution of the augmented solver
1729  LinearAlgebraDistribution result_dist(result.distribution_pt());
1730 
1731  // Locally cache a pointer to the parameter
1732  double* const parameter_pt = handler_pt->Parameter_pt;
1733 
1734  // Firstly get the derivatives of the full augmented system with
1735  // respect to the parameter
1736 
1737  // Allocate storage for the derivatives of the residuals with respect
1738  // to the global parameter using the augmented distribution
1739  DoubleVector dRdparam;
1740  // Then get the appropriate derivatives which will come back in
1741  // some distribution
1742  problem_pt->get_derivative_wrt_global_parameter(parameter_pt, dRdparam);
1743  // Redistribute into the augmented distribution
1744  dRdparam.redistribute(&aug_dist);
1745 
1746  // Switch the handler to "block solver" mode (sort out distribution)
1747  handler_pt->solve_block_system();
1748 
1749  // Temporary vector for the result (I shouldn't have to set this up)
1750  DoubleVector x1;
1751 
1752  // We are going to do resolves using the underlying linear solver
1754  // Solve the first (standard) system Jx1 = R
1755  Linear_solver_pt->solve(problem_pt, x1);
1756 
1757  // Allocate storage for B, C and D which can be used in the resolve
1758  // and the derivatives of the jacobian/eigenvector product with
1759  // respect to the parameter
1760  if (B_pt != 0)
1761  {
1762  delete B_pt;
1763  }
1765  if (C_pt != 0)
1766  {
1767  delete C_pt;
1768  }
1770  if (D_pt != 0)
1771  {
1772  delete D_pt;
1773  }
1775  // Need this to be in the distribution of the dofs
1776  if (dJy_dparam_pt != 0)
1777  {
1778  delete dJy_dparam_pt;
1779  }
1780  dJy_dparam_pt = new DoubleVector(handler_pt->Dof_distribution_pt, 0.0);
1781 
1782  // Get the symmetry vector from the handler should have the
1783  // Dof distribution
1784  DoubleVector psi = handler_pt->Psi;
1785 
1786  // Temporary vector for the rhs that is dR/dparam (augmented distribution)
1787  // DoubleVector F(Linear_solver_pt->distribution_pt(),0.0);
1788  DoubleVector F(handler_pt->Dof_distribution_pt);
1789  const unsigned n_dof_local = F.nrow_local();
1790 
1791  // f.nrow local copied from dRdparam
1792  for (unsigned n = 0; n < n_dof_local; n++)
1793  {
1794  F[n] = dRdparam[n];
1795  }
1796  // Fill in the rhs that is dJy/dparam //dJy_dparam nrow local
1797 
1798  // In standard cases the offset here will be one
1799  unsigned offset = 1;
1800 #ifdef OOMPH_HAS_MPI
1801  // If we are distributed and not on the first processor
1802  // then there is no offset and the eigenfunction is
1803  // directly after the standard dofs
1804  int my_rank = problem_pt->communicator_pt()->my_rank();
1805  if ((problem_pt->distributed()) && (my_rank != 0))
1806  {
1807  offset = 0;
1808  }
1809 #endif
1810  for (unsigned n = 0; n < n_dof_local; n++)
1811  {
1812  (*dJy_dparam_pt)[n] = dRdparam[n_dof_local + offset + n];
1813  }
1814 
1815  // Now resolve to find c and d
1816  // First, redistribute F and psi into the linear algebra distribution
1817  F.redistribute(Linear_solver_pt->distribution_pt());
1818  psi.redistribute(Linear_solver_pt->distribution_pt());
1819 
1821  Linear_solver_pt->resolve(psi, *D_pt);
1822 
1823  // We can now construct various dot products
1824  double psi_d = psi.dot(*D_pt);
1825  double psi_c = psi.dot(*C_pt);
1826  double psi_x1 = psi.dot(x1);
1827 
1828  // Calculate another intermediate constant
1829  const double Psi = psi_d / psi_c;
1830 
1831  // Construct the second intermediate value,
1832  // assumption is that result has been
1833  // set to the current value of the residuals
1834  // First, redistribute into the Natural distribution of the augmented system
1835  result.redistribute(&aug_dist);
1836  // The required parameter is that corresponding to the dof, which
1837  // is only stored on the root processor
1838  double parameter_residual = result[n_dof_local];
1839 #ifdef OOMPH_HAS_MPI
1840  // Broadcast to all others, if we have a distributed problem
1841  if (problem_pt->distributed())
1842  {
1843  MPI_Bcast(&parameter_residual,
1844  1,
1845  MPI_DOUBLE,
1846  0,
1847  problem_pt->communicator_pt()->mpi_comm());
1848  }
1849 #endif
1850  // Now construct the value
1851  double x2 = (psi_x1 - parameter_residual) / psi_c;
1852 
1853  // Now construct the vectors that multiply the jacobian terms
1854  Vector<DoubleVectorWithHaloEntries> D_and_X1(2);
1855  D_and_X1[0].build(Linear_solver_pt->distribution_pt(), 0.0);
1856  D_and_X1[1].build(Linear_solver_pt->distribution_pt(), 0.0);
1857  // Fill in the appropriate terms
1858  // Get the number of local dofs from the Linear_solver_pt distribution
1859  const unsigned n_dof_local_linear_solver =
1861  for (unsigned n = 0; n < n_dof_local_linear_solver; n++)
1862  {
1863  const double C_ = (*C_pt)[n];
1864  D_and_X1[0][n] = (*D_pt)[n] - Psi * C_;
1865  D_and_X1[1][n] = x1[n] - x2 * C_;
1866  }
1867 
1868  // Local storage for the result of the product terms
1869  Vector<DoubleVectorWithHaloEntries> Jprod_D_and_X1(2);
1870 
1871  // Redistribute the inputs to have the Dof distribution pt
1872  D_and_X1[0].redistribute(handler_pt->Dof_distribution_pt);
1873  D_and_X1[1].redistribute(handler_pt->Dof_distribution_pt);
1874 
1875  // Set up the halo scheme
1876 #ifdef OOMPH_HAS_MPI
1877  D_and_X1[0].build_halo_scheme(problem_pt->Halo_scheme_pt);
1878  D_and_X1[1].build_halo_scheme(problem_pt->Halo_scheme_pt);
1879 #endif
1880 
1881  // Get the products from the new problem function
1882  problem_pt->get_hessian_vector_products(
1883  handler_pt->Y, D_and_X1, Jprod_D_and_X1);
1884 
1885  // OK, now we can formulate the next vectors
1886  //(again assuming result contains residuals)
1887  // Need to redistribute F to the dof distribution
1888  // F.redistribute(handler_pt->Dof_distribution_pt);
1889  DoubleVector G(handler_pt->Dof_distribution_pt);
1890 
1891  for (unsigned n = 0; n < n_dof_local; n++)
1892  {
1893  G[n] = result[n_dof_local + offset + n] - Jprod_D_and_X1[1][n] -
1894  x2 * dRdparam[n_dof_local + offset + n];
1895  Jprod_D_and_X1[0][n] *= -1.0;
1896  Jprod_D_and_X1[0][n] -= Psi * dRdparam[n_dof_local + offset + n];
1897  }
1898 
1899 
1900  // Then redistribute back to the linear solver distribution
1901  G.redistribute(Linear_solver_pt->distribution_pt());
1902  Jprod_D_and_X1[0].redistribute(Linear_solver_pt->distribution_pt());
1903  Jprod_D_and_X1[1].redistribute(Linear_solver_pt->distribution_pt());
1904 
1905  // Linear solve to get B
1906  Linear_solver_pt->resolve(Jprod_D_and_X1[0], *B_pt);
1907  // Liner solve to get x3
1909  Linear_solver_pt->resolve(G, x3);
1910 
1911  // Construst a couple of additional products
1912  double l_x3 = psi.dot(x3);
1913  double l_b = psi.dot(*B_pt);
1914 
1915  // get the last intermediate variable
1916  // The required parameter is that corresponding to the dof, which
1917  // is only stored on the root processor
1918  double sigma_residual = result[2 * (n_dof_local + offset) - 1];
1919 #ifdef OOMPH_HAS_MPI
1920  // Broadcast to all others, if we have a distributed problem
1921  if (problem_pt->distributed())
1922  {
1923  MPI_Bcast(&sigma_residual,
1924  1,
1925  MPI_DOUBLE,
1926  0,
1927  problem_pt->communicator_pt()->mpi_comm());
1928  }
1929 #endif
1930 
1931 
1932  const double delta_sigma = (l_x3 - sigma_residual) / l_b;
1933  const double delta_lambda = x2 - delta_sigma * Psi;
1934 
1935  // Need to do some more rearrangements here because result is global
1936  // but the other vectors are not!
1937 
1938  // Create temporary DoubleVectors to hold the results
1941 
1942  for (unsigned n = 0; n < n_dof_local_linear_solver; n++)
1943  {
1944  res1[n] = x1[n] - delta_lambda * (*C_pt)[n] - delta_sigma * (*D_pt)[n];
1945  res2[n] = x3[n] - delta_sigma * (*B_pt)[n];
1946  }
1947 
1948  // Now redistribute these into the Dof distribution pointer
1949  res1.redistribute(handler_pt->Dof_distribution_pt);
1950  res2.redistribute(handler_pt->Dof_distribution_pt);
1951 
1952  // Now can copy over into results into the result vector
1953  for (unsigned n = 0; n < n_dof_local; n++)
1954  {
1955  result[n] = res1[n];
1956  result[n_dof_local + offset + n] = res2[n];
1957  }
1958 
1959  // Add the final contributions to the residuals
1960  // only on the root processor if we have a distributed problem
1961 #ifdef OOMPH_HAS_MPI
1962  if ((!problem_pt->distributed()) || (my_rank == 0))
1963 #endif
1964  {
1965  result[n_dof_local] = delta_lambda;
1966  result[2 * n_dof_local + 1] = delta_sigma;
1967  }
1968 
1969 
1970  // The sign of the determinant is given by the sign of
1971  // the product psi_c and l_b
1972  // NOT CHECKED YET!
1973  problem_pt->sign_of_jacobian() =
1974  static_cast<int>(std::fabs(psi_c * l_b) / (psi_c * l_b));
1975 
1976  // Redistribute the result into its incoming distribution
1977  result.redistribute(&result_dist);
1978 
1979  // Switch things to our block solver
1980  handler_pt->solve_full_system();
1981 
1982  // If we are not storing things, clear the results
1983  if (!Enable_resolve)
1984  {
1985  // We no longer need to store the matrix
1987  delete B_pt;
1988  B_pt = 0;
1989  delete C_pt;
1990  C_pt = 0;
1991  delete D_pt;
1992  D_pt = 0;
1993  delete dJy_dparam_pt;
1994  dJy_dparam_pt = 0;
1995  }
1996  // Otherwise also store the pointer to the problem
1997  else
1998  {
1999  Problem_pt = problem_pt;
2000  }
2001  }
JacobiRotation< float > G
Definition: Jacobi_makeGivens.cpp:2
void build_distribution(const LinearAlgebraDistribution *const dist_pt)
Definition: linear_algebra_distribution.h:507
virtual void solve(Problem *const &problem_pt, DoubleVector &result)=0
bool Enable_resolve
Definition: linear_solver.h:73
Real fabs(const Real &a)
Definition: boostmultiprec.cpp:117
@ F
Definition: octree.h:74

References oomph::Problem::assembly_handler_pt(), oomph::PitchForkHandler::Augmented_dof_distribution_pt, B_pt, oomph::DistributableLinearAlgebraObject::build_distribution(), oomph::DoubleVector::built(), C_pt, oomph::Problem::communicator_pt(), D_pt, oomph::LinearSolver::disable_resolve(), oomph::Problem::distributed(), oomph::DistributableLinearAlgebraObject::distribution_pt(), dJy_dparam_pt, oomph::PitchForkHandler::Dof_distribution_pt, oomph::DoubleVector::dot(), oomph::LinearSolver::Enable_resolve, oomph::LinearSolver::enable_resolve(), oomph::OcTreeNames::F, boost::multiprecision::fabs(), G, oomph::Problem::get_derivative_wrt_global_parameter(), oomph::Problem::get_hessian_vector_products(), Linear_solver_pt, oomph::OomphCommunicator::my_rank(), n, oomph::LinearAlgebraDistribution::nrow_local(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::PitchForkHandler::Parameter_pt, Problem_pt, oomph::PitchForkHandler::Psi, oomph::DoubleVector::redistribute(), oomph::LinearSolver::resolve(), oomph::Problem::sign_of_jacobian(), oomph::LinearSolver::solve(), oomph::PitchForkHandler::solve_block_system(), oomph::PitchForkHandler::solve_full_system(), Global_parameters::x1(), Global_parameters::x2(), and oomph::PitchForkHandler::Y.

Member Data Documentation

◆ B_pt

DoubleVector* oomph::BlockPitchForkLinearSolver::B_pt
private

Pointer to the storage for the vector b.

Referenced by resolve(), solve(), and ~BlockPitchForkLinearSolver().

◆ C_pt

DoubleVector* oomph::BlockPitchForkLinearSolver::C_pt
private

Pointer to the storage for the vector c.

Referenced by resolve(), solve(), and ~BlockPitchForkLinearSolver().

◆ D_pt

DoubleVector* oomph::BlockPitchForkLinearSolver::D_pt
private

Pointer to the storage for the vector d.

Referenced by resolve(), solve(), and ~BlockPitchForkLinearSolver().

◆ dJy_dparam_pt

DoubleVector* oomph::BlockPitchForkLinearSolver::dJy_dparam_pt
private

Pointer to the storage for the vector of derivatives with respect to the bifurcation parameter

Referenced by solve(), and ~BlockPitchForkLinearSolver().

◆ Linear_solver_pt

LinearSolver* oomph::BlockPitchForkLinearSolver::Linear_solver_pt
private

Pointer to the original linear solver.

Referenced by linear_solver_pt(), resolve(), and solve().

◆ Problem_pt

Problem* oomph::BlockPitchForkLinearSolver::Problem_pt
private

Pointer to the problem, used in the resolve.

Referenced by resolve(), and solve().


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