// Solves turning point equations via Phipps modified bordering
// The first m columns of input_x and input_null store the RHS while
// the last column stores df/dp, d(Jn)/dp respectively.  Note however
// input_param has only m columns (not m+1).  result_x, result_null,
// are result_param have the same dimensions as their input counterparts
NOX::Abstract::Group::ReturnType 
LOCA::TurningPoint::MooreSpence::PhippsBordering::solveContiguous(
		  Teuchos::ParameterList& params,
		  const NOX::Abstract::MultiVector& input_x,
		  const NOX::Abstract::MultiVector& input_null,
	          const NOX::Abstract::MultiVector::DenseMatrix& input_param,
		  NOX::Abstract::MultiVector& result_x,
		  NOX::Abstract::MultiVector& result_null,
	          NOX::Abstract::MultiVector::DenseMatrix& result_param) const
{
  std::string callingFunction = 
    "LOCA::TurningPoint::MooreSpence::PhippsBordering::solveContiguous()";
  NOX::Abstract::Group::ReturnType finalStatus = NOX::Abstract::Group::Ok;
  NOX::Abstract::Group::ReturnType status;

  int m = input_x.numVectors()-2;
  std::vector<int> index_input(m);
  std::vector<int> index_input_dp(m+1);
  std::vector<int> index_null(1);
  std::vector<int> index_dp(1);
  for (int i=0; i<m; i++) {
    index_input[i] = i;
    index_input_dp[i] = i;
  }
  index_input_dp[m] = m;
  index_dp[0] = m;
  index_null[0] = m+1;

  NOX::Abstract::MultiVector::DenseMatrix tmp_mat_1(1, m+1);
  NOX::Abstract::MultiVector::DenseMatrix tmp_mat_2(1, m+2);

  // Create view of first m+1 columns of input_x, result_x
  Teuchos::RCP<NOX::Abstract::MultiVector> input_x_view = 
      input_x.subView(index_input_dp);
  Teuchos::RCP<NOX::Abstract::MultiVector> result_x_view = 
      result_x.subView(index_input_dp);

  // verify underlying Jacobian is valid
  if (!group->isJacobian()) {
    status = group->computeJacobian();
    finalStatus = 
      globalData->locaErrorCheck->combineAndCheckReturnTypes(status, 
							     finalStatus,
							     callingFunction);
  }
  
  // Solve  |J   u||A B| = |F df/dp|
  //        |v^T 0||a b|   |0   0  |
  status = borderedSolver->applyInverse(params, input_x_view.get(), NULL, 
					*result_x_view, tmp_mat_1);
  finalStatus = 
    globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus,
							   callingFunction);
  Teuchos::RCP<NOX::Abstract::MultiVector> A = 
    result_x.subView(index_input);
  Teuchos::RCP<NOX::Abstract::MultiVector> B = 
    result_x.subView(index_dp);
  double b = tmp_mat_1(0,m);

  // compute (Jv)_x[A B v]
  result_x[m+1] = *nullVector;
  Teuchos::RCP<NOX::Abstract::MultiVector> tmp = 
    result_x.clone(NOX::ShapeCopy);
  status = group->computeDJnDxaMulti(*nullVector, *JnVector, result_x,
				     *tmp);
  finalStatus = 
    globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus,
							   callingFunction);

  // compute (Jv)_x[A B v] - [G d(Jn)/dp 0]
  tmp->update(-1.0, input_null, 1.0);

  // verify underlying Jacobian is valid
  if (!group->isJacobian()) {
    status = group->computeJacobian();
    finalStatus = 
      globalData->locaErrorCheck->combineAndCheckReturnTypes(status, 
							     finalStatus,
							     callingFunction);
  }

  // Solve  |J   u||C D E| = |(Jv)_x A - G  (Jv)_x B - d(Jv)/dp  (Jv)_x v|
  //        |v^T 0||c d e|   |         0             0               0   |
  status = borderedSolver->applyInverse(params, tmp.get(), NULL, result_null,
					tmp_mat_2);
  finalStatus = 
    globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus,
							   callingFunction);
  Teuchos::RCP<NOX::Abstract::MultiVector> C = 
    result_null.subView(index_input);
  Teuchos::RCP<NOX::Abstract::MultiVector> D = 
    result_null.subView(index_dp);
  Teuchos::RCP<NOX::Abstract::MultiVector> E = 
    result_null.subView(index_null);
  double d = tmp_mat_2(0, m);
  double e = tmp_mat_2(0, m+1);

  // Fill coefficient arrays
  double M[9];
  M[0] = s;   M[1] =  e;  M[2] = -tpGroup->lTransNorm((*E)[0]);
  M[3] = 0.0; M[4] =  s;  M[5] =  tpGroup->lTransNorm(*nullVector);
  M[6] = b;   M[7] = -d;  M[8] =  tpGroup->lTransNorm((*D)[0]);

  // compute h + phi^T C
  tpGroup->lTransNorm(*C, result_param);
  result_param += input_param;

  double *R = new double[3*m];
  for (int i=0; i<m; i++) {
    R[3*i]   =  tmp_mat_1(0,i);
    R[3*i+1] = -tmp_mat_2(0,i);
    R[3*i+2] =  result_param(0,i);
  }

  // Solve M*P = R
  int three = 3;
  int piv[3];
  int info;
  Teuchos::LAPACK<int,double> L;
  L.GESV(three, m, M, three, piv, R, three, &info);
  if (info != 0) {
    globalData->locaErrorCheck->throwError(
				    callingFunction,
				    "Solve of 3x3 coefficient matrix failed!");
    return NOX::Abstract::Group::Failed;
  }

  NOX::Abstract::MultiVector::DenseMatrix alpha(1,m);
  NOX::Abstract::MultiVector::DenseMatrix beta(1,m);
  for (int i=0; i<m; i++) {
    alpha(0,i)        = R[3*i];
    beta(0,i)         = R[3*i+1];
    result_param(0,i) = R[3*i+2];
  }

  // compute A = A - B*z + v*alpha (remember A is a sub-view of result_x)
  A->update(Teuchos::NO_TRANS, -1.0, *B, result_param, 1.0);
  A->update(Teuchos::NO_TRANS, 1.0, *nullMultiVector, alpha, 1.0);

  // compute C = -C + d*z - E*alpha + v*beta 
  // (remember C is a sub-view of result_null)
  C->update(Teuchos::NO_TRANS, 1.0, *D, result_param, -1.0);
  C->update(Teuchos::NO_TRANS, -1.0, *E, alpha, 1.0);
  C->update(Teuchos::NO_TRANS, 1.0, *nullMultiVector, beta, 1.0);

  delete [] R;

  return finalStatus;
}
// Solves turning point equations via classic Salinger bordering
// The first m columns of input_x and input_null store the RHS while
// the last column stores df/dp, d(Jn)/dp respectively.  Note however
// input_param has only m columns (not m+1).  result_x, result_null,
// are result_param have the same dimensions as their input counterparts
NOX::Abstract::Group::ReturnType 
LOCA::TurningPoint::MooreSpence::PhippsBordering::solveTransposeContiguous(
		  Teuchos::ParameterList& params,
		  const NOX::Abstract::MultiVector& input_x,
		  const NOX::Abstract::MultiVector& input_null,
	          const NOX::Abstract::MultiVector::DenseMatrix& input_param,
		  NOX::Abstract::MultiVector& result_x,
		  NOX::Abstract::MultiVector& result_null,
	          NOX::Abstract::MultiVector::DenseMatrix& result_param) const
{
  std::string callingFunction = 
    "LOCA::TurningPoint::MooreSpence::PhippsBordering::solveTransposeContiguous()";
  NOX::Abstract::Group::ReturnType finalStatus = NOX::Abstract::Group::Ok;
  NOX::Abstract::Group::ReturnType status;

  int m = input_x.numVectors()-2;
  std::vector<int> index_input(m);
  std::vector<int> index_input_dp(m+1);
  std::vector<int> index_null(1);
  std::vector<int> index_dp(1);
  for (int i=0; i<m; i++) {
    index_input[i] = i;
    index_input_dp[i] = i;
  }
  index_input_dp[m] = m;
  index_dp[0] = m;
  index_null[0] = m+1;

  NOX::Abstract::MultiVector::DenseMatrix tmp_mat_1(1, m+1);
  NOX::Abstract::MultiVector::DenseMatrix tmp_mat_2(1, m+2);

  // Create view of first m+1 columns of input_null, result_null
  Teuchos::RCP<NOX::Abstract::MultiVector> input_null_view = 
      input_null.subView(index_input_dp);
  Teuchos::RCP<NOX::Abstract::MultiVector> result_null_view = 
      result_null.subView(index_input_dp);

  // verify underlying Jacobian is valid
  if (!group->isJacobian()) {
    status = group->computeJacobian();
    finalStatus = 
      globalData->locaErrorCheck->combineAndCheckReturnTypes(status, 
							     finalStatus,
							     callingFunction);
  }

  // Solve  |J^T v||A B| = |G -phi|
  //        |u^T 0||a b|   |0   0 |
  status =
    transposeBorderedSolver->applyInverseTranspose(params, 
						   input_null_view.get(), 
						   NULL, 
						   *result_null_view, 
						   tmp_mat_1);
  finalStatus = 
    globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus,
							   callingFunction);
  Teuchos::RCP<NOX::Abstract::MultiVector> A = 
    result_null.subView(index_input);
  Teuchos::RCP<NOX::Abstract::MultiVector> B = 
    result_null.subView(index_dp);
  double b = tmp_mat_1(0,m);

  // compute (Jv)_x^T[A B u]
  result_null[m+1] = *uVector;
  Teuchos::RCP<NOX::Abstract::MultiVector> tmp = 
    result_null.clone(NOX::ShapeCopy);
  status = group->computeDwtJnDxMulti(result_null, *nullVector, *tmp);
  finalStatus = 
    globalData->locaErrorCheck->combineAndCheckReturnTypes(status, 
							   finalStatus,
							   callingFunction);

  // compute [F 0 0] - (Jv)_x^T[A B u]
  tmp->update(1.0, input_x, -1.0);

  // verify underlying Jacobian is valid
  if (!group->isJacobian()) {
    status = group->computeJacobian();
    finalStatus = 
      globalData->locaErrorCheck->combineAndCheckReturnTypes(status, 
							     finalStatus,
							     callingFunction);
  }

  // Solve  |J^T v||C D E| = |F - (Jv)_x^T A  -(Jv)_x^T B  -(Jv)_x^T u|
  //        |u^T 0||c d e|   |         0             0            0   |
  status = 
    transposeBorderedSolver->applyInverseTranspose(params, 
						   tmp.get(), 
						   NULL, 
						   result_x,
						   tmp_mat_2);
  finalStatus = 
    globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus,
							   callingFunction);
  Teuchos::RCP<NOX::Abstract::MultiVector> C = 
    result_x.subView(index_input);
  Teuchos::RCP<NOX::Abstract::MultiVector> D = 
    result_x.subView(index_dp);
  Teuchos::RCP<NOX::Abstract::MultiVector> E = 
    result_x.subView(index_null);
  double d = tmp_mat_2(0, m);
  double e = tmp_mat_2(0, m+1);

  // compute (Jv)_p^T*[A B u]
  NOX::Abstract::MultiVector::DenseMatrix t1(1,m+2);
  result_null.multiply(1.0, *dJndp, t1);

  // compute f_p^T*[C D E]
  NOX::Abstract::MultiVector::DenseMatrix t2(1,m+2);
  result_x.multiply(1.0, *dfdp, t2);

  // compute f_p^T*u
  double fptu = uVector->innerProduct((*dfdp)[0]);

  // Fill coefficient arrays
  double M[9];
  M[0] = st;   M[1] =  -e;   M[2] = t1(0,m+1) + t2(0,m+1);
  M[3] = 0.0;  M[4] =   st;  M[5] = fptu;
  M[6] = -b;   M[7] =  -d;   M[8] = t1(0,m) + t2(0,m);

  // Compute RHS
  double *R = new double[3*m];
  for (int i=0; i<m; i++) {
    R[3*i]   = tmp_mat_1(0,i);
    R[3*i+1] = tmp_mat_2(0,i);
    R[3*i+2] = result_param(0,i) - t1(0,i) - t2(0,i);
  }

  // Solve M*P = R
  int three = 3;
  int piv[3];
  int info;
  Teuchos::LAPACK<int,double> L;
  L.GESV(three, m, M, three, piv, R, three, &info);
  if (info != 0) {
    globalData->locaErrorCheck->throwError(
				    callingFunction,
				    "Solve of 3x3 coefficient matrix failed!");
    return NOX::Abstract::Group::Failed;
  }

  NOX::Abstract::MultiVector::DenseMatrix alpha(1,m);
  NOX::Abstract::MultiVector::DenseMatrix beta(1,m);
  for (int i=0; i<m; i++) {
    alpha(0,i)        = R[3*i];
    beta(0,i)         = R[3*i+1];
    result_param(0,i) = R[3*i+2];
  }

  // compute A = A + B*z + alpha*u (remember A is a sub-view of result_null)
  A->update(Teuchos::NO_TRANS, 1.0, *B, result_param, 1.0);
  A->update(Teuchos::NO_TRANS, 1.0, *uMultiVector, alpha, 1.0);

  // compute C = C + D*z + alpha*E + beta*u 
  // (remember C is a sub-view of result_x)
  C->update(Teuchos::NO_TRANS, 1.0, *D, result_param, 1.0);
  C->update(Teuchos::NO_TRANS, 1.0, *E, alpha, 1.0);
  C->update(Teuchos::NO_TRANS, 1.0, *uMultiVector, beta, 1.0);

  delete [] R;

  return finalStatus;
}
Exemple #3
0
// Solves pitchfork equations via Phipps modified bordering
// The first m columns of input_x and input_null store the RHS,
// column m+1 stores df/dp, d(Jn)/dp, column m+2 stores psi and 0,
// and the last column provides space for solving (Jv_x) v.  Note however
// input_param has only m columns.  result_x, result_null,
// are result_param have the same dimensions as their input counterparts
NOX::Abstract::Group::ReturnType 
LOCA::Pitchfork::MooreSpence::PhippsBordering::solveContiguous(
		  Teuchos::ParameterList& params,
		  const NOX::Abstract::MultiVector& input_x,
		  const NOX::Abstract::MultiVector& input_null,
		  const NOX::Abstract::MultiVector::DenseMatrix& input_slack,
	          const NOX::Abstract::MultiVector::DenseMatrix& input_param,
		  NOX::Abstract::MultiVector& result_x,
		  NOX::Abstract::MultiVector& result_null,
		  NOX::Abstract::MultiVector::DenseMatrix& result_slack,
	          NOX::Abstract::MultiVector::DenseMatrix& result_param) const
{
  string callingFunction = 
    "LOCA::Pitchfork::MooreSpence::PhippsBordering::solveContiguous()";
  NOX::Abstract::Group::ReturnType finalStatus = NOX::Abstract::Group::Ok;
  NOX::Abstract::Group::ReturnType status;

  int m = input_x.numVectors()-3;
  vector<int> index_input(m);
  vector<int> index_input_dp(m+2);
  vector<int> index_null(1);
  vector<int> index_dp(1);
  vector<int> index_s(1);
  for (int i=0; i<m; i++) {
    index_input[i] = i;
    index_input_dp[i] = i;
  }
  index_input_dp[m] = m;
  index_input_dp[m+1] = m+1;
  index_dp[0] = m;
  index_s[0] = m+1;
  index_null[0] = m+2;

  NOX::Abstract::MultiVector::DenseMatrix tmp_mat_1(1, m+2);
  NOX::Abstract::MultiVector::DenseMatrix tmp_mat_2(1, m+3);

  // Create view of first m+2 columns of input_x, result_x
  Teuchos::RCP<NOX::Abstract::MultiVector> input_x_view = 
      input_x.subView(index_input_dp);
  Teuchos::RCP<NOX::Abstract::MultiVector> result_x_view = 
      result_x.subView(index_input_dp);

  // verify underlying Jacobian is valid
  if (!group->isJacobian()) {
    status = group->computeJacobian();
    finalStatus = 
      globalData->locaErrorCheck->combineAndCheckReturnTypes(status, 
							     finalStatus,
							     callingFunction);
  }
  
  // Solve  |J   u||A B C| = |F df/dp psi|
  //        |v^T 0||a b c|   |0   0    0 |
  status = borderedSolver->applyInverse(params, input_x_view.get(), NULL, 
					*result_x_view, tmp_mat_1);
  finalStatus = 
    globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus,
							   callingFunction);
  Teuchos::RCP<NOX::Abstract::MultiVector> A = 
    result_x.subView(index_input);
  Teuchos::RCP<NOX::Abstract::MultiVector> B = 
    result_x.subView(index_dp);
  Teuchos::RCP<NOX::Abstract::MultiVector> C = 
    result_x.subView(index_s);
  double b = tmp_mat_1(0,m);
  double c = tmp_mat_1(0,m+1);

  // compute (Jv)_x[A B C v]
  result_x[m+2] = *nullVector;
  Teuchos::RCP<NOX::Abstract::MultiVector> tmp = 
    result_x.clone(NOX::ShapeCopy);
  status = group->computeDJnDxaMulti(*nullVector, *JnVector, result_x,
				     *tmp);
  finalStatus = 
    globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus,
							   callingFunction);

  // compute [G d(Jn)/dp 0 0] - (Jv)_x[A B C v]
  tmp->update(1.0, input_null, -1.0);

  // verify underlying Jacobian is valid
  if (!group->isJacobian()) {
    status = group->computeJacobian();
    finalStatus = 
      globalData->locaErrorCheck->combineAndCheckReturnTypes(status, 
							     finalStatus,
							     callingFunction);
  }

  // Solve  |J   u||D E K L| = |G-(Jv)_xA  d(Jv)/dp-(Jv)_xB  -(Jv)_xC -(Jv)_xv|
  //        |v^T 0||d e k l|   |    0             0              0        0   |
  status = borderedSolver->applyInverse(params, tmp.get(), NULL, result_null,
					tmp_mat_2);
  finalStatus = 
    globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus,
							   callingFunction);
  Teuchos::RCP<NOX::Abstract::MultiVector> D = 
    result_null.subView(index_input);
  Teuchos::RCP<NOX::Abstract::MultiVector> E = 
    result_null.subView(index_dp);
  Teuchos::RCP<NOX::Abstract::MultiVector> K = 
    result_null.subView(index_s);
  Teuchos::RCP<NOX::Abstract::MultiVector> L = 
    result_null.subView(index_null);
  double e = tmp_mat_2(0, m);
  double k = tmp_mat_2(0, m+1);
  double l = tmp_mat_2(0, m+2);

  double ltE = pfGroup->lTransNorm((*E)[0]);
  double ltK = pfGroup->lTransNorm((*K)[0]);
  double ltL = pfGroup->lTransNorm((*L)[0]);
  double ltv = pfGroup->lTransNorm(*nullVector);
  double ipv = group->innerProduct(*nullVector, *asymVector);
  double ipB = group->innerProduct((*B)[0], *asymVector);
  double ipC = group->innerProduct((*C)[0], *asymVector);

  // Fill coefficient arrays
  double M[16];
  M[0]  = sigma; M[1]  = -l;     M[2]  =  ipv; M[3]  =  ltL;
  M[4]  = 0.0;   M[5]  =  sigma; M[6]  =  0.0; M[7]  =  ltv;
  M[8]  = b;     M[9]  =  e;     M[10] = -ipB; M[11] = -ltE;
  M[12] = c;     M[13] =  k;     M[14] = -ipC; M[15] = -ltK;

  // compute s - <A,psi>
  NOX::Abstract::MultiVector::DenseMatrix tmp_mat_3(1, m);
  group->innerProduct(*asymMultiVector, *A, tmp_mat_3);
  tmp_mat_3 -= input_slack;
  tmp_mat_3.scale(-1.0);

  // compute h - phi^T D
  NOX::Abstract::MultiVector::DenseMatrix tmp_mat_4(1, m);
  pfGroup->lTransNorm(*D, tmp_mat_4);
  tmp_mat_4 -= input_param;
  tmp_mat_4.scale(-1.0);

  double *R = new double[4*m];
  for (int i=0; i<m; i++) {
    R[4*i]   = tmp_mat_1(0,i);
    R[4*i+1] = tmp_mat_2(0,i);
    R[4*i+2] = tmp_mat_3(0,i);
    R[4*i+3] = tmp_mat_4(0,i);
  }

  // Solve M*P = R
  int piv[4];
  int info;
  Teuchos::LAPACK<int,double> dlapack;
  dlapack.GESV(4, m, M, 4, piv, R, 4, &info);
  if (info != 0) {
    globalData->locaErrorCheck->throwError(
				    callingFunction,
				    "Solve of 4x4 coefficient matrix failed!");
    return NOX::Abstract::Group::Failed;
  }

  NOX::Abstract::MultiVector::DenseMatrix alpha(1,m);
  NOX::Abstract::MultiVector::DenseMatrix beta(1,m);
  for (int i=0; i<m; i++) {
    alpha(0,i)        = R[4*i];
    beta(0,i)         = R[4*i+1];
    result_param(0,i) = R[4*i+2];
    result_slack(0,i) = R[4*i+3];
  }

  // compute A = A - B*z -C*w + v*alpha (remember A is a sub-view of result_x)
  A->update(Teuchos::NO_TRANS, -1.0, *B, result_param, 1.0);
  A->update(Teuchos::NO_TRANS, -1.0, *C, result_slack, 1.0);
  A->update(Teuchos::NO_TRANS, 1.0, *nullMultiVector, alpha, 1.0);

  // compute D = D - E*z - K*w + L*alpha + v*beta 
  // (remember D is a sub-view of result_null)
  D->update(Teuchos::NO_TRANS, -1.0, *E, result_param, 1.0);
  D->update(Teuchos::NO_TRANS, -1.0, *K, result_slack, 1.0);
  D->update(Teuchos::NO_TRANS, 1.0, *L, alpha, 1.0);
  D->update(Teuchos::NO_TRANS, 1.0, *nullMultiVector, beta, 1.0);

  delete [] R;

  return finalStatus;
}