MAST
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
multiphysics_nonlinear_solver.cpp
Go to the documentation of this file.
1 /*
2  * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit
3  * Copyright (C) 2013-2020 Manav Bhatia and MAST authors
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 
21 // MAST includes
25 #include "base/nonlinear_system.h"
26 
27 // libMesh includes
28 #include "libmesh/libmesh_logging.h"
29 #include "libmesh/dof_map.h"
30 #include "libmesh/petsc_matrix.h"
31 #include "libmesh/petsc_vector.h"
32 
33 
34 //---------------------------------------------------------------
35 // method for matrix vector multiplicaiton of the off-diagonal component y=Ax
36 struct
38  unsigned int i;
39  unsigned int j;
40  SNES snes;
42 };
43 
44 
45 PetscErrorCode
46 __mast_multiphysics_petsc_mat_mult(Mat mat,Vec dx,Vec y) {
47 
48  LOG_SCOPE("mat_mult()", "PetscNonlinearSolver");
49 
50  PetscErrorCode ierr=0;
51 
52  libmesh_assert(mat);
53  libmesh_assert(dx);
54  libmesh_assert(y);
55 
56 
57  void * ctx = PETSC_NULL;
58 
59  // get the matrix context. This is for the i^th row-block and j^th column
60  // block, which uses the linear perturbation in the j^th block.
61  ierr = MatShellGetContext(mat, &ctx);
62 
64  *mat_ctx = static_cast<__mast_multiphysics_petsc_shell_context*> (ctx);
65 
66 
68  *solver = mat_ctx->solver;
69 
70  // get the current nonlinear solution
71  Vec x;
72 
73  ierr = SNESGetSolution(mat_ctx->snes, &x); CHKERRABORT(solver->comm().get(), ierr);
74 
75 
76  const unsigned int
77  nd = solver->n_disciplines();
78 
79  std::vector<Vec>
80  sol (nd);
81 
82  std::vector<libMesh::NumericVector<Real>*>
83  sys_sols (nd, nullptr),
84  sys_dsols(nd, nullptr);
85 
86 
88  // get the subvectors for each discipline
90  for (unsigned int i=0; i< nd; i++) {
91 
92  // system for this discipline
94 
95  // get the IS for this system
96  IS sys_is = solver->index_sets()[i];
97 
98  // extract the subvector for this system
99  ierr = VecGetSubVector( x, sys_is, &sol[i]); CHKERRABORT(solver->comm().get(), ierr);
100 
101  // use the nonlinear sol of all disciplines, by the perturbed sol of only
102  // one should be nonzero.
103  sys_sols[i] = new libMesh::PetscVector<Real>( sol[i], sys.comm());
104  if (i == mat_ctx->j) {
105  sys_dsols[i] = new libMesh::PetscVector<Real>(dx, sys.comm());
106 
107  // Enforce constraints (if any) exactly on the
108  // current_local_solution. This is the solution vector that is
109  // actually used in the computation of the residual below, and is
110  // not locked by debug-enabled PETSc the way that "x" is.
111  sys.get_dof_map().enforce_constraints_exactly(sys, sys_dsols[i],
112  true /* homogeneous = true */);
113  }
114  else
115  sys_dsols[i] = sys_sols[i]->zero_clone().release();
116  }
117 
119  // initialize the data structures before calculation of residuals
121  if (solver->get_pre_residual_update_object())
123  sys_dsols);
124 
126  // calculate the matrix-vector product
128 
129  std::unique_ptr<libMesh::NumericVector<Real> >
130  res(new libMesh::PetscVector<Real>(y, solver->comm()));
131 
132  // system for this discipline
133  MAST::NonlinearSystem& sys = solver->get_system_assembly(mat_ctx->i).system();
134 
136  (*sys_sols [mat_ctx->i],
137  *sys_dsols[mat_ctx->i],
138  *res,
139  sys);
140 
141  res->close();
142 
144  // resotre the subvectors
146  for (unsigned int i=0; i< nd; i++) {
147 
148  // system for this discipline
150 
151  // get the IS for this system
152  IS sys_is = solver->index_sets()[i];
153 
154  // delete the NumericVector wrappers
155  delete sys_sols[i];
156  delete sys_dsols[i];
157 
158  // now restore the subvectors
159  ierr = VecRestoreSubVector(x, sys_is, &sol[i]); CHKERRABORT(solver->comm().get(), ierr);
160  }
161 
162  return ierr;
163 }
164 
165 
166 //---------------------------------------------------------------
167 // this function is called by PETSc to evaluate the residual at X
168 PetscErrorCode
169 __mast_multiphysics_petsc_snes_residual (SNES snes, Vec x, Vec r, void * ctx) {
170 
171  LOG_SCOPE("residual()", "PetscMultiphysicsNonlinearSolver");
172 
173  PetscErrorCode ierr=0;
174 
175  libmesh_assert(x);
176  libmesh_assert(r);
177  libmesh_assert(ctx);
178 
180  static_cast<MAST::MultiphysicsNonlinearSolverBase*> (ctx);
181 
182  const unsigned int
183  nd = solver->n_disciplines();
184 
185  std::vector<Vec>
186  sol(nd),
187  res(nd);
188 
189  std::vector<libMesh::NumericVector<Real>*>
190  sys_sols(nd, nullptr),
191  sys_res (nd, nullptr);
192 
193 
195  // get the subvectors for each discipline
197  for (unsigned int i=0; i< nd; i++) {
198 
199  // system for this discipline
201 
202  // get the IS for this system
203  IS sys_is = solver->index_sets()[i];
204 
205  // extract the subvector for this system
206  ierr = VecGetSubVector(x, sys_is, &sol[i]); CHKERRABORT(solver->comm().get(), ierr);
207  ierr = VecGetSubVector(r, sys_is, &res[i]); CHKERRABORT(solver->comm().get(), ierr);
208 
209  sys_sols[i] = new libMesh::PetscVector<Real>(sol[i], sys.comm()),
210  sys_res[i] = new libMesh::PetscVector<Real>(res[i], sys.comm());
211 
212  // Enforce constraints (if any) exactly on the
213  // current_local_solution. This is the solution vector that is
214  // actually used in the computation of the residual below, and is
215  // not locked by debug-enabled PETSc the way that "x" is.
216  sys.get_dof_map().enforce_constraints_exactly(sys, sys_sols[i]);
217  }
218 
220  // initialize the data structures before calculation of residuals
222  if (solver->get_pre_residual_update_object())
224 
226  // calculate the residuals
228  std::vector<Real>
229  l2_norms(nd, 0.);
230 
231  Real
232  global_l2 = 0.;
233 
234  for (unsigned int i=0; i< nd; i++) {
235 
236  // system for this discipline
238 
239  solver->get_system_assembly(i).residual_and_jacobian (*sys_sols[i],
240  sys_res[i],
241  nullptr,
242  sys);
243 
244  sys_res[i]->close();
245 
246  // now calculate the norms
247  l2_norms[i] = sys_res[i]->l2_norm();
248  global_l2 += pow(l2_norms[i], 2);
249  }
250 
251  global_l2 = pow(global_l2, 0.5);
252 
253  // write the global and component-wise l2 norms of the residual
254  libMesh::out
255  << "|| R ||_2 = " << global_l2 << " : || R_i ||_2 = ( ";
256  for (unsigned int i=0; i<nd; i++) {
257  libMesh::out << l2_norms[i];
258  if (i < nd-1)
259  libMesh::out << " , ";
260  }
261  libMesh::out << " )" << std::endl;
262 
264  // resotre the subvectors
266  for (unsigned int i=0; i< nd; i++) {
267 
268  // get the IS for this system
269  IS sys_is = solver->index_sets()[i];
270 
271  // delete the NumericVector wrappers
272  delete sys_sols[i];
273  delete sys_res[i];
274 
275  // now restore the subvectors
276  ierr = VecRestoreSubVector(x, sys_is, &sol[i]); CHKERRABORT(solver->comm().get(), ierr);
277  ierr = VecRestoreSubVector(r, sys_is, &res[i]); CHKERRABORT(solver->comm().get(), ierr);
278  }
279 
280  return ierr;
281 }
282 
283 
284 
285 //---------------------------------------------------------------
286 // this function is called by PETSc to evaluate the Jacobian at X
287 PetscErrorCode
288 __mast_multiphysics_petsc_snes_jacobian(SNES snes, Vec x, Mat jac, Mat pc, void * ctx)
289 {
290  LOG_SCOPE("jacobian()", "PetscMultiphysicsNonlinearSolver");
291 
292  PetscErrorCode ierr=0;
293 
294  libmesh_assert(x);
295  libmesh_assert(jac);
296  libmesh_assert(pc);
297  libmesh_assert(ctx);
298 
299 
301  static_cast<MAST::MultiphysicsNonlinearSolverBase*> (ctx);
302 
303  const unsigned int
304  nd = solver->n_disciplines();
305 
306  std::vector<Vec>
307  sol(nd);
308 
309  std::vector<libMesh::NumericVector<Real>*>
310  sys_sols(nd, nullptr);
311 
312 
314  // get the subvectors for each discipline
316  for (unsigned int i=0; i< nd; i++) {
317 
318  // system for this discipline
320 
321  // get the IS for this system
322  IS sys_is = solver->index_sets()[i];
323 
324  // extract the subvector for this system
325  ierr = VecGetSubVector(x, sys_is, &sol[i]); CHKERRABORT(solver->comm().get(), ierr);
326 
327  sys_sols[i] = new libMesh::PetscVector<Real>(sol[i], sys.comm());
328 
329 
330  // Enforce constraints (if any) exactly on the
331  // current_local_solution. This is the solution vector that is
332  // actually used in the computation of the residual below, and is
333  // not locked by debug-enabled PETSc the way that "x" is.
334  sys.get_dof_map().enforce_constraints_exactly(sys, sys_sols[i]);
335  }
336 
337 
339  // initialize the data structures before calculation of residuals
341  if (solver->get_pre_residual_update_object())
343 
345  // calculate the residuals
347  for (unsigned int i=0; i< nd; i++) {
348 
349  // system for this discipline
351 
352  //PetscMatrix<Number> PC(pc, sys.comm());
353  //PC.attach_dof_map(sys.get_dof_map());
354  //PC.close();
355 
356  solver->get_system_assembly(i).residual_and_jacobian (*sys_sols[i],
357  nullptr,
358  sys.matrix,
359  sys);
360 
361  sys.matrix->close();
362  }
363 
365  // resotre the subvectors
367  for (unsigned int i=0; i< nd; i++) {
368 
369  // get the IS for this system
370  IS sys_is = solver->index_sets()[i];
371 
372  // delete the NumericVector wrappers
373  delete sys_sols[i];
374 
375  // now restore the subvectors
376  ierr = VecRestoreSubVector(x, sys_is, &sol[i]); CHKERRABORT(solver->comm().get(), ierr);
377  }
378 
379 
380  // call assembly of the global matrix
381  ierr = MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY); CHKERRABORT(solver->comm().get(), ierr);
382  ierr = MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY); CHKERRABORT(solver->comm().get(), ierr);
383 
384 
385  return ierr;
386 }
387 
388 
389 
390 
391 
393 MultiphysicsNonlinearSolverBase(const libMesh::Parallel::Communicator& comm_in,
394  const std::string& nm,
395  unsigned int n):
396 libMesh::ParallelObject (comm_in),
397 _name (nm),
398 _n_disciplines (n),
399 _update (nullptr),
400 _discipline_assembly (n, nullptr),
401 _is (_n_disciplines, PETSC_NULL),
402 _sub_mats (_n_disciplines*_n_disciplines, PETSC_NULL),
403 _n_dofs (0) {
404 
405 }
406 
407 
408 
409 
410 
412 
413 }
414 
415 
416 
417 
418 void
420 set_system_assembly(unsigned int i,
421  MAST::TransientAssembly& assembly) {
422 
423  // make sure that the index is within bounds
424  libmesh_assert_less(i, _n_disciplines);
425 
426  // also make sure that the specific discipline has not been set already
427  libmesh_assert(!_discipline_assembly[i]);
428 
429  _discipline_assembly[i] = &assembly;
430 }
431 
432 
433 
436 get_system_assembly(unsigned int i) {
437 
438  // make sure that the index is within bounds
439  libmesh_assert_less(i, _n_disciplines);
440 
441  // also make sure that the specific discipline has not been set already
442  libmesh_assert(_discipline_assembly[i]);
443 
444  return *_discipline_assembly[i];
445 }
446 
447 
448 
449 void
451 
452 
453  // make sure that all systems have been specified
454  bool p = true;
455  for (unsigned int i=0; i<_n_disciplines; i++)
456  p = ((_discipline_assembly[i] != nullptr) && p);
457  libmesh_assert(p);
458 
459 
461  // create the solver context. This will be partially initialized now
462  // since it is needed in the shell matrix context
464  PetscErrorCode ierr;
465  SNES snes;
466 
467  // setup the solver context
468  ierr = SNESCreate(this->comm().get(), &snes); CHKERRABORT(this->comm().get(), ierr);
469 
471  // create a petsc nested matrix of size NxN
473  const bool sys_name = libMesh::on_command_line("--solver_system_names");
474  std::string nm;
475  unsigned int n_local_dofs = 0;
476  std::vector<__mast_multiphysics_petsc_shell_context>
477  mat_ctx(_n_disciplines*_n_disciplines);
478 
479 
480  // all diagonal blocks use the system matrcices, while shell matrices
481  // are created for the off-diagonal terms.
482  _n_dofs = 0.;
483  for (unsigned int i=0; i<_n_disciplines; i++) {
484 
485  MAST::NonlinearSystem& sys = _discipline_assembly[i]->system();
486 
487  // add the number of dofs in this system to the global count
488  _n_dofs += sys.n_dofs();
489  n_local_dofs += sys.n_local_dofs();
490 
491  for (unsigned int j=0; j<_n_disciplines; j++) {
492 
493  if (i==j) {
494 
495  // the diagonal matrix
496  _sub_mats[i*_n_disciplines+j] =
497  dynamic_cast<libMesh::PetscMatrix<Real>*>(sys.matrix)->mat();
498  }
499  else {
500 
501  MAST::NonlinearSystem& sys_j = _discipline_assembly[j]->system();
502 
503  PetscInt
504  mat_i_m = sys.get_dof_map().n_dofs(),
505  mat_i_n_l = sys.get_dof_map().n_dofs_on_processor(sys.processor_id()),
506  mat_j_m = sys_j.get_dof_map().n_dofs(),
507  mat_j_n_l = sys_j.get_dof_map().n_dofs_on_processor(sys.processor_id());
508 
509  // the off-diagonal matrix
510  ierr = MatCreateShell(this->comm().get(),
511  mat_i_n_l,
512  mat_j_n_l,
513  mat_i_m,
514  mat_j_m,
515  PETSC_NULL,
516  &_sub_mats[i*_n_disciplines+j]);
517  CHKERRABORT(this->comm().get(), ierr);
518 
519  // initialize the context and tell the matrix about it
520  mat_ctx[i*_n_disciplines+j].i = i;
521  mat_ctx[i*_n_disciplines+j].j = j;
522  mat_ctx[i*_n_disciplines+j].snes = snes;
523  mat_ctx[i*_n_disciplines+j].solver = this;
524 
525  ierr = MatShellSetContext(_sub_mats[i*_n_disciplines+j],
526  &mat_ctx[i*_n_disciplines+j]);
527  CHKERRABORT(this->comm().get(), ierr);
528 
529  // set the mat-vec multiplication operation for this
530  // shell matrix
531  ierr = MatShellSetOperation(_sub_mats[i*_n_disciplines+j],
532  MATOP_MULT,
533  (void(*)(void))__mast_multiphysics_petsc_mat_mult);
534  CHKERRABORT(this->comm().get(), ierr);
535  }
536  }
537  }
538 
539 
540  ierr = MatCreateNest(this->comm().get(),
541  _n_disciplines, PETSC_NULL,
542  _n_disciplines, PETSC_NULL,
543  &_sub_mats[0],
544  &_mat);
545  CHKERRABORT(this->comm().get(), ierr);
546 
547  // we need to turn off MULT_TRANSPOSE operator for the global matrix
548  // since that is not implemented for the shell matrices pushes PETSc 3.7.4
549  // to produce an error about it.
550  ierr = MatShellSetOperation(_mat,
551  MATOP_MULT_TRANSPOSE,
552  PETSC_NULL);
553  CHKERRABORT(this->comm().get(), ierr);
554 
555  if (sys_name) {
556 
557  nm = this->name() + "_";
558  MatSetOptionsPrefix(_mat, nm.c_str());
559  }
560  ierr = MatSetFromOptions(_mat);
561  CHKERRABORT(this->comm().get(), ierr);
562 
563  // get the IS belonging to each block
564  ierr = MatNestGetISs(_mat, &_is[0], PETSC_NULL);
565  CHKERRABORT(this->comm().get(), ierr);
566 
568  // setup the vector for solution
570  ierr = VecCreate(this->comm().get(), &_sol); CHKERRABORT(this->comm().get(), ierr);
571  ierr = VecSetSizes(_sol, n_local_dofs, _n_dofs); CHKERRABORT(this->comm().get(), ierr);
572  ierr = VecSetType(_sol, VECMPI); CHKERRABORT(this->comm().get(), ierr);
573  ierr = VecDuplicate(_sol, &_res); CHKERRABORT(this->comm().get(), ierr);
574 
575  ierr = MatShellSetOperation(_mat,
576  MATOP_MULT_TRANSPOSE_ADD,
577  PETSC_NULL);
578  CHKERRABORT(this->comm().get(), ierr);
579  ierr = MatShellSetOperation(_mat,
580  MATOP_TRANSPOSE,
581  PETSC_NULL);
582  CHKERRABORT(this->comm().get(), ierr);
583 
585  // now initialize the vector from the system solutions, which will serve
586  // as the initial solution for the coupled system
588  for (unsigned int i=0; i<_n_disciplines; i++) {
589 
590  // solution from the provided system
591  libMesh::NumericVector<Real>
592  &sys_sol = *_discipline_assembly[i]->system().solution;
593 
594  // limiting indices for the system, and multiphysics assembly. Should
595  // be the same
596  int
597  multiphysics_first = 0,
598  multiphysics_last = 0,
599  first = sys_sol.first_local_index(),
600  last = sys_sol.last_local_index();
601 
602  // get the subvector corresponding to the the discipline
603  Vec sub_vec;
604 
605  ierr = VecGetSubVector(_sol, _is[i], &sub_vec); CHKERRABORT(this->comm().get(), ierr);
606  ierr = VecGetOwnershipRange(sub_vec,
607  &multiphysics_first,
608  &multiphysics_last); CHKERRABORT(this->comm().get(), ierr);
609 
610  // the first and last indices must match between the two representations
611  libmesh_assert_equal_to(multiphysics_first, first);
612  libmesh_assert_equal_to( multiphysics_last, last);
613 
614  std::unique_ptr<libMesh::NumericVector<Real> >
615  multiphysics_sol(new libMesh::PetscVector<Real>(sub_vec, this->comm()));
616 
617  for (unsigned int i=first; i<last; i++)
618  multiphysics_sol->set(i, sys_sol(i));
619 
620  multiphysics_sol->close();
621 
622  ierr = VecRestoreSubVector(_sol, _is[i], &sub_vec); CHKERRABORT(this->comm().get(), ierr);
623  }
624 
625 
626 
627 
629  // initialize the solver context
631  KSP ksp;
632  PC pc;
633 
634 
635 
636  // tell the solver where to store the Jacobian and how to calculate it
637  ierr = SNESSetFunction (snes,
638  _res,
640  this);
641  ierr = SNESSetJacobian(snes,
642  _mat,
643  _mat,
645  this);
646 
647 
648  if (sys_name) {
649 
650  nm = this->name() + "_";
651  SNESSetOptionsPrefix(snes, nm.c_str());
652  }
653 
654 
655 
656  // setup the ksp
657  ierr = SNESGetKSP (snes, &ksp); CHKERRABORT(this->comm().get(), ierr);
658  ierr = SNESSetFromOptions(snes); CHKERRABORT(this->comm().get(), ierr);
659 
660 
661 
662  // setup the pc
663  ierr = KSPGetPC(ksp, &pc); CHKERRABORT(this->comm().get(), ierr);
664 
665  for (unsigned int i=0; i<_n_disciplines; i++) {
666 
667  if (sys_name) {
668 
669  nm = _discipline_assembly[i]->system().name();
670  ierr = PCFieldSplitSetIS(pc, nm.c_str(), _is[i]); CHKERRABORT(this->comm().get(), ierr);
671  }
672  else
673  ierr = PCFieldSplitSetIS(pc, nullptr, _is[i]);CHKERRABORT(this->comm().get(), ierr);
674  }
675 
676 
677  //ierr = SNESSetSolution(snes, _sol);
678  //this->verify_gateaux_derivatives(snes);
679 
681  // now, solve
683  START_LOG("SNESSolve", this->name()+"_MultiphysicsSolve");
684 
685  // now solve
686  ierr = SNESSolve(snes, PETSC_NULL, _sol);
687 
688  STOP_LOG("SNESSolve", this->name()+"_MultiphysicsSolve");
689 
690 
692  // now copy the solution back to the system solution vector
694  for (unsigned int i=0; i<_n_disciplines; i++) {
695 
696  // solution from the provided system
697  libMesh::NumericVector<Real>
698  &sys_sol = *_discipline_assembly[i]->system().solution;
699 
700  // limiting indices for the system, and multiphysics assembly. Should
701  // be the same
702  int
703  multiphysics_first = 0,
704  multiphysics_last = 0,
705  first = sys_sol.first_local_index(),
706  last = sys_sol.last_local_index();
707 
708  // get the subvector corresponding to the the discipline
709  Vec sub_vec;
710 
711  ierr = VecGetSubVector(_sol, _is[i], &sub_vec); CHKERRABORT(this->comm().get(), ierr);
712  ierr = VecGetOwnershipRange(sub_vec,
713  &multiphysics_first,
714  &multiphysics_last); CHKERRABORT(this->comm().get(), ierr);
715 
716  // the first and last indices must match between the two representations
717  libmesh_assert_equal_to(multiphysics_first, first);
718  libmesh_assert_equal_to( multiphysics_last, last);
719 
720  std::unique_ptr<libMesh::NumericVector<Real> >
721  multiphysics_sol(new libMesh::PetscVector<Real>(sub_vec, this->comm()));
722 
723  for (unsigned int i=first; i<last; i++)
724  sys_sol.set(i, (*multiphysics_sol)(i));
725 
726  ierr = VecRestoreSubVector(_sol, _is[i], &sub_vec); CHKERRABORT(this->comm().get(), ierr);
727  }
728 
729 
730 
731  // destroy the Petsc contexts
732  ierr = SNESDestroy(&snes); CHKERRABORT(this->comm().get(), ierr);
733  for (unsigned int i=0; i<_n_disciplines; i++)
734  for (unsigned int j=0; j<_n_disciplines; j++)
735  if (i != j) {
736  ierr = MatDestroy(&_sub_mats[i*_n_disciplines+j]);
737  CHKERRABORT(this->comm().get(), ierr);
738  }
739 
740  ierr = MatDestroy(&_mat); CHKERRABORT(this->comm().get(), ierr);
741  ierr = VecDestroy(&_sol); CHKERRABORT(this->comm().get(), ierr);
742  ierr = VecDestroy(&_res); CHKERRABORT(this->comm().get(), ierr);
743 
744 }
745 
746 
747 
748 
749 void
751 
752  PetscErrorCode ierr=0;
753 
754  // create vectors for the sol, dsol, and res of the global and
755  // disciplinary systems
756  std::unique_ptr<libMesh::NumericVector<Real> >
757  global_sol (new libMesh::PetscVector<Real>(_sol, this->comm())),
758  global_res (new libMesh::PetscVector<Real>(_res, this->comm())),
759  global_res0 (global_sol->zero_clone().release());
760 
761  // first calculate the baseline residual for the global solution vector
763  _sol,
764  dynamic_cast<libMesh::PetscVector<Real>*>(global_res0.get())->vec(),
765  this);
766 
767  // value of perturbation used
768  const Real
769  delta = 1.0e-4;
770 
771  // now, iterate over each dof on the disciplines, and calculate the
772  // Gateaux derivative
773  for (unsigned int i=0; i<_n_disciplines; i++) {
774 
775  // system for this discipline
777 
778  // get the IS for this system
779  IS sys_is_i = this->index_sets()[i];
780 
781  // verify the derivative wrt dofs from other disciplines
782  for (unsigned int j=0; j<_n_disciplines; j++) {
783 
784  if (i != j) {
785 
786  IS sys_is_j = this->index_sets()[j];
787 
788  // system for this discipline
790 
791  std::unique_ptr<libMesh::NumericVector<Real> >
792  dsol_j (sys_j.solution->zero_clone().release()),
793  dJac_ij_dXj(sys_i.solution->zero_clone().release());
794 
795  for (unsigned int k=0; k<sys_j.n_dofs(); k++) {
796 
797  dsol_j->zero();
798  dsol_j->add(k, delta);
799  dsol_j->close();
800 
801  Vec
802  vecx = dynamic_cast<libMesh::PetscVector<Real>*>(dsol_j.get())->vec(),
803  vecy = dynamic_cast<libMesh::PetscVector<Real>*>(dJac_ij_dXj.get())->vec();
804 
805  __mast_multiphysics_petsc_mat_mult(_sub_mats[i*_n_disciplines+j], vecx, vecy);
806 
807  // now perform the same calculation with the finite differencing
808  // using residual calculation
809  // extract the subvector for this system
810  Vec
811  res_i,
812  sol_j;
813  ierr = VecGetSubVector(_sol, sys_is_j, &sol_j); CHKERRABORT(this->comm().get(), ierr);
814 
815  Real
816  old_val = 0.;
817 
818  // create a vector for modification of the ith value of this solution
819  {
820  libMesh::PetscVector<Real> v(sol_j, this->comm());
821 
822  // perturb the solution vector
823  old_val = v.el(k);
824  v.add(k, delta);
825  v.close();
826  }
827 
828  ierr = VecRestoreSubVector( _sol, sys_is_j, &sol_j); CHKERRABORT(this->comm().get(), ierr);
829 
830  // now calculate the residual
832  _sol,
833  _res,
834  this);
835 
836  // reset the global solution vector
837  ierr = VecGetSubVector(_sol, sys_is_j, &sol_j); CHKERRABORT(this->comm().get(), ierr);
838 
839  // create a vector for modification of the ith value of this solution
840  {
841  libMesh::PetscVector<Real> v(sol_j, this->comm());
842 
843  // perturb the solution vector
844  v.set(k, old_val);
845  v.close();
846  }
847 
848  ierr = VecRestoreSubVector( _sol, sys_is_j, &sol_j); CHKERRABORT(this->comm().get(), ierr);
849 
850  global_res->close();
851  global_res->add(-1., *global_res0);
852  global_res->close();
853 
854 
855  // get the finite differenced residual
856  ierr = VecGetSubVector(_res, sys_is_i, &res_i); CHKERRABORT(this->comm().get(), ierr);
857 
858  // create a vector for comparison
859  {
860  libMesh::PetscVector<Real> v(res_i, this->comm());
861  for (unsigned int l=0; l<sys_i.n_dofs(); l++) {
862 
863  if (dJac_ij_dXj->el(l) != v.el(l))
864  libMesh::out
865  << k << " "
866  << l << " "
867  << dJac_ij_dXj->el(l) << " "
868  << v.el(l) << std::endl;
869  }
870 
871  libMesh::out << std::endl;
872  }
873 
874  ierr = VecRestoreSubVector( _res, sys_is_i, &res_i); CHKERRABORT(this->comm().get(), ierr);
875 
876  }
877  }
878  }
879  }
880 }
881 
882 
883 
const MAST::NonlinearSystem & system() const
MultiphysicsNonlinearSolverBase(const libMesh::Parallel::Communicator &comm_in, const std::string &nm, unsigned int n)
default constructor
MAST::MultiphysicsNonlinearSolverBase * solver
This class implements a system for solution of nonlinear systems.
virtual void update_at_solution(std::vector< libMesh::NumericVector< Real > *> &sol_vecs)=0
sol_vecs is the vector containing the solution for each discipline in this multiphysics solution ...
virtual void update_at_perturbed_solution(std::vector< libMesh::NumericVector< Real > *> &sol_vecs, std::vector< libMesh::NumericVector< Real > *> &dsol_vecs)=0
sol_vecs is the vector containing the solution for each discipline in this multiphysics solution...
PetscErrorCode __mast_multiphysics_petsc_snes_residual(SNES snes, Vec x, Vec r, void *ctx)
libMesh::Real Real
PetscErrorCode __mast_multiphysics_petsc_snes_jacobian(SNES snes, Vec x, Mat jac, Mat pc, void *ctx)
virtual void linearized_jacobian_solution_product(const libMesh::NumericVector< Real > &X, const libMesh::NumericVector< Real > &dX, libMesh::NumericVector< Real > &JdX, libMesh::NonlinearImplicitSystem &S)
calculates the product of the Jacobian and a perturbation in solution vector .
std::vector< MAST::TransientAssembly * > _discipline_assembly
vector of assembly objects for each discipline in this multiphysics system
const unsigned int _n_disciplines
number of disciplines
PetscErrorCode __mast_multiphysics_petsc_mat_mult(Mat mat, Vec dx, Vec y)
MAST::TransientAssembly & get_system_assembly(unsigned int i)
MAST::MultiphysicsNonlinearSolverBase::PreResidualUpdate * get_pre_residual_update_object()
returns a pointer to the update object
virtual void residual_and_jacobian(const libMesh::NumericVector< Real > &X, libMesh::NumericVector< Real > *R, libMesh::SparseMatrix< Real > *J, libMesh::NonlinearImplicitSystem &S)
function that assembles the matrices and vectors quantities for nonlinear solution ...
void solve()
solves the system using the nested matrices that uses the discipline specific solver options ...
void set_system_assembly(unsigned int i, MAST::TransientAssembly &assembly)
method to set the n^th discipline of this multiphysics system assembly.