11 "Test the null-space TAO solver on an epigraph problem.\n\n";
20 const PetscScalar *data;
21 CHKERR VecGetOwnershipRange(vec, &first, &last);
22 CHKERR VecGetArrayRead(vec, &data);
23 for (
auto i = first;
i != last; ++
i)
25 CHKERR VecRestoreArrayRead(vec, &data);
26 CHKERR MPI_Allreduce(MPI_IN_PLACE,
values.data(),
N, MPIU_SCALAR, MPI_SUM,
36 CHKERR VecGetOwnershipRange(vec, &first, &last);
37 CHKERR VecGetArray(vec, &data);
38 for (
auto i = first;
i != last; ++
i)
40 CHKERR VecRestoreArray(vec, &data);
46 PetscInt objectiveCalls = 0;
47 PetscInt gradientCalls = 0;
48 PetscInt constraintCalls = 0;
49 PetscInt jacobianCalls = 0;
53 std::array<PetscScalar, 3>
values;
55 const auto p1 = PetscRealPart(
values[0]);
56 const auto p2 = PetscRealPart(
values[1]);
59 *value = 0.5 * ((p1 - 3) * (p1 - 3) + (p2 - 4) * (p2 - 4)) +
65 std::array<PetscScalar, 3>{p1 - 3, p2 - 4, 1});
70 static PetscErrorCode
constraints(Tao, Vec x, Vec
c,
void *ctx) {
72 auto *problem_ptr =
static_cast<Problem *
>(ctx);
73 ++problem_ptr->constraintCalls;
74 std::array<PetscScalar, 3>
values;
77 std::hypot(PetscRealPart(
values[0]), PetscRealPart(
values[1]));
79 c, std::array<PetscScalar, 2>{problem_ptr->scale * (
values[2] - radius),
84 static PetscErrorCode
jacobian(Tao, Vec x, Mat
j, Mat j_pre,
void *ctx) {
86 auto *problem_ptr =
static_cast<Problem *
>(ctx);
87 ++problem_ptr->jacobianCalls;
88 std::array<PetscScalar, 3>
values;
91 std::hypot(PetscRealPart(
values[0]), PetscRealPart(
values[1]));
92 const auto scale = problem_ptr->scale;
93 const PetscScalar
rows[2][3] = {{radius ? -
scale *
values[0] / radius : 0,
97 const PetscInt columns[] = {0, 1, 2};
98 for (
auto matrix : {
j, j_pre}) {
100 CHKERR MatGetOwnershipRange(matrix, &first, &last);
101 for (
auto row = first; row != last; ++row)
104 CHKERR MatAssemblyBegin(matrix, MAT_FINAL_ASSEMBLY);
105 CHKERR MatAssemblyEnd(matrix, MAT_FINAL_ASSEMBLY);
114 CHKERR PetscPushErrorHandler(PetscReturnErrorHandler,
nullptr);
115 const auto objective_error = TaoComputeObjective(inner, x, &value);
116 const auto gradient_error = TaoComputeGradient(inner, x,
gradient);
117 CHKERR PetscPopErrorHandler();
123 if (objective_error != PETSC_ERR_ARG_WRONGSTATE ||
124 gradient_error != PETSC_ERR_ARG_WRONGSTATE)
126 "Inner callbacks require a live parent and a frozen outer iterate");
136 TaoLineSearch line_search;
137 CHKERR TaoGetLineSearch(inner, &line_search);
138 for (
const auto type : {TAOLINESEARCHARMIJO,
"nullspace"}) {
139 CHKERR TaoLineSearchSetType(line_search,
type);
140 CHKERR TaoLineSearchReset(line_search);
141 CHKERR TaoLineSearchUseTaoRoutines(line_search, inner);
142 CHKERR TaoLineSearchSetInitialStepLength(line_search, 1);
143 CHKERR VecCopy(start, trial);
144 PetscReal value, step;
145 CHKERR TaoComputeObjectiveAndGradient(inner, trial, &value,
gradient);
148 CHKERR VecScale(direction, -100);
149 const auto objective_calls = problem.objectiveCalls;
150 const auto gradient_calls = problem.gradientCalls;
151 const auto jacobian_calls = problem.jacobianCalls;
152 TaoLineSearchConvergedReason reason;
153 CHKERR TaoLineSearchApply(line_search, trial, &value,
gradient, direction,
155 if (reason <= 0 || !(step < 1) ||
156 problem.objectiveCalls <= objective_calls + 1 ||
157 problem.gradientCalls != gradient_calls + 1 ||
158 problem.jacobianCalls != jacobian_calls + 1)
160 "%s backtracking must evaluate derivatives only at the accepted "
161 "trial: objective/gradient/Jacobian calls %d/%d/%d, step %g",
162 type,
static_cast<int>(problem.objectiveCalls - objective_calls),
163 static_cast<int>(problem.gradientCalls - gradient_calls),
164 static_cast<int>(problem.jacobianCalls - jacobian_calls),
165 static_cast<double>(step));
166 PetscReal expected_value, gradient_error;
167 CHKERR TaoComputeObjectiveAndGradient(inner, trial, &expected_value,
170 CHKERR VecNorm(expected_gradient, NORM_INFINITY, &gradient_error);
171 if (std::abs(value - expected_value) > 1e-12 || gradient_error > 1e-12)
173 "%s backtracking returned inconsistent value and gradient",
180 const bool combined) {
185 CHKERR VecCopy(solution, trial);
186 CHKERR writeValues(direction, std::array<PetscScalar, 3>{0.2, -0.3, 0.1});
187 CHKERR VecAXPY(trial, 0.01, direction);
188 const auto objective_calls = problem.objectiveCalls;
189 const auto gradient_calls = problem.gradientCalls;
190 const auto constraint_calls = problem.constraintCalls;
191 const auto jacobian_calls = problem.jacobianCalls;
193 CHKERR TaoComputeObjective(inner, trial, &value);
194 if (problem.objectiveCalls != objective_calls + 1 ||
195 problem.constraintCalls != constraint_calls + 1 ||
196 problem.jacobianCalls != jacobian_calls ||
197 (!combined && problem.gradientCalls != gradient_calls))
199 "Inner objective requested unnecessary derivatives");
201 if (problem.gradientCalls != gradient_calls + (combined ? 2 : 1) ||
202 problem.jacobianCalls != jacobian_calls + 1)
204 "Inner gradient did not evaluate the required derivatives");
206 PetscReal combined_value, gradient_error;
207 CHKERR TaoComputeObjectiveAndGradient(inner, trial, &combined_value,
210 CHKERR VecNorm(combined_gradient, NORM_INFINITY, &gradient_error);
211 if (std::abs(value - combined_value) > 1e-12 || gradient_error > 1e-12)
213 "Separate and combined frozen merit evaluations differ");
214 PetscScalar derivative;
216 constexpr PetscReal epsilon = 1e-6;
217 PetscReal plus, minus;
218 CHKERR VecAXPY(trial, epsilon, direction);
219 CHKERR TaoComputeObjective(inner, trial, &plus);
220 CHKERR VecAXPY(trial, -2 * epsilon, direction);
221 CHKERR TaoComputeObjective(inner, trial, &minus);
222 if (std::abs((plus - minus) / (2 * epsilon) - PetscRealPart(derivative)) >
223 2e-6 * (1 + PetscAbsScalar(derivative)))
225 "Inner gradient is not the derivative of its frozen scalar merit");
227 CHKERR checkLineSearchRequests(inner, trial, problem);
231MoFEMErrorCode solveProblem(
const std::array<PetscScalar, 3> &start,
232 const PetscReal
scale,
const bool combined) {
238 auto dm =
createDM(PETSC_COMM_WORLD, DMSHELL);
239 CHKERR writeValues(x, start);
240 PetscInt local_rows, local_columns;
241 CHKERR VecGetLocalSize(
c, &local_rows);
242 CHKERR VecGetLocalSize(x, &local_columns);
244 CHKERR MatCreateAIJ(PETSC_COMM_WORLD, local_rows, local_columns, 2, 3,
245 local_columns,
nullptr, 3 - local_columns,
nullptr,
248 CHKERR MatCreateAIJ(PETSC_COMM_WORLD, local_rows, local_columns, 2, 3,
249 local_columns,
nullptr, 3 - local_columns,
nullptr,
253 CHKERR TaoSetType(tao, combined ? TAOSHELL : TAOALMM);
254 CHKERR TaoSetOptionsPrefix(tao,
"test_");
255 CHKERR TaoSetSolution(tao, x);
257 CHKERR ::TaoSetObjectiveAndGradient(
259 [](Tao, Vec x, PetscReal *f, Vec
g,
void *ctx) {
260 return static_cast<Problem *
>(ctx)->evaluate(x, f,
g);
264 CHKERR ::TaoSetObjective(
266 [](Tao, Vec x, PetscReal *f,
void *ctx) {
267 return static_cast<Problem *
>(ctx)->evaluate(x, f,
nullptr);
270 CHKERR ::TaoSetGradient(
272 [](Tao, Vec x, Vec
g,
void *ctx) {
273 return static_cast<Problem *
>(ctx)->evaluate(x,
nullptr,
g);
277 CHKERR TaoSetInequalityConstraintsRoutine(tao,
c, Problem::constraints,
280 Problem::jacobian, &problem);
284 CHKERR TaoSetFromOptions(tao);
286 CHKERR TaoSetMaximumIterations(tao, 300);
287 CHKERR TaoSetTolerances(tao, 1e-7, 0, 0);
288 CHKERR TaoSetConstraintTolerances(tao, 1e-7, 0);
289 CHKERR TaoSetFromOptions(tao);
298 CHKERR TaoGetOptionsPrefix(inner, &prefix);
299 CHKERR PetscStrcmp(prefix,
"test_tao_nullspace_", &matches);
302 "Inner TAO did not inherit its options prefix");
305 CHKERR TaoGetSolution(inner, &sub_solution);
306 CHKERR TaoGetGradient(inner, &sub_gradient,
nullptr,
nullptr);
308 CHKERR VecEqual(x, sub_solution, &matches);
309 if (!matches || sub_solution == x.get() || sub_gradient ==
g.get())
311 "Inner TAO needs an independent copy of the parent state");
312 CHKERR checkUnavailableSubproblem(inner, x,
g);
314 TaoConvergedReason reason;
315 CHKERR TaoGetConvergedReason(tao, &reason);
318 "Epigraph solve did not converge (scale %g, reason %d)",
319 static_cast<double>(
scale),
static_cast<int>(reason));
321 PetscBool check_recycling = PETSC_FALSE;
322 CHKERR PetscOptionsHasName(
nullptr, prefix,
"-tao_lmvm_recycle",
325 CHKERR TaoView(inner, PETSC_VIEWER_STDOUT_WORLD);
327 std::array<PetscScalar, 3> solution;
328 std::array<PetscScalar, 2> dual;
329 CHKERR readValues(x, solution);
331 constexpr PetscReal tolerance = 5e-6;
332 const PetscReal radius =
333 std::hypot(PetscRealPart(solution[0]), PetscRealPart(solution[1]));
334 if (PetscAbsScalar(solution[0] - 2.4) > tolerance ||
335 PetscAbsScalar(solution[1] - 3.2) > tolerance ||
336 PetscAbsScalar(solution[2] - 4) > tolerance ||
337 PetscAbsScalar(
scale * dual[0] - 1) > tolerance ||
338 PetscAbsScalar(dual[1]) > tolerance ||
339 PetscRealPart(solution[2]) - radius < -tolerance ||
340 PetscRealPart(6 - solution[2]) < -tolerance)
342 "Incorrect epigraph optimum (scale %g): x=(%g,%g,%g), "
343 "scaled multipliers=(%g,%g)",
344 static_cast<double>(
scale),
static_cast<double>(solution[0]),
345 static_cast<double>(solution[1]),
static_cast<double>(solution[2]),
346 static_cast<double>(
scale * dual[0]),
static_cast<double>(dual[1]));
348 CHKERR TaoComputeObjectiveAndGradient(tao, x, &objective,
g);
354 if (std::abs(objective - 4.5) > tolerance ||
stationarity > tolerance ||
355 !problem.objectiveCalls || !problem.gradientCalls ||
356 !problem.constraintCalls || !problem.jacobianCalls)
358 "Epigraph objective or constrained stationarity is incorrect");
359 CHKERR checkFrozenMerit(inner, x, problem, combined);
362 "Epigraph scale %g start (%g,%g,%g): x=(%g,%g,%g), f=%g, KKT=%g\n",
363 static_cast<double>(
scale),
static_cast<double>(start[0]),
364 static_cast<double>(start[1]),
static_cast<double>(start[2]),
365 static_cast<double>(solution[0]),
static_cast<double>(solution[1]),
366 static_cast<double>(solution[2]),
static_cast<double>(objective),
374 CHKERR TaoSetType(tao, TAOLMVM);
376 retained_multipliers.
use_count() != 1 || dm.use_count() != 1)
378 "Parent destruction did not release null-space solver resources");
379 CHKERR checkUnavailableSubproblem(inner, x,
g);
383struct ActivationProblem {
386 static PetscErrorCode objective(Tao, Vec x, PetscReal *f, Vec
g,
void *) {
388 std::array<PetscScalar, 2>
values;
391 *f =
k + 0.5 *
k *
k;
393 g, std::array<PetscScalar, 2>{2 *
values[0] * (1 +
k), 1 +
k});
397 static PetscErrorCode
constraints(Tao, Vec x, Vec
c,
void *ctx) {
399 const auto scale =
static_cast<ActivationProblem *
>(ctx)->
scale;
400 std::array<PetscScalar, 2>
values;
406 static PetscErrorCode
jacobian(Tao, Vec x, Mat
j, Mat,
void *ctx) {
408 const auto scale =
static_cast<ActivationProblem *
>(ctx)->
scale;
409 std::array<PetscScalar, 2>
values;
411 const PetscInt columns[] = {0, 1};
413 PetscInt first, last;
414 CHKERR MatGetOwnershipRange(
j, &first, &last);
415 for (
auto row = first; row != last; ++row)
417 CHKERR MatAssemblyBegin(
j, MAT_FINAL_ASSEMBLY);
418 CHKERR MatAssemblyEnd(
j, MAT_FINAL_ASSEMBLY);
425 PetscReal active_distance = 1e-6;
427 "-tao_nullspace_active_tol", &active_distance,
429 for (
const auto scale : {0.1, 1.0, 10.0}) {
430 ActivationProblem problem{
scale};
435 PetscInt local_rows, local_columns;
436 CHKERR VecGetLocalSize(
c, &local_rows);
437 CHKERR VecGetLocalSize(x, &local_columns);
439 CHKERR MatCreateAIJ(PETSC_COMM_WORLD, local_rows, local_columns, 1, 2,
440 local_columns,
nullptr, 2 - local_columns,
nullptr,
445 CHKERR TaoSetOptionsPrefix(tao,
"activation_");
446 CHKERR TaoSetSolution(tao, x);
447 CHKERR ::TaoSetObjectiveAndGradient(tao,
g, ActivationProblem::objective,
449 CHKERR TaoSetInequalityConstraintsRoutine(
450 tao,
c, ActivationProblem::constraints, &problem);
451 CHKERR TaoSetJacobianInequalityRoutine(
454 CHKERR TaoSetFromOptions(tao);
456 CHKERR TaoSetConvergenceTest(
458 [](Tao tao,
void *) {
459 return TaoSetConvergedReason(tao, TAO_CONVERGED_USER);
464 for (
const auto first_value : {0.5, 1.0}) {
465 const auto norm_squared = 4 * first_value * first_value + 1;
466 for (
const auto distance_fraction : {0.95, 1.05}) {
468 distance_fraction * active_distance * std::sqrt(norm_squared);
469 CHKERR writeValues(x, std::array<PetscScalar, 2>{
470 first_value,
k - first_value * first_value});
476 std::array<PetscScalar, 1>
lambda;
477 std::array<PetscScalar, 2> merit_gradient;
480 CHKERR TaoComputeObjectiveAndGradient(inner, x, &merit, sub_gradient);
481 CHKERR readValues(sub_gradient, merit_gradient);
482 const bool active = distance_fraction < 1;
483 const auto expected_multiplier =
active ? 1 +
k : 0;
484 const auto expected_merit =
485 active ? -0.5 *
k *
k + 0.5 *
k *
k / norm_squared
487 const auto gradient_factor =
active ?
k / norm_squared : 1 +
k;
488 constexpr PetscReal tolerance = 1e-9;
489 if (PetscAbsScalar(
scale *
lambda[0] - expected_multiplier) >
491 std::abs(merit - expected_merit) > tolerance ||
492 PetscAbsScalar(merit_gradient[0] -
493 2 * first_value * gradient_factor) > tolerance ||
494 PetscAbsScalar(merit_gradient[1] - gradient_factor) > tolerance)
496 "Candidate activation or restoration changed with row "
497 "scaling: scale %g, x0 %g, normalized distance %g h",
498 static_cast<double>(
scale),
static_cast<double>(first_value),
499 static_cast<double>(distance_fraction));
506struct LineSearchProblem {
507 bool objectiveDomain;
508 PetscReal domainUpper;
509 PetscInt rejectedObjectives = 0;
510 PetscReal objectivePoint = 0;
511 PetscReal constraintPoint = 0;
512 PetscReal jacobianPoint = 0;
514 static PetscErrorCode objective(Tao, Vec x, PetscReal *f, Vec
g,
void *ctx) {
516 auto &problem = *
static_cast<LineSearchProblem *
>(ctx);
517 std::array<PetscScalar, 1>
values;
519 problem.objectivePoint = PetscRealPart(
values[0]);
520 if (problem.objectiveDomain &&
521 problem.objectivePoint > problem.domainUpper) {
522 ++problem.rejectedObjectives;
524 CHKERR VecSet(
g, std::numeric_limits<PetscReal>::quiet_NaN());
527 *f = 0.5 * PetscSqr(problem.objectivePoint - 2);
528 CHKERR VecSet(
g, problem.objectivePoint - 2);
532 static PetscErrorCode
constraints(Tao, Vec x, Vec
c,
void *ctx) {
534 auto &problem = *
static_cast<LineSearchProblem *
>(ctx);
535 std::array<PetscScalar, 1>
values;
537 problem.constraintPoint = PetscRealPart(
values[0]);
538 if (problem.objectiveDomain &&
539 problem.constraintPoint > problem.domainUpper)
541 "Constraints evaluated after an invalid objective");
542 CHKERR VecSet(
c, 1 - problem.constraintPoint);
546 static PetscErrorCode
jacobian(Tao, Vec x, Mat
j, Mat,
void *ctx) {
548 auto &problem = *
static_cast<LineSearchProblem *
>(ctx);
549 std::array<PetscScalar, 1>
values;
551 problem.jacobianPoint = PetscRealPart(
values[0]);
552 if (problem.objectiveDomain && problem.jacobianPoint > problem.domainUpper)
554 "Jacobian evaluated after an invalid objective");
555 PetscInt first, last;
556 CHKERR MatGetOwnershipRange(
j, &first, &last);
557 for (
auto row = first; row != last; ++row)
558 CHKERR MatSetValue(
j, row, 0, -1, INSERT_VALUES);
559 CHKERR MatAssemblyBegin(
j, MAT_FINAL_ASSEMBLY);
560 CHKERR MatAssemblyEnd(
j, MAT_FINAL_ASSEMBLY);
565MoFEMErrorCode checkObjectiveDomainLineSearch(
const bool exhaust_budget) {
569 LineSearchProblem problem{
true, exhaust_budget ? 0.0 : 1.0};
573 auto dm =
createDM(PETSC_COMM_WORLD, DMSHELL);
576 CHKERR VecGetLocalSize(x, &local_size);
578 CHKERR MatCreateAIJ(PETSC_COMM_WORLD, local_size, local_size, 1, 1,
579 local_size,
nullptr, 1 - local_size,
nullptr, &matrix);
583 CHKERR TaoSetOptionsPrefix(tao,
"domain_");
584 CHKERR TaoSetSolution(tao, x);
585 CHKERR ::TaoSetObjectiveAndGradient(tao,
g, LineSearchProblem::objective,
587 CHKERR TaoSetInequalityConstraintsRoutine(
588 tao,
c, LineSearchProblem::constraints, &problem);
590 LineSearchProblem::jacobian, &problem);
592 CHKERR TaoSetMaximumIterations(tao, 1);
593 CHKERR TaoSetTolerances(tao, 1e-10, 0, 0);
594 CHKERR TaoSetConstraintTolerances(tao, 1e-10, 0);
595 CHKERR TaoSetFromOptions(tao);
597 TaoConvergedReason reason;
598 CHKERR TaoGetConvergedReason(tao, &reason);
600 CHKERR readValues(x, solution);
602 const auto accepted = PetscRealPart(solution[0]);
603 constexpr PetscReal tolerance = 1e-10;
604 if (!problem.rejectedObjectives ||
605 std::abs(problem.objectivePoint - accepted) > tolerance ||
606 std::abs(problem.constraintPoint - accepted) > tolerance ||
607 std::abs(problem.jacobianPoint - accepted) > tolerance ||
608 std::abs(PetscRealPart(
constraints[0]) - (1 - accepted)) > tolerance)
610 "Objective-domain line search did not preserve valid application "
612 if (exhaust_budget) {
613 if (reason != TAO_DIVERGED_LS_FAILURE || accepted != 0)
615 "Exhausted line search must fail and restore the initial state");
617 if (!(accepted > 0) || accepted > 1 + tolerance ||
618 (reason <= 0 && reason != TAO_DIVERGED_MAXITS))
621 "Objective-domain line search did not accept a valid descent step");
623 TaoLineSearch line_search;
625 CHKERR TaoGetLineSearch(inner, &line_search);
627 CHKERR TaoGetSolution(inner, &ls_x);
628 CHKERR TaoGetGradient(inner, &ls_g,
nullptr,
nullptr);
629 PetscReal objective, step;
630 TaoLineSearchConvergedReason ls_reason;
631 CHKERR TaoLineSearchGetSolution(line_search, ls_x, &objective, ls_g, &step,
633 std::array<PetscScalar, 1> ls_solution, ls_gradient, direction;
634 CHKERR readValues(ls_x, ls_solution);
635 CHKERR readValues(ls_g, ls_gradient);
637 CHKERR TaoLineSearchGetStepDirection(line_search, &step_direction);
638 CHKERR readValues(step_direction, direction);
639 if (ls_reason != TAOLINESEARCH_SUCCESS_USER || !(step > 0) ||
640 PetscAbsScalar(ls_solution[0] - accepted) > tolerance ||
641 PetscAbsScalar(step * direction[0] - accepted) > tolerance ||
642 PetscAbsScalar(ls_gradient[0] - (accepted - 2)) > tolerance ||
643 std::abs(objective - 0.5 * PetscSqr(accepted - 2)) > tolerance ||
644 objective > 2 - 1e-4 * 2 * accepted)
647 "Domain fallback returned inconsistent objective, gradient or step");
651 "Objective-domain line search budget exhaustion %d: "
652 "x=%g, rejected objectives=%d, reason=%d\n",
653 static_cast<int>(exhaust_budget),
static_cast<double>(accepted),
654 static_cast<int>(problem.rejectedObjectives),
static_cast<int>(reason));
660 LineSearchProblem problem{
false, 0};
666 CHKERR VecGetLocalSize(x, &local_size);
668 CHKERR MatCreateAIJ(PETSC_COMM_WORLD, local_size, local_size, 1, 1,
669 local_size,
nullptr, 1 - local_size,
nullptr, &matrix);
673 CHKERR TaoSetOptionsPrefix(tao,
"flow_");
674 CHKERR TaoSetSolution(tao, x);
675 CHKERR ::TaoSetObjectiveAndGradient(tao,
g, LineSearchProblem::objective,
677 CHKERR TaoSetInequalityConstraintsRoutine(
678 tao,
c, LineSearchProblem::constraints, &problem);
680 LineSearchProblem::jacobian, &problem);
682 CHKERR TaoSetTolerances(tao, 1e-10, 0, 0);
683 CHKERR TaoSetConstraintTolerances(tao, 1e-10, 0);
684 CHKERR TaoSetMaximumIterations(tao, exhaust_budget ? 1 : 2);
688 CHKERR TaoSetType(inner, TAOLMVM);
689 CHKERR TaoSetType(inner, TAOSHELL);
690 CHKERR TaoSetFromOptions(tao);
691 TaoLineSearch line_search;
692 CHKERR TaoGetLineSearch(inner, &line_search);
696 "Returning the inner TAO to shell did not recreate its line search");
697 for (
const auto type : {TAOLINESEARCHARMIJO, TAOLINESEARCHMT}) {
698 CHKERR TaoLineSearchSetType(line_search,
type);
699 CHKERR TaoLineSearchSetType(line_search,
"nullspace");
701 CHKERR TaoLineSearchReset(line_search);
703 CHKERR TaoLineSearchSetFromOptions(line_search);
704 if (!exhaust_budget) {
707 [](Tao tao,
void *) {
710 CHKERR TaoGetIterationNumber(tao, &iteration);
711 if (iteration == 1) {
713 CHKERR TaoGetSolution(tao, &solution);
714 std::array<PetscScalar, 1>
values;
717 if (PetscAbsScalar(
values[0] - 2) > 1e-12)
719 "The first null-space flow step was blocked by an "
720 "inactive inequality");
727 TaoConvergedReason reason;
728 CHKERR TaoGetConvergedReason(tao, &reason);
729 std::array<PetscScalar, 1> solution, dual;
732 CHKERR readValues(x, solution);
734 const auto expected_solution = exhaust_budget ? 6.0 : 1.5;
735 const auto expected_multiplier = exhaust_budget ? 0.0 : 0.5;
736 if (reason != TAO_DIVERGED_MAXITS ||
737 PetscAbsScalar(solution[0] - expected_solution) > 1e-10 ||
738 PetscAbsScalar(dual[0] - expected_multiplier) > 1e-10)
740 "Incorrect null-space flow step or refreshed active set: "
741 "budget %d, x=%g, lambda=%g, reason=%d",
742 static_cast<int>(exhaust_budget),
743 static_cast<double>(PetscRealPart(solution[0])),
744 static_cast<double>(PetscRealPart(dual[0])),
745 static_cast<int>(reason));
747 if (exhaust_budget) {
748 Vec inner_x, inner_g;
749 CHKERR TaoGetSolution(inner, &inner_x);
750 CHKERR TaoGetGradient(inner, &inner_g,
nullptr,
nullptr);
751 PetscReal objective, step;
752 TaoLineSearchConvergedReason ls_reason;
753 CHKERR TaoLineSearchGetSolution(line_search, inner_x, &objective, inner_g,
755 std::array<PetscScalar, 1>
gradient;
758 if (ls_reason != TAOLINESEARCH_SUCCESS_USER ||
759 std::abs(objective - 8) > 1e-12 || std::abs(step - 3) > 1e-12 ||
760 PetscAbsScalar(
gradient[0] - 4) > 1e-12)
762 "Algorithm 1 did not accept the final finite trial at its "
763 "evaluation limit with its actual merit and gradient");
765 CHKERR PetscPrintf(PETSC_COMM_WORLD,
766 "Algorithm 1 budget fallback %d: x=%g, lambda=%g\n",
767 static_cast<int>(exhaust_budget),
768 static_cast<double>(PetscRealPart(solution[0])),
769 static_cast<double>(PetscRealPart(dual[0])));
775int main(
int argc,
char *argv[]) {
779 PetscBool activation = PETSC_FALSE, domain = PETSC_FALSE,
780 domain_budget = PETSC_FALSE, flow = PETSC_FALSE,
781 flow_budget = PETSC_FALSE;
783 &activation,
nullptr);
787 "-test_nullspace_domain_budget", &domain_budget,
792 &flow_budget,
nullptr);
794 CHKERR checkCandidateActivation();
795 }
else if (domain_budget) {
796 CHKERR checkObjectiveDomainLineSearch(
true);
798 CHKERR checkObjectiveDomainLineSearch(
false);
799 }
else if (flow || flow_budget) {
800 CHKERR checkAlgorithmOneStep(flow_budget);
802 const std::array<std::array<PetscScalar, 3>, 3> starts = {
803 {{1, 1, 3}, {3, 4, 2}, {1, 1, 6}}};
804 for (
const auto scale : {1.0, 0.1, 10.0})
805 for (
size_t i = 0;
i != starts.size(); ++
i)
SmartPetscObj< Vec > residual
SmartPetscObj< Vec > gradient
SmartPetscObj< Mat > jacobian
SmartPetscObj< Vec > values
SmartPetscObj< Mat > preconditioner
SmartPetscObj< Vec > constraints
SmartPetscObj< Vec > stationarity
SmartPetscObj< Vec > multipliers
#define CATCH_ERRORS
Catch errors.
#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 ...
@ MOFEM_DATA_INCONSISTENCY
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
constexpr char TAONULLSPACE[]
FTensor::Index< 'i', SPACE_DIM > i
const double c
speed of light (cm/ns)
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
MoFEMErrorCode TaoNullSpaceGetMultipliers(Tao tao, Vec *multipliers)
MoFEMErrorCode TaoNullSpaceSetConstraints(Tao tao, DM constraint_dm, Vec constraints, Mat jacobian, Mat preconditioner)
PetscErrorCode PetscOptionsGetReal(PetscOptions *, const char pre[], const char name[], PetscReal *dval, PetscBool *set)
PetscErrorCode PetscOptionsGetBool(PetscOptions *, const char pre[], const char name[], PetscBool *bval, PetscBool *set)
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
auto createVectorMPI(MPI_Comm comm, PetscInt n, PetscInt N)
Create MPI Vector.
MoFEMErrorCode MatSetValues(Mat M, const EntitiesFieldData::EntData &row_data, const EntitiesFieldData::EntData &col_data, const double *ptr, InsertMode iora)
Assemble PETSc matrix.
PetscObject getPetscObject(T obj)
MoFEMErrorCode TaoNullSpaceGetSubsolver(Tao tao, Tao *subsolver)
MoFEMErrorCode TaoRegisterNullSpace()
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
auto createTao(MPI_Comm comm)
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
keeps basic data about problem
intrusive_ptr for managing petsc objects