@@ -1491,13 +1491,92 @@ TEST_F(RealPwNcgga, LibxcGgaGrad2DifferentiatesMixedLdaAndGgaComponents)
14911491 expect_vtxc_matches_returned_potential (" libxc_gga2_mixed_lda_gga" , evaluate);
14921492}
14931493
1494+ TEST_F (RealPwNcgga, LibxcGgaGrad2StressProductionDispatchClosesSmoothMetricDerivative)
1495+ {
1496+ const BranchMargins margins = report_branch_margins (" libxc_stress_smooth" );
1497+ EXPECT_GT (margins.min_abs_total_density , 1.0 );
1498+ EXPECT_GT (margins.min_signed_saturation_gap , 0.8 );
1499+ EXPECT_GT (margins.min_eta_distance , 0.3 );
14941500
1501+ // The analytic tensor must come through the existing public production
1502+ // dispatch. Keeping the new helper out of the test-only patch lets the
1503+ // matched parent build and fail on the numerical identity, not at link
1504+ // time because the child-only helper does not exist yet.
1505+ expect_gradient_stress_metric_derivative (
1506+ " libxc_smooth_dispatch" ,
1507+ [this ]() { return evaluate_libxc_gga (); },
1508+ [this ]() { return evaluate_libxc_pbe_gradient_stress_dispatch (); },
1509+ 3.0e-4 ,
1510+ 1.0e-11 );
1511+ }
14951512
1513+ TEST_F (RealPwNcgga, LibxcGgaGrad2StressProductionDispatchClosesLocalMapBranches)
1514+ {
1515+ const Evaluator energy = [this ]() { return evaluate_libxc_gga (); };
1516+ const StressEvaluator stress = [this ]() { return evaluate_libxc_pbe_gradient_stress_dispatch (); };
14961517
1518+ set_negative_gga_state ();
1519+ const BranchMargins negative = report_branch_margins (" libxc_stress_negative_abs" );
1520+ EXPECT_GT (negative.min_abs_total_density , 1.3 );
1521+ EXPECT_GT (negative.min_signed_saturation_gap , 0.8 );
1522+ expect_gradient_stress_metric_derivative (" libxc_negative_abs_dispatch" , energy, stress, 3.0e-4 , 1.0e-11 );
14971523
1524+ set_saturated_gga_state ();
1525+ const BranchMargins saturated = report_branch_margins (" libxc_stress_saturated" );
1526+ EXPECT_LT (saturated.max_signed_saturation_gap , -0.1 );
1527+ expect_gradient_stress_metric_derivative (" libxc_saturated_dispatch" , energy, stress, 3.0e-4 , 1.0e-11 );
14981528
1529+ set_inside_eta_state ();
1530+ const BranchMargins radial = report_branch_margins (" libxc_stress_inside_eta" );
1531+ EXPECT_LT (radial.max_magnitude , 6.0e-4 );
1532+ EXPECT_GT (radial.min_eta_distance , 4.0e-4 );
1533+ expect_gradient_stress_metric_derivative (" libxc_inside_eta_dispatch" , energy, stress, 3.0e-4 , 1.0e-11 );
1534+ }
14991535
1536+ TEST_F (RealPwNcgga, LibxcGgaGrad2StressAggregatesPublicFunctionalScaling)
1537+ {
1538+ const std::vector<int > gga = {XC_GGA_X_ITYH , XC_GGA_C_LYPR , XC_GGA_X_B88 , XC_GGA_C_LYP };
1539+ const std::map<int , double > scaling
1540+ = {{XC_GGA_X_ITYH , -1.0 }, {XC_GGA_C_LYPR , -1.0 }, {XC_GGA_X_B88 , 1.0 }, {XC_GGA_C_LYP , 1.0 }};
1541+ const std::vector<double > exchange_short = evaluate_gradient_stress_dispatch (" GGA_X_ITYH" );
1542+ const std::vector<double > correlation_short = evaluate_gradient_stress_dispatch (" GGA_C_LYPR" );
1543+ const std::vector<double > exchange_full = evaluate_gradient_stress_dispatch (" GGA_X_B88" );
1544+ const std::vector<double > correlation_full = evaluate_gradient_stress_dispatch (" GGA_C_LYP" );
1545+ const std::vector<double > scaled = evaluate_gradient_stress_dispatch (" BLYP_LR" );
1546+ ASSERT_EQ (exchange_short.size (), 9U );
1547+ ASSERT_EQ (correlation_short.size (), 9U );
1548+ ASSERT_EQ (exchange_full.size (), 9U );
1549+ ASSERT_EQ (correlation_full.size (), 9U );
1550+ ASSERT_EQ (scaled.size (), 9U );
1551+ for (int row = 0 ; row < 3 ; ++row)
1552+ {
1553+ for (int column = 0 ; column <= row; ++column)
1554+ {
1555+ const int index = row * 3 + column;
1556+ const double expected
1557+ = -exchange_short[index] - correlation_short[index] + exchange_full[index] + correlation_full[index];
1558+ EXPECT_NEAR (scaled[index], expected, 3.0e-12 * std::max (1.0 , std::abs (expected)));
1559+ }
1560+ }
1561+ expect_gradient_stress_metric_derivative (
1562+ " libxc_blyp_lr_dispatch" ,
1563+ [this , &gga, &scaling]() { return evaluate_libxc (gga, &scaling); },
1564+ [this ]() { return evaluate_gradient_stress_dispatch (" BLYP_LR" ); },
1565+ 3.0e-4 ,
1566+ 1.0e-11 );
1567+ }
15001568
1569+ TEST_F (RealPwNcgga, LibxcGgaGrad2StressProductionDispatchClosesFullXcDiagonalWithoutCore)
1570+ {
1571+ set_zero_core_density ();
1572+ const BranchMargins margins = report_branch_margins (" libxc_full_xc_no_core" );
1573+ EXPECT_GT (margins.min_abs_total_density , 1.0 );
1574+ EXPECT_GT (margins.min_signed_saturation_gap , 0.8 );
1575+ expect_full_xc_diagonal_stress (
1576+ " libxc_full_xc_dispatch_no_core" ,
1577+ [this ]() { return evaluate_libxc_gga (); },
1578+ [this ]() { return evaluate_libxc_pbe_gradient_stress_dispatch (); });
1579+ }
15011580#endif
15021581
15031582TEST_F (RealPwNcgga, BuiltinGgaGrad2VtxcEqualsFinalValencePotentialInnerProduct)
@@ -1653,13 +1732,64 @@ TEST_F(RealPwNcgga, BuiltinGgaGrad2IsCovariantUnderGlobalSpinRotation)
16531732 }
16541733}
16551734
1735+ TEST_F (RealPwNcgga, BuiltinGgaGrad2StressClosesSmoothSixComponentMetricDerivative)
1736+ {
1737+ const BranchMargins margins = report_branch_margins (" stress_smooth" );
1738+ EXPECT_GT (margins.min_abs_total_density , 1.0 );
1739+ EXPECT_GT (margins.min_signed_saturation_gap , 0.8 );
1740+ EXPECT_GT (margins.min_eta_distance , 0.3 );
1741+ expect_builtin_gradient_stress_metric_derivative (" smooth" );
16561742
1743+ set_zero_core_density ();
1744+ const BranchMargins zero_core = report_branch_margins (" stress_smooth_zero_core" );
1745+ EXPECT_GT (zero_core.min_abs_total_density , 1.0 );
1746+ EXPECT_GT (zero_core.min_signed_saturation_gap , 0.8 );
1747+ expect_builtin_full_xc_diagonal_stress (" smooth" );
1748+ }
16571749
1750+ TEST_F (RealPwNcgga, BuiltinGgaGrad2StressClosesNegativeAbsSixComponentMetricDerivative)
1751+ {
1752+ set_negative_gga_state ();
1753+ const BranchMargins margins = report_branch_margins (" stress_negative_abs" );
1754+ EXPECT_GT (margins.min_abs_total_density , 1.3 );
1755+ EXPECT_GT (margins.min_signed_saturation_gap , 0.8 );
1756+ expect_builtin_gradient_stress_metric_derivative (" negative_abs" );
16581757
1758+ set_zero_core_density ();
1759+ const BranchMargins zero_core = report_branch_margins (" stress_negative_abs_zero_core" );
1760+ EXPECT_GT (zero_core.min_abs_total_density , 1.3 );
1761+ EXPECT_GT (zero_core.min_signed_saturation_gap , 0.8 );
1762+ expect_builtin_full_xc_diagonal_stress (" negative_abs" );
1763+ }
16591764
1765+ TEST_F (RealPwNcgga, BuiltinGgaGrad2StressClosesSaturatedSixComponentMetricDerivative)
1766+ {
1767+ set_saturated_gga_state ();
1768+ const BranchMargins margins = report_branch_margins (" stress_saturated" );
1769+ EXPECT_LT (margins.max_signed_saturation_gap , -0.1 );
1770+ expect_builtin_gradient_stress_metric_derivative (" saturated" );
16601771
1772+ set_zero_core_density ();
1773+ const BranchMargins zero_core = report_branch_margins (" stress_saturated_zero_core" );
1774+ EXPECT_LT (zero_core.max_signed_saturation_gap , -0.1 );
1775+ expect_builtin_full_xc_diagonal_stress (" saturated" );
1776+ }
16611777
1778+ TEST_F (RealPwNcgga, BuiltinGgaGrad2StressClosesRadialEtaSixComponentMetricDerivative)
1779+ {
1780+ set_inside_eta_state ();
1781+ const BranchMargins margins = report_branch_margins (" stress_inside_eta" );
1782+ EXPECT_GT (margins.min_abs_total_density , 0.025 );
1783+ EXPECT_LT (margins.max_magnitude , 6.0e-4 );
1784+ EXPECT_GT (margins.min_eta_distance , 4.0e-4 );
1785+ expect_builtin_gradient_stress_metric_derivative (" inside_eta" );
16621786
1787+ set_zero_core_density ();
1788+ const BranchMargins zero_core = report_branch_margins (" stress_inside_eta_zero_core" );
1789+ EXPECT_GT (zero_core.min_abs_total_density , 0.025 );
1790+ EXPECT_LT (zero_core.max_magnitude , 6.0e-4 );
1791+ expect_builtin_full_xc_diagonal_stress (" inside_eta" );
1792+ }
16631793
16641794} // namespace
16651795
0 commit comments