From 98c5598d5af70e298bacbbe3c64246464379b8a9 Mon Sep 17 00:00:00 2001 From: Tyler Sax Date: Wed, 1 Jul 2026 15:38:57 -0500 Subject: [PATCH 1/7] Symmetrization M2: derive 2D point group from a holohedry pool Replace the per-geometry declared point-group files (2d_square/hexagonal/oblique/rectangular) with a single holohedries_2d.hpp defining the two 2D holohedries D4 and D6 and the candidate pool they generate. By the crystallographic restriction every 2D point group is a subgroup of one of these, so the lower-symmetry groups (rectangular D2, oblique C2, ...) are derived by the geometry filter rather than declared per model. - Correct D6 at the source: add the identity and use mirror denominator 12 so all six mirror lines survive (the legacy list omitted the identity and used denominator 6, collapsing to only three distinct mirrors). - Delete the now-unused subgroup structs and repoint all D4 consumers to holohedries_2d.hpp. - Migrate the triangular lattice test from C6 to D6 (its actual holohedry) and drop C6 - Add a completeness oracle (holohedries_2d_test) asserting that filtering the pool by each 2D lattice reproduces its full holohedry (8/12/4/2). --- .../point_groups/2d/2d_hexagonal.hpp | 81 ---------- .../symmetries/point_groups/2d/2d_oblique.hpp | 33 ---- .../point_groups/2d/2d_rectangular.hpp | 38 ----- .../symmetries/point_groups/2d/2d_square.hpp | 74 --------- .../point_groups/2d/holohedries_2d.hpp | 64 ++++++++ .../analytic_hamiltonians/fe_as_lattice.hpp | 2 +- .../threeband_hubbard.hpp | 2 +- .../analytic_hamiltonians/twoband_Cu.hpp | 2 +- .../bilayer_lattice_Nc1_interband.cpp | 2 +- ...layer_lattice_Nc1_intra_plus_interband.cpp | 2 +- .../bilayer_lattice_Nc1_intraband.cpp | 2 +- .../Nc4_nn/square_lattice_Nc4_nn.cpp | 2 +- .../square_lattice_Nc4_onSite_plus_nn.cpp | 2 +- .../ctint_double_update_comparison_test.cpp | 2 +- .../cluster_solver/ctint/ctint_fe_as_test.cpp | 2 +- .../ctint/ctint_hund_lattice_test.cpp | 2 +- .../ctint/ctint_square_lattice_test.cpp | 2 +- .../ctint/ctint_square_lattice_test_gpu.cpp | 2 +- .../ctint/ctint_square_lattice_tp_test.cpp | 2 +- .../accumulation/tp/test_setup.hpp | 2 +- .../ctint_double_update_comparison_test.cpp | 2 +- .../gpu/stdthread_ctaux_gpu_tp_test.cpp | 2 +- .../gpu/stdthread_ctint_gpu_tp_test.cpp | 2 +- .../stdthread_ctaux_tp_test.cpp | 2 +- ...stdthread_ctint_cluster_solver_io_test.cpp | 2 +- .../stdthread_ctint_cluster_solver_test.hpp | 2 +- .../ed_cluster_solver_test_helper.hpp | 2 +- .../hamiltonian_test.cpp | 2 +- .../lattice_mapping_sp_test.cpp | 2 +- .../symmetrize_characterization_test.cpp | 2 +- .../bilayer_lattice/bilayer_lattice_setup.hpp | 2 +- .../rashba_lattice/rashba_lattice_setup.hpp | 2 +- .../square_lattice/square_lattice_setup.hpp | 2 +- .../sp_accumulation_performance_test.cpp | 2 +- .../tp_accumulation_performance_test.cpp | 2 +- .../ctaux/ctaux_walker_performance_test.cpp | 2 +- .../ctint/ctint_walker_performance_test.cpp | 2 +- ...dca_post_interpolation_pp_up_down_test.cpp | 2 +- .../analysis_dca_pp_up_down_full_test.cpp | 2 +- .../analysis_dca_pp_up_down_sym_test.cpp | 2 +- .../analysis_dcaplus_pp_up_down_full_test.cpp | 2 +- .../analysis_dcaplus_pp_up_down_sym_test.cpp | 2 +- .../dca/ctint_sp_DCA_mpi_thread_test.cpp | 2 +- .../dca/dca_sp_DCA+_mpi_cuda_test.cpp | 2 +- .../system-level/dca/dca_sp_DCA+_mpi_test.cpp | 2 +- .../dca/dca_sp_DCA+_thread_test.cpp | 2 +- .../function_transform_test.cpp | 2 +- .../compute_band_structure_test.cpp | 2 +- .../compute_free_greens_function_test.cpp | 2 +- .../compute_greens_function_test.cpp | 2 +- .../ctint/ct_int_solver_methods_test.cpp | 2 +- .../dca_step/cluster_solver/test_setup.hpp | 2 +- .../deconvolution_routines_test.cpp | 2 +- test/unit/phys/domains/cluster/CMakeLists.txt | 2 + .../wannier_interpolation_test.cpp | 2 +- .../domains/cluster/symmetries/CMakeLists.txt | 5 + .../symmetries/holohedries_2d_test.cpp | 146 ++++++++++++++++++ .../bilayer_lattice_test.cpp | 2 +- .../square_lattice_test.cpp | 2 +- .../triangular_lattice_test.cpp | 6 +- .../phys/models/general_interaction_test.cpp | 2 +- .../model_parameters_2d_2band_test.cpp | 2 +- .../model_parameters_2d_4band_test.cpp | 2 +- .../model_parameters_bilayer_hubbard_test.cpp | 2 +- .../model_parameters_material_test.cpp | 2 +- .../model_parameters_rashba_hubbard_test.cpp | 2 +- ...el_parameters_single_band_hubbard_test.cpp | 2 +- 67 files changed, 278 insertions(+), 287 deletions(-) delete mode 100644 include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_hexagonal.hpp delete mode 100644 include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_oblique.hpp delete mode 100644 include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_rectangular.hpp delete mode 100644 include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp create mode 100644 include/dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp create mode 100644 test/unit/phys/domains/cluster/symmetries/CMakeLists.txt create mode 100644 test/unit/phys/domains/cluster/symmetries/holohedries_2d_test.cpp diff --git a/include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_hexagonal.hpp b/include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_hexagonal.hpp deleted file mode 100644 index 70086253d..000000000 --- a/include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_hexagonal.hpp +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (C) 2018 ETH Zurich -// Copyright (C) 2018 UT-Battelle, LLC -// All rights reserved. -// -// See LICENSE for terms of usage. -// See CITATION.md for citation guidelines, if DCA++ is used for scientific publications. -// -// Author: Peter Staar (taa@zurich.ibm.com) -// -// 2D hexagonal. - -#ifndef DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_2D_HEXAGONAL_HPP -#define DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_2D_HEXAGONAL_HPP - -#include "dca/phys/domains/cluster/symmetries/symmetry_operations/2d/Cn_2d.hpp" -#include "dca/phys/domains/cluster/symmetries/symmetry_operations/2d/Sn_2d.hpp" -#include "dca/util/type_list.hpp" - -namespace dca { -namespace phys { -namespace domains { -// dca::phys::domains:: - -// Group actions -typedef Cn_2D<1, 3> Cn_2D_1_3_type; -typedef Cn_2D<2, 3> Cn_2D_2_3_type; - -typedef Sn_2D<0, 3> Sn_2D_0_3_type; -typedef Sn_2D<1, 3> Sn_2D_1_3_type; -typedef Sn_2D<2, 3> Sn_2D_2_3_type; - -typedef Cn_2D<1, 6> Cn_2D_1_6_type; -typedef Cn_2D<2, 6> Cn_2D_2_6_type; -typedef Cn_2D<3, 6> Cn_2D_3_6_type; -typedef Cn_2D<4, 6> Cn_2D_4_6_type; -typedef Cn_2D<5, 6> Cn_2D_5_6_type; - -typedef Sn_2D<0, 6> Sn_2D_0_6_type; -typedef Sn_2D<1, 6> Sn_2D_1_6_type; -typedef Sn_2D<2, 6> Sn_2D_2_6_type; -typedef Sn_2D<3, 6> Sn_2D_3_6_type; -typedef Sn_2D<4, 6> Sn_2D_4_6_type; -typedef Sn_2D<5, 6> Sn_2D_5_6_type; - -// Point group: set of group actions -struct C3 { - typedef dca::util::Typelist point_group_type_list; -}; - -struct S3 { - typedef dca::util::Typelist point_group_type_list; -}; - -struct D3 { - typedef dca::util::Typelist - point_group_type_list; -}; - -struct C6 { - typedef dca::util::Typelist - point_group_type_list; -}; - -struct S6 { - typedef dca::util::Typelist - point_group_type_list; -}; - -struct D6 { - typedef dca::util::Typelist - point_group_type_list; -}; - -} // domains -} // phys -} // dca - -#endif // DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_2D_HEXAGONAL_HPP diff --git a/include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_oblique.hpp b/include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_oblique.hpp deleted file mode 100644 index 3d52cc7ad..000000000 --- a/include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_oblique.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (C) 2018 ETH Zurich -// Copyright (C) 2018 UT-Battelle, LLC -// All rights reserved. -// -// See LICENSE for terms of usage. -// See CITATION.md for citation guidelines, if DCA++ is used for scientific publications. -// -// Author: Peter Staar (taa@zurich.ibm.com) -// -// 2D oblique. - -#ifndef DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_2D_OBLIQUE_HPP -#define DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_2D_OBLIQUE_HPP - -#include "dca/phys/domains/cluster/symmetries/symmetry_operations/2d/Cn_2d.hpp" -#include "dca/util/type_list.hpp" - -namespace dca { -namespace phys { -namespace domains { -// dca::phys::domains:: - -// Group actions -typedef Cn_2D<1, 2> Cn_2D_1_2_type; - -// Point group: set of group actions -typedef dca::util::Typelist C2; - -} // domains -} // phys -} // dca - -#endif // DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_2D_OBLIQUE_HPP diff --git a/include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_rectangular.hpp b/include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_rectangular.hpp deleted file mode 100644 index 05f7e3135..000000000 --- a/include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_rectangular.hpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2018 ETH Zurich -// Copyright (C) 2018 UT-Battelle, LLC -// All rights reserved. -// -// See LICENSE for terms of usage. -// See CITATION.md for citation guidelines, if DCA++ is used for scientific publications. -// -// Author: Peter Staar (taa@zurich.ibm.com) -// -// 2D rectangular. - -#ifndef DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_2D_RECTANGULAR_HPP -#define DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_2D_RECTANGULAR_HPP - -#include "dca/phys/domains/cluster/symmetries/symmetry_operations/2d/Sn_2d.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_oblique.hpp" // for C2 -#include "dca/util/type_list.hpp" - -namespace dca { -namespace phys { -namespace domains { -// dca::phys::domains:: - -// Group actions -typedef Sn_2D<0, 4> Sn_2D_0_4_type; -typedef Sn_2D<1, 4> Sn_2D_1_4_type; - -// Point group: set of group actions -typedef dca::util::Typelist Sx_2d; -typedef dca::util::Typelist Sy_2d; - -typedef dca::util::Append::type>::type D2; - -} // domains -} // phys -} // dca - -#endif // DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_2D_RECTANGULAR_HPP diff --git a/include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp b/include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp deleted file mode 100644 index f0738f3a6..000000000 --- a/include/dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) 2018 ETH Zurich -// Copyright (C) 2018 UT-Battelle, LLC -// All rights reserved. -// -// See LICENSE for terms of usage. -// See CITATION.md for citation guidelines, if DCA++ is used for scientific publications. -// -// Author: Peter Staar (taa@zurich.ibm.com) -// -// 2D square. - -#ifndef DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_2D_SQUARE_HPP -#define DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_2D_SQUARE_HPP - -#include "dca/phys/domains/cluster/symmetries/symmetry_operations/2d/Cn_2d.hpp" -#include "dca/phys/domains/cluster/symmetries/symmetry_operations/2d/Sn_2d.hpp" -#include "dca/phys/domains/cluster/symmetries/symmetry_operations/identity_group_operation.hpp" -#include "dca/util/type_list.hpp" - -namespace dca { -namespace phys { -namespace domains { -// dca::phys::domains:: - -// Group actions -typedef Cn_2D<1, 4> Cn_2D_1_4_type; -typedef Cn_2D<2, 4> Cn_2D_2_4_type; -typedef Cn_2D<3, 4> Cn_2D_3_4_type; -typedef Cn_2D<4, 4> Cn_2D_4_4_type; - -typedef Sn_2D<0, 8> Sn_2D_0_8_type; -typedef Sn_2D<1, 8> Sn_2D_1_8_type; -typedef Sn_2D<2, 8> Sn_2D_2_8_type; -typedef Sn_2D<3, 8> Sn_2D_3_8_type; -typedef Sn_2D<4, 8> Sn_2D_4_8_type; -typedef Sn_2D<5, 8> Sn_2D_5_8_type; -typedef Sn_2D<6, 8> Sn_2D_6_8_type; -typedef Sn_2D<7, 8> Sn_2D_7_8_type; -typedef Sn_2D<8, 8> Sn_2D_8_8_type; - -// Point group: set of group actions -struct C4 { - typedef dca::util::Typelist - point_group_type_list; -}; - -struct S4 { - typedef dca::util::Typelist - point_group_type_list; -}; - -struct S4_plus { - typedef dca::util::Typelist, Cn_2D_2_4_type, Sn_2D_0_8_type, Sn_2D_2_8_type> - point_group_type_list; -}; - -struct S8 { - typedef dca::util::Typelist> - point_group_type_list; -}; - -struct D4 { - using point_group_type_list = - dca::util::Typelist, Sn_2D<1, 8>, Sn_2D<2, 8>, Sn_2D<3, 8>, Cn_2D<1, 4>, - Cn_2D<2, 4>, Cn_2D<3, 4>, identity_group_operation<2>>; -}; - -} // namespace domains -} // namespace phys -} // namespace dca - -#endif // DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_2D_SQUARE_HPP diff --git a/include/dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp b/include/dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp new file mode 100644 index 000000000..37d8c4b33 --- /dev/null +++ b/include/dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp @@ -0,0 +1,64 @@ +// Copyright (C) 2018 UT-Battelle, LLC +// All rights reserved. +// +// See LICENSE for terms of usage. +// See CITATION.md for citation guidelines, if DCA++ is used for scientific publications. +// +// Author: Tyler Sax +// +// The two 2D crystallographic holohedries and the candidate pool they generate. +// +// D4 (square holohedry, order 8) and D6 (hexagonal holohedry, order 12) are the two maximal point +// groups in 2D. By the crystallographic restriction, every 2D crystallographic point group is a +// subgroup of one of them, so they are the only primitives needed: the lower-symmetry groups +// (rectangular D2, oblique C2, trigonal C3/D3, ...) are not declared per model but derived at +// runtime from the pool by the geometry filter (search_symmetry_group: is_lattice_compatible + +// is_unit_cell_compatible) and the H0-invariance gate. +// +// holohedry_pool_2D is the union D4 U D6 -- the model-independent candidate set that discovery +// filters. It is a superset, not a closed group (it holds both a 90 deg and a 60 deg rotation, whose +// product is absent); that is intentional, the per-lattice filter extracts the closed subgroup. + +#ifndef DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_HOLOHEDRIES_2D_HPP +#define DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_HOLOHEDRIES_2D_HPP + +#include "dca/phys/domains/cluster/symmetries/symmetry_operations/2d/Cn_2d.hpp" +#include "dca/phys/domains/cluster/symmetries/symmetry_operations/2d/Sn_2d.hpp" +#include "dca/phys/domains/cluster/symmetries/symmetry_operations/identity_group_operation.hpp" +#include "dca/util/type_list.hpp" + +namespace dca { +namespace phys { +namespace domains { +// dca::phys::domains:: + +// Square holohedry (order 8): the three C4 rotations, four mirrors (reflection lines at n*pi/4, +// n={0...3}), and the identity. +struct D4 { + using point_group_type_list = + dca::util::Typelist, Sn_2D<1, 8>, Sn_2D<2, 8>, Sn_2D<3, 8>, Cn_2D<1, 4>, + Cn_2D<2, 4>, Cn_2D<3, 4>, identity_group_operation<2>>; +}; + +// Hexagonal holohedry (order 12): the five C6 rotations, six mirrors (reflection lines at n*pi/6, +// n = 0..5), and the identity. +struct D6 { + using point_group_type_list = + dca::util::Typelist, Cn_2D<2, 6>, Cn_2D<3, 6>, Cn_2D<4, 6>, Cn_2D<5, 6>, + Sn_2D<0, 12>, Sn_2D<1, 12>, Sn_2D<2, 12>, Sn_2D<3, 12>, Sn_2D<4, 12>, + Sn_2D<5, 12>, identity_group_operation<2>>; +}; + +// Universal 2D candidate pool = square holohedry D4 U hexagonal holohedry D6. Overlapping ops +// (identity, the C2 rotation) appear twice; search_symmetry_group::is_duplicate collapses them at +// populate time, so the union need not be hand-deduplicated. +struct holohedry_pool_2D { + using point_group_type_list = + dca::util::Append::type; +}; + +} // namespace domains +} // namespace phys +} // namespace dca + +#endif // DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_HOLOHEDRIES_2D_HPP diff --git a/include/dca/phys/models/analytic_hamiltonians/fe_as_lattice.hpp b/include/dca/phys/models/analytic_hamiltonians/fe_as_lattice.hpp index 802beae01..6a31b41e1 100644 --- a/include/dca/phys/models/analytic_hamiltonians/fe_as_lattice.hpp +++ b/include/dca/phys/models/analytic_hamiltonians/fe_as_lattice.hpp @@ -17,7 +17,7 @@ #include "dca/function/domains.hpp" #include "dca/function/function.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/bilayer_lattice.hpp" #include "dca/phys/models/analytic_hamiltonians/cluster_shape_type.hpp" #include "dca/phys/models/traits.hpp" diff --git a/include/dca/phys/models/analytic_hamiltonians/threeband_hubbard.hpp b/include/dca/phys/models/analytic_hamiltonians/threeband_hubbard.hpp index e4a5ab094..34c6220e3 100644 --- a/include/dca/phys/models/analytic_hamiltonians/threeband_hubbard.hpp +++ b/include/dca/phys/models/analytic_hamiltonians/threeband_hubbard.hpp @@ -21,7 +21,7 @@ #include "dca/function/domains.hpp" #include "dca/function/function.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/cluster/symmetries/point_groups/no_symmetry.hpp" #include "dca/phys/models/analytic_hamiltonians/cluster_shape_type.hpp" #include "dca/util/type_list.hpp" diff --git a/include/dca/phys/models/analytic_hamiltonians/twoband_Cu.hpp b/include/dca/phys/models/analytic_hamiltonians/twoband_Cu.hpp index c8b2e65a0..56dff502e 100644 --- a/include/dca/phys/models/analytic_hamiltonians/twoband_Cu.hpp +++ b/include/dca/phys/models/analytic_hamiltonians/twoband_Cu.hpp @@ -21,7 +21,7 @@ #include "dca/function/domains.hpp" #include "dca/function/function.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/cluster/symmetries/point_groups/no_symmetry.hpp" #include "dca/phys/models/analytic_hamiltonians/cluster_shape_type.hpp" #include "dca/util/type_list.hpp" diff --git a/test/integration/cluster_solver/ctaux/bilayer_lattice/Nc1_interband/bilayer_lattice_Nc1_interband.cpp b/test/integration/cluster_solver/ctaux/bilayer_lattice/Nc1_interband/bilayer_lattice_Nc1_interband.cpp index c068ac3a1..7ea7e098a 100644 --- a/test/integration/cluster_solver/ctaux/bilayer_lattice/Nc1_interband/bilayer_lattice_Nc1_interband.cpp +++ b/test/integration/cluster_solver/ctaux/bilayer_lattice/Nc1_interband/bilayer_lattice_Nc1_interband.cpp @@ -29,7 +29,7 @@ #include "dca/config/profiler.hpp" #include "dca/phys/dca_step/cluster_solver/ctaux/ctaux_cluster_solver.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/quantum/electron_band_domain.hpp" #include "dca/phys/domains/quantum/electron_spin_domain.hpp" #include "dca/phys/domains/time_and_frequency/frequency_domain.hpp" diff --git a/test/integration/cluster_solver/ctaux/bilayer_lattice/Nc1_intra_plus_interband/bilayer_lattice_Nc1_intra_plus_interband.cpp b/test/integration/cluster_solver/ctaux/bilayer_lattice/Nc1_intra_plus_interband/bilayer_lattice_Nc1_intra_plus_interband.cpp index 7b3427730..500c8db46 100644 --- a/test/integration/cluster_solver/ctaux/bilayer_lattice/Nc1_intra_plus_interband/bilayer_lattice_Nc1_intra_plus_interband.cpp +++ b/test/integration/cluster_solver/ctaux/bilayer_lattice/Nc1_intra_plus_interband/bilayer_lattice_Nc1_intra_plus_interband.cpp @@ -40,7 +40,7 @@ using McOptions = MockMcOptions; #include "dca/config/profiler.hpp" #include "dca/phys/dca_step/cluster_solver/ctaux/ctaux_cluster_solver.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/quantum/electron_band_domain.hpp" #include "dca/phys/domains/quantum/electron_spin_domain.hpp" #include "dca/phys/domains/time_and_frequency/frequency_domain.hpp" diff --git a/test/integration/cluster_solver/ctaux/bilayer_lattice/Nc1_intraband/bilayer_lattice_Nc1_intraband.cpp b/test/integration/cluster_solver/ctaux/bilayer_lattice/Nc1_intraband/bilayer_lattice_Nc1_intraband.cpp index 16f8d9bef..68a2bc03f 100644 --- a/test/integration/cluster_solver/ctaux/bilayer_lattice/Nc1_intraband/bilayer_lattice_Nc1_intraband.cpp +++ b/test/integration/cluster_solver/ctaux/bilayer_lattice/Nc1_intraband/bilayer_lattice_Nc1_intraband.cpp @@ -38,7 +38,7 @@ using McOptions = MockMcOptions; #include "dca/config/profiler.hpp" #include "dca/phys/dca_step/cluster_solver/ctaux/ctaux_cluster_solver.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/quantum/electron_band_domain.hpp" #include "dca/phys/domains/quantum/electron_spin_domain.hpp" #include "dca/phys/domains/time_and_frequency/frequency_domain.hpp" diff --git a/test/integration/cluster_solver/ctaux/square_lattice/Nc4_nn/square_lattice_Nc4_nn.cpp b/test/integration/cluster_solver/ctaux/square_lattice/Nc4_nn/square_lattice_Nc4_nn.cpp index 4c22ccb6b..b13c0a084 100644 --- a/test/integration/cluster_solver/ctaux/square_lattice/Nc4_nn/square_lattice_Nc4_nn.cpp +++ b/test/integration/cluster_solver/ctaux/square_lattice/Nc4_nn/square_lattice_Nc4_nn.cpp @@ -39,7 +39,7 @@ using McOptions = MockMcOptions; #include "dca/config/profiler.hpp" #include "dca/phys/dca_step/cluster_solver/ctaux/ctaux_cluster_solver.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/quantum/electron_band_domain.hpp" #include "dca/phys/domains/quantum/electron_spin_domain.hpp" #include "dca/phys/domains/time_and_frequency/frequency_domain.hpp" diff --git a/test/integration/cluster_solver/ctaux/square_lattice/Nc4_onSite_plus_nn/square_lattice_Nc4_onSite_plus_nn.cpp b/test/integration/cluster_solver/ctaux/square_lattice/Nc4_onSite_plus_nn/square_lattice_Nc4_onSite_plus_nn.cpp index bf972c72e..60d0307a5 100644 --- a/test/integration/cluster_solver/ctaux/square_lattice/Nc4_onSite_plus_nn/square_lattice_Nc4_onSite_plus_nn.cpp +++ b/test/integration/cluster_solver/ctaux/square_lattice/Nc4_onSite_plus_nn/square_lattice_Nc4_onSite_plus_nn.cpp @@ -39,7 +39,7 @@ using McOptions = MockMcOptions; #include "dca/config/profiler.hpp" #include "dca/phys/dca_step/cluster_solver/ctaux/ctaux_cluster_solver.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/quantum/electron_band_domain.hpp" #include "dca/phys/domains/quantum/electron_spin_domain.hpp" #include "dca/phys/domains/time_and_frequency/frequency_domain.hpp" diff --git a/test/integration/cluster_solver/ctint/ctint_double_update_comparison_test.cpp b/test/integration/cluster_solver/ctint/ctint_double_update_comparison_test.cpp index 33104e949..1af69d9fc 100644 --- a/test/integration/cluster_solver/ctint/ctint_double_update_comparison_test.cpp +++ b/test/integration/cluster_solver/ctint/ctint_double_update_comparison_test.cpp @@ -38,7 +38,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_step/cluster_solver/ctint/walker/ctint_walker_cpu_submatrix.hpp" #include "test/unit/phys/dca_step/cluster_solver/ctint/walker/walker_wrapper_submatrix.hpp" #include "test/unit/phys/dca_step/cluster_solver/ctint/walker/walker_wrapper.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/fe_as_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/parallel/no_threading/no_threading.hpp" diff --git a/test/integration/cluster_solver/ctint/ctint_fe_as_test.cpp b/test/integration/cluster_solver/ctint/ctint_fe_as_test.cpp index d2722521c..dea7874a9 100644 --- a/test/integration/cluster_solver/ctint/ctint_fe_as_test.cpp +++ b/test/integration/cluster_solver/ctint/ctint_fe_as_test.cpp @@ -33,7 +33,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_data/dca_data.hpp" #include "dca/config/profiler.hpp" #include "dca/phys/dca_step/cluster_solver/ctint/ctint_cluster_solver.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/fe_as_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/parallel/no_threading/no_threading.hpp" diff --git a/test/integration/cluster_solver/ctint/ctint_hund_lattice_test.cpp b/test/integration/cluster_solver/ctint/ctint_hund_lattice_test.cpp index 4b3ac5b4c..d0af55bb1 100644 --- a/test/integration/cluster_solver/ctint/ctint_hund_lattice_test.cpp +++ b/test/integration/cluster_solver/ctint/ctint_hund_lattice_test.cpp @@ -32,7 +32,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_data/dca_data.hpp" #include "dca/config/profiler.hpp" #include "dca/phys/dca_step/cluster_solver/ctint/ctint_cluster_solver.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/hund_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/parallel/no_threading/no_threading.hpp" diff --git a/test/integration/cluster_solver/ctint/ctint_square_lattice_test.cpp b/test/integration/cluster_solver/ctint/ctint_square_lattice_test.cpp index d58c0cfb8..63d867952 100644 --- a/test/integration/cluster_solver/ctint/ctint_square_lattice_test.cpp +++ b/test/integration/cluster_solver/ctint/ctint_square_lattice_test.cpp @@ -32,7 +32,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_data/dca_data.hpp" #include "dca/config/profiler.hpp" #include "dca/phys/dca_step/cluster_solver/ctint/ctint_cluster_solver.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/parallel/no_threading/no_threading.hpp" diff --git a/test/integration/cluster_solver/ctint/ctint_square_lattice_test_gpu.cpp b/test/integration/cluster_solver/ctint/ctint_square_lattice_test_gpu.cpp index 79464fcf9..248827a7c 100644 --- a/test/integration/cluster_solver/ctint/ctint_square_lattice_test_gpu.cpp +++ b/test/integration/cluster_solver/ctint/ctint_square_lattice_test_gpu.cpp @@ -35,7 +35,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_data/dca_data.hpp" #include "dca/config/profiler.hpp" #include "dca/phys/dca_step/cluster_solver/ctint/ctint_cluster_solver.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/parallel/no_threading/no_threading.hpp" diff --git a/test/integration/cluster_solver/ctint/ctint_square_lattice_tp_test.cpp b/test/integration/cluster_solver/ctint/ctint_square_lattice_tp_test.cpp index 17ee70a33..62cf87ca5 100644 --- a/test/integration/cluster_solver/ctint/ctint_square_lattice_tp_test.cpp +++ b/test/integration/cluster_solver/ctint/ctint_square_lattice_tp_test.cpp @@ -36,7 +36,7 @@ using McOptions = MockMcOptions; #include "dca/config/profiler.hpp" #include "dca/phys/dca_step/cluster_solver/ctint/ctint_cluster_solver.hpp" #include "dca/phys/dca_step/cluster_solver/stdthread_qmci/stdthread_qmci_cluster_solver.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/parallel/no_concurrency/no_concurrency.hpp" diff --git a/test/integration/cluster_solver/shared_tools/accumulation/tp/test_setup.hpp b/test/integration/cluster_solver/shared_tools/accumulation/tp/test_setup.hpp index 8f94854b1..b58f6f406 100644 --- a/test/integration/cluster_solver/shared_tools/accumulation/tp/test_setup.hpp +++ b/test/integration/cluster_solver/shared_tools/accumulation/tp/test_setup.hpp @@ -19,7 +19,7 @@ #include "dca/io/json/json_reader.hpp" #include "dca/phys/parameters/parameters.hpp" #include "dca/phys/dca_step/cluster_solver/ctint/structs/interaction_vertices.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/quantum/electron_band_domain.hpp" #include "dca/phys/domains/quantum/electron_spin_domain.hpp" #include "dca/phys/domains/time_and_frequency/frequency_domain.hpp" diff --git a/test/integration/cluster_solver/stdthread_qmci/gpu/ctint_double_update_comparison_test.cpp b/test/integration/cluster_solver/stdthread_qmci/gpu/ctint_double_update_comparison_test.cpp index 445bebfa7..4c50f4a96 100644 --- a/test/integration/cluster_solver/stdthread_qmci/gpu/ctint_double_update_comparison_test.cpp +++ b/test/integration/cluster_solver/stdthread_qmci/gpu/ctint_double_update_comparison_test.cpp @@ -26,7 +26,7 @@ #include "dca/phys/dca_data/dca_data.hpp" #include "dca/parallel//no_concurrency/no_concurrency.hpp" #include "test/unit/phys/dca_step/cluster_solver/ctint/walker/walker_wrapper_submatrix.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/fe_as_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/parallel/no_threading/no_threading.hpp" diff --git a/test/integration/cluster_solver/stdthread_qmci/gpu/stdthread_ctaux_gpu_tp_test.cpp b/test/integration/cluster_solver/stdthread_qmci/gpu/stdthread_ctaux_gpu_tp_test.cpp index 9d78666f3..cfcf665bf 100644 --- a/test/integration/cluster_solver/stdthread_qmci/gpu/stdthread_ctaux_gpu_tp_test.cpp +++ b/test/integration/cluster_solver/stdthread_qmci/gpu/stdthread_ctaux_gpu_tp_test.cpp @@ -40,7 +40,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_step/cluster_solver/ctaux/ctaux_cluster_solver.hpp" #include "dca/phys/dca_step/cluster_solver/stdthread_qmci/stdthread_qmci_cluster_solver.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/parallel/no_concurrency/no_concurrency.hpp" diff --git a/test/integration/cluster_solver/stdthread_qmci/gpu/stdthread_ctint_gpu_tp_test.cpp b/test/integration/cluster_solver/stdthread_qmci/gpu/stdthread_ctint_gpu_tp_test.cpp index 004a48c49..827b01e29 100644 --- a/test/integration/cluster_solver/stdthread_qmci/gpu/stdthread_ctint_gpu_tp_test.cpp +++ b/test/integration/cluster_solver/stdthread_qmci/gpu/stdthread_ctint_gpu_tp_test.cpp @@ -35,7 +35,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_step/cluster_solver/ctint/ctint_cluster_solver.hpp" #include "dca/phys/dca_step/cluster_solver/stdthread_qmci/stdthread_qmci_cluster_solver.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/parallel/no_concurrency/no_concurrency.hpp" diff --git a/test/integration/cluster_solver/stdthread_qmci/stdthread_ctaux_tp_test.cpp b/test/integration/cluster_solver/stdthread_qmci/stdthread_ctaux_tp_test.cpp index b9516c765..09f712210 100644 --- a/test/integration/cluster_solver/stdthread_qmci/stdthread_ctaux_tp_test.cpp +++ b/test/integration/cluster_solver/stdthread_qmci/stdthread_ctaux_tp_test.cpp @@ -41,7 +41,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_step/cluster_solver/ctaux/ctaux_cluster_solver.hpp" #include "dca/phys/dca_step/cluster_solver/stdthread_qmci/stdthread_qmci_cluster_solver.hpp" #include "dca/phys/domains/cluster/momentum_exchange_domain.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/time_and_frequency/frequency_exchange_domain.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" diff --git a/test/integration/cluster_solver/stdthread_qmci/stdthread_ctint_cluster_solver_io_test.cpp b/test/integration/cluster_solver/stdthread_qmci/stdthread_ctint_cluster_solver_io_test.cpp index ffe5db075..0e2ab0944 100644 --- a/test/integration/cluster_solver/stdthread_qmci/stdthread_ctint_cluster_solver_io_test.cpp +++ b/test/integration/cluster_solver/stdthread_qmci/stdthread_ctint_cluster_solver_io_test.cpp @@ -37,7 +37,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_step/cluster_solver/ctint/ctint_cluster_solver.hpp" #include "dca/phys/dca_step/cluster_solver/stdthread_qmci/stdthread_qmci_cluster_solver.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/parallel/mpi_concurrency/mpi_concurrency.hpp" diff --git a/test/integration/cluster_solver/stdthread_qmci/stdthread_ctint_cluster_solver_test.hpp b/test/integration/cluster_solver/stdthread_qmci/stdthread_ctint_cluster_solver_test.hpp index dd724a41e..872eb3e9c 100644 --- a/test/integration/cluster_solver/stdthread_qmci/stdthread_ctint_cluster_solver_test.hpp +++ b/test/integration/cluster_solver/stdthread_qmci/stdthread_ctint_cluster_solver_test.hpp @@ -28,7 +28,7 @@ #include "dca/config/profiler.hpp" #include "dca/phys/dca_step/cluster_solver/ctint/ctint_cluster_solver.hpp" #include "dca/phys/dca_step/cluster_solver/stdthread_qmci/stdthread_qmci_cluster_solver.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/parallel/no_concurrency/no_concurrency.hpp" diff --git a/test/integration/exact_diagonalization_advanced/ed_cluster_solver_test_helper.hpp b/test/integration/exact_diagonalization_advanced/ed_cluster_solver_test_helper.hpp index 662a4f030..d503a6c1d 100644 --- a/test/integration/exact_diagonalization_advanced/ed_cluster_solver_test_helper.hpp +++ b/test/integration/exact_diagonalization_advanced/ed_cluster_solver_test_helper.hpp @@ -21,7 +21,7 @@ #include "dca/phys/dca_data/dca_data.hpp" #include "dca/phys/dca_data/dca_data_real_freq.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/quantum/electron_band_domain.hpp" #include "dca/phys/domains/quantum/electron_spin_domain.hpp" #include "dca/phys/domains/time_and_frequency/frequency_domain.hpp" diff --git a/test/integration/exact_diagonalization_advanced/hamiltonian_test.cpp b/test/integration/exact_diagonalization_advanced/hamiltonian_test.cpp index 469a7eb9c..3aa3a0dfc 100644 --- a/test/integration/exact_diagonalization_advanced/hamiltonian_test.cpp +++ b/test/integration/exact_diagonalization_advanced/hamiltonian_test.cpp @@ -23,7 +23,7 @@ #include "dca/parallel/no_concurrency/no_concurrency.hpp" #include "dca/phys/dca_step/cluster_solver/exact_diagonalization_advanced/fock_space.hpp" #include "dca/phys/dca_step/cluster_solver/exact_diagonalization_advanced/options.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" diff --git a/test/integration/phys/lattice_mapping/lattice_mapping_sp_test.cpp b/test/integration/phys/lattice_mapping/lattice_mapping_sp_test.cpp index f397210dd..3e5c75fd6 100644 --- a/test/integration/phys/lattice_mapping/lattice_mapping_sp_test.cpp +++ b/test/integration/phys/lattice_mapping/lattice_mapping_sp_test.cpp @@ -39,7 +39,7 @@ using McOptions = MockMcOptions; #include "dca/profiling/null_profiler.hpp" #include "dca/phys/dca_step/cluster_solver/cluster_solver_id.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/quantum/electron_band_domain.hpp" #include "dca/phys/domains/quantum/electron_spin_domain.hpp" #include "dca/phys/domains/time_and_frequency/frequency_domain.hpp" diff --git a/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp b/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp index 558f10bf1..e33cb98c2 100644 --- a/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp +++ b/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp @@ -58,7 +58,7 @@ #include "dca/parallel/no_concurrency/no_concurrency.hpp" #include "dca/phys/dca_algorithms/compute_free_greens_function.hpp" #include "dca/phys/domains/cluster/cluster_symmetry.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/cluster/symmetries/point_groups/no_symmetry.hpp" #include "dca/phys/parameters/parameters.hpp" #include "dca/profiling/null_profiler.hpp" diff --git a/test/integration/statistical_tests/bilayer_lattice/bilayer_lattice_setup.hpp b/test/integration/statistical_tests/bilayer_lattice/bilayer_lattice_setup.hpp index 2632fb73d..8d3c4c328 100644 --- a/test/integration/statistical_tests/bilayer_lattice/bilayer_lattice_setup.hpp +++ b/test/integration/statistical_tests/bilayer_lattice/bilayer_lattice_setup.hpp @@ -25,7 +25,7 @@ #include "dca/phys/dca_step/cluster_solver/ctaux/ctaux_cluster_solver.hpp" #include "dca/phys/dca_step/cluster_solver/ctint/ctint_cluster_solver.hpp" #include "dca/phys/dca_step/cluster_solver/stdthread_qmci/stdthread_qmci_cluster_solver.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/math/random/random.hpp" #include "dca/math/statistical_testing/function_cut.hpp" #include "dca/math/statistical_testing/statistical_testing.hpp" diff --git a/test/integration/statistical_tests/rashba_lattice/rashba_lattice_setup.hpp b/test/integration/statistical_tests/rashba_lattice/rashba_lattice_setup.hpp index 05ff0e97d..9e414b258 100644 --- a/test/integration/statistical_tests/rashba_lattice/rashba_lattice_setup.hpp +++ b/test/integration/statistical_tests/rashba_lattice/rashba_lattice_setup.hpp @@ -29,7 +29,7 @@ #include "dca/phys/dca_step/cluster_mapping/double_counting_correction.hpp" #include "dca/phys/dca_step/cluster_mapping/update_chemical_potential.hpp" #include "dca/phys/dca_step/cluster_solver/stdthread_qmci/stdthread_qmci_cluster_solver.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/math/random/random.hpp" #include "dca/phys/dca_step/cluster_mapping/update_chemical_potential.hpp" #include "dca/math/statistical_testing/function_cut.hpp" diff --git a/test/integration/statistical_tests/square_lattice/square_lattice_setup.hpp b/test/integration/statistical_tests/square_lattice/square_lattice_setup.hpp index d3b84bde4..d485cd7c9 100644 --- a/test/integration/statistical_tests/square_lattice/square_lattice_setup.hpp +++ b/test/integration/statistical_tests/square_lattice/square_lattice_setup.hpp @@ -25,7 +25,7 @@ #include "dca/phys/dca_step/cluster_solver/ctaux/ctaux_cluster_solver.hpp" #include "dca/phys/dca_step/cluster_solver/ctint/ctint_cluster_solver.hpp" #include "dca/phys/dca_step/cluster_solver/stdthread_qmci/stdthread_qmci_cluster_solver.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/math/random/random.hpp" #include "dca/math/statistical_testing/function_cut.hpp" #include "dca/math/statistical_testing/statistical_testing.hpp" diff --git a/test/performance/phys/accumulation/sp_accumulation_performance_test.cpp b/test/performance/phys/accumulation/sp_accumulation_performance_test.cpp index cc7be41f5..8328f887d 100644 --- a/test/performance/phys/accumulation/sp_accumulation_performance_test.cpp +++ b/test/performance/phys/accumulation/sp_accumulation_performance_test.cpp @@ -34,7 +34,7 @@ using Profiler = dca::profiling::CountingProfiler; #include "dca/io/json/json_reader.hpp" #include "dca/math/random/std_random_wrapper.hpp" #include "dca/phys/dca_data/dca_data.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/parallel/no_concurrency/no_concurrency.hpp" diff --git a/test/performance/phys/ctint/ctint_walker_performance_test.cpp b/test/performance/phys/ctint/ctint_walker_performance_test.cpp index e58793e58..d3db7fcd9 100644 --- a/test/performance/phys/ctint/ctint_walker_performance_test.cpp +++ b/test/performance/phys/ctint/ctint_walker_performance_test.cpp @@ -30,7 +30,7 @@ using McOptions = MockMcOptions; } // namespace dca #include "dca/phys/dca_step/cluster_solver/ctint/walker/ctint_walker_choice.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/bilayer_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/parallel/no_concurrency/no_concurrency.hpp" diff --git a/test/system-level/analysis/dca_post_interpolation_pp_up_down/analysis_dca_post_interpolation_pp_up_down_test.cpp b/test/system-level/analysis/dca_post_interpolation_pp_up_down/analysis_dca_post_interpolation_pp_up_down_test.cpp index 641ba3111..1a9df8028 100644 --- a/test/system-level/analysis/dca_post_interpolation_pp_up_down/analysis_dca_post_interpolation_pp_up_down_test.cpp +++ b/test/system-level/analysis/dca_post_interpolation_pp_up_down/analysis_dca_post_interpolation_pp_up_down_test.cpp @@ -42,7 +42,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_analysis/bse_solver/bse_solver.hpp" #include "dca/phys/dca_data/dca_data.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/phys/parameters/parameters.hpp" diff --git a/test/system-level/analysis/dca_pp_up_down_full/analysis_dca_pp_up_down_full_test.cpp b/test/system-level/analysis/dca_pp_up_down_full/analysis_dca_pp_up_down_full_test.cpp index 367483335..202c41f37 100644 --- a/test/system-level/analysis/dca_pp_up_down_full/analysis_dca_pp_up_down_full_test.cpp +++ b/test/system-level/analysis/dca_pp_up_down_full/analysis_dca_pp_up_down_full_test.cpp @@ -42,7 +42,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_analysis/bse_solver/bse_solver.hpp" #include "dca/phys/dca_data/dca_data.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/phys/parameters/parameters.hpp" diff --git a/test/system-level/analysis/dca_pp_up_down_sym/analysis_dca_pp_up_down_sym_test.cpp b/test/system-level/analysis/dca_pp_up_down_sym/analysis_dca_pp_up_down_sym_test.cpp index 2c177a041..c54db984e 100644 --- a/test/system-level/analysis/dca_pp_up_down_sym/analysis_dca_pp_up_down_sym_test.cpp +++ b/test/system-level/analysis/dca_pp_up_down_sym/analysis_dca_pp_up_down_sym_test.cpp @@ -40,7 +40,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_analysis/bse_solver/bse_solver.hpp" #include "dca/phys/dca_data/dca_data.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/phys/parameters/parameters.hpp" diff --git a/test/system-level/analysis/dcaplus_pp_up_down_full/analysis_dcaplus_pp_up_down_full_test.cpp b/test/system-level/analysis/dcaplus_pp_up_down_full/analysis_dcaplus_pp_up_down_full_test.cpp index b74cc6f33..054c2e063 100644 --- a/test/system-level/analysis/dcaplus_pp_up_down_full/analysis_dcaplus_pp_up_down_full_test.cpp +++ b/test/system-level/analysis/dcaplus_pp_up_down_full/analysis_dcaplus_pp_up_down_full_test.cpp @@ -42,7 +42,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_analysis/bse_solver/bse_solver.hpp" #include "dca/phys/dca_data/dca_data.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/phys/parameters/parameters.hpp" diff --git a/test/system-level/analysis/dcaplus_pp_up_down_sym/analysis_dcaplus_pp_up_down_sym_test.cpp b/test/system-level/analysis/dcaplus_pp_up_down_sym/analysis_dcaplus_pp_up_down_sym_test.cpp index c6591b8cd..cd5c54d61 100644 --- a/test/system-level/analysis/dcaplus_pp_up_down_sym/analysis_dcaplus_pp_up_down_sym_test.cpp +++ b/test/system-level/analysis/dcaplus_pp_up_down_sym/analysis_dcaplus_pp_up_down_sym_test.cpp @@ -40,7 +40,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_analysis/bse_solver/bse_solver.hpp" #include "dca/phys/dca_data/dca_data.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/phys/parameters/parameters.hpp" diff --git a/test/system-level/dca/ctint_sp_DCA_mpi_thread_test.cpp b/test/system-level/dca/ctint_sp_DCA_mpi_thread_test.cpp index e4d397e1b..7a34b0a21 100644 --- a/test/system-level/dca/ctint_sp_DCA_mpi_thread_test.cpp +++ b/test/system-level/dca/ctint_sp_DCA_mpi_thread_test.cpp @@ -36,7 +36,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_loop/dca_loop.hpp" #include "dca/phys/dca_data/dca_data.hpp" #include "dca/phys/dca_step/cluster_solver/stdthread_qmci/stdthread_qmci_cluster_solver.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/phys/parameters/parameters.hpp" diff --git a/test/system-level/dca/dca_sp_DCA+_mpi_cuda_test.cpp b/test/system-level/dca/dca_sp_DCA+_mpi_cuda_test.cpp index 5ef504b71..b05250392 100644 --- a/test/system-level/dca/dca_sp_DCA+_mpi_cuda_test.cpp +++ b/test/system-level/dca/dca_sp_DCA+_mpi_cuda_test.cpp @@ -40,7 +40,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_loop/dca_loop.hpp" #include "dca/phys/dca_step/cluster_solver/ctaux/ctaux_cluster_solver.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/phys/parameters/parameters.hpp" diff --git a/test/system-level/dca/dca_sp_DCA+_mpi_test.cpp b/test/system-level/dca/dca_sp_DCA+_mpi_test.cpp index 1d15396d6..d18e42508 100644 --- a/test/system-level/dca/dca_sp_DCA+_mpi_test.cpp +++ b/test/system-level/dca/dca_sp_DCA+_mpi_test.cpp @@ -41,7 +41,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_loop/dca_loop.hpp" #include "dca/phys/dca_step/cluster_solver/ctaux/ctaux_cluster_solver.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/phys/parameters/parameters.hpp" diff --git a/test/system-level/dca/dca_sp_DCA+_thread_test.cpp b/test/system-level/dca/dca_sp_DCA+_thread_test.cpp index 53dc07d1a..eef8e76e4 100644 --- a/test/system-level/dca/dca_sp_DCA+_thread_test.cpp +++ b/test/system-level/dca/dca_sp_DCA+_thread_test.cpp @@ -41,7 +41,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_step/cluster_solver/stdthread_qmci/stdthread_qmci_cluster_solver.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/quantum/electron_band_domain.hpp" #include "dca/phys/domains/quantum/electron_spin_domain.hpp" #include "dca/phys/domains/time_and_frequency/frequency_domain.hpp" diff --git a/test/unit/math/function_transform/function_transform_test.cpp b/test/unit/math/function_transform/function_transform_test.cpp index 6a1f68dba..f9354754b 100644 --- a/test/unit/math/function_transform/function_transform_test.cpp +++ b/test/unit/math/function_transform/function_transform_test.cpp @@ -16,7 +16,7 @@ #include "dca/io/json/json_reader.hpp" #include "dca/io/hdf5/hdf5_reader.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "test/mock_mcconfig.hpp" namespace dca { diff --git a/test/unit/phys/dca_algorithms/compute_band_structure_test.cpp b/test/unit/phys/dca_algorithms/compute_band_structure_test.cpp index f1b236bb4..e98fd127d 100644 --- a/test/unit/phys/dca_algorithms/compute_band_structure_test.cpp +++ b/test/unit/phys/dca_algorithms/compute_band_structure_test.cpp @@ -22,7 +22,7 @@ #include "dca/parallel/no_threading/no_threading.hpp" #include "dca/profiling/null_profiler.hpp" #include "dca/phys/dca_step/cluster_solver/cluster_solver_id.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/quantum/brillouin_zone_cut_domain.hpp" #include "dca/phys/domains/quantum/electron_band_domain.hpp" #include "dca/phys/domains/quantum/electron_spin_domain.hpp" diff --git a/test/unit/phys/dca_algorithms/compute_free_greens_function_test.cpp b/test/unit/phys/dca_algorithms/compute_free_greens_function_test.cpp index 03117e75e..c572e99b7 100644 --- a/test/unit/phys/dca_algorithms/compute_free_greens_function_test.cpp +++ b/test/unit/phys/dca_algorithms/compute_free_greens_function_test.cpp @@ -21,7 +21,7 @@ #include "dca/function/domains.hpp" #include "dca/function/function.hpp" #include "dca/parallel/no_concurrency/no_concurrency.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/bilayer_lattice.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" diff --git a/test/unit/phys/dca_algorithms/compute_greens_function_test.cpp b/test/unit/phys/dca_algorithms/compute_greens_function_test.cpp index 9f485b0c7..92577e123 100644 --- a/test/unit/phys/dca_algorithms/compute_greens_function_test.cpp +++ b/test/unit/phys/dca_algorithms/compute_greens_function_test.cpp @@ -21,7 +21,7 @@ #include "dca/function/function.hpp" #include "dca/parallel/no_concurrency/no_concurrency.hpp" #include "dca/phys/dca_algorithms/compute_free_greens_function.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/bilayer_lattice.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" diff --git a/test/unit/phys/dca_step/cluster_solver/ctint/ct_int_solver_methods_test.cpp b/test/unit/phys/dca_step/cluster_solver/ctint/ct_int_solver_methods_test.cpp index ac8802612..6508d3fd0 100644 --- a/test/unit/phys/dca_step/cluster_solver/ctint/ct_int_solver_methods_test.cpp +++ b/test/unit/phys/dca_step/cluster_solver/ctint/ct_int_solver_methods_test.cpp @@ -14,7 +14,7 @@ using McOptions = MockMcOptions; #include "dca/phys/dca_step/cluster_solver/ctint/ctint_cluster_solver.hpp" #include "dca/testing/gtest_h_w_warning_blocking.h" #include "test/unit/phys/dca_step/cluster_solver/stub_rng.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/parallel/no_concurrency/no_concurrency.hpp" #include "dca/parallel/no_threading/no_threading.hpp" diff --git a/test/unit/phys/dca_step/cluster_solver/test_setup.hpp b/test/unit/phys/dca_step/cluster_solver/test_setup.hpp index 2cf8821e3..0cbc408f9 100644 --- a/test/unit/phys/dca_step/cluster_solver/test_setup.hpp +++ b/test/unit/phys/dca_step/cluster_solver/test_setup.hpp @@ -21,7 +21,7 @@ #include "dca/phys/parameters/parameters.hpp" #include "dca/phys/dca_step/cluster_solver/ctint/structs/interaction_vertices.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/quantum/electron_band_domain.hpp" #include "dca/phys/domains/quantum/electron_spin_domain.hpp" #include "dca/phys/domains/time_and_frequency/frequency_domain.hpp" diff --git a/test/unit/phys/dca_step/lattice_mapping/deconvolution/deconvolution_routines_test.cpp b/test/unit/phys/dca_step/lattice_mapping/deconvolution/deconvolution_routines_test.cpp index 1c59a3bed..524255a93 100644 --- a/test/unit/phys/dca_step/lattice_mapping/deconvolution/deconvolution_routines_test.cpp +++ b/test/unit/phys/dca_step/lattice_mapping/deconvolution/deconvolution_routines_test.cpp @@ -19,7 +19,7 @@ #include "dca/parallel/no_concurrency/no_concurrency.hpp" #include "dca/profiling/null_profiler.hpp" #include "dca/phys/dca_step/cluster_solver/cluster_solver_id.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" diff --git a/test/unit/phys/domains/cluster/CMakeLists.txt b/test/unit/phys/domains/cluster/CMakeLists.txt index 821b36155..716421069 100644 --- a/test/unit/phys/domains/cluster/CMakeLists.txt +++ b/test/unit/phys/domains/cluster/CMakeLists.txt @@ -13,5 +13,7 @@ dca_add_gtest(cluster_domain_test GTEST_MAIN LIBS ${LAPACK_LIBRARIES} function enumerations quantum_domains cluster_domains dca_io FFTW::Double ${DCA_GPU_LIBS}) +add_subdirectory(symmetries) + # deprecated (requires NFFT) # add_subdirectory(interpolation/wannier_interpolation) diff --git a/test/unit/phys/domains/cluster/interpolation/wannier_interpolation/wannier_interpolation_test.cpp b/test/unit/phys/domains/cluster/interpolation/wannier_interpolation/wannier_interpolation_test.cpp index 2acf8a390..b4d351d43 100644 --- a/test/unit/phys/domains/cluster/interpolation/wannier_interpolation/wannier_interpolation_test.cpp +++ b/test/unit/phys/domains/cluster/interpolation/wannier_interpolation/wannier_interpolation_test.cpp @@ -22,7 +22,7 @@ #include "dca/parallel/no_threading/no_threading.hpp" #include "dca/profiling/null_profiler.hpp" #include "dca/phys/dca_step/cluster_solver/cluster_solver_name.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/tight_binding_model.hpp" #include "dca/phys/parameters/parameters.hpp" diff --git a/test/unit/phys/domains/cluster/symmetries/CMakeLists.txt b/test/unit/phys/domains/cluster/symmetries/CMakeLists.txt new file mode 100644 index 000000000..1361082fb --- /dev/null +++ b/test/unit/phys/domains/cluster/symmetries/CMakeLists.txt @@ -0,0 +1,5 @@ +# domains/cluster/symmetries unit tests + +dca_add_gtest(holohedries_2d_test + GTEST_MAIN + LIBS ${DCA_GPU_LIBS}) diff --git a/test/unit/phys/domains/cluster/symmetries/holohedries_2d_test.cpp b/test/unit/phys/domains/cluster/symmetries/holohedries_2d_test.cpp new file mode 100644 index 000000000..a2bf531b0 --- /dev/null +++ b/test/unit/phys/domains/cluster/symmetries/holohedries_2d_test.cpp @@ -0,0 +1,146 @@ +// Copyright (C) 2018 UT-Battelle, LLC +// All rights reserved. +// +// See LICENSE for terms of usage. +// See CITATION.md for citation guidelines, if DCA++ is used for scientific publications. +// +// Author: Tyler Sax +// +// Completeness oracle for the 2D holohedry candidate pool. Proves the pool is a complete +// crystallographic op set: filtering the pool by each 2D Bravais lattice reproduces that +// lattice's full holohedry (square -> D4 order 8, hexagonal -> D6 order 12, rectangular -> D2 +// order 4, oblique -> C2 order 2). Because every one of the ten 2D crystallographic point groups +// is a subgroup of one of these holohedries, realizing all four maximal groups proves the pool +// misses no op. + +#include +#include +#include + +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" + +#include "gtest/gtest.h" + +#include "dca/util/type_list.hpp" + +namespace { + +// A 2x2 op stored row-major: m[i][j]. +using Mat2 = std::array, 2>; + +constexpr double kTol = 1e-10; + +// The op classes store their matrix column-major (m[i + 2*j] = row i, col j); convert to row-major. +Mat2 fromColumnMajor(const double* m) { + return {{{m[0], m[2]}, {m[1], m[3]}}}; +} + +// Materialize a point_group_type_list into its op matrices. Recurses over the typelist by index so +// the same helper serves any pool/group. +template +struct Collect { + static void run(std::vector& out) { + using Op = typename dca::util::TypeAt::type; + out.push_back(fromColumnMajor(Op::matrix())); + Collect::run(out); + } +}; +template +struct Collect { + static void run(std::vector&) {} +}; + +template +std::vector collectOps() { + using List = typename PointGroup::point_group_type_list; + std::vector out; + Collect::value>::run(out); + return out; +} + +// Note that the algebra below is implemented directly in this test, as opposed +// to being imported via the existing linalg path. Given this is a logic-only +// test operating on 2x2 matrices, hand rolling makes more sense than adding +// a dependency on LAPACK/BLAS, which is overkill here. +bool equal(const Mat2& a, const Mat2& b) { + for (int i = 0; i < 2; ++i) + for (int j = 0; j < 2; ++j) + if (std::abs(a[i][j] - b[i][j]) > kTol) + return false; + return true; +} + +std::vector dedup(const std::vector& ops) { + std::vector out; + for (const auto& o : ops) { + bool seen = false; + for (const auto& k : out) + seen = seen || equal(o, k); + if (!seen) + out.push_back(o); + } + return out; +} + +Mat2 matmul(const Mat2& a, const Mat2& b) { + Mat2 c{}; + for (int i = 0; i < 2; ++i) + for (int j = 0; j < 2; ++j) + c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j]; + return c; +} + +double det(const Mat2& a) { + return a[0][0] * a[1][1] - a[0][1] * a[1][0]; +} + +Mat2 inverse(const Mat2& a) { + const double d = det(a); + return {{{a[1][1] / d, -a[0][1] / d}, {-a[1][0] / d, a[0][0] / d}}}; +} + +bool isInteger(const Mat2& a) { + for (int i = 0; i < 2; ++i) + for (int j = 0; j < 2; ++j) + if (std::abs(a[i][j] - std::round(a[i][j])) > 1e-8) + return false; + return true; +} + +// Order of the holohedry of the lattice whose primitive vectors are the columns of +// `basis`: the number of pool ops that map the lattice onto itself (verified by applying +// the operation to the basis vectors, multiplying by the inverse of the basis, and +// checking whether the resulting matrix has integer values.) +int holohedryOrder(const std::vector& ops, const Mat2& basis) { + const Mat2 binv = inverse(basis); + int count = 0; + for (const auto& O : ops) + if (isInteger(matmul(binv, matmul(O, basis)))) + ++count; + return count; +} + +const double kHalfRoot3 = std::sqrt(3.0) / 2.0; + +} // namespace + +// Completeness: filtering the pool by each 2D Bravais lattice yields that lattice's full holohedry. +// Covering all four maximal groups (D4, D6, D2, C2) covers all ten 2D point groups as subgroups, so +// this is the load-bearing check that the pool misses no op. +// +// The pool lists D4 (8) + D6 (12) = 20 ops; the shared {identity, C2, mirror@0, mirror@90} collapse +// under dedup to 16 distinct ops, which is what the per-lattice filter runs over. +TEST(HolohedryPool2DTest, RealizesEvery2DHolohedry) { + const auto ops = dedup(collectOps()); + ASSERT_EQ(ops.size(), 16u); // 20 listed, 16 distinct after the D4/D6 overlap collapses + + const Mat2 square{{{1, 0}, {0, 1}}}; + const Mat2 hexagonal{{{1, -0.5}, {0, kHalfRoot3}}}; + const Mat2 rectangular{{{1, 0}, {0, 2}}}; + const Mat2 oblique{{{1, 0}, {0.3, 1.7}}}; + + EXPECT_EQ(holohedryOrder(ops, square), 8); // D4 + EXPECT_EQ(holohedryOrder(ops, hexagonal), 12); // D6 + EXPECT_EQ(holohedryOrder(ops, rectangular), 4); // D2 + EXPECT_EQ(holohedryOrder(ops, oblique), 2); // C2 +} diff --git a/test/unit/phys/models/analytic_hamiltonians/bilayer_lattice_test.cpp b/test/unit/phys/models/analytic_hamiltonians/bilayer_lattice_test.cpp index 41c0ae3d3..9e1d3b353 100644 --- a/test/unit/phys/models/analytic_hamiltonians/bilayer_lattice_test.cpp +++ b/test/unit/phys/models/analytic_hamiltonians/bilayer_lattice_test.cpp @@ -22,7 +22,7 @@ #include "dca/function/function.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" #include "dca/phys/domains/cluster/cluster_domain_initializer.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/cluster/cluster_domain_aliases.hpp" #include "dca/phys/parameters/model_parameters.hpp" diff --git a/test/unit/phys/models/analytic_hamiltonians/square_lattice_test.cpp b/test/unit/phys/models/analytic_hamiltonians/square_lattice_test.cpp index 2ae7c7665..04683e1f4 100644 --- a/test/unit/phys/models/analytic_hamiltonians/square_lattice_test.cpp +++ b/test/unit/phys/models/analytic_hamiltonians/square_lattice_test.cpp @@ -22,7 +22,7 @@ #include "dca/function/function.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" #include "dca/phys/domains/cluster/cluster_domain_initializer.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/cluster/cluster_domain_aliases.hpp" #include "dca/phys/parameters/model_parameters.hpp" diff --git a/test/unit/phys/models/analytic_hamiltonians/triangular_lattice_test.cpp b/test/unit/phys/models/analytic_hamiltonians/triangular_lattice_test.cpp index 0ef7e3431..ff9d9f8ae 100644 --- a/test/unit/phys/models/analytic_hamiltonians/triangular_lattice_test.cpp +++ b/test/unit/phys/models/analytic_hamiltonians/triangular_lattice_test.cpp @@ -22,14 +22,14 @@ #include "dca/function/function.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" #include "dca/phys/domains/cluster/cluster_domain_initializer.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_hexagonal.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/domains/cluster/cluster_domain_aliases.hpp" #include "dca/phys/parameters/model_parameters.hpp" using namespace dca; TEST(TriangularLatticeTest, Initialize_H_0) { - using PointGroup = phys::domains::C6; + using PointGroup = phys::domains::D6; using Lattice = phys::models::triangular_lattice; using BandDmn = func::dmn<1, int>; @@ -77,7 +77,7 @@ TEST(TriangularLatticeTest, Initialize_H_0) { } TEST(TriangularLatticeTest, Initialize_H_interaction) { - using PointGroup = phys::domains::C6; + using PointGroup = phys::domains::D6; using Lattice = phys::models::triangular_lattice; using BandDmn = func::dmn_0>; diff --git a/test/unit/phys/models/general_interaction_test.cpp b/test/unit/phys/models/general_interaction_test.cpp index a303fc624..07aec3601 100644 --- a/test/unit/phys/models/general_interaction_test.cpp +++ b/test/unit/phys/models/general_interaction_test.cpp @@ -17,7 +17,7 @@ #include "dca/function/function.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" #include "dca/phys/domains/cluster/cluster_domain_initializer.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/bilayer_lattice.hpp" #include "dca/phys/domains/cluster/cluster_domain_aliases.hpp" #include "dca/phys/parameters/model_parameters.hpp" diff --git a/test/unit/phys/parameters/model_parameters/model_parameters_2d_2band_test.cpp b/test/unit/phys/parameters/model_parameters/model_parameters_2d_2band_test.cpp index 2482eeb01..0b2f5c4e8 100644 --- a/test/unit/phys/parameters/model_parameters/model_parameters_2d_2band_test.cpp +++ b/test/unit/phys/parameters/model_parameters/model_parameters_2d_2band_test.cpp @@ -14,7 +14,7 @@ #include "dca/phys/parameters/model_parameters.hpp" #include "gtest/gtest.h" #include "dca/io/json/json_reader.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" using PointGroup = dca::phys::domains::D4; diff --git a/test/unit/phys/parameters/model_parameters/model_parameters_2d_4band_test.cpp b/test/unit/phys/parameters/model_parameters/model_parameters_2d_4band_test.cpp index 4ff63e190..361c59c51 100644 --- a/test/unit/phys/parameters/model_parameters/model_parameters_2d_4band_test.cpp +++ b/test/unit/phys/parameters/model_parameters/model_parameters_2d_4band_test.cpp @@ -14,7 +14,7 @@ #include "dca/phys/parameters/model_parameters.hpp" #include "gtest/gtest.h" #include "dca/io/json/json_reader.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" using PointGroup = dca::phys::domains::D4; diff --git a/test/unit/phys/parameters/model_parameters/model_parameters_bilayer_hubbard_test.cpp b/test/unit/phys/parameters/model_parameters/model_parameters_bilayer_hubbard_test.cpp index 640ff77ac..bc6fe528f 100644 --- a/test/unit/phys/parameters/model_parameters/model_parameters_bilayer_hubbard_test.cpp +++ b/test/unit/phys/parameters/model_parameters/model_parameters_bilayer_hubbard_test.cpp @@ -16,7 +16,7 @@ #include "dca/phys/parameters/model_parameters.hpp" #include "gtest/gtest.h" #include "dca/io/json/json_reader.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" using PointGroup = dca::phys::domains::D4; diff --git a/test/unit/phys/parameters/model_parameters/model_parameters_material_test.cpp b/test/unit/phys/parameters/model_parameters/model_parameters_material_test.cpp index 8dad1373d..cc7d8f7db 100644 --- a/test/unit/phys/parameters/model_parameters/model_parameters_material_test.cpp +++ b/test/unit/phys/parameters/model_parameters/model_parameters_material_test.cpp @@ -16,7 +16,7 @@ #include "dca/testing/gtest_h_w_warning_blocking.h" #include "dca/io/json/json_reader.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" using PointGroup = dca::phys::domains::D4; diff --git a/test/unit/phys/parameters/model_parameters/model_parameters_rashba_hubbard_test.cpp b/test/unit/phys/parameters/model_parameters/model_parameters_rashba_hubbard_test.cpp index 439579ce5..807d327f2 100644 --- a/test/unit/phys/parameters/model_parameters/model_parameters_rashba_hubbard_test.cpp +++ b/test/unit/phys/parameters/model_parameters/model_parameters_rashba_hubbard_test.cpp @@ -16,7 +16,7 @@ #include "dca/phys/parameters/model_parameters.hpp" #include "dca/testing/gtest_h_w_warning_blocking.h" #include "dca/io/json/json_reader.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/rashba_hubbard.hpp" using Lattice = dca::phys::models::RashbaHubbard>; diff --git a/test/unit/phys/parameters/model_parameters/model_parameters_single_band_hubbard_test.cpp b/test/unit/phys/parameters/model_parameters/model_parameters_single_band_hubbard_test.cpp index 7ff326ca8..a9e86574e 100644 --- a/test/unit/phys/parameters/model_parameters/model_parameters_single_band_hubbard_test.cpp +++ b/test/unit/phys/parameters/model_parameters/model_parameters_single_band_hubbard_test.cpp @@ -15,7 +15,7 @@ #include "dca/phys/parameters/model_parameters.hpp" #include "dca/testing/gtest_h_w_warning_blocking.h" #include "dca/io/json/json_reader.hpp" -#include "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" using PointGroup = dca::phys::domains::D4; From d7ecf0d85f7e0fede75733f51db784c366811b2b Mon Sep 17 00:00:00 2001 From: Tyler Sax Date: Thu, 2 Jul 2026 19:51:37 -0500 Subject: [PATCH 2/7] Symmetrization M2b: derive point group in update_domains, report divergence deriveAndComparePointGroup installs the 2D holohedry pool as the live group of a cluster family, gates the geometrically realized ops on H0 invariance, then restores (and verifies) the declared symmetry state. update_domains runs the check after each family's declared initializer and prints a rank-0 report only when the derived and declared groups differ; production symmetrization is unchanged. 3D models and legacy lattices without initializeH0 skip derivation. --- .../symmetrization/derive_point_group.hpp | 194 ++++++++++++++++++ include/dca/phys/parameters/parameters.hpp | 23 ++- .../symmetrize_characterization_test.cpp | 47 +++++ 3 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 include/dca/phys/dca_step/symmetrization/derive_point_group.hpp diff --git a/include/dca/phys/dca_step/symmetrization/derive_point_group.hpp b/include/dca/phys/dca_step/symmetrization/derive_point_group.hpp new file mode 100644 index 000000000..8244aae59 --- /dev/null +++ b/include/dca/phys/dca_step/symmetrization/derive_point_group.hpp @@ -0,0 +1,194 @@ +// Copyright (C) 2018 UT-Battelle, LLC +// All rights reserved. +// +// See LICENSE for terms of usage. +// See CITATION.md for citation guidelines, if DCA++ is used for scientific publications. +// +// Author: Tyler Sax (tylersax@gmail.com) +// +// Derives a 2D model's point group -- the built-in 2D holohedry pool filtered by the lattice geometry +// and by H0 invariance -- and compares it against the group realized from the model's declared +// DCA_point_group. Production symmetrization continues to use the DECLARED group: +// deriveAndComparePointGroup restores the declared symmetry state before returning and only +// reports divergences. The reports build a per-model map of models whose declaration disagrees with +// the symmetry encoded in their own Hamiltonian, which drives later declaration-free upgrades. + +#ifndef DCA_PHYS_DCA_STEP_SYMMETRIZATION_DERIVE_POINT_GROUP_HPP +#define DCA_PHYS_DCA_STEP_SYMMETRIZATION_DERIVE_POINT_GROUP_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include "dca/function/domains.hpp" +#include "dca/function/function.hpp" +#include "dca/phys/dca_step/symmetrization/solve_orbital_op_signs.hpp" +#include "dca/phys/domains/cluster/cluster_symmetry.hpp" +#include "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp" +#include "dca/phys/domains/cluster/symmetrization_algorithms/search_maximal_symmetry_group.hpp" +#include "dca/phys/domains/cluster/symmetrization_algorithms/set_symmetry_matrices.hpp" +#include "dca/phys/domains/quantum/electron_band_domain.hpp" +#include "dca/phys/domains/quantum/electron_spin_domain.hpp" +#include "dca/phys/domains/quantum/point_group_symmetry_element.hpp" + +namespace dca { +namespace phys { +// dca::phys:: + +namespace detail { +// dca::phys::detail:: + +// Geometric equality of two symmetry elements (same linear part and fractional translation), at the +// tolerance the symmetry search uses to deduplicate operations. +inline bool isSameSymmetryElement(const domains::point_group_symmetry_element& a, + const domains::point_group_symmetry_element& b) { + constexpr double tol = 1e-6; + if (a.DIMENSION != b.DIMENSION) + return false; + double diff = 0.; + for (int i = 0; i < a.DIMENSION * a.DIMENSION; ++i) + diff = std::max(diff, std::abs(a.O[i] - b.O[i])); + for (int i = 0; i < a.DIMENSION; ++i) + diff = std::max(diff, std::abs(a.t[i] - b.t[i])); + return diff < tol; +} + +inline bool containsSymmetryElement(const std::vector& set, + const domains::point_group_symmetry_element& op) { + for (const auto& element : set) + if (isSameSymmetryElement(element, op)) + return true; + return false; +} + +// Detects the initializeH0 lattice interface: the legacy lattices cannot feed the +// H0-invariance gate, so derivation skips them. +template +struct LatticeHasInitializeH0 : std::false_type {}; +template +struct LatticeHasInitializeH0(), std::declval()))>> + : std::true_type {}; + +// Makes PointGroup the live group of one cluster family, overwriting the previously realized group: +// clear the operation lists (the search only appends), re-search under the same geometric filter, +// resize the per-operation functions to the new count, and rebuild the symmetry tables. Assumes the +// family was already populated once by cluster_domain_symmetry_initializer. +template +void installPointGroup() { + using CS_k = domains::cluster_symmetry; + using CS_r = domains::cluster_symmetry; + using Family = typename CS_k::cluster_family_type; + + CS_k::sym_unit_cell_dmn_t::parameter_type::get_elements().clear(); + CS_k::sym_super_cell_dmn_t::parameter_type::get_elements().clear(); + domains::search_maximal_symmetry_group::execute(); + domains::search_maximal_symmetry_group::execute(); + CS_k::get_symmetry_matrix().reset(); + CS_r::get_symmetry_matrix().reset(); + CS_k::get_mapped_point().reset(); + CS_k::get_fold_phase().reset(); + CS_k::get_orbital_op().reset(); + domains::set_symmetry_matrices::execute(); +} + +} // namespace detail +// dca::phys:: + +// Derives the point group of a 2D model for one cluster family and returns a human-readable report +// of how it diverges from the declared group -- empty when they agree. Must be called right after +// cluster_domain_symmetry_initializer::execute() for the same family; +// the declared symmetry state is restored before returning, so production behavior is unchanged. +// 3D models (no 3D pool yet) and legacy lattices (no initializeH0) skip derivation entirely. +template +std::string deriveAndComparePointGroup(const Parameters& parameters) { + using Lattice = typename Model::lattice_type; + using RCluster = typename RClusterDmn::parameter_type; + using KCluster = typename domains::cluster_symmetry::dual_type; + using BDmn = func::dmn_0; + using SDmn = func::dmn_0; + using NuDmn = func::dmn_variadic; + using H0Type = + func::function, func::dmn_variadic>>; + + if constexpr (Lattice::DIMENSION != 2 || + !detail::LatticeHasInitializeH0::value) { + (void)parameters; + return ""; + } + else { + using KSymDmn = typename domains::cluster_symmetry::sym_super_cell_dmn_t; + using Element = domains::point_group_symmetry_element; + + // The realized declared group, populated by the initializer that just ran. Only the first + // get_size() entries are the live group: on a re-initialization (some tests run update_domains + // twice per process) the search zeroes the count but appends to the never-cleared element + // vector, so the vector can be longer than the group. The reference tracks the singleton + // through the group installs below; the copy preserves the declared ops. + const std::vector& realized = KSymDmn::parameter_type::get_elements(); + const int n_declared = KSymDmn::parameter_type::get_size(); + const std::vector declared(realized.begin(), realized.begin() + n_declared); + + // Derive: candidate pool -> same geometric filter -> H0-invariance gate. + detail::installPointGroup(); + + H0Type H0; + Model::initializeH0(parameters, H0); + + std::vector derived; + for (const int s : verifiedSymmetryOps(H0)) + derived.push_back(realized[s]); + + // Restore the declared production state, and verify the restoration: every consumer of the + // symmetry domains must see exactly the state the declared initializer produced. + detail::installPointGroup(); + + if (KSymDmn::parameter_type::get_size() != n_declared) + throw std::logic_error( + "deriveAndComparePointGroup: failed to restore the declared symmetry state of " + + KCluster::get_name() + "."); + for (std::size_t i = 0; i < declared.size(); ++i) + if (!detail::isSameSymmetryElement(realized[i], declared[i])) + throw std::logic_error( + "deriveAndComparePointGroup: failed to restore the declared symmetry state of " + + KCluster::get_name() + "."); + + // Compare as sets and report the divergence, if any. + int n_underdeclared = 0; + for (const auto& op : derived) + if (!detail::containsSymmetryElement(declared, op)) + ++n_underdeclared; + + int n_unverified = 0; + for (const auto& op : declared) + if (!detail::containsSymmetryElement(derived, op)) + ++n_unverified; + + if (n_underdeclared == 0 && n_unverified == 0) + return ""; + + std::ostringstream report; + report << "derived-symmetry check [" << KCluster::get_name() << "]:\n" + << "\tdeclared group: " << declared.size() << " op(s); derived group: " << derived.size() + << " op(s).\n"; + if (n_underdeclared > 0) + report << "\tunder-declared: " << n_underdeclared + << " derived H0-verified symmetry op(s) beyond the declared group " + << "(symmetry averaging left unexploited).\n"; + if (n_unverified > 0) + report << "\tWARNING: " << n_unverified + << " declared op(s) not reproduced by the derivation -- the op fails the " + << "H0-invariance check (or, the lattice is not in the pool's standard orientation).\n"; + return report.str(); + } +} + +} // namespace phys +} // namespace dca + +#endif // DCA_PHYS_DCA_STEP_SYMMETRIZATION_DERIVE_POINT_GROUP_HPP diff --git a/include/dca/phys/parameters/parameters.hpp b/include/dca/phys/parameters/parameters.hpp index b9bf52383..b1f66a280 100644 --- a/include/dca/phys/parameters/parameters.hpp +++ b/include/dca/phys/parameters/parameters.hpp @@ -40,6 +40,7 @@ #include "dca/phys/parameters/model_parameters.hpp" #include "dca/phys/parameters/output_parameters.hpp" #include "dca/phys/parameters/physics_parameters.hpp" +#include "dca/phys/dca_step/symmetrization/derive_point_group.hpp" #include "dca/phys/domains/cluster/cluster_domain.hpp" #include "dca/phys/domains/cluster/cluster_domain_family.hpp" #include "dca/phys/domains/cluster/cluster_domain_initializer.hpp" @@ -138,6 +139,16 @@ class Parameters : public AnalysisParameters, void update_model(); void update_domains(); + // Derives the point group of one cluster family from the holohedry pool + H0 and prints how it + // diverges from the declared group (rank 0; silent on agreement). The declared symmetry state is + // restored by the check, so production symmetrization is unchanged. + template + void checkDerivedSymmetry() const { + const std::string report = deriveAndComparePointGroup(*this); + if (!report.empty() && concurrency_.id() == concurrency_.first()) + std::cout << report; + } + int get_buffer_size(const concurrency_type& concurrency) const; void pack(const concurrency_type& concurrency, char* buffer, int buffer_size, int& position) const; void unpack(const concurrency_type& concurrency, char* buffer, int buffer_size, int& position); @@ -285,8 +296,8 @@ void ParametersreadWrite(read_obj); // Detect model-section input mistakes while the parsed tree is still live (before close_file). - // Only the JSON reader tracks which sections were read; HDF5 as input is realistically - // machine-generated, so the access check is not implemented for that path + // Only the JSON reader tracks which sections were read; HDF5 as input is realistically + // machine-generated, so the access check is not implemented for that path if constexpr (std::is_same_v) { checkModelSections(read_obj.topLevelGroupAccess(), filename); } @@ -335,6 +346,10 @@ void Parameters::execute(); + // The check runs immediately after the initializer: the derivation temporarily overwrites + // this family's symmetry singletons with the pool-derived group and then restores exactly + // the state the line above just produced. + checkDerivedSymmetry(); if (concurrency_.id() == concurrency_.first()) KClusterDmn::parameter_type::print(std::cout); @@ -344,6 +359,7 @@ void Parameters::execute(); + checkDerivedSymmetry(); domains::MomentumExchangeDomain::initialize(*this); @@ -355,6 +371,7 @@ void Parameters::execute(); + checkDerivedSymmetry(); if (concurrency_.id() == concurrency_.first()) KQHostDmn::parameter_type::print(std::cout); @@ -364,6 +381,7 @@ void Parameters::execute(); + checkDerivedSymmetry(); if (concurrency_.id() == concurrency_.first()) KQFineDmn::parameter_type::print(std::cout); @@ -381,6 +399,7 @@ void Parameters::execute(); + checkDerivedSymmetry(); if (concurrency_.id() == concurrency_.first()) KTpHostDmn::parameter_type::print(std::cout); diff --git a/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp b/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp index e33cb98c2..49a1ce596 100644 --- a/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp +++ b/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp @@ -40,6 +40,7 @@ #include "dca/platform/dca_gpu.h" #include "dca/phys/dca_step/symmetrization/symmetrize.hpp" +#include "dca/phys/dca_step/symmetrization/derive_point_group.hpp" #include "dca/phys/dca_step/symmetrization/solve_orbital_op_signs.hpp" #include @@ -107,6 +108,7 @@ struct SquareD4 { static std::vector expectedFailingKOps() { return {}; } static std::vector expectedFailingROps() { return {}; } static std::vector expectedUnverifiedKOps() { return {}; } + static constexpr int expected_num_derived_symmetries = 8; }; // CASE 2 -- three-band Hubbard (Emery/CuO2) model on D4. This case fails the @@ -126,6 +128,7 @@ struct ThreebandD4 { static std::vector expectedFailingKOps() { return {}; } static std::vector expectedFailingROps() { return {}; } static std::vector expectedUnverifiedKOps() { return {}; } + static constexpr int expected_num_derived_symmetries = 8; }; // CASE 3 -- 1D chain. Since this model has identity-only symmetry, this test exercises @@ -141,6 +144,7 @@ struct SinglebandChain { static std::vector expectedFailingKOps() { return {}; } static std::vector expectedFailingROps() { return {}; } static std::vector expectedUnverifiedKOps() { return {}; } + static constexpr int expected_num_derived_symmetries = 4; }; // Templated test fixture @@ -514,6 +518,49 @@ TYPED_TEST(SymmetrizeCharacterizationTest, GroupShadowCrossCheck) { "sign-consistency check rejects changed vs the expectation."; } +// TEST 5c: DerivedGroupReport -- the production derive-and-report step. update_domains now derives +// each 2D model's point group from scratch (2D holohedry pool -> geometry filter -> H0 gate), +// reports any divergence from the declared group, and keeps symmetrizing with the declared group. +// This exercises the same routine directly and asserts the three things production relies on: +// (1) the declared symmetry state -- op count and the full symmetry table -- is restored, so the +// derivation is invisible to every downstream consumer +// (2) the report is silent exactly when derived == declared, and names the divergence otherwise +// (3) the derived-group size matches the trait expectation +TYPED_TEST(SymmetrizeCharacterizationTest, DerivedGroupReport) { + using Fixture = SymmetrizeCharacterizationTest; + using RClusterDmn = typename Fixture::RClusterDmn; + using KCluster = typename Fixture::KCluster; + using Model = typename Fixture::Model; + using CS_k = dca::phys::domains::cluster_symmetry; + + const int n_ops_before = Fixture::KSymDmn::dmn_size(); + const auto symmetry_matrix_before = CS_k::get_symmetry_matrix(); + + const std::string report = + dca::phys::deriveAndComparePointGroup(this->parameters_); + + // (1) restoration: production must be left in exactly the declared state. + ASSERT_EQ(Fixture::KSymDmn::dmn_size(), n_ops_before); + const auto& symmetry_matrix_after = CS_k::get_symmetry_matrix(); + for (int i = 0; i < symmetry_matrix_before.size(); ++i) + ASSERT_EQ(symmetry_matrix_after(i), symmetry_matrix_before(i)) + << "symmetry table changed at linear index " << i; + + // (2) + (3): silent on match; on divergence the report names the derived-group size and the + // under-declaration. + if (TypeParam::expected_num_derived_symmetries == TypeParam::expected_num_symmetries) { + EXPECT_TRUE(report.empty()) << "unexpected divergence report:\n" << report; + } + else { + const std::string expected_size = "derived group: " + + std::to_string(TypeParam::expected_num_derived_symmetries) + + " op(s)"; + EXPECT_NE(report.find(expected_size), std::string::npos) << report; + EXPECT_NE(report.find("under-declared"), std::string::npos) << report; + std::cout << "[derived group] " << TypeParam::Input << ":\n" << report; + } +} + // TEST 6: MappedPointShadow -- the mapped_point accessor. The band-independent ".first" of the // legacy symmetry matrix (the image of each momentum under each op) is promoted into its own // (cluster-point x op) accessor. Verify it reproduces .first for every band, which confirms both From bae58db69592f9056abcbba10c5c26bc27ee58f9 Mon Sep 17 00:00:00 2001 From: Tyler Sax Date: Mon, 13 Jul 2026 15:28:14 -0500 Subject: [PATCH 3/7] name the divergent ops in the derived-symmetry report Add point_group_symmetry_element::describe(): a short human-readable label decoded from the op matrix -- Schoenflies name (Cn^k, sigma) plus geometry (rotation angle, mirror-line angle). The derive-and-compare report now lists the labeled ops in both divergence directions (under-declared and unverified) instead of bare counts, so a report line like "sigma (mirror @ 45 deg)" pinpoints which symmetry a model's declaration is missing or overclaiming. Some minor comment cleanup as well --- .../symmetrization/derive_point_group.hpp | 40 +++++++++++-------- .../point_groups/2d/holohedries_2d.hpp | 4 -- .../quantum/point_group_symmetry_element.hpp | 4 ++ .../quantum/point_group_symmetry_element.cpp | 39 ++++++++++++++++++ .../symmetrize_characterization_test.cpp | 5 +-- .../symmetries/holohedries_2d_test.cpp | 18 ++++----- 6 files changed, 78 insertions(+), 32 deletions(-) diff --git a/include/dca/phys/dca_step/symmetrization/derive_point_group.hpp b/include/dca/phys/dca_step/symmetrization/derive_point_group.hpp index 8244aae59..01649dc59 100644 --- a/include/dca/phys/dca_step/symmetrization/derive_point_group.hpp +++ b/include/dca/phys/dca_step/symmetrization/derive_point_group.hpp @@ -42,8 +42,8 @@ namespace phys { namespace detail { // dca::phys::detail:: -// Geometric equality of two symmetry elements (same linear part and fractional translation), at the -// tolerance the symmetry search uses to deduplicate operations. +// Geometric equality of two symmetry elements (same linear part .O and fractional translation .t), +// at the tolerance the symmetry search uses to deduplicate operations. inline bool isSameSymmetryElement(const domains::point_group_symmetry_element& a, const domains::point_group_symmetry_element& b) { constexpr double tol = 1e-6; @@ -144,8 +144,8 @@ std::string deriveAndComparePointGroup(const Parameters& parameters) { for (const int s : verifiedSymmetryOps(H0)) derived.push_back(realized[s]); - // Restore the declared production state, and verify the restoration: every consumer of the - // symmetry domains must see exactly the state the declared initializer produced. + // Restore the declared state, and verify the restoration: every consumer of the symmetry + // domains must see exactly the state the declared initializer produced. detail::installPointGroup(); if (KSymDmn::parameter_type::get_size() != n_declared) @@ -158,32 +158,40 @@ std::string deriveAndComparePointGroup(const Parameters& parameters) { "deriveAndComparePointGroup: failed to restore the declared symmetry state of " + KCluster::get_name() + "."); - // Compare as sets and report the divergence, if any. - int n_underdeclared = 0; + // Compare as sets and report the divergence, if any, naming the ops that differ. + std::vector underdeclared; for (const auto& op : derived) if (!detail::containsSymmetryElement(declared, op)) - ++n_underdeclared; + underdeclared.push_back(op.describe()); - int n_unverified = 0; + std::vector unverified; for (const auto& op : declared) if (!detail::containsSymmetryElement(derived, op)) - ++n_unverified; + unverified.push_back(op.describe()); - if (n_underdeclared == 0 && n_unverified == 0) + if (underdeclared.empty() && unverified.empty()) return ""; + auto join = [](const std::vector& ops) { + std::string s; + for (std::size_t i = 0; i < ops.size(); ++i) + s += (i ? ", " : "") + ops[i]; + return s; + }; + std::ostringstream report; report << "derived-symmetry check [" << KCluster::get_name() << "]:\n" << "\tdeclared group: " << declared.size() << " op(s); derived group: " << derived.size() << " op(s).\n"; - if (n_underdeclared > 0) - report << "\tunder-declared: " << n_underdeclared + if (!underdeclared.empty()) + report << "\tunder-declared: " << underdeclared.size() << " derived H0-verified symmetry op(s) beyond the declared group " - << "(symmetry averaging left unexploited).\n"; - if (n_unverified > 0) - report << "\tWARNING: " << n_unverified + << "(symmetry averaging left unexploited): " << join(underdeclared) << ".\n"; + if (!unverified.empty()) + report << "\tWARNING: " << unverified.size() << " declared op(s) not reproduced by the derivation -- the op fails the " - << "H0-invariance check (or, the lattice is not in the pool's standard orientation).\n"; + << "H0-invariance check (or, the lattice is not in the pool's standard orientation): " + << join(unverified) << ".\n"; return report.str(); } } diff --git a/include/dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp b/include/dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp index 37d8c4b33..c7eec398f 100644 --- a/include/dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp +++ b/include/dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp @@ -14,10 +14,6 @@ // (rectangular D2, oblique C2, trigonal C3/D3, ...) are not declared per model but derived at // runtime from the pool by the geometry filter (search_symmetry_group: is_lattice_compatible + // is_unit_cell_compatible) and the H0-invariance gate. -// -// holohedry_pool_2D is the union D4 U D6 -- the model-independent candidate set that discovery -// filters. It is a superset, not a closed group (it holds both a 90 deg and a 60 deg rotation, whose -// product is absent); that is intentional, the per-lattice filter extracts the closed subgroup. #ifndef DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_HOLOHEDRIES_2D_HPP #define DCA_PHYS_DOMAINS_CLUSTER_SYMMETRIES_POINT_GROUPS_2D_HOLOHEDRIES_2D_HPP diff --git a/include/dca/phys/domains/quantum/point_group_symmetry_element.hpp b/include/dca/phys/domains/quantum/point_group_symmetry_element.hpp index c61569ab8..9a808aae2 100644 --- a/include/dca/phys/domains/quantum/point_group_symmetry_element.hpp +++ b/include/dca/phys/domains/quantum/point_group_symmetry_element.hpp @@ -13,6 +13,7 @@ #define DCA_PHYS_DOMAINS_QUANTUM_POINT_GROUP_SYMMETRY_ELEMENT_HPP #include +#include #include namespace dca { @@ -38,6 +39,9 @@ class point_group_symmetry_element { void transform(const double* t0, double* t1) const; + // A short human-readable label for the operation. + std::string describe() const; + template void to_JSON(stream_type& ss) const; diff --git a/src/phys/domains/quantum/point_group_symmetry_element.cpp b/src/phys/domains/quantum/point_group_symmetry_element.cpp index 9c40ea952..5afceb7a4 100644 --- a/src/phys/domains/quantum/point_group_symmetry_element.cpp +++ b/src/phys/domains/quantum/point_group_symmetry_element.cpp @@ -11,7 +11,10 @@ #include "dca/phys/domains/quantum/point_group_symmetry_element.hpp" +#include #include +#include +#include namespace dca { namespace phys { @@ -80,6 +83,42 @@ void point_group_symmetry_element::transform(const double* t0, double* t1) const t1[i] += t[i]; } +std::string point_group_symmetry_element::describe() const { + std::ostringstream label; + + if (DIMENSION == 2) { + // O is column major, so its first column (O[0], O[1]) is (cos, sin) of the rotation angle for a + // proper rotation (det +1) and (cos, sin) of twice the mirror-line angle for a reflection (det + // -1). Each operation gets a Schoenflies name (Cn^k for rotation, and sigma for reflection) and + // a geometric description. + const double det = O[0] * O[3] - O[2] * O[1]; + if (det > 0.) { + const long raw = std::lround(std::atan2(O[1], O[0]) * 180. / M_PI); + const int deg = static_cast((raw % 360 + 360) % 360); + if (deg == 0) { + label << "E (identity)"; + } + else { + const int g = std::gcd(deg, 360); + label << "C" << 360 / g; + if (deg / g > 1) + label << "^" << deg / g; + label << " (rotation " << deg << " deg)"; + } + } + else { + const long raw = std::lround(std::atan2(O[1], O[0]) / 2. * 180. / M_PI); + const int deg = static_cast((raw % 180 + 180) % 180); + label << "sigma (mirror @ " << deg << " deg)"; + } + } + else { + label << DIMENSION << "D symmetry element"; + } + + return label.str(); +} + } // namespace domains } // namespace phys } // namespace dca diff --git a/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp b/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp index 49a1ce596..4e02b348f 100644 --- a/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp +++ b/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp @@ -522,9 +522,8 @@ TYPED_TEST(SymmetrizeCharacterizationTest, GroupShadowCrossCheck) { // each 2D model's point group from scratch (2D holohedry pool -> geometry filter -> H0 gate), // reports any divergence from the declared group, and keeps symmetrizing with the declared group. // This exercises the same routine directly and asserts the three things production relies on: -// (1) the declared symmetry state -- op count and the full symmetry table -- is restored, so the -// derivation is invisible to every downstream consumer -// (2) the report is silent exactly when derived == declared, and names the divergence otherwise +// (1) the declared symmetry state is restored, so the derivation is invisible downstream +// (2) the report is silent when derived == declared, and names the divergence otherwise // (3) the derived-group size matches the trait expectation TYPED_TEST(SymmetrizeCharacterizationTest, DerivedGroupReport) { using Fixture = SymmetrizeCharacterizationTest; diff --git a/test/unit/phys/domains/cluster/symmetries/holohedries_2d_test.cpp b/test/unit/phys/domains/cluster/symmetries/holohedries_2d_test.cpp index a2bf531b0..a2dfc7618 100644 --- a/test/unit/phys/domains/cluster/symmetries/holohedries_2d_test.cpp +++ b/test/unit/phys/domains/cluster/symmetries/holohedries_2d_test.cpp @@ -30,7 +30,8 @@ using Mat2 = std::array, 2>; constexpr double kTol = 1e-10; -// The op classes store their matrix column-major (m[i + 2*j] = row i, col j); convert to row-major. +// The op classes store their matrix column-major (m[i + 2*j] = row i, col j); convert to nested +// row-major in order to make the algebra more readable, and easier to verify. Mat2 fromColumnMajor(const double* m) { return {{{m[0], m[2]}, {m[1], m[3]}}}; } @@ -58,10 +59,9 @@ std::vector collectOps() { return out; } -// Note that the algebra below is implemented directly in this test, as opposed -// to being imported via the existing linalg path. Given this is a logic-only -// test operating on 2x2 matrices, hand rolling makes more sense than adding -// a dependency on LAPACK/BLAS, which is overkill here. +// Note that the algebra below is implemented directly in this test, as opposed to being imported +// via the existing linalg path. Given this is a logic-only test operating on 2x2 matrices, hand +// rolling makes more sense than adding a dependency on LAPACK/BLAS, which is overkill here. bool equal(const Mat2& a, const Mat2& b) { for (int i = 0; i < 2; ++i) for (int j = 0; j < 2; ++j) @@ -107,10 +107,10 @@ bool isInteger(const Mat2& a) { return true; } -// Order of the holohedry of the lattice whose primitive vectors are the columns of -// `basis`: the number of pool ops that map the lattice onto itself (verified by applying -// the operation to the basis vectors, multiplying by the inverse of the basis, and -// checking whether the resulting matrix has integer values.) +// Order of the holohedry of the lattice whose primitive vectors are the columns of `basis`: the +// number of pool ops that map the lattice onto itself (verified by applying the operation to the +// basis vectors, multiplying by the inverse of the basis, and checking whether the resulting +// matrix has integer values.) int holohedryOrder(const std::vector& ops, const Mat2& basis) { const Mat2 binv = inverse(basis); int count = 0; From c401448b094170df86e125e16545aa87952a86fa Mon Sep 17 00:00:00 2001 From: Tyler Sax Date: Tue, 14 Jul 2026 15:16:39 -0500 Subject: [PATCH 4/7] apply -1 guard in solveSignsForOp to prevent OOB Hats off to Claude for catching this. Since set_symmetry_matrices records (-1, -1) when no band image is found (i.e. no symmetry gets accepted), there is a possibility that H0 gets indexed with -1 leading to an out-of-bounds read. (Identified statically, confirmed with AddressSanitizer). The fix is one more rejection branch on solveSignsForOp. Kagome is the model that reliably produces this state, so it gets added as a fixture. --- .../symmetrization/solve_orbital_op_signs.hpp | 16 +++- .../phys/symmetrization/CMakeLists.txt | 11 +++ .../phys/symmetrization/kagome_input.json | 31 +++++++ .../symmetrize_characterization_test.cpp | 83 ++++++++++++++++++- 4 files changed, 135 insertions(+), 6 deletions(-) create mode 100644 test/integration/phys/symmetrization/kagome_input.json diff --git a/include/dca/phys/dca_step/symmetrization/solve_orbital_op_signs.hpp b/include/dca/phys/dca_step/symmetrization/solve_orbital_op_signs.hpp index ae2d5768f..80e602c55 100644 --- a/include/dca/phys/dca_step/symmetrization/solve_orbital_op_signs.hpp +++ b/include/dca/phys/dca_step/symmetrization/solve_orbital_op_signs.hpp @@ -29,9 +29,11 @@ // // The analytic models shipped with DCA++ have at most n_b = 3 orbitals, so once the gauge // sigma(0) = +1 is fixed there are at most 2^(n_b-1) <= 4 candidate sign vectors. We simply -// enumerate them and keep the one that satisfies every coupling constraint. Three conditions make +// enumerate them and keep the one that satisfies every coupling constraint. Four conditions make // an operation fail: // +// * a missing band image in the symmetry table (the -1 value recorded by set_symmetry_matrices +// when it finds no admissible image) means the op has no candidate permutation at all; // * a magnitude mismatch (an entry vanishing on only one side) means the permutation is not a // symmetry of H0; // * a non-real or non-unit ratio means the op needs a non-signed-permutation U_S (genuine orbital @@ -78,8 +80,18 @@ void solveSignsForOp(int s, int nb, int nk, const SymFunc& sym, const FoldFunc& // half of U_S (which orbital maps to which); it is k-independent for a point-group op, so read it // at k = 0. Only the signs that decorate it are unknown. std::vector image(nb); - for (int b = 0; b < nb; ++b) + for (int b = 0; b < nb; ++b) { image[b] = sym(0, b, s).second; + // set_symmetry_matrices records a silent -1 sentinel when its position/flavor matching finds + // no admissible image (its own throw is commented out), so the table cannot be assumed + // complete here. Reject the op before the sentinel is used to index H0. + if (image[b] < 0 || image[b] >= nb) + throw std::out_of_range( + "solveOrbitalOpSignsFromH0: no band image in the symmetry table for band " + + std::to_string(b) + " under op " + std::to_string(s) + + " -- the geometric position/flavor matching found no admissible image, so the op has no " + "candidate permutation."); + } // Gather one sign-product constraint per nonzero coupling, over all cluster momenta. Each nonzero // coupling forces sigma(b0) sigma(b1) to the +/-1 fold-corrected ratio of the two H0 entries. The diff --git a/test/integration/phys/symmetrization/CMakeLists.txt b/test/integration/phys/symmetrization/CMakeLists.txt index fd3ba98d8..7653c0dea 100644 --- a/test/integration/phys/symmetrization/CMakeLists.txt +++ b/test/integration/phys/symmetrization/CMakeLists.txt @@ -22,6 +22,17 @@ dca_add_gtest(symmetrize_characterization_threeband_D4_test TEST_DEFINES ThreebandD4 ) +# Regression case for solveSignsForOp's -1 guard: Kagome produces the -1 which the solver +# must reject instead of indexing H0 out of bounds. +dca_add_gtest(symmetrize_characterization_kagome_test + FAST + GTEST_MPI_MAIN + INCLUDE_DIRS ${DCA_INCLUDES};${PROJECT_SOURCE_DIR};${FFTW_INCLUDE_DIR} + LIBS ${DCA_LIBS} + CUSTOM_SOURCE symmetrize_characterization_test.cpp + TEST_DEFINES KagomeNoSym + ) + dca_add_gtest(symmetrize_characterization_singleband_chain_test FAST GTEST_MPI_MAIN diff --git a/test/integration/phys/symmetrization/kagome_input.json b/test/integration/phys/symmetrization/kagome_input.json new file mode 100644 index 000000000..0df6aae0d --- /dev/null +++ b/test/integration/phys/symmetrization/kagome_input.json @@ -0,0 +1,31 @@ +{ + "physics": { + "beta" : 1., + "chemical-potential" : 0. + }, + + "Kagome-Hubbard-model": + { + "t" : 1., + "U" : 2. + }, + + "domains": { + "real-space-grids": { + "cluster": [[2, 0], [0, 2]], + "sp-host": [[8, 0], [0, 8]] + }, + + "imaginary-time": { + "sp-time-intervals": 128 + }, + + "imaginary-frequency": { + "sp-fermionic-frequencies": 64 + } + }, + + "DCA": { + "interacting-orbitals": [0, 1, 2] + } +} diff --git a/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp b/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp index 4e02b348f..495ab4729 100644 --- a/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp +++ b/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp @@ -63,6 +63,7 @@ #include "dca/phys/domains/cluster/symmetries/point_groups/no_symmetry.hpp" #include "dca/phys/parameters/parameters.hpp" #include "dca/profiling/null_profiler.hpp" +#include "dca/phys/models/analytic_hamiltonians/Kagome_hubbard.hpp" #include "dca/phys/models/analytic_hamiltonians/singleband_chain.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/analytic_hamiltonians/threeband_hubbard.hpp" @@ -147,6 +148,24 @@ struct SinglebandChain { static constexpr int expected_num_derived_symmetries = 4; }; +// CASE 4 -- Kagome lattice declared with no_symmetry<2>, mirroring the production +// instantiation in test/unit/phys/dca_step/cluster_solver/test_setup.hpp. This is the +// regression case for solveSignsForOp's -1 guard: the hexagonal has the 12 D6 ops, +// but the orbital position+flavor matching in set_symmetry_matrices filters them all out, +// and records (-1, -1). The H0 sign solver must reject the ops instead of indexing H0 with +// band -1 (an OOB). +struct KagomeNoSym { + using Scalar = double; + using Lattice = dca::phys::models::KagomeHubbard>; + static constexpr char Input[] = "kagome_input.json"; + static constexpr int expected_num_symmetries = 1; + static std::vector expectedFailingReps() { return {}; } + static std::vector expectedFailingKOps() { return {}; } + static std::vector expectedFailingROps() { return {}; } + static std::vector expectedUnverifiedKOps() { return {}; } + static constexpr int expected_num_derived_symmetries = 2; +}; + // Templated test fixture template class SymmetrizeCharacterizationTest : public ::testing::Test { @@ -652,11 +671,12 @@ TYPED_TEST(SymmetrizeCharacterizationTest, PerOpMapRealSpace) { << "Real-space per-op red/green map changed vs the expected failing set."; } -// TEST 8 (a/b/c): rejection fixtures for the sign-consistency solver. +// TEST 8 (a/b/c/d): rejection fixtures for the sign-consistency solver. // -// solveOrbitalOpSignsFromH0 has three throw branches. No shipped model exercises any of the -// three on a correct H0 -- the spine cases all pass -- so we perturb a copy of the (exactly -// symmetric) H0 to break one operation and assert the solver throws for the intended reason. +// solveOrbitalOpSignsFromH0 has four throw branches. No shipped model exercises any of the +// four on a correct H0 and a complete symmetry table -- the spine cases all pass -- so we +// perturb a copy of the (exactly symmetric) H0 (8a-8c), or the table itself (8d), to break one +// operation and assert the solver throws for the intended reason. // // These need a multi-orbital model. A single band has no off-diagonal coupling to corrupt, // and on the spine's square cluster every nonzero single-band entry sits at a k that is a @@ -686,6 +706,29 @@ TYPED_TEST(SymmetrizeCharacterizationTest, RejectsBrokenOffDiagonalCoupling) { const auto t = findStrongestOffDiagonal(this->H0_, nb, nk); ASSERT_GT(t.mag, kTolerance) << "no off-diagonal coupling to perturb."; + // The perturbation is only visible to an op that maps the corrupted entry to a *different* + // (unperturbed) H0 entry. Both the entry and its Hermitian partner are perturbed, so an op + // landing on either sees a consistent H0 and cannot throw. An identity-only group (e.g. a + // multi-band lattice declared with no_symmetry) therefore has nothing to detect: skip. + { + const auto& sym = dca::phys::domains::cluster_symmetry::get_symmetry_matrix(); + const int n_ops = Fixture::KSymDmn::dmn_size(); + bool movable = false; + for (int s = 0; s < n_ops && !movable; ++s) { + const int k_new = sym(t.k, 0, s).first; + const int b0_new = sym(0, t.b0, s).second; + const int b1_new = sym(0, t.b1, s).second; + const bool fixes = k_new == t.k && b0_new == t.b0 && b1_new == t.b1; + const bool hermitian_partner = k_new == t.k && b0_new == t.b1 && b1_new == t.b0; + movable = !fixes && !hermitian_partner; + } + if (!movable) { + std::cout << "[skip] " << TypeParam::Input + << ": no op moves the corrupted coupling to an unperturbed entry.\n"; + return; + } + } + // Vanish: the op connecting this entry to its (still nonzero) image sees it gone on one side only. { auto H0p = this->H0_; @@ -811,4 +854,36 @@ TEST(SolveOrbitalOpSigns, BoundaryFoldDoesNotMaskPxParity) { EXPECT_DOUBLE_EQ(u_s(2, 2, 0), 1.); } +// 8d -- missing band image: the geometric position/flavor matching in set_symmetry_matrices +// records -1 when it finds no admissible image, so the solver cannot assume a complete table. +// Unlike 8a-8c this perturbs the symmetry table, not H0: the whole-group populator must throw, +// and the non-throwing classifier must omit the op instead of indexing H0 with -1 (an OOB). The +// table is shared static state, so it gets restored. +TYPED_TEST(SymmetrizeCharacterizationTest, RejectsMissingBandImage) { + using Fixture = SymmetrizeCharacterizationTest; + using KCluster = typename Fixture::KCluster; + + const std::vector baseline = dca::phys::verifiedSymmetryOps(this->H0_); + ASSERT_FALSE(baseline.empty()) << "no verified op to corrupt (identity should always pass)."; + const int s_target = baseline.front(); + + auto& sym = dca::phys::domains::cluster_symmetry::get_symmetry_matrix(); + const int saved_image = sym(0, 0, s_target).second; + sym(0, 0, s_target).second = -1; + + const std::string msg = + captureThrowMessage([&] { dca::phys::solveOrbitalOpSignsFromH0(this->H0_); }); + const std::vector verified = dca::phys::verifiedSymmetryOps(this->H0_); + + sym(0, 0, s_target).second = saved_image; + + ASSERT_FALSE(msg.empty()) << "sign solver did not reject a -1 sentinel band image."; + EXPECT_NE(msg.find("no band image"), std::string::npos) << "actual: " << msg; + + std::vector expected = baseline; + expected.erase(std::find(expected.begin(), expected.end(), s_target)); + EXPECT_EQ(verified, expected) + << "classifier did not cleanly omit (only) the op with the sentinel image."; +} + } // namespace From a7a0c8b058f2667bc3439dbf5a920d3c0e0f7a2a Mon Sep 17 00:00:00 2001 From: Tyler Sax Date: Wed, 15 Jul 2026 16:08:17 -0500 Subject: [PATCH 5/7] repair point-group config, decode rotations in twelfths --- cmake/dca_config.cmake | 13 ++++++------ .../quantum/point_group_symmetry_element.cpp | 20 +++++++++++-------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/cmake/dca_config.cmake b/cmake/dca_config.cmake index 976f24253..1d660cead 100644 --- a/cmake/dca_config.cmake +++ b/cmake/dca_config.cmake @@ -100,15 +100,16 @@ endif() # TODO: Add more point groups and lattices. # Point group -set(DCA_POINT_GROUP "D4" CACHE STRING "Point group symmetry, options are: C6 | D4 | no_symmetry<2> | no_symmetry<3>.") -set_property(CACHE DCA_POINT_GROUP PROPERTY STRINGS C6 D4 no_symmetry<2> no_symmetry<3>) +set(DCA_POINT_GROUP "D4" CACHE STRING "Point group symmetry, options are: D6 | D4 | no_symmetry<2> | no_symmetry<3>.") +set_property(CACHE DCA_POINT_GROUP PROPERTY STRINGS D6 D4 no_symmetry<2> no_symmetry<3>) -if (DCA_POINT_GROUP STREQUAL "C6") +if (DCA_POINT_GROUP STREQUAL "D6") set(DCA_POINT_GROUP_INCLUDE - "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_hexagonal.hpp") + "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp") elseif (DCA_POINT_GROUP STREQUAL "D4") - set(DCA_POINT_GROUP_INCLUDE "dca/phys/domains/cluster/symmetries/point_groups/2d/2d_square.hpp") + set(DCA_POINT_GROUP_INCLUDE + "dca/phys/domains/cluster/symmetries/point_groups/2d/holohedries_2d.hpp") elseif (DCA_POINT_GROUP STREQUAL "no_symmetry<2>") set(DCA_POINT_GROUP_INCLUDE "dca/phys/domains/cluster/symmetries/point_groups/no_symmetry.hpp") @@ -116,7 +117,7 @@ elseif (DCA_POINT_GROUP STREQUAL "no_symmetry<3>") set(DCA_POINT_GROUP_INCLUDE "dca/phys/domains/cluster/symmetries/point_groups/no_symmetry.hpp") else() - message(FATAL_ERROR "Please set DCA_POINT_GROUP to a valid option: C6 | D4 | no_symmetry<2> | no_symmetry<3>.") + message(FATAL_ERROR "Please set DCA_POINT_GROUP to a valid option: D6 | D4 | no_symmetry<2> | no_symmetry<3>.") endif() # Lattice type diff --git a/src/phys/domains/quantum/point_group_symmetry_element.cpp b/src/phys/domains/quantum/point_group_symmetry_element.cpp index 5afceb7a4..813f50cb6 100644 --- a/src/phys/domains/quantum/point_group_symmetry_element.cpp +++ b/src/phys/domains/quantum/point_group_symmetry_element.cpp @@ -91,19 +91,23 @@ std::string point_group_symmetry_element::describe() const { // proper rotation (det +1) and (cos, sin) of twice the mirror-line angle for a reflection (det // -1). Each operation gets a Schoenflies name (Cn^k for rotation, and sigma for reflection) and // a geometric description. + // + // Rotations are decoded in twelfths of a full turn, with the parenthetical is still printed in + // degrees (t * 30) for readability. + constexpr int kTwelfths = 12; const double det = O[0] * O[3] - O[2] * O[1]; if (det > 0.) { - const long raw = std::lround(std::atan2(O[1], O[0]) * 180. / M_PI); - const int deg = static_cast((raw % 360 + 360) % 360); - if (deg == 0) { + const long raw = std::lround(std::atan2(O[1], O[0]) * kTwelfths / (2. * M_PI)); + const int t = static_cast((raw % kTwelfths + kTwelfths) % kTwelfths); + if (t == 0) { label << "E (identity)"; } else { - const int g = std::gcd(deg, 360); - label << "C" << 360 / g; - if (deg / g > 1) - label << "^" << deg / g; - label << " (rotation " << deg << " deg)"; + const int g = std::gcd(t, kTwelfths); + label << "C" << kTwelfths / g; + if (t / g > 1) + label << "^" << t / g; + label << " (rotation " << t * (360 / kTwelfths) << " deg)"; } } else { From 45c21a0a53ea6193a99dc2e5b51266f791523e66 Mon Sep 17 00:00:00 2001 From: Tyler Sax Date: Mon, 20 Jul 2026 09:11:59 -0500 Subject: [PATCH 6/7] update point_group_symmetry_element::describe() to report radians, not degrees --- .../quantum/point_group_symmetry_element.cpp | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/src/phys/domains/quantum/point_group_symmetry_element.cpp b/src/phys/domains/quantum/point_group_symmetry_element.cpp index 813f50cb6..82f1e824b 100644 --- a/src/phys/domains/quantum/point_group_symmetry_element.cpp +++ b/src/phys/domains/quantum/point_group_symmetry_element.cpp @@ -83,6 +83,27 @@ void point_group_symmetry_element::transform(const double* t0, double* t1) const t1[i] += t[i]; } +namespace { +// Writes the angle (num / den) * pi in lowest terms, e.g. 0, pi, pi/2, 2pi/3. +std::string formatPiFraction(int num, int den) { + if (num == 0) + return "0"; + + const int g = std::gcd(num, den); + num /= g; + den /= g; + + std::ostringstream angle; + if (num > 1) + angle << num; + angle << "pi"; + if (den > 1) + angle << "/" << den; + + return angle.str(); +} +} // namespace + std::string point_group_symmetry_element::describe() const { std::ostringstream label; @@ -92,28 +113,31 @@ std::string point_group_symmetry_element::describe() const { // -1). Each operation gets a Schoenflies name (Cn^k for rotation, and sigma for reflection) and // a geometric description. // - // Rotations are decoded in twelfths of a full turn, with the parenthetical is still printed in - // degrees (t * 30) for readability. - constexpr int kTwelfths = 12; + // Rotations are decoded in twelfths of a full turn, and mirror lines are decoded in twelfths of + // pi. Both are reported in radians. + constexpr int kTurn = 12; const double det = O[0] * O[3] - O[2] * O[1]; if (det > 0.) { - const long raw = std::lround(std::atan2(O[1], O[0]) * kTwelfths / (2. * M_PI)); - const int t = static_cast((raw % kTwelfths + kTwelfths) % kTwelfths); + const long raw = std::lround(std::atan2(O[1], O[0]) * kTurn / (2. * M_PI)); + const int t = static_cast((raw % kTurn + kTurn) % kTurn); if (t == 0) { label << "E (identity)"; } else { - const int g = std::gcd(t, kTwelfths); - label << "C" << kTwelfths / g; + const int g = std::gcd(t, kTurn); + label << "C" << kTurn / g; if (t / g > 1) label << "^" << t / g; - label << " (rotation " << t * (360 / kTwelfths) << " deg)"; + // A rotation by t twelfths of a turn is an angle of 2 pi t / 12 = t pi / 6. + label << " (rotation " << formatPiFraction(t, kTurn / 2) << " rad)"; } } else { - const long raw = std::lround(std::atan2(O[1], O[0]) / 2. * 180. / M_PI); - const int deg = static_cast((raw % 180 + 180) % 180); - label << "sigma (mirror @ " << deg << " deg)"; + // The mirror-line angle is half the angle carried by the first column, so halving turns + // twelfths of a turn into twelfths of pi and the mirror line is m * pi / 12. + const long raw = std::lround(std::atan2(O[1], O[0]) * kTurn / (2. * M_PI)); + const int m = static_cast((raw % kTurn + kTurn) % kTurn); + label << "sigma (mirror @ " << formatPiFraction(m, kTurn) << " rad)"; } } else { From 663769f8d80d2bef8c81526efbe60759a75a57a1 Mon Sep 17 00:00:00 2001 From: Tyler Sax Date: Tue, 21 Jul 2026 10:14:52 -0500 Subject: [PATCH 7/7] recover symmetries for same-site orbital swap case Background: I was running FeAs against the derived-symmetry report we just landed in #369, and it came back with 4 ops vs the expected 8. The solver was rejecting C4, C4^3 and the two diagonal mirrors. Problem: FeAs's two orbitals (d_xz, d_yz) both sit at a_vec = 0. set_symmetry_matrices builds the band image by transforming r + a_b and looking for an orbital at the image position carrying the same flavor. Two orbitals on one site make the position test uninformative -- it matches every band equally. The "flavor" breaks the tie, and that pins each band to itself. The band image comes out the identity for every op, unconditionally. solveSignsForOp took the image on faith and solved only the signs. Signs can flip an entry, but they cannot move it to another band. So the solver falsely rejected real symmetries. The (small) fix: treat the geometric image as a candidate rather than an oracle. solveSignsForOp splits into tryPermutation (same function we had before, returning false where it used to throw) and deriveOrbitalOpForOp, which checks the geometric candidate first and otherwise walks the remaining permutations. Throw only when none of them works. Result 1: FeAs goes from 4 derived ops to 8, and is added as a characterization fixture to pin the number. Result 2: A Kagome win falls out of the same change. Kagome labels its three symmetry-equivalent sublattices with distinct flavors, so its matching finds no admissible image at all and records the -1 that c401448b added a guard for. Deriving P from H0 does more than dodge the out-of-bounds read -- it recovers the ops geometry could not place, and Kagome goes from 2 derived ops to 12. --- .../symmetrization/solve_orbital_op_signs.hpp | 125 ++++++++++-------- .../phys/symmetrization/CMakeLists.txt | 15 ++- .../phys/symmetrization/fe_as_input.json | 37 ++++++ .../symmetrize_characterization_test.cpp | 86 +++++++----- 4 files changed, 171 insertions(+), 92 deletions(-) create mode 100644 test/integration/phys/symmetrization/fe_as_input.json diff --git a/include/dca/phys/dca_step/symmetrization/solve_orbital_op_signs.hpp b/include/dca/phys/dca_step/symmetrization/solve_orbital_op_signs.hpp index 80e602c55..f40ffb39f 100644 --- a/include/dca/phys/dca_step/symmetrization/solve_orbital_op_signs.hpp +++ b/include/dca/phys/dca_step/symmetrization/solve_orbital_op_signs.hpp @@ -9,9 +9,12 @@ // Derives the orbital-operation matrix U_S of each point-group operation from H0(k) and populates // cluster_symmetry::get_orbital_op(), without reading hand-coded Lattice::transformationSignOf*. // -// Scope: for every analytic model, U_S is a real signed permutation U_S = D P, where the -// permutation P is already encoded in the symmetry table (the band image .second) and the only -// unknown is the diagonal of +/-1 signs D = diag(sigma). +// Scope: for every analytic model, U_S is a real signed permutation U_S = D P. Both halves are +// derived from H0: the permutation P (which orbital maps to which) and the diagonal of +/-1 signs +// D = diag(sigma). The symmetry table's band image (.second) is only the first candidate for P; +// when H0 rejects it -- geometry cannot see an on-site orbital rotation, such as the dxz/dyz swap +// under C4 of two orbitals sharing a_vec = 0 -- the remaining permutations are searched. n_b <= 3 +// for every shipped model, so that is at most 3! = 6 candidates. // // The symmetry table stores not the exact momentum image S k but its folded representative // k_new = S k - G, and with intra-cell orbital offsets a_b the fold is not free: H0 picks up the @@ -27,22 +30,25 @@ // the odd parity of p_x under a mirror at a zone-boundary momentum) instead of the intrinsic // orbital transform. // -// The analytic models shipped with DCA++ have at most n_b = 3 orbitals, so once the gauge -// sigma(0) = +1 is fixed there are at most 2^(n_b-1) <= 4 candidate sign vectors. We simply -// enumerate them and keep the one that satisfies every coupling constraint. Four conditions make -// an operation fail: +// For a candidate permutation, the signs are found by enumerating the at most 2^(n_b-1) <= 4 +// vectors with the gauge sigma(0) = +1 and keeping the one that satisfies every constraint. +// A malformed candidate (an out-of-range or repeated band image -- only the geometric one can be) +// is rejected up front; an admissible one is rejected, and the next tried, when: // -// * a missing band image in the symmetry table (the -1 value recorded by set_symmetry_matrices -// when it finds no admissible image) means the op has no candidate permutation at all; -// * a magnitude mismatch (an entry vanishing on only one side) means the permutation is not a -// symmetry of H0; -// * a non-real or non-unit ratio means the op needs a non-signed-permutation U_S (genuine orbital -// mixing, not yet supported) or is not a symmetry; -// * no candidate sign vector satisfying all couplings means no signed-permutation U_S exists. +// * a coupling vanishes on only one side (a magnitude mismatch -- the permutation is not a +// symmetry of H0) +// * a fold-corrected ratio is not a real +/-1 (this permutation would need a +// non-signed-permutation U_S) +// * no sign vector satisfies all couplings +// +// Only when every band permutation is rejected does the operation fail outright: it then needs a +// genuinely non-signed-permutation U_S (orbital mixing or a complex phase out of scope) or is not +// a symmetry of H0. #ifndef DCA_PHYS_DCA_STEP_SYMMETRIZATION_SOLVE_ORBITAL_OP_SIGNS_HPP #define DCA_PHYS_DCA_STEP_SYMMETRIZATION_SOLVE_ORBITAL_OP_SIGNS_HPP +#include #include #include #include @@ -67,37 +73,25 @@ constexpr double kCouplingZeroTol = 1e-10; // magnitude from 1 must both be below this. constexpr double kSignRealTol = 1e-9; -// Solves the +/-1 signs of one operation s and writes that op's U_S block into u_s. fold_phase is -// the diagonal folding phase phi (callable as fold_phase(k, band, s)) that undresses the folded -// H0 samples, so the solved signs are the intrinsic orbital transform. Throws if op s is not a -// signed-permutation symmetry of H0. Shared by the whole-group populator -- which lets the throw -// propagate, since a model must be a genuine symmetry group -- and by the group verification, -// which catches it to classify the op. +// Tests one candidate band permutation `image` against H0. Returns true, and writes that op into +// u_s, iff `image` is a signed-permutation symmetry of H0: every nonzero coupling gives a real +// +/-1 (fold-corrected) ratio, and some sign vector satisfies the resulting products. template -void solveSignsForOp(int s, int nb, int nk, const SymFunc& sym, const FoldFunc& fold_phase, - const H0Function& H0, UFunc& u_s) { - // Band permutation P: row b's single entry lands in column image[b]. This is the geometry-derived - // half of U_S (which orbital maps to which); it is k-independent for a point-group op, so read it - // at k = 0. Only the signs that decorate it are unknown. - std::vector image(nb); +bool tryPermutation(const std::vector& image, int s, int nb, int nk, const SymFunc& sym, + const FoldFunc& fold_phase, const H0Function& H0, UFunc& u_s) { + // Reject a malformed candidate before it indexes H0: an out-of-range entry (the -1 recorded when + // set_symmetry_matrices finds no admissible image) or a repeated one (two orbitals sharing a site + // and a flavor collide). + std::vector is_hit(nb, false); for (int b = 0; b < nb; ++b) { - image[b] = sym(0, b, s).second; - // set_symmetry_matrices records a silent -1 sentinel when its position/flavor matching finds - // no admissible image (its own throw is commented out), so the table cannot be assumed - // complete here. Reject the op before the sentinel is used to index H0. - if (image[b] < 0 || image[b] >= nb) - throw std::out_of_range( - "solveOrbitalOpSignsFromH0: no band image in the symmetry table for band " + - std::to_string(b) + " under op " + std::to_string(s) + - " -- the geometric position/flavor matching found no admissible image, so the op has no " - "candidate permutation."); + if (image[b] < 0 || image[b] >= nb || is_hit[image[b]]) + return false; + is_hit[image[b]] = true; } // Gather one sign-product constraint per nonzero coupling, over all cluster momenta. Each nonzero - // coupling forces sigma(b0) sigma(b1) to the +/-1 fold-corrected ratio of the two H0 entries. The - // ratio must be a real +/-1 for a signed permutation to exist at all; the two checks below - // (magnitude match, real +/-1) are independent of the signs themselves, so they are tested here - // and reported as the first two rejection branches. + // coupling forces sigma(b0) sigma(b1) to the +/-1 fold-corrected ratio of the two H0 entries; the + // ratio must be a real +/-1 for a signed permutation to exist under this permutation at all. struct Constraint { int b0, b1, product; }; @@ -114,10 +108,7 @@ void solveSignsForOp(int s, int nb, int nk, const SymFunc& sym, const FoldFunc& if (zero_lhs && zero_rhs) continue; // coupling absent on both sides: consistent, but no constraint. if (zero_lhs != zero_rhs) - throw std::logic_error( - "solveOrbitalOpSignsFromH0: H0 magnitude mismatch for op " + std::to_string(s) + - " -- the band permutation is not a symmetry of H0 (a coupling vanishes on only one " - "side)."); + return false; // magnitude mismatch: this permutation is not a symmetry of H0. // Undress the fold before taking the ratio. phi lives at the image bands -- the rhs entry // sits at (image(b0), image(b1)) -- with G determined by (k, s); the stored table carries // the band as a free index, so the image-band lookup is direct. @@ -125,10 +116,7 @@ void solveSignsForOp(int s, int nb, int nk, const SymFunc& sym, const FoldFunc& const std::complex ratio = lhs / (fold * rhs); if (std::abs(std::imag(ratio)) > kSignRealTol || std::abs(std::abs(ratio) - 1.) > kSignRealTol) - throw std::domain_error( - "solveOrbitalOpSignsFromH0: H0 ratio is not a real +/-1 for op " + std::to_string(s) + - " -- the operation requires a non-signed-permutation U_S (genuine orbital mixing) or " - "is not a symmetry of H0."); + return false; // non-signed-permutation ratio: this permutation would need a dense U_S. constraints.push_back({b0, b1, std::real(ratio) > 0. ? 1 : -1}); } @@ -152,15 +140,44 @@ void solveSignsForOp(int s, int nb, int nk, const SymFunc& sym, const FoldFunc& break; } } - // No sign vector satisfied every constraint, so no signed permutation reproduces H0 under this op if (!found) - throw std::logic_error( - "solveOrbitalOpSignsFromH0: no consistent +/-1 signs for op " + std::to_string(s) + - " -- the H0 couplings admit no signed-permutation U_S."); + return false; // no sign vector reproduces H0 under this permutation. // Materialize U_S = D P one entry at a time: sign sigma(b) at (row b, column image[b]). for (int b = 0; b < nb; ++b) u_s(b, image[b], s) = static_cast(sigma[b]); + return true; +} + +// Derives op s's orbital operation U_S = D P from H0 -- both the permutation P and the signs D -- +// and writes it into u_s. H0 is the authority: U_S is whatever signed permutation makes +// H0(S k) = U_S H0(k) U_S^dagger hold. +template +void deriveOrbitalOpForOp(int s, int nb, int nk, const SymFunc& sym, const FoldFunc& fold_phase, + const H0Function& H0, UFunc& u_s) { + // The geometric image is the canonical candidate: verify it against H0 first. + std::vector geometric(nb); + for (int b = 0; b < nb; ++b) + geometric[b] = sym(0, b, s).second; + + if (tryPermutation(geometric, s, nb, nk, sym, fold_phase, H0, u_s)) + return; + + // H0 did not admit it; check the remaining permutations, in std::next_permutation order so the + // search is deterministic, skipping the geometric candidate already tried. + std::vector image(nb); + for (int b = 0; b < nb; ++b) + image[b] = b; + do { + if (image != geometric && tryPermutation(image, s, nb, nk, sym, fold_phase, H0, u_s)) + return; + } while (std::next_permutation(image.begin(), image.end())); + + throw std::logic_error( + "solveOrbitalOpSignsFromH0: no signed-permutation U_S reproduces H0 under op " + + std::to_string(s) + + " for any band permutation -- the operation needs a non-signed-permutation U_S (genuine " + "orbital mixing or a complex phase) or is not a symmetry of H0."); } } // namespace detail @@ -185,7 +202,7 @@ void solveOrbitalOpSignsFromH0(const H0Function& H0) { const int n_ops = SymDmn::dmn_size(); for (int s = 0; s < n_ops; ++s) - detail::solveSignsForOp(s, nb, nk, sym, fold_phase, H0, u_s); + detail::deriveOrbitalOpForOp(s, nb, nk, sym, fold_phase, H0, u_s); } // Returns the sorted op indices that pass the sign-consistency (H0-invariance) check -- the @@ -210,7 +227,7 @@ std::vector verifiedSymmetryOps(const H0Function& H0) { std::vector verified; for (int s = 0; s < n_ops; ++s) { try { - detail::solveSignsForOp(s, nb, nk, sym, fold_phase, H0, u_s); + detail::deriveOrbitalOpForOp(s, nb, nk, sym, fold_phase, H0, u_s); verified.push_back(s); } catch (const std::exception&) { diff --git a/test/integration/phys/symmetrization/CMakeLists.txt b/test/integration/phys/symmetrization/CMakeLists.txt index 7653c0dea..07d66c8a6 100644 --- a/test/integration/phys/symmetrization/CMakeLists.txt +++ b/test/integration/phys/symmetrization/CMakeLists.txt @@ -22,8 +22,8 @@ dca_add_gtest(symmetrize_characterization_threeband_D4_test TEST_DEFINES ThreebandD4 ) -# Regression case for solveSignsForOp's -1 guard: Kagome produces the -1 which the solver -# must reject instead of indexing H0 out of bounds. +# Regression case for deriveOrbitalOpForOp's -1 guard: Kagome produces the -1 which the solver +# must skip instead of indexing H0 out of bounds. dca_add_gtest(symmetrize_characterization_kagome_test FAST GTEST_MPI_MAIN @@ -33,6 +33,17 @@ dca_add_gtest(symmetrize_characterization_kagome_test TEST_DEFINES KagomeNoSym ) +# The motivating case for deriving P from H0: FeAs's two orbitals share a site, so the geometric +# band image is always the identity and half of D4 is recoverable only by searching for the swap. +dca_add_gtest(symmetrize_characterization_fe_as_test + FAST + GTEST_MPI_MAIN + INCLUDE_DIRS ${DCA_INCLUDES};${PROJECT_SOURCE_DIR};${FFTW_INCLUDE_DIR} + LIBS ${DCA_LIBS} + CUSTOM_SOURCE symmetrize_characterization_test.cpp + TEST_DEFINES FeAs + ) + dca_add_gtest(symmetrize_characterization_singleband_chain_test FAST GTEST_MPI_MAIN diff --git a/test/integration/phys/symmetrization/fe_as_input.json b/test/integration/phys/symmetrization/fe_as_input.json new file mode 100644 index 000000000..2be024ef7 --- /dev/null +++ b/test/integration/phys/symmetrization/fe_as_input.json @@ -0,0 +1,37 @@ +{ + "physics": { + "beta" : 1., + "chemical-potential" : 0. + }, + + "FeAs-model": + { + "t1" : -1., + "t2" : 1.3, + "t3" : -0.85, + "t4" : -0.85, + "U" : 4., + "V" : 2., + "J" : 0.5, + "Jp" : 0.5 + }, + + "domains": { + "real-space-grids": { + "cluster": [[4, 0], [0, 4]], + "sp-host": [[8, 0], [0, 8]] + }, + + "imaginary-time": { + "sp-time-intervals": 128 + }, + + "imaginary-frequency": { + "sp-fermionic-frequencies": 64 + } + }, + + "DCA": { + "interacting-orbitals": [0, 1] + } +} diff --git a/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp b/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp index 495ab4729..80d7f75b3 100644 --- a/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp +++ b/test/integration/phys/symmetrization/symmetrize_characterization_test.cpp @@ -64,6 +64,7 @@ #include "dca/phys/parameters/parameters.hpp" #include "dca/profiling/null_profiler.hpp" #include "dca/phys/models/analytic_hamiltonians/Kagome_hubbard.hpp" +#include "dca/phys/models/analytic_hamiltonians/fe_as_lattice.hpp" #include "dca/phys/models/analytic_hamiltonians/singleband_chain.hpp" #include "dca/phys/models/analytic_hamiltonians/square_lattice.hpp" #include "dca/phys/models/analytic_hamiltonians/threeband_hubbard.hpp" @@ -150,10 +151,10 @@ struct SinglebandChain { // CASE 4 -- Kagome lattice declared with no_symmetry<2>, mirroring the production // instantiation in test/unit/phys/dca_step/cluster_solver/test_setup.hpp. This is the -// regression case for solveSignsForOp's -1 guard: the hexagonal has the 12 D6 ops, -// but the orbital position+flavor matching in set_symmetry_matrices filters them all out, -// and records (-1, -1). The H0 sign solver must reject the ops instead of indexing H0 with -// band -1 (an OOB). +// regression case for deriveOrbitalOpForOp's -1 guard: the hexagonal has the 12 D6 ops, +// but the orbital position+flavor matching in set_symmetry_matrices filters them all out +// and records (-1, -1). Deriving P from H0 recovers all 12 -- the search skips the -1 +// candidate and finds the sublattice permutation geometry could not place. struct KagomeNoSym { using Scalar = double; using Lattice = dca::phys::models::KagomeHubbard>; @@ -163,7 +164,26 @@ struct KagomeNoSym { static std::vector expectedFailingKOps() { return {}; } static std::vector expectedFailingROps() { return {}; } static std::vector expectedUnverifiedKOps() { return {}; } - static constexpr int expected_num_derived_symmetries = 2; + static constexpr int expected_num_derived_symmetries = 12; +}; + +// CASE 5 -- FeAs (minimal two-band iron-pnictide model, PRB 77, 220503): the motivating case for +// deriving P from H0. Its two orbitals (d_xz, d_yz) share a site (a_vec = 0 for both), so +// position/flavor matching can only return the IDENTITY band image. But H0's two diagonals are the +// same dispersion with k_x and k_y exchanged, so the four D4 ops exchanging the axes (C4, C4^3, the +// two diagonal mirrors) are symmetries only with the band SWAP: geometry derives 4 ops, H0 all 8. +struct FeAs { + using Scalar = double; + // FeAsLattice ignores its template argument: it hardcodes FeAsPointGroup = {identity, C2}, the + // largest group the geometry-derived permutation could support. + using Lattice = dca::phys::models::FeAsLattice; + static constexpr char Input[] = "fe_as_input.json"; + static constexpr int expected_num_symmetries = 2; + static std::vector expectedFailingReps() { return {}; } + static std::vector expectedFailingKOps() { return {}; } + static std::vector expectedFailingROps() { return {}; } + static std::vector expectedUnverifiedKOps() { return {}; } + static constexpr int expected_num_derived_symmetries = 8; }; // Templated test fixture @@ -673,25 +693,21 @@ TYPED_TEST(SymmetrizeCharacterizationTest, PerOpMapRealSpace) { // TEST 8 (a/b/c/d): rejection fixtures for the sign-consistency solver. // -// solveOrbitalOpSignsFromH0 has four throw branches. No shipped model exercises any of the -// four on a correct H0 and a complete symmetry table -- the spine cases all pass -- so we -// perturb a copy of the (exactly symmetric) H0 (8a-8c), or the table itself (8d), to break one -// operation and assert the solver throws for the intended reason. +// solveOrbitalOpSignsFromH0 derives the permutation from H0, throwing only when no band +// permutation reproduces it. No shipped model triggers that on a correct H0 -- the spine cases all +// pass -- so we perturb a copy of the (exactly symmetric) H0 (8a-8c) to break one op past every +// permutation, or corrupt the table (8d) to show the search recovers what geometry cannot place. // // These need a multi-orbital model. A single band has no off-diagonal coupling to corrupt, // and on the spine's square cluster every nonzero single-band entry sits at a k that is a // fixed point of every op (the BZ center and corner), so no single-entry perturbation can // break a symmetry there. Threeband (d, px, py) is the driver; square and singleband skip. -// 8a/8b -- the two ways a single broken off-diagonal coupling is rejected. Both perturb the -// strongest off-diagonal H0 entry (and its Hermitian partner) so its symmetry image no longer -// matches, differing only in how: -// * vanish it (-> magnitude mismatch: a coupling present on one side of the relation but gone on -// the other, so the band permutation is no longer a symmetry of H0); -// * scale it by 1.5 (-> non-unit ratio: the H0 ratio that would fix the sign product is no longer -// a real +/-1, the signature of an op needing a non-signed-permutation U_S -- genuine orbital -// mixing -- or simply not a symmetry). -// They share everything but the perturbation, so they live in one test with two assertion blocks. +// 8a/8b -- two ways a single broken off-diagonal coupling breaks the op past any permutation. Both +// perturb the strongest off-diagonal H0 entry (and its Hermitian partner), differing only in how: +// * vanish it (a coupling present on one side of the relation but gone on the other); +// * scale it by 1.5 (the H0 ratio that would fix a sign product is no longer a real +/-1). +// Either way the search exhausts every permutation and throws the unified message. TYPED_TEST(SymmetrizeCharacterizationTest, RejectsBrokenOffDiagonalCoupling) { using Fixture = SymmetrizeCharacterizationTest; using KCluster = typename Fixture::KCluster; @@ -737,7 +753,7 @@ TYPED_TEST(SymmetrizeCharacterizationTest, RejectsBrokenOffDiagonalCoupling) { const std::string msg = captureThrowMessage([&] { dca::phys::solveOrbitalOpSignsFromH0(H0p); }); ASSERT_FALSE(msg.empty()) << "sign solver did not reject a vanished coupling."; - EXPECT_NE(msg.find("magnitude mismatch"), std::string::npos) << "actual: " << msg; + EXPECT_NE(msg.find("for any band permutation"), std::string::npos) << "actual: " << msg; } // Scale by 1.5: the entry stays nonzero but its ratio to the image is not +/-1. @@ -748,7 +764,7 @@ TYPED_TEST(SymmetrizeCharacterizationTest, RejectsBrokenOffDiagonalCoupling) { const std::string msg = captureThrowMessage([&] { dca::phys::solveOrbitalOpSignsFromH0(H0p); }); ASSERT_FALSE(msg.empty()) << "sign solver did not reject a non-unit coupling ratio."; - EXPECT_NE(msg.find("not a real"), std::string::npos) << "actual: " << msg; + EXPECT_NE(msg.find("for any band permutation"), std::string::npos) << "actual: " << msg; } } @@ -756,7 +772,8 @@ TYPED_TEST(SymmetrizeCharacterizationTest, RejectsBrokenOffDiagonalCoupling) { // jointly satisfied by any assignment. At the zone corner all three bands couple (d-px, d-py, // px-py), so the d-px and d-py signs force the px-py sign product, and a px<->py swap op // reads the px-py sign off H0 directly. Flipping one direction of the px-py coupling -// makes the direct reading contradict the forced product: no sign vector works. +// makes the direct reading contradict the forced product: no sign vector works -- and, because the +// flip is asymmetric, no other band permutation rescues it either, so the search still throws. TYPED_TEST(SymmetrizeCharacterizationTest, RejectsInconsistentSigns) { using Fixture = SymmetrizeCharacterizationTest; using KCluster = typename Fixture::KCluster; @@ -798,7 +815,7 @@ TYPED_TEST(SymmetrizeCharacterizationTest, RejectsInconsistentSigns) { const std::string msg = captureThrowMessage([&] { dca::phys::solveOrbitalOpSignsFromH0(H0p); }); ASSERT_FALSE(msg.empty()) << "sign solver did not reject an inconsistent sign system."; - EXPECT_NE(msg.find("no consistent"), std::string::npos) << "actual: " << msg; + EXPECT_NE(msg.find("for any band permutation"), std::string::npos) << "actual: " << msg; } // TEST 9: the folding phase must not be absorbed into U_S (PR #368 review). At a zone-boundary @@ -847,19 +864,18 @@ TEST(SolveOrbitalOpSigns, BoundaryFoldDoesNotMaskPxParity) { }; USTable u_s; - dca::phys::detail::solveSignsForOp(0, 3, 1, Sym{}, Fold{}, H0{}, u_s); + dca::phys::detail::deriveOrbitalOpForOp(0, 3, 1, Sym{}, Fold{}, H0{}, u_s); EXPECT_DOUBLE_EQ(u_s(0, 0, 0), 1.); EXPECT_DOUBLE_EQ(u_s(1, 1, 0), -1.); // The intrinsic p_x parity, not the fold-dressed +1. EXPECT_DOUBLE_EQ(u_s(2, 2, 0), 1.); } -// 8d -- missing band image: the geometric position/flavor matching in set_symmetry_matrices -// records -1 when it finds no admissible image, so the solver cannot assume a complete table. -// Unlike 8a-8c this perturbs the symmetry table, not H0: the whole-group populator must throw, -// and the non-throwing classifier must omit the op instead of indexing H0 with -1 (an OOB). The -// table is shared static state, so it gets restored. -TYPED_TEST(SymmetrizeCharacterizationTest, RejectsMissingBandImage) { +// 8d -- recovery from a missing band image: set_symmetry_matrices records -1 when its position/ +// flavor matching finds no admissible image. Unlike 8a-8c this perturbs the symmetry table, not H0: +// the solver skips the -1 candidate (no OOB) and recovers the op from the search, so the populator +// succeeds and the classifier still includes it. The table is static state, so it gets restored. +TYPED_TEST(SymmetrizeCharacterizationTest, RecoversFromMissingBandImage) { using Fixture = SymmetrizeCharacterizationTest; using KCluster = typename Fixture::KCluster; @@ -871,19 +887,17 @@ TYPED_TEST(SymmetrizeCharacterizationTest, RejectsMissingBandImage) { const int saved_image = sym(0, 0, s_target).second; sym(0, 0, s_target).second = -1; + // The populator must NOT throw: the -1 makes the geometric candidate inadmissible, but the search + // should continue const std::string msg = captureThrowMessage([&] { dca::phys::solveOrbitalOpSignsFromH0(this->H0_); }); const std::vector verified = dca::phys::verifiedSymmetryOps(this->H0_); sym(0, 0, s_target).second = saved_image; - ASSERT_FALSE(msg.empty()) << "sign solver did not reject a -1 sentinel band image."; - EXPECT_NE(msg.find("no band image"), std::string::npos) << "actual: " << msg; - - std::vector expected = baseline; - expected.erase(std::find(expected.begin(), expected.end(), s_target)); - EXPECT_EQ(verified, expected) - << "classifier did not cleanly omit (only) the op with the sentinel image."; + EXPECT_TRUE(msg.empty()) << "solver failed to recover from a -1 valued band image: " << msg; + EXPECT_EQ(verified, baseline) + << "the H0 search did not recover the op whose geometric band image was corrupted."; } } // namespace