8#include <petsc/private/taoimpl.h>
9#include <petsc/private/taolinesearchimpl.h>
17constexpr char nullSpaceContextKey[] =
"_MoFEM_TaoNullSpace";
18constexpr char nullSpaceLineSearch[] =
"nullspace";
23 ls->ops->setup =
nullptr;
24 ls->ops->reset =
nullptr;
25 ls->ops->monitor =
nullptr;
26 ls->ops->view =
nullptr;
27 ls->ops->destroy =
nullptr;
28 ls->ops->setfromoptions =
nullptr;
29 ls->ops->apply = [](TaoLineSearch ls,
Vec x, PetscReal *
f,
Vec g,
32 if (!std::isfinite(ls->initstep) || !(ls->initstep > 0) ||
34 SETERRQ(PetscObjectComm(
getPetscObject(ls)), PETSC_ERR_ARG_OUTOFRANGE,
35 "Null-space backtracking requires positive stepinit and "
40 CHKERR VecCopy(
g, start_gradient);
41 const auto initial_value = *
f;
42 CHKERR TaoLineSearchMonitor(ls, 0, *f, 0);
43 ls->step = std::min(ls->initstep, ls->stepmax);
44 ls->reason = TAOLINESEARCH_HALTED_LOWERBOUND;
45 for (PetscInt trial = 1;
46 trial <= ls->max_funcs && ls->step >= ls->stepmin && ls->step > 0;
47 ++trial, ls->step *= 0.5) {
48 CHKERR VecWAXPY(x, ls->step, direction, start);
49 CHKERR TaoLineSearchComputeObjective(ls, x, f);
52 CHKERR TaoLineSearchMonitor(ls, trial, *f, ls->step);
53 if (std::isfinite(*f) && std::abs(*f) < PETSC_INFINITY &&
54 (*f < initial_value || trial == ls->max_funcs)) {
57 CHKERR TaoLineSearchComputeObjectiveAndGradient(ls, x, f,
g);
59 CHKERR VecNorm(
g, NORM_2, &norm);
60 if (std::isfinite(*f) && std::abs(*f) < PETSC_INFINITY &&
61 std::isfinite(norm)) {
62 ls->reason = *
f < initial_value ? TAOLINESEARCH_SUCCESS
63 : TAOLINESEARCH_SUCCESS_USER;
64 if (ls->reason == TAOLINESEARCH_SUCCESS_USER)
65 CHKERR PetscInfo(ls,
"Null-space backtracking accepted the final "
66 "finite trial without merit decrease\n");
70 if (trial == ls->max_funcs) {
71 ls->reason = TAOLINESEARCH_HALTED_MAXFCN;
77 CHKERR VecCopy(start_gradient,
g);
89 CHKERR TaoGetSolution(tao, &x);
90 CHKERR TaoGetGradient(tao, &
g,
nullptr,
nullptr);
91 PetscReal objective, norm, step;
92 CHKERR TaoComputeObjectiveAndGradient(tao, x, &objective,
g);
93 CHKERR VecNorm(
g, NORM_2, &norm);
94 CHKERR TaoSetConvergedReason(tao, TAO_CONTINUE_ITERATING);
95 CHKERR TaoSetIterationNumber(tao, 0);
96 CHKERR TaoLogConvergenceHistory(tao, objective, norm, 0, 0);
97 CHKERR TaoMonitor(tao, 0, objective, norm, 0, 0);
100 CHKERR VecScale(direction, -1);
102 CHKERR TaoGetLineSearch(tao, &ls);
103 CHKERR TaoLineSearchUseTaoRoutines(ls, tao);
104 TaoLineSearchConvergedReason ls_reason;
105 CHKERR TaoLineSearchApply(ls, x, &objective,
g, direction, &step, &ls_reason);
106 tao->lsflag = ls_reason > 0 ? PETSC_FALSE : PETSC_TRUE;
107 CHKERR TaoAddLineSearchCounts(tao);
108 CHKERR VecNorm(
g, NORM_2, &norm);
109 CHKERR TaoSetIterationNumber(tao, 1);
110 CHKERR TaoSetConvergedReason(tao, ls_reason > 0 ? TAO_CONVERGED_USER
111 : TAO_DIVERGED_LS_FAILURE);
112 CHKERR TaoLogConvergenceHistory(tao, objective, norm, 0, 0);
113 CHKERR TaoMonitor(tao, 1, objective, norm, 0, step);
118struct NullSpaceRows {
128 const std::vector<PetscInt> &indices) {
130 *
this = NullSpaceRows();
133 CHKERR ISCreateGeneral(
comm, indices.size(), indices.data(),
134 PETSC_COPY_VALUES, &is);
135 rows = SmartPetscObj<IS>(is);
139 CHKERR MatCreateSubMatrix(full_jacobian,
rows, columns,
140 MAT_INITIAL_MATRIX, &matrix);
141 jacobian = SmartPetscObj<Mat>(matrix);
144 values = SmartPetscObj<Vec>(vector);
154 CHKERR VecGetSubVector(full, rows, &sub);
155 CHKERR VecCopy(sub, selected);
156 CHKERR VecRestoreSubVector(full, rows, &sub);
161 const std::string &prefix,
162 PetscOptions options) {
170 CHKERR PCSetType(pc, PCLU);
171 CHKERR PCFactorSetMatSolverType(pc, MATSOLVERMUMPS);
172 CHKERR KSPSetTolerances(
ksp, 1e-12, 1e-14, PETSC_DEFAULT, 1000);
173 CHKERR KSPSetOptionsPrefix(
ksp, prefix.c_str());
178 CHKERR MatCreateVecs(jacobian, &vector,
nullptr);
179 SmartPetscObj<Vec> column_vector(vector);
181 CHKERR VecScatterCreate(control, columns, column_vector, columns, &scatter);
182 SmartPetscObj<VecScatter> identity(scatter);
221 PetscErrorCode (*applyLineSearch)(TaoLineSearch, Vec, PetscReal *, Vec,
223 PetscErrorCode (*destroyShell)(Tao) =
nullptr;
228 if (tao->eq_constrained || tao->bounded || tao->ineq_doublesided ||
229 tao->ops->computebounds || tao->ops->computeconstraints)
231 "TAONULLSPACE currently requires constraints in c_i >= 0 form; "
232 "separate equality constraints and bounds are unsupported");
234 SETERRQ(PetscObjectComm(
getPetscObject(tao)), PETSC_ERR_ARG_WRONGSTATE,
235 "Call TaoNullSpaceSetConstraints before TaoSetUp");
236 Vec solution =
nullptr;
237 CHKERR TaoGetSolution(tao, &solution);
250 CHKERR ::TaoSetGradient(tao,
stationarity,
nullptr,
nullptr);
251 CHKERR VecDestroy(&tao->stepdirection);
255 PetscInt first, last;
263 CHKERR ::TaoSetObjective(
265 [](Tao, Vec x, PetscReal *objective,
void *ctx) {
266 return static_cast<TaoNullSpace *
>(ctx)->evaluateSubObjective(
270 CHKERR ::TaoSetGradient(
272 [](Tao, Vec x, Vec
g,
void *ctx) {
273 return static_cast<TaoNullSpace *
>(ctx)->evaluateSubGradient(x,
g);
276 CHKERR ::TaoSetObjectiveAndGradient(
278 [](Tao, Vec x, PetscReal *objective, Vec
g,
void *ctx) {
279 return static_cast<TaoNullSpace *
>(ctx)->evaluateSubProblem(
290 CHKERR TaoComputeObjectiveAndGradient(parentTao, solution, &objective,
g);
292 CHKERR TaoComputeObjective(parentTao, solution, &objective);
295 if (!std::isfinite(objective) || std::abs(objective) >= PETSC_INFINITY)
297 CHKERR TaoComputeInequalityConstraints(parentTao, solution, constraints);
298 PetscReal constraint_norm;
299 CHKERR VecNorm(constraints, NORM_2, &constraint_norm);
300 if (!std::isfinite(constraint_norm)) {
301 objective = PETSC_INFINITY;
305 PetscReal gradient_norm;
306 CHKERR VecNorm(
g, NORM_2, &gradient_norm);
307 if (!std::isfinite(gradient_norm)) {
308 objective = PETSC_INFINITY;
311 CHKERR TaoComputeJacobianInequality(parentTao, solution, jacobian,
320 if (candidates.size) {
333 CHKERR VecZeroEntries(lower);
334 CHKERR VecSet(upper, PETSC_INFINITY);
335 CHKERR TaoSetType(dual, TAOBLMVM);
337 CHKERR TaoSetVariableBounds(dual, lower, upper);
338 CHKERR ::TaoSetObjectiveAndGradient(
340 [](Tao, Vec
mu, PetscReal *f, Vec
g,
void *ctx) {
342 auto *problem =
static_cast<DualProblem *
>(ctx);
343 CHKERR MatMultTranspose(problem->jacobian,
mu, problem->residual);
344 CHKERR VecAXPY(problem->residual, -1, problem->gradient);
346 CHKERR VecDot(problem->residual, problem->residual, &squared);
347 *
f = 0.5 * PetscRealPart(squared);
348 CHKERR MatMult(problem->jacobian, problem->residual,
g);
352 const char *prefix =
nullptr;
353 PetscOptions options =
nullptr;
354 CHKERR TaoGetOptionsPrefix(parentTao, &prefix);
357 CHKERR TaoSetOptionsPrefix(dual, prefix);
358 CHKERR TaoAppendOptionsPrefix(dual,
"tao_nullspace_dual_");
359 CHKERR TaoSetTolerances(dual, 1e-12, 0, 0);
360 CHKERR TaoSetMaximumIterations(dual, 500);
361 CHKERR TaoSetFromOptions(dual);
362 PetscBool diagonal_nnls;
369 TaoConvergedReason reason;
371 PetscReal residual_norm;
372 CHKERR TaoGetSolutionStatus(dual, &iterations,
nullptr, &residual_norm,
373 nullptr,
nullptr, &reason);
374 if (reason == TAO_DIVERGED_MAXITS) {
376 <<
"Null-space multiplier selection reached its iteration limit ("
377 << iterations <<
"), residual " << residual_norm
378 <<
"; continuing with the current multipliers";
379 }
else if (reason <= 0)
381 PETSC_ERR_NOT_CONVERGED,
382 "Null-space multiplier selection failed: %s",
383 TaoConvergedReasons[reason]);
384 CHKERR VecZeroEntries(multipliers);
386 CHKERR VecGetSubVector(multipliers, candidates.rows, &sub);
388 CHKERR VecRestoreSubVector(multipliers, candidates.rows, &sub);
390 CHKERR VecZeroEntries(multipliers);
399 CHKERR VecCopy(solution, baseSolution);
400 CHKERR VecCopy(gradient, baseGradient);
401 PetscInt first, last;
402 CHKERR VecGetOwnershipRange(constraints, &first, &last);
403 const PetscScalar *
c;
404 CHKERR VecGetArrayRead(constraints, &
c);
405 std::vector<PetscInt> candidates_indices;
406 for (PetscInt
i = 0;
i != last - first; ++
i) {
408 const PetscScalar *
values;
409 CHKERR MatGetRow(jacobian, first +
i, &count,
nullptr, &
values);
410 PetscReal row_norm = 0;
411 for (PetscInt
j = 0;
j != count; ++
j)
412 row_norm = std::hypot(row_norm, PetscAbsScalar(
values[
j]));
413 CHKERR MatRestoreRow(jacobian, first +
i, &count,
nullptr, &
values);
416 if (PetscRealPart(
c[
i]) <= activeTolerance * row_norm)
417 candidates_indices.push_back(first +
i);
419 CHKERR VecRestoreArrayRead(constraints, &
c);
420 NullSpaceRows candidates;
421 CHKERR candidates.select(jacobian, allColumns, candidates_indices);
422 CHKERR selectMultipliers(candidates);
423 const PetscScalar *
mu;
424 CHKERR VecGetArrayRead(constraints, &
c);
425 CHKERR VecGetArrayRead(multipliers, &
mu);
426 std::vector<PetscInt> binding_indices;
427 std::vector<PetscInt> restoration_indices;
428 for (PetscInt
i = 0;
i != last - first; ++
i) {
431 binding_indices.push_back(first +
i);
432 if (binds || PetscRealPart(
c[
i]) <= 0)
433 restoration_indices.push_back(first +
i);
435 CHKERR VecRestoreArrayRead(multipliers, &
mu);
436 CHKERR VecRestoreArrayRead(constraints, &
c);
437 CHKERR binding.select(jacobian, allColumns, binding_indices);
439 const char *prefix =
nullptr;
440 PetscOptions options =
nullptr;
441 CHKERR TaoGetOptionsPrefix(parentTao, &prefix);
443 const std::string base_prefix = prefix ? prefix :
"";
445 base_prefix +
"tao_nullspace_binding_",
448 baseGradient, allColumns, base_prefix +
"tao_nullspace_restoration_",
454 CHKERR binding.projection->applyQ(baseGradient, projectedGradient);
457 CHKERR VecCopy(baseGradient, projectedGradient);
467 MoFEMErrorCode evaluateSubProblem(Vec x, PetscReal *objective, Vec
g) {
472 PETSC_ERR_ARG_WRONGSTATE,
473 "The null-space subproblem needs an accepted-iterate active set");
476 if (!std::isfinite(f) || std::abs(f) >= PETSC_INFINITY) {
477 CHKERR rejectSubProblem(objective,
g);
482 CHKERR VecZeroEntries(constraintWeights);
487 *objective -=
alphaJ * PetscRealPart(value);
490 CHKERR VecGetSubVector(constraintWeights,
binding.rows, &sub);
491 CHKERR VecCopy(bindingMultipliers, sub);
492 CHKERR VecScale(sub, -alphaJ);
493 CHKERR VecRestoreSubVector(constraintWeights,
binding.rows, &sub);
501 *objective += 0.5 *
alphaC * PetscRealPart(value);
510 CHKERR MatMultTranspose(jacobian, constraintWeights,
g);
511 CHKERR VecAXPY(
g, alphaJ, gradient);
513 CHKERR VecNorm(
g, NORM_2, &norm);
514 if (!std::isfinite(norm)) {
515 CHKERR rejectSubProblem(objective,
g);
519 if (!std::isfinite(*objective) || std::abs(*objective) >= PETSC_INFINITY) {
520 CHKERR rejectSubProblem(objective,
g);
530 *objective = PETSC_INFINITY;
533 if (activeLineSearch) {
547 MoFEMErrorCode applyMoreThuente(TaoLineSearch ls, Vec x, PetscReal *f, Vec
g,
553 CHKERR VecCopy(
g, start_gradient);
554 const auto initial_value = *
f;
555 const auto step_min = ls->stepmin;
556 const auto step_max = ls->stepmax;
558 CHKERR VecDot(
g, direction, &slope);
563 ls->stepmin = step_min;
564 ls->stepmax = step_max;
569 CHKERR PetscInfo(ls,
"Null-space trial rejected; backtracking without "
570 "interpolating rejected objective/gradient data\n");
571 ls->step = std::min(0.5 * ls->step, step_max);
572 while (ls->nfeval + ls->nfgeval < ls->max_funcs && ls->step >= step_min &&
574 CHKERR VecWAXPY(x, ls->step, direction, start);
575 CHKERR TaoLineSearchComputeObjective(ls, x, f);
576 CHKERR TaoLineSearchMonitor(ls, ls->nfeval + ls->nfgeval, *f, ls->step);
577 if (subproblemValid &&
578 *f <= initial_value + ls->ftol * ls->step * PetscRealPart(slope)) {
579 CHKERR TaoLineSearchComputeObjectiveAndGradient(ls, x, f,
g);
580 if (subproblemValid) {
583 ls->reason = TAOLINESEARCH_SUCCESS_USER;
585 "Null-space domain safeguard accepted a valid "
586 "sufficient-decrease step %g\n",
587 static_cast<double>(ls->step));
593 ls->reason = ls->nfeval + ls->nfgeval >= ls->max_funcs
594 ? TAOLINESEARCH_HALTED_MAXFCN
595 : TAOLINESEARCH_HALTED_LOWERBOUND;
597 CHKERR VecCopy(start_gradient,
g);
606 TaoLineSearch ls =
nullptr;
607 CHKERR TaoGetLineSearch(subsolver, &ls);
608 PetscBool more_thuente = PETSC_FALSE;
613 CHKERR TaoSolve(subsolver);
616 CHKERR TaoLineSearchUseTaoRoutines(ls, subsolver);
618 ls->ops->apply = [](TaoLineSearch ls,
Vec x, PetscReal *
f,
Vec g,
Vec s) {
619 return static_cast<TaoNullSpace *
>(ls->tao->user_objgradP)
620 ->applyMoreThuente(ls, x, f,
g, s);
622 const auto error = TaoSolve(subsolver);
632 MoFEMErrorCode evaluateSubObjective(Vec x, PetscReal *objective) {
634 CHKERR evaluateSubProblem(x, objective,
nullptr);
641 CHKERR evaluateSubProblem(x, &objective,
g);
648 CHKERR TaoSetConvergedReason(tao, TAO_CONTINUE_ITERATING);
650 CHKERR TaoGetSolution(tao, &solution);
652 for (PetscInt iteration = 0;; ++iteration) {
654 CHKERR evaluate(solution, objective, gradient);
655 if (!std::isfinite(objective) || std::abs(objective) >= PETSC_INFINITY)
657 "Null-space accepted iterate has non-finite objective, "
658 "gradient or constraint data");
659 CHKERR buildEpoch(solution);
660 CHKERR MatMultTranspose(jacobian, multipliers, stationarity);
661 CHKERR VecAYPX(stationarity, -1, gradient);
662 PetscReal stationarity_norm, projected_norm, complementarity_norm,
664 CHKERR VecNorm(stationarity, NORM_2, &stationarity_norm);
665 CHKERR VecNorm(projectedGradient, NORM_2, &projected_norm);
666 CHKERR VecPointwiseMult(constraintWork, multipliers, constraints);
667 CHKERR VecNorm(constraintWork, NORM_2, &complementarity_norm);
668 CHKERR VecZeroEntries(constraintWork);
669 CHKERR VecPointwiseMin(constraintWork, constraintWork, constraints);
670 CHKERR VecNorm(constraintWork, NORM_2, &constraint_norm);
671 if (!std::isfinite(stationarity_norm) || !std::isfinite(projected_norm) ||
672 !std::isfinite(complementarity_norm) ||
673 !std::isfinite(constraint_norm))
675 "Null-space KKT residual is not finite");
677 std::max({stationarity_norm, projected_norm, complementarity_norm});
678 CHKERR TaoSetIterationNumber(tao, iteration);
679 CHKERR TaoLogConvergenceHistory(tao, objective,
residual, constraint_norm,
681 CHKERR TaoMonitor(tao, iteration, objective,
residual, constraint_norm,
685 <<
"Null-space KKT iteration " << iteration
686 <<
": stationarity " << stationarity_norm
687 <<
", projected gradient " << projected_norm
688 <<
", complementarity " << complementarity_norm;
689 CHKERR (*tao->ops->convergencetest)(tao, tao->cnvP);
690 if (tao->reason == TAO_CONVERGED_STEPTOL) {
691 PetscReal gatol, catol;
692 CHKERR TaoGetTolerances(tao, &gatol,
nullptr,
nullptr);
693 CHKERR TaoGetConstraintTolerances(tao, &catol,
nullptr);
694 if (
residual > gatol || constraint_norm > catol)
695 CHKERR TaoSetConvergedReason(tao, TAO_DIVERGED_LS_FAILURE);
697 if (tao->reason != TAO_CONTINUE_ITERATING)
699 PetscReal merit_before, merit_after;
700 CHKERR evaluateSubProblem(baseSolution, &merit_before, subGradient);
701 CHKERR VecCopy(baseSolution, subSolution);
702 CHKERR TaoSetRecycleHistory(subsolver, PETSC_FALSE);
704 TaoConvergedReason reason;
705 CHKERR TaoGetConvergedReason(subsolver, &reason);
706 CHKERR evaluateSubProblem(subSolution, &merit_after, subGradient);
707 CHKERR VecWAXPY(stepDirection, -1, baseSolution, subSolution);
708 CHKERR VecNorm(stepDirection, NORM_2, &step);
710 CHKERR TaoGetLineSearch(subsolver, &ls);
711 PetscBool algorithm_one = PETSC_FALSE;
715 const bool final_trial =
716 algorithm_one && ls->reason == TAOLINESEARCH_SUCCESS_USER;
717 if ((reason <= 0 && reason != TAO_DIVERGED_MAXITS) || !subproblemValid ||
718 !std::isfinite(step) || step <= minimumStep ||
720 merit_after > merit_before + 8 * PETSC_MACHINE_EPSILON *
721 (1 + std::abs(merit_before)))) {
723 CHKERR evaluate(solution, objective, gradient);
724 CHKERR TaoSetConvergedReason(tao, TAO_DIVERGED_LS_FAILURE);
727 CHKERR VecCopy(subSolution, solution);
734MoFEMErrorCode getNullSpaceContext(Tao tao, TaoNullSpace *&ctx_ptr) {
736 PetscBool is_nullspace = PETSC_FALSE;
740 SETERRQ(PetscObjectComm(
getPetscObject(tao)), PETSC_ERR_ARG_WRONG,
741 "TAO type must be nullspace");
742 PetscContainer container =
nullptr;
744 reinterpret_cast<PetscObject *
>(&container));
746 SETERRQ(PetscObjectComm(
getPetscObject(tao)), PETSC_ERR_ARG_WRONGSTATE,
747 "TAONULLSPACE context is not attached");
749 CHKERR PetscContainerGetPointer(container, &ptr);
750 ctx_ptr =
static_cast<TaoNullSpace *
>(ptr);
760 CHKERR TaoSetType(tao, TAOSHELL);
762 auto ctx_ptr = std::make_unique<TaoNullSpace>();
763 ctx_ptr->parentTao = tao;
764 ctx_ptr->destroyShell = tao->ops->destroy;
766 CHKERR TaoSetType(ctx_ptr->subsolver, TAOSHELL);
767 CHKERR TaoShellSetSolve(ctx_ptr->subsolver, solveNullSpaceFlowStep);
768 CHKERR TaoSetTolerances(ctx_ptr->subsolver, 1e-14, 0, 0);
769 CHKERR TaoSetMaximumIterations(ctx_ptr->subsolver, 1);
771 CHKERR TaoLineSearchCreate(
comm, &ctx_ptr->subsolver.get()->linesearch);
772 CHKERR TaoLineSearchSetType(ctx_ptr->subsolver.get()->linesearch,
773 nullSpaceLineSearch);
775 PetscContainer container =
nullptr;
776 CHKERR PetscContainerCreate(
comm, &container);
777 CHKERR PetscContainerSetPointer(container, ctx_ptr.get());
778 CHKERR PetscContainerSetUserDestroy(container, [](
void *ptr) {
780 auto *ctx_ptr =
static_cast<TaoNullSpace *
>(ptr);
783 auto inner = ctx_ptr->subsolver.get();
784 inner->ops->computeobjective =
nullptr;
785 inner->user_objP =
nullptr;
786 inner->ops->computegradient =
nullptr;
787 inner->user_gradP =
nullptr;
788 inner->ops->computeobjectiveandgradient =
nullptr;
789 inner->user_objgradP =
nullptr;
794 const auto compose_error = PetscObjectCompose(
796 CHKERR PetscContainerDestroy(&container);
799 tao->ops->destroy = [](Tao tao) {
801 TaoNullSpace *ctx_ptr =
nullptr;
802 CHKERR getNullSpaceContext(tao, ctx_ptr);
803 const auto destroy_shell = ctx_ptr->destroyShell;
807 CHKERR destroy_shell(tao);
810 tao->ops->setup = [](Tao tao) {
812 TaoNullSpace *ctx_ptr =
nullptr;
813 CHKERR getNullSpaceContext(tao, ctx_ptr);
814 CHKERR ctx_ptr->setUp(tao);
817 tao->ops->setfromoptions = [](Tao tao, PetscOptionItems *PetscOptionsObject) {
819 TaoNullSpace *ctx_ptr =
nullptr;
820 CHKERR getNullSpaceContext(tao, ctx_ptr);
821 PetscOptionsHeadBegin(PetscOptionsObject,
"Null-space TAO shell options");
823 "-tao_nullspace_monitor_kkt",
"Print individual KKT residual norms",
824 nullptr, ctx_ptr->monitorKkt, &ctx_ptr->monitorKkt,
nullptr);
825 CHKERR PetscOptionsReal(
"-tao_nullspace_alpha_j",
"Objective descent scale",
826 nullptr, ctx_ptr->alphaJ, &ctx_ptr->alphaJ,
828 CHKERR PetscOptionsReal(
"-tao_nullspace_alpha_c",
829 "Constraint restoration scale",
nullptr,
830 ctx_ptr->alphaC, &ctx_ptr->alphaC,
nullptr);
832 "-tao_nullspace_active_tol",
"Activation distance h in control space",
833 nullptr, ctx_ptr->activeTolerance, &ctx_ptr->activeTolerance,
nullptr);
834 CHKERR PetscOptionsReal(
"-tao_nullspace_multiplier_tol",
835 "Binding multiplier tolerance",
nullptr,
836 ctx_ptr->multiplierTolerance,
837 &ctx_ptr->multiplierTolerance,
nullptr);
839 "-tao_nullspace_min_step",
"Minimum accepted step norm",
nullptr,
840 ctx_ptr->minimumStep, &ctx_ptr->minimumStep,
nullptr);
841 PetscOptionsHeadEnd();
842 if (!(ctx_ptr->alphaJ > 0) || !(ctx_ptr->alphaC > 0) ||
843 !std::isfinite(ctx_ptr->alphaJ) || !std::isfinite(ctx_ptr->alphaC) ||
844 !std::isfinite(ctx_ptr->activeTolerance) ||
845 ctx_ptr->activeTolerance < 0 ||
846 !(ctx_ptr->multiplierTolerance > 0) ||
847 !(ctx_ptr->minimumStep > 0))
848 SETERRQ(PetscObjectComm(
getPetscObject(tao)), PETSC_ERR_ARG_OUTOFRANGE,
849 "Require finite positive null-space scales, finite active_tol "
850 ">= 0, and positive multiplier_tol/min_step");
851 const char *prefix =
nullptr;
852 PetscOptions options =
nullptr;
853 CHKERR TaoGetOptionsPrefix(tao, &prefix);
857 CHKERR TaoSetOptionsPrefix(ctx_ptr->subsolver, prefix);
858 CHKERR TaoAppendOptionsPrefix(ctx_ptr->subsolver,
"tao_nullspace_");
859 if (ctx_ptr->subsolver.get()->linesearch)
860 CHKERR PetscObjectSetOptions(
862 CHKERR TaoSetFromOptions(ctx_ptr->subsolver);
867 CHKERR TaoShellSetSolve(ctx_ptr->subsolver, solveNullSpaceFlowStep);
869 auto inner = ctx_ptr->subsolver.get();
870 if (!inner->linesearch) {
873 CHKERR TaoLineSearchSetType(inner->linesearch, nullSpaceLineSearch);
874 const char *inner_prefix;
875 CHKERR TaoGetOptionsPrefix(inner, &inner_prefix);
876 CHKERR TaoLineSearchSetOptionsPrefix(inner->linesearch, inner_prefix);
878 CHKERR TaoLineSearchSetFromOptions(inner->linesearch);
883 tao->ops->view = [](Tao tao, PetscViewer viewer) {
885 TaoNullSpace *ctx_ptr =
nullptr;
886 CHKERR getNullSpaceContext(tao, ctx_ptr);
887 PetscBool is_ascii = PETSC_FALSE;
891 CHKERR PetscViewerASCIIPrintf(
893 " Null-space gradient flow (default: Algorithm 1 Euler step)\n"
894 " Objective scale %g, constraint scale %g\n"
895 " Activation distance h %g (epsilon_i = h ||J_i||_2)\n",
896 static_cast<double>(ctx_ptr->alphaJ),
897 static_cast<double>(ctx_ptr->alphaC),
898 static_cast<double>(ctx_ptr->activeTolerance));
899 CHKERR TaoView(ctx_ptr->subsolver, viewer);
903 CHKERR TaoShellSetSolve(tao, [](Tao tao) {
905 TaoNullSpace *ctx_ptr =
nullptr;
906 CHKERR getNullSpaceContext(tao, ctx_ptr);
907 CHKERR ctx_ptr->solve(tao);
918 CHKERR TaoLineSearchRegister(nullSpaceLineSearch, createNullSpaceLineSearch);
927 TaoNullSpace *ctx_ptr =
nullptr;
928 CHKERR getNullSpaceContext(tao, ctx_ptr);
929 if (tao->setupcalled)
930 SETERRQ(PetscObjectComm(
getPetscObject(tao)), PETSC_ERR_ARG_WRONGSTATE,
931 "Set null-space constraints before TaoSetUp");
935 ctx_ptr->preconditioner =
942 TaoNullSpace *ctx_ptr =
nullptr;
943 CHKERR getNullSpaceContext(tao, ctx_ptr);
950 TaoNullSpace *ctx_ptr =
nullptr;
951 CHKERR getNullSpaceContext(tao, ctx_ptr);
952 if (!ctx_ptr->multipliers)
953 SETERRQ(PetscObjectComm(
getPetscObject(tao)), PETSC_ERR_ARG_WRONGSTATE,
954 "Call TaoSetUp before requesting null-space multipliers");
SmartPetscObj< Vec > work
SmartPetscObj< Vec > residual
SmartPetscObj< Vec > gradient
SmartPetscObj< Mat > jacobian
SmartPetscObj< Vec > values
SmartPetscObj< Vec > baseSolution
PetscReal multiplierTolerance
SmartPetscObj< Mat > preconditioner
SmartPetscObj< Vec > projectedGradient
SmartPetscObj< Vec > baseGradient
SmartPetscObj< IS > allColumns
SmartPetscObj< Vec > constraintWork
SmartPetscObj< DM > constraintDM
SmartPetscObj< Vec > stepDirection
SmartPetscObj< Vec > constraintWeights
boost::shared_ptr< ConstrainMatrixCtx > projection
SmartPetscObj< Tao > subsolver
SmartPetscObj< Vec > constraints
SmartPetscObj< Vec > stationarity
SmartPetscObj< Mat > inverse
TaoLineSearch activeLineSearch
SmartPetscObj< Vec > bindingMultipliers
SmartPetscObj< Vec > subGradient
SmartPetscObj< Vec > multipliers
PetscReal activeTolerance
PetscErrorCode(* applyLineSearch)(TaoLineSearch, Vec, PetscReal *, Vec, Vec)
NullSpaceRows restoration
SmartPetscObj< Vec > subSolution
TAO shell interface for null-space constrained optimization.
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
#define MOFEM_LOG(channel, severity)
Log.
constexpr char TAONULLSPACE[]
FTensor::Index< 'i', SPACE_DIM > i
const double c
speed of light (cm/ns)
FTensor::Index< 'j', 3 > j
const FTensor::Tensor2< T, Dim, Dim > Vec
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
auto createKSP(MPI_Comm comm)
MoFEMErrorCode TaoNullSpaceGetMultipliers(Tao tao, Vec *multipliers)
MoFEMErrorCode TaoDiagonalNNLSSetProblem(Tao tao, Mat jacobian, Vec target)
MoFEMErrorCode TaoNullSpaceSetConstraints(Tao tao, DM constraint_dm, Vec constraints, Mat jacobian, Mat preconditioner)
SmartPetscObj< Mat > createCCTInverseKSP(Mat constrain_matrix, KSP ksp=nullptr, const std::string &options_prefix="constraint_matrix_")
MoFEMErrorCode TaoRegisterDiagonalNNLS()
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
static PetscErrorCode solve(Mat mat, Vec x, Vec y)
constexpr char TAODIAGONALNNLS[]
boost::shared_ptr< ConstrainMatrixCtx > createConstrainMatrixCtx(DM x_dm, DM y_dm, Mat constrain_matrix, Mat inverse_cct)
PetscObject getPetscObject(T obj)
MoFEMErrorCode TaoNullSpaceGetSubsolver(Tao tao, Tao *subsolver)
MoFEMErrorCode TaoRegisterNullSpace()
auto createTao(MPI_Comm comm)
intrusive_ptr for managing petsc objects