19using namespace PlasticIncrementalOptimizationInternal;
24 OpVerifyPlasticControl(boost::shared_ptr<MatrixDouble> values,
25 boost::shared_ptr<VectorDouble> kappa_increments,
26 const double expected_kappa_increment,
27 boost::shared_ptr<PetscInt> element_count)
35 const int number_of_points = getGaussPts().size2();
39 "Plastic-flow reconstruction has shape %zu x %zu, expected "
46 "Plastic-kappa increment reconstruction has size %zu, "
50 if (number_of_points <= 1)
52 "Plastic-flow reconstruction must exercise multiple "
55 auto t_flow = getFTensor2SymmetricFromMat<3>(*
valuesPtr);
57 t_coordinates(1., 2., 3., 4., 5.);
58 const auto t_expected =
60 for (
int gg = 0; gg != number_of_points; ++gg) {
61 for (
int row = 0; row != 3; ++row)
62 for (
int column = row; column != 3; ++column)
63 if (t_flow(row, column) != t_expected(row, column))
65 "Trace-free plastic-flow reconstruction failed at "
66 "point %d component (%d,%d): %.17g != %.17g",
67 gg, row, column, t_flow(row, column),
68 t_expected(row, column));
71 "Vector-backed plastic-kappa increment reconstruction failed "
72 "at point %d: %.17g != %.17g",
87using TestControlBlockVisitor =
89using TestOpAssemblePlasticCellMeasure =
91 GAUSS>::OpSource<1, 1>;
98 "Cannot create a field IS from a null DM");
107 const PetscInt block_size,
108 PetscInt &local_count,
109 PetscInt &global_count) {
113 PetscInt local_size = 0;
114 PetscInt global_size = 0;
115 CHKERR ISGetLocalSize(field_is, &local_size);
116 CHKERR ISGetSize(field_is, &global_size);
117 if (block_size <= 0 || local_size % block_size || global_size % block_size)
119 "Invalid %s field layout: local/global sizes %d/%d, block %d",
120 field_name.c_str(),
static_cast<int>(local_size),
121 static_cast<int>(global_size),
static_cast<int>(block_size));
122 local_count = local_size / block_size;
123 global_count = global_size / block_size;
128 DM dm,
const std::string &
field_name,
const PetscInt block_size, Vec vec,
129 const TestControlBlockVisitor &visitor) {
131 if (!vec || block_size <= 0)
133 "Invalid vector or block size for field %s",
field_name.c_str());
136 Vec field_vec =
nullptr;
137 CHKERR VecGetSubVector(vec, field_is, &field_vec);
138 PetscRestoreGuard field_vec_guard(
139 [&] {
return VecRestoreSubVector(vec, field_is, &field_vec); });
140 PetscInt local_size = 0;
141 CHKERR VecGetLocalSize(field_vec, &local_size);
142 if (local_size % block_size) {
143 CHKERR field_vec_guard.restore();
145 "Field %s local size %d is not divisible by block size %d",
146 field_name.c_str(),
static_cast<int>(local_size),
147 static_cast<int>(block_size));
149 PetscScalar *array =
nullptr;
150 CHKERR VecGetArray(field_vec, &array);
151 PetscRestoreGuard array_guard(
152 [&] {
return VecRestoreArray(field_vec, &array); });
154 for (PetscInt block = 0; block != local_size / block_size; ++block) {
155 visitor_error = visitor(block, array + block * block_size);
160 const MoFEMErrorCode restore_vector_error = field_vec_guard.restore();
162 CHKERR restore_array_error;
163 CHKERR restore_vector_error;
169 const PetscInt block_size, std::vector<EntityHandle> &entities) {
174 PetscInt local_size = 0;
175 CHKERR ISGetLocalSize(field_is, &local_size);
176 if (block_size <= 0 || local_size % block_size)
178 "Invalid owned %s field layout",
field_name.c_str());
179 const Problem *problem_ptr =
nullptr;
183 "Field %s DM has no numbered row DOFs",
field_name.c_str());
186 const PetscInt *indices =
nullptr;
187 CHKERR ISGetIndices(field_is, &indices);
188 PetscRestoreGuard indices_guard(
189 [&] {
return ISRestoreIndices(field_is, &indices); });
190 entities.reserve(local_size / block_size);
191 for (PetscInt base = 0; base != local_size; base += block_size) {
192 const auto first_dof = dofs.find(indices[base]);
193 if (first_dof == dofs.end())
195 "Missing field %s DOF %d",
field_name.c_str(),
196 static_cast<int>(indices[base]));
197 const EntityHandle entity = (*first_dof)->getEnt();
198 entities.emplace_back(entity);
199 for (PetscInt coefficient = 0; coefficient != block_size; ++coefficient) {
200 const auto dof = dofs.find(indices[base + coefficient]);
201 if (dof == dofs.end() || (*dof)->getEnt() != entity ||
202 (*dof)->getDofOrder() != 0 ||
203 (*dof)->getDofCoeffIdx() != coefficient)
205 "Field %s is not an entity-ordered P0 block layout",
209 CHKERR indices_guard.restore();
214 std::vector<double> &values) {
216 std::vector<EntityHandle> entities;
221 values.resize(entities.size());
222 for (std::size_t block = 0; block != entities.size(); ++block) {
223 const auto history_it = history.find(entities[block]);
224 if (history_it == history.end())
226 "Missing committed plastic kappa for entity %llu",
227 static_cast<unsigned long long>(entities[block]));
228 values[block] = history_it->second;
237 CHKERR VecZeroEntries(measure);
240 auto fe = boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.
mField);
241 fe->getUserPolynomialBase() =
242 boost::make_shared<CGGUserPolynomialBase>(
nullptr,
true);
244 fe->getRuleHook = [](
int,
int,
int order_data) {
245 return 2 * (order_data + 1);
249 fe->getOpPtrVector().push_back(
new TestOpAssemblePlasticCellMeasure(
251 fe->exeTestHook = [&ep](
FEMethod *method) {
256 CHKERR VecAssemblyBegin(measure);
257 CHKERR VecAssemblyEnd(measure);
262 Vec cell_measure, IS kappa_is, std::vector<double> &scales) {
264 Vec measures =
nullptr;
265 CHKERR VecGetSubVector(cell_measure, kappa_is, &measures);
267 CHKERR VecGetLocalSize(measures, &size);
268 const PetscScalar *values =
nullptr;
269 CHKERR VecGetArrayRead(measures, &values);
271 for (PetscInt block = 0; block != size; ++block)
272 scales[block] = std::sqrt(PetscRealPart(values[block]));
273 CHKERR VecRestoreArrayRead(measures, &values);
274 CHKERR VecRestoreSubVector(cell_measure, kappa_is, &measures);
279 Range entities,
const std::size_t block_size) {
281 auto set = [&](boost::shared_ptr<FieldEntity> field_entity) {
283 auto data = field_entity->getEntFieldData();
284 if (data.size() != block_size)
286 "Field %s has %zu coefficients on entity %llu; expected %zu",
287 field.c_str(), data.size(),
288 static_cast<unsigned long long>(field_entity->getEnt()),
290 for (std::size_t coefficient = 0; coefficient != block_size; ++coefficient)
291 data[coefficient] = coefficient + 1.;
302 const PetscInt expected_block_size) {
304 ParallelComm *parallel =
308 "ParallelComm is unavailable while checking control layout");
309 Range owned_entities;
310 CHKERR parallel->filter_pstatus(entities, PSTATUS_NOT_OWNED, PSTATUS_NOT, -1,
312 PetscInt expected_local = owned_entities.size();
313 PetscInt expected_global = 0;
314 const int mpi_error = MPI_Allreduce(&expected_local, &expected_global, 1,
316 if (mpi_error != MPI_SUCCESS)
318 "MPI reduction of control entity counts failed");
320 PetscInt actual_local = 0;
321 PetscInt actual_global = 0;
323 actual_local, actual_global);
324 if (actual_local != expected_local || actual_global != expected_global)
326 "Field %s layout mismatch: block/local/global = %d/%d/%d, "
328 field_name.c_str(),
static_cast<int>(expected_block_size),
329 static_cast<int>(actual_local),
static_cast<int>(actual_global),
330 static_cast<int>(expected_block_size),
331 static_cast<int>(expected_local),
332 static_cast<int>(expected_global));
337 EshelbianCore &ep,
const PlasticIncrementalOptimizationProblem &problem) {
339 const Problem *dm_problem_ptr =
nullptr;
343 "Incremental-optimization DM has no problem");
347 CHKERR getTestFieldIS(problem.getControlDM(),
348 problem.getPlasticFlowFieldName(), plastic_is);
349 CHKERR getTestFieldIS(problem.getControlDM(),
350 problem.getPlasticKappaFieldName(), kappa_is);
351 PetscInt plastic_size = 0;
352 PetscInt epigraph_size = 0;
353 CHKERR ISGetLocalSize(plastic_is, &plastic_size);
354 CHKERR ISGetLocalSize(kappa_is, &epigraph_size);
357 "Plastic and epigraph local layouts cannot be paired");
359 const PetscInt *plastic_indices =
nullptr;
360 const PetscInt *epigraph_indices =
nullptr;
361 CHKERR ISGetIndices(plastic_is, &plastic_indices);
362 CHKERR ISGetIndices(kappa_is, &epigraph_indices);
363 const auto &dofs_by_global =
365 std::vector<double> entity_measures(epigraph_size);
366 for (PetscInt block = 0; block != epigraph_size; ++block) {
367 const auto epigraph_dof = dofs_by_global.find(epigraph_indices[block]);
368 if (epigraph_dof == dofs_by_global.end())
370 "Missing epigraph DOF %d in the control DM",
371 static_cast<int>(epigraph_indices[block]));
372 const EntityHandle entity = (*epigraph_dof)->getEnt();
373 if ((*epigraph_dof)->getDofCoeffIdx() != 0)
375 "Epigraph block %d does not start at coefficient zero",
376 static_cast<int>(block));
377 for (PetscInt coordinate = 0;
379 const PetscInt offset =
381 const auto plastic_dof = dofs_by_global.find(plastic_indices[offset]);
382 if (plastic_dof == dofs_by_global.end())
384 "Missing plastic DOF %d in the control DM",
385 static_cast<int>(plastic_indices[offset]));
386 if ((*plastic_dof)->getEnt() != entity ||
387 (*plastic_dof)->getDofCoeffIdx() != coordinate)
389 "Plastic block %d and epigraph block %d refer to different "
390 "entities or coefficient orderings",
391 static_cast<int>(block),
static_cast<int>(block));
394 const EntityHandle *connectivity =
nullptr;
395 int number_of_nodes = 0;
396 std::vector<EntityHandle> connectivity_storage;
398 entity, connectivity, number_of_nodes,
true, &connectivity_storage);
399 if (number_of_nodes != 4)
401 "Plastic P0 entity %llu is not a four-node tetrahedron",
402 static_cast<unsigned long long>(entity));
403 double coordinates[12];
406 const double a_x = coordinates[3] - coordinates[0];
407 const double a_y = coordinates[4] - coordinates[1];
408 const double a_z = coordinates[5] - coordinates[2];
409 const double b_x = coordinates[6] - coordinates[0];
410 const double b_y = coordinates[7] - coordinates[1];
411 const double b_z = coordinates[8] - coordinates[2];
412 const double c_x = coordinates[9] - coordinates[0];
413 const double c_y = coordinates[10] - coordinates[1];
414 const double c_z = coordinates[11] - coordinates[2];
415 entity_measures[block] =
416 std::abs(a_x * (b_y * c_z - b_z * c_y) - a_y * (b_x * c_z - b_z * c_x) +
417 a_z * (b_x * c_y - b_y * c_x)) /
420 CHKERR ISRestoreIndices(kappa_is, &epigraph_indices);
421 CHKERR ISRestoreIndices(plastic_is, &plastic_indices);
424 CHKERR createTestPlasticCellMeasure(ep, problem.getControlDM(),
425 plastic_cell_measure);
426 Vec measures =
nullptr;
427 CHKERR VecGetSubVector(plastic_cell_measure, kappa_is, &measures);
428 PetscInt measure_size = 0;
429 CHKERR VecGetLocalSize(measures, &measure_size);
430 if (measure_size != epigraph_size) {
431 CHKERR VecRestoreSubVector(plastic_cell_measure, kappa_is, &measures);
433 "Cell-measure and epigraph entity layouts differ");
435 const PetscScalar *measure_array =
nullptr;
436 CHKERR VecGetArrayRead(measures, &measure_array);
437 double maximum_measure_error_local = 0;
438 double minimum_entity_measure_local = std::numeric_limits<double>::max();
439 double maximum_entity_measure_local = 0;
440 for (PetscInt block = 0; block != measure_size; ++block) {
441 const double assembled_measure = PetscRealPart(measure_array[block]);
442 const double entity_measure = entity_measures[block];
443 if (!std::isfinite(assembled_measure) || !(assembled_measure > 0) ||
444 !std::isfinite(entity_measure) || !(entity_measure > 0))
446 "Epigraph entity block %d has invalid assembled/entity cell "
448 static_cast<int>(block), assembled_measure, entity_measure);
449 maximum_measure_error_local =
450 std::max(maximum_measure_error_local,
451 std::abs(assembled_measure - entity_measure));
452 minimum_entity_measure_local =
453 std::min(minimum_entity_measure_local, entity_measure);
454 maximum_entity_measure_local =
455 std::max(maximum_entity_measure_local, entity_measure);
457 CHKERR VecRestoreArrayRead(measures, &measure_array);
458 CHKERR VecRestoreSubVector(plastic_cell_measure, kappa_is, &measures);
459 double maximum_measure_error = 0;
460 double minimum_entity_measure = 0;
461 double maximum_entity_measure = 0;
462 CHKERR MPI_Allreduce(&maximum_measure_error_local, &maximum_measure_error, 1,
464 CHKERR MPI_Allreduce(&minimum_entity_measure_local, &minimum_entity_measure,
466 CHKERR MPI_Allreduce(&maximum_entity_measure_local, &maximum_entity_measure,
468 const double measure_tolerance = 1e-11 * std::max(1., maximum_entity_measure);
469 if (maximum_measure_error > measure_tolerance)
471 "Epigraph measure is not paired with its tetrahedral entity: "
473 maximum_measure_error, measure_tolerance);
475 <<
"Entity-paired P0 measure range [" << minimum_entity_measure <<
", "
476 << maximum_entity_measure <<
"], maximum assembly error "
477 << maximum_measure_error;
483 const boost::shared_ptr<IncrementalOptimizationContext> &
context) {
490 CHKERR VecZeroEntries(control);
491 CHKERR VecZeroEntries(smooth_gradient);
492 CHKERR VecZeroEntries(multipliers);
493 CHKERR VecZeroEntries(initial_multipliers);
494 CHKERR problem.initialiseInequalityMultipliers(
context->constraintDM,
495 initial_multipliers);
498 CHKERR getTestFieldIS(problem.getControlDM(),
499 problem.getPlasticFlowFieldName(), plastic_is);
500 CHKERR getTestFieldIS(problem.getControlDM(),
501 problem.getPlasticKappaFieldName(), kappa_is);
503 CHKERR createTestPlasticCellMeasure(ep, problem.getControlDM(),
504 plastic_cell_measure);
505 std::vector<double> committed_kappa;
506 CHKERR getOwnedTestKappaValues(ep, problem.getControlDM(), committed_kappa);
508 Vec plastic =
nullptr;
509 Vec epigraph =
nullptr;
510 Vec plastic_gradient =
nullptr;
511 Vec measures =
nullptr;
512 CHKERR VecGetSubVector(control, plastic_is, &plastic);
513 CHKERR VecGetSubVector(control, kappa_is, &epigraph);
514 CHKERR VecGetSubVector(smooth_gradient, plastic_is, &plastic_gradient);
515 CHKERR VecGetSubVector(plastic_cell_measure, kappa_is, &measures);
516 PetscInt plastic_size = 0;
517 PetscInt epigraph_size = 0;
518 PetscInt gradient_size = 0;
519 PetscInt measure_size = 0;
520 PetscInt multiplier_size = 0;
521 CHKERR VecGetLocalSize(plastic, &plastic_size);
522 CHKERR VecGetLocalSize(epigraph, &epigraph_size);
523 CHKERR VecGetLocalSize(plastic_gradient, &gradient_size);
524 CHKERR VecGetLocalSize(measures, &measure_size);
525 CHKERR VecGetLocalSize(multipliers, &multiplier_size);
527 gradient_size != plastic_size || measure_size != epigraph_size ||
528 multiplier_size != epigraph_size ||
529 static_cast<PetscInt
>(committed_kappa.size()) != epigraph_size)
531 "Synthetic active-flow vector layouts are inconsistent");
533 PetscScalar *plastic_array =
nullptr;
534 PetscScalar *epigraph_array =
nullptr;
535 PetscScalar *gradient_array =
nullptr;
536 PetscScalar *multiplier_array =
nullptr;
537 const PetscScalar *initial_multiplier_array =
nullptr;
538 const PetscScalar *measure_array =
nullptr;
539 CHKERR VecGetArray(plastic, &plastic_array);
540 CHKERR VecGetArray(epigraph, &epigraph_array);
541 CHKERR VecGetArray(plastic_gradient, &gradient_array);
542 CHKERR VecGetArrayRead(measures, &measure_array);
543 CHKERR VecGetArray(multipliers, &multiplier_array);
544 CHKERR VecGetArrayRead(initial_multipliers, &initial_multiplier_array);
546 t_direction(.31, -.17, .23, -.29, .19);
549 double initial_multiplier_error_local = 0;
550 for (PetscInt block = 0; block != epigraph_size; ++block) {
551 auto t_flow = getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(
554 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(
556 const double flow_norm = .02 * (1. + .05 * block);
557 t_flow(
L) = flow_norm * t_direction(
L) / direction_norm;
558 const double denominator =
560 problem.getDissipationRegularizationEpsilon());
562 denominator - problem.getDissipationRegularizationEpsilon();
563 const double current_yield =
564 problem.getInitialYieldStress() +
565 problem.getIsotropicHardeningModulus() *
566 (committed_kappa[block] + alpha);
567 const double lambda = PetscRealPart(measure_array[block]) * current_yield;
568 epigraph_array[block] = alpha;
569 multiplier_array[block] =
570 lambda / std::sqrt(PetscRealPart(measure_array[block]));
571 const double initial_yield =
572 problem.getInitialYieldStress() +
573 problem.getIsotropicHardeningModulus() * committed_kappa[block];
574 initial_multiplier_error_local = std::max(
575 initial_multiplier_error_local,
576 std::abs(std::sqrt(PetscRealPart(measure_array[block])) *
577 PetscRealPart(initial_multiplier_array[block]) -
578 PetscRealPart(measure_array[block]) * initial_yield));
580 t_flow(
L) / denominator;
582 CHKERR VecRestoreArrayRead(initial_multipliers, &initial_multiplier_array);
583 CHKERR VecRestoreArray(multipliers, &multiplier_array);
584 CHKERR VecRestoreArrayRead(measures, &measure_array);
585 CHKERR VecRestoreArray(plastic_gradient, &gradient_array);
586 CHKERR VecRestoreArray(epigraph, &epigraph_array);
587 CHKERR VecRestoreArray(plastic, &plastic_array);
588 CHKERR VecRestoreSubVector(plastic_cell_measure, kappa_is, &measures);
589 CHKERR VecRestoreSubVector(smooth_gradient, plastic_is, &plastic_gradient);
590 CHKERR VecRestoreSubVector(control, kappa_is, &epigraph);
591 CHKERR VecRestoreSubVector(control, plastic_is, &plastic);
592 CHKERR VecGhostUpdateBegin(control, INSERT_VALUES, SCATTER_FORWARD);
593 CHKERR VecGhostUpdateEnd(control, INSERT_VALUES, SCATTER_FORWARD);
594 CHKERR VecGhostUpdateBegin(smooth_gradient, INSERT_VALUES, SCATTER_FORWARD);
595 CHKERR VecGhostUpdateEnd(smooth_gradient, INSERT_VALUES, SCATTER_FORWARD);
597 constexpr PetscReal gradient_tolerance = 1e-10;
598 constexpr PetscReal constraint_tolerance = 1e-10;
599 double initial_multiplier_error = 0;
600 CHKERR MPI_Allreduce(&initial_multiplier_error_local,
601 &initial_multiplier_error, 1, MPI_DOUBLE, MPI_MAX,
603 if (!std::isfinite(initial_multiplier_error) ||
604 initial_multiplier_error > gradient_tolerance)
606 "Volume-scaled multiplier initialization violates eta "
607 "stationarity: error %g",
608 initial_multiplier_error);
612 CHKERR problem.assembleObjectiveGradient(control, smooth_gradient,
615 CHKERR problem.assembleInequalityJacobian(control, smooth_gradient,
617 CHKERR MatMultTranspose(
context->inequalityJacobian, multipliers,
619 CHKERR VecAXPY(stationarity, -1., objective_gradient);
620 PetscReal stationarity_norm = 0;
621 CHKERR VecNorm(stationarity, NORM_INFINITY, &stationarity_norm);
622 if (!std::isfinite(stationarity_norm) ||
623 stationarity_norm > gradient_tolerance)
625 "Volume-scaled Jacobian and multipliers violate physical "
626 "stationarity: residual %g",
629 std::string diagnostics;
630 CHKERR problem.validateSolution(
context->constraintDM, control,
631 smooth_gradient, multipliers,
632 gradient_tolerance, constraint_tolerance,
634 if (diagnostics.find(
"plastic flow active true") == std::string::npos)
636 "Synthetic KKT point passed validation without reporting active "
638 diagnostics.c_str());
641 <<
"Synthetic active-flow validation atom test passed";
653 t_coordinates(1., 2., 3., 4., 5.);
654 const auto t_trace_free =
656 const auto t_round_trip =
661 t_round_trip_error(
L) = t_round_trip(
L) - t_coordinates(
L);
662 if (std::abs(t_trace_free(
i,
i)) > 1e-14 ||
667 "Trace-free plastic-coordinate basis is inconsistent");
679 "The incremental-optimization layout test currently requires "
680 "-plastic_volume 1 and -cohesive_interface_on 0");
688 DM control_dm = problem.getControlDM();
690 CHKERR getTestFieldIS(control_dm, problem.getPlasticKappaFieldName(),
694 "Incremental optimization has no constraint DM");
695 PetscBool square_constraint_problem = PETSC_TRUE;
697 &square_constraint_problem);
698 if (square_constraint_problem)
700 "Plastic constraint DM must be rectangular");
702 DM constraint_vector_dm =
nullptr;
703 DM constraint_matrix_dm =
nullptr;
704 CHKERR VecGetDM(
context->inequalityConstraints, &constraint_vector_dm);
705 CHKERR MatGetDM(
context->inequalityJacobian, &constraint_matrix_dm);
706 if (constraint_vector_dm !=
context->constraintDM.get() ||
707 constraint_matrix_dm !=
context->constraintDM.get())
709 "Plastic constraint vector or Jacobian lost its constraint DM");
711 PetscInt local_constraint_blocks = 0;
712 PetscInt global_constraint_blocks = 0;
713 CHKERR getTestFieldBlockCounts(control_dm,
714 problem.getPlasticKappaFieldName(), 1,
715 local_constraint_blocks,
716 global_constraint_blocks);
717 PetscInt local_constraint_size = 0;
718 PetscInt global_constraint_size = 0;
719 PetscInt local_control_size = 0;
720 PetscInt global_control_size = 0;
721 PetscInt local_matrix_rows = 0;
722 PetscInt local_matrix_columns = 0;
723 PetscInt global_matrix_rows = 0;
724 PetscInt global_matrix_columns = 0;
726 &local_constraint_size);
727 CHKERR VecGetSize(
context->inequalityConstraints, &global_constraint_size);
728 CHKERR VecGetLocalSize(
context->committedControl, &local_control_size);
729 CHKERR VecGetSize(
context->committedControl, &global_control_size);
730 CHKERR MatGetLocalSize(
context->inequalityJacobian, &local_matrix_rows,
731 &local_matrix_columns);
732 CHKERR MatGetSize(
context->inequalityJacobian, &global_matrix_rows,
733 &global_matrix_columns);
734 if (local_constraint_size != local_constraint_blocks ||
735 global_constraint_size != global_constraint_blocks ||
736 local_matrix_rows != local_constraint_size ||
737 global_matrix_rows != global_constraint_size ||
738 local_matrix_columns != local_control_size ||
739 global_matrix_columns != global_control_size)
741 "Plastic constraint DM vector/matrix dimensions are inconsistent");
743 IS raw_sub_row_is =
nullptr;
746 PetscBool rows_match_kappa = PETSC_FALSE;
747 CHKERR ISEqual(sub_row_is.get(), kappa_is, &rows_match_kappa);
748 if (!rows_match_kappa)
750 "Constraint-DM rows do not match the plastic kappa field");
752 IS raw_sub_col_is =
nullptr;
755 PetscInt local_sub_columns = 0;
756 PetscInt global_sub_columns = 0;
757 CHKERR ISGetLocalSize(sub_col_is, &local_sub_columns);
758 CHKERR ISGetSize(sub_col_is, &global_sub_columns);
759 if (local_sub_columns != local_control_size ||
760 global_sub_columns != global_control_size)
762 "Constraint-DM columns do not span the plastic control space");
763 PetscInt control_start = 0;
764 PetscInt control_end = 0;
765 CHKERR VecGetOwnershipRange(
context->committedControl, &control_start,
767 if (control_end - control_start != local_control_size)
769 "TAO control ownership is inconsistent with its local size");
770 const PetscInt *sub_column_indices =
nullptr;
771 CHKERR ISGetIndices(sub_col_is, &sub_column_indices);
772 for (PetscInt column = 0; column != local_sub_columns; ++column)
773 if (sub_column_indices[column] != control_start + column)
775 "Constraint-DM column numbering differs from the TAO control");
776 CHKERR ISRestoreIndices(sub_col_is, &sub_column_indices);
777 if (
context->candidateControl.get() ==
context->committedControl.get())
779 "TAO candidate aliases the committed control vector");
781 CHKERR checkControlLayout(ep, control_dm,
782 problem.getPlasticFlowFieldName(),
785 CHKERR checkControlLayout(ep, control_dm,
786 problem.getPlasticKappaFieldName(),
788 CHKERR checkPlasticControlEntityPairing(ep, problem);
790 auto check_zero_block = [&](
const PetscInt block_size, PetscInt,
791 PetscScalar *block) {
793 for (PetscInt component = 0; component != block_size; ++component)
794 if (PetscRealPart(block[component]) != 0)
796 "Incremental TAO control was initialized from mesh history");
799 const auto check_zero_control = [&](Vec control) {
801 CHKERR forEachOwnedTestFieldBlock(
802 control_dm, problem.getPlasticFlowFieldName(),
804 [&](PetscInt block, PetscScalar *values) {
805 return check_zero_block(plasticLogarithmicStretchCoordinateSize,
808 CHKERR forEachOwnedTestFieldBlock(
809 control_dm, problem.getPlasticKappaFieldName(), 1, control,
810 [&](PetscInt block, PetscScalar *values) {
811 return check_zero_block(1, block, values);
820 for (
const auto &[entity,
kappa] : initial_kappa_history)
823 "Committed mesh kappa on entity %llu was not preserved "
824 "independently of the TAO increment vector",
825 static_cast<unsigned long long>(entity));
827 constexpr double trial_delta_kappa = 0.25;
828 CHKERR forEachOwnedTestFieldBlock(
829 control_dm, problem.getPlasticFlowFieldName(),
831 [](PetscInt, PetscScalar *values) {
832 for (PetscInt coordinate = 0;
833 coordinate != plasticLogarithmicStretchCoordinateSize;
835 values[coordinate] = coordinate + 1.;
836 return MoFEMErrorCode(0);
838 CHKERR forEachOwnedTestFieldBlock(
839 control_dm, problem.getPlasticKappaFieldName(), 1,
841 [trial_delta_kappa](PetscInt, PetscScalar *value) {
842 value[0] = trial_delta_kappa;
843 return MoFEMErrorCode(0);
845 CHKERR VecGhostUpdateBegin(
context->candidateControl, INSERT_VALUES,
847 CHKERR VecGhostUpdateEnd(
context->candidateControl, INSERT_VALUES,
852 for (
const auto &[entity,
kappa] : mesh_kappa_before_trial)
855 "TAO-vector initialization changed mesh kappa on entity %llu",
856 static_cast<unsigned long long>(entity));
860 auto values = boost::make_shared<MatrixDouble>();
861 auto kappa_increments = boost::make_shared<VectorDouble>();
862 auto count = boost::make_shared<PetscInt>(0);
863 auto fe = boost::make_shared<VolumeElementForcesAndSourcesCore>(ep.
mField);
864 auto bubble_cache = boost::make_shared<CGGUserPolynomialBase::CachePhi>(
866 fe->getUserPolynomialBase() = boost::shared_ptr<BaseFunction>(
868 fe->getRuleHook = [rule](int, int, int) {
return rule; };
869 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
877 kappa_increments,
context->candidateControl, MBTET));
878 fe->getOpPtrVector().push_back(
new OpVerifyPlasticControl(
879 values, kappa_increments, trial_delta_kappa, count));
880 fe->exeTestHook = [&ep](
FEMethod *method) {
886 PetscInt verified_global = 0;
887 const PetscInt verified_local = *count;
888 if (MPI_Allreduce(&verified_local, &verified_global, 1, MPIU_INT, MPI_SUM,
891 "MPI reduction of reconstructed plastic cells failed");
892 PetscInt unused_local = 0;
893 PetscInt global_count = 0;
894 CHKERR getTestFieldBlockCounts(control_dm,
895 problem.getPlasticFlowFieldName(),
897 unused_local, global_count);
898 if (verified_global != global_count)
900 "Plastic reconstruction visited %d blocks; expected %d",
901 static_cast<int>(verified_global),
902 static_cast<int>(global_count));
908 PetscBool candidate_equal = PETSC_FALSE;
909 PetscBool committed_equal = PETSC_FALSE;
914 if (!candidate_equal || !committed_equal)
916 "Trial rollback changed committed fields or failed to restore the "
917 "candidate bitwise");
921 if (!candidate_equal)
923 "Post-commit rollback failed to restore the candidate bitwise");
932 CHKERR VecZeroEntries(accepted_solution);
933 constexpr double accepted_delta_kappa = 0.02;
934 CHKERR forEachOwnedTestFieldBlock(
935 control_dm, problem.getPlasticFlowFieldName(),
937 [accepted_delta_kappa](PetscInt, PetscScalar *values) {
938 for (PetscInt coordinate = 0;
939 coordinate != plasticLogarithmicStretchCoordinateSize;
941 values[coordinate] = 0.;
942 values[0] = accepted_delta_kappa /
943 plasticEquivalentIncrementScale;
944 return MoFEMErrorCode(0);
946 CHKERR forEachOwnedTestFieldBlock(
947 control_dm, problem.getPlasticKappaFieldName(), 1, accepted_solution,
948 [accepted_delta_kappa](PetscInt, PetscScalar *value) {
949 value[0] = accepted_delta_kappa;
950 return MoFEMErrorCode(0);
952 CHKERR VecGhostUpdateBegin(accepted_solution, INSERT_VALUES,
954 CHKERR VecGhostUpdateEnd(accepted_solution, INSERT_VALUES,
956 CHKERR VecCopy(accepted_solution, accepted_solution_before);
961 PetscBool accepted_solution_unchanged = PETSC_FALSE;
962 PetscBool state_unchanged = PETSC_FALSE;
963 CHKERR VecEqual(accepted_solution, accepted_solution_before,
964 &accepted_solution_unchanged);
965 CHKERR VecEqual(
state, state_before_commit, &state_unchanged);
966 if (!accepted_solution_unchanged || !state_unchanged)
968 "Plastic commit modified its read-only solution or state input");
977 for (
const auto &[entity, before] : plastic_history_before_commit) {
978 const auto after = plastic_history_after_commit.find(entity);
979 if (after == plastic_history_after_commit.end())
981 "Committed plastic-H entity %llu disappeared",
982 static_cast<unsigned long long>(entity));
983 for (PetscInt coordinate = 0;
986 const double increment =
990 if (std::abs(after->second[coordinate] -
991 (before[coordinate] + increment)) > 1e-14)
993 "Plastic-H additive commit failed on entity %llu",
994 static_cast<unsigned long long>(entity));
997 for (
const auto &[entity, before] : kappa_history_before_commit) {
998 const auto after = kappa_history_after_commit.find(entity);
999 if (after == kappa_history_after_commit.end() ||
1000 std::abs(after->second - (before + accepted_delta_kappa)) > 1e-14)
1002 "Plastic-kappa additive commit failed on entity %llu",
1003 static_cast<unsigned long long>(entity));
1006 auto check_zero_flow = [&](boost::shared_ptr<FieldEntity> field_entity) {
1008 for (
const double value : field_entity->getEntFieldData())
1011 "Transient plastic-flow mesh data were not cleared");
1018 if (kappa_history_after_clear != kappa_history_after_commit)
1020 "Clearing transient plastic flow erased committed kappa");
1022 PetscInt global_size = 0;
1024 PetscInt local_blocks = 0;
1025 PetscInt global_blocks = 0;
1026 CHKERR getTestFieldBlockCounts(control_dm,
1027 problem.getPlasticFlowFieldName(),
1029 local_blocks, global_blocks);
1033 "Linear hardening added an unnecessary TAO control block");
1035 <<
"Incremental-optimization layout verified: global control size "
1036 << global_size <<
", plastic blocks " << ep.
plasticVolumes->size();
1049 "The equilibrated-value identity test is plastic-only");
1051 double fd_epsilon = 1e-6;
1052 double relative_tolerance = 1e-4;
1053 double absolute_tolerance = 1e-8;
1055 "-equilibrated_value_fd_epsilon", &fd_epsilon,
1058 "-equilibrated_value_gradient_rtol",
1059 &relative_tolerance, PETSC_NULLPTR);
1061 "-equilibrated_value_gradient_atol",
1062 &absolute_tolerance, PETSC_NULLPTR);
1063 if (!(fd_epsilon > 0) || !(relative_tolerance >= 0) ||
1064 !(absolute_tolerance >= 0))
1066 "Invalid equilibrated-value derivative test tolerances");
1068 constexpr double inv_sqrt_two = 0.70710678118654752440;
1070 inv_sqrt_two, 0., 0., -inv_sqrt_two, 0., 0.);
1075 auto restore = [&]() {
1082 auto solve_equilibrium = [&]() {
1088 "Equilibrated-value fixed-control solve did not converge "
1089 "(status %d, error %d)",
1093 auto solve_at_scale = [&](
const double scale,
double &value) {
1098 CHKERR solve_equilibrium();
1103 CHKERR solve_equilibrium();
1106 auto reduced_gradient =
1110 CHKERR VecZeroEntries(direction_vector);
1111 const auto t_direction_coordinates =
1113 CHKERR forEachOwnedTestFieldBlock(
1116 [&t_direction_coordinates](PetscInt, PetscScalar *values) {
1118 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(
1120 FTENSOR_INDEX(plasticLogarithmicStretchCoordinateSize, L);
1121 t_values(L) = t_direction_coordinates(L);
1122 return MoFEMErrorCode(0);
1124 PetscScalar assembled_derivative_scalar = 0;
1125 CHKERR VecDot(reduced_gradient, direction_vector,
1126 &assembled_derivative_scalar);
1127 const double assembled_derivative =
1128 PetscRealPart(assembled_derivative_scalar);
1129 double value_plus = 0;
1130 double value_minus = 0;
1131 const MoFEMErrorCode plus_error = solve_at_scale(fd_epsilon, value_plus);
1133 plus_error ? 0 : solve_at_scale(-fd_epsilon, value_minus);
1139 const double finite_difference =
1140 (value_plus - value_minus) / (2 * fd_epsilon);
1141 const double absolute_error =
1142 std::abs(finite_difference - assembled_derivative);
1143 const double tolerance =
1144 absolute_tolerance +
1145 relative_tolerance *
1146 std::max(std::abs(finite_difference), std::abs(assembled_derivative));
1148 <<
"Reduced Helmholtz plastic derivative: finite difference "
1150 << finite_difference <<
", assembled = " << assembled_derivative
1151 <<
", absolute error = " << absolute_error
1152 <<
", tolerance = " << tolerance;
1153 if (!std::isfinite(finite_difference) ||
1154 !std::isfinite(assembled_derivative) || absolute_error > tolerance)
1156 "Reduced Helmholtz value/adjoint-gradient identity is "
1157 "inconsistent: error = %g, tolerance = %g",
1158 absolute_error, tolerance);
1171 DM control_dm = problem.getControlDM();
1180 context->gradientAssemblySeconds != 0)
1182 "Objective-only transaction must equilibrate without assembling "
1186 PetscReal reference_objective = 0;
1189 context,
context->referenceControl, reference_objective,
nullptr,
1194 context->gradientAssemblySeconds != 0)
1196 "TAO objective-only callback did not reuse the value cache");
1201 PetscBool state_reused = PETSC_FALSE;
1202 CHKERR VecEqual(value_state,
context->equilibratedState, &state_reused);
1209 "Gradient request did not reuse its objective-only equilibrium");
1215 "Transaction returned invalid diagnostics or reported "
1216 "outer stationarity before the complete objective was active");
1222 const auto first_gradient_seconds =
context->gradientAssemblySeconds;
1225 0.31, -0.17, 0.23, -0.24, 0.19, -0.07);
1226 const auto t_direction_coordinates =
1229 CHKERR VecZeroEntries(direction_vector);
1230 CHKERR forEachOwnedTestFieldBlock(
1231 control_dm, problem.getPlasticFlowFieldName(),
1233 [&t_direction_coordinates](PetscInt, PetscScalar *values) {
1235 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(
1237 FTENSOR_INDEX(plasticLogarithmicStretchCoordinateSize, L);
1238 t_values(L) = t_direction_coordinates(L);
1239 return MoFEMErrorCode(0);
1243 PetscScalar vector_derivative = 0;
1244 CHKERR VecDot(fixed_state_force, direction_vector, &vector_derivative);
1245 double scalar_derivative = 0;
1247 const double force_error =
1248 std::abs(PetscRealPart(vector_derivative) - scalar_derivative);
1249 const double force_tolerance =
1250 1e-11 * std::max({1., std::abs(PetscRealPart(vector_derivative)),
1251 std::abs(scalar_derivative)});
1252 if (force_error > force_tolerance)
1254 "Fixed-state mixed plastic conjugate does not reproduce the "
1255 "exact discrete directional variation: error %g > %g",
1256 force_error, force_tolerance);
1262 PetscBool cached_gradient_equal = PETSC_FALSE;
1263 PetscBool cached_state_equal = PETSC_FALSE;
1264 CHKERR VecEqual(
context->gradient, first_gradient, &cached_gradient_equal);
1265 CHKERR VecEqual(
context->equilibratedState, first_state, &cached_state_equal);
1268 !cached_gradient_equal || !cached_state_equal ||
1269 context->gradientAssemblySeconds != first_gradient_seconds)
1271 "Repeated transaction evaluation was not served deterministically "
1272 "from the state/value/gradient cache");
1275 PetscReal first_objective = 0;
1279 first_objective_gradient, complete);
1282 PetscReal repeated_objective = 0;
1285 context->objectiveGradient, complete);
1286 PetscBool objective_gradient_restored = PETSC_FALSE;
1287 CHKERR VecEqual(
context->objectiveGradient, first_objective_gradient,
1288 &objective_gradient_restored);
1290 repeated_objective != first_objective || !objective_gradient_restored ||
1291 context->gradientAssemblySeconds != first_gradient_seconds)
1293 "Complete objective gradient was not restored from the cached "
1294 "conservative gradient after TAO modified its workspace");
1298 0.31, -0.17, 0.23, -0.24, 0.19, -0.07);
1299 const auto t_direction_coordinates =
1302 CHKERR VecZeroEntries(direction_vector);
1303 CHKERR forEachOwnedTestFieldBlock(
1304 control_dm, problem.getPlasticFlowFieldName(),
1306 [&t_direction_coordinates](PetscInt, PetscScalar *values) {
1308 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(
1310 FTENSOR_INDEX(plasticLogarithmicStretchCoordinateSize, L);
1311 t_values(L) = t_direction_coordinates(L);
1312 return MoFEMErrorCode(0);
1314 constexpr double epsilon = 1e-5;
1317 CHKERR VecWAXPY(plus_control, epsilon, direction_vector,
1319 CHKERR VecWAXPY(minus_control, -epsilon, direction_vector,
1321 const auto state_solve =
context->stateSolve;
1322 const auto state_count =
context->stateSolveCount;
1325 CHKERR VecSet(trial_state, 17);
1328 report.equilibriumNorm = 1;
1331 PetscReal rejected_objective = 0;
1333 const auto rejection_error =
1335 context, plus_control, rejected_objective,
nullptr, rejected);
1336 context->stateSolve = state_solve;
1338 PetscBool control_rolled_back = PETSC_FALSE;
1339 PetscBool state_rolled_back = PETSC_FALSE;
1341 &control_rolled_back);
1343 &state_rolled_back);
1345 !std::isinf(rejected_objective) || rejected_objective < 0 ||
1347 !control_rolled_back || !state_rolled_back ||
1348 context->gradientAssemblySeconds != first_gradient_seconds)
1350 "Rejected objective-only trial did not restore state and "
1351 "controls without gradient assembly");
1361 context->gradientAssemblySeconds != first_gradient_seconds)
1363 "Objective-only plastic-flow trials did not converge without "
1364 "gradient assembly");
1365 PetscScalar assembled = 0;
1366 CHKERR VecDot(first_gradient, direction_vector, &assembled);
1367 const double finite_difference =
1369 const double tolerance =
1370 2e-6 + 5e-4 * std::max(std::abs(finite_difference),
1371 std::abs(PetscRealPart(assembled)));
1372 if (std::abs(finite_difference - PetscRealPart(assembled)) > tolerance)
1374 "Direct trial DeltaHp incremental-objective gradient finite "
1376 "failed: %g versus %g",
1377 finite_difference, PetscRealPart(assembled));
1383 "Could not restore reference state after plastic trials");
1389 <<
"Incremental-optimization transaction/cache atom test passed";
1404 t_history_coordinates(.13, -.29, .17, .31, -.11);
1405 const auto t_history =
1412 DM control_dm = problem.getControlDM();
1414 CHKERR getTestFieldIS(control_dm, problem.getPlasticKappaFieldName(),
1417 CHKERR createTestPlasticCellMeasure(ep, control_dm, plastic_cell_measure);
1418 std::vector<double> committed_kappa;
1419 CHKERR getOwnedTestKappaValues(ep, control_dm, committed_kappa);
1421 double epsilon = 1e-5;
1422 double relative_tolerance = 5e-4;
1423 double absolute_tolerance = 2e-6;
1425 "-incremental_optimization_derivative_epsilon",
1426 &epsilon, PETSC_NULLPTR);
1428 "-incremental_optimization_derivative_rtol",
1429 &relative_tolerance, PETSC_NULLPTR);
1431 "-incremental_optimization_derivative_atol",
1432 &absolute_tolerance, PETSC_NULLPTR);
1439 "Objective derivative test could not establish equilibrium");
1445 t_centre(.31, -.17, .23, -.24, .19);
1447 CHKERR forEachOwnedTestFieldBlock(
1448 control_dm, problem.getPlasticFlowFieldName(),
1450 [&](PetscInt, PetscScalar *values) {
1452 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(values);
1453 FTENSOR_INDEX(plasticLogarithmicStretchCoordinateSize, L);
1454 t_values(L) = 1e-3 * t_centre(L) / centre_norm;
1455 return MoFEMErrorCode(0);
1457 CHKERR forEachOwnedTestFieldBlock(
1458 control_dm, problem.getPlasticKappaFieldName(), 1, centre,
1459 [](PetscInt, PetscScalar *value) {
1461 return MoFEMErrorCode(0);
1463 CHKERR VecGhostUpdateBegin(centre, INSERT_VALUES, SCATTER_FORWARD);
1464 CHKERR VecGhostUpdateEnd(centre, INSERT_VALUES, SCATTER_FORWARD);
1467 PetscReal objective = 0;
1470 context, centre, objective, gradient, centre_evaluation);
1473 "Objective derivative centre did not equilibrate");
1475 Vec epigraph =
nullptr;
1476 Vec epigraph_gradient =
nullptr;
1477 Vec measures =
nullptr;
1478 CHKERR VecGetSubVector(centre, kappa_is, &epigraph);
1479 CHKERR VecGetSubVector(gradient, kappa_is, &epigraph_gradient);
1480 CHKERR VecGetSubVector(plastic_cell_measure, kappa_is, &measures);
1481 PetscInt epigraph_size = 0;
1482 PetscInt gradient_size = 0;
1483 PetscInt measure_size = 0;
1484 CHKERR VecGetLocalSize(epigraph, &epigraph_size);
1485 CHKERR VecGetLocalSize(epigraph_gradient, &gradient_size);
1486 CHKERR VecGetLocalSize(measures, &measure_size);
1487 if (gradient_size != epigraph_size || measure_size != epigraph_size ||
1488 static_cast<PetscInt
>(committed_kappa.size()) != epigraph_size) {
1489 CHKERR VecRestoreSubVector(plastic_cell_measure, kappa_is, &measures);
1490 CHKERR VecRestoreSubVector(gradient, kappa_is, &epigraph_gradient);
1491 CHKERR VecRestoreSubVector(centre, kappa_is, &epigraph);
1493 "Objective test kappa layouts are inconsistent");
1495 const PetscScalar *epigraph_array =
nullptr;
1496 const PetscScalar *gradient_array =
nullptr;
1497 const PetscScalar *measure_array =
nullptr;
1498 CHKERR VecGetArrayRead(epigraph, &epigraph_array);
1499 CHKERR VecGetArrayRead(epigraph_gradient, &gradient_array);
1500 CHKERR VecGetArrayRead(measures, &measure_array);
1501 double expected_dissipation_local = 0;
1502 double maximum_epigraph_gradient_error_local = 0;
1503 for (PetscInt block = 0; block != epigraph_size; ++block) {
1504 const double delta_kappa = PetscRealPart(epigraph_array[block]);
1505 const double kappa_n = committed_kappa[block];
1506 const double hardening_modulus =
1507 problem.getIsotropicHardeningModulus();
1508 const double expected_gradient =
1509 PetscRealPart(measure_array[block]) *
1510 (problem.getInitialYieldStress() +
1511 hardening_modulus * (kappa_n + delta_kappa));
1512 expected_dissipation_local += PetscRealPart(measure_array[block]) *
1513 ((problem.getInitialYieldStress() +
1514 hardening_modulus * kappa_n) *
1516 0.5 * hardening_modulus * delta_kappa *
1518 maximum_epigraph_gradient_error_local = std::max(
1519 maximum_epigraph_gradient_error_local,
1520 std::abs(PetscRealPart(gradient_array[block]) - expected_gradient));
1522 CHKERR VecRestoreArrayRead(measures, &measure_array);
1523 CHKERR VecRestoreArrayRead(epigraph_gradient, &gradient_array);
1524 CHKERR VecRestoreArrayRead(epigraph, &epigraph_array);
1525 CHKERR VecRestoreSubVector(plastic_cell_measure, kappa_is, &measures);
1526 CHKERR VecRestoreSubVector(gradient, kappa_is, &epigraph_gradient);
1527 CHKERR VecRestoreSubVector(centre, kappa_is, &epigraph);
1528 double expected_dissipation = 0;
1529 double maximum_epigraph_gradient_error = 0;
1530 CHKERR MPI_Allreduce(&expected_dissipation_local, &expected_dissipation, 1,
1532 CHKERR MPI_Allreduce(&maximum_epigraph_gradient_error_local,
1533 &maximum_epigraph_gradient_error, 1, MPI_DOUBLE, MPI_MAX,
1535 double assembled_dissipation = 0;
1537 assembled_dissipation);
1538 const double dissipation_tolerance =
1539 1e-13 * std::max(1., std::abs(expected_dissipation));
1540 if (std::abs(assembled_dissipation - expected_dissipation) >
1541 dissipation_tolerance ||
1542 maximum_epigraph_gradient_error > dissipation_tolerance)
1544 "Kappa-increment objective value or gradient is inconsistent "
1545 "with linear isotropic hardening");
1552 CHKERR VecZeroEntries(plastic_direction);
1553 CHKERR VecZeroEntries(plastic_direction_two);
1554 CHKERR VecZeroEntries(plastic_direction_three);
1555 CHKERR VecZeroEntries(epigraph_direction);
1557 t_plastic_direction(.37, -.19, .11, .29, -.23);
1559 t_plastic_direction_two(-.07, .43, -.31, .13, .29);
1561 t_plastic_direction_three(.19, .11, -.41, .37, -.17);
1562 CHKERR forEachOwnedTestFieldBlock(
1563 control_dm, problem.getPlasticFlowFieldName(),
1565 [&t_plastic_direction](PetscInt block, PetscScalar *values) {
1567 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(values);
1568 FTENSOR_INDEX(plasticLogarithmicStretchCoordinateSize, L);
1569 t_values(L) = (1. + .125 * block) * t_plastic_direction(L);
1570 return MoFEMErrorCode(0);
1572 CHKERR forEachOwnedTestFieldBlock(
1573 control_dm, problem.getPlasticFlowFieldName(),
1575 [&t_plastic_direction_two](PetscInt block, PetscScalar *values) {
1577 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(values);
1578 FTENSOR_INDEX(plasticLogarithmicStretchCoordinateSize, L);
1579 const double sign = block % 2 ? -1. : 1.;
1580 t_values(L) = sign * (1. + .075 * block) * t_plastic_direction_two(L);
1581 return MoFEMErrorCode(0);
1583 CHKERR forEachOwnedTestFieldBlock(
1584 control_dm, problem.getPlasticFlowFieldName(),
1586 [&t_plastic_direction_three](PetscInt block, PetscScalar *values) {
1588 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(values);
1589 FTENSOR_INDEX(plasticLogarithmicStretchCoordinateSize, L);
1590 const double scale[] = {-1.25, .5, 1.75};
1591 t_values(
L) =
scale[block % 3] * t_plastic_direction_three(
L);
1594 CHKERR forEachOwnedTestFieldBlock(
1595 control_dm, problem.getPlasticKappaFieldName(), 1, epigraph_direction,
1596 [](PetscInt block, PetscScalar *value) {
1597 value[0] = block % 2 ? -.75 : 1.;
1598 return MoFEMErrorCode(0);
1600 PetscReal plastic_direction_norm = 0;
1601 PetscReal plastic_direction_two_norm = 0;
1602 PetscReal plastic_direction_three_norm = 0;
1603 PetscReal epigraph_direction_norm = 0;
1604 CHKERR VecNormalize(plastic_direction, &plastic_direction_norm);
1605 CHKERR VecNormalize(plastic_direction_two, &plastic_direction_two_norm);
1606 CHKERR VecNormalize(plastic_direction_three, &plastic_direction_three_norm);
1607 CHKERR VecNormalize(epigraph_direction, &epigraph_direction_norm);
1608 if (!(plastic_direction_norm > 0) || !(plastic_direction_two_norm > 0) ||
1609 !(plastic_direction_three_norm > 0) || !(epigraph_direction_norm > 0))
1611 "Deterministic objective direction is zero");
1612 PetscScalar dot_one_two = 0;
1613 PetscScalar dot_one_three = 0;
1614 PetscScalar dot_two_three = 0;
1615 CHKERR VecDot(plastic_direction, plastic_direction_two, &dot_one_two);
1616 CHKERR VecDot(plastic_direction, plastic_direction_three, &dot_one_three);
1617 CHKERR VecDot(plastic_direction_two, plastic_direction_three, &dot_two_three);
1618 const double a = PetscRealPart(dot_one_two);
1619 const double b = PetscRealPart(dot_one_three);
1620 const double c = PetscRealPart(dot_two_three);
1621 const double gram_determinant = 1. + 2. *
a * b *
c -
a *
a - b * b -
c *
c;
1622 if (!(gram_determinant > 1e-8))
1624 "Plastic objective directions are not linearly independent: "
1625 "Gram determinant %g",
1627 CHKERR VecWAXPY(mixed_direction, 1., epigraph_direction, plastic_direction);
1628 PetscReal mixed_direction_norm = 0;
1629 CHKERR VecNormalize(mixed_direction, &mixed_direction_norm);
1630 if (!(mixed_direction_norm > 0))
1632 "Mixed objective direction is zero");
1634 auto reset_state = [&]() {
1642 const OperatorsTester::ScalarFunction evaluate = [&](
Vec control,
1646 const auto gradient_seconds =
context->gradientAssemblySeconds;
1647 IncrementalObjectiveEvaluation evaluation;
1649 context, control, value,
nullptr, evaluation);
1651 evaluation.smoothGradient || evaluation.objectiveGradient ||
1652 context->gradientAssemblySeconds != gradient_seconds)
1654 "Perturbed objective did not equilibrate without gradient "
1658 double maximum_error = 0;
1659 auto check_direction = [&](
const char *name,
Vec direction) {
1661 PetscReal finite_difference = 0;
1662 PetscReal assembled = 0;
1663 CHKERR operators_tester->checkScalarCentralFiniteDifference(
1664 centre, direction, gradient, epsilon, evaluate, finite_difference,
1666 const double error = std::abs(finite_difference - assembled);
1667 const double tolerance =
1668 absolute_tolerance +
1669 relative_tolerance *
1670 std::max(std::abs(finite_difference), std::abs(assembled));
1671 if (!std::isfinite(finite_difference) || !std::isfinite(assembled) ||
1674 "%s objective derivative mismatch: error %g > %g", name, error,
1676 maximum_error = std::max(maximum_error, error);
1678 <<
"OperatorsTester " << name
1679 <<
" objective derivative: finite difference " << finite_difference
1680 <<
", assembled " << assembled <<
", error " << error;
1683 CHKERR check_direction(
"plastic-only", plastic_direction);
1684 CHKERR check_direction(
"plastic-only-two", plastic_direction_two);
1685 CHKERR check_direction(
"plastic-only-three", plastic_direction_three);
1686 CHKERR check_direction(
"epigraph-only", epigraph_direction);
1687 CHKERR check_direction(
"mixed", mixed_direction);
1696 <<
"Maximum objective directional-derivative error " << maximum_error;
1702 Vec control, Vec smooth_gradient) {
1706 "INCREMENTAL_OPTIMIZATION_COUPLED_TEST");
1720 CHKERR DMSetUp(coupled_dm);
1724 CHKERR VecZeroEntries(coupled_constraints);
1726 coupled_constraints);
1727 CHKERR MatZeroEntries(coupled_jacobian);
1729 problem, control, smooth_gradient, coupled_jacobian);
1731 IS raw_extra_row_is =
nullptr;
1735 Vec extra_constraints =
nullptr;
1736 CHKERR VecGetSubVector(coupled_constraints, extra_row_is,
1737 &extra_constraints);
1738 PetscReal extra_constraint_norm = 0;
1739 CHKERR VecNorm(extra_constraints, NORM_INFINITY, &extra_constraint_norm);
1740 CHKERR VecRestoreSubVector(coupled_constraints, extra_row_is,
1741 &extra_constraints);
1744 CHKERR VecSet(unit_control, 1);
1745 CHKERR VecGhostUpdateBegin(unit_control, INSERT_VALUES, SCATTER_FORWARD);
1746 CHKERR VecGhostUpdateEnd(unit_control, INSERT_VALUES, SCATTER_FORWARD);
1748 CHKERR MatMult(coupled_jacobian, unit_control, coupled_action);
1749 Vec extra_action =
nullptr;
1750 CHKERR VecGetSubVector(coupled_action, extra_row_is, &extra_action);
1751 PetscReal extra_action_norm = 0;
1752 CHKERR VecNorm(extra_action, NORM_INFINITY, &extra_action_norm);
1753 CHKERR VecRestoreSubVector(coupled_action, extra_row_is, &extra_action);
1754 if (extra_constraint_norm > 1e-14 || extra_action_norm > 1e-14)
1756 "Plastic contribution modified non-plastic constraint rows");
1767 PetscBool active_validation_only = PETSC_FALSE;
1769 "-incremental_optimization_active_validation_only",
1770 &active_validation_only, PETSC_NULLPTR);
1771 if (active_validation_only) {
1775 DM control_dm = problem.getControlDM();
1778 CHKERR getTestFieldIS(control_dm, problem.getPlasticFlowFieldName(),
1780 CHKERR getTestFieldIS(control_dm, problem.getPlasticKappaFieldName(),
1783 CHKERR createTestPlasticCellMeasure(ep, control_dm, plastic_cell_measure);
1784 const double regularization_epsilon =
1785 problem.getDissipationRegularizationEpsilon();
1786 std::vector<double> constraint_scales;
1787 CHKERR getTestPlasticConstraintScales(plastic_cell_measure, kappa_is,
1789 double epsilon = 1e-7;
1790 double relative_tolerance = 1e-7;
1791 double absolute_tolerance = 1e-10;
1793 "-incremental_optimization_derivative_epsilon",
1794 &epsilon, PETSC_NULLPTR);
1796 "-incremental_optimization_derivative_rtol",
1797 &relative_tolerance, PETSC_NULLPTR);
1799 "-incremental_optimization_derivative_atol",
1800 &absolute_tolerance, PETSC_NULLPTR);
1806 if (
context->stateSolveCount ||
context->gradientAssemblySeconds != 0 ||
1807 context->cachedEvaluation.smoothGradient)
1809 "Independent plastic constraints requested equilibrium or "
1810 "adjoint evaluation");
1812 auto baseline_objective_gradient =
1814 PetscReal baseline_objective = 0;
1818 baseline_objective_gradient, baseline);
1819 if (baseline.
stateStatus != EquilibriumSolveStatus::Converged)
1821 "Constraint derivative test could not establish equilibrium");
1826 Vec baseline_gradient =
nullptr;
1827 Vec baseline_measures =
nullptr;
1829 &baseline_gradient);
1830 CHKERR VecGetSubVector(plastic_cell_measure, kappa_is, &baseline_measures);
1831 const PetscScalar *baseline_gradient_array =
nullptr;
1832 const PetscScalar *baseline_measure_array =
nullptr;
1833 PetscInt baseline_measure_size = 0;
1834 CHKERR VecGetLocalSize(baseline_measures, &baseline_measure_size);
1835 CHKERR VecGetArrayRead(baseline_gradient, &baseline_gradient_array);
1836 CHKERR VecGetArrayRead(baseline_measures, &baseline_measure_array);
1837 double maximum_baseline_q_local = 0;
1838 for (PetscInt block = 0; block != baseline_measure_size; ++block) {
1839 const double measure = PetscRealPart(baseline_measure_array[block]);
1840 const auto t_coefficient_force =
1841 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(
1842 baseline_gradient_array +
1846 t_force(
L) = -t_coefficient_force(
L) / measure;
1847 maximum_baseline_q_local =
1848 std::max(maximum_baseline_q_local,
1851 CHKERR VecRestoreArrayRead(baseline_measures, &baseline_measure_array);
1852 CHKERR VecRestoreArrayRead(baseline_gradient, &baseline_gradient_array);
1853 CHKERR VecRestoreSubVector(plastic_cell_measure, kappa_is,
1854 &baseline_measures);
1856 &baseline_gradient);
1857 double maximum_baseline_q = 0;
1858 CHKERR MPI_Allreduce(&maximum_baseline_q_local, &maximum_baseline_q, 1,
1861 <<
"Constraint derivative baseline maximum q " << maximum_baseline_q;
1863 if (regularization_epsilon == 0) {
1872 Vec apex_gradient =
nullptr;
1873 Vec apex_measures =
nullptr;
1876 CHKERR VecGetSubVector(plastic_cell_measure, kappa_is, &apex_measures);
1877 PetscInt apex_measure_size = 0;
1878 CHKERR VecGetLocalSize(apex_measures, &apex_measure_size);
1879 const PetscScalar *apex_gradient_array =
nullptr;
1880 const PetscScalar *apex_measure_array =
nullptr;
1881 const PetscInt *apex_plastic_indices =
nullptr;
1882 const PetscInt *apex_epigraph_indices =
nullptr;
1883 CHKERR VecGetArrayRead(apex_gradient, &apex_gradient_array);
1884 CHKERR VecGetArrayRead(apex_measures, &apex_measure_array);
1885 CHKERR ISGetIndices(plastic_is, &apex_plastic_indices);
1886 CHKERR ISGetIndices(kappa_is, &apex_epigraph_indices);
1887 PetscInt apex_row_start = 0;
1888 PetscInt apex_row_end = 0;
1889 CHKERR MatGetOwnershipRange(
context->inequalityJacobian, &apex_row_start,
1891 if (apex_row_end - apex_row_start != apex_measure_size)
1893 "Objective-evaluation apex rows do not match cell measures");
1894 double adapter_error_local = 0;
1895 for (PetscInt block = 0; block != apex_measure_size; ++block) {
1896 const double measure = PetscRealPart(apex_measure_array[block]);
1897 const auto t_coefficient_force =
1898 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(
1899 apex_gradient_array +
1903 t_force(
L) = -t_coefficient_force(
L) / measure;
1906 const double denominator = std::max(problem.getInitialYieldStress(),
q);
1908 const PetscInt row = apex_row_start + block;
1911 apex_plastic_indices +
1914 for (PetscInt coordinate = 0;
1916 adapter_error_local =
1917 std::max(adapter_error_local,
1918 std::abs(PetscRealPart(row_values[coordinate]) +
1919 constraint_scales[block] *
1920 t_force(coordinate) / denominator));
1921 PetscScalar epigraph_value = 0;
1922 CHKERR MatGetValues(
context->inequalityJacobian, 1, &row, 1,
1923 apex_epigraph_indices + block, &epigraph_value);
1924 adapter_error_local = std::max(
1925 adapter_error_local,
1926 std::abs(PetscRealPart(epigraph_value) - constraint_scales[block]));
1928 CHKERR ISRestoreIndices(kappa_is, &apex_epigraph_indices);
1929 CHKERR ISRestoreIndices(plastic_is, &apex_plastic_indices);
1930 CHKERR VecRestoreArrayRead(apex_measures, &apex_measure_array);
1931 CHKERR VecRestoreArrayRead(apex_gradient, &apex_gradient_array);
1932 CHKERR VecRestoreSubVector(plastic_cell_measure, kappa_is,
1936 double adapter_error = 0;
1937 CHKERR MPI_Allreduce(&adapter_error_local, &adapter_error, 1, MPI_DOUBLE,
1939 if (adapter_error > 1e-12)
1941 "Same-control objective-evaluation apex adapter row error %g",
1943 CHKERR VecCopy(preserved_baseline_gradient,
context->gradient);
1950 t_centre(.31, -.17, .23, -.24, .19);
1952 CHKERR forEachOwnedTestFieldBlock(
1953 control_dm, problem.getPlasticFlowFieldName(),
1955 [&](PetscInt block, PetscScalar *values) {
1957 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(values);
1958 FTENSOR_INDEX(plasticLogarithmicStretchCoordinateSize, L);
1959 t_values(L) = 1e-2 * (1. + .125 * block) * t_centre(L) / centre_norm;
1960 return MoFEMErrorCode(0);
1962 CHKERR forEachOwnedTestFieldBlock(
1963 control_dm, problem.getPlasticKappaFieldName(), 1, centre,
1964 [](PetscInt block, PetscScalar *value) {
1965 value[0] = 1.5e-2 + 5e-4 * block;
1966 return MoFEMErrorCode(0);
1968 CHKERR VecGhostUpdateBegin(centre, INSERT_VALUES, SCATTER_FORWARD);
1969 CHKERR VecGhostUpdateEnd(centre, INSERT_VALUES, SCATTER_FORWARD);
1971 const auto baseline_state_count =
context->stateSolveCount;
1972 const auto baseline_gradient_seconds =
context->gradientAssemblySeconds;
1977 PetscBool smooth_gradient_unchanged = PETSC_FALSE;
1978 PetscBool objective_gradient_unchanged = PETSC_FALSE;
1979 CHKERR VecEqual(
context->gradient, preserved_baseline_gradient,
1980 &smooth_gradient_unchanged);
1981 CHKERR VecEqual(
context->objectiveGradient, baseline_objective_gradient,
1982 &objective_gradient_unchanged);
1983 if (
context->stateSolveCount != baseline_state_count ||
1984 context->gradientAssemblySeconds != baseline_gradient_seconds ||
1985 !smooth_gradient_unchanged || !objective_gradient_unchanged)
1987 "Plastic constraint trials recomputed or modified objective "
1992 Vec plastic_centre =
nullptr;
1993 Vec epigraph_centre =
nullptr;
1994 CHKERR VecGetSubVector(centre, plastic_is, &plastic_centre);
1995 CHKERR VecGetSubVector(centre, kappa_is, &epigraph_centre);
1996 PetscInt plastic_size = 0;
1997 PetscInt epigraph_size = 0;
1998 PetscInt constraint_size = 0;
1999 CHKERR VecGetLocalSize(plastic_centre, &plastic_size);
2000 CHKERR VecGetLocalSize(epigraph_centre, &epigraph_size);
2001 CHKERR VecGetLocalSize(
context->inequalityConstraints, &constraint_size);
2003 constraint_size != epigraph_size)
2005 "Constraint test layouts are inconsistent");
2006 const PetscScalar *plastic_array =
nullptr;
2007 const PetscScalar *epigraph_array =
nullptr;
2008 const PetscScalar *constraint_array =
nullptr;
2009 const PetscInt *plastic_indices =
nullptr;
2010 const PetscInt *epigraph_indices =
nullptr;
2011 CHKERR VecGetArrayRead(plastic_centre, &plastic_array);
2012 CHKERR VecGetArrayRead(epigraph_centre, &epigraph_array);
2013 CHKERR VecGetArrayRead(
context->inequalityConstraints, &constraint_array);
2014 CHKERR ISGetIndices(plastic_is, &plastic_indices);
2015 CHKERR ISGetIndices(kappa_is, &epigraph_indices);
2016 PetscInt centre_row_start = 0;
2017 PetscInt centre_row_end = 0;
2018 CHKERR MatGetOwnershipRange(
context->inequalityJacobian, ¢re_row_start,
2020 if (centre_row_end - centre_row_start != epigraph_size)
2022 "Constraint matrix rows do not pair with epigraph blocks");
2023 double constitutive_error_local = 0;
2024 for (PetscInt block = 0; block != epigraph_size; ++block) {
2026 const auto t_increment =
2027 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(
2028 plastic_array + base);
2031 const double expected_equivalent_increment =
2032 regularization_epsilon > 0
2033 ? std::hypot(scaled_norm, regularization_epsilon) -
2034 regularization_epsilon
2036 const double expected_constraint =
2037 constraint_scales[block] *
2038 (PetscRealPart(epigraph_array[block]) - expected_equivalent_increment);
2039 constitutive_error_local = std::max(
2040 constitutive_error_local,
2041 std::abs(PetscRealPart(constraint_array[block]) - expected_constraint));
2044 const PetscInt row = centre_row_start + block;
2047 plastic_indices + base, plastic_values);
2048 const double denominator = std::hypot(scaled_norm, regularization_epsilon);
2049 for (PetscInt coordinate = 0;
2051 const double expected =
2053 t_increment(coordinate) / denominator;
2054 constitutive_error_local = std::max(
2055 constitutive_error_local,
2056 std::abs(PetscRealPart(plastic_values[coordinate]) - expected));
2058 PetscScalar epigraph_value = 0;
2059 CHKERR MatGetValues(
context->inequalityJacobian, 1, &row, 1,
2060 epigraph_indices + block, &epigraph_value);
2061 constitutive_error_local = std::max(
2062 constitutive_error_local,
2063 std::abs(PetscRealPart(epigraph_value) - constraint_scales[block]));
2065 CHKERR ISRestoreIndices(kappa_is, &epigraph_indices);
2066 CHKERR ISRestoreIndices(plastic_is, &plastic_indices);
2067 CHKERR VecRestoreArrayRead(
context->inequalityConstraints, &constraint_array);
2068 CHKERR VecRestoreArrayRead(epigraph_centre, &epigraph_array);
2069 CHKERR VecRestoreArrayRead(plastic_centre, &plastic_array);
2070 CHKERR VecRestoreSubVector(centre, kappa_is, &epigraph_centre);
2071 CHKERR VecRestoreSubVector(centre, plastic_is, &plastic_centre);
2072 double constitutive_error = 0;
2073 CHKERR MPI_Allreduce(&constitutive_error_local, &constitutive_error, 1,
2075 if (!std::isfinite(constitutive_error) || constitutive_error > 1e-12)
2077 "Independent constraint/Jacobian formula check failed: error %g",
2078 constitutive_error);
2083 CHKERR VecZeroEntries(plastic_direction);
2084 CHKERR VecZeroEntries(epigraph_direction);
2086 t_direction(.41, -.13, .23, -.31, .17);
2087 CHKERR forEachOwnedTestFieldBlock(
2088 control_dm, problem.getPlasticFlowFieldName(),
2090 [&t_direction](PetscInt block, PetscScalar *values) {
2092 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(values);
2093 FTENSOR_INDEX(plasticLogarithmicStretchCoordinateSize, L);
2094 t_values(L) = (1. + .1 * block) * t_direction(L);
2095 return MoFEMErrorCode(0);
2097 CHKERR forEachOwnedTestFieldBlock(
2098 control_dm, problem.getPlasticKappaFieldName(), 1, epigraph_direction,
2099 [](PetscInt block, PetscScalar *value) {
2100 value[0] = block % 2 ? -.5 : 1.;
2101 return MoFEMErrorCode(0);
2103 PetscReal plastic_direction_norm = 0;
2104 PetscReal epigraph_direction_norm = 0;
2105 CHKERR VecNormalize(plastic_direction, &plastic_direction_norm);
2106 CHKERR VecNormalize(epigraph_direction, &epigraph_direction_norm);
2107 if (!(plastic_direction_norm > 0) || !(epigraph_direction_norm > 0))
2109 "Deterministic constraint direction is zero");
2110 CHKERR VecWAXPY(mixed_direction, 1., epigraph_direction, plastic_direction);
2111 PetscReal mixed_direction_norm = 0;
2112 CHKERR VecNormalize(mixed_direction, &mixed_direction_norm);
2113 if (!(mixed_direction_norm > 0))
2115 "Mixed constraint direction is zero");
2118 const OperatorsTester::VectorFunction evaluate = [&](Vec control,
2121 context, control, constraints);
2123 PetscReal error_norm = 0;
2124 double tolerance = 0;
2125 auto check_direction = [&](
const char *name, Vec direction) {
2127 CHKERR operators_tester->checkVectorCentralFiniteDifference(
2128 centre, direction,
context->inequalityConstraints,
2129 context->inequalityJacobian, epsilon, evaluate, error);
2130 PetscReal direction_error_norm = 0;
2131 CHKERR VecNorm(error, NORM_INFINITY, &direction_error_norm);
2133 CHKERR MatMult(
context->inequalityJacobian, direction, assembled);
2134 PetscReal assembled_norm = 0;
2135 CHKERR VecNorm(assembled, NORM_INFINITY, &assembled_norm);
2136 const double direction_tolerance =
2137 absolute_tolerance + relative_tolerance * assembled_norm;
2138 if (!std::isfinite(direction_error_norm) ||
2139 direction_error_norm > direction_tolerance)
2141 "%s constraint Jacobian mismatch: error %g > %g", name,
2142 direction_error_norm, direction_tolerance);
2143 error_norm = std::max(error_norm, direction_error_norm);
2144 tolerance = std::max(tolerance, direction_tolerance);
2147 CHKERR check_direction(
"plastic-only", plastic_direction);
2148 CHKERR check_direction(
"epigraph-only", epigraph_direction);
2149 CHKERR check_direction(
"mixed", mixed_direction);
2154 if (regularization_epsilon > 0) {
2157 const PetscInt *apex_plastic_indices =
nullptr;
2158 const PetscInt *apex_epigraph_indices =
nullptr;
2159 CHKERR ISGetIndices(plastic_is, &apex_plastic_indices);
2160 CHKERR ISGetIndices(kappa_is, &apex_epigraph_indices);
2161 PetscInt row_start = 0;
2162 PetscInt row_end = 0;
2163 CHKERR MatGetOwnershipRange(
context->inequalityJacobian, &row_start,
2165 double apex_row_error_local = 0;
2166 for (PetscInt block = 0; block != row_end - row_start; ++block) {
2167 const PetscInt row = row_start + block;
2171 apex_plastic_indices +
2174 for (
const auto value : values)
2175 apex_row_error_local =
2176 std::max(apex_row_error_local, std::abs(PetscRealPart(value)));
2177 PetscScalar eta_value = 0;
2178 CHKERR MatGetValues(
context->inequalityJacobian, 1, &row, 1,
2179 apex_epigraph_indices + block, &eta_value);
2180 apex_row_error_local = std::max(
2181 apex_row_error_local,
2182 std::abs(PetscRealPart(eta_value) - constraint_scales[block]));
2184 CHKERR ISRestoreIndices(kappa_is, &apex_epigraph_indices);
2185 CHKERR ISRestoreIndices(plastic_is, &apex_plastic_indices);
2186 double apex_row_error = 0;
2187 CHKERR MPI_Allreduce(&apex_row_error_local, &apex_row_error, 1, MPI_DOUBLE,
2189 if (apex_row_error > 1e-12)
2191 "Regularized apex row is not sqrt(V)*[0,...,0,1]: error %g",
2195 CHKERR operators_tester->checkVectorCentralFiniteDifference(
2196 context->referenceControl, mixed_direction,
2197 context->inequalityConstraints,
context->inequalityJacobian, epsilon,
2198 evaluate, apex_error);
2199 PetscReal apex_error_norm = 0;
2200 CHKERR VecNorm(apex_error, NORM_INFINITY, &apex_error_norm);
2202 CHKERR MatMult(
context->inequalityJacobian, mixed_direction,
2204 PetscReal apex_assembled_norm = 0;
2205 CHKERR VecNorm(apex_assembled, NORM_INFINITY, &apex_assembled_norm);
2206 const double apex_tolerance =
2207 absolute_tolerance + relative_tolerance * apex_assembled_norm;
2208 if (!std::isfinite(apex_error_norm) || apex_error_norm > apex_tolerance)
2210 "Regularized apex constraint Jacobian mismatch: error %g > %g",
2211 apex_error_norm, apex_tolerance);
2212 error_norm = std::max(error_norm, apex_error_norm);
2215 t_force_direction(.31, -.17, .23, -.29, .19);
2216 const double force_direction_norm =
2218 auto check_exact_apex = [&](
const double yield_ratio) {
2222 const double force_norm =
2223 yield_ratio * problem.getInitialYieldStress() /
2225 t_force(
L) = force_norm * t_force_direction(
L) / force_direction_norm;
2228 CHKERR VecZeroEntries(synthetic_gradient);
2229 Vec apex_measures =
nullptr;
2230 CHKERR VecGetSubVector(plastic_cell_measure, kappa_is, &apex_measures);
2231 const PetscScalar *apex_measure_array =
nullptr;
2232 CHKERR VecGetArrayRead(apex_measures, &apex_measure_array);
2233 CHKERR forEachOwnedTestFieldBlock(
2234 control_dm, problem.getPlasticFlowFieldName(),
2236 [&](PetscInt block, PetscScalar *gradient_values) {
2238 getFTensor1FromPtr<plasticLogarithmicStretchCoordinateSize>(
2241 -PetscRealPart(apex_measure_array[block]) * t_force(L);
2242 return MoFEMErrorCode(0);
2244 CHKERR VecRestoreArrayRead(apex_measures, &apex_measure_array);
2245 CHKERR VecRestoreSubVector(plastic_cell_measure, kappa_is,
2250 problem,
context->referenceControl, synthetic_gradient,
2252 const PetscInt *apex_plastic_indices =
nullptr;
2253 const PetscInt *apex_epigraph_indices =
nullptr;
2254 CHKERR ISGetIndices(plastic_is, &apex_plastic_indices);
2255 CHKERR ISGetIndices(kappa_is, &apex_epigraph_indices);
2256 CHKERR VecGetSubVector(plastic_cell_measure, kappa_is, &apex_measures);
2257 CHKERR VecGetArrayRead(apex_measures, &apex_measure_array);
2258 PetscInt row_start = 0;
2259 PetscInt row_end = 0;
2260 CHKERR MatGetOwnershipRange(
context->inequalityJacobian, &row_start,
2262 double selection_error_local = 0;
2263 double kkt_error_local = 0;
2265 const double slope_denominator =
2266 std::max(problem.getInitialYieldStress(),
q);
2267 for (PetscInt block = 0; block != row_end - row_start; ++block) {
2268 const PetscInt row = row_start + block;
2272 apex_plastic_indices +
2275 double kkt_norm_squared = 0;
2276 const double measure = PetscRealPart(apex_measure_array[block]);
2277 for (PetscInt coordinate = 0;
2280 const double expected_row =
2281 -constraint_scales[block] * t_force(coordinate) /
2283 selection_error_local = std::max(
2284 selection_error_local,
2285 std::abs(PetscRealPart(values[coordinate]) - expected_row));
2286 const double kkt_component = -measure * t_force(coordinate) -
2287 measure / constraint_scales[block] *
2288 problem.getInitialYieldStress() *
2289 PetscRealPart(values[coordinate]);
2290 kkt_norm_squared += kkt_component * kkt_component;
2292 const double expected_kkt_norm =
2293 measure * std::max(0., yield_ratio - 1.) *
2296 std::max(kkt_error_local,
2297 std::abs(std::sqrt(kkt_norm_squared) - expected_kkt_norm));
2298 PetscScalar eta_value = 0;
2299 CHKERR MatGetValues(
context->inequalityJacobian, 1, &row, 1,
2300 apex_epigraph_indices + block, &eta_value);
2301 selection_error_local = std::max(
2302 selection_error_local,
2303 std::abs(PetscRealPart(eta_value) - constraint_scales[block]));
2305 CHKERR VecRestoreArrayRead(apex_measures, &apex_measure_array);
2306 CHKERR VecRestoreSubVector(plastic_cell_measure, kappa_is,
2308 CHKERR ISRestoreIndices(kappa_is, &apex_epigraph_indices);
2309 CHKERR ISRestoreIndices(plastic_is, &apex_plastic_indices);
2310 double selection_error = 0;
2311 double kkt_error = 0;
2312 CHKERR MPI_Allreduce(&selection_error_local, &selection_error, 1,
2314 CHKERR MPI_Allreduce(&kkt_error_local, &kkt_error, 1, MPI_DOUBLE, MPI_MAX,
2316 const double apex_tolerance =
2317 1e-12 * std::max(1., problem.getInitialYieldStress());
2318 if (selection_error > apex_tolerance || kkt_error > apex_tolerance)
2320 "Exact apex force selection at q/sigma_y=%g failed: row "
2321 "error %g, KKT error %g",
2322 yield_ratio, selection_error, kkt_error);
2325 CHKERR check_exact_apex(.5);
2326 CHKERR check_exact_apex(2.);
2329 <<
"OperatorsTester constraint derivative error " << error_norm
2330 <<
", tolerance " << tolerance <<
", dissipation epsilon "
2331 << regularization_epsilon;
2338 return testIncrementalOptimizationLayout(*
this, ts,
state);
boost::shared_ptr< AuxiliaryLogarithmicStressData > valuesPtr
Eshelbian plasticity interface.
boost::shared_ptr< IncrementalOptimizationContext > context
Lie algebra implementation.
Shared implementation details for plastic incremental optimization.
boost::shared_ptr< PetscInt > elementCount
boost::shared_ptr< VectorDouble > kappaIncrementsPtr
double expectedKappaIncrement
Plasticity implementation of incremental optimization.
#define FTENSOR_INDEX(DIM, I)
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define MYPCOMM_INDEX
default communicator number PCOMM
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_OPERATION_UNSUCCESSFUL
@ MOFEM_ATOM_TEST_INVALID
@ MOFEM_DATA_INCONSISTENCY
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
PetscErrorCode DMMoFEMCreateSubDM(DM subdm, DM dm, const char problem_name[])
Must be called by user to set Sub DM MoFEM data structures.
PetscErrorCode DMMoFEMAddElement(DM dm, std::string fe_name)
add element to dm
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
PetscErrorCode DMMoFEMGetProblemPtr(DM dm, const MoFEM::Problem **problem_ptr)
Get pointer to problem data structure.
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
PetscErrorCode DMMoFEMGetSquareProblem(DM dm, PetscBool *square_problem)
get squared problem
PetscErrorCode DMoFEMLoopFiniteElements(DM dm, const char fe_name[], MoFEM::FEMethod *method, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
PetscErrorCode DMMoFEMGetFieldIS(DM dm, RowColData rc, const char field_name[], IS *is)
get field is in the problem
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
auto createDMMatrix(DM dm)
Get smart matrix from DM.
#define MOFEM_LOG(channel, severity)
Log.
FTensor::Index< 'i', SPACE_DIM > i
const double c
speed of light (cm/ns)
const FTensor::Tensor2< T, Dim, Dim > Vec
std::map< EntityHandle, double > PlasticKappaHistory
constexpr double plasticEquivalentIncrementScale
MoFEMErrorCode assemblePlasticInequalityJacobian(PlasticIncrementalOptimizationProblem &problem, Vec control, Vec smooth_gradient, Mat jacobian)
MoFEMErrorCode assemblePlasticForce(EshelbianCore &ep, Vec force)
constexpr double plasticEquivalentIncrementScaleSquared
MoFEMErrorCode setPlasticHistory(EshelbianCore &ep, const PlasticHistory &history, const FTensor::Tensor2_symmetric< double, SPACE_DIM > &t_direction, const double scale)
MoFEMErrorCode clearPlasticIncrementFields(EshelbianCore &ep)
MoFEMErrorCode setPlasticKappaHistory(EshelbianCore &ep, const PlasticKappaHistory &history)
MoFEMErrorCode setStateOnMesh(EshelbianCore &ep, Vec state)
MoFEMErrorCode savePlasticHistory(EshelbianCore &ep, PlasticHistory &history)
MoFEMErrorCode evaluatePlasticInequalityConstraints(const PlasticIncrementalOptimizationProblem &problem, Vec control, Vec constraints)
MoFEMErrorCode savePlasticKappaHistory(EshelbianCore &ep, PlasticKappaHistory &history)
double plasticCoordinateNorm(const FTensor::Tensor1< T, plasticLogarithmicStretchCoordinateSize > &t_values)
MoFEMErrorCode evaluatePlasticIncrementalResistanceValue(const PlasticIncrementalOptimizationProblem &problem, Vec control, double &value)
constexpr double plasticYieldFunctionScale
FTensor::Tensor1< double, plasticLogarithmicStretchCoordinateSize > plasticLogarithmicStretchCoordinatesFromTensor(const FTensor::Tensor2_symmetric< T, SPACE_DIM > &t_values)
MoFEMErrorCode assembleReducedHelmholtzGradient(EshelbianCore &ep, TS ts, Vec gradient)
std::map< EntityHandle, PackedPlasticCoordinates > PlasticHistory
FTensor::Tensor2_symmetric< double, SPACE_DIM > plasticLogarithmicStretchTensorFromCoordinates(const FTensor::Tensor1< T, plasticLogarithmicStretchCoordinateSize > &t_coordinates)
double plasticFrobeniusNorm(const FTensor::Tensor2_symmetric< T, SPACE_DIM > &t_values)
constexpr int plasticLogarithmicStretchCoordinateSize
MoFEMErrorCode validateEquilibratedMechanicalValueScope(EshelbianCore &ep)
boost::shared_ptr< IncrementalOptimizationContext > createPlasticIncrementalOptimizationContext(EshelbianCore &ep, SmartPetscObj< TS > ts, SmartPetscObj< Vec > state)
MoFEMErrorCode testIncrementalOptimizationLayout(EshelbianCore &ep, TS ts, Vec state)
VolumeElementForcesAndSourcesCore::UserDataOperator VolUserDataOperator
MoFEMErrorCode solveEquilibriumStateTS(TopologicalTAOCtxImpl *ctx_impl_ptr)
MoFEMErrorCode testIncrementalOptimizationConstraintDerivative(EshelbianCore &ep, TS ts, Vec state)
MoFEMErrorCode testIncrementalConstitutiveKernels()
MoFEMErrorCode checkPlasticConstraintSubsetAssembly(EshelbianCore &ep, PlasticIncrementalOptimizationProblem &problem, Vec control, Vec smooth_gradient)
MoFEMErrorCode testIncrementalOptimizationTransaction(EshelbianCore &ep, TS ts, Vec state)
MoFEMErrorCode evaluateEquilibratedMechanicalValue(EshelbianCore &ep, TS ts, double &value)
MoFEMErrorCode evaluateIncrementalObjectiveAndGradient(const boost::shared_ptr< IncrementalOptimizationContext > &context, Vec control, IncrementalObjectiveEvaluation &evaluation)
MoFEMErrorCode testIncrementalOptimizationObjectiveDerivative(EshelbianCore &ep, TS ts, Vec state)
MoFEMErrorCode evaluatePlasticConjugateWork(EshelbianCore &ep, const FTensor::Tensor2_symmetric< double, SPACE_DIM > &t_direction, double &conjugate_work)
MoFEMErrorCode assembleIncrementalOptimizationInequalityJacobianFromEvaluation(const boost::shared_ptr< IncrementalOptimizationContext > &context, Vec control, const IncrementalObjectiveEvaluation &evaluation, Mat jacobian)
MoFEMErrorCode testEquilibratedMechanicalValue(EshelbianCore &ep, TS ts, Vec state)
MoFEMErrorCode evaluateIncrementalOptimizationTAOObjectiveAndGradient(const boost::shared_ptr< IncrementalOptimizationContext > &context, Vec control, PetscReal &objective, Vec objective_gradient, IncrementalObjectiveEvaluation &evaluation)
PlasticIncrementalOptimizationProblem & getPlasticIncrementalOptimizationProblem(const boost::shared_ptr< IncrementalOptimizationContext > &context)
MoFEMErrorCode addCalculatePlasticLogarithmicStretchFieldValues(boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pipeline, const std::string &field_name, boost::shared_ptr< MatrixDouble > tensor_values, const EntityType zero_type, SmartPetscObj< DM > data_dm, SmartPetscObj< Vec > data_vector)
MoFEMErrorCode evaluateIncrementalObjective(const boost::shared_ptr< IncrementalOptimizationContext > &context, Vec control, IncrementalObjectiveEvaluation &evaluation)
MoFEMErrorCode assembleIncrementalOptimizationInequalityJacobian(const boost::shared_ptr< IncrementalOptimizationContext > &context, Vec control, Mat jacobian)
MoFEMErrorCode evaluateIncrementalOptimizationInequalityConstraints(const boost::shared_ptr< IncrementalOptimizationContext > &context, Vec control, Vec constraints)
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
UBlasMatrix< double > MatrixDouble
implementation of Data Operators for Forces and Sources
PetscErrorCode DMMoFEMSetDestroyProblem(DM dm, PetscBool destroy_problem)
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)
PetscErrorCode DMMoFEMGetSubRowIS(DM dm, IS *is)
get sub problem is
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
PetscErrorCode DMMoFEMGetSubColIS(DM dm, IS *is)
get sub problem is
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
constexpr auto field_name
CGG User Polynomial Base.
boost::shared_ptr< Range > frontAdjEdges
MoFEM::Interface & mField
boost::shared_ptr< Range > plasticVolumes
const std::string materialH1Positions
const std::string elementVolumeName
MoFEMErrorCode solveTestIncrementalOptimizationLayout(TS ts, Vec x, int start_step, double start_time)
const std::string plasticFlowField
static PetscBool plasticVolume
static PetscBool interfaceCrack
const std::string plasticKappaField
SmartPetscObj< DM > dmIncrementalOptimization
Incremental-optimization control problem.
EquilibriumSolveStatus status
SmartPetscObj< Vec > objectiveGradient
double objectiveGradientNorm
EquilibriumSolveStatus stateStatus
double smoothGradientNorm
SmartPetscObj< Vec > smoothGradient
Add operators pushing bases from local to physical configuration.
virtual moab::Interface & get_moab()=0
virtual MPI_Comm & get_comm() const =0
Data on single entity (This is passed as argument to DataOperator::doWork)
Structure for user loop methods on finite elements.
@ OPROW
operator doWork function is executed on FE rows
Specialization for double precision scalar field values calculation.
Calculate directional derivative of the right hand side and compare it with tangent matrix derivative...
keeps basic data about problem
auto & getNumeredRowDofsPtr() const
get access to numeredRowDofsPtr storing DOFs on rows
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.