├── .clang-format ├── .github ├── codecov.yml └── workflows │ └── test.yaml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake ├── AddGreenKernel.cmake └── GreenDeps.cmake ├── main.cpp ├── python ├── init_data_df.py ├── init_data_mol_df.py ├── migrate.py ├── plot_bands.py └── requirements.txt ├── src ├── CMakeLists.txt ├── dyson.cpp ├── gf2_solver.cpp ├── gf2_solver_t_ewald_correction.cpp ├── green │ └── mbpt │ │ ├── common_defs.h │ │ ├── common_utils.h │ │ ├── custom_kernels.h │ │ ├── df_integral_t.h │ │ ├── dyson.h │ │ ├── except.h │ │ ├── gf2_solver.h │ │ ├── gw_solver.h │ │ ├── hf_solver.h │ │ ├── kernel_factory.h │ │ ├── kernels.h │ │ ├── mbpt_q0_utils_t.h │ │ └── mbpt_run.h ├── gw_cpu_kernel.cpp ├── gw_solver.cpp ├── hf_cpu_kernels.cpp ├── hf_solver.cpp └── mbpt_q0_utils_t.cpp └── test ├── CMakeLists.txt ├── data ├── Dyson │ └── input.h5 ├── GF2 │ ├── data.h5 │ ├── data_e.h5 │ ├── df_hf_int │ │ ├── VQ_0.h5 │ │ └── meta.h5 │ ├── df_hf_int_e │ │ ├── VQ_0.h5 │ │ ├── df_ewald.h5 │ │ └── meta.h5 │ ├── df_hf_int_z │ │ ├── VQ_0.h5 │ │ ├── df_ewald.h5 │ │ └── meta.h5 │ ├── input.h5 │ └── input_e.h5 ├── GW │ ├── data.h5 │ ├── data_c.h5 │ ├── df_hf_int │ │ ├── AqQ.h5 │ │ ├── VQ_0.h5 │ │ └── meta.h5 │ ├── df_int │ │ ├── VQ_0.h5 │ │ └── meta.h5 │ └── input.h5 ├── GW_X2C │ ├── data.h5 │ ├── df_hf_int │ │ ├── VQ_0.h5 │ │ └── meta.h5 │ └── input.h5 ├── HF │ ├── data.h5 │ ├── df_hf_int │ │ ├── VQ_0.h5 │ │ └── meta.h5 │ ├── df_int │ │ ├── VQ_0.h5 │ │ └── meta.h5 │ └── input.h5 ├── HF_X2C │ ├── data.h5 │ ├── df_hf_int │ │ ├── VQ_0.h5 │ │ └── meta.h5 │ └── input.h5 └── Input │ ├── df_int │ ├── VQ_0.h5 │ └── meta.h5 │ ├── df_int_0.3.0 │ ├── VQ_0.h5 │ └── meta.h5 │ ├── df_int_x │ ├── VQ_0.h5 │ └── meta.h5 │ ├── df_int_y │ ├── VQ_0.h5 │ └── meta.h5 │ └── input.h5 ├── solvers_test.cpp └── tensor_test.h /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Google 3 | AccessModifierOffset: -2 4 | AlignAfterOpenBracket: Align 5 | AlignArrayOfStructures: Right 6 | AlignConsecutiveAssignments: AcrossEmptyLinesAndComments 7 | AlignConsecutiveBitFields: AcrossEmptyLinesAndComments 8 | AlignConsecutiveDeclarations: AcrossEmptyLinesAndComments 9 | AlignConsecutiveMacros: Consecutive 10 | AlignEscapedNewlines: Left 11 | AlignOperands: Align 12 | AlignTrailingComments: true 13 | AllowAllArgumentsOnNextLine: true 14 | AllowAllConstructorInitializersOnNextLine: true 15 | AllowAllParametersOfDeclarationOnNextLine: true 16 | AllowShortBlocksOnASingleLine: Never 17 | AllowShortCaseLabelsOnASingleLine: false 18 | AllowShortEnumsOnASingleLine: true 19 | AllowShortFunctionsOnASingleLine: All 20 | AllowShortIfStatementsOnASingleLine: WithoutElse 21 | AllowShortLambdasOnASingleLine: All 22 | AllowShortLoopsOnASingleLine: true 23 | AlwaysBreakAfterDefinitionReturnType: None 24 | AlwaysBreakAfterReturnType: None 25 | AlwaysBreakBeforeMultilineStrings: true 26 | AlwaysBreakTemplateDeclarations: Yes 27 | AttributeMacros: 28 | - __capability 29 | BinPackArguments: true 30 | BinPackParameters: true 31 | BitFieldColonSpacing: Both 32 | BraceWrapping: 33 | AfterCaseLabel: false 34 | AfterClass: false 35 | AfterControlStatement: Never 36 | AfterEnum: false 37 | AfterFunction: false 38 | AfterNamespace: false 39 | AfterObjCDeclaration: false 40 | AfterStruct: false 41 | AfterUnion: false 42 | AfterExternBlock: false 43 | BeforeCatch: false 44 | BeforeElse: false 45 | BeforeLambdaBody: false 46 | BeforeWhile: false 47 | IndentBraces: false 48 | SplitEmptyFunction: true 49 | SplitEmptyRecord: true 50 | SplitEmptyNamespace: true 51 | BreakAfterJavaFieldAnnotations: false 52 | BreakBeforeBinaryOperators: None 53 | BreakBeforeBraces: Attach 54 | BreakBeforeConceptDeclarations: true 55 | BreakBeforeTernaryOperators: true 56 | BreakConstructorInitializers: AfterColon 57 | BreakInheritanceList: AfterColon 58 | BreakStringLiterals: true 59 | ColumnLimit: 130 60 | CommentPragmas: "^ IWYU pragma:" 61 | CompactNamespaces: true 62 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 63 | ConstructorInitializerIndentWidth: 4 64 | ContinuationIndentWidth: 4 65 | Cpp11BracedListStyle: true 66 | DeriveLineEnding: true 67 | DerivePointerAlignment: false 68 | DisableFormat: false 69 | EmptyLineAfterAccessModifier: Never 70 | EmptyLineBeforeAccessModifier: LogicalBlock 71 | ExperimentalAutoDetectBinPacking: false 72 | FixNamespaceComments: true 73 | ForEachMacros: 74 | - foreach 75 | - Q_FOREACH 76 | - BOOST_FOREACH 77 | IfMacros: 78 | - KJ_IF_MAYBE 79 | IncludeBlocks: Regroup 80 | IncludeCategories: 81 | - Regex: ^ 82 | Priority: 2 83 | SortPriority: 0 84 | CaseSensitive: false 85 | - Regex: ^<.*\.h> 86 | Priority: 1 87 | SortPriority: 0 88 | CaseSensitive: false 89 | - Regex: ^<.* 90 | Priority: 2 91 | SortPriority: 0 92 | CaseSensitive: false 93 | - Regex: .* 94 | Priority: 3 95 | SortPriority: 0 96 | CaseSensitive: false 97 | IncludeIsMainRegex: ([-_](test|unittest))?$ 98 | IncludeIsMainSourceRegex: "" 99 | IndentAccessModifiers: false 100 | IndentCaseBlocks: false 101 | IndentCaseLabels: true 102 | IndentExternBlock: AfterExternBlock 103 | IndentGotoLabels: true 104 | IndentPPDirectives: None 105 | IndentRequires: false 106 | IndentWidth: 2 107 | IndentWrappedFunctionNames: false 108 | InsertTrailingCommas: None 109 | JavaScriptQuotes: Leave 110 | JavaScriptWrapImports: true 111 | KeepEmptyLinesAtTheStartOfBlocks: false 112 | LambdaBodyIndentation: Signature 113 | Language: Cpp 114 | MacroBlockBegin: "" 115 | MacroBlockEnd: "" 116 | MaxEmptyLinesToKeep: 1 117 | NamespaceIndentation: All 118 | ObjCBinPackProtocolList: Never 119 | ObjCBlockIndentWidth: 2 120 | ObjCBreakBeforeNestedBlockParam: true 121 | ObjCSpaceAfterProperty: false 122 | ObjCSpaceBeforeProtocolList: true 123 | PPIndentWidth: -1 124 | PackConstructorInitializers: NextLine 125 | PenaltyBreakAssignment: 2 126 | PenaltyBreakBeforeFirstCallParameter: 1 127 | PenaltyBreakComment: 300 128 | PenaltyBreakFirstLessLess: 120 129 | PenaltyBreakOpenParenthesis: 0 130 | PenaltyBreakString: 1000 131 | PenaltyBreakTemplateDeclaration: 10 132 | PenaltyExcessCharacter: 1000000 133 | PenaltyIndentedWhitespace: 0 134 | PenaltyReturnTypeOnItsOwnLine: 200 135 | PointerAlignment: Left 136 | QualifierAlignment: Leave 137 | RawStringFormats: 138 | - Language: Cpp 139 | Delimiters: 140 | - cc 141 | - CC 142 | - cpp 143 | - Cpp 144 | - CPP 145 | - c++ 146 | - C++ 147 | CanonicalDelimiter: "" 148 | BasedOnStyle: google 149 | - Language: TextProto 150 | Delimiters: 151 | - pb 152 | - PB 153 | - proto 154 | - PROTO 155 | EnclosingFunctions: 156 | - EqualsProto 157 | - EquivToProto 158 | - PARSE_PARTIAL_TEXT_PROTO 159 | - PARSE_TEST_PROTO 160 | - PARSE_TEXT_PROTO 161 | - ParseTextOrDie 162 | - ParseTextProtoOrDie 163 | - ParseTestProto 164 | - ParsePartialTestProto 165 | CanonicalDelimiter: pb 166 | BasedOnStyle: google 167 | ReferenceAlignment: Pointer 168 | ReflowComments: true 169 | RemoveBracesLLVM: false 170 | SeparateDefinitionBlocks: Leave 171 | ShortNamespaceLines: 1 172 | SortIncludes: CaseSensitive 173 | SortJavaStaticImport: Before 174 | SortUsingDeclarations: true 175 | SpaceAfterCStyleCast: false 176 | SpaceAfterLogicalNot: false 177 | SpaceAfterTemplateKeyword: true 178 | SpaceAroundPointerQualifiers: Default 179 | SpaceBeforeAssignmentOperators: true 180 | SpaceBeforeCaseColon: false 181 | SpaceBeforeCpp11BracedList: false 182 | SpaceBeforeCtorInitializerColon: true 183 | SpaceBeforeInheritanceColon: true 184 | SpaceBeforeParens: ControlStatements 185 | SpaceBeforeParensOptions: 186 | AfterControlStatements: true 187 | AfterForeachMacros: true 188 | AfterFunctionDeclarationName: false 189 | AfterFunctionDefinitionName: false 190 | AfterIfMacros: true 191 | AfterOverloadedOperator: false 192 | BeforeNonEmptyParentheses: false 193 | SpaceBeforeRangeBasedForLoopColon: true 194 | SpaceBeforeSquareBrackets: false 195 | SpaceInEmptyBlock: false 196 | SpaceInEmptyParentheses: false 197 | SpacesBeforeTrailingComments: 2 198 | SpacesInAngles: Never 199 | SpacesInCStyleCastParentheses: false 200 | SpacesInConditionalStatement: false 201 | SpacesInContainerLiterals: true 202 | SpacesInLineCommentPrefix: 203 | Minimum: 1 204 | Maximum: 1 205 | SpacesInParentheses: false 206 | SpacesInSquareBrackets: false 207 | Standard: c++17 208 | StatementAttributeLikeMacros: 209 | - Q_EMIT 210 | StatementMacros: 211 | - Q_UNUSED 212 | - QT_REQUIRE_VERSION 213 | TabWidth: 4 214 | UseCRLF: false 215 | UseTab: Never 216 | WhitespaceSensitiveMacros: 217 | - STRINGIZE 218 | - PP_STRINGIZE 219 | - BOOST_PP_STRINGIZE 220 | - NS_SWIFT_NAME 221 | - CF_SWIFT_NAME 222 | -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "test/*" -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | 12 | strategy: 13 | fail-fast: false 14 | 15 | runs-on: self-hosted 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - name: Build 21 | run: | 22 | module load BuildEnv/gcc-12.2.0.lua; 23 | mkdir -p build && cd build; 24 | cmake -DCMAKE_CXX_FLAGS=" --coverage -fno-inline -fno-inline-small-functions -fno-default-inline -fprofile-arcs -ftest-coverage " ..; 25 | make -j 8; 26 | 27 | - name: Test 28 | env: 29 | HDF5_USE_FILE_LOCKING: 'FALSE' 30 | OMP_NUM_THREADS: 1 31 | run: | 32 | module load BuildEnv/gcc-12.2.0.lua; 33 | cd build; 34 | ctest -j 1 35 | 36 | - name: Run coverage 37 | run: | 38 | module load BuildEnv/gcc-12.2.0.lua; 39 | cd build; 40 | lcov --capture --directory . --output-file coverage.info; 41 | lcov --remove coverage.info '/usr/*' --output-file coverage.info 42 | lcov --remove coverage.info '/opt/ohpc/pub/compiler/*' --output-file coverage.info 43 | lcov --remove coverage.info '*_deps*' --output-file coverage.info 44 | lcov --remove coverage.info '*libs*' --output-file coverage.info 45 | lcov --list coverage.info 46 | 47 | - name: Upload coverage reports to Codecov 48 | uses: codecov/codecov-action@v3 49 | with: 50 | flags: unittests 51 | env: 52 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build directories 2 | *build*/ 3 | 4 | # IDE directories 5 | .idea/* 6 | 7 | # Prerequisites 8 | *.d 9 | 10 | # Compiled Object files 11 | *.slo 12 | *.lo 13 | *.o 14 | *.obj 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Compiled Dynamic libraries 21 | *.so 22 | *.dylib 23 | *.dll 24 | 25 | # Fortran module files 26 | *.mod 27 | *.smod 28 | 29 | # Compiled Static libraries 30 | *.lai 31 | *.la 32 | *.a 33 | *.lib 34 | 35 | # Executables 36 | *.exe 37 | *.out 38 | *.app 39 | 40 | __pycache__ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | set(CMAKE_DISABLE_SOURCE_CHANGES ON) 3 | set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) 4 | project(mbpt) 5 | 6 | if (${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR}) 7 | message(FATAL_ERROR "In-source builds are not allowed") 8 | endif () 9 | 10 | ################ GREEN RELEASE VERSION ##################### 11 | set(GREEN_RELEASE origin/main) 12 | 13 | set(CMAKE_CXX_STANDARD 17) 14 | 15 | execute_process( 16 | COMMAND git log -1 --format=%h 17 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 18 | OUTPUT_VARIABLE TMP_HASH 19 | OUTPUT_STRIP_TRAILING_WHITESPACE 20 | ) 21 | set(GIT_HASH "${PROJECT_NAME}:${TMP_HASH}" CACHE INTERNAL "") 22 | 23 | 24 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) 25 | 26 | find_package(BLAS) 27 | if (BLAS_FOUND) 28 | if (BLAS_LIBRARIES MATCHES ".*Accelerate") 29 | message(INFO " Using Apple BLAS") 30 | endif () 31 | if (BLAS_LIBRARIES MATCHES ".*openblas") 32 | message(INFO " Using OpenBLAS") 33 | add_compile_definitions(USE_GEMM3M) 34 | endif () 35 | add_compile_definitions(EIGEN_USE_BLAS) 36 | endif () 37 | 38 | include(GreenDeps) 39 | 40 | add_green_dependency(green-grids) 41 | add_green_dependency(green-h5pp) 42 | add_green_dependency(green-ndarray) 43 | add_green_dependency(green-params) 44 | add_green_dependency(green-sc) 45 | add_green_dependency(green-symmetry) 46 | add_green_dependency(green-utils) 47 | 48 | if (CUSTOM_KERNELS) 49 | include(AddGreenKernel) 50 | add_green_kernel("${CUSTOM_KERNELS}") 51 | endif () 52 | 53 | add_subdirectory(src) 54 | add_library(GREEN::MBPT ALIAS mbpt) 55 | if (CUSTOM_KERNELS) 56 | list(LENGTH CUSTOM_KERNELS NUM_OF_KERNELS) 57 | list(LENGTH CUSTOM_KERNEL_ENUMS NUM_OF_ENUMS) 58 | list(LENGTH CUSTOM_KERNEL_HEADERS NUM_OF_HEADERS) 59 | list(LENGTH CUSTOM_KERNEL_NAMESPACES NUM_OF_NS) 60 | list(LENGTH CUSTOM_KERNEL_LIBS NUM_OF_LIBS) 61 | if( NOT ( ( ${NUM_OF_LIBS} EQUAL ${NUM_OF_ENUMS} ) 62 | AND ( ${NUM_OF_LIBS} EQUAL ${NUM_OF_NS} ) 63 | AND ( ${NUM_OF_LIBS} EQUAL ${NUM_OF_HEADERS} ) ) ) 64 | message(FATAL_ERROR "Inconsistent number of enums, libs, namespaces or headers!!!") 65 | endif() 66 | foreach(KERNEL_NUM RANGE ${NUM_OF_KERNELS}) 67 | math(EXPR BASE_1 "${KERNEL_NUM} + 1") 68 | list(GET CUSTOM_KERNEL_HEADERS ${KERNEL_NUM} HEADER) 69 | list(GET CUSTOM_KERNEL_ENUMS ${KERNEL_NUM} ENUM) 70 | list(GET CUSTOM_KERNEL_NAMESPACES ${KERNEL_NUM} NS) 71 | list(GET CUSTOM_KERNEL_LIBS ${KERNEL_NUM} LIB) 72 | if( "${ENUM}" STREQUAL "" ) 73 | break() 74 | endif() 75 | message(STATUS "KERNEL No. ${BASE_1}: ${HEADER} ${ENUM} ${NS} ${LIB}") 76 | target_compile_definitions(mbpt PUBLIC GREEN_CUSTOM_KERNEL_HEADER_${KERNEL_NUM}=${HEADER}) 77 | target_compile_definitions(mbpt PUBLIC GREEN_CUSTOM_KERNEL_ENUM_${KERNEL_NUM}=${ENUM}) 78 | target_compile_definitions(mbpt PUBLIC GREEN_CUSTOM_KERNEL_NS_${KERNEL_NUM}=${NS}) 79 | target_link_libraries(mbpt PUBLIC ${LIB}) 80 | endforeach() 81 | endif () 82 | 83 | add_executable(mbpt.exe main.cpp) 84 | target_link_libraries(mbpt.exe PUBLIC GREEN::MBPT) 85 | if (BLAS_FOUND) 86 | target_link_libraries(mbpt.exe PUBLIC BLAS::BLAS) 87 | endif (BLAS_FOUND) 88 | target_compile_definitions(mbpt.exe PRIVATE GIT_HASHES="${GIT_HASH}") 89 | 90 | option(Build_Tests "Build tests" ON) 91 | if (Build_Tests) 92 | enable_testing() 93 | add_subdirectory(test) 94 | endif () 95 | install(TARGETS mbpt.exe DESTINATION bin) 96 | install(DIRECTORY python DESTINATION . FILES_MATCHING PATTERN "*.py") -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Green-Phys 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GitHub license](https://img.shields.io/github/license/Green-Phys/green-mbpt?cacheSeconds=3600&color=informational&label=License)](./LICENSE) 2 | [![GitHub license](https://img.shields.io/badge/C%2B%2B-17-blue)](https://en.cppreference.com/w/cpp/compiler_support/17) 3 | [![DOI](https://zenodo.org/badge/699493450.svg)](https://zenodo.org/doi/10.5281/zenodo.10071545) 4 | 5 | ![grids](https://github.com/Green-Phys/green-mbpt/actions/workflows/test.yaml/badge.svg) 6 | [![codecov](https://codecov.io/gh/Green-Phys/green-mbpt/graph/badge.svg?token=ZHN38G4O5U)](https://codecov.io/gh/Green-Phys/green-mbpt) 7 | 8 | ``` 9 | █▀▀█ █▀▀█ █▀▀ █▀▀ █▀▀▄ 10 | █ ▄▄ █▄▄▀ █▀▀ █▀▀ █ █ 11 | █▄▄█ ▀ ▀▀ ▀▀▀ ▀▀▀ ▀ ▀ 12 | 13 | █ █ █▀▀ █▀▀█ █ █ █▀▀█ █▀▀█ █ █ █▀▀█ █ ▀ █▀▀▄ █▀▀▀ 14 | █ █ █ █▀▀ █▄▄█ █▀▄ ▀▀ █ █ █ █ █ █ █ █ ▀█▀ █ █ █ ▀█ 15 | █▄▀▄█ ▀▀▀ ▀ ▀ ▀ ▀ █▄▄█ ▀▀▀▀ ▀▀▀ █▀▀▀ ▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀▀ 16 | ``` 17 | *** 18 | 19 | `Green/WeakCoupling` is a weak-coupling perturbation expansion solver for real materials expressed in Gaussian Bloch orbitals 20 | 21 | ## Installation 22 | 23 | ### Dependencies 24 | 25 | `Green/WeakCoupling` has the following required external dependencies 26 | - HDF5 library version >= 1.10.2 27 | - Message Passing Interface >= 3.1 28 | - Eigen3 library >= 3.4.0 29 | - BLAS 30 | 31 | To build `Green/WeakCoupling` CMake version 3.18 or above is required 32 | 33 | `PySCF` interface requires 34 | - `PySCF` version >= 2.0 35 | - `numba` version >= 0.57 36 | 37 | ### Build and Install 38 | 39 | The following example will build, test and install `Green/WeakCoupling` to `/path/to/weakcoupling/install/dir` directory. 40 | 41 | ```ShellSession 42 | $ git clone https://github.com/Green-Phys/green-mbpt 43 | $ cd green-mbpt 44 | $ mkdir build && cd build 45 | $ cmake -DCMAKE_BUILD_TYPE=Release \ 46 | -DCMAKE_INSTALL_PREFIX=/path/to/weakcoupling/install/dir .. 47 | $ make 48 | $ make test 49 | $ make install 50 | ``` 51 | 52 | ## Basic usage 53 | 54 | ### Generate input data 55 | `Green/WeakCoupling` provides `PySCF` interface to generate input data and initial starting point through the `green-mbtools` Python package. 56 | 57 | To generate initial mean-field solution and one- and two-body integrals run: 58 | ```ShellSession 59 | python python/init_data_df.py --a --atom --nk --basis 60 | ``` 61 | 62 | To perform weak-coupling simulations, one have to call `mbpt.exe` executable located at the installation path in the `bin` subdirectory. 63 | Minimal parameters that are needed to run weak-coupling simulations are following: 64 | 65 | - `--BETA` inverse temperature 66 | - `--scf_type` type of self-consistent approximation, should be either `GW`, `GF2` or `HF` 67 | - `--grid_file` path to a file containing non-uniform grids, program will check three possible locations: 68 | - current directory or absolute path 69 | - `/share` 70 | - build directory of weak-coupling code 71 | 72 | Currently, we provide IR (`ir` subdirectory) and Chebyshev grids (`cheb` subdirectory) for nonuniform imaginary time representation. 73 | 74 | After succesful completetion results will be written to a file located at `--results_file` (by default set to `sim.h5`) 75 | To get information about other parameters and their default values call `mbpt.exe --help`. 76 | 77 | ## Acknowledgements 78 | 79 | This work is supported by the National Science Foundation under the award OAC-2310582 80 | -------------------------------------------------------------------------------- /cmake/AddGreenKernel.cmake: -------------------------------------------------------------------------------- 1 | 2 | function(add_green_kernel CUSTOM_KERNELS_IN) 3 | set(CUSTOM_KERNELS_TMP "${CUSTOM_KERNELS_IN}") 4 | set(CUSTOM_KERNELS_LST "") 5 | foreach(KERNEL ${CUSTOM_KERNELS_TMP}) 6 | string(REGEX MATCH "([^/]+)/?$" KERNEL_NAME ${KERNEL}) 7 | message("Adding kernel ${KERNEL_NAME} ${KERNEL}") 8 | if(NOT DEFINED KERNEL_NAME) 9 | message(FATAL_ERROR "Can not extract kernel name") 10 | endif() 11 | 12 | Include(FetchContent) 13 | 14 | FetchContent_Declare( 15 | ${KERNEL_NAME} 16 | GIT_REPOSITORY ${KERNEL} 17 | GIT_TAG ${GREEN_RELEASE} # or a later release 18 | ) 19 | 20 | FetchContent_MakeAvailable(${KERNEL_NAME}) 21 | list(APPEND CUSTOM_KERNELS_LST ${KERNEL}) 22 | endforeach() 23 | set(CUSTOM_KERNELS "${CUSTOM_KERNELS_LST}" PARENT_SCOPE) 24 | endfunction() 25 | -------------------------------------------------------------------------------- /cmake/GreenDeps.cmake: -------------------------------------------------------------------------------- 1 | 2 | function(add_green_dependency TARGET) 3 | Include(FetchContent) 4 | 5 | FetchContent_Declare( 6 | ${TARGET} 7 | GIT_REPOSITORY https://github.com/Green-Phys/${TARGET}.git 8 | GIT_TAG ${GREEN_RELEASE} # or a later release 9 | ) 10 | 11 | FetchContent_MakeAvailable(${TARGET}) 12 | endfunction() -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 University of Michigan 3 | * 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | template 12 | auto init_solver(const green::params::params p) {} 13 | 14 | int main(int argc, char** argv) { 15 | MPI_Init(&argc, &argv); 16 | green::utils::context; 17 | std::string hashes = std::string(GIT_HASHES); 18 | int pos; 19 | while ((pos = hashes.find("**")) != std::string::npos) hashes.replace(pos, 2, "\n"); 20 | std::string name = R"( 21 | █▀▀█ █▀▀█ █▀▀ █▀▀ █▀▀▄ 22 | █ ▄▄ █▄▄▀ █▀▀ █▀▀ █ █ 23 | █▄▄█ ▀ ▀▀ ▀▀▀ ▀▀▀ ▀ ▀ 24 | 25 | █ █ █▀▀ █▀▀█ █ █ █▀▀█ █▀▀█ █ █ █▀▀█ █ ▀ █▀▀▄ █▀▀▀ 26 | █ █ █ █▀▀ █▄▄█ █▀▄ ▀▀ █ █ █ █ █ █ █ █ ▀█▀ █ █ █ ▀█ 27 | █▄▀▄█ ▀▀▀ ▀ ▀ ▀ ▀ █▄▄█ ▀▀▀▀ ▀▀▀ █▀▀▀ ▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀▀)"; 28 | 29 | auto p = green::params::params( 30 | name + "\n\nMichigan Weak-Coupling Many-Body perturbation solver.\n\n=====================================\nGit hashes:\n" + 31 | hashes + "\n====================================="); 32 | green::sc::define_parameters(p); 33 | green::symmetry::define_parameters(p); 34 | green::grids::define_parameters(p); 35 | green::mbpt::define_parameters(p); 36 | 37 | if (!p.parse(argc, argv)) { 38 | if (!green::utils::context.global_rank) p.help(); 39 | MPI_Finalize(); 40 | return -1; 41 | } 42 | if (!green::utils::context.global_rank) p.print(); 43 | 44 | try { 45 | green::mbpt::check_input(p); 46 | green::sc::sc_loop sc(MPI_COMM_WORLD, p); 47 | green::mbpt::run(sc, p); 48 | } catch (std::exception& e) { 49 | std::cerr << "Error on node " << green::utils::context.global_rank << ": " << e.what() << std::endl; 50 | MPI_Abort(green::utils::context.global, -1); 51 | } 52 | 53 | MPI_Finalize(); 54 | return 0; 55 | } -------------------------------------------------------------------------------- /python/init_data_df.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import green_mbtools.mint as pymb 3 | 4 | logging.basicConfig(level=logging.INFO) 5 | 6 | pyscf_init = pymb.pyscf_pbc_init() 7 | 8 | if "init" in pyscf_init.args.job: 9 | pyscf_init.mean_field_input() 10 | if "sym_path" in pyscf_init.args.job: 11 | pyscf_init.evaluate_high_symmetry_path() 12 | if "ewald_corr" in pyscf_init.args.job: 13 | pyscf_init.compute_twobody_finitesize_correction() 14 | 15 | print("Done") 16 | -------------------------------------------------------------------------------- /python/init_data_mol_df.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import green_mbtools.mint as pymb 3 | 4 | logging.basicConfig(level=logging.INFO) 5 | 6 | pyscf_init = pymb.pyscf_mol_init() 7 | 8 | pyscf_init.mean_field_input() 9 | 10 | print("Done") 11 | -------------------------------------------------------------------------------- /python/migrate.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | 4 | import h5py 5 | 6 | def copy_input_data(old_input_file, new_input_file): 7 | ''' 8 | copy all existing data from old file into a new file 9 | both files have to be open 10 | Parameters 11 | ---------- 12 | old_input_file: old HDF5 file object 13 | new_input_file: new HDF5 file object 14 | ''' 15 | for key in old_input_file.keys(): 16 | old_input_file.copy(key, new_input_file) 17 | 18 | 19 | 20 | def pregreen_version_0_2_4(args): 21 | ''' 22 | Migrate data into version 0.2.4 23 | ''' 24 | old_input = None 25 | new_input = None 26 | old_meta = h5py.File(args.old_integral_path[0] + "/meta.h5", "r") 27 | 28 | if args.old_input_file != args.new_input_file: 29 | old_input = h5py.File(args.old_input_file, "r") 30 | new_input = h5py.File(args.new_input_file, "a") 31 | copy_input_data(old_input, new_input) 32 | else: 33 | new_input = h5py.File(args.new_input_file, "a") 34 | old_input = new_input 35 | 36 | # get shapes for spin and spin-orbits 37 | X = old_input["HF/S-k"][()] 38 | ns = X.shape[0] 39 | nk = X.shape[1] 40 | nso = X.shape[2] 41 | 42 | if not "params/ns" in new_input: 43 | new_input["params/ns"] = ns 44 | if not "params/nso" in new_input: 45 | new_input["params/nso"] = nso 46 | if not "grid/nk" in new_input: 47 | new_input["grid/nk"] = nk 48 | 49 | if not "/grid" in new_input : 50 | new_input.create_group("/grid") 51 | new_grid = new_input["/grid"] 52 | 53 | meta_dsets = ["conj_pairs_list", "kpair_idx", "kpair_irre_list", "num_kpair_stored", "trans_pairs_list"] 54 | if "/grid" in old_meta: 55 | for dset in meta_dsets: 56 | if dset in old_meta["/grid"].keys() and not dset in new_grid.keys(): 57 | old_meta["/grid"].copy(dset, new_grid) 58 | 59 | old_meta.close() 60 | for m in args.new_integral_path: 61 | if not os.path.exists(m): 62 | os.mkdir(m) 63 | meta = h5py.File(m + "/meta.h5", "a") 64 | meta.attrs[GREEN_VERSION] = "0.2.4" 65 | meta.close() 66 | 67 | new_input.attrs[GREEN_VERSION] = "0.2.4" 68 | new_input.close() 69 | old_input.close() 70 | 71 | 72 | GREEN_VERSION = "__green_version__" 73 | 74 | migration_map = { 75 | (("", ""), "0.2.4"): pregreen_version_0_2_4 76 | } 77 | 78 | parser = argparse.ArgumentParser(description="Migration util.") 79 | 80 | parser.add_argument("--old_input_file", type=str, required=True, help="Name of the input file for pre-Green codes") 81 | parser.add_argument("--old_integral_path", type=str, nargs="+", required=True, 82 | help="Path to a directory with density-fitted integrals for old code") 83 | parser.add_argument("--new_input_file", type=str, required=True, 84 | help="Name of the input file for Green weak-coupling code") 85 | parser.add_argument("--new_integral_path", type=str, nargs="+", required=True, 86 | help="Path to a directory with density-fitted integrals for new code") 87 | parser.add_argument("--version", type=str, required=True, help="version to migrate to") 88 | 89 | args = parser.parse_args() 90 | 91 | if not os.path.exists(args.old_input_file) or not os.path.isfile(args.old_input_file): 92 | print("pre-Green input file is not found") 93 | exit(-1) 94 | 95 | for m in args.old_integral_path: 96 | if not os.path.exists(m): 97 | print("previous version density-fitted integrals are not found") 98 | exit(-1) 99 | 100 | assert (len(args.old_integral_path) == len(args.new_integral_path)) 101 | 102 | old_input = h5py.File(args.old_input_file, "r") 103 | inp_version = "" 104 | if GREEN_VERSION in old_input.attrs: 105 | inp_version = old_input.attrs[GREEN_VERSION] 106 | old_input.close() 107 | 108 | old_meta_versions = [] 109 | for m in args.old_integral_path: 110 | old_meta = h5py.File(m + "/meta.h5", "r") 111 | version = "" 112 | if GREEN_VERSION in old_meta.attrs: 113 | version = old_meta.attrs[GREEN_VERSION] 114 | old_meta.close() 115 | old_meta_versions.append(version) 116 | 117 | # Check that all integrals have the same version 118 | assert (old_meta_versions.count(old_meta_versions[0]) == len(old_meta_versions)) 119 | 120 | v2 = inp_version if inp_version != '' else "undefined" 121 | v2 = old_meta_versions[0] if old_meta_versions[0] != '' else "undefined" 122 | 123 | print(f"old input file version is '{inp_version}', old integrals version " 124 | f"is '{v2}'") 125 | 126 | if not ((inp_version, old_meta_versions[0]), args.version) in migration_map: 127 | print(f"No migration between version {inp_version} and {args.version} has been defined") 128 | exit(0) 129 | 130 | migration_map[((inp_version, old_meta_versions[0]), args.version)](args) 131 | 132 | print(f"Migration to version {args.version} successfully finished") -------------------------------------------------------------------------------- /python/plot_bands.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import h5py 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | import os 6 | 7 | parser = argparse.ArgumentParser("Band-structure plotting") 8 | 9 | parser.add_argument("--input_file", type=str, required=True, help="Name of the file containing analytically continued data evaluated on high-symmetry path") 10 | parser.add_argument("--output_dir", type=str, required=True, help="Name of the directory to save band-strtructure plots") 11 | parser.add_argument("--e_min", type=float, default=-12.0, help="Lower bound of energy window (eV)") 12 | parser.add_argument("--e_max", type=float, default=12.0, help="Upper bound of energy window (eV)") 13 | 14 | args = parser.parse_args() 15 | 16 | with h5py.File(args.input_file, "r") as fff: 17 | if "G_tau_hs" not in fff : 18 | raise RuntimeError("Input file does not contain G_tau_hs group. Check your input data!!!") 19 | DOS = fff["G_tau_hs/data"][()] 20 | mesh = fff["G_tau_hs/mesh"][()] 21 | 22 | freqs = mesh 23 | print(DOS.shape) 24 | nomega=DOS.shape[0] 25 | nspin=DOS.shape[1] 26 | nk_again=DOS.shape[2] 27 | norb=DOS.shape[3] 28 | nk = nk_again 29 | KDOS = np.einsum("wski->skw", -DOS.imag/np.pi) 30 | 31 | x = np.where(KDOS < 0.0) 32 | print(KDOS[x]) 33 | KDOS[x] = 0.0 34 | 35 | if not os.path.isdir(args.output_dir): 36 | os.makedirs(args.output_dir) 37 | 38 | 39 | TXDOS =np.zeros([nomega,2]) 40 | for s in range(nspin): 41 | for k in range(nk): 42 | #writing spectral functions to text 43 | TXDOS[:,0]=freqs 44 | TXDOS[:,1]=KDOS[s,k,:] 45 | np.savetxt(args.output_dir+"/dos_spin"+str(s)+"_k"+str(k)+".txt",TXDOS) 46 | 47 | HartreeToEv = 27.211396641308 48 | freqs_limit=mesh*HartreeToEv 49 | mask=(freqs_limitargs.e_min) 50 | KDOS=KDOS[0,:,mask]*HartreeToEv 51 | freqs = freqs_limit[mask].real 52 | path=np.array(range(0,nk_again)) 53 | #plt.imshow(KDOS, aspect='auto', origin='lower', cmap='hot', extent=[path[0], path[-1], freqs_limit[mask][0], freqs_limit[mask][-1]]) 54 | z_max = np.abs(KDOS).max() 55 | plt.pcolormesh(path, freqs, KDOS, cmap='RdBu', vmin=0, vmax=z_max,linewidth=0,rasterized=True) 56 | 57 | #plt.colorbar() 58 | plt.xlabel('k-path') 59 | plt.ylabel('Frequency') 60 | plt.savefig(args.output_dir+"/bands.png") 61 | 62 | -------------------------------------------------------------------------------- /python/requirements.txt: -------------------------------------------------------------------------------- 1 | green-mbtools >= 0.2.1b0 2 | numba >= 0.58.0 3 | spglib >= 2.2.0 4 | ase >= 3.21.0 5 | matplotlib >=3.8.0 -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(mbpt-lib CXX) 2 | 3 | add_library(mbpt dyson.cpp hf_solver.cpp gw_solver.cpp gf2_solver.cpp gf2_solver_t_ewald_correction.cpp mbpt_q0_utils_t.cpp 4 | hf_cpu_kernels.cpp 5 | gw_cpu_kernel.cpp) 6 | target_include_directories(mbpt PUBLIC .) 7 | target_link_libraries(mbpt PUBLIC GREEN::PARAMS GREEN::H5PP GREEN::UTILS GREEN::NDARRAY GREEN::GRIDS GREEN::SYMMETRY GREEN::SC) -------------------------------------------------------------------------------- /src/dyson.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2022 University of Michigan. 3 | * 4 | */ 5 | 6 | #include "green/mbpt/dyson.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "green/mbpt/common_utils.h" 15 | #include "green/mbpt/except.h" 16 | 17 | namespace green::mbpt { 18 | 19 | template 20 | dyson::dyson(const params::params& p) : 21 | _ft(p), _bz_utils(p), _ncheb(_ft.sd().repn_fermi().ni()), _nts(_ft.sd().repn_fermi().nts()), 22 | _nw(_ft.sd().repn_fermi().nw()), _nk(_bz_utils.nk()), _ink(_bz_utils.ink()), _X2C(false), _mu(0.0), 23 | _const_density(p["const_density"]), _tol(p["tolerance"]), _verbose(p["verbose"]) { 24 | dtensor<5> S_k_tmp; 25 | dtensor<5> H_k_tmp; 26 | h5pp::archive in_file(p["input_file"]); 27 | in_file["HF/S-k"] >> S_k_tmp; 28 | in_file["HF/H-k"] >> H_k_tmp; 29 | in_file["HF/Energy_nuc"] >> _E_nuc; 30 | in_file["params/ns"] >> _ns; 31 | in_file["params/nso"] >> _nso; 32 | in_file["params/nao"] >> _nao; 33 | in_file["params/nel_cell"] >> _nel; 34 | in_file.close(); 35 | _X2C = _nso == 2 * _nao; 36 | std::array shape; 37 | std::copy(S_k_tmp.shape().begin(), S_k_tmp.shape().end() - 1, shape.begin()); 38 | _S_k.resize(_ns, _ink, _nso, _nso); 39 | _H_k.resize(_ns, _ink, _nso, _nso); 40 | for (size_t is = 0; is < _ns; ++is) { 41 | _S_k(is) << _bz_utils.full_to_ibz(S_k_tmp.view>().reshape(shape)(is)); 42 | _H_k(is) << _bz_utils.full_to_ibz(H_k_tmp.view>().reshape(shape)(is)); 43 | } 44 | make_hermitian(_S_k); 45 | make_hermitian(_H_k); 46 | } 47 | 48 | template 49 | void dyson::selfenergy_eigenspectra(const Sigma1& sigma1, const Sigma_tau& sigma_tau_s, 50 | std::vector>& eigenvalues_Sigma_p_F) const { 51 | const ztensor<5>& sigma_tau = extract_local(sigma_tau_s); 52 | ztensor<2> X_k(_nso, _nso); 53 | ztensor<2> Sigma_w(_nso, _nso); 54 | size_t batch_number = 0; 55 | Eigen::ComplexEigenSolver solver(_nso); 56 | // iterate over all matsubara frequencies 57 | for (size_t iwsk = utils::context.global_rank; iwsk < _nw * _ns * _ink; iwsk += utils::context.global_size) { 58 | size_t iw = iwsk / (_ns * _ink); 59 | size_t is = (iwsk % (_ns * _ink)) / _ink; 60 | size_t ik = iwsk % _ink; 61 | _ft.tau_to_omega_wsk(sigma_tau, Sigma_w, iw, is, ik, 1); 62 | X_k = _H_k(is, ik) + sigma1(is, ik) + Sigma_w; 63 | MatrixXcd S_k_inv = matrix(_S_k(is, ik)).inverse().eval(); 64 | column ev = solver.compute(S_k_inv * matrix(X_k), false).eigenvalues(); 65 | // store eigenvalues for each frequency and k-point 66 | for (size_t i = 0; i < _nso; ++i) { 67 | eigenvalues_Sigma_p_F.push_back(ev(i, 0)); 68 | } 69 | } 70 | } 71 | 72 | template 73 | double dyson::compute_number_of_electrons(double mu, 74 | const std::vector>& eigenvalues_Sigma_p_F) const { 75 | // Get density matrix for given mu 76 | MatrixXcd TtBn = _ft.Ttn().block(_nts - 1, 0, 1, _nw); 77 | double nel = 0.0; 78 | MatrixXcd trace_w(_nw, 1); 79 | MatrixXcd trace_t(1, 1); 80 | std::complex muomega; 81 | trace_w = MatrixXcd::Zero(_nw, 1); 82 | for (size_t iwsk = utils::context.global_rank, iii = 0; iwsk < _nw * _ns * _ink; iwsk += utils::context.global_size) { 83 | size_t iw = iwsk / (_ns * _ink); 84 | size_t is = (iwsk % (_ns * _ink)) / _ink; 85 | size_t ik = (iwsk % _ink); 86 | size_t k_ir = _bz_utils.symmetry().full_point(ik); 87 | muomega = _ft.wsample_fermi()(iw) * 1.0i + mu; 88 | // Trace over AO index 89 | for (size_t i = 0; i < _nso; ++i, ++iii) { 90 | trace_w(iw, 0) += _bz_utils.nkpw() * _bz_utils.symmetry().weight()[k_ir] / (muomega - eigenvalues_Sigma_p_F[iii]); 91 | } 92 | } 93 | // Transform to tau 94 | trace_t = TtBn * trace_w; 95 | int prefactor = (_ns == 2 or _X2C) ? 1 : 2; 96 | nel += prefactor * -trace_t(0, 0).real(); 97 | MPI_Allreduce(MPI_IN_PLACE, &nel, 1, MPI_DOUBLE, MPI_SUM, utils::context.global); 98 | return nel; 99 | } 100 | 101 | template 102 | std::pair dyson::find_mu(const Sigma1& sigma1, const Sigma_tau& sigma_tau_s) const { 103 | double mu = _mu; 104 | double nel, nel1, nel2, nel_old; 105 | double mu1; 106 | double mu2; 107 | double delta = 0.5; 108 | utils::timing& t = utils::timing::get_instance(); 109 | t.start("Chemical potential search"); 110 | 111 | std::stringstream ss; 112 | ss << std::scientific << std::setprecision(15); 113 | mu = _mu; 114 | std::vector> eigenvalues_Sigma_p_F; 115 | selfenergy_eigenspectra(sigma1, sigma_tau_s, eigenvalues_Sigma_p_F); 116 | // Start search for the chemical potential 117 | nel = compute_number_of_electrons(mu, eigenvalues_Sigma_p_F); 118 | if (!utils::context.global_rank && _verbose != 0) ss << "nel:" << nel << " mu: " << mu << " target nel:" << _nel << std::endl; 119 | 120 | if (std::abs((nel - _nel) / double(_nel)) > _tol) { 121 | if (nel > _nel) { 122 | mu1 = mu - delta; 123 | double d = delta; 124 | do { 125 | nel1 = compute_number_of_electrons(mu1, eigenvalues_Sigma_p_F); 126 | if (!utils::context.global_rank && _verbose != 0) ss << "nel:" << nel1 << " mu: " << mu1 << std::endl; 127 | mu1 -= d; 128 | } while (nel1 > _nel); 129 | mu2 = mu; 130 | nel2 = nel; 131 | } else { 132 | mu2 = mu + delta; 133 | double d = delta; 134 | do { 135 | nel2 = compute_number_of_electrons(mu2, eigenvalues_Sigma_p_F); 136 | if (!utils::context.global_rank && _verbose != 0) ss << "nel:" << nel2 << " mu: " << mu2 << std::endl; 137 | mu2 += d; 138 | } while (nel2 < _nel); 139 | mu1 = mu; 140 | nel1 = nel; 141 | } 142 | if (!utils::context.global_rank && _verbose != 0) { 143 | std::cout << ss.str() << std::flush; 144 | ss.str(""); 145 | } 146 | while (std::abs((nel - _nel) / double(_nel)) > _tol && std::abs(mu2 - mu1) > 0.01 * _tol) { 147 | mu = (mu1 + mu2) * 0.5; 148 | nel_old = compute_number_of_electrons(mu, eigenvalues_Sigma_p_F); 149 | // check if we get stuck in chemical potential search 150 | if (std::abs((nel_old - _nel) / double(_nel)) > _tol && std::abs(nel - nel_old) < 0.001 * _tol) { 151 | throw mbpt_chemical_potential_search_failure("Chemical potential search failed."); 152 | } 153 | nel = nel_old; 154 | if (nel > _nel) { 155 | mu2 = mu; 156 | } else { 157 | mu1 = mu; 158 | } 159 | if (!utils::context.global_rank && _verbose != 0) ss << "nel:" << nel << " mu: " << mu << std::endl; 160 | if (!utils::context.global_rank && _verbose != 0) { 161 | std::cout << ss.str() << std::flush; 162 | ss.str(""); 163 | } 164 | } 165 | } 166 | if (!utils::context.global_rank) { 167 | ss << std::right << std::setw(36) << "New chemical potential, μ = " << std::setw(22) << std::right << mu << std::endl; 168 | ss << std::right << std::setw(37) << "Chemical potential difference Δμ = " << std::setw(22) << std::right 169 | << std::abs(mu - _mu) << std::endl; 170 | } 171 | t.end(); 172 | std::cout << ss.str(); 173 | return {nel, mu}; 174 | } 175 | 176 | template <> 177 | void dyson>, ztensor<4>, utils::shared_object>>::compute_G( 178 | G& g_tau_s, Sigma1& sigma1, Sigma_tau& sigma_tau_s) const { 179 | // Get G(tau) 180 | auto& g_tau = g_tau_s.object(); 181 | auto& sigma_tau = sigma_tau_s.object(); 182 | MPI_Datatype dt_matrix = utils::create_matrix_datatype>(_nso * _nso); 183 | MPI_Op matrix_sum_op = utils::create_matrix_operation>(); 184 | ztensor<3> G_t(_nts, _nso, _nso); 185 | ztensor<3> G_c(1, _nso, _nso); 186 | ztensor<3> G_w(_nw, _nso, _nso); 187 | ztensor<3> Sigma_w(_nw, _nso, _nso); 188 | ztensor<3> Sigma_k(_nts, _nso, _nso); 189 | Eigen::FullPivLU lusolver(_nso, _nso); 190 | g_tau_s.fence(); 191 | if (!utils::context.node_rank) g_tau.set_zero(); 192 | double coeff_last = 0.0; 193 | double coeff_first = 0.0; 194 | g_tau_s.fence(); 195 | g_tau_s.fence(); 196 | make_hermitian(sigma1); 197 | sigma_tau_s.fence(); 198 | if (!utils::context.node_rank) make_hermitian(sigma_tau_s.object()); 199 | sigma_tau_s.fence(); 200 | for (int isk = utils::context.global_rank; isk < _ns * _ink; isk += utils::context.global_size) { 201 | int is = isk / _ink; 202 | int ik = isk % _ink; 203 | Sigma_k.set_zero(); 204 | for (int it = 0; it < _nts; ++it) matrix(Sigma_k(it)) = matrix(sigma_tau(it, is, ik)); 205 | _ft.tau_to_omega(Sigma_k, Sigma_w, 1); 206 | for (int ic = 0; ic < _nw; ++ic) { 207 | std::complex muomega = _ft.wsample_fermi()(ic) * 1.0i + _mu; 208 | matrix(G_w(ic)) = muomega * matrix(_S_k(is, ik)) - matrix(_H_k(is, ik)) - matrix(sigma1(is, ik)) - matrix(Sigma_w(ic)); 209 | matrix(G_w(ic)) = lusolver.compute(matrix(G_w(ic))).inverse().eval(); 210 | } 211 | 212 | // Transform back to tau 213 | _ft.omega_to_tau(G_w, G_t, 1); 214 | 215 | for (int it = 0; it < _nts; ++it) { 216 | matrix(g_tau(it, is, ik)) = matrix(G_t(it)); 217 | } 218 | // Check Chebyshev 219 | _ft.tau_to_chebyshev_c(G_t, G_c, _ncheb - 1, 1); 220 | coeff_last = std::max(matrix(G_c(0)).cwiseAbs().maxCoeff(), coeff_last); 221 | _ft.tau_to_chebyshev_c(G_t, G_c, 0, 1); 222 | coeff_first = std::max(matrix(G_c(0)).cwiseAbs().maxCoeff(), coeff_first); 223 | } 224 | g_tau_s.fence(); 225 | g_tau_s.fence(); 226 | if (!utils::context.node_rank) { 227 | utils::allreduce(MPI_IN_PLACE, g_tau.data(), g_tau.size() / (_nso * _nso), dt_matrix, matrix_sum_op, 228 | utils::context.internode_comm); 229 | } 230 | g_tau_s.fence(); 231 | double leakage = coeff_last / coeff_first; 232 | if (!utils::context.global_rank) std::cout << "Leakage of Dyson G: " << leakage << std::endl; 233 | if (!utils::context.global_rank and leakage > 1e-8) std::cerr << "WARNING: The leakage is larger than 1e-8" << std::endl; 234 | MPI_Type_free(&dt_matrix); 235 | MPI_Op_free(&matrix_sum_op); 236 | } 237 | 238 | template <> 239 | void dyson, ztensor<4>, ztensor<5>>::compute_G(G& g_tau, Sigma1& sigma1, Sigma_tau& sigma_tau) const { 240 | // Get G(tau) 241 | MPI_Datatype dt_matrix = utils::create_matrix_datatype>(_nso * _nso); 242 | MPI_Op matrix_sum_op = utils::create_matrix_operation>(); 243 | ztensor<3> G_t(_nts, _nso, _nso); 244 | ztensor<3> G_c(1, _nso, _nso); 245 | ztensor<3> G_w(_nw, _nso, _nso); 246 | ztensor<3> Sigma_w(_nw, _nso, _nso); 247 | ztensor<3> Sigma_k(_nts, _nso, _nso); 248 | Eigen::FullPivLU lusolver(_nso, _nso); 249 | if (!utils::context.node_rank) g_tau.set_zero(); 250 | double coeff_last = 0.0; 251 | double coeff_first = 0.0; 252 | for (int isk = utils::context.global_rank; isk < _ns * _ink; isk += utils::context.global_size) { 253 | int is = isk / _ink; 254 | int ik = isk % _ink; 255 | Sigma_k.set_zero(); 256 | // G_w.set_zero(); 257 | for (int it = 0; it < _nts; ++it) matrix(Sigma_k(it)) = matrix(sigma_tau(it, is, ik)); 258 | _ft.tau_to_omega(Sigma_k, Sigma_w, 1); 259 | for (int ic = 0; ic < _nw; ++ic) { 260 | std::complex muomega = _ft.wsample_fermi()(ic) * 1.0i + _mu; 261 | matrix(G_w(ic)) = muomega * matrix(_S_k(is, ik)) - matrix(_H_k(is, ik)) - matrix(sigma1(is, ik)) - matrix(Sigma_w(ic)); 262 | matrix(G_w(ic)) = lusolver.compute(matrix(G_w(ic))).inverse().eval(); 263 | // G_w(ic).matrix() = G_w(ic).matrix().inverse(); 264 | } 265 | 266 | // Transform back to tau 267 | _ft.omega_to_tau(G_w, G_t, 1); 268 | 269 | // Eigen::ComplexEigenSolver solver(_nso); 270 | for (int it = 0; it < _nts; ++it) { 271 | matrix(g_tau(it, is, ik)) = matrix(G_t(it)); 272 | } 273 | // Check Chebyshev 274 | _ft.tau_to_chebyshev_c(G_t, G_c, _ncheb - 1, 1); 275 | coeff_last = std::max(matrix(G_c(0)).cwiseAbs().maxCoeff(), coeff_last); 276 | _ft.tau_to_chebyshev_c(G_t, G_c, 0, 1); 277 | coeff_first = std::max(matrix(G_c(0)).cwiseAbs().maxCoeff(), coeff_first); 278 | } 279 | if (!utils::context.node_rank) { 280 | utils::allreduce(MPI_IN_PLACE, g_tau.data(), g_tau.size() / (_nso * _nso), dt_matrix, matrix_sum_op, 281 | utils::context.internode_comm); 282 | } 283 | double leakage = coeff_last / coeff_first; 284 | if (!utils::context.global_rank) std::cout << "Leakage of Dyson G: " << leakage << std::endl; 285 | if (!utils::context.global_rank and leakage > 1e-8) std::cerr << "WARNING: The leakage is larger than 1e-8" << std::endl; 286 | MPI_Type_free(&dt_matrix); 287 | MPI_Op_free(&matrix_sum_op); 288 | } 289 | 290 | template <> 291 | double dyson>, ztensor<4>, utils::shared_object>>::diff(G& g, Sigma1& sigma1, 292 | Sigma_tau& sigma_tau) { 293 | compute_G(g, sigma1, sigma_tau); 294 | auto [e1, e2, e3] = compute_energy(g.object(), sigma1, sigma_tau.object(), _H_k, _ft, _bz_utils, _nao != _nso); 295 | double diff = std::abs(_E_1b - e1) + std::abs(_E_hf - e2) + std::abs(_E_corr - e3); 296 | _E_1b = e1; 297 | _E_hf = e2; 298 | _E_corr = e3; 299 | return diff; 300 | } 301 | 302 | template <> 303 | double dyson, ztensor<4>, ztensor<5>>::diff(G& g, Sigma1& sigma1, Sigma_tau& sigma_tau) { 304 | compute_G(g, sigma1, sigma_tau); 305 | auto [e1, e2, e3] = compute_energy(g, sigma1, sigma_tau, _H_k, _ft, _bz_utils, _nao != _nso); 306 | double diff = std::abs(_E_1b - e1) + std::abs(_E_hf - e2) + std::abs(_E_corr - e3); 307 | _E_1b = e1; 308 | _E_hf = e2; 309 | _E_corr = e3; 310 | return diff; 311 | } 312 | 313 | template 314 | void dyson::solve(G& g, Sigma1& sigma1, Sigma_tau& sigma_tau) { 315 | if (_const_density) { 316 | std::tie(_nel_found, _mu) = find_mu(sigma1, sigma_tau); 317 | } 318 | compute_G(g, sigma1, sigma_tau); 319 | } 320 | 321 | template 322 | void dyson::dump_iteration(size_t iter, const G& gtau, const S1&, const St&, const std::string& result_file) { 323 | if (!utils::context.global_rank) { 324 | h5pp::archive ar(result_file, "a"); 325 | ar["iter" + std::to_string(iter) + "/G_tau/mesh"] << _ft.sd().repn_fermi().tsample(); 326 | ar["iter" + std::to_string(iter) + "/Selfenergy/mesh"] << _ft.sd().repn_fermi().tsample(); 327 | ar["iter" + std::to_string(iter) + "/Energy_1b"] << _E_1b; 328 | ar["iter" + std::to_string(iter) + "/Energy_HF"] << _E_hf + _E_nuc; 329 | ar["iter" + std::to_string(iter) + "/Energy_2b"] << _E_corr; 330 | ar["iter" + std::to_string(iter) + "/mu"] << _mu; 331 | ar.close(); 332 | std::stringstream ss; 333 | ss << std::scientific << std::setprecision(15); 334 | ss << std::setw(35) << "One-body Energy: " << std::setw(17) << std::right << _E_1b << std::endl; 335 | ss << std::setw(35) << "HF Energy: " << std::setw(17) << std::right << _E_hf + _E_nuc << std::endl; 336 | ss << std::setw(35) << "Correlation Energy: " << std::setw(17) << std::right << _E_corr << std::endl; 337 | ss << std::setw(35) << "Total Energy: " << std::setw(17) << std::right << _E_hf + _E_nuc + _E_corr << std::endl; 338 | std::cout << ss.str(); 339 | print_convergence(iter, gtau, result_file); 340 | } 341 | } 342 | 343 | template 344 | void dyson::print_convergence(size_t iter, const G& gtau, const std::string& result_file) { 345 | double e1, ehf, e2b, mu; 346 | double e1_1 = 0, ehf_1 = 0, e2b_1 = 0, mu_1 = 0; 347 | h5pp::archive ar(result_file, "r"); 348 | S1 gam; 349 | std::vector new_shape(4); 350 | if constexpr (std::is_same_v>) { 351 | std::copy(gtau.shape().begin()+1, gtau.shape().end(), new_shape.begin()); 352 | gam.resize(new_shape); 353 | gam << gtau(gtau.shape()[0] - 1); 354 | } else if constexpr (std::is_same_v>>) { 355 | const auto & gtau_o = gtau.object(); 356 | std::copy(gtau_o.shape().begin()+1, gtau_o.shape().end(), new_shape.begin()); 357 | gam.resize(new_shape); 358 | gam << gtau_o(gtau_o.shape()[0] - 1); 359 | } 360 | if (!ar.has_group("iter" + std::to_string(iter))) { 361 | return; 362 | } 363 | if (ar.has_group("iter" + std::to_string(iter - 1))) { 364 | ar["iter" + std::to_string(iter - 1) + "/Energy_1b"] >> e1_1; 365 | ar["iter" + std::to_string(iter - 1) + "/Energy_HF"] >> ehf_1; 366 | ar["iter" + std::to_string(iter - 1) + "/Energy_2b"] >> e2b_1; 367 | ar["iter" + std::to_string(iter - 1) + "/mu"] >> mu_1; 368 | { 369 | ztensor<5> g_tmp; 370 | ar["iter" + std::to_string(iter - 1) + "/G_tau/data"] >> g_tmp; 371 | gam -= g_tmp(g_tmp.shape()[0] - 1); 372 | } 373 | } 374 | ar["iter" + std::to_string(iter) + "/Energy_1b"] >> e1; 375 | ar["iter" + std::to_string(iter) + "/Energy_HF"] >> ehf; 376 | ar["iter" + std::to_string(iter) + "/Energy_2b"] >> e2b; 377 | ar["iter" + std::to_string(iter) + "/mu"] >> mu; 378 | ar.close(); 379 | double dg = std::sqrt(std::transform_reduce(gam.begin(), gam.end(), std::complex(0.0), std::plus{}, 380 | [](const std::complex& a) { return a * std::conj(a); }) 381 | .real()) / 382 | gam.size(); 383 | 384 | std::stringstream ss; 385 | ss << "====================================================================================" << std::endl; 386 | ss << std::scientific << std::setprecision(15); 387 | ss << std::setw(28) << std::right << "|ΔE_tot|" << std::setw(23) << std::right << "|Δμ|" << std::setw(26) << std::right 388 | << "|Δγ|" << std::endl; 389 | ss << "Convergence: " << std::abs(+ehf + e2b - ehf_1 - e2b_1) << " " << std::abs(mu - mu_1) << " " << dg << std::endl; 390 | ss << std::endl; 391 | std::cout << ss.str(); 392 | } 393 | 394 | template class dyson>, ztensor<4>, utils::shared_object>>; 395 | template class dyson, ztensor<4>, ztensor<5>>; 396 | } // namespace green::mbpt 397 | -------------------------------------------------------------------------------- /src/gf2_solver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 University of Michigan 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 5 | * software and associated documentation files (the “Software”), to deal in the Software 6 | * without restriction, including without limitation the rights to use, copy, modify, 7 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so, subject to the following 9 | * conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all copies or 12 | * substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #include "green/mbpt/gf2_solver.h" 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace green::mbpt { 32 | void gf2_solver::solve(G_type& g_tau, S1_type& sigma1, St_type& sigma_tau) { 33 | _G_k1_tmp.resize(_nao, _nao); 34 | _Gb_k2_tmp.resize(_nao, _nao); 35 | _G_k3_tmp.resize(_nao, _nao); 36 | vijkl.resize(_nao, _nao, _nao, _nao); 37 | vcijkl.resize(_nao, _nao, _nao, _nao); 38 | vxijkl.resize(_nao, _nao, _nao, _nao); 39 | vxcijkl.resize(_nao, _nao, _nao, _nao); 40 | // 41 | MPI_Datatype dt_matrix = utils::create_matrix_datatype>(_nso * _nso); 42 | MPI_Op matrix_sum_op = utils::create_matrix_operation>(); 43 | _coul_int_c_1 = new df_integral_t(_path, _nao, _NQ, _bz_utils); 44 | _coul_int_c_2 = new df_integral_t(_path, _nao, _NQ, _bz_utils); 45 | _coul_int_c_3 = new df_integral_t(_path, _nao, _NQ, _bz_utils); 46 | _coul_int_c_4 = new df_integral_t(_path, _nao, _NQ, _bz_utils); 47 | _coul_int_x_3 = new df_integral_t(_path, _nao, _NQ, _bz_utils); 48 | _coul_int_x_4 = new df_integral_t(_path, _nao, _NQ, _bz_utils); 49 | auto& Sigma_tau = sigma_tau.object(); 50 | // clean self_energy array 51 | Sigma_local = Sigma_tau; 52 | sigma_tau.fence(); 53 | if (!utils::context.node_rank) Sigma_tau.set_zero(); 54 | sigma_tau.fence(); 55 | statistics.start("GF2 total"); 56 | auto [ntau_local, tau_offset] = compute_local_and_offset_node_comm(_nts); 57 | // start main loop 58 | MPI_Win_lock_all(MPI_MODE_NOCHECK, sigma_tau.win()); 59 | for (size_t k1k3k2 = utils::context.internode_rank; k1k3k2 < _nk * _nk * _ink; k1k3k2 += utils::context.internode_size) { 60 | size_t k1_pos = k1k3k2 / (_nk * _nk); 61 | // Link the reduce index (k1_pos) to corresponding momentum 62 | size_t k1_red = _bz_utils.symmetry().full_point(k1_pos); 63 | size_t k3 = (k1k3k2 / _nk) % _nk; 64 | size_t k2 = k1k3k2 % _nk; 65 | std::array k = _bz_utils.momentum_conservation({k1_red, k2, k3}); 66 | statistics.start("read"); 67 | // read next part of integrals 68 | read_next(k); 69 | statistics.end(); 70 | statistics.start("setup"); 71 | setup_integrals(k); 72 | statistics.end(); 73 | for (size_t is = 0; is < _ns; ++is) { 74 | selfenergy_innerloop(tau_offset, ntau_local, k, is, g_tau.object()); 75 | } 76 | } 77 | statistics.start("correction"); 78 | if (_ewald) { 79 | if (!utils::context.global_rank) std::cout << "Correction for selfenergy" << std::endl; 80 | compute_2nd_exch_correction(tau_offset, ntau_local, g_tau.object()); 81 | } 82 | statistics.end(); 83 | MPI_Win_sync(sigma_tau.win()); 84 | MPI_Barrier(utils::context.node_comm); 85 | MPI_Win_unlock_all(sigma_tau.win()); 86 | MPI_Barrier(utils::context.global); 87 | 88 | statistics.start("reduce"); 89 | // // collect data within a node 90 | // MPI_Win_lock(MPI_LOCK_EXCLUSIVE, 0, 0, sigma_tau.win()); 91 | // Sigma_tau += Sigma_local; 92 | // MPI_Win_unlock(0, sigma_tau.win()); 93 | // collect data among nodes 94 | sigma_tau.fence(); 95 | if (!utils::context.node_rank) { 96 | utils::allreduce(MPI_IN_PLACE, Sigma_tau.data(), Sigma_tau.size() / (_nso * _nso), dt_matrix, matrix_sum_op, 97 | utils::context.internode_comm); 98 | Sigma_tau /= (_nk * _nk); 99 | } 100 | sigma_tau.fence(); 101 | statistics.end(); 102 | statistics.end(); 103 | // print execution time 104 | statistics.print(utils::context.global); 105 | delete _coul_int_c_1; 106 | delete _coul_int_c_2; 107 | delete _coul_int_c_3; 108 | delete _coul_int_c_4; 109 | delete _coul_int_x_3; 110 | delete _coul_int_x_4; 111 | _G_k1_tmp.resize(0, 0); 112 | _Gb_k2_tmp.resize(0, 0); 113 | _G_k3_tmp.resize(0, 0); 114 | vijkl.resize(0, 0, 0, 0); 115 | vcijkl.resize(0, 0, 0, 0); 116 | vxijkl.resize(0, 0, 0, 0); 117 | vxcijkl.resize(0, 0, 0, 0); 118 | MPI_Type_free(&dt_matrix); 119 | MPI_Op_free(&matrix_sum_op); 120 | } 121 | 122 | void gf2_solver::selfenergy_innerloop(size_t tau_offset, size_t ntau_local, const std::array& k, size_t is, const ztensor<5>& Gr_full_tau) { 123 | statistics.start("nao"); 124 | size_t nao2 = _nao * _nao; 125 | size_t nao3 = _nao * _nao * _nao; 126 | // Link current k-points to corresponding reduced k's 127 | // k = (k_red, k1, k2, k3) 128 | // Find the position in the irreducible list 129 | size_t k1_pos = _bz_utils.symmetry().reduced_point(k[1]); 130 | size_t k2_pos = _bz_utils.symmetry().reduced_point(k[2]); 131 | size_t k3_pos = _bz_utils.symmetry().reduced_point(k[3]); 132 | size_t k0_pos = _bz_utils.symmetry().reduced_point(k[0]); 133 | size_t momshift = k0_pos * nao2; 134 | #pragma omp parallel 135 | { 136 | Eigen::MatrixXcd G1(_nao, _nao); 137 | Eigen::MatrixXcd G2(_nao, _nao); 138 | Eigen::MatrixXcd G3(_nao, _nao); 139 | ztensor<3> X(_nao, _nao, _nao); 140 | MMatrixXcd Xm_4(X.data(), _nao, nao2); 141 | ztensor<3> X1(_nao, _nao, _nao); 142 | MMatrixXcd Xm_1(X1.data(), nao2, _nao); 143 | MMatrixXcd Xm_2(X1.data(), _nao, nao2); 144 | ztensor<3> Y1(_nao, _nao, _nao); 145 | MMatrixXcd Ym_1(Y1.data(), nao2, _nao); 146 | MMatrixXcd Ym_2(Y1.data(), _nao, nao2); 147 | MMatrixXcd Xm(X.data(), 1, nao3); 148 | MMatrixXcd Vm(vcijkl.data(), nao3, _nao); 149 | MMatrixXcd Vmx(vxcijkl.data(), nao3, _nao); 150 | 151 | // Loop over tau indices 152 | #pragma omp for 153 | for (size_t t = tau_offset, ttt = 0; ttt < ntau_local; ++t, ++ttt) { 154 | int shift = t * _ns * _ink * nao2 + is * _ink * nao2 + momshift; 155 | int tt = _nts - t - 1; 156 | // initialize Green's functions 157 | for (size_t isp = 0; isp < _ns; ++isp) { 158 | for (size_t q0 = 0; q0 < _nao; ++q0) { 159 | for (size_t p0 = 0; p0 < _nao; ++p0) { 160 | G1(q0, p0) = _bz_utils.symmetry().conj_list()[k[1]] == 0 ? Gr_full_tau(t, is, k1_pos, q0, p0) 161 | : std::conj(Gr_full_tau(t, is, k1_pos, q0, p0)); 162 | G2(q0, p0) = _bz_utils.symmetry().conj_list()[k[2]] == 0 ? Gr_full_tau(tt, isp, k2_pos, q0, p0) 163 | : std::conj(Gr_full_tau(tt, isp, k2_pos, q0, p0)); 164 | G3(q0, p0) = _bz_utils.symmetry().conj_list()[k[3]] == 0 ? Gr_full_tau(t, isp, k3_pos, q0, p0) 165 | : std::conj(Gr_full_tau(t, isp, k3_pos, q0, p0)); 166 | } 167 | } 168 | for (size_t i = 0; i < _nao; ++i) { 169 | // pm,k 170 | MMatrixXcd Sm(Sigma_local.data() + shift + i * _nao, 1, _nao); 171 | // v1 for direct 172 | MMatrixXcd vm_1(vijkl.data() + i * nao3, nao2, _nao); 173 | // Direct diagram 174 | contraction(nao2, nao3, is == isp, false, G1, G2, G3, Xm_4, Xm_1, Xm_2, Ym_1, Ym_2, vm_1, Xm, Vm, Vmx, Sm); 175 | } 176 | } 177 | } 178 | } 179 | statistics.end(); 180 | } 181 | 182 | void gf2_solver::contraction(size_t nao2, size_t nao3, bool eq_spin, bool ew_correct, const Eigen::MatrixXcd& G1, 183 | const Eigen::MatrixXcd& G2, const Eigen::MatrixXcd& G3, MMatrixXcd& Xm_4, MMatrixXcd& Xm_1, 184 | MMatrixXcd& Xm_2, MMatrixXcd& Ym_1, MMatrixXcd& Ym_2, const MMatrixXcd& vm_1, MMatrixXcd& Xm, 185 | MMatrixXcd& Vm, MMatrixXcd& Vxm, MMatrixXcd& Sm) { 186 | // pm,l = pm,k k,l 187 | Xm_1.noalias() = (vm_1 * G3); 188 | // ml,q = ml,p p,q 189 | Ym_1.noalias() = (Xm_2.transpose() * G1); 190 | // n,lq = n,m m,lq 191 | Xm_2.noalias() = G2 * Ym_2; 192 | // q,nl 193 | Xm_4.noalias() = Xm_1.transpose(); 194 | // i,j = i,qnl qnl,j 195 | Sm.noalias() += Xm * Vm; 196 | // Additional exchange contribution of same spin 197 | if (eq_spin and !ew_correct) { 198 | Sm.noalias() += Xm * Vxm; 199 | } 200 | } 201 | 202 | void gf2_solver::read_next(const std::array& k) { 203 | // k = (k1_red, k2, k3, k1_red+k3-k2) 204 | // Read integral for the 2nd-order direct diagram 205 | _coul_int_c_1->read_integrals(k[0], k[1]); 206 | _coul_int_c_2->read_integrals(k[2], k[3]); 207 | // Read integral for the 2nd-order exchange diagram 208 | _coul_int_c_3->read_integrals(k[0], k[1]); 209 | _coul_int_c_4->read_integrals(k[2], k[3]); 210 | _coul_int_x_3->read_integrals(k[0], k[3]); 211 | _coul_int_x_4->read_integrals(k[2], k[1]); 212 | } 213 | 214 | void gf2_solver::setup_integrals(const std::array& kpts) { 215 | vijkl.set_zero(); 216 | vcijkl.set_zero(); 217 | vxijkl.set_zero(); 218 | vxcijkl.set_zero(); 219 | 220 | ztensor<3> Vx1(_NQ, _nao, _nao); 221 | ztensor<3> Vx2(_NQ, _nao, _nao); 222 | ztensor<3> V1(_NQ, _nao, _nao); 223 | ztensor<3> V2(_NQ, _nao, _nao); 224 | _coul_int_x_3->symmetrize(Vx1, kpts[0], kpts[3]); 225 | _coul_int_x_4->symmetrize(Vx2, kpts[2], kpts[1]); 226 | _coul_int_c_1->symmetrize(V1, kpts[0], kpts[1]); 227 | _coul_int_c_2->symmetrize(V2, kpts[2], kpts[3]); 228 | CMMatrixXcd vx1(Vx1.data(), _NQ, _nao * _nao); 229 | CMMatrixXcd vx2(Vx2.data(), _NQ, _nao * _nao); 230 | CMMatrixXcd v1(V1.data(), _NQ, _nao * _nao); 231 | CMMatrixXcd v2(V2.data(), _NQ, _nao * _nao); 232 | 233 | MMatrixXcd v(vijkl.data(), _nao * _nao, _nao * _nao); 234 | MMatrixXcd vx(vxijkl.data(), _nao * _nao, _nao * _nao); 235 | MMatrixXcd vxc(vijkl.data(), _nao * _nao, _nao * _nao); 236 | MMatrixXcd vc(vijkl.data(), _nao * _nao, _nao * _nao); 237 | 238 | // For direct diagram 239 | double prefactor = (_ns == 2) ? 1.0 : 2.0; 240 | vc = prefactor * v1.transpose().conjugate() * v2.conjugate(); 241 | 242 | #pragma omp parallel for 243 | for (size_t i = 0; i < _nao; ++i) { 244 | for (size_t j = 0; j < _nao; ++j) { 245 | for (size_t k = 0; k < _nao; ++k) { 246 | for (size_t l = 0; l < _nao; ++l) { 247 | // v2 for Direct term 248 | vcijkl(j, k, l, i) = vijkl(i, j, k, l); 249 | } 250 | } 251 | } 252 | } 253 | // For exchange diagram 254 | vxc = vx1.transpose().conjugate() * vx2.conjugate(); 255 | #pragma omp parallel for 256 | for (size_t i = 0; i < _nao; ++i) { 257 | for (size_t j = 0; j < _nao; ++j) { 258 | for (size_t k = 0; k < _nao; ++k) { 259 | for (size_t l = 0; l < _nao; ++l) { 260 | // v2 for exchange term 261 | vxcijkl(j, k, l, i) = -vijkl(i, l, k, j); 262 | } 263 | } 264 | } 265 | } 266 | // v1 for direct term 267 | v = v1.transpose() * v2; 268 | } 269 | } // namespace green::mbpt 270 | -------------------------------------------------------------------------------- /src/gf2_solver_t_ewald_correction.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022 University of Michigan. 3 | * 4 | */ 5 | 6 | #include "green/mbpt/gf2_solver.h" 7 | 8 | namespace green::mbpt { 9 | void gf2_solver::compute_2nd_exch_correction(size_t tau_offset, size_t ntau_local, const ztensor<5>& Gr_full_tau) { 10 | // compute Ewald correction to the second order 11 | size_t nao2 = _nao * _nao; 12 | size_t nao3 = _nao * _nao * _nao; 13 | MatrixXcd G1(_nao, _nao); 14 | MatrixXcd G2(_nao, _nao); 15 | MatrixXcd G3(_nao, _nao); 16 | ztensor<3> X(_nao, _nao, _nao); 17 | MMatrixXcd Xm_4(X.data(), _nao, nao2); 18 | ztensor<3> X1(_nao, _nao, _nao); 19 | MMatrixXcd Xm_1(X1.data(), nao2, _nao); 20 | MMatrixXcd Xm_2(X1.data(), _nao, nao2); 21 | ztensor<3> Y1(_nao, _nao, _nao); 22 | MMatrixXcd Ym_1(Y1.data(), nao2, _nao); 23 | MMatrixXcd Ym_2(Y1.data(), _nao, nao2); 24 | MMatrixXcd Xm(X.data(), 1, nao3); 25 | // TODO Check this 26 | MMatrixXcd Vm(vcijkl.data(), nao3, _nao); 27 | ewald_2nd_order_0_0(tau_offset, ntau_local, Gr_full_tau, G1, G2, G3, Xm_4, Xm_1, Xm_2, Ym_1, Ym_2, Xm, Vm); 28 | ewald_2nd_order_0_1(tau_offset, ntau_local, Gr_full_tau, G1, G2, G3, Xm_4, Xm_1, Xm_2, Ym_1, Ym_2, Xm, Vm); 29 | ewald_2nd_order_1_0(tau_offset, ntau_local, Gr_full_tau, G1, G2, G3, Xm_4, Xm_1, Xm_2, Ym_1, Ym_2, Xm, Vm); 30 | } 31 | 32 | void gf2_solver::ewald_2nd_order_0_0(size_t tau_offset, size_t ntau_local, const ztensor<5>& Gr_full_tau, MatrixXcd& G1, MatrixXcd& G2, MatrixXcd& G3, 33 | MMatrixXcd& Xm_4, MMatrixXcd& Xm_1, MMatrixXcd& Xm_2, MMatrixXcd& Ym_1, MMatrixXcd& Ym_2, 34 | MMatrixXcd& Xm, MMatrixXcd& Vm) { 35 | size_t nao2 = _nao * _nao; 36 | size_t nao3 = nao2 * _nao; 37 | _coul_int_c_1->reset(); 38 | _coul_int_c_2->reset(); 39 | _coul_int_c_3->reset(); 40 | _coul_int_c_4->reset(); 41 | _coul_int_x_3->reset(); 42 | _coul_int_x_4->reset(); 43 | int old_k1 = -1; 44 | // start main loop 45 | // execution will proceed while current point is non-negative 46 | for (size_t k1i = utils::context.internode_rank; k1i < _ink * _nao; k1i += utils::context.internode_size) { 47 | size_t k1_pos = k1i / _nao; 48 | int k1_red = _bz_utils.symmetry().full_point(k1_pos); 49 | size_t i = k1i % _nao; 50 | size_t momshift = k1_pos * nao2; 51 | // read next part of integrals 52 | if (old_k1 != k1_red) { 53 | read_next_correction_0_0(k1_red); 54 | old_k1 = k1_red; 55 | } 56 | for(size_t t = tau_offset, lt = 0; lt< ntau_local; ++lt, ++t) { 57 | size_t tt = _nts - t - 1; 58 | for (size_t s = 0; s < _ns; ++s) { 59 | size_t shift = t * _ns * _ink * nao2 + s * _ink * nao2 + momshift; 60 | // initialize Green's functions 61 | G1 = extract_G_tau_k(Gr_full_tau, t, k1_pos, k1_red, s); 62 | G2 = extract_G_tau_k(Gr_full_tau, tt, k1_pos, k1_red, s); 63 | G3 = extract_G_tau_k(Gr_full_tau, t, k1_pos, k1_red, s); 64 | MMatrixXcd Sm(Sigma_local.data() + shift + i * _nao, 1, _nao); 65 | MMatrixXcd vm_1(vijkl.data() + i * nao3, nao2, _nao); 66 | contraction(nao2, nao3, false, true, G1, G2, G3, Xm_4, Xm_1, Xm_2, Ym_1, Ym_2, vm_1, Xm, Vm, Vm, Sm); 67 | } 68 | } 69 | } 70 | //MPI_Barrier(utils::context.global); 71 | } 72 | 73 | void gf2_solver::ewald_2nd_order_0_1(size_t tau_offset, size_t ntau_local, const ztensor<5>& Gr_full_tau, MatrixXcd& G1, MatrixXcd& G2, MatrixXcd& G3, 74 | MMatrixXcd& Xm_4, MMatrixXcd& Xm_1, MMatrixXcd& Xm_2, MMatrixXcd& Ym_1, MMatrixXcd& Ym_2, 75 | MMatrixXcd& Xm, MMatrixXcd& Vm) { 76 | size_t nao2 = _nao * _nao; 77 | size_t nao3 = nao2 * _nao; 78 | _coul_int_c_1->reset(); 79 | _coul_int_c_2->reset(); 80 | _coul_int_c_3->reset(); 81 | _coul_int_c_4->reset(); 82 | _coul_int_x_3->reset(); 83 | _coul_int_x_4->reset(); 84 | int old_k1 = -1; 85 | int old_k2 = -1; 86 | // start main loop 87 | // execution will proceed while current point is non-negative 88 | for (size_t k1k2 = utils::context.internode_rank; k1k2 < _ink * _nk; k1k2 += utils::context.internode_size) { 89 | // k1k2 = k1 * _nk + k2 90 | size_t k1_pos = k1k2 / (_nk); 91 | int k1_red = _bz_utils.symmetry().full_point(k1_pos); 92 | 93 | int k2_red = (k1k2) % _nk; 94 | size_t k2_pos = _bz_utils.symmetry().reduced_point(k2_red); 95 | size_t momshift = k1_pos * nao2; 96 | // read next part of integrals 97 | if (old_k1 != k1_red || old_k2 != k2_red) { 98 | read_next_correction_0_1(k1_red, k2_red); 99 | old_k1 = k1_red; 100 | old_k2 = k2_red; 101 | } 102 | for(size_t t = tau_offset, lt = 0; lt< ntau_local; ++lt, ++t) { 103 | size_t tt = _nts - t - 1; 104 | for (size_t s = 0; s < _ns; ++s) { 105 | size_t shift = t * _ns * _ink * nao2 + s * _ink * nao2 + momshift; 106 | // initialize Green's functions 107 | G1 = extract_G_tau_k(Gr_full_tau, t, k1_pos, k1_red, s); 108 | G2 = extract_G_tau_k(Gr_full_tau, tt, k2_pos, k2_red, s); 109 | G3 = extract_G_tau_k(Gr_full_tau, t, k2_pos, k2_red, s); 110 | for (size_t i = 0; i < _nao; ++i) { 111 | MMatrixXcd Sm(Sigma_local.data() + shift + i * _nao, 1, _nao); 112 | MMatrixXcd vm_1(vijkl.data() + i * nao3, nao2, _nao); 113 | contraction(nao2, nao3, false, true, G1, G2, G3, Xm_4, Xm_1, Xm_2, Ym_1, Ym_2, vm_1, Xm, Vm, Vm, Sm); 114 | } 115 | } 116 | } 117 | } 118 | // MPI_Barrier(utils::context.global); 119 | } 120 | 121 | void gf2_solver::ewald_2nd_order_1_0(size_t tau_offset, size_t ntau_local, const ztensor<5>& Gr_full_tau, MatrixXcd& G1, MatrixXcd& G2, MatrixXcd& G3, 122 | MMatrixXcd& Xm_4, MMatrixXcd& Xm_1, MMatrixXcd& Xm_2, MMatrixXcd& Ym_1, MMatrixXcd& Ym_2, 123 | MMatrixXcd& Xm, MMatrixXcd& Vm) { 124 | size_t nao2 = _nao * _nao; 125 | size_t nao3 = nao2 * _nao; 126 | int old_k1 = -1; 127 | int old_k2 = -1; 128 | _coul_int_c_1->reset(); 129 | _coul_int_c_2->reset(); 130 | _coul_int_c_3->reset(); 131 | _coul_int_c_4->reset(); 132 | _coul_int_x_3->reset(); 133 | _coul_int_x_4->reset(); 134 | // start main loop 135 | for (size_t k1k2 = utils::context.internode_rank; k1k2 < _ink * _nk; k1k2 += utils::context.internode_size) { 136 | // k1k2 = k1 * _nk + k2 137 | size_t k1_pos = k1k2 / (_nk); 138 | int k1_red = _bz_utils.symmetry().full_point(k1_pos); 139 | int k2_red = k1k2 % _nk; 140 | size_t k2_pos = _bz_utils.symmetry().reduced_point(k2_red); 141 | size_t momshift = k1_pos * nao2; 142 | // read next part of integrals 143 | if (old_k1 != k1_red || old_k2 != k2_red) { 144 | read_next_correction_1_0(k1_red, k2_red); 145 | old_k1 = k1_red; 146 | old_k2 = k2_red; 147 | } 148 | for(size_t t = tau_offset, lt = 0; lt< ntau_local; ++lt, ++t) { 149 | size_t tt = _nts - t - 1; 150 | for (size_t s = 0; s < _ns; ++s) { 151 | size_t shift = t * _ns * _ink * nao2 + s * _ink * nao2 + momshift; 152 | // initialize Green's functions 153 | G1 = extract_G_tau_k(Gr_full_tau, t, k2_pos, k2_red, s); 154 | G2 = extract_G_tau_k(Gr_full_tau, tt, k2_pos, k2_red, s); 155 | G3 = extract_G_tau_k(Gr_full_tau, t, k1_pos, k1_red, s); 156 | for (size_t i = 0; i < _nao; ++i) { 157 | MMatrixXcd Sm(Sigma_local.data() + shift + i * _nao, 1, _nao); 158 | MMatrixXcd vm_1(vijkl.data() + i * nao3, nao2, _nao); 159 | contraction(nao2, nao3, false, true, G1, G2, G3, Xm_4, Xm_1, Xm_2, Ym_1, Ym_2, vm_1, Xm, Vm, Vm, Sm); 160 | } 161 | } 162 | } 163 | } 164 | // MPI_Barrier(utils::context.global); 165 | } 166 | 167 | void gf2_solver::read_next_correction_0_0(size_t k) { 168 | _coul_int_c_1->read_correction(k); 169 | _coul_int_c_2->read_correction(k); 170 | _coul_int_x_3->read_correction(k); 171 | _coul_int_x_4->read_correction(k); 172 | // direct 173 | CMMatrixXcd vc_1(_coul_int_c_1->v0ij_Q().data(), _NQ, _nao * _nao); 174 | CMMatrixXcd vc_2(_coul_int_c_2->v0ij_Q().data(), _NQ, _nao * _nao); 175 | CMMatrixXcd vc_bar_1(_coul_int_c_1->v_bar_ij_Q().data(), _NQ, _nao * _nao); 176 | CMMatrixXcd vc_bar_2(_coul_int_c_2->v_bar_ij_Q().data(), _NQ, _nao * _nao); 177 | // exchange 178 | CMMatrixXcd vx_3(_coul_int_x_3->v0ij_Q().data(), _NQ, _nao * _nao); 179 | CMMatrixXcd vx_4(_coul_int_x_4->v0ij_Q().data(), _NQ, _nao * _nao); 180 | CMMatrixXcd vx_bar_3(_coul_int_x_3->v_bar_ij_Q().data(), _NQ, _nao * _nao); 181 | CMMatrixXcd vx_bar_4(_coul_int_x_4->v_bar_ij_Q().data(), _NQ, _nao * _nao); 182 | 183 | MMatrixXcd v(vijkl.data(), _nao * _nao, _nao * _nao); 184 | MMatrixXcd vx2(vijkl.data(), _nao * _nao, _nao * _nao); 185 | vijkl.set_zero(); 186 | vcijkl.set_zero(); 187 | 188 | vx2 = vx_3.transpose() * vx_4 + vx_3.transpose() * vx_bar_4 + vx_bar_3.transpose() * vx_4; 189 | #pragma omp parallel for 190 | for (size_t i = 0; i < _nao; ++i) { 191 | for (size_t j = 0; j < _nao; ++j) { 192 | for (size_t k = 0; k < _nao; ++k) { 193 | for (size_t l = 0; l < _nao; ++l) { 194 | vcijkl(k, l, i, j) = -vijkl(i, j, k, l); 195 | } 196 | } 197 | } 198 | } 199 | v = vc_1.transpose() * vc_2 + vc_bar_1.transpose() * vc_2 + vc_1.transpose() * vc_bar_2; 200 | } 201 | 202 | void gf2_solver::read_next_correction_0_1(size_t k1, size_t k2) { 203 | size_t kx3 = _coul_int_x_3->wrap(k2, k1); 204 | size_t kx4 = _coul_int_x_4->wrap(k1, k2); 205 | _coul_int_c_1->read_correction(k1); 206 | _coul_int_c_2->read_correction(k2); 207 | _coul_int_x_3->read_integrals(k2, k1); 208 | _coul_int_x_4->read_integrals(k1, k2); 209 | // direct 210 | CMMatrixXcd vc_1(_coul_int_c_1->v0ij_Q().data(), _NQ, _nao * _nao); 211 | CMMatrixXcd vc_2(_coul_int_c_2->v0ij_Q().data(), _NQ, _nao * _nao); 212 | CMMatrixXcd vc_bar_1(_coul_int_c_1->v_bar_ij_Q().data(), _NQ, _nao * _nao); 213 | CMMatrixXcd vc_bar_2(_coul_int_c_2->v_bar_ij_Q().data(), _NQ, _nao * _nao); 214 | // exchange 215 | CMMatrixXcd vx_3(_coul_int_x_3->vij_Q().data() + kx3 * _nao * _nao * _NQ, _NQ, _nao * _nao); 216 | CMMatrixXcd vx_4(_coul_int_x_4->vij_Q().data() + kx4 * _nao * _nao * _NQ, _NQ, _nao * _nao); 217 | MMatrixXcd v(vijkl.data(), _nao * _nao, _nao * _nao); 218 | MMatrixXcd vx2(vijkl.data(), _nao * _nao, _nao * _nao); 219 | vijkl.set_zero(); 220 | vcijkl.set_zero(); 221 | 222 | vx2 = vx_3.transpose() * vx_4; 223 | //#pragma omp parallel for 224 | for (size_t i = 0; i < _nao; ++i) { 225 | for (size_t j = 0; j < _nao; ++j) { 226 | for (size_t k = 0; k < _nao; ++k) { 227 | for (size_t l = 0; l < _nao; ++l) { 228 | vcijkl(k, l, i, j) = -vijkl(i, j, k, l); 229 | } 230 | } 231 | } 232 | } 233 | v = vc_1.transpose() * vc_2 + vc_bar_1.transpose() * vc_2 + vc_1.transpose() * vc_bar_2; 234 | } 235 | 236 | void gf2_solver::read_next_correction_1_0(size_t k1, size_t k2) { 237 | size_t k1_w = _coul_int_c_1->wrap(k1, k2); 238 | size_t k2_w = _coul_int_c_2->wrap(k2, k1); 239 | _coul_int_c_1->read_integrals(k1, k2); 240 | _coul_int_c_2->read_integrals(k2, k1); 241 | _coul_int_x_3->read_correction(k1); 242 | _coul_int_x_4->read_correction(k2); 243 | // direct 244 | CMMatrixXcd vc_1(_coul_int_c_1->vij_Q().data() + k1_w * _nao * _nao * _NQ, _NQ, _nao * _nao); 245 | CMMatrixXcd vc_2(_coul_int_c_2->vij_Q().data() + k2_w * _nao * _nao * _NQ, _NQ, _nao * _nao); 246 | // exchange 247 | CMMatrixXcd vx_3(_coul_int_x_3->v0ij_Q().data(), _NQ, _nao * _nao); 248 | CMMatrixXcd vx_4(_coul_int_x_4->v0ij_Q().data(), _NQ, _nao * _nao); 249 | CMMatrixXcd vx_bar_3(_coul_int_x_3->v_bar_ij_Q().data(), _NQ, _nao * _nao); 250 | CMMatrixXcd vx_bar_4(_coul_int_x_4->v_bar_ij_Q().data(), _NQ, _nao * _nao); 251 | MMatrixXcd v(vijkl.data(), _nao * _nao, _nao * _nao); 252 | MMatrixXcd vx2(vijkl.data(), _nao * _nao, _nao * _nao); 253 | vijkl.set_zero(); 254 | vcijkl.set_zero(); 255 | 256 | vx2 = vx_3.transpose() * vx_4 + vx_3.transpose() * vx_bar_4 + vx_bar_3.transpose() * vx_4; 257 | #pragma omp parallel for 258 | for (size_t i = 0; i < _nao; ++i) { 259 | for (size_t j = 0; j < _nao; ++j) { 260 | for (size_t k = 0; k < _nao; ++k) { 261 | for (size_t l = 0; l < _nao; ++l) { 262 | vcijkl(k, l, i, j) = -vijkl(i, j, k, l); 263 | } 264 | } 265 | } 266 | } 267 | v = vc_1.transpose() * vc_2; 268 | } 269 | } // namespace green::mbpt -------------------------------------------------------------------------------- /src/green/mbpt/common_defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 University of Michigan 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 5 | * software and associated documentation files (the “Software”), to deal in the Software 6 | * without restriction, including without limitation the rights to use, copy, modify, 7 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so, subject to the following 9 | * conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all copies or 12 | * substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #ifndef MBPT_COMMON_DEFS_H 23 | #define MBPT_COMMON_DEFS_H 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include "custom_kernels.h" 32 | 33 | namespace green::mbpt { 34 | 35 | static const std::string INPUT_VERSION = "0.2.4"; 36 | 37 | // Matrix types 38 | template 39 | using MatrixX = Eigen::Matrix; 40 | using MatrixXcd = Eigen::Matrix, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>; 41 | using MatrixXcf = Eigen::Matrix, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>; 42 | using MatrixXd = Eigen::Matrix; 43 | // Matrix-Map types 44 | template 45 | using MMatrixX = Eigen::Map>; 46 | using MMatrixXcd = Eigen::Map, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>; 47 | using MMatrixXcf = Eigen::Map, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>; 48 | using MMatrixXd = Eigen::Map>; 49 | // Const Matrix-Map types 50 | template 51 | using CMMatrixX = Eigen::Map>; 52 | using CMMatrixXcd = Eigen::Map, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>; 53 | using CMMatrixXcf = Eigen::Map, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>; 54 | using CMMatrixXd = Eigen::Map>; 55 | // Column type 56 | using column = Eigen::Matrix, Eigen::Dynamic, 1, Eigen::ColMajor>; 57 | using Mcolumn = Eigen::Map, Eigen::Dynamic, 1, Eigen::ColMajor>>; 58 | using CMcolumn = Eigen::Map, Eigen::Dynamic, 1, Eigen::ColMajor>>; 59 | // time grid type 60 | using tau_mesh = grids::itime_mesh_t; 61 | // Tensor types 62 | template 63 | using tensor = green::ndarray::ndarray; 64 | template 65 | using ztensor = green::ndarray::ndarray, Dim>; 66 | template 67 | using ztensor_view = green::ndarray::ndarray, Dim>; 68 | template 69 | using ztensor_base = green::ndarray::ndarray, Dim>; 70 | template 71 | using ctensor = green::ndarray::ndarray, Dim>; 72 | template 73 | using dtensor = green::ndarray::ndarray; 74 | template 75 | using ltensor = green::ndarray::ndarray; 76 | template 77 | using itensor = green::ndarray::ndarray; 78 | 79 | template >>> 80 | auto matrix(green::ndarray::ndarray& array) { 81 | return MMatrixX(array.data(), array.shape()[0], array.shape()[1]); 82 | } 83 | 84 | template >>> 85 | auto matrix(green::ndarray::ndarray&& array) { 86 | return MMatrixX(array.data(), array.shape()[0], array.shape()[1]); 87 | } 88 | 89 | template 90 | auto matrix(const green::ndarray::ndarray& array) { 91 | return CMMatrixX(const_cast(array.data()), array.shape()[0], array.shape()[1]); 92 | } 93 | 94 | template 95 | auto matrix(green::ndarray::ndarray&& array) { 96 | return CMMatrixX(const_cast(array.data()), array.shape()[0], array.shape()[1]); 97 | } 98 | 99 | template 100 | auto matrix(const green::ndarray::ndarray& array) { 101 | return CMMatrixX(array.data(), array.shape()[0], array.shape()[1]); 102 | } 103 | 104 | template 105 | void make_hermitian(ndarray::ndarray, N>& X) { 106 | // check that two innermost dimensions form a matrix 107 | assert(X.shape()[N - 1] == X.shape()[N - 2]); 108 | // Dimension of the rest of arrays 109 | size_t dim1 = std::accumulate(X.shape().begin(), X.shape().end() - 2, 1ul, std::multiplies()); 110 | size_t nao = X.shape()[N - 1]; 111 | for (size_t i = 0; i < dim1; ++i) { 112 | MMatrixXcd Xm(X.data() + i * nao * nao, nao, nao); 113 | Xm = 0.5 * (Xm + Xm.conjugate().transpose().eval()); 114 | } 115 | } 116 | 117 | template 118 | std::array operator+(const std::array& a, T b) { 119 | std::array result; 120 | std::copy(a.begin(), a.end(), result.begin()); 121 | result[D] = size_t(b); 122 | return result; 123 | } 124 | 125 | template 126 | std::array operator+(T b, const std::array& a) { 127 | std::array result; 128 | std::copy(a.begin(), a.end(), result.begin() + 1); 129 | result[0] = size_t(b); 130 | return result; 131 | } 132 | 133 | enum scf_type { HF, GF2, GW }; 134 | 135 | enum sigma_q0_treatment_e { ignore_G0, ewald_int, extrapolate }; 136 | 137 | enum job_type { SC, WINTER, THERMODYNAMICS }; 138 | 139 | enum kernel_type { 140 | CPU 141 | #ifdef GREEN_CUSTOM_KERNEL_ENUM_0 142 | , GREEN_CUSTOM_KERNEL_ENUM_0 143 | #endif 144 | #ifdef GREEN_CUSTOM_KERNEL_ENUM_1 145 | , GREEN_CUSTOM_KERNEL_ENUM_1 146 | #endif 147 | #ifdef GREEN_CUSTOM_KERNEL_ENUM_2 148 | , GREEN_CUSTOM_KERNEL_ENUM_2 149 | #endif 150 | #ifdef GREEN_CUSTOM_KERNEL_ENUM_3 151 | , GREEN_CUSTOM_KERNEL_ENUM_3 152 | #endif 153 | }; 154 | 155 | inline void define_parameters(params::params& p) { 156 | p.define("dfintegral_hf_file", "Path to Hartree-Fock integrals", "df_hf_int"); 157 | p.define("dfintegral_file", "Path to integrals for high orfer theories", "df_int"); 158 | p.define("verbose", "Print verbose output.", 0); 159 | p.define("tolerance,tol", "Double precision tolerance for chemical potential search.", 1e-9); 160 | p.define("BETA,beta", "Inverse temperature."); 161 | p.define("scf_type", "Self-consistency level."); 162 | p.define("P_sp", "Compute polarization in single precision", false); 163 | p.define("Sigma_sp", "Compute self-energy in single precision", false); 164 | p.define("high_symmetry_output_file", "Name of the file to store Wannier interpolated Green's function.", 165 | "output_hs.h5"); 166 | p.define("q0_treatment", "GW q=0 divergence treatment", ignore_G0); 167 | p.define>("jobs", "Jobs to run.", std::vector{SC}); 168 | p.define("kernel", "Type of the computing kernel.", CPU); 169 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_0 170 | GREEN_CUSTOM_KERNEL_NS_0::custom_kernel_parameters(p); 171 | #endif 172 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_1 173 | GREEN_CUSTOM_KERNEL_NS_1::custom_kernel_parameters(p); 174 | #endif 175 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_2 176 | GREEN_CUSTOM_KERNEL_NS_2::custom_kernel_parameters(p); 177 | #endif 178 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_3 179 | GREEN_CUSTOM_KERNEL_NS_3::custom_kernel_parameters(p); 180 | #endif 181 | } 182 | 183 | /** 184 | * @brief Compare two version strings 185 | * 186 | * @param v (std::string) 187 | * @return true if v >= INPUT_VERSION 188 | * @return false otherwise 189 | */ 190 | inline bool CheckVersion(const std::string& v) { 191 | int major_Vin, minor_Vin, patch_Vin; 192 | int major_Vref, minor_Vref, patch_Vref; 193 | 194 | char suffixV[32] = ""; 195 | char suffixM[32] = ""; 196 | 197 | std::sscanf(v.c_str(), "%d.%d.%d%31s", &major_Vin, &minor_Vin, &patch_Vin, suffixV); 198 | std::sscanf(INPUT_VERSION.c_str(), "%d.%d.%d%31s", &major_Vref, &minor_Vref, &patch_Vref, suffixM); 199 | 200 | if (major_Vin != major_Vref) return major_Vin > major_Vref; 201 | if (minor_Vin != minor_Vref) return minor_Vin > minor_Vref; 202 | if (patch_Vin != patch_Vref) return patch_Vin > patch_Vref; 203 | 204 | // If numeric parts in version are all equal, do not worry about suffix 205 | // e.g., 0.2.4b10 has same integral format as 0.2.4 206 | return true; 207 | } 208 | 209 | } // namespace green::mbpt 210 | #endif // MBPT_COMMON_DEFS_H 211 | -------------------------------------------------------------------------------- /src/green/mbpt/common_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 University of Michigan 3 | * 4 | */ 5 | #ifndef MBPT_COMMON_UTILS_H 6 | #define MBPT_COMMON_UTILS_H 7 | 8 | #include 9 | #include 10 | #include "df_integral_t.h" 11 | 12 | namespace green::mbpt { 13 | 14 | inline void print_leakage(double leakage, const std::string& object) { 15 | std::cout << "Leakage of " + object << ": " << leakage << std::endl; 16 | if (leakage > 1e-8) std::cerr << "WARNING: The leakage is larger than 1e-8" << std::endl; 17 | } 18 | 19 | inline auto compute_energy(const ztensor<5>& g_tau, const ztensor<4>& sigma1, const ztensor<5>& sigma_tau, 20 | const ztensor<4>& H_k, const grids::transformer_t& ft, 21 | const symmetry::brillouin_zone_utils& bz, bool X2C) { 22 | size_t _nso = g_tau.shape()[4]; 23 | size_t _ns = g_tau.shape()[1]; 24 | size_t _ink = g_tau.shape()[2]; 25 | size_t _nw = ft.sd().repn_fermi().nw(); 26 | size_t _nts = ft.sd().repn_fermi().nts(); 27 | // Transform G and Sigma to Matsubara axis 28 | ztensor<2> G_w(_nso, _nso); 29 | ztensor<2> Sigma_w(_nso, _nso); 30 | ztensor<4> dmr(_ns, _ink, _nso, _nso); 31 | dmr << g_tau(_nts - 1); 32 | dmr *= (_ns == 2 or X2C) ? -1.0 : -2.0; 33 | 34 | MatrixXcd GS_w = MatrixXcd::Zero(_nw, 1); 35 | MatrixXcd GS_t(1, 1); 36 | MatrixXcd TtBn = ft.Ttn().block(_nts - 1, 0, 1, _nw); 37 | 38 | double energy = 0.0; 39 | double ehf = 0.0; 40 | double e1e = 0.0; 41 | for (size_t iwsk = utils::context.global_rank; iwsk < _nw * _ns * _ink; iwsk += utils::context.global_size) { 42 | size_t iw = iwsk / (_ns * _ink); 43 | size_t is = (iwsk % (_ns * _ink)) / _ink; 44 | size_t ik = iwsk % _ink; 45 | ft.tau_to_omega_wsk(sigma_tau, Sigma_w, iw, is, ik, 1); 46 | ft.tau_to_omega_wsk(g_tau, G_w, iw, is, ik, 1); 47 | size_t k_ir = bz.symmetry().full_point(ik); 48 | GS_w(iw, 0) += bz.symmetry().weight()[k_ir] * (matrix(G_w) * matrix(Sigma_w)).eval().trace(); 49 | } 50 | GS_t = TtBn * GS_w; 51 | double energy_prefactor = (_ns == 1 and !X2C) ? 1.0 : 0.5; 52 | energy = -GS_t(0, 0).real() * energy_prefactor; 53 | MPI_Allreduce(MPI_IN_PLACE, &energy, 1, MPI_DOUBLE_PRECISION, MPI_SUM, utils::context.global); 54 | for (size_t isk = utils::context.global_rank; isk < _ns * _ink; isk += utils::context.global_size) { 55 | size_t is = isk / _ink; 56 | size_t ik = isk % _ink; 57 | size_t k_ir = bz.symmetry().full_point(ik); 58 | ehf += 0.5 * (matrix(dmr(is, ik)) * (matrix(sigma1(is, ik)) + 2.0 * matrix(H_k(is, ik)))).trace().real() * 59 | bz.symmetry().weight()[k_ir]; 60 | e1e += (matrix(dmr(is, ik)) * matrix(H_k(is, ik))).trace().real() * bz.symmetry().weight()[k_ir]; 61 | } 62 | MPI_Allreduce(MPI_IN_PLACE, &e1e, 1, MPI_DOUBLE_PRECISION, MPI_SUM, utils::context.global); 63 | MPI_Allreduce(MPI_IN_PLACE, &ehf, 1, MPI_DOUBLE_PRECISION, MPI_SUM, utils::context.global); 64 | e1e *= bz.nkpw(); 65 | ehf *= bz.nkpw(); 66 | energy *= bz.nkpw(); 67 | 68 | return std::array{e1e, ehf, energy}; 69 | } 70 | 71 | inline std::pair compute_local_and_offset_node_comm(size_t size) { 72 | size_t local = size / utils::context.node_size; 73 | local += (size % utils::context.node_size > utils::context.node_rank) ? 1 : 0; 74 | size_t offset = local * utils::context.node_rank + 75 | ((size % utils::context.node_size > utils::context.node_rank) ? 0 : (size % utils::context.node_size)); 76 | return {local, offset}; 77 | } 78 | 79 | } // namespace green::mbpt 80 | #endif // MBPT_COMMON_UTILS_H 81 | -------------------------------------------------------------------------------- /src/green/mbpt/custom_kernels.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 University of Michigan 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 5 | * software and associated documentation files (the “Software”), to deal in the Software 6 | * without restriction, including without limitation the rights to use, copy, modify, 7 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so, subject to the following 9 | * conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all copies or 12 | * substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #ifndef MBPT_CUSTOM_KERNELS_H 23 | #define MBPT_CUSTOM_KERNELS_H 24 | 25 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_0 26 | #include GREEN_CUSTOM_KERNEL_HEADER_0 27 | #endif 28 | 29 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_1 30 | #include GREEN_CUSTOM_KERNEL_HEADER_1 31 | #endif 32 | 33 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_2 34 | #include GREEN_CUSTOM_KERNEL_HEADER_2 35 | #endif 36 | 37 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_3 38 | #include GREEN_CUSTOM_KERNEL_HEADER_3 39 | #endif 40 | 41 | #endif // MBPT_CUSTOM_KERNELS_H -------------------------------------------------------------------------------- /src/green/mbpt/df_integral_t.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 University of Michigan. 3 | * 4 | */ 5 | 6 | #ifndef GREEN_OLD_DFINTEGRAL_H 7 | #define GREEN_OLD_DFINTEGRAL_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | namespace green::mbpt { 20 | enum integral_symmetry_type_e { direct, conjugated, transposed }; 21 | /** 22 | * @brief Integral class read Density fitted 3-center integrals from a HDF5 file, given by the path argument 23 | */ 24 | class df_integral_t { 25 | // prefixes for hdf5 26 | const std::string _chunk_basename = "VQ"; 27 | const std::string _corr_path = "df_ewald.h5"; 28 | const std::string _corr_basename = "EW"; 29 | const std::string _corr_bar_basename = "EW_bar"; 30 | 31 | using bz_utils_t = symmetry::brillouin_zone_utils; 32 | using int_data = utils::shared_object>; 33 | 34 | public: 35 | using MatrixXcd = Eigen::Matrix, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>; 36 | using MatrixXcf = Eigen::Matrix, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>; 37 | using MatrixXd = Eigen::Matrix; 38 | df_integral_t(const std::string& path, int nao, int NQ, const bz_utils_t& bz_utils) : 39 | _base_path(path), _k0(-1), _current_chunk(-1), _chunk_size(0), _NQ(NQ), _bz_utils(bz_utils) { 40 | h5pp::archive ar(path + "/meta.h5"); 41 | if(ar.has_attribute("__green_version__")) { 42 | std::string int_version = ar.get_attribute("__green_version__"); 43 | if (!CheckVersion(int_version)) { 44 | throw mbpt_outdated_input("Integral files at '" + path +"' are outdated, please run migration script python/migrate.py"); 45 | } 46 | } else { 47 | throw mbpt_outdated_input("Integral files at '" + path +"' are outdated, please run migration script python/migrate.py"); 48 | } 49 | ar["chunk_size"] >> _chunk_size; 50 | ar.close(); 51 | _vij_Q = std::make_shared(_chunk_size, NQ, nao, nao); 52 | } 53 | 54 | virtual ~df_integral_t() {} 55 | 56 | /** 57 | * Read next part of the interaction integral from 58 | * @param k1 59 | * @param k2 60 | * @param type 61 | */ 62 | void read_integrals(size_t k1, size_t k2) { 63 | assert(k1 >= 0); 64 | assert(k2 >= 0); 65 | // Find corresponding index for k-pair (k1,k2). Only k-pair with k1 > k2 will be stored. 66 | size_t idx = (k1 >= k2) ? k1 * (k1 + 1) / 2 + k2 : k2 * (k2 + 1) / 2 + k1; // k-pair = (k1, k2) or (k2, k1) 67 | // Corresponding symmetry-related k-pair 68 | if (_bz_utils.symmetry().conj_kpair_list()[idx] != idx) { 69 | idx = _bz_utils.symmetry().conj_kpair_list()[idx]; 70 | } else if (_bz_utils.symmetry().trans_kpair_list()[idx] != idx) { 71 | idx = _bz_utils.symmetry().trans_kpair_list()[idx]; 72 | } 73 | long idx_red = _bz_utils.symmetry().irre_pos_kpair(idx); 74 | if ((idx_red / _chunk_size) == _current_chunk) return; // we have data cached 75 | 76 | _current_chunk = idx_red / _chunk_size; 77 | 78 | size_t c_id = _current_chunk * _chunk_size; 79 | (*_vij_Q).fence(); 80 | if (!utils::context.node_rank) read_a_chunk(c_id, _vij_Q->object()); 81 | (*_vij_Q).fence(); 82 | } 83 | 84 | void read_a_chunk(size_t c_id, ztensor<4>& V_buffer) { 85 | std::string fname = _base_path + "/" + _chunk_basename + "_" + std::to_string(c_id) + ".h5"; 86 | h5pp::archive ar(fname); 87 | ar["/" + std::to_string(c_id)] >> reinterpret_cast(V_buffer.data()); 88 | ar.close(); 89 | } 90 | 91 | void Complex_DoubleToType(const std::complex* in, std::complex* out, size_t size) { 92 | memcpy(out, in, size * sizeof(std::complex)); 93 | } 94 | 95 | void Complex_DoubleToType(const std::complex* in, std::complex* out, size_t size) { 96 | for (int i = 0; i < size; ++i) { 97 | out[i] = static_cast>(in[i]); 98 | } 99 | } 100 | 101 | /** 102 | * read next part of the G=0 correction to interaction integral for the specific k-point 103 | * @param file - file to be used 104 | * @param k - k-point 105 | */ 106 | void read_correction(int k) { 107 | auto shape = _vij_Q->object().shape(); 108 | _v0ij_Q.resize(shape[1], shape[2], shape[3]); 109 | _v_bar_ij_Q.resize(shape[1], shape[2], shape[3]); 110 | // avoid unnecessary reading 111 | if (k == _k0) { 112 | // we have data cached 113 | return; 114 | } 115 | _k0 = k; 116 | std::string inner = std::to_string(_current_chunk * _chunk_size); 117 | std::string fname = _base_path + "/" + _corr_path; 118 | h5pp::archive ar(fname); 119 | // Construct integral dataset name 120 | std::string dsetnum = _corr_basename + "/" + std::to_string(k); 121 | // read data 122 | ar[dsetnum] >> reinterpret_cast(_v0ij_Q.data()); 123 | // Construct integral dataset name 124 | dsetnum = _corr_bar_basename + "/" + std::to_string(k); 125 | // read data 126 | ar[dsetnum] >> reinterpret_cast(_v_bar_ij_Q.data()); 127 | ar.close(); 128 | }; 129 | 130 | /** 131 | * Determine the type of symmetries for the integral based on the current k-points 132 | * 133 | * @param k1 incomming k-point 134 | * @param k2 outgoing k-point 135 | * @return A pair of sign and type of applied symmetry 136 | */ 137 | std::pair v_type(size_t k1, size_t k2) { 138 | size_t idx = (k1 >= k2) ? k1 * (k1 + 1) / 2 + k2 : k2 * (k2 + 1) / 2 + k1; // k-pair = (k1, k2) or (k2, k1) 139 | // determine sign 140 | int sign = (k1 >= k2) ? 1 : -1; 141 | // determine applied symmetry type 142 | // by default no symmetries applied 143 | integral_symmetry_type_e symmetry_type = direct; 144 | if (_bz_utils.symmetry().conj_kpair_list()[idx] != idx) { 145 | symmetry_type = conjugated; 146 | } else if (_bz_utils.symmetry().trans_kpair_list()[idx] != idx) { 147 | symmetry_type = transposed; 148 | } 149 | return std::make_pair(sign, symmetry_type); 150 | } 151 | 152 | /** 153 | * Extract V(Q, i, j) with given (k1, k2) from chunks of integrals (_vij_Q) 154 | * @tparam prec 155 | * @param vij_Q_k1k2 156 | * @param k1 157 | * @param k2 158 | */ 159 | template 160 | void symmetrize(tensor& vij_Q_k1k2, size_t k1, size_t k2, size_t NQ_offset = 0, size_t NQ_local = 0) { 161 | int k1k2_wrap = wrap(k1, k2); 162 | std::pair vtype = v_type(k1, k2); 163 | int NQ = _NQ; 164 | NQ_local = (NQ_local == 0) ? NQ : NQ_local; 165 | auto& vij_Q = _vij_Q->object(); 166 | if (vtype.first < 0) { 167 | for (int Q = NQ_offset, Q_loc = 0; Q_loc < NQ_local; ++Q, ++Q_loc) { 168 | matrix(vij_Q_k1k2(Q_loc)) = matrix(vij_Q(k1k2_wrap, Q)).transpose().conjugate().cast(); 169 | } 170 | } else { 171 | for (int Q = NQ_offset, Q_loc = 0; Q_loc < NQ_local; ++Q, ++Q_loc) { 172 | matrix(vij_Q_k1k2(Q_loc)) = matrix(vij_Q(k1k2_wrap, Q)).cast(); 173 | } 174 | } 175 | if (vtype.second == conjugated) { // conjugate 176 | for (int Q = NQ_offset, Q_loc = 0; Q_loc < NQ_local; ++Q, ++Q_loc) { 177 | matrix(vij_Q_k1k2(Q_loc)) = matrix(vij_Q_k1k2(Q_loc)).conjugate(); 178 | } 179 | } else if (vtype.second == transposed) { // transpose 180 | for (int Q = NQ_offset, Q_loc = 0; Q_loc < NQ_local; ++Q, ++Q_loc) { 181 | matrix(vij_Q_k1k2(Q_loc)) = matrix(vij_Q_k1k2(Q_loc)).transpose().eval(); 182 | } 183 | } 184 | } 185 | 186 | const ztensor<4>& vij_Q() const { return _vij_Q->object(); } 187 | const ztensor<3>& v0ij_Q() const { return _v0ij_Q; } 188 | const ztensor<3>& v_bar_ij_Q() const { return _v_bar_ij_Q; } 189 | 190 | int wrap(int k1, int k2) { 191 | size_t idx = (k1 >= k2) ? k1 * (k1 + 1) / 2 + k2 : k2 * (k2 + 1) / 2 + k1; // k-pair = (k1, k2) or (k2, k1) 192 | // determine type 193 | if (_bz_utils.symmetry().conj_kpair_list()[idx] != idx) { 194 | idx = _bz_utils.symmetry().conj_kpair_list()[idx]; 195 | } else if (_bz_utils.symmetry().trans_kpair_list()[idx] != idx) { 196 | idx = _bz_utils.symmetry().trans_kpair_list()[idx]; 197 | } 198 | int idx_red = _bz_utils.symmetry().irre_pos_kpair(idx); 199 | return idx_red % _chunk_size; 200 | } 201 | 202 | void reset() { 203 | _current_chunk = -1; 204 | _k0 = -1; 205 | } 206 | 207 | private: 208 | // Coulomb integrals stored in density fitting format 209 | std::shared_ptr _vij_Q; 210 | // G=0 correction to coulomb integral stored in density fitting format for second-order e3xchange diagram 211 | ztensor<3> _v0ij_Q; 212 | ztensor<3> _v_bar_ij_Q; 213 | 214 | bool _exch; 215 | // current leading index 216 | int _k0; 217 | long _current_chunk; 218 | long _chunk_size; 219 | long _NQ; 220 | const bz_utils_t& _bz_utils; 221 | 222 | // base path to integral files 223 | std::string _base_path; 224 | }; 225 | 226 | } // namespace green::mbpt 227 | 228 | #endif // GF2_OLD_DFINTEGRAL_H 229 | -------------------------------------------------------------------------------- /src/green/mbpt/dyson.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 University of Michigan 3 | * 4 | */ 5 | #ifndef SC_DYSON_H 6 | #define SC_DYSON_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "common_defs.h" 14 | 15 | namespace green::mbpt { 16 | 17 | template 18 | auto& extract_local(const T& t) { 19 | if constexpr (std::is_same_v>>) { 20 | return t.object(); 21 | } else { 22 | return t; 23 | } 24 | } 25 | 26 | template 27 | class dyson { 28 | using brillouin_zone_utils = symmetry::brillouin_zone_utils; 29 | 30 | public: 31 | using G = G_type; 32 | using Sigma1 = Sigma1_type; 33 | using Sigma_tau = Sigma_tau_type; 34 | 35 | dyson(const params::params& p); 36 | 37 | virtual ~dyson(){}; 38 | 39 | /** 40 | * Using Dyson equation compute new g_tau for given static (sigma1) and dynamic (sigma_tau) parts of the self-energy 41 | * 42 | * @param g_tau [OUT] new 43 | * @param sigma1 44 | * @param sigma_tau 45 | */ 46 | void compute_G(G& g_tau, Sigma1& sigma1, Sigma_tau& sigma_tau) const; 47 | 48 | /** 49 | * For each matsubara frequency compute eigenvalues of (H + sigma1 + sigma_w) to speedup chemical potetial search 50 | * 51 | * @param sigma1 - static part of the self-energy 52 | * @param sigma_tau - dynamic part of the self-energy 53 | * @param eigenvalues_Sigma_p_F - eigenvalues of (H + sigma1 + sigma_w) 54 | */ 55 | void selfenergy_eigenspectra(const Sigma1& sigma1, const Sigma_tau& sigma_tau, 56 | std::vector>& eigenvalues_Sigma_p_F) const; 57 | 58 | /** 59 | * For a given chemical potetial and eigenspectra of (H + sigma1 + sigma_w) find number of electrons 60 | * 61 | * @param mu - chemical potetial 62 | * @param eigenvalues_Sigma_p_F - eigenspectra of (H + sigma1 + sigma_w) 63 | * @return number of electrons for given parameters 64 | */ 65 | double compute_number_of_electrons(double mu, const std::vector>& eigenvalues_Sigma_p_F) const; 66 | 67 | /** 68 | * From diagonalized Dyson equation find new chemical potential 69 | * @param sigma1 - static part of the self-energy 70 | * @param sigma_tau_s - dynamic part of the self-energy 71 | */ 72 | std::pair find_mu(const Sigma1& sigma1, const Sigma_tau& sigma_tau_s) const; 73 | 74 | /** 75 | * Store additional information for current iteration 76 | * 77 | * @param iter - number of the current iteration 78 | * @param gtau - Green's function to be dumped 79 | * @param s1 - Static part of the self-energy to be dumped 80 | * @param st - Dynamic part of the self-energy to be dumped 81 | * @param result_file - name of the file with results 82 | */ 83 | void dump_iteration(size_t iter, const G_type& gtau, const Sigma1_type&s1, const Sigma_tau_type&st, 84 | const std::string& result_file); 85 | 86 | /** 87 | * For a given static and dynamic parts of a self-energy solve the dyson equation and obtain new 88 | * Green's function. Number of electrons in the local unit-cell will be fixed 89 | * if the `const_density` parameter has been set to true. 90 | * 91 | * @param g - Green's function to be evaluated 92 | * @param sigma1 - static part of a self-energy 93 | * @param sigma_tau - dynamic part of a self-energy 94 | */ 95 | void solve(G& g, Sigma1& sigma1, Sigma_tau& sigma_tau); 96 | 97 | /** 98 | * Compute difference for a target parameter for the current iteration 99 | * 100 | * @param g - Green's function at the current iteration 101 | * @param sigma1 - static part of a self-energy at the current iteration 102 | * @param sigma_tau - dynamic part of a self-energy at the current iteration 103 | */ 104 | double diff(G& g, Sigma1& sigma1, Sigma_tau& sigma_tau); 105 | 106 | const grids::transformer_t& ft() const { return _ft; } 107 | // 108 | const brillouin_zone_utils& bz_utils() const { return _bz_utils; } 109 | const ztensor<4>& S_k() const { return _S_k; } 110 | const ztensor<4>& H_k() const { return _H_k; } 111 | 112 | [[nodiscard]] size_t nao() const { return _nao; } 113 | [[nodiscard]] size_t nso() const { return _nso; } 114 | [[nodiscard]] size_t ns() const { return _ns; } 115 | [[nodiscard]] double mu() const { return _mu; } 116 | double& mu() { return _mu; } 117 | 118 | protected: 119 | // Imaginary time/frequency transform class 120 | grids::transformer_t _ft; 121 | // 122 | brillouin_zone_utils _bz_utils; 123 | // number of Chebyshev polynomials 124 | int _ncheb; 125 | // number of tau points 126 | int _nts; 127 | // number of frequency points 128 | int _nw; 129 | // number of k-points 130 | int _nk; 131 | // number of k-points in the reduced Brillouin zone 132 | int _ink; 133 | // number of spin-orbitals 134 | int _nso; 135 | // number of orbitals 136 | int _nao; 137 | // number of spins 138 | int _ns; 139 | // 140 | bool _X2C; 141 | // chemical potential data 142 | double _mu; 143 | // Number of electrons to be preserved during dyson equation solution 144 | double _nel; 145 | // Current number of electrons 146 | double _nel_found; 147 | // do we need to preserve number of electrons 148 | bool _const_density; 149 | // 150 | double _tol; 151 | // 152 | ztensor<4> _H_k; 153 | ztensor<4> _S_k; 154 | // 155 | double _E_corr{0}; 156 | double _E_hf{0}; 157 | double _E_1b{0}; 158 | double _E_nuc{0}; 159 | 160 | int _verbose; 161 | 162 | private: 163 | /** 164 | * Reads data from the current and the previous iterations and compute the difference 165 | * 166 | * @param iter - current iteration 167 | * @param gtau - Green's function at the current iteration, needed to get density matrix 168 | * @param result_file - file with the simulation results 169 | */ 170 | void print_convergence(size_t iter, const G>au, const std::string& result_file); 171 | }; 172 | 173 | using shared_mem_dyson = dyson>, ztensor<4>, utils::shared_object>>; 174 | using local_mem_dyson = dyson, ztensor<4>, ztensor<5>>; 175 | } // namespace green::mbpt 176 | #endif // SC_DYSON_H 177 | -------------------------------------------------------------------------------- /src/green/mbpt/except.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 University of Michigan 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 5 | * software and associated documentation files (the “Software”), to deal in the Software 6 | * without restriction, including without limitation the rights to use, copy, modify, 7 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so, subject to the following 9 | * conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all copies or 12 | * substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #ifndef GREEN_MBPT_EXCEPT_H 23 | #define GREEN_MBPT_EXCEPT_H 24 | 25 | #include 26 | 27 | namespace green::mbpt { 28 | class mbpt_kernel_error : public std::runtime_error { 29 | public: 30 | explicit mbpt_kernel_error(const std::string& what) : std::runtime_error(what) {} 31 | }; 32 | 33 | class mbpt_wrong_grid : public std::runtime_error { 34 | public: 35 | explicit mbpt_wrong_grid(const std::string& what) : std::runtime_error(what) {} 36 | }; 37 | 38 | class mbpt_chemical_potential_search_failure : public std::runtime_error { 39 | public: 40 | explicit mbpt_chemical_potential_search_failure(const std::string& what) : std::runtime_error(what) {} 41 | }; 42 | 43 | class mbpt_outdated_input : public std::runtime_error { 44 | public: 45 | explicit mbpt_outdated_input(const std::string& what) : std::runtime_error(what) {} 46 | }; 47 | } // namespace green::mbpt 48 | #endif // GREEN_MBPT_EXCEPT_H 49 | -------------------------------------------------------------------------------- /src/green/mbpt/gf2_solver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022 University of Michigan. 3 | * 4 | */ 5 | 6 | #ifndef MPIGF2_DFGF2SOLVER_H 7 | #define MPIGF2_DFGF2SOLVER_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | #include "common_defs.h" 22 | #include "df_integral_t.h" 23 | 24 | namespace green::mbpt { 25 | /** 26 | * @brief This class performs self-energy calculation by means of second-order PT using density fitting 27 | */ 28 | class gf2_solver { 29 | using bz_utils_t = symmetry::brillouin_zone_utils; 30 | using G_type = utils::shared_object>; 31 | using S1_type = ztensor<4>; 32 | using St_type = utils::shared_object>; 33 | 34 | public: 35 | 36 | /** 37 | * 38 | * @param p - command line parameters 39 | * @param tr - time-frequency transform 40 | * @param bz - Brillouin transform 41 | */ 42 | gf2_solver(const params::params& p, const grids::transformer_t& tr, const bz_utils_t& bz) : 43 | _nts(tr.sd().repn_fermi().nts()), _nk(bz.nk()), _ink(bz.ink()), _path(p["dfintegral_file"]), 44 | _ewald(std::filesystem::exists(_path + "/df_ewald.h5")), _bz_utils(bz), 45 | statistics("GF2") { 46 | h5pp::archive ar(p["input_file"]); 47 | ar["params/nao"] >> _nao; 48 | ar["params/nso"] >> _nso; 49 | ar["params/ns"] >> _ns; 50 | ar["params/NQ"] >> _NQ; 51 | ar.close(); 52 | } 53 | 54 | /** 55 | * Solve GF2 equations for Self-energy 56 | * 57 | * @param g_tau - Green's function object 58 | * @param sigma1 - static part of the self-energy 59 | * @param sigma_tau - dynamical part of the self-energy 60 | */ 61 | void solve(G_type& g_tau, S1_type& sigma1, St_type& sigma_tau); 62 | 63 | private: 64 | // dimension of problem (nao*ncell) 65 | size_t _dim; 66 | // number of time steps 67 | size_t _nts; 68 | 69 | size_t _nk; 70 | size_t _ink; 71 | size_t _nao; 72 | size_t _nso; 73 | size_t _ns; 74 | size_t _NQ; 75 | 76 | // Path to H5 file 77 | const std::string _path; 78 | 79 | // references to arrays 80 | ztensor<5> Sigma_local; 81 | 82 | // Current time step Green's function matrix for k1 83 | Eigen::MatrixXcd _G_k1_tmp; 84 | // Current reverse time step Green's function matrix for k2 85 | Eigen::MatrixXcd _Gb_k2_tmp; 86 | // Current time step Green's function matrix for k3 87 | Eigen::MatrixXcd _G_k3_tmp; 88 | 89 | /** 90 | * Read next part of Coulomb integrals for fixed set of k-points 91 | */ 92 | void read_next(const std::array& k); 93 | 94 | // Compute correction into second-order from the divergent G=0 part of the interaction 95 | void compute_2nd_exch_correction(size_t tau_offset, size_t ntau_local, const ztensor<5>& Gr_full_tau); 96 | 97 | void ewald_2nd_order_0_0(size_t tau_offset, size_t ntau_local, const ztensor<5>& Gr_full_tau, MatrixXcd& G1, MatrixXcd& G2, MatrixXcd& G3, MMatrixXcd& Xm_4, 98 | MMatrixXcd& Xm_1, MMatrixXcd& Xm_2, MMatrixXcd& Ym_1, MMatrixXcd& Ym_2, MMatrixXcd& Xm, 99 | MMatrixXcd& Vm); 100 | 101 | void ewald_2nd_order_1_0(size_t tau_offset, size_t ntau_local, const ztensor<5>& Gr_full_tau, MatrixXcd& G1, MatrixXcd& G2, MatrixXcd& G3, MMatrixXcd& Xm_4, 102 | MMatrixXcd& Xm_1, MMatrixXcd& Xm_2, MMatrixXcd& Ym_1, MMatrixXcd& Ym_2, MMatrixXcd& Xm, 103 | MMatrixXcd& Vm); 104 | 105 | void ewald_2nd_order_0_1(size_t tau_offset, size_t ntau_local, const ztensor<5>& Gr_full_tau, MatrixXcd& G1, MatrixXcd& G2, MatrixXcd& G3, MMatrixXcd& Xm_4, 106 | MMatrixXcd& Xm_1, MMatrixXcd& Xm_2, MMatrixXcd& Ym_1, MMatrixXcd& Ym_2, MMatrixXcd& Xm, 107 | MMatrixXcd& Vm); 108 | 109 | // Read next portion of the correction to a coulomb integral 110 | void read_next_correction_0_0(size_t k); 111 | 112 | void read_next_correction_1_0(size_t k1, size_t k2); 113 | 114 | void read_next_correction_0_1(size_t k1, size_t k2); 115 | 116 | /** 117 | * Performs loop over time for fixed set of k-points 118 | */ 119 | void selfenergy_innerloop(size_t tau_offset, size_t ntau_local, const std::array& k, size_t is, const ztensor<5>& Gr_full_tau); 120 | 121 | MatrixXcd extract_G_tau_k(const ztensor<5>& G_tau, size_t t, size_t k_pos, size_t k_red, size_t s) { 122 | int ts_shift = t * G_tau.shape()[1] * G_tau.shape()[2] * _nao * _nao + s * G_tau.shape()[2] * _nao * _nao; 123 | int k_shift = k_pos * _nao * _nao; 124 | CMMatrixXcd tmp(G_tau.data() + ts_shift + k_shift, G_tau.shape()[3], G_tau.shape()[4]); 125 | MatrixXcd G = tmp; 126 | if (_bz_utils.symmetry().conj_list()[k_red] == 1) { 127 | for (size_t i = 0; i < _nao; ++i) { 128 | for (size_t j = 0; j < _nao; ++j) { 129 | G(i, j) = std::conj(G(i, j)); 130 | } 131 | } 132 | } 133 | 134 | return G; 135 | } 136 | 137 | /** 138 | * Performs all possible contractions for i and n indices 139 | */ 140 | void contraction(size_t nao2, size_t nao3, bool eq_spin, bool ew_correct, const Eigen::MatrixXcd& G1, 141 | const Eigen::MatrixXcd& G2, const Eigen::MatrixXcd& G3, MMatrixXcd& Xm_4, MMatrixXcd& Xm_1, MMatrixXcd& Xm_2, 142 | MMatrixXcd& Ym_1, MMatrixXcd& Ym_2, const MMatrixXcd& vm_1, MMatrixXcd& Xm, MMatrixXcd& Vm, MMatrixXcd& Vxm, 143 | MMatrixXcd& Sm); 144 | 145 | /** 146 | * Compute two-electron integrals for the fixed set of k-points using pre-computed fitted densities 147 | * 148 | * @param set of k-points 149 | */ 150 | void setup_integrals(const std::array& k); 151 | 152 | // Pre-computed fitted densities 153 | // To avoid divergence in G=0 we separately compute ewald correction for the divergent part 154 | // Left interaction term 155 | df_integral_t* _coul_int_c_1; 156 | df_integral_t* _coul_int_c_2; 157 | // Right direct term 158 | df_integral_t* _coul_int_c_3; 159 | df_integral_t* _coul_int_c_4; 160 | // Right exchange term 161 | df_integral_t* _coul_int_x_3; 162 | df_integral_t* _coul_int_x_4; 163 | 164 | ztensor<4> vijkl; 165 | ztensor<4> vcijkl; 166 | ztensor<4> vxijkl; 167 | ztensor<4> vxcijkl; 168 | 169 | bool _ewald; 170 | 171 | const bz_utils_t& _bz_utils; 172 | 173 | // 174 | utils::timing statistics; 175 | }; 176 | } // namespace green::mbpt 177 | 178 | #endif // MPIGF2_DFGF2SOLVER_H 179 | -------------------------------------------------------------------------------- /src/green/mbpt/gw_solver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022 University of Michigan. 3 | * 4 | */ 5 | 6 | #ifndef GREEN_GW_SOLVER_T_H 7 | #define GREEN_GW_SOLVER_T_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | // #include "gscf/gscf_cuhf_solver_t.h" 20 | // #include "transformer_t.h" 21 | #include "common_defs.h" 22 | #include "df_integral_t.h" 23 | #include "mbpt_q0_utils_t.h" 24 | 25 | #include "kernels.h" 26 | #include "kernel_factory.h" 27 | 28 | namespace green::mbpt { 29 | /** 30 | * @brief GWSolver class performs self-energy calculation by means of GW approximation using density fitting 31 | */ 32 | class gw_solver { 33 | using bz_utils_t = symmetry::brillouin_zone_utils; 34 | using G_type = utils::shared_object>; 35 | using S1_type = ztensor<4>; 36 | using St_type = utils::shared_object>; 37 | 38 | public: 39 | /** 40 | * Class constructor 41 | * 42 | * @param p -- simulation parameters 43 | * @param ft -- imaginary time transformer 44 | * @param Gk -- Green's function in (tau, kcell, nao, nao) domain 45 | * @param Sigma -- Self-energy in (tau, kcell, nao, nao) domain 46 | * @param bz_utils -- Brillouin zone utilities 47 | * @param second_only -- Whether do GW or only second-order direct diagram 48 | */ 49 | gw_solver(const params::params& p, const grids::transformer_t& ft, const bz_utils_t& bz_utils, const ztensor<4>& S_k) { 50 | h5pp::archive ar(p["input_file"]); 51 | size_t nao, nso, ns, NQ; 52 | bool X2C; 53 | ar["params/nao"] >> nao; 54 | ar["params/nso"] >> nso; 55 | ar["params/ns"] >> ns; 56 | ar["params/NQ"] >> NQ; 57 | ar.close(); 58 | X2C = nao != nso; 59 | std::tie(_kernel, _callback) = kernels::gw_kernel_factory::get_kernel(X2C, p, nao, nso, ns, NQ, ft, bz_utils, S_k); 60 | } 61 | 62 | /** 63 | * Solve GW equations for Self-energy 64 | */ 65 | void solve(G_type& g, S1_type&, St_type& sigma_tau); 66 | 67 | private: 68 | std::shared_ptr _kernel; 69 | std::function _callback; 70 | }; 71 | 72 | } // namespace green::mbpt 73 | 74 | #endif // GF2_GW_SOLVER_T_H 75 | -------------------------------------------------------------------------------- /src/green/mbpt/hf_solver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022 University of Michigan. 3 | * 4 | */ 5 | 6 | #ifndef MPIGF2_GF2SOLVER_H 7 | #define MPIGF2_GF2SOLVER_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "common_defs.h" 16 | #include "df_integral_t.h" 17 | #include "kernel_factory.h" 18 | #include "kernels.h" 19 | 20 | namespace green::mbpt { 21 | 22 | class hf_solver { 23 | using bz_utils_t = symmetry::brillouin_zone_utils; 24 | using callback_t = std::function(const ztensor<4>&)>; 25 | 26 | public: 27 | hf_solver(const params::params& p, const bz_utils_t& bz_utils, const ztensor<4>& S_k) { 28 | size_t NQ, nao, nso, ns; 29 | double madelung; 30 | h5pp::archive ar(p["input_file"]); 31 | ar["params/NQ"] >> NQ; 32 | ar["params/nao"] >> nao; 33 | ar["params/nso"] >> nso; 34 | ar["params/ns"] >> ns; 35 | ar["HF/madelung"] >> madelung; 36 | ar.close(); 37 | bool X2C = nso != nao; 38 | _spin_prefactor = (ns == 2 or X2C) ? -1.0 : -2.0; 39 | if (ns != 1 and X2C) { 40 | throw std::logic_error("For GSCF methods, \"ns\" has to be 1."); 41 | } 42 | std::tie(_kernel,_callback) = kernels::hf_kernel_factory::get_kernel(X2C, p, nao, nso, ns, NQ, madelung, bz_utils, S_k); 43 | } 44 | void solve(utils::shared_object>& G, ztensor<4>& Sigma1, utils::shared_object>& Sigma_tau); 45 | 46 | protected: 47 | double _spin_prefactor; 48 | 49 | std::shared_ptr _kernel; 50 | callback_t _callback; 51 | }; 52 | 53 | } // namespace green::mbpt 54 | 55 | #endif // MPIGF2_GF2SOLVER_H 56 | -------------------------------------------------------------------------------- /src/green/mbpt/kernel_factory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 University of Michigan 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 5 | * software and associated documentation files (the “Software”), to deal in the Software 6 | * without restriction, including without limitation the rights to use, copy, modify, 7 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so, subject to the following 9 | * conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all copies or 12 | * substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #ifndef GREEN_MBPT_KERNEL_FACTORY_H 23 | #define GREEN_MBPT_KERNEL_FACTORY_H 24 | 25 | #include "kernels.h" 26 | #include "custom_kernels.h" 27 | 28 | #define CUSTOM_GW_KERNEL_CALL(NS, ENUM, X2C, p, nao, nso, ns, NQ, ft, bz_utils, S_k) \ 29 | if (p["kernel"].as() == ENUM ) { \ 30 | return NS::custom_gw_kernel(X2C, p, nao, nso, ns, NQ, ft, bz_utils, S_k); \ 31 | } 32 | 33 | #define CUSTOM_HF_KERNEL_CALL(NS, ENUM, X2C, p, nao, nso, ns, NQ, madelung, bz_utils, S_k) \ 34 | if (p["kernel"].as() == ENUM ) { \ 35 | return NS::custom_hf_kernel(X2C, p, nao, nso, ns, NQ, madelung, bz_utils, S_k); \ 36 | } 37 | 38 | 39 | namespace green::mbpt::kernels { 40 | class hf_kernel_factory { 41 | using bz_utils_t = symmetry::brillouin_zone_utils; 42 | using x_type = ztensor<4>; 43 | 44 | public: 45 | static std::tuple, std::function> get_kernel(bool X2C, const params::params& p, 46 | size_t nao, size_t nso, size_t ns, 47 | size_t NQ, double madelung, 48 | const bz_utils_t& bz_utils, 49 | const ztensor<4>& S_k) { 50 | if (p["kernel"].as() == CPU) { 51 | if (X2C) { 52 | std::shared_ptr kernel(new hf_x2c_cpu_kernel(p, nao, nso, ns, NQ, madelung, bz_utils, S_k)); 53 | std::function callback = [kernel](const x_type& dm) -> x_type { 54 | return static_cast(kernel.get())->solve(dm); 55 | }; 56 | return std::tuple{kernel, callback}; 57 | } 58 | std::shared_ptr kernel(new hf_scalar_cpu_kernel(p, nao, nso, ns, NQ, madelung, bz_utils, S_k)); 59 | std::function callback = [kernel](const x_type& dm) -> x_type { 60 | return static_cast(kernel.get())->solve(dm); 61 | }; 62 | return std::tuple{kernel, callback}; 63 | } 64 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_0 65 | CUSTOM_HF_KERNEL_CALL(GREEN_CUSTOM_KERNEL_NS_0, GREEN_CUSTOM_KERNEL_ENUM_0, X2C, p, nao, nso, ns, NQ, madelung, bz_utils, S_k); 66 | #endif 67 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_1 68 | CUSTOM_HF_KERNEL_CALL(GREEN_CUSTOM_KERNEL_NS_1, GREEN_CUSTOM_KERNEL_ENUM_1, X2C, p, nao, nso, ns, NQ, madelung, bz_utils, S_k); 69 | #endif 70 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_2 71 | CUSTOM_HF_KERNEL_CALL(GREEN_CUSTOM_KERNEL_NS_2, GREEN_CUSTOM_KERNEL_ENUM_2, X2C, p, nao, nso, ns, NQ, madelung, bz_utils, S_k); 72 | #endif 73 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_3 74 | CUSTOM_HF_KERNEL_CALL(GREEN_CUSTOM_KERNEL_NS_3, GREEN_CUSTOM_KERNEL_ENUM_3, X2C, p, nao, nso, ns, NQ, madelung, bz_utils, S_k); 75 | #endif 76 | throw mbpt_kernel_error("Cannot determine HF kernel"); 77 | } 78 | }; 79 | 80 | class gw_kernel_factory { 81 | using bz_utils_t = symmetry::brillouin_zone_utils; 82 | using G_type = utils::shared_object>; 83 | 84 | public: 85 | static std::tuple, std::function> get_kernel( 86 | bool X2C, const params::params& p, size_t nao, size_t nso, size_t ns, size_t NQ, const grids::transformer_t& ft, 87 | const bz_utils_t& bz_utils, const ztensor<4>& S_k) { 88 | if (p["kernel"].as() == CPU) { 89 | std::shared_ptr kernel(new gw_cpu_kernel(p, nao, nso, ns, NQ, ft, bz_utils, S_k, X2C)); 90 | std::function callback = [kernel](G_type& g, G_type& s) { static_cast(kernel.get())->solve(g, s); }; 91 | return std::tuple{kernel, callback}; 92 | } 93 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_0 94 | CUSTOM_GW_KERNEL_CALL(GREEN_CUSTOM_KERNEL_NS_0, GREEN_CUSTOM_KERNEL_ENUM_0, X2C, p, nao, nso, ns, NQ, ft, bz_utils, S_k); 95 | #endif 96 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_1 97 | CUSTOM_GW_KERNEL_CALL(GREEN_CUSTOM_KERNEL_NS_1, GREEN_CUSTOM_KERNEL_ENUM_1, X2C, p, nao, nso, ns, NQ, ft, bz_utils, S_k); 98 | #endif 99 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_2 100 | CUSTOM_GW_KERNEL_CALL(GREEN_CUSTOM_KERNEL_NS_2, GREEN_CUSTOM_KERNEL_ENUM_2, X2C, p, nao, nso, ns, NQ, ft, bz_utils, S_k); 101 | #endif 102 | #ifdef GREEN_CUSTOM_KERNEL_HEADER_3 103 | CUSTOM_GW_KERNEL_CALL(GREEN_CUSTOM_KERNEL_NS_3, GREEN_CUSTOM_KERNEL_ENUM_3, X2C, p, nao, nso, ns, NQ, ft, bz_utils, S_k); 104 | #endif 105 | throw mbpt_kernel_error("Cannot determine GW kernel"); 106 | } 107 | }; 108 | } // namespace green::mbpt::kernels 109 | 110 | #endif // GREEN_MBPT_KERNEL_FACTORY_H 111 | -------------------------------------------------------------------------------- /src/green/mbpt/kernels.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 University of Michigan 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 5 | * software and associated documentation files (the “Software”), to deal in the Software 6 | * without restriction, including without limitation the rights to use, copy, modify, 7 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so, subject to the following 9 | * conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all copies or 12 | * substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #ifndef GREEN_MBPT_GW_KERNEL_H 23 | #define GREEN_MBPT_GW_KERNEL_H 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "common_defs.h" 31 | #include "df_integral_t.h" 32 | #include "except.h" 33 | #include "mbpt_q0_utils_t.h" 34 | 35 | namespace green::mbpt::kernels { 36 | class gw_cpu_kernel { 37 | using bz_utils_t = symmetry::brillouin_zone_utils; 38 | using G_type = utils::shared_object>; 39 | using St_type = utils::shared_object>; 40 | 41 | public: 42 | gw_cpu_kernel(const params::params& p, size_t nao, size_t nso, size_t ns, size_t NQ, const grids::transformer_t& ft, 43 | const bz_utils_t& bz_utils, const ztensor<4>& S_k, bool X2C = false) : 44 | _beta(p["BETA"]), _nts(ft.sd().repn_fermi().nts()), _nts_b(ft.sd().repn_bose().nts()), _ni(ft.sd().repn_fermi().ni()), 45 | _ni_b(ft.sd().repn_bose().ni()), _nw(ft.sd().repn_fermi().nw()), _nw_b(ft.sd().repn_bose().nw()), _nk(bz_utils.nk()), 46 | _ink(bz_utils.ink()), _nao(nao), _nso(nso), _ns(ns), _NQ(NQ), _X2C(X2C), _p_sp(p["P_sp"]), _sigma_sp(p["Sigma_sp"]), 47 | _ft(ft), _bz_utils(bz_utils), _path(p["dfintegral_file"]), statistics("GW"), 48 | _q0_utils(bz_utils.ink(), 0, S_k, _path, p["q0_treatment"]), 49 | // _P0_tilde(0, 0, 0, 0), 50 | _eps_inv_wq(ft.wsample_bose().size(), bz_utils.ink()), 51 | _coul_int1(nullptr) { 52 | _q0_utils.resize(_NQ); 53 | } 54 | 55 | void solve(G_type& g, St_type& sigma_tau); 56 | 57 | private: 58 | double _beta; 59 | size_t _nts; 60 | size_t _nts_b; 61 | size_t _ni; 62 | size_t _ni_b; 63 | size_t _nw; 64 | size_t _nw_b; 65 | 66 | size_t _nk; 67 | size_t _ink; 68 | size_t _nao; 69 | size_t _nso; 70 | size_t _ns; 71 | size_t _NQ; 72 | bool _X2C; 73 | 74 | bool _p_sp; 75 | bool _sigma_sp; 76 | 77 | const grids::transformer_t& _ft; 78 | const bz_utils_t& _bz_utils; 79 | // Path to integral files 80 | const std::string _path; 81 | utils::timing statistics; 82 | // 83 | mbpt_q0_utils_t _q0_utils; 84 | // Array for the polarization bubble and for screened interaction 85 | // ztensor<4> _P0_tilde; 86 | // Dielectric function inverse in the plane-wave basis with G = G' = 0 87 | ztensor<2> _eps_inv_wq; 88 | // Pre-computed fitted densities 89 | // This object reads 3-index tensors into Vij_Q 90 | df_integral_t* _coul_int1; 91 | 92 | private: 93 | /** 94 | * Evaluate self-energy contribution from P^{q_ir} 95 | * @param q_ir - [INPUT] momentum index of polarization and screened interaction 96 | */ 97 | void selfenergy_innerloop(size_t q_ir, const G_type& G_fermi, St_type& Sigma_fermi_s, 98 | utils::shared_object>& P0_tilde_s, utils::shared_object>& Pw_tilde_s); 99 | 100 | /** 101 | * Read next part of Coulomb integrals in terms of 3-index tensors for fixed set of k-points 102 | * @param k - [INPUT] (k1, 0, q, k1+q) or (k1, q, 0, k1-q) 103 | */ 104 | void read_next(const std::array& k); 105 | 106 | /** 107 | * Evaluate polarization function P for a given job portion (maybe a single k-point or a set of k-points), 108 | * in desired precision 109 | */ 110 | template 111 | void eval_P0_tilde(const std::array& k, const G_type& G, ztensor<4>& P0_tilde_s, size_t local_tau, 112 | size_t tau_offset); 113 | 114 | template 115 | void assign_G(size_t k, size_t t, size_t s, const ztensor<5>& G_fermi, MatrixX& G_k); 116 | template 117 | void assign_G_nso(size_t k, size_t t, size_t s1, size_t s2, const ztensor<5>& G_fermi, MatrixX& G_k); 118 | 119 | /** 120 | * Contraction of polarization function for given tau and k-point 121 | * @param t - [INPUT] imaginary time 122 | * @param k - [INPUT] [k1, k2, k1, k2] 123 | * @param q - [INPUT] k1 - k2 124 | */ 125 | template 126 | void P0_contraction(const MatrixX& Gb_k1, const MatrixX& G_k1q, MMatrixX& vm, MMatrixX& VVm, 127 | MMatrixX& VVmm, MMatrixX& X1m, MMatrixX& vmm, MMatrixX& X2m, MMatrixX& X1mm, 128 | MMatrixX& X2mm, MMatrixXcd& P0, double& prefactor); 129 | 130 | /** 131 | * Symmetrize polarization function by ultilizing P0(t) = P0(beta-t) 132 | */ 133 | void symmetrize_P0(ztensor<4>& P0_tilde, size_t local_tau, size_t tau_offset); 134 | 135 | /** 136 | * Solve Dyson-like equation for screened interaction W using Chebyshev convolution 137 | * Writes the resulting P_tilde(tau) in_P0_tilde; 138 | */ 139 | void eval_P_tilde(int q_ir, utils::shared_object>& P0_tilde_s, utils::shared_object>& Pw_s); 140 | 141 | /** 142 | * Evaluate self-energy 143 | */ 144 | template 145 | void eval_selfenergy(const std::array& k, const G_type& G_fermi, St_type& Sigma_fermi_s, ztensor<4>& P0_tilde); 146 | 147 | /** 148 | * Contraction for evaluating self-energy for given tau and k-point 149 | */ 150 | template 151 | void selfenergy_contraction(const std::array& k, const MatrixX& G_k1q, MMatrixX& vm, 152 | MMatrixX& Y1m, MMatrixX& Y1mm, MMatrixX& Y2mm, MMatrixX& X2m, 153 | MMatrixX& Y2mmm, MMatrixX& X2mm, MatrixX& P, MatrixXcd& Sm_ts); 154 | }; 155 | 156 | class hf_kernel { 157 | public: 158 | using bz_utils_t = symmetry::brillouin_zone_utils; 159 | using dm_type = ztensor<4>; 160 | using S1_type = ztensor<4>; 161 | 162 | hf_kernel(const params::params& p, size_t nao, size_t nso, size_t ns, size_t NQ, double madelung, const bz_utils_t& bz_utils, 163 | const ztensor<4>& S_k) : 164 | _nao(nao), _nso(nso), _nk(bz_utils.nk()), _ink(bz_utils.ink()), _ns(ns), _NQ(NQ), _madelung(madelung), 165 | _bz_utils(bz_utils), _S_k(S_k), _hf_path(p["dfintegral_hf_file"]), statistics("Hartree Fock"){}; 166 | virtual ~hf_kernel() = default; 167 | 168 | protected: 169 | // number of atomic orbitals per cell 170 | size_t _nao; 171 | size_t _nso; 172 | // number of cells for GF2 loop 173 | size_t _nk; 174 | // number of k-point after time-reversal symmetry 175 | size_t _ink; 176 | // number of spins 177 | size_t _ns; 178 | // auxiliraly basis size 179 | size_t _NQ; 180 | // madelung constant 181 | double _madelung; 182 | const bz_utils_t& _bz_utils; 183 | // overlap 184 | const ztensor<4>& _S_k; 185 | const std::string _hf_path; 186 | utils::timing statistics; 187 | }; 188 | 189 | class hf_scalar_cpu_kernel final : public hf_kernel { 190 | public: 191 | hf_scalar_cpu_kernel(const params::params& p, size_t nao, size_t nso, size_t ns, size_t NQ, double madelung, 192 | const bz_utils_t& bz_utils, const ztensor<4>& S_k) : 193 | hf_kernel(p, nao, nso, ns, NQ, madelung, bz_utils, S_k) {} 194 | S1_type solve(const dm_type& dm); 195 | }; 196 | 197 | class hf_x2c_cpu_kernel : public hf_kernel { 198 | public: 199 | hf_x2c_cpu_kernel(const params::params& p, size_t nao, size_t nso, size_t ns, size_t NQ, double madelung, 200 | const bz_utils_t& bz_utils, const ztensor<4>& S_k) : 201 | hf_kernel(p, nao, nso, ns, NQ, madelung, bz_utils, S_k) {} 202 | S1_type solve(const dm_type& dm); 203 | 204 | private: 205 | MatrixXcd compute_exchange(int ik, ztensor<3>& dm_s1_s2, ztensor<3>& dm_ms1_ms2, ztensor<3>& v, df_integral_t& coul_int1, 206 | ztensor<3>& Y, MMatrixXcd& Ym, MMatrixXcd& Ymm, ztensor<3>& Y1, MMatrixXcd& Y1m, MMatrixXcd& Y1mm, 207 | MMatrixXcd& vmm, ztensor<3>& v2, MMatrixXcd& v2m, MMatrixXcd& v2mm, size_t NQ_local, size_t NQ_offset); 208 | MatrixXcd compute_exchange_ab(int ik, ztensor<3>& dm_ab, ztensor<3>& v, df_integral_t& coul_int1, ztensor<3>& Y, 209 | MMatrixXcd& Ym, MMatrixXcd& Ymm, ztensor<3>& Y1, MMatrixXcd& Y1m, MMatrixXcd& Y1mm, 210 | MMatrixXcd& vmm, ztensor<3>& v2, MMatrixXcd& v2m, MMatrixXcd& v2mm, size_t NQ_local, size_t NQ_offset); 211 | }; 212 | } // namespace green::mbpt::kernels 213 | 214 | #endif // GREEN_MBPT_GW_KERNEL_H 215 | -------------------------------------------------------------------------------- /src/green/mbpt/mbpt_q0_utils_t.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022 University of Michigan. 3 | * 4 | */ 5 | 6 | #ifndef GF2_MBPT_Q0_UTILS_T_H 7 | #define GF2_MBPT_Q0_UTILS_T_H 8 | 9 | #include 10 | 11 | #include "common_defs.h" 12 | #include 13 | 14 | namespace green::mbpt { 15 | // TODO Merge two different corrections into this class 16 | class mbpt_q0_utils_t { 17 | public: 18 | mbpt_q0_utils_t(size_t ink, size_t NQ, const ztensor<4>&S_k, const std::string & path, sigma_q0_treatment_e q0_treatment): 19 | _ink(ink), _S_k(S_k), _q_abs(ink), _q0_treatment(q0_treatment) { 20 | if (_q0_treatment == extrapolate) { 21 | std::string Aq_path = path + "/AqQ.h5"; 22 | // Read _Aq, madelung constant 23 | if (std::filesystem::exists(Aq_path)) { 24 | green::h5pp::archive int_file(Aq_path, "r"); 25 | int_file["AqQ"] >> _AqQ; 26 | int_file["q_abs"] >> _q_abs; 27 | int_file["madelung"] >> _madelung; 28 | int_file.close(); 29 | _NQ = _AqQ.shape()[1]; 30 | //check_Aq(); 31 | } else { 32 | std::cout << "## Warning: " << Aq_path << " is not found! Extrapolation treatment for GW self-energy will be disabled." << std::endl; 33 | _q0_treatment = ignore_G0; 34 | } 35 | } 36 | } 37 | 38 | void resize(size_t NQ) { 39 | _NQ = NQ; 40 | } 41 | 42 | void aux_to_PW_00(ztensor<4> &X_aux, ztensor<2> &X_PW_00, size_t iq); 43 | void check_AqQ(); 44 | 45 | void etrapolate_dielectric_inv_q0(); 46 | std::complex extrapolate_q0(std::complex *eps_q_inv_wn_ptr, size_t fit_order, double q_max = 1.0, bool debug = false); 47 | void polyfit(double *x, double *y, size_t fit_order, size_t num_sample, MatrixXd &c); 48 | std::vector filter_q_abs(double q_max = 1.0); 49 | 50 | /** 51 | * Apply the extrapolated GW finite-size correction 52 | */ 53 | void GW_q0_correction(ztensor<2> &eps_inv_wq, ztensor_view<5> &Sigma, ztensor_view<5> &Gtau, 54 | const grids::transformer_t &ft, bool X2C, 55 | size_t myid, size_t intranode_rank, size_t intranode_size, MPI_Win win_Sigma); 56 | 57 | /** 58 | * Contractions of the extrapolated self-energy finite-size correction 59 | */ 60 | void apply_q0_correction(ztensor<2> &eps_q0_inv_t, ztensor_view<5> &Sigma, ztensor_view<5> &G_tau, 61 | size_t intranode_rank, size_t intranode_size, MPI_Win win_Sigma); 62 | /** 63 | * Two-component version of contractions 64 | */ 65 | void apply_q0_correction_2C(ztensor<2> &eps_q0_inv_t, ztensor_view<5> &Sigma, ztensor_view<5> &G_tau, 66 | size_t intranode_rank, size_t intranode_size, MPI_Win win_Sigma); 67 | 68 | 69 | sigma_q0_treatment_e _q0_treatment; 70 | size_t _ink; 71 | size_t _NQ; 72 | 73 | ztensor<2> _AqQ; 74 | const ztensor<4> &_S_k; 75 | std::vector _q_abs; 76 | // Madelung constant 77 | double _madelung; 78 | 79 | double madelung() const {return _madelung;} 80 | sigma_q0_treatment_e q0_treatment() const {return _q0_treatment;} 81 | const ztensor<2> &AqQ() const {return _AqQ;} 82 | }; 83 | } 84 | 85 | 86 | #endif //GF2_MBPT_Q0_UTILS_T_H 87 | -------------------------------------------------------------------------------- /src/green/mbpt/mbpt_run.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 University of Michigan 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 5 | * software and associated documentation files (the “Software”), to deal in the Software 6 | * without restriction, including without limitation the rights to use, copy, modify, 7 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so, subject to the following 9 | * conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all copies or 12 | * substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #ifndef MBPT_MBPT_RUN_H 23 | #define MBPT_MBPT_RUN_H 24 | 25 | #include 26 | #include 27 | 28 | #include "common_defs.h" 29 | #include "dyson.h" 30 | #include "gf2_solver.h" 31 | #include "gw_solver.h" 32 | #include "hf_solver.h" 33 | 34 | namespace green::mbpt { 35 | 36 | inline void read_hartree_fock_selfenergy(const params::params& p, 37 | const symmetry::brillouin_zone_utils& bz, 38 | sc::ztensor<4>& Sigma1) { 39 | h5pp::archive ar(p["input_file"]); 40 | std::array shape = Sigma1.shape(); 41 | shape[1] = bz.nk(); 42 | ztensor<4> tmp(shape); 43 | ztensor<4> tmp2(shape); 44 | ar["HF/Fock-k"] >> tmp.reshape(shape + 1).view(); 45 | ar["HF/H-k"] >> tmp2.reshape(shape + 1).view(); 46 | tmp -= tmp2; 47 | for (size_t is = 0; is < Sigma1.shape()[0]; ++is) { 48 | Sigma1(is) << bz.full_to_ibz(tmp(is)); 49 | } 50 | } 51 | 52 | template 53 | tensor, N> transform_to_hs(const tensor& in, const ztensor<2>& tr) { 54 | size_t dim_rest = std::accumulate(in.shape().begin() + 1, in.shape().end(), 1ul, std::multiplies()); 55 | size_t in_1 = in.shape()[0]; 56 | size_t out_1 = tr.shape()[0]; 57 | std::array out_shape = in.shape(); 58 | out_shape[0] = out_1; 59 | ztensor out(out_shape); 60 | CMMatrixXcd in_m(in.data(), in_1, dim_rest); 61 | MMatrixXcd out_m(out.data(), out_1, dim_rest); 62 | out_m = matrix(tr) * in_m; 63 | return out; 64 | } 65 | 66 | inline void compute_S_sqrt(const ztensor<3>& Sk, ztensor<3>& Sk_12_inv) { 67 | size_t ink = Sk.shape()[0]; 68 | size_t nso = Sk.shape()[1]; 69 | using Matrixcd = Eigen::Matrix, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>; 70 | Eigen::SelfAdjointEigenSolver solver(nso); 71 | Eigen::FullPivLU lusolver(nso, nso); 72 | for (size_t ik = 0; ik < ink; ++ik) { 73 | Matrixcd S = matrix(Sk(ik)); 74 | solver.compute(S); 75 | matrix(Sk_12_inv(ik)) = 76 | solver.eigenvectors() * (solver.eigenvalues().cwiseSqrt().asDiagonal()) * solver.eigenvectors().adjoint(); 77 | matrix(Sk_12_inv(ik)) = lusolver.compute(matrix(Sk_12_inv(ik))).inverse().eval(); 78 | } 79 | } 80 | 81 | template 82 | void wannier_interpolation(const Dyson& dyson_solver, const ztensor<4>& sigma_1, 83 | const utils::shared_object>& sigma_tau, const h5pp::archive& input, 84 | const std::string& results_file) { 85 | using tau_hs_t = utils::shared_object>; 86 | auto [nel, mu] = dyson_solver.find_mu(sigma_1, sigma_tau); 87 | // Init arrays 88 | dtensor<2> kmesh_hs; 89 | dtensor<2> rmesh; 90 | ztensor<3> Hk_hs; 91 | ztensor<3> Sk_hs; 92 | input["high_symm_path/k_mesh"] >> kmesh_hs; 93 | input["high_symm_path/r_mesh"] >> rmesh; 94 | input["high_symm_path/Hk"] >> Hk_hs; 95 | input["high_symm_path/Sk"] >> Sk_hs; 96 | size_t nts = sigma_tau.object().shape()[0]; 97 | size_t ns = sigma_tau.object().shape()[1]; 98 | size_t ink = sigma_tau.object().shape()[2]; 99 | size_t nso = sigma_tau.object().shape()[3]; 100 | size_t nw = nts - 2; 101 | size_t nk = dyson_solver.bz_utils().nk(); 102 | size_t hs_nk = kmesh_hs.shape()[0]; 103 | ztensor<3> Sigma_w(ink, nso, nso); 104 | ztensor<2> G_w(nso, nso); 105 | ztensor<2> G_w_hs(nso, nso); 106 | ztensor<2> transform(hs_nk, nk); 107 | ztensor<3> Sk_hs_12_inv(Sk_hs.shape()); 108 | // exponential from r to k_hs 109 | ztensor<2> exp_kr(hs_nk, rmesh.shape()[0]); 110 | // exponential from k to r 111 | ztensor<2> exp_rk(rmesh.shape()[0], nk); 112 | // (nts, ns, nk_hs, nao) 113 | tau_hs_t g_tau_hs(nts, ns, kmesh_hs.shape()[0], nso); 114 | tau_hs_t g_omega_hs(nw, ns, kmesh_hs.shape()[0], nso); 115 | // Compute transformation matricies 116 | for (size_t ir = 0; ir < rmesh.shape()[0]; ++ir) { 117 | auto r = rmesh(ir); 118 | for (size_t ik = 0; ik < nk; ++ik) { 119 | auto k = dyson_solver.bz_utils().mesh()(ik); 120 | double rk = std::inner_product(r.begin(), r.end(), k.begin(), 0.0); 121 | exp_rk(ir, ik) = std::exp(std::complex(0, 2 * rk * M_PI)); 122 | } 123 | } 124 | for (size_t ik_hs = 0; ik_hs < hs_nk; ++ik_hs) { 125 | auto k = kmesh_hs(ik_hs); 126 | for (size_t ir = 0; ir < rmesh.shape()[0]; ++ir) { 127 | auto r = rmesh(ir); 128 | double rk = std::inner_product(r.begin(), r.end(), k.begin(), 0.0); 129 | exp_kr(ik_hs, ir) = std::exp(std::complex(0, -2 * rk * M_PI)); 130 | } 131 | } 132 | 133 | matrix(transform) = matrix(exp_kr) * matrix(exp_rk) / double(nk); 134 | 135 | ztensor<4> Sigma_1_fbz(ns, hs_nk, nso, nso); 136 | ztensor<3> Sigma_w_fbz(hs_nk, nso, nso); 137 | // Compute orthogonalization transforamtion matrix 138 | compute_S_sqrt(Sk_hs, Sk_hs_12_inv); 139 | Eigen::FullPivLU lusolver(nso, nso); 140 | // Interpolate G onto a new grid and perform symmetric orthogonalization 141 | g_omega_hs.fence(); 142 | for (int iws = utils::context.global_rank; iws < ns * nw; iws += utils::context.global_size) { 143 | int iw = iws / ns; 144 | int is = iws % ns; 145 | Sigma_w.set_zero(); 146 | dyson_solver.ft().tau_to_omega_ws(sigma_tau.object(), Sigma_w, iw, is); 147 | Sigma_1_fbz(is) << transform_to_hs(dyson_solver.bz_utils().ibz_to_full(sigma_1(is)), transform); 148 | Sigma_w_fbz << transform_to_hs(dyson_solver.bz_utils().ibz_to_full(Sigma_w), transform); 149 | for (int ik = 0; ik < hs_nk; ++ik) { 150 | auto muomega = dyson_solver.ft().wsample_fermi()(iw) * 1.0i + mu; 151 | 152 | matrix(G_w) = matrix(Sk_hs_12_inv(ik)) * 153 | (muomega * matrix(Sk_hs(ik)) - matrix(Hk_hs(ik)) - matrix(Sigma_1_fbz(is, ik)) - matrix(Sigma_w_fbz(ik))) * 154 | matrix(Sk_hs_12_inv(ik)); 155 | matrix(G_w_hs) = lusolver.compute(matrix(G_w)).inverse().eval(); 156 | for (size_t i = 0; i < nso; ++i) { 157 | g_omega_hs.object()(iw, is, ik, i) = G_w_hs(i, i); 158 | } 159 | } 160 | } 161 | g_omega_hs.fence(); 162 | MPI_Datatype dt_matrix = utils::create_matrix_datatype>(nso * nso); 163 | MPI_Op matrix_sum_op = utils::create_matrix_operation>(); 164 | g_omega_hs.fence(); 165 | if (!utils::context.node_rank) { 166 | utils::allreduce(MPI_IN_PLACE, g_omega_hs.object().data(), g_omega_hs.object().size() / (nso * nso), dt_matrix, 167 | matrix_sum_op, utils::context.internode_comm); 168 | } 169 | g_omega_hs.fence(); 170 | g_tau_hs.fence(); 171 | if (!utils::context.node_rank) dyson_solver.ft().omega_to_tau(g_omega_hs.object(), g_tau_hs.object(), 1); 172 | g_tau_hs.fence(); 173 | MPI_Type_free(&dt_matrix); 174 | MPI_Op_free(&matrix_sum_op); 175 | if (!utils::context.global_rank) { 176 | h5pp::archive res(results_file, "w"); 177 | res["G_tau_hs/data"] << g_tau_hs.object(); 178 | res["G_tau_hs/mesh"] << dyson_solver.ft().sd().repn_fermi().tsample(); 179 | res["Sigma_1_hs"] << Sigma_1_fbz; 180 | res["Hk_hs"] << Hk_hs; 181 | res["Sk_hs"] << Sk_hs; 182 | res.close(); 183 | } 184 | MPI_Barrier(utils::context.global); 185 | } 186 | 187 | inline void sc_job(sc::sc_loop& sc, const params::params& p, scf_type type, shared_mem_dyson& dyson, 188 | utils::shared_object>& G_tau, utils::shared_object>& Sigma_tau, ztensor<4>& Sigma1) { 189 | read_hartree_fock_selfenergy(p, dyson.bz_utils(), Sigma1); 190 | G_tau.fence(); 191 | if (!utils::context.node_rank) G_tau.object().set_zero(); 192 | G_tau.fence(); 193 | Sigma_tau.fence(); 194 | if (!utils::context.node_rank) Sigma_tau.object().set_zero(); 195 | Sigma_tau.fence(); 196 | // Hartree-Fock solver is used by all perturbation solvers. 197 | hf_solver hf(p, dyson.bz_utils(), dyson.S_k()); 198 | switch (type) { 199 | case HF: { 200 | sc.solve(hf, dyson.H_k(), dyson.S_k(), G_tau, Sigma1, Sigma_tau); 201 | break; 202 | } 203 | case GW: { 204 | gw_solver gw(p, dyson.ft(), dyson.bz_utils(), dyson.S_k()); 205 | sc::composition_solver cs(hf, gw); 206 | sc.solve(cs, dyson.H_k(), dyson.S_k(), G_tau, Sigma1, Sigma_tau); 207 | break; 208 | } 209 | case GF2: { 210 | gf2_solver gf2(p, dyson.ft(), dyson.bz_utils()); 211 | sc::composition_solver cs(hf, gf2); 212 | sc.solve(cs, dyson.H_k(), dyson.S_k(), G_tau, Sigma1, Sigma_tau); 213 | break; 214 | } 215 | default: { 216 | break; 217 | } 218 | } 219 | } 220 | 221 | inline void winter_job(sc::sc_loop& sc, const params::params& p, shared_mem_dyson& dyson, 222 | utils::shared_object>& g0_tau, utils::shared_object>& sigma_tau, 223 | ztensor<4>& sigma1) { 224 | h5pp::archive input(p["input_file"]); 225 | if (input.has_group("high_symm_path")) { 226 | if (!utils::context.global_rank) std::cout << "Running Wannier interpolation" << std::endl; 227 | sc::read_results(dyson.mu(), g0_tau, sigma1, sigma_tau, p["results_file"]); 228 | wannier_interpolation(dyson, sigma1, sigma_tau, input, p["high_symmetry_output_file"]); 229 | } 230 | input.close(); 231 | } 232 | 233 | inline void check_input(const params::params&p) { 234 | std::string path = p["input_file"]; 235 | h5pp::archive ar(path, "r"); 236 | if(ar.has_attribute("__green_version__")) { 237 | std::string int_version = ar.get_attribute("__green_version__"); 238 | if (!CheckVersion(int_version)) { 239 | throw mbpt_outdated_input("Input file at '" + path +"' is outdated, please run migration script python/migrate.py"); 240 | } 241 | } else { 242 | throw mbpt_outdated_input("Input file at '" + path +"' is outdated, please run migration script python/migrate.py"); 243 | } 244 | ar.close(); 245 | } 246 | 247 | inline void run(sc::sc_loop& sc, const params::params& p) { 248 | const auto jobs = p["jobs"].as>(); 249 | const scf_type type = p["scf_type"]; 250 | // initialize Dyson solver 251 | shared_mem_dyson dyson(p); 252 | // Allocate working arrays 253 | auto G_tau = utils::shared_object>(dyson.ft().sd().repn_fermi().nts(), dyson.ns(), dyson.bz_utils().ink(), 254 | dyson.nso(), dyson.nso()); 255 | auto Sigma_tau = utils::shared_object>(dyson.ft().sd().repn_fermi().nts(), dyson.ns(), dyson.bz_utils().ink(), 256 | dyson.nso(), dyson.nso()); 257 | auto Sigma1 = ztensor<4>(dyson.ns(), dyson.bz_utils().ink(), dyson.nso(), dyson.nso()); 258 | for (const auto job : jobs) { 259 | if (job == SC) { 260 | sc_job(sc, p, type, dyson, G_tau, Sigma_tau, Sigma1); 261 | } else if (job == WINTER) { 262 | winter_job(sc, p, dyson, G_tau, Sigma_tau, Sigma1); 263 | } 264 | if (!utils::context.global_rank) std::cout << "Job " << magic_enum::enum_name(job) << " is finished." << std::endl; 265 | } 266 | if (!utils::context.global_rank) std::cout << "Completed." << std::endl; 267 | } 268 | 269 | } // namespace green::mbpt 270 | 271 | #endif // MBPT_MBPT_RUN_H 272 | -------------------------------------------------------------------------------- /src/gw_solver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 University of Michigan 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 5 | * software and associated documentation files (the “Software”), to deal in the Software 6 | * without restriction, including without limitation the rights to use, copy, modify, 7 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so, subject to the following 9 | * conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all copies or 12 | * substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #include "green/mbpt/gw_solver.h" 23 | 24 | #include 25 | 26 | #include "green/mbpt/common_utils.h" 27 | 28 | namespace green::mbpt { 29 | 30 | void gw_solver::solve(G_type& g, S1_type&, St_type& sigma_tau) { 31 | _callback(g, sigma_tau); 32 | } 33 | 34 | } // namespace green::mbpt 35 | -------------------------------------------------------------------------------- /src/hf_cpu_kernels.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 University of Michigan 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 5 | * software and associated documentation files (the “Software”), to deal in the Software 6 | * without restriction, including without limitation the rights to use, copy, modify, 7 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so, subject to the following 9 | * conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all copies or 12 | * substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #include "green/mbpt/kernels.h" 23 | 24 | namespace green::mbpt::kernels { 25 | ztensor<4> hf_scalar_cpu_kernel::solve(const ztensor<4>& dm) { 26 | statistics.start("Hartree-Fock"); 27 | ztensor<4> new_Fock(_ns, _ink, _nao, _nao); 28 | new_Fock.set_zero(); 29 | { 30 | df_integral_t coul_int1(_hf_path, _nao, _NQ, _bz_utils); 31 | 32 | size_t NQ_local = _NQ / utils::context.node_size; 33 | NQ_local += (_NQ % utils::context.node_size > utils::context.node_rank) ? 1 : 0; 34 | size_t NQ_offset = NQ_local * utils::context.node_rank + 35 | ((_NQ % utils::context.node_size > utils::context.node_rank) ? 0 : (_NQ % utils::context.node_size)); 36 | NQ_offset = (NQ_offset >= _NQ) ? 0 : NQ_offset; 37 | statistics.start("Direct"); 38 | // Direct diagram 39 | MatrixXcd X1(_nao, _nao); 40 | ztensor<3> v(NQ_local, _nao, _nao); 41 | ztensor<2> upper_Coul(_NQ, 1); 42 | MMatrixXcd X1m(X1.data(), _nao * _nao, 1); 43 | MMatrixXcd vm(v.data(), NQ_local, _nao * _nao); 44 | MMatrixXcd upper_Coul_m(upper_Coul.data() + NQ_offset, NQ_local, 1); 45 | for (int ikps = utils::context.internode_rank; ikps < _ink * _ns; ikps += utils::context.internode_size) { 46 | int is = ikps % _ns; 47 | int ikp = ikps / _ns; 48 | int kp_ir = _bz_utils.symmetry().full_point(ikp); 49 | statistics.start("Read Coulomb Up"); 50 | coul_int1.read_integrals(kp_ir, kp_ir); 51 | statistics.end(); 52 | if(NQ_local > 0) { 53 | coul_int1.symmetrize(v, kp_ir, kp_ir, NQ_offset, NQ_local); 54 | 55 | X1 = CMMatrixXcd(dm.data() + is * _ink * _nao * _nao + ikp * _nao * _nao, _nao, _nao); 56 | X1 = X1.transpose().eval(); 57 | // (Q, 1) = (Q, ab) * (ab, 1) 58 | upper_Coul_m += _bz_utils.symmetry().weight()[kp_ir] * vm * X1m; 59 | } 60 | } 61 | statistics.start("Reduce Direct"); 62 | MPI_Allreduce(MPI_IN_PLACE, upper_Coul.data(), upper_Coul.size(), MPI_CXX_DOUBLE_COMPLEX, MPI_SUM, utils::context.global); 63 | statistics.end(); 64 | 65 | upper_Coul /= double(_nk); 66 | for (int ii = utils::context.internode_rank; ii < _ink * _ns; ii += utils::context.internode_size) { 67 | int is = ii / _ink; 68 | int ik = ii % _ink; 69 | int k_ir = _bz_utils.symmetry().full_point(ik); 70 | statistics.start("Read Coulomb Low"); 71 | coul_int1.read_integrals(k_ir, k_ir); 72 | statistics.end(); 73 | if(NQ_local > 0) { 74 | coul_int1.symmetrize(v, k_ir, k_ir, NQ_offset, NQ_local); 75 | 76 | MMatrixXcd Fm(new_Fock.data() + is * _ink * _nao * _nao + ik * _nao * _nao, 1, _nao * _nao); 77 | // (1, ij) = (1, Q) * (Q, ij) 78 | Fm += upper_Coul_m.transpose() * vm; 79 | } 80 | } 81 | statistics.end(); 82 | 83 | // Exchange diagram 84 | ztensor<3> Y(NQ_local, _nao, _nao); 85 | MMatrixXcd Ym(Y.data(), NQ_local * _nao, _nao); 86 | MMatrixXcd Ymm(Y.data(), NQ_local, _nao * _nao); 87 | 88 | ztensor<3> Y1(_nao, _nao, NQ_local); 89 | MMatrixXcd Y1m(Y1.data(), _nao * _nao, NQ_local); 90 | MMatrixXcd Y1mm(Y1.data(), _nao, _nao * NQ_local); 91 | 92 | MMatrixXcd vmm(v.data(), NQ_local * _nao, _nao); 93 | 94 | ztensor<3> v2(_nao, NQ_local, _nao); 95 | MMatrixXcd v2m(v2.data(), _nao, NQ_local * _nao); 96 | MMatrixXcd v2mm(v2.data(), _nao * NQ_local, _nao); 97 | double prefactor = (_ns == 2) ? 1.0 : 0.5; 98 | statistics.start("Exchange"); 99 | for (int ii = utils::context.internode_rank; ii < _ink * _ns; ii += utils::context.internode_size) { 100 | int is = ii / _ink; 101 | int ik = ii % _ink; 102 | int k_ir = _bz_utils.symmetry().full_point(ik); 103 | MMatrixXcd Fmm(new_Fock.data() + is * _ink * _nao * _nao + ik * _nao * _nao, _nao, _nao); 104 | for (int ikp = 0; ikp < _nk; ++ikp) { 105 | int kp = _bz_utils.symmetry().reduced_point(ikp); 106 | CMMatrixXcd dmm(dm.data() + is * _ink * _nao * _nao + kp * _nao * _nao, _nao, _nao); 107 | statistics.start("Read Coulomb Exch"); 108 | coul_int1.read_integrals(k_ir, ikp); 109 | statistics.end(); 110 | if(NQ_local > 0) { 111 | // (Q, i, b) or conj(Q, j, a) 112 | coul_int1.symmetrize(v, k_ir, ikp, NQ_offset, NQ_local); 113 | 114 | // (Qi, a) = (Qi, b) * (b, a) 115 | if (_bz_utils.symmetry().conj_list()[ikp] == 0) { 116 | Ym = vmm * dmm; 117 | } else { 118 | Ym = vmm * dmm.conjugate(); 119 | } 120 | // (ia, Q) 121 | Y1m = Ymm.transpose(); 122 | // (a, Qj). (Q, j, a) -> (a, Q, j)* 123 | v2m = vmm.conjugate().transpose(); 124 | // (i, j) = (i, aQ) * (aQ, j) 125 | Fmm -= prefactor * Y1mm * v2mm / double(_nk); 126 | } 127 | } 128 | } 129 | statistics.end(); 130 | 131 | statistics.start("Ewald correction"); 132 | for (int ii = utils::context.global_rank; ii < _ns * _ink; ii += utils::context.global_size) { 133 | int is = ii / _ink; 134 | int ik = ii % _ink; 135 | CMMatrixXcd dmm(dm.data() + is * _ink * _nao * _nao + ik * _nao * _nao, _nao, _nao); 136 | CMMatrixXcd Sm(_S_k.data() + is * _ink * _nao * _nao + ik * _nao * _nao, _nao, _nao); 137 | MMatrixXcd Fm(new_Fock.data() + is * _ink * _nao * _nao + ik * _nao * _nao, _nao, _nao); 138 | Fm -= prefactor * _madelung * Sm * dmm * Sm; 139 | } 140 | statistics.end(); 141 | } 142 | statistics.start("Reduce Fock"); 143 | utils::allreduce(MPI_IN_PLACE, new_Fock.data(), new_Fock.size(), MPI_C_DOUBLE_COMPLEX, MPI_SUM, utils::context.global); 144 | statistics.end(); 145 | statistics.end(); 146 | statistics.print(utils::context.global); 147 | return new_Fock; 148 | } 149 | 150 | ztensor<4> hf_x2c_cpu_kernel::solve(const ztensor<4>& dm) { 151 | statistics.start("X2C Hartree-Fock"); 152 | ztensor<4> new_Fock(1, _ink, _nso, _nso); 153 | new_Fock.set_zero(); 154 | { 155 | df_integral_t coul_int1(_hf_path, _nao, _NQ, _bz_utils); 156 | 157 | ztensor<3> dm_spblks[3]{ 158 | {_ink, _nao, _nao}, 159 | {_ink, _nao, _nao}, 160 | {_ink, _nao, _nao} 161 | }; 162 | for (int ik = 0; ik < _ink; ++ik) { 163 | CMMatrixXcd dmm(dm.data() + ik * _nso * _nso, _nso, _nso); 164 | // alpha-alpha 165 | matrix(dm_spblks[0](ik)) = dmm.block(0, 0, _nao, _nao); 166 | // beta-beta 167 | matrix(dm_spblks[1](ik)) = dmm.block(_nao, _nao, _nao, _nao); 168 | // alpha-beta 169 | matrix(dm_spblks[2](ik)) = dmm.block(0, _nao, _nao, _nao); 170 | } 171 | 172 | size_t NQ_local = _NQ / utils::context.node_size; 173 | NQ_local += (_NQ % utils::context.node_size > utils::context.node_rank) ? 1 : 0; 174 | size_t NQ_offset = NQ_local * utils::context.node_rank + 175 | ((_NQ % utils::context.node_size > utils::context.node_rank) ? 0 : (_NQ % utils::context.node_size)); 176 | NQ_offset = (NQ_offset >= _NQ) ? 0 : NQ_offset; 177 | ztensor<3> v(NQ_local, _nao, _nao); 178 | // Direct diagram 179 | // if (utils::context.global_rank < _ink) { 180 | statistics.start("X2C direct diagram"); 181 | { 182 | MatrixXcd X1(_nao, _nao); 183 | MMatrixXcd X1m(X1.data(), _nao * _nao, 1); 184 | 185 | MMatrixXcd vm(v.data(), NQ_local, _nao * _nao); 186 | 187 | ztensor<2> upper_Coul(_NQ, 1); 188 | MMatrixXcd upper_Coul_m(upper_Coul.data() + NQ_offset, NQ_local, 1); 189 | for (int ikp = utils::context.internode_rank; ikp < _ink; ikp += utils::context.internode_size) { 190 | // for (size_t ikp = 0; ikp < _ink; ++ikp) { 191 | size_t kp_ir = _bz_utils.symmetry().full_point(ikp); 192 | 193 | coul_int1.read_integrals(kp_ir, kp_ir); 194 | if(NQ_local > 0) { 195 | coul_int1.symmetrize(v, kp_ir, kp_ir, NQ_offset, NQ_local); 196 | 197 | // Sum of alpha-alpha and beta-beta spin block 198 | // In the presence of TR symmetry, 199 | // (dm_aa(-k) + dm_bb(-k)) = (dm_aa(k) + dm_bb(k))* 200 | X1 = matrix(dm_spblks[0](ikp)) + matrix(dm_spblks[1](ikp)); 201 | X1 = X1.transpose().eval(); 202 | // (Q, 1) = (Q, ab) * (ab, 1) 203 | // Since vm(k) = vm(-k)* as well, we only need to take care of half of the k-point 204 | upper_Coul_m += _bz_utils.symmetry().weight()[kp_ir] * vm * X1m; 205 | } 206 | } 207 | statistics.start("Reduce Direct"); 208 | MPI_Allreduce(MPI_IN_PLACE, upper_Coul.data(), upper_Coul.size(), MPI_CXX_DOUBLE_COMPLEX, MPI_SUM, utils::context.global); 209 | statistics.end(); 210 | upper_Coul /= double(_nk); 211 | 212 | MatrixXcd Fm(1, _nao * _nao); 213 | MMatrixXcd Fmm(Fm.data(), _nao, _nao); 214 | for (int ik = utils::context.internode_rank; ik < _ink; ik += utils::context.internode_size) { 215 | int k_ir = _bz_utils.symmetry().full_point(ik); 216 | 217 | coul_int1.read_integrals(k_ir, k_ir); 218 | if(NQ_local > 0) { 219 | coul_int1.symmetrize(v, k_ir, k_ir, NQ_offset, NQ_local); 220 | 221 | Fm = upper_Coul_m.transpose() * vm; 222 | MMatrixXcd Fm_nso(new_Fock.data() + ik * _nso * _nso, _nso, _nso); 223 | Fm_nso.block(0, 0, _nao, _nao) += Fmm; 224 | Fm_nso.block(_nao, _nao, _nao, _nao) += Fmm; 225 | } 226 | } 227 | } 228 | 229 | statistics.end(); 230 | 231 | statistics.start("X2C exchange diagram"); 232 | // Exchange diagram 233 | ztensor<3> Y(NQ_local, _nao, _nao); 234 | MMatrixXcd Ym(Y.data(), NQ_local * _nao, _nao); 235 | MMatrixXcd Ymm(Y.data(), NQ_local, _nao * _nao); 236 | 237 | ztensor<3> Y1(_nao, _nao, NQ_local); 238 | MMatrixXcd Y1m(Y1.data(), _nao * _nao, NQ_local); 239 | MMatrixXcd Y1mm(Y1.data(), _nao, _nao * NQ_local); 240 | 241 | MMatrixXcd vmm(v.data(), NQ_local * _nao, _nao); 242 | 243 | ztensor<3> v2(_nao, NQ_local, _nao); 244 | MMatrixXcd v2m(v2.data(), _nao, NQ_local * _nao); 245 | MMatrixXcd v2mm(v2.data(), _nao * NQ_local, _nao); 246 | 247 | for (int iks = utils::context.internode_rank; iks < 3 * _ink; iks += utils::context.internode_size) { 248 | size_t ik = iks / 3; 249 | size_t is = iks % 3; 250 | MMatrixXcd Fm_nso(new_Fock.data() + ik * _nso * _nso, _nso, _nso); 251 | MatrixXcd Fm_spblk(_nao, _nao); 252 | CMMatrixXcd Sm_nso(_S_k.data() + ik * _nso * _nso, _nso, _nso); 253 | MatrixXcd S_aa = Sm_nso.block(0, 0, _nao, _nao); 254 | if (is == 0) { 255 | // alpha-alpha 256 | Fm_nso.block(0, 0, _nao, _nao) += 257 | compute_exchange(ik, dm_spblks[0], dm_spblks[1], v, coul_int1, Y, Ym, Ymm, Y1, Y1m, Y1mm, vmm, v2, v2m, v2mm, NQ_local, NQ_offset); 258 | Fm_nso.block(0, 0, _nao, _nao) -= _madelung * S_aa * matrix(dm_spblks[0](ik)) * S_aa; 259 | } else if (is == 1) { 260 | // beta-beta 261 | Fm_nso.block(_nao, _nao, _nao, _nao) += 262 | compute_exchange(ik, dm_spblks[1], dm_spblks[0], v, coul_int1, Y, Ym, Ymm, Y1, Y1m, Y1mm, vmm, v2, v2m, v2mm, NQ_local, NQ_offset); 263 | Fm_nso.block(_nao, _nao, _nao, _nao) -= _madelung * S_aa * matrix(dm_spblks[1](ik)) * S_aa; 264 | } else if (is == 2) { 265 | // alpha-beta 266 | Fm_nso.block(0, _nao, _nao, _nao) += 267 | compute_exchange_ab(ik, dm_spblks[2], v, coul_int1, Y, Ym, Ymm, Y1, Y1m, Y1mm, vmm, v2, v2m, v2mm, NQ_local, NQ_offset); 268 | Fm_nso.block(0, _nao, _nao, _nao) -= _madelung * S_aa * matrix(dm_spblks[2](ik)) * S_aa; 269 | // beta-alpha 270 | Fm_nso.block(_nao, 0, _nao, _nao) = Fm_nso.block(0, _nao, _nao, _nao).transpose().conjugate(); 271 | } 272 | } 273 | statistics.end(); 274 | } 275 | 276 | statistics.start("Reduce Fock"); 277 | utils::allreduce(MPI_IN_PLACE, new_Fock.data(), new_Fock.size(), MPI_C_DOUBLE_COMPLEX, MPI_SUM, utils::context.global); 278 | statistics.end(); 279 | statistics.end(); 280 | statistics.print(utils::context.global); 281 | return new_Fock; 282 | } 283 | 284 | MatrixXcd hf_x2c_cpu_kernel::compute_exchange(int ik, ztensor<3>& dm_s1_s2, ztensor<3>& dm_ms1_ms2, ztensor<3>& v, 285 | df_integral_t& coul_int1, ztensor<3>& Y, MMatrixXcd& Ym, MMatrixXcd& Ymm, 286 | ztensor<3>& Y1, MMatrixXcd& Y1m, MMatrixXcd& Y1mm, MMatrixXcd& vmm, 287 | ztensor<3>& v2, MMatrixXcd& v2m, MMatrixXcd& v2mm, size_t NQ_local, size_t NQ_offset) { 288 | int k_ir = _bz_utils.symmetry().full_point(ik); 289 | MatrixXcd Fock = MatrixXcd::Zero(_nao, _nao); 290 | 291 | for (int ikp = 0; ikp < _nk; ++ikp) { 292 | int kp = _bz_utils.symmetry().reduced_point(ikp); 293 | 294 | coul_int1.read_integrals(k_ir, ikp); 295 | if(NQ_local > 0) { 296 | // (Q, i, b) or conj(Q, j, a) 297 | coul_int1.symmetrize(v, k_ir, ikp, NQ_offset, NQ_local); 298 | 299 | // (Qi, a) = (Qi, b) * (b, a) 300 | if (_bz_utils.symmetry().conj_list()[ikp] == 0) { 301 | CMMatrixXcd dmm(dm_s1_s2.data() + kp * _nao * _nao, _nao, _nao); 302 | Ym = vmm * dmm; 303 | } else { 304 | CMMatrixXcd dmm(dm_ms1_ms2.data() + kp * _nao * _nao, _nao, _nao); 305 | Ym = vmm * dmm.conjugate(); 306 | } 307 | // (ia, Q) 308 | Y1m = Ymm.transpose(); 309 | // (a, Qj) 310 | v2m = vmm.conjugate().transpose(); 311 | // (i, j) = (i, aQ) * (aQ, j) 312 | Fock -= Y1mm * v2mm / double(_nk); 313 | } 314 | } 315 | return Fock; 316 | } 317 | 318 | MatrixXcd hf_x2c_cpu_kernel::compute_exchange_ab(int ik, ztensor<3>& dm_ab, ztensor<3>& v, df_integral_t& coul_int1, 319 | ztensor<3>& Y, MMatrixXcd& Ym, MMatrixXcd& Ymm, ztensor<3>& Y1, 320 | MMatrixXcd& Y1m, MMatrixXcd& Y1mm, MMatrixXcd& vmm, ztensor<3>& v2, 321 | MMatrixXcd& v2m, MMatrixXcd& v2mm, size_t NQ_local, size_t NQ_offset) { 322 | int k_ir = _bz_utils.symmetry().full_point(ik); 323 | MatrixXcd Fock = MatrixXcd::Zero(_nao, _nao); 324 | 325 | for (int ikp = 0; ikp < _nk; ++ikp) { 326 | int kp = _bz_utils.symmetry().reduced_point(ikp); 327 | 328 | coul_int1.read_integrals(k_ir, ikp); 329 | if(NQ_local > 0) { 330 | // (Q, i, b) or conj(Q, j, a) 331 | coul_int1.symmetrize(v, k_ir, ikp, NQ_offset, NQ_local); 332 | 333 | // (Qi, a) = (Qi, b) * (b, a) 334 | if (_bz_utils.symmetry().conj_list()[ikp] == 0) { 335 | CMMatrixXcd dmm(dm_ab.data() + kp * _nao * _nao, _nao, _nao); 336 | Ym = vmm * dmm; 337 | } else { 338 | CMMatrixXcd dmm(dm_ab.data() + kp * _nao * _nao, _nao, _nao); 339 | Ym = vmm * (-1.0) * dmm.transpose(); 340 | } 341 | // (ia, Q) 342 | Y1m = Ymm.transpose(); 343 | // (a, Qj) 344 | v2m = vmm.conjugate().transpose(); 345 | // (i, j) = (i, aQ) * (aQ, j) 346 | Fock -= Y1mm * v2mm / double(_nk); 347 | } 348 | } 349 | return Fock; 350 | } 351 | } -------------------------------------------------------------------------------- /src/hf_solver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022 University of Michigan. 3 | * 4 | */ 5 | 6 | #include "green/mbpt/hf_solver.h" 7 | 8 | namespace green::mbpt { 9 | void hf_solver::solve(utils::shared_object>& g, ztensor<4>& sigma1, utils::shared_object>&) { 10 | std::array shape; 11 | std::copy(g.object().shape().begin() + 1, g.object().shape().end(), shape.begin()); 12 | ztensor<4> dm(shape); 13 | dm << g.object()(g.object().shape()[0] - 1); 14 | dm *= _spin_prefactor; 15 | sigma1 << _callback(dm); 16 | } 17 | } // namespace green::mbpt 18 | -------------------------------------------------------------------------------- /src/mbpt_q0_utils_t.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022 University of Michigan. 3 | * 4 | */ 5 | 6 | #include 7 | #include 8 | #include "green/mbpt/mbpt_q0_utils_t.h" 9 | 10 | namespace green::mbpt { 11 | void mbpt_q0_utils_t::aux_to_PW_00(ztensor<4> &X_aux, ztensor<2> &X_PW_00, size_t iq) { 12 | // X_PW_00[dim0, iq] = Aq[iq, NQ].conj() * X_aux[dim0, NQ, NQ] * Aq[iq, NQ] 13 | size_t dim0 = X_aux.shape()[0]; 14 | //MMatrixX vm(v.data(), _NQ * _nao, _nao); 15 | MMatrixXcd AqQ_m(_AqQ.data(), _ink, _NQ); 16 | 17 | for (size_t i = 0; i < dim0; ++i) { 18 | // X_PW_00_nw = _Aq(NQ).conj() * X_aux_nw(NQ, NQ) * _Aq(NQ) 19 | X_PW_00(i, iq) = (AqQ_m.row(iq).conjugate() * matrix(X_aux(i, 0)) * AqQ_m.transpose().col(iq))(0,0); 20 | } 21 | } 22 | 23 | void mbpt_q0_utils_t::check_AqQ() { 24 | MMatrixXcd AqQ_m(_AqQ.data(), _ink, _NQ); 25 | for (size_t q = 0; q < _ink; ++q) { 26 | std::complex identity = AqQ_m.row(q).conjugate() * AqQ_m.transpose().col(q); 27 | if (q != 0) std::cout << "identity = " << identity << std::endl; 28 | } 29 | } 30 | 31 | std::complex mbpt_q0_utils_t::extrapolate_q0(std::complex *X, size_t fit_order, double q_max, bool debug) { 32 | // Find unique q_abs with q_abs <= q_max 33 | std::vector q_indices = filter_q_abs(q_max); 34 | size_t num_sample = q_indices.size(); 35 | if (debug) std::cout << "Will use " << num_sample << " points to extrapolate q->0 limit:" << std::endl; 36 | std::vector X_filtered(q_indices.size()); 37 | std::vector q_filtered(q_indices.size()); 38 | for (int i = 0; i < q_indices.size(); ++i) { 39 | size_t idx = q_indices[i]; 40 | X_filtered[i] = X[idx].real(); 41 | q_filtered[i] = _q_abs[idx]; 42 | if (debug) std::cout << _q_abs[idx] << std::endl; 43 | } 44 | // Construct elements with q_abs <= q_max; 45 | MatrixXd poly_coeffs(fit_order+1, 1); 46 | polyfit(q_filtered.data(), X_filtered.data(), fit_order, num_sample, poly_coeffs); 47 | if (debug) { 48 | std::cout << "Polynomial at the lowest Matsubara frequency: " << 49 | poly_coeffs(0, 0) << " + " << poly_coeffs(1, 0) << "q + " << poly_coeffs(2, 0) << "q^2" << std::endl; 50 | } 51 | return poly_coeffs(0, 0); 52 | } 53 | 54 | std::vector mbpt_q0_utils_t::filter_q_abs(double q_max) { 55 | std::vector q_indices; 56 | std::set q_set; 57 | for (int i = 0; i < _q_abs.size(); ++i) { 58 | if (_q_abs[i] > 0.0 && _q_abs[i] <= q_max) { 59 | auto insert_pair = q_set.insert(_q_abs[i]); 60 | if (insert_pair.second) { 61 | q_indices.push_back(i); 62 | } 63 | } 64 | } 65 | return q_indices; 66 | } 67 | 68 | void mbpt_q0_utils_t::polyfit(double *x, double *y, size_t fit_order, size_t num_sample, MatrixXd &c) { 69 | MatrixXd A(num_sample, fit_order+1); 70 | MatrixXd b(num_sample, 1); 71 | for (int i = 0; i < num_sample; ++i) { 72 | b(i) = y[i]; 73 | A(i, 0) = 1.0; 74 | for (int j = 1; j <= fit_order; ++j) { 75 | A(i, j) = pow(x[i], j); 76 | } 77 | } 78 | 79 | // Least-squares fit 80 | //c = A.bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b); 81 | // Normal equation: A^{T}Ax = A^{T}b 82 | Eigen::FullPivLU lusolver(fit_order+1, fit_order+1); 83 | MatrixXd ATA = A.transpose() * A; 84 | MatrixXd ATb = A.transpose() * b; 85 | c = lusolver.compute(ATA).solve(ATb); 86 | } 87 | 88 | void mbpt_q0_utils_t::GW_q0_correction(ztensor<2> &eps_inv_wq, ztensor_view<5> &Sigma, ztensor_view<5> &Gtau, 89 | const grids::transformer_t &ft, bool X2C, 90 | size_t myid, size_t intranode_rank, size_t intranode_size, MPI_Win win_Sigma) { 91 | //MPI_Allreduce(MPI_IN_PLACE, _eps_inv_wq.data(), _eps_inv_wq.size(), MPI_C_DOUBLE_COMPLEX, MPI_SUM, _comm); 92 | size_t nts = Sigma.shape()[0]; 93 | size_t nw_b = eps_inv_wq.shape()[0]; 94 | size_t ink = eps_inv_wq.shape()[1]; 95 | 96 | // Extrapolate to q->0 limit 97 | ztensor<2> eps_q0_inv_w(nw_b, 1); 98 | size_t fit_order = 2; 99 | column poly_coeffs(fit_order+1); 100 | for (int n = 0; n < nw_b; ++n) { 101 | // eps_q0_inv_w(n,0) = _eps_q_inv_w(n, 1); 102 | std::complex *eps_inv_wn_q_ptr = eps_inv_wq.data() + n * ink; 103 | if (n == nw_b/2) { 104 | eps_q0_inv_w(n, 0) = (!myid)? extrapolate_q0(eps_inv_wn_q_ptr, fit_order, 1.0, true) 105 | : extrapolate_q0(eps_inv_wn_q_ptr, fit_order, 1.0); 106 | } else { 107 | eps_q0_inv_w(n, 0) = extrapolate_q0(eps_inv_wn_q_ptr, fit_order, 1.0); 108 | } 109 | } 110 | 111 | // Transform to fermionic tau grid 112 | ztensor<2> eps_q0_inv_t(nts, 1); 113 | ft.w_b_to_tau_f(eps_q0_inv_w, eps_q0_inv_t); 114 | // Apply correction term 115 | if (!X2C) { 116 | apply_q0_correction(eps_q0_inv_t, Sigma, Gtau, intranode_rank, intranode_size, win_Sigma); 117 | } else { 118 | apply_q0_correction_2C(eps_q0_inv_t, Sigma, Gtau, intranode_rank, intranode_size, win_Sigma); 119 | } 120 | } 121 | 122 | void mbpt_q0_utils_t::apply_q0_correction(ztensor<2> &eps_q0_inv_t, ztensor_view<5> &Sigma, ztensor_view<5> &G_tau, 123 | size_t intranode_rank, size_t intranode_size, MPI_Win win_Sigma) { 124 | size_t nts = Sigma.shape()[0]; 125 | size_t ns = Sigma.shape()[1]; 126 | size_t ink = Sigma.shape()[2]; 127 | 128 | MPI_Win_fence(0, win_Sigma); 129 | // Delta = -madelung * epsilon_inv_q0 * S * G * S 130 | for (size_t t = intranode_rank; t < nts; t+=intranode_size) { 131 | for (size_t s = 0; s < ns; ++s) { 132 | for (size_t k = 0; k < ink; ++k) { 133 | matrix(Sigma(t, s, k)) -= _madelung * eps_q0_inv_t(t, 0) * 134 | matrix(_S_k(s, k)) * matrix(G_tau(t, s, k)) * matrix(_S_k(s, k)); 135 | } 136 | } 137 | } 138 | MPI_Win_fence(0, win_Sigma); 139 | } 140 | 141 | void mbpt_q0_utils_t::apply_q0_correction_2C(ztensor<2> &eps_q0_inv_t, ztensor_view<5> &Sigma, ztensor_view<5> &G_tau, 142 | size_t intranode_rank, size_t intranode_size, MPI_Win win_Sigma) { 143 | size_t nts = Sigma.shape()[0]; 144 | size_t ns = Sigma.shape()[1]; 145 | size_t ink = Sigma.shape()[2]; 146 | size_t nso = Sigma.shape()[3]; 147 | size_t nao = nso / 2; 148 | 149 | MPI_Win_fence(0, win_Sigma); 150 | // Delta = -madelung * epsilon_inv_q0 * S * G * S 151 | MatrixXcd off_spin_blk_buffer(nao, nao); 152 | for (size_t t = intranode_rank; t < nts; t+=intranode_size) { 153 | for (size_t k = 0; k < ink; ++k) { 154 | MMatrixXcd Sigmam_nso(Sigma.data() + t*ink*nso*nso + k*nso*nso, nso, nso); 155 | MMatrixXcd Gm_nso(G_tau.data() + t*ink*nso*nso + k*nso*nso, nso, nso); 156 | CMMatrixXcd Sm_nso(_S_k.data() + k*nso*nso, nso, nso); 157 | MatrixXcd Sm_nao = Sm_nso.block(0, 0, nao, nao); 158 | for (size_t s = 0; s < 3; ++s) { 159 | if (s == 0) { 160 | // alpha-alpha 161 | Sigmam_nso.block(0, 0, nao, nao) -= _madelung * eps_q0_inv_t(t, 0) * 162 | Sm_nao * Gm_nso.block(0, 0, nao, nao) * Sm_nao; 163 | } else if (s == 1) { 164 | // beta-beta 165 | Sigmam_nso.block(nao, nao, nao, nao) -= _madelung * eps_q0_inv_t(t, 0) * 166 | Sm_nao * Gm_nso.block(nao, nao, nao, nao) * Sm_nao; 167 | } else { 168 | // alpha-beta and beta-alpha 169 | off_spin_blk_buffer = _madelung * eps_q0_inv_t(t, 0) * 170 | Sm_nao * Gm_nso.block(0, nao, nao, nao) * Sm_nao; 171 | Sigmam_nso.block(0, nao, nao, nao) -= off_spin_blk_buffer; 172 | Sigmam_nso.block(nao, 0, nao, nao) -= off_spin_blk_buffer.transpose().conjugate(); 173 | } 174 | } 175 | } 176 | } 177 | MPI_Win_fence(0, win_Sigma); 178 | } 179 | 180 | 181 | } 182 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(_test) 2 | 3 | Include(FetchContent) 4 | 5 | FetchContent_Declare( 6 | Catch2 7 | GIT_REPOSITORY https://github.com/catchorg/Catch2.git 8 | GIT_TAG v3.4.0 # or a later release_ 9 | ) 10 | 11 | FetchContent_MakeAvailable(Catch2) 12 | list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras) 13 | 14 | add_executable(solvers_test solvers_test.cpp) 15 | target_compile_definitions(solvers_test PRIVATE TEST_PATH="${CMAKE_CURRENT_SOURCE_DIR}/data" 16 | GRID_PATH="${grids_SOURCE_DIR}/data") 17 | target_link_libraries(solvers_test 18 | PRIVATE 19 | Catch2::Catch2 20 | GREEN::MBPT GREEN::SC BLAS::BLAS) 21 | 22 | include(CTest) 23 | include(Catch) 24 | catch_discover_tests(solvers_test) -------------------------------------------------------------------------------- /test/data/Dyson/input.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/Dyson/input.h5 -------------------------------------------------------------------------------- /test/data/GF2/data.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GF2/data.h5 -------------------------------------------------------------------------------- /test/data/GF2/data_e.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GF2/data_e.h5 -------------------------------------------------------------------------------- /test/data/GF2/df_hf_int/VQ_0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GF2/df_hf_int/VQ_0.h5 -------------------------------------------------------------------------------- /test/data/GF2/df_hf_int/meta.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GF2/df_hf_int/meta.h5 -------------------------------------------------------------------------------- /test/data/GF2/df_hf_int_e/VQ_0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GF2/df_hf_int_e/VQ_0.h5 -------------------------------------------------------------------------------- /test/data/GF2/df_hf_int_e/df_ewald.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GF2/df_hf_int_e/df_ewald.h5 -------------------------------------------------------------------------------- /test/data/GF2/df_hf_int_e/meta.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GF2/df_hf_int_e/meta.h5 -------------------------------------------------------------------------------- /test/data/GF2/df_hf_int_z/VQ_0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GF2/df_hf_int_z/VQ_0.h5 -------------------------------------------------------------------------------- /test/data/GF2/df_hf_int_z/df_ewald.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GF2/df_hf_int_z/df_ewald.h5 -------------------------------------------------------------------------------- /test/data/GF2/df_hf_int_z/meta.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GF2/df_hf_int_z/meta.h5 -------------------------------------------------------------------------------- /test/data/GF2/input.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GF2/input.h5 -------------------------------------------------------------------------------- /test/data/GF2/input_e.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GF2/input_e.h5 -------------------------------------------------------------------------------- /test/data/GW/data.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GW/data.h5 -------------------------------------------------------------------------------- /test/data/GW/data_c.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GW/data_c.h5 -------------------------------------------------------------------------------- /test/data/GW/df_hf_int/AqQ.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GW/df_hf_int/AqQ.h5 -------------------------------------------------------------------------------- /test/data/GW/df_hf_int/VQ_0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GW/df_hf_int/VQ_0.h5 -------------------------------------------------------------------------------- /test/data/GW/df_hf_int/meta.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GW/df_hf_int/meta.h5 -------------------------------------------------------------------------------- /test/data/GW/df_int/VQ_0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GW/df_int/VQ_0.h5 -------------------------------------------------------------------------------- /test/data/GW/df_int/meta.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GW/df_int/meta.h5 -------------------------------------------------------------------------------- /test/data/GW/input.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GW/input.h5 -------------------------------------------------------------------------------- /test/data/GW_X2C/data.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GW_X2C/data.h5 -------------------------------------------------------------------------------- /test/data/GW_X2C/df_hf_int/VQ_0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GW_X2C/df_hf_int/VQ_0.h5 -------------------------------------------------------------------------------- /test/data/GW_X2C/df_hf_int/meta.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GW_X2C/df_hf_int/meta.h5 -------------------------------------------------------------------------------- /test/data/GW_X2C/input.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/GW_X2C/input.h5 -------------------------------------------------------------------------------- /test/data/HF/data.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/HF/data.h5 -------------------------------------------------------------------------------- /test/data/HF/df_hf_int/VQ_0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/HF/df_hf_int/VQ_0.h5 -------------------------------------------------------------------------------- /test/data/HF/df_hf_int/meta.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/HF/df_hf_int/meta.h5 -------------------------------------------------------------------------------- /test/data/HF/df_int/VQ_0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/HF/df_int/VQ_0.h5 -------------------------------------------------------------------------------- /test/data/HF/df_int/meta.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/HF/df_int/meta.h5 -------------------------------------------------------------------------------- /test/data/HF/input.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/HF/input.h5 -------------------------------------------------------------------------------- /test/data/HF_X2C/data.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/HF_X2C/data.h5 -------------------------------------------------------------------------------- /test/data/HF_X2C/df_hf_int/VQ_0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/HF_X2C/df_hf_int/VQ_0.h5 -------------------------------------------------------------------------------- /test/data/HF_X2C/df_hf_int/meta.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/HF_X2C/df_hf_int/meta.h5 -------------------------------------------------------------------------------- /test/data/HF_X2C/input.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/HF_X2C/input.h5 -------------------------------------------------------------------------------- /test/data/Input/df_int/VQ_0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/Input/df_int/VQ_0.h5 -------------------------------------------------------------------------------- /test/data/Input/df_int/meta.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/Input/df_int/meta.h5 -------------------------------------------------------------------------------- /test/data/Input/df_int_0.3.0/VQ_0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/Input/df_int_0.3.0/VQ_0.h5 -------------------------------------------------------------------------------- /test/data/Input/df_int_0.3.0/meta.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/Input/df_int_0.3.0/meta.h5 -------------------------------------------------------------------------------- /test/data/Input/df_int_x/VQ_0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/Input/df_int_x/VQ_0.h5 -------------------------------------------------------------------------------- /test/data/Input/df_int_x/meta.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/Input/df_int_x/meta.h5 -------------------------------------------------------------------------------- /test/data/Input/df_int_y/VQ_0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/Input/df_int_y/VQ_0.h5 -------------------------------------------------------------------------------- /test/data/Input/df_int_y/meta.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/Input/df_int_y/meta.h5 -------------------------------------------------------------------------------- /test/data/Input/input.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-Phys/green-mbpt/b607aadc2bba7e6d91add8f53530835d42b04ff9/test/data/Input/input.h5 -------------------------------------------------------------------------------- /test/solvers_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 University of Michigan 3 | * 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include "catch2/matchers/catch_matchers.hpp" 18 | #include "tensor_test.h" 19 | 20 | void solve_hf(const std::string& input, const std::string& int_hf, const std::string& data) { 21 | auto p = green::params::params("DESCR"); 22 | std::string input_file = TEST_PATH + input; 23 | std::string df_int_path = TEST_PATH + int_hf; 24 | std::string test_file = TEST_PATH + data; 25 | std::string grid_file = GRID_PATH + "/ir/1e4.h5"s; 26 | std::string args = 27 | "test --restart 0 --itermax 1 --E_thr 1e-13 --mixing_type SIGMA_MIXING --mixing_weight 0.8 --input_file=" + input_file + 28 | " --BETA 100 --grid_file=" + grid_file + " --dfintegral_hf_file=" + df_int_path; 29 | green::grids::define_parameters(p); 30 | green::mbpt::define_parameters(p); 31 | green::symmetry::define_parameters(p); 32 | p.parse(args); 33 | green::symmetry::brillouin_zone_utils bz(p); 34 | size_t nso, ns, nk, ink, nts; 35 | green::sc::ztensor<4> tmp; 36 | { 37 | green::h5pp::archive ar(input_file); 38 | ar["params/nso"] >> nso; 39 | ar["params/ns"] >> ns; 40 | ar["params/nk"] >> nk; 41 | ar["grid/ink"] >> ink; 42 | green::sc::dtensor<5> S_k; 43 | ar["HF/S-k"] >> S_k; 44 | ar.close(); 45 | tmp.resize(ns, nk, nso, nso); 46 | tmp << S_k.view>().reshape(ns, nk, nso, nso); 47 | } 48 | { 49 | green::h5pp::archive ar(grid_file); 50 | ar["fermi/metadata/ncoeff"] >> nts; 51 | ar.close(); 52 | nts += 2; 53 | } 54 | auto G_shared = green::utils::shared_object(green::sc::ztensor<5>(nullptr, nts, ns, ink, nso, nso)); 55 | auto S_shared = green::utils::shared_object(green::sc::ztensor<5>(nullptr, nts, ns, ink, nso, nso)); 56 | auto Sigma1 = green::sc::ztensor<4>(ns, ink, nso, nso); 57 | auto Sigma1_test = green::sc::ztensor<4>(ns, ink, nso, nso); 58 | auto Sk = green::sc::ztensor<4>(ns, ink, nso, nso); 59 | for (int is = 0; is < ns; ++is) Sk(is) << bz.full_to_ibz(tmp(is)); 60 | { 61 | green::h5pp::archive ar(test_file, "r"); 62 | G_shared.fence(); 63 | if (!green::utils::context.node_rank) ar["G_tau"] >> G_shared.object(); 64 | G_shared.fence(); 65 | ar["result/Sigma1"] >> Sigma1_test; 66 | ar.close(); 67 | } 68 | green::mbpt::hf_solver solver(p, bz, Sk); 69 | solver.solve(G_shared, Sigma1, S_shared); 70 | REQUIRE_THAT(Sigma1, IsCloseTo(Sigma1_test)); 71 | } 72 | 73 | void solve_gw(const std::string& input, const std::string& int_f, const std::string& data, const std::string& q0 = "IGNORE_G0") { 74 | auto p = green::params::params("DESCR"); 75 | std::string input_file = TEST_PATH + input; 76 | std::string df_int_path = TEST_PATH + int_f; 77 | std::string test_file = TEST_PATH + data; 78 | std::string grid_file = GRID_PATH + "/ir/1e4.h5"s; 79 | std::string args = 80 | "test --restart 0 --itermax 1 --E_thr 1e-13 --mixing_type SIGMA_MIXING --mixing_weight 0.8 --input_file=" + input_file + 81 | " --BETA 100 --grid_file=" + grid_file + " --dfintegral_file=" + df_int_path + " --q0_treatment " + q0; 82 | green::grids::define_parameters(p); 83 | green::mbpt::define_parameters(p); 84 | green::symmetry::define_parameters(p); 85 | p.define("BETA", "Inverse temperature", 10.0); 86 | p.parse(args); 87 | green::symmetry::brillouin_zone_utils bz(p); 88 | green::grids::transformer_t ft(p); 89 | size_t nso, ns, nk, ink, nts; 90 | green::sc::ztensor<4> tmp; 91 | { 92 | green::h5pp::archive ar(input_file); 93 | ar["params/nso"] >> nso; 94 | ar["params/ns"] >> ns; 95 | ar["params/nk"] >> nk; 96 | ar["grid/ink"] >> ink; 97 | green::sc::dtensor<5> S_k; 98 | ar["HF/S-k"] >> S_k; 99 | ar.close(); 100 | tmp.resize(ns, nk, nso, nso); 101 | tmp << S_k.view>().reshape(ns, nk, nso, nso); 102 | } 103 | { 104 | green::h5pp::archive ar(grid_file); 105 | ar["fermi/metadata/ncoeff"] >> nts; 106 | ar.close(); 107 | nts += 2; 108 | } 109 | auto G_shared = green::utils::shared_object(green::sc::ztensor<5>(nullptr, nts, ns, ink, nso, nso)); 110 | auto S_shared = green::utils::shared_object(green::sc::ztensor<5>(nullptr, nts, ns, ink, nso, nso)); 111 | auto S_shared_tst = green::utils::shared_object(green::sc::ztensor<5>(nullptr, nts, ns, ink, nso, nso)); 112 | auto Sigma1 = green::sc::ztensor<4>(ns, ink, nso, nso); 113 | auto Sk = green::sc::ztensor<4>(ns, ink, nso, nso); 114 | for (int is = 0; is < ns; ++is) Sk(is) << bz.full_to_ibz(tmp(is)); 115 | { 116 | green::h5pp::archive ar(test_file, "r"); 117 | G_shared.fence(); 118 | if (!green::utils::context.node_rank) ar["G_tau"] >> G_shared.object(); 119 | G_shared.fence(); 120 | S_shared_tst.fence(); 121 | if (!green::utils::context.node_rank) ar["result/Sigma_tau"] >> S_shared_tst.object(); 122 | S_shared_tst.fence(); 123 | ar.close(); 124 | } 125 | green::mbpt::gw_solver solver(p, ft, bz, Sk); 126 | solver.solve(G_shared, Sigma1, S_shared); 127 | REQUIRE_THAT(S_shared.object(), IsCloseTo(S_shared_tst.object(), 1e-6)); 128 | } 129 | 130 | void solve_gf2(const std::string& df_int_path, const std::string& test_file, const std::string& input_file) { 131 | auto p = green::params::params("DESCR"); 132 | 133 | std::string grid_file = GRID_PATH + "/ir/1e4.h5"s; 134 | std::string args = 135 | "test --restart 0 --itermax 1 --E_thr 1e-13 --mixing_type SIGMA_MIXING --mixing_weight 0.8 --input_file=" + input_file + 136 | " --BETA 100 --grid_file=" + grid_file + " --dfintegral_file=" + df_int_path + " --dfintegral_hf_file=" + df_int_path; 137 | green::grids::define_parameters(p); 138 | green::mbpt::define_parameters(p); 139 | green::symmetry::define_parameters(p); 140 | p.parse(args); 141 | green::symmetry::brillouin_zone_utils bz(p); 142 | green::grids::transformer_t ft(p); 143 | size_t nso, ns, nk, ink, nts; 144 | green::sc::ztensor<4> tmp; 145 | { 146 | green::h5pp::archive ar(input_file); 147 | ar["params/nso"] >> nso; 148 | ar["params/ns"] >> ns; 149 | ar["params/nk"] >> nk; 150 | ar["grid/ink"] >> ink; 151 | green::sc::dtensor<5> S_k; 152 | ar["HF/S-k"] >> S_k; 153 | ar.close(); 154 | tmp.resize(ns, nk, nso, nso); 155 | tmp << S_k.view>().reshape(ns, nk, nso, nso); 156 | } 157 | { 158 | green::h5pp::archive ar(grid_file); 159 | ar["fermi/metadata/ncoeff"] >> nts; 160 | ar.close(); 161 | nts += 2; 162 | } 163 | auto G_shared = green::utils::shared_object(green::sc::ztensor<5>(nullptr, nts, ns, ink, nso, nso)); 164 | auto S_shared = green::utils::shared_object(green::sc::ztensor<5>(nullptr, nts, ns, ink, nso, nso)); 165 | auto S_shared_tst = green::utils::shared_object(green::sc::ztensor<5>(nullptr, nts, ns, ink, nso, nso)); 166 | auto Sigma1 = green::sc::ztensor<4>(ns, ink, nso, nso); 167 | auto Sk = green::sc::ztensor<4>(ns, ink, nso, nso); 168 | for (int is = 0; is < ns; ++is) Sk(is) << bz.full_to_ibz(tmp(is)); 169 | { 170 | green::h5pp::archive ar(test_file, "r"); 171 | G_shared.fence(); 172 | if (!green::utils::context.node_rank) ar["G_tau"] >> G_shared.object(); 173 | G_shared.fence(); 174 | S_shared_tst.fence(); 175 | if (!green::utils::context.node_rank) ar["result/Sigma_tau"] >> S_shared_tst.object(); 176 | S_shared_tst.fence(); 177 | ar.close(); 178 | } 179 | green::mbpt::gf2_solver solver(p, ft, bz); 180 | solver.solve(G_shared, Sigma1, S_shared); 181 | REQUIRE_THAT(S_shared.object(), IsCloseTo(S_shared_tst.object(), 1e-6)); 182 | } 183 | 184 | TEST_CASE("MBPT Solver") { 185 | SECTION("HF") { solve_hf("/HF/input.h5", "/HF/df_hf_int", "/HF/data.h5"); } 186 | SECTION("HF_X2C") { solve_hf("/HF_X2C/input.h5", "/HF_X2C/df_hf_int", "/HF_X2C/data.h5"); } 187 | SECTION("GW") { solve_gw("/GW/input.h5", "/GW/df_int", "/GW/data.h5"); } 188 | SECTION("GW_C") { solve_gw("/GW/input.h5", "/GW/df_hf_int", "/GW/data_c.h5", "EXTRAPOLATE"); } 189 | SECTION("GW_X2C") { solve_gw("/GW_X2C/input.h5", "/GW_X2C/df_hf_int", "/GW_X2C/data.h5"); } 190 | 191 | SECTION("GF2") { solve_gf2(TEST_PATH + "/GF2/df_hf_int"s, TEST_PATH + "/GF2/data.h5"s, TEST_PATH + "/GF2/input.h5"s); } 192 | 193 | SECTION("GF2_Empty_Ewald") { 194 | solve_gf2(TEST_PATH + "/GF2/df_hf_int_z"s, TEST_PATH + "/GF2/data.h5"s, TEST_PATH + "/GF2/input.h5"s); 195 | } 196 | 197 | SECTION("GF2_Ewald") { 198 | solve_gf2(TEST_PATH + "/GF2/df_hf_int_e"s, TEST_PATH + "/GF2/data_e.h5"s, TEST_PATH + "/GF2/input_e.h5"s); 199 | } 200 | 201 | SECTION("Input Data Version") { 202 | auto p = green::params::params("DESCR"); 203 | std::string input_file = TEST_PATH + "/Input/input.h5"s; 204 | std::string df_int_path_1 = TEST_PATH + "/Input/df_int"s; 205 | std::string df_int_path_2 = TEST_PATH + "/Input/df_int_x"s; 206 | std::string df_int_path_3 = TEST_PATH + "/Input/df_int_y"s; 207 | std::string df_int_path_4 = TEST_PATH + "/Input/df_int_0.3.0"s; 208 | std::string grid_file = GRID_PATH + "/ir/1e4.h5"s; 209 | std::string args = 210 | "test --restart 0 --itermax 2 --E_thr 1e-13 --mixing_type G_MIXING --mixing_weight 0.8 --input_file=" + input_file + 211 | " --BETA 100 --verbose=1 --grid_file=" + grid_file + " --dfintegral_file=" + df_int_path_1 + 212 | " --dfintegral_hf_file=" + df_int_path_2; 213 | green::sc::define_parameters(p); 214 | green::symmetry::define_parameters(p); 215 | green::grids::define_parameters(p); 216 | green::mbpt::define_parameters(p); 217 | p.parse(args); 218 | green::symmetry::brillouin_zone_utils bz_utils(p); 219 | REQUIRE_THROWS_AS(green::mbpt::df_integral_t(df_int_path_1, 2, 36, bz_utils), green::mbpt::mbpt_outdated_input); 220 | REQUIRE_THROWS_AS(green::mbpt::df_integral_t(df_int_path_2, 2, 36, bz_utils), green::mbpt::mbpt_outdated_input); 221 | REQUIRE_NOTHROW(green::mbpt::df_integral_t(df_int_path_3, 2, 36, bz_utils)); 222 | REQUIRE_NOTHROW(green::mbpt::df_integral_t(df_int_path_4, 2, 36, bz_utils)); 223 | REQUIRE_THROWS_AS(green::mbpt::check_input(p), green::mbpt::mbpt_outdated_input); 224 | } 225 | 226 | SECTION("Test Version Strings") { 227 | std::vector fail_versions = {"0.2.0", "0.2.3"}; 228 | std::vector pass_versions = { 229 | "0.2.4", "0.2.4b10", "0.3.0", "0.3.0b8", "0.3.1", "0.3.1b10" 230 | }; 231 | for (int i=0; i < fail_versions.size() - 1; i++) { 232 | REQUIRE_FALSE(green::mbpt::CheckVersion(fail_versions[i])); 233 | } 234 | for (int i=0; i < pass_versions.size() - 1; i++) { 235 | REQUIRE(green::mbpt::CheckVersion(pass_versions[i])); 236 | } 237 | } 238 | 239 | SECTION("Init real Dyson") { 240 | auto p = green::params::params("DESCR"); 241 | std::string input_file = TEST_PATH + "/Dyson/input.h5"s; 242 | std::string grid_file = GRID_PATH + "/ir/1e4.h5"s; 243 | std::string args = 244 | "test --restart 0 --itermax 2 --E_thr 1e-13 --mixing_type G_MIXING --mixing_weight 0.8 --input_file=" + input_file + 245 | " --BETA 100 --verbose=1 --grid_file=" + grid_file; 246 | green::sc::define_parameters(p); 247 | green::symmetry::define_parameters(p); 248 | green::grids::define_parameters(p); 249 | green::mbpt::define_parameters(p); 250 | p.parse(args); 251 | green::sc::noop_solver noop; 252 | green::sc::sc_loop sc(MPI_COMM_WORLD, p); 253 | size_t nts; 254 | size_t ns = sc.dyson_solver().ns(); 255 | size_t nk = sc.dyson_solver().bz_utils().nk(); 256 | size_t ink = sc.dyson_solver().bz_utils().ink(); 257 | size_t nao = sc.dyson_solver().nao(); 258 | size_t nso = sc.dyson_solver().nso(); 259 | green::sc::ztensor<4> tmp; 260 | { 261 | green::h5pp::archive ar(input_file); 262 | green::sc::dtensor<5> H_k; 263 | green::sc::dtensor<5> F_k; 264 | ar["HF/H-k"] >> H_k; 265 | ar["HF/Fock-k"] >> F_k; 266 | ar.close(); 267 | F_k -= H_k; 268 | tmp.resize(ns, nk, nao, nao); 269 | tmp << F_k.view>().reshape(ns, nk, nao, nao); 270 | } 271 | nts = sc.dyson_solver().ft().sd().repn_fermi().nts(); 272 | green::symmetry::brillouin_zone_utils bz(p); 273 | auto G_shared = green::utils::shared_object(green::sc::ztensor<5>(nullptr, nts, ns, ink, nao, nao)); 274 | auto S_shared = green::utils::shared_object(green::sc::ztensor<5>(nullptr, nts, ns, ink, nao, nao)); 275 | auto Sigma1 = green::sc::ztensor<4>(ns, ink, nao, nao); 276 | S_shared.fence(); 277 | if (!green::utils::context.node_rank) S_shared.object().set_zero(); 278 | S_shared.fence(); 279 | Sigma1(0) << sc.dyson_solver().bz_utils().full_to_ibz(tmp(0)); 280 | Sigma1(1) << sc.dyson_solver().bz_utils().full_to_ibz(tmp(1)); 281 | sc.dyson_solver().mu() = -1.5; 282 | sc.solve(noop, sc.dyson_solver().H_k(), sc.dyson_solver().S_k(), G_shared, Sigma1, S_shared); 283 | } 284 | SECTION("Init real Dyson. non shared") { 285 | auto p = green::params::params("DESCR"); 286 | std::string input_file = TEST_PATH + "/Dyson/input.h5"s; 287 | std::string grid_file = GRID_PATH + "/ir/1e4.h5"s; 288 | std::string args = 289 | "test --restart 0 --itermax 2 --E_thr 1e-13 --mixing_type G_MIXING --mixing_weight 0.8 --input_file=" + input_file + 290 | " --BETA 100 --grid_file=" + grid_file; 291 | green::sc::define_parameters(p); 292 | green::symmetry::define_parameters(p); 293 | green::grids::define_parameters(p); 294 | green::mbpt::define_parameters(p); 295 | p.parse(args); 296 | green::sc::noop_solver noop; 297 | green::sc::sc_loop sc(MPI_COMM_WORLD, p); 298 | size_t nts, ns, nk, ink, nao; 299 | green::sc::ztensor<4> tmp; 300 | { 301 | green::h5pp::archive ar(input_file); 302 | ar["params/nao"] >> nao; 303 | ar["params/ns"] >> ns; 304 | ar["params/nk"] >> nk; 305 | ar["grid/ink"] >> ink; 306 | green::sc::dtensor<5> H_k; 307 | green::sc::dtensor<5> F_k; 308 | ar["HF/H-k"] >> H_k; 309 | ar["HF/Fock-k"] >> F_k; 310 | ar.close(); 311 | F_k -= H_k; 312 | tmp.resize(ns, nk, nao, nao); 313 | tmp << F_k.view>().reshape(ns, nk, nao, nao); 314 | } 315 | { 316 | green::h5pp::archive ar(grid_file); 317 | ar["fermi/metadata/ncoeff"] >> nts; 318 | ar.close(); 319 | nts += 2; 320 | } 321 | green::symmetry::brillouin_zone_utils bz(p); 322 | auto G = green::sc::ztensor<5>(nts, ns, ink, nao, nao); 323 | auto S = green::sc::ztensor<5>(nts, ns, ink, nao, nao); 324 | auto Sigma1 = green::sc::ztensor<4>(ns, ink, nao, nao); 325 | Sigma1(0) << bz.full_to_ibz(tmp(0)); 326 | Sigma1(1) << bz.full_to_ibz(tmp(1)); 327 | sc.solve(noop, sc.dyson_solver().H_k(), sc.dyson_solver().S_k(), G, Sigma1, S); 328 | } 329 | } 330 | 331 | int main(int argc, char** argv) { 332 | MPI_Init(&argc, &argv); 333 | int result = Catch::Session().run(argc, argv); 334 | MPI_Finalize(); 335 | return result; 336 | } 337 | -------------------------------------------------------------------------------- /test/tensor_test.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022 University of Michigan. 3 | * 4 | */ 5 | 6 | #ifndef GREEN_MBPT_TENSOR_TEST_H 7 | #define GREEN_MBPT_TENSOR_TEST_H 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | // Catch2 Matcher class that checks proximity of two tensors 16 | template 17 | class IsCloseToMatcher : public Catch::Matchers::MatcherBase> { 18 | using tensor_t = green::ndarray::ndarray; 19 | tensor_t const& ref; 20 | double tol; 21 | 22 | public: 23 | template 24 | IsCloseToMatcher(R const& ref, double tol) : ref(ref), tol(tol) {} 25 | 26 | bool match(tensor_t const& x) const override { 27 | if (x.shape() != ref.shape()) return false; 28 | bool res = 29 | std::equal(x.data(), x.data() + x.size(), ref.data(), [this](T const& a, T const& b) { return std::abs(a - b) < tol; }); 30 | return res; 31 | } 32 | 33 | virtual std::string describe() const override { 34 | std::ostringstream ss; 35 | ss << "is close to Tensor with leading dimension [" << ref.shape()[0] << "] (tol = " << tol << ")"; 36 | return ss.str(); 37 | } 38 | }; 39 | 40 | template 41 | inline IsCloseToMatcher IsCloseTo(green::ndarray::ndarray const& ref, double tol = 1e-10) { 42 | return IsCloseToMatcher(ref, tol); 43 | } 44 | 45 | #endif // GREEN_MBPT_TENSOR_TEST_H 46 | --------------------------------------------------------------------------------