pax_global_header00006660000000000000000000000064133656445110014522gustar00rootroot0000000000000052 comment=4a6579a77979a8ae1b82e921d3bdc97dd175f386 CheMPS2-1.8.9/000077500000000000000000000000001336564451100127025ustar00rootroot00000000000000CheMPS2-1.8.9/.gitignore000066400000000000000000000002671336564451100146770ustar00rootroot00000000000000mycompilation build Build objects *~ *.o *.swp integrals/pyscf/*.pyc PyCheMPS2/build PyCheMPS2/PyCheMPS2.cpp PyCheMPS2/tests/*.h5 integrals/molcas/a.out integrals/molcas/molcas_*.h5 CheMPS2-1.8.9/.travis.yml000066400000000000000000000015161336564451100150160ustar00rootroot00000000000000language: cpp addons: apt: sources: # Clang 5.0 - llvm-toolchain-trusty-5.0 # Newer GCC - ubuntu-toolchain-r-test packages: - cmake - cmake-data - liblapack-dev - libhdf5-serial-dev - gcc-7 - g++-7 - clang-5.0 env: global: # should be limited to 4 on travis - OMP_NUM_THREADS=4 # make cmake verbose - VERBOSE=1 matrix: # test three different compilers - OUR_CXX='clang++-5.0' OUR_CC='clang-5.0' BUILD_TYPE='release' - OUR_CXX='g++-7' OUR_CC='gcc-7' BUILD_TYPE='release' install: - mkdir build - cd build - cmake -DCMAKE_C_COMPILER=$OUR_CC -DCMAKE_CXX_COMPILER=$OUR_CXX -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. - make script: # we put a timeout of 90 minutes - travis_wait 90 make test ARGS="-V" CheMPS2-1.8.9/CHANGELOG.md000066400000000000000000000066771336564451100145330ustar00rootroot00000000000000#### Version 1.8.9 LTS update (2018-10-29): * Bug fix long double literal Wigner.cpp #### Version 1.8.8 LTS update (2018-09-26): * Print the number of MPS variables #### Version 1.8.7 LTS update (2018-03-25): * Bump up SO version from 2 to 3 #### Version 1.8.6 LTS update (2018-03-16): * Set initial guess to an ROHF determinant (for @quanp) #### Version 1.8.5 LTS update (2018-01-18): * Fix build; bump up required CMake (thanks @quanp) #### Version 1.8.4 LTS update (2017-05-23): * MOLCAS state average CASPT2 interface (thanks @quanp) * Update build system for psi4 (thanks @loriab) #### Version 1.8.3 LTS update (2016-11-15): * Custom orbital reordering for MOLCAS interface * Fix building PyCheMPS2 (thanks @loriab) #### Version 1.8.2 LTS update (2016-10-26): * Fix PyCheMPS2 build #### Version 1.8.1 LTS update (2016-10-25): * MPS checkpoint for MOLCAS interface * Fiedler order checkpoint for MOLCAS interface #### Version 1.8 LTS (2016-08-24): * Fix slow convergence linear Davidson algorithm * Fix MPI bug binary * MOLCAS interface binary (2-RDM, 3-RDM, and F.4-RDM dump) * Fortran example to read in CASPT2 intermediates for MOLCAS #### Version 1.7.3 (2016-07-14): * DMRG workshop in sphinx documentation #### Version 1.7.2 (2016-07-07): * Rotate molden files with DMRG-SCF unitary from executable #### Version 1.7.1 (2016-06-29): * Global reordering of the active space orbitals (mixing irreps) based on Fiedler vector of the exchange matrix * Davidson algorithm for linear systems (for CASPT2) #### Version 1.7 (2016-05-24): * Class ConjugateGradient * Class TensorOperator * Class ThreeDM: DMRG 3-RDM in O(L^4 D^3 + L^6 D^2) * Class Cumulant: Cumulant reconstruction of the DMRG 4-RDM * Class CASPT2: Internally contracted CASPT2 * Class Molden: Rotate molpro/psi4 molden to CAS orbitals * Class Excitation: Build |1> = ( b + a * ( E_ij + E_ji )) |0> * Part of DMRG 4-RDM via DMRG::Symm4RDM * DMRG sweeps after RDM calculation allowed * FCI 3-RDM in FCI::Fill3RDM * FCI 4-RDM in FCI::Fill4RDM * FCI diagonal 4-RDM in FCI::Diag4RDM * FCI 4-RDM contraction with Fock operator in FCI::Fock4RDM * Blockwise ERI rotations with DMRGSCFrotations using disk * Update binary for DMRG-CASPT2 * Break API: bump up SO version * Deprecate TwoDMstorage class * Deprecate TensorDiag class * Deprecate TensorSwap class * Deprecate TensorS0Abase class * Deprecate TensorS1Bbase class * Deprecate TensorF0Cbase class * Deprecate TensorF1Dbase class * Deprecate TensorA class * Deprecate TensorB class * Deprecate TensorC class * Deprecate TensorD class #### Version 1.6 (2015-08-26): * Disk i/o improvements with HDF5's hyperslab * Performance counters in DMRG class * Faster preconditioner FCI Green's function solver * Bug fix FCIDUMP read-in * chemps2 binary * manpage for binary #### Version 1.5 (2015-06-18): * DMRG-CI plugin pyscf * DMRG-SCF plugin psi4 (official release for psi4) * Fix bug small electron number FCI class * FCIDUMP file support * Sphinx documentation * DMRG class supports 4-fold permutation symmetry (i.o. 8-fold) * Hybrid MPI & OpenMP for DMRG + 2-RDM (not for DMRG-SCF yet) #### Version 1.4 (2014-11-23): * 2-RDM storage class * Optimization OpenMP over symmetry blocks Heff * DIIS acceleration DMRG-SCF * Two-orbital mutual information and correlation functions * Augmented Hessian NR Edmiston-Ruedenberg orbital localization * PyCheMPS2: python interface to libchemps2 * FCI Green's function solver * State-averaged DMRG-SCF #### Version 1.0 (2014-04-08): * Initial release CheMPS2-1.8.9/CMake/000077500000000000000000000000001336564451100136625ustar00rootroot00000000000000CheMPS2-1.8.9/CMake/CheMPS2Config.cmake.in000066400000000000000000000116361336564451100175670ustar00rootroot00000000000000# CheMPS2Config.cmake # ------------------ # # CheMPS2 cmake module. # This module sets the following variables in your project:: # # CheMPS2_FOUND - true if CheMPS2 and all required components found on the system # CheMPS2_VERSION - CheMPS2 version in format Major.Minor.Release # CheMPS2_INCLUDE_DIRS - Directory where chemps2/DMRG.h header is located. # CheMPS2_INCLUDE_DIR - same as DIRS # CheMPS2_DEFINITIONS: Definitions necessary to use CheMPS2, namely USING_CheMPS2. # CheMPS2_LIBRARIES - CheMPS2 library to link against. # CheMPS2_LIBRARY - same as LIBRARIES # CheMPS2_EXECUTABLE - path to CheMPS2 executable # # # Available components: shared static exe :: # # shared - search for only shared library # static - search for only static library # exe - search for executable as well as library # # # Exported targets:: # # If CheMPS2 is found, this module defines the following :prop_tgt:`IMPORTED` # target. :: # # CheMPS2::chemps2 - the main CheMPS2 library with header & defs attached. # # # Suggested usage:: # # find_package(CheMPS2) # find_package(CheMPS2 1.8 CONFIG REQUIRED COMPONENTS shared) # # # The following variables can be set to guide the search for this package:: # # CheMPS2_DIR - CMake variable, set to directory containing this Config file # CMAKE_PREFIX_PATH - CMake variable, set to root directory of this package # PATH - environment variable, set to bin directory of this package # CMAKE_DISABLE_FIND_PACKAGE_CheMPS2 - CMake variable, disables # find_package(CheMPS2) perhaps to force internal build @PACKAGE_INIT@ set(PN CheMPS2) set (_valid_components static shared exe ) # find includes unset(_temp_h CACHE) find_path(_temp_h NAMES chemps2/DMRG.h PATHS ${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_INCLUDEDIR@ NO_DEFAULT_PATH) if(_temp_h) set(${PN}_INCLUDE_DIR "${_temp_h}") set(${PN}_INCLUDE_DIRS ${${PN}_INCLUDE_DIR}) else() set(${PN}_FOUND 0) if(NOT CMAKE_REQUIRED_QUIET) message(STATUS "${PN}Config missing component: header (${PN}: ${_temp_h})") endif() endif() # find executable list(FIND ${PN}_FIND_COMPONENTS "exe" _seek_exe) unset(_temp_exe CACHE) find_program(_temp_exe NAMES chemps2 PATHS ${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_BINDIR@ NO_DEFAULT_PATH) if(_temp_exe) set(${PN}_EXECUTABLE "{_temp_exe}") if(_seek_exe GREATER -1) set(${PN}_exe_FOUND 1) endif() else() if(_seek_exe GREATER -1) if(NOT CMAKE_REQUIRED_QUIET) message(STATUS "${PN}Config missing component: executable (${PN}: ${_temp_exe})") endif() endif() endif() # find library: shared, static, or whichever set(_hold_library_suffixes ${CMAKE_FIND_LIBRARY_SUFFIXES}) list(FIND ${PN}_FIND_COMPONENTS "shared" _seek_shared) list(FIND ${PN}_FIND_COMPONENTS "static" _seek_static) if(_seek_shared GREATER -1) set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX}) elseif(_seek_static GREATER -1) set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) endif() unset(_temp CACHE) find_library(_temp NAMES chemps2 PATHS ${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_LIBDIR@ NO_DEFAULT_PATH) if(_temp) set(${PN}_LIBRARY "${_temp}") if(_seek_shared GREATER -1) set(${PN}_shared_FOUND 1) elseif(_seek_static GREATER -1) set(${PN}_static_FOUND 1) endif() else() if(_seek_shared GREATER -1) if(NOT CMAKE_REQUIRED_QUIET) message(STATUS "${PN}Config missing component: shared library (${PN}: ${_temp})") endif() elseif(_seek_static GREATER -1) if(NOT CMAKE_REQUIRED_QUIET) message(STATUS "${PN}Config missing component: static library (${PN}: ${_temp})") endif() else() set(${PN}_FOUND 0) if(NOT CMAKE_REQUIRED_QUIET) message(STATUS "${PN}Config missing component: library (${PN}: ${_temp})") endif() endif() endif() set(CMAKE_FIND_LIBRARY_SUFFIXES ${_hold_library_suffixes}) set(${PN}_LIBRARIES ${${PN}_LIBRARY}) set(${PN}_DEFINITIONS USING_${PN}) check_required_components(${PN}) # make detectable the FindTarget*.cmake modules list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) #----------------------------------------------------------------------------- # Don't include targets if this file is being picked up by another # project which has already built this as a subproject #----------------------------------------------------------------------------- if(NOT TARGET ${PN}::chemps2) get_filename_component(_fext ${${PN}_LIBRARY} EXT) if(${_fext} STREQUAL ${CMAKE_SHARED_LIBRARY_SUFFIX}) include("${CMAKE_CURRENT_LIST_DIR}/${PN}Targets-shared.cmake") else() include("${CMAKE_CURRENT_LIST_DIR}/${PN}Targets-static.cmake") endif() include(CMakeFindDependencyMacro) if(NOT TARGET tgt::hdf5) find_dependency(TargetHDF5 @TargetHDF5_VERSION@ EXACT) endif() endif() CheMPS2-1.8.9/CMake/FindSphinx.cmake000066400000000000000000000020751336564451100167420ustar00rootroot00000000000000# - This module looks for Sphinx # Find the Sphinx documentation generator # # This modules defines # SPHINX_EXECUTABLE # SPHINX_FOUND #============================================================================= # Copyright 2002-2009 Kitware, Inc. # Copyright 2009-2011 Peter Colberg # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file COPYING-CMAKE-SCRIPTS for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) find_program(SPHINX_EXECUTABLE NAMES sphinx-build HINTS $ENV{SPHINX_DIR} PATH_SUFFIXES bin DOC "Sphinx documentation generator" ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Sphinx DEFAULT_MSG SPHINX_EXECUTABLE ) mark_as_advanced( SPHINX_EXECUTABLE ) CheMPS2-1.8.9/CMake/FindTargetHDF5.cmake000066400000000000000000000064401336564451100173260ustar00rootroot00000000000000# FindTargetHDF5.cmake # -------------------- # # HDF5 cmake module to wrap FindHDF5.cmake in a target. # # This module sets the following variables in your project: :: # # TargetHDF5_FOUND - true if HDF5 and all required components found on the system # TargetHDF5_VERSION - HDF5 version in format Major.Minor.Release # TargetHDF5_MESSAGE - status message with HDF5 library path list and version # # Note that components are passed along to find_package(HDF5 (untested) but not checked in the direct TargetHDF5Config # Note that version checking/attaching not working yet # # This module *unsets* the following conventional HDF5 variables so as # to force using the target: :: # # HDF5_FOUND # HDF5_VERSION # HDF5_INCLUDE_DIRS # HDF5_LIBRARIES # # Exported targets:: # # If HDF5 is found, this module defines the following :prop_tgt:`IMPORTED` # target. :: # # tgt::hdf5 - the HDF5 libraries with headers attached. # # Suggested usage:: # # find_package(TargetHDF5) # find_package(TargetHDF5 1.8.16 REQUIRED) # # # The following variables can be set to guide the search for this package:: # # TargetHDF5_DIR - CMake variable, set to directory containing this Config file # CMAKE_PREFIX_PATH - CMake variable, set to root directory of this package set(PN TargetHDF5) # 1st precedence - libraries passed in through -DHDF5_LIBRARIES if (HDF5_LIBRARIES AND HDF5_INCLUDE_DIRS) if (HDF5_VERSION) if (NOT ${PN}_FIND_QUIETLY) message (STATUS "HDF5 detection suppressed.") endif() add_library (tgt::hdf5 INTERFACE IMPORTED) set_property (TARGET tgt::hdf5 PROPERTY INTERFACE_LINK_LIBRARIES ${HDF5_LIBRARIES}) set_property (TARGET tgt::hdf5 PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${HDF5_INCLUDE_DIRS}) set (${PN}_VERSION ${HDF5_VERSION}) else() message (FATAL_ERROR "Humor the build system - pass in the version, too (for example, -DHDF5_VERSION=1.8.17).") endif() else() # 2nd precedence - target already prepared and findable in TargetHDF5Config.cmake find_package (TargetHDF5 QUIET CONFIG) if ((TARGET tgt::hdf5) AND (${PN}_VERSION)) if (NOT ${PN}_FIND_QUIETLY) message (STATUS "TargetHDF5Config detected.") endif() else() # 3rd precedence - usual variables from FindHDF5.cmake find_package (HDF5 QUIET COMPONENTS ${HDF5_FIND_COMPONENTS}) if (NOT ${PN}_FIND_QUIETLY) message (STATUS "HDF5 detected.") endif() add_library (tgt::hdf5 INTERFACE IMPORTED) set_property (TARGET tgt::hdf5 PROPERTY INTERFACE_LINK_LIBRARIES ${HDF5_LIBRARIES}) set_property (TARGET tgt::hdf5 PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${HDF5_INCLUDE_DIRS}) set (${PN}_VERSION ${HDF5_VERSION}) unset (HDF5_FOUND) unset (HDF5_VERSION) unset (HDF5_LIBRARIES) unset (HDF5_INCLUDE_DIRS) endif() endif() get_property(_ill TARGET tgt::hdf5 PROPERTY INTERFACE_LINK_LIBRARIES) get_property(_iid TARGET tgt::hdf5 PROPERTY INTERFACE_INCLUDE_DIRECTORIES) set(${PN}_MESSAGE "Found HDF5: ${_ill} (found version ${${PN}_VERSION})") include(FindPackageHandleStandardArgs) find_package_handle_standard_args(${PN} REQUIRED_VARS ${PN}_MESSAGE VERSION_VAR ${PN}_VERSION) CheMPS2-1.8.9/CMake/FindTargetLAPACK.cmake000066400000000000000000000046501336564451100175740ustar00rootroot00000000000000# FindTargetLAPACK.cmake # ---------------------- # # LAPACK cmake module to wrap FindLAPACK.cmake in a target. # # This module sets the following variables in your project: :: # # TargetLAPACK_FOUND - true if BLAS/LAPACK found on the system # TargetLAPACK_MESSAGE - status message with BLAS/LAPACK library path list # # This module *unsets* the following conventional LAPACK variables so as # to force using the target: :: # # LAPACK_FOUND # LAPACK_LIBRARIES # # In order of decreasing precedence, this module returns in a target ``tgt::lapack`` # (1) the libraries passed through CMake variable LAPACK_LIBRARIES, # (2) the libraries defined in a detectable TargetLAPACKConfig.cmake file # (skip via DISABLE_FIND_PACKAGE_TargetLAPACK), or # (3) the libraries detected by the usual FindLAPACK.cmake module. # set(PN TargetLAPACK) # 1st precedence - libraries passed in through -DLAPACK_LIBRARIES if (LAPACK_LIBRARIES) if (NOT ${PN}_FIND_QUIETLY) message (STATUS "LAPACK detection suppressed.") endif() add_library (tgt::lapack INTERFACE IMPORTED) set_property (TARGET tgt::lapack PROPERTY INTERFACE_LINK_LIBRARIES ${LAPACK_LIBRARIES}) else() # 2nd precedence - target already prepared and findable in TargetLAPACKConfig.cmake if (NOT "${DISABLE_FIND_PACKAGE_${PN}}") find_package (TargetLAPACK QUIET CONFIG) endif() if (TARGET tgt::lapack) if (NOT ${PN}_FIND_QUIETLY) message (STATUS "TargetLAPACKConfig detected.") endif() else() # 3rd precedence - usual variables from FindLAPACK.cmake find_package (LAPACK QUIET MODULE) if (NOT ${PN}_FIND_QUIETLY) message (STATUS "LAPACK detected.") endif() add_library (tgt::lapack INTERFACE IMPORTED) set_property (TARGET tgt::lapack PROPERTY INTERFACE_LINK_LIBRARIES ${LAPACK_LIBRARIES}) unset (LAPACK_FOUND) unset (LAPACK_LIBRARIES) endif() endif() get_property (_ill TARGET tgt::lapack PROPERTY INTERFACE_LINK_LIBRARIES) set (${PN}_MESSAGE "Found LAPACK: ${_ill}") if ((TARGET tgt::blas) AND (TARGET tgt::lapk)) get_property (_illb TARGET tgt::blas PROPERTY INTERFACE_LINK_LIBRARIES) get_property (_illl TARGET tgt::lapk PROPERTY INTERFACE_LINK_LIBRARIES) set (${PN}_MESSAGE "Found LAPACK: ${_illl};${_illb}") endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args (${PN} DEFAULT_MSG ${PN}_MESSAGE) CheMPS2-1.8.9/CMakeLists.txt000066400000000000000000000127771336564451100154600ustar00rootroot00000000000000project (CheMPS2) set (CheMPS2_MMP_VERSION "1.8.9") set (CheMPS2_VERSION "${CheMPS2_MMP_VERSION} (2018-10-29)") #set (CheMPS2_VERSION "${CheMPS2_MMP_VERSION}-15 (2017-05-22)") set (CheMPS2_AUTHORS "Sebastian Wouters") set (CheMPS2_DESCRIPTION "A spin-adapted implementation of DMRG for ab initio quantum chemistry") set (CheMPS2_EMAIL "sebastianwouters@gmail.com") set (CheMPS2_URL "https://github.com/SebWouters/CheMPS2") set (CheMPS2_LICENSE "GNU General Public License, version 2") set (CheMPS2_LIB_SOVERSION 3) cmake_minimum_required (VERSION 3.0.2) # <<< CMake includes >>> include (GNUInstallDirs) include (CheckCXXCompilerFlag) include (CMakePackageConfigHelpers) # <<< Default CMake options >>> option (MKL "Compile using the MKL" OFF) option (BUILD_DOXYGEN "Use Doxygen to create a HTML/PDF manual" OFF) option (BUILD_SPHINX "Build the user manual with Sphinx" OFF) option (STATIC_ONLY "Compile only the static library" OFF) option (SHARED_ONLY "Compile only the shared library" OFF) option (ENABLE_TESTS "Compile the tests" ON) option (ENABLE_XHOST "Enable processor-specific optimizations" ON) option (ENABLE_GENERIC "Enable mostly static linking in shared library" OFF) option (ENABLE_OPENMP "Enable OpenMP parallelization" ON) option (WITH_MPI "Build the library with MPI" OFF) option (BUILD_FPIC "Static library in STATIC_ONLY will be compiled with position independent code" OFF) set (CMAKE_VERBOSE_MAKEFILE OFF) set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CheMPS2_SOURCE_DIR}/CMake/") if (STATIC_ONLY AND SHARED_ONLY) message (FATAL_ERROR "The options STATIC_ONLY=ON and SHARED_ONLY=ON are conflicting." ) endif() # <<< Enable MPI >>> if (WITH_MPI) add_definitions (-DCHEMPS2_MPI_COMPILATION) endif () # <<< Pass CheMPS2 version >>> add_definitions(-DCHEMPS2_VERSION="${CheMPS2_VERSION}") # <<< Check build type >>> if (NOT CMAKE_BUILD_TYPE) set (CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) endif() message("-- The CMake build type is ${CMAKE_BUILD_TYPE}") # <<< Enable OpenMP >>> if (ENABLE_OPENMP) find_package (OpenMP) if (OPENMP_FOUND) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() endif() # <<< Enable host specific optimizations >>> if (ENABLE_XHOST) check_cxx_compiler_flag (-xHost HAS_XHOST) check_cxx_compiler_flag (-march=native HAS_MARCH_NATIVE) if (HAS_XHOST) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -xHost") elseif (HAS_MARCH_NATIVE) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") endif() endif() # <<< Enable inter-parts / link-time optimization >>> check_cxx_compiler_flag (-ipo HAS_IPO) if (HAS_IPO) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ipo") endif() check_cxx_compiler_flag (-flto HAS_FLTO) if (HAS_FLTO) set (CMAKE_CXX_FLAGS "-flto ${CMAKE_CXX_FLAGS}") endif() # <<< Enable generic >>> if (ENABLE_GENERIC) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++ -static-libgcc") check_cxx_compiler_flag (-static-intel HAS_INTEL_COMPILERS) if (HAS_INTEL_COMPILERS) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-intel -wd10237") endif() endif() # <<< Find LAPACK and BLAS >>> link_directories ($ENV{LD_LIBRARY_PATH}) if (MKL) set (ENV{BLA_VENDOR} "Intel10_64lp") endif() find_package (TargetLAPACK REQUIRED) get_property(_lapack_libraries TARGET tgt::lapack PROPERTY INTERFACE_LINK_LIBRARIES) foreach (_l IN LISTS _lapack_libraries) if (${_l} MATCHES "mkl") set (MKL "ON") endif() endforeach() if (MKL) add_definitions (-DCHEMPS2_MKL) endif () # <<< Find HDF5 >>> find_package (TargetHDF5 REQUIRED) # <<< Add source files, tests, sphinx, and doxygen >>> enable_testing () add_subdirectory (CheMPS2) if (ENABLE_TESTS) add_subdirectory (tests) endif() if (BUILD_SPHINX) add_subdirectory (sphinx) endif() if (BUILD_DOXYGEN) find_package (Doxygen) if (NOT DOXYGEN_FOUND) message (FATAL_ERROR "Doxygen is needed to build the documentation. Please install it correctly.") endif() configure_file (${CheMPS2_SOURCE_DIR}/CheMPS2/Doxyfile.in ${CheMPS2_BINARY_DIR}/Doxyfile @ONLY IMMEDIATE) add_custom_target (doc COMMAND ${DOXYGEN_EXECUTABLE} ${CheMPS2_BINARY_DIR}/Doxyfile SOURCES ${CheMPS2_BINARY_DIR}/Doxyfile) endif() # <<< Export config >>> # GNUInstallDirs "DATADIR" wrong here; CMake search path wants "share". set (CMAKECONFIG_INSTALL_DIR "share/cmake/${PROJECT_NAME}") configure_package_config_file (${CheMPS2_SOURCE_DIR}/CMake/${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}) write_basic_package_version_file (${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${CheMPS2_MMP_VERSION} COMPATIBILITY AnyNewerVersion) install (FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake ${CheMPS2_SOURCE_DIR}/CMake/FindTargetHDF5.cmake DESTINATION ${CMAKECONFIG_INSTALL_DIR}) CheMPS2-1.8.9/CheMPS2/000077500000000000000000000000001336564451100140435ustar00rootroot00000000000000CheMPS2-1.8.9/CheMPS2/CASPT2.cpp000066400000000000000000014105001336564451100155040ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include "CASPT2.h" #include "Lapack.h" #include "Options.h" #include "ConjugateGradient.h" #include "Davidson.h" #include "Special.h" using std::cout; using std::endl; using std::min; using std::max; CheMPS2::CASPT2::CASPT2( DMRGSCFindices * idx, DMRGSCFintegrals * ints, DMRGSCFmatrix * oei, DMRGSCFmatrix * fock_in, double * one_dm, double * two_dm, double * three_dm, double * contract_4dm, const double IPEA ){ indices = idx; fock = fock_in; one_rdm = one_dm; two_rdm = two_dm; three_rdm = three_dm; f_dot_4dm = contract_4dm; num_irreps = indices->getNirreps(); struct timeval start, end; gettimeofday( &start, NULL ); create_f_dots(); vector_helper(); make_AA_CC( true, 0.0 ); make_DD( true, 0.0 ); make_EE_GG( true, 0.0 ); make_BB_FF_singlet( true, 0.0 ); make_BB_FF_triplet( true, 0.0 ); construct_rhs( oei, ints ); make_AA_CC( false, IPEA ); make_DD( false, IPEA ); make_EE_GG( false, IPEA ); make_BB_FF_singlet( false, IPEA ); make_BB_FF_triplet( false, IPEA ); make_FAD_FCD(); make_FEH_FGH(); make_FAB_FCF_singlet(); make_FAB_FCF_triplet(); make_FBE_FFG_singlet(); make_FBE_FFG_triplet(); make_FDE_FDG(); delete [] f_dot_3dm; delete [] f_dot_2dm; gettimeofday( &end, NULL ); double elapsed = ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); cout << "CASPT2 : Wall time tensors = " << elapsed << " seconds" << endl; gettimeofday( &start, NULL ); recreate(); gettimeofday( &end, NULL ); elapsed = ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); cout << "CASPT2 : Wall time diag(ovlp) = " << elapsed << " seconds" << endl; } CheMPS2::CASPT2::~CASPT2(){ for ( int irrep = 0; irrep < num_irreps; irrep++ ){ delete [] FAA[ irrep ]; delete [] FCC[ irrep ]; delete [] FDD[ irrep ]; delete [] FEE[ irrep ]; delete [] FGG[ irrep ]; delete [] FBB_singlet[ irrep ]; delete [] FBB_triplet[ irrep ]; delete [] FFF_singlet[ irrep ]; delete [] FFF_triplet[ irrep ]; } delete [] FAA; delete [] FCC; delete [] FDD; delete [] FEE; delete [] FGG; delete [] FBB_singlet; delete [] FBB_triplet; delete [] FFF_singlet; delete [] FFF_triplet; for ( int irrep_left = 0; irrep_left < num_irreps; irrep_left++ ){ for ( int irrep_right = 0; irrep_right < num_irreps; irrep_right++ ){ const int irrep_w = Irreps::directProd( irrep_left, irrep_right ); const int num_w = indices->getNDMRG( irrep_w ); for ( int w = 0; w < num_w; w++ ){ delete [] FAD[ irrep_left ][ irrep_right ][ w ]; delete [] FCD[ irrep_left ][ irrep_right ][ w ]; delete [] FAB_singlet[ irrep_left ][ irrep_right ][ w ]; delete [] FAB_triplet[ irrep_left ][ irrep_right ][ w ]; delete [] FCF_singlet[ irrep_left ][ irrep_right ][ w ]; delete [] FCF_triplet[ irrep_left ][ irrep_right ][ w ]; delete [] FBE_singlet[ irrep_left ][ irrep_right ][ w ]; delete [] FBE_triplet[ irrep_left ][ irrep_right ][ w ]; delete [] FFG_singlet[ irrep_left ][ irrep_right ][ w ]; delete [] FFG_triplet[ irrep_left ][ irrep_right ][ w ]; delete [] FDE_singlet[ irrep_left ][ irrep_right ][ w ]; delete [] FDE_triplet[ irrep_left ][ irrep_right ][ w ]; delete [] FDG_singlet[ irrep_left ][ irrep_right ][ w ]; delete [] FDG_triplet[ irrep_left ][ irrep_right ][ w ]; } delete [] FAD[ irrep_left ][ irrep_right ]; delete [] FCD[ irrep_left ][ irrep_right ]; delete [] FAB_singlet[ irrep_left ][ irrep_right ]; delete [] FAB_triplet[ irrep_left ][ irrep_right ]; delete [] FCF_singlet[ irrep_left ][ irrep_right ]; delete [] FCF_triplet[ irrep_left ][ irrep_right ]; delete [] FBE_singlet[ irrep_left ][ irrep_right ]; delete [] FBE_triplet[ irrep_left ][ irrep_right ]; delete [] FFG_singlet[ irrep_left ][ irrep_right ]; delete [] FFG_triplet[ irrep_left ][ irrep_right ]; delete [] FDE_singlet[ irrep_left ][ irrep_right ]; delete [] FDE_triplet[ irrep_left ][ irrep_right ]; delete [] FDG_singlet[ irrep_left ][ irrep_right ]; delete [] FDG_triplet[ irrep_left ][ irrep_right ]; } delete [] FAD[ irrep_left ]; delete [] FCD[ irrep_left ]; delete [] FAB_singlet[ irrep_left ]; delete [] FAB_triplet[ irrep_left ]; delete [] FCF_singlet[ irrep_left ]; delete [] FCF_triplet[ irrep_left ]; delete [] FBE_singlet[ irrep_left ]; delete [] FBE_triplet[ irrep_left ]; delete [] FFG_singlet[ irrep_left ]; delete [] FFG_triplet[ irrep_left ]; delete [] FDE_singlet[ irrep_left ]; delete [] FDE_triplet[ irrep_left ]; delete [] FDG_singlet[ irrep_left ]; delete [] FDG_triplet[ irrep_left ]; } delete [] FAD; delete [] FCD; delete [] FAB_singlet; delete [] FAB_triplet; delete [] FCF_singlet; delete [] FCF_triplet; delete [] FBE_singlet; delete [] FBE_triplet; delete [] FFG_singlet; delete [] FFG_triplet; delete [] FDE_singlet; delete [] FDE_triplet; delete [] FDG_singlet; delete [] FDG_triplet; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int num_w = indices->getNDMRG( irrep ); for ( int w = 0; w < num_w; w++ ){ delete [] FEH[ irrep ][ w ]; delete [] FGH[ irrep ][ w ]; } delete [] FEH[ irrep ]; delete [] FGH[ irrep ]; } delete [] FEH; delete [] FGH; delete [] size_A; delete [] size_C; delete [] size_D; delete [] size_E; delete [] size_G; delete [] size_B_singlet; delete [] size_B_triplet; delete [] size_F_singlet; delete [] size_F_triplet; delete [] jump; delete [] vector_rhs; } double CheMPS2::CASPT2::solve( const double imag_shift, const bool CONJUGATE_GRADIENT ) const{ struct timeval start, end; gettimeofday( &start, NULL ); // Normalizations of sectors A Bs Bt C D Es Et Fs Ft Gs Gt Hs Ht const int normalizations[] = { 1, 2, 2, 1, 1, 2, 6, 2, 2, 2, 6, 4, 12 }; const bool apply_shift = (( fabs( imag_shift ) > 0.0 ) ? true : false ); int total_size = jump[ CHEMPS2_CASPT2_NUM_CASES * num_irreps ]; double * diag_fock = new double[ total_size ]; diagonal( diag_fock ); double min_eig = diag_fock[ 0 ]; for ( int elem = 1; elem < total_size; elem++ ){ min_eig = min( min_eig, diag_fock[ elem ] ); } cout << "CASPT2 : Solution algorithm = " << (( CONJUGATE_GRADIENT ) ? "Conjugate Gradient" : "Davidson" ) << endl; cout << "CASPT2 : Minimum(diagonal) = " << min_eig << endl; ConjugateGradient * CG = (( CONJUGATE_GRADIENT ) ? new ConjugateGradient( total_size, CheMPS2::CONJ_GRADIENT_RTOL, CheMPS2::CONJ_GRADIENT_PRECOND_CUTOFF, false ) : NULL ); Davidson * DAVID = (( CONJUGATE_GRADIENT ) ? NULL : new Davidson( total_size, CheMPS2::DAVIDSON_NUM_VEC, CheMPS2::DAVIDSON_NUM_VEC_KEEP, CheMPS2::CONJ_GRADIENT_RTOL, CheMPS2::CONJ_GRADIENT_PRECOND_CUTOFF, true, // debug_print 'L' )); // Linear problem double ** pointers = new double*[ 3 ]; char instruction = (( CONJUGATE_GRADIENT ) ? CG->step( pointers ) : DAVID->FetchInstruction( pointers )); assert( instruction == 'A' ); for ( int elem = 0; elem < total_size; elem++ ){ pointers[ 0 ][ elem ] = vector_rhs[ elem ] / diag_fock[ elem ]; } // Initial guess of F * x = V for ( int elem = 0; elem < total_size; elem++ ){ pointers[ 1 ][ elem ] = diag_fock[ elem ]; } // Diagonal of the operator F for ( int elem = 0; elem < total_size; elem++ ){ pointers[ 2 ][ elem ] = vector_rhs[ elem ]; } // RHS of the linear problem F * x = V int inc1 = 1; const double E2_DIAGONAL = - ddot_( &total_size, pointers[ 0 ], &inc1, pointers[ 2 ], &inc1 ); instruction = (( CONJUGATE_GRADIENT ) ? CG->step( pointers ) : DAVID->FetchInstruction( pointers )); assert( instruction == 'B' ); while ( instruction == 'B' ){ matvec( pointers[ 0 ], pointers[ 1 ], diag_fock ); if ( apply_shift ){ add_shift( pointers[ 0 ], pointers[ 1 ], diag_fock, imag_shift, normalizations ); } instruction = (( CONJUGATE_GRADIENT ) ? CG->step( pointers ) : DAVID->FetchInstruction( pointers )); } assert( instruction == 'C' ); const double E2_NONVARIATIONAL = - ddot_( &total_size, pointers[ 0 ], &inc1, vector_rhs, &inc1 ); const double rnorm = pointers[ 1 ][ 0 ]; cout << "CASPT2 : Number of iterations = " << (( CONJUGATE_GRADIENT ) ? CG->get_num_matvec() : DAVID->GetNumMultiplications() ) << endl; cout << "CASPT2 : Residual norm = " << rnorm << endl; matvec( pointers[ 0 ], pointers[ 1 ], diag_fock ); // pointers[ 1 ] is a WORK array when instruction == 'C' const double E2_VARIATIONAL = 2 * E2_NONVARIATIONAL + ddot_( &total_size, pointers[ 0 ], &inc1, pointers[ 1 ], &inc1 ); delete [] diag_fock; const double inproduct = inproduct_vectors( pointers[ 0 ], pointers[ 0 ], normalizations ); const double reference_weight = 1.0 / ( 1.0 + inproduct ); cout << "CASPT2 : Reference weight = " << reference_weight << endl; //energy_per_sector( pointers[ 0 ] ); delete [] pointers; if ( CG != NULL ){ delete CG; } if ( DAVID != NULL ){ delete DAVID; } gettimeofday( &end, NULL ); double elapsed = ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); cout << "CASPT2 : Wall time solution = " << elapsed << " seconds" << endl; cout << "CASPT2 : E2 [DIAGONAL] = " << E2_DIAGONAL << endl; cout << "CASPT2 : E2 [NON-VARIATIONAL] = " << E2_NONVARIATIONAL << endl; cout << "CASPT2 : E2 [VARIATIONAL] = " << E2_VARIATIONAL << endl; return E2_VARIATIONAL; } void CheMPS2::CASPT2::add_shift( double * vector, double * result, double * diag_fock, const double imag_shift, const int * normalizations ) const{ for ( int sector = 0; sector < CHEMPS2_CASPT2_NUM_CASES; sector++ ){ const int start = jump[ num_irreps * sector ]; const int stop = jump[ num_irreps * ( sector + 1 ) ]; const double factor = imag_shift * imag_shift * normalizations[ sector ] * normalizations[ sector ]; for ( int elem = start; elem < stop; elem ++ ){ result[ elem ] += factor * vector[ elem ] / diag_fock[ elem ]; } } } double CheMPS2::CASPT2::inproduct_vectors( double * first, double * second, const int * normalizations ) const{ int inc1 = 1; double value = 0.0; for ( int sector = 0; sector < CHEMPS2_CASPT2_NUM_CASES; sector++ ){ int pointer = jump[ num_irreps * sector ]; int size = jump[ num_irreps * ( sector + 1 ) ] - pointer; value += normalizations[ sector ] * ddot_( &size, first + pointer, &inc1, second + pointer, &inc1 ); } return value; } void CheMPS2::CASPT2::energy_per_sector( double * solution ) const{ int inc1 = 1; double energies[ CHEMPS2_CASPT2_NUM_CASES ]; for ( int sector = 0; sector < CHEMPS2_CASPT2_NUM_CASES; sector++ ){ int pointer = jump[ num_irreps * sector ]; int size = jump[ num_irreps * ( sector + 1 ) ] - pointer; energies[ sector ] = - ddot_( &size, solution + pointer, &inc1, vector_rhs + pointer, &inc1 ); } cout << "************************************************" << endl; cout << "* CASPT2 non-variational energy per sector *" << endl; cout << "************************************************" << endl; cout << " A or VJTU = " << energies[ CHEMPS2_CASPT2_A ] << endl; cout << " B or VJTI = " << energies[ CHEMPS2_CASPT2_B_SINGLET ] + energies[ CHEMPS2_CASPT2_B_TRIPLET ] << endl; cout << " C or ATVX = " << energies[ CHEMPS2_CASPT2_C ] << endl; cout << " D or AIVX = " << energies[ CHEMPS2_CASPT2_D ] << endl; cout << " E or VJAI = " << energies[ CHEMPS2_CASPT2_E_SINGLET ] + energies[ CHEMPS2_CASPT2_E_TRIPLET ] << endl; cout << " F or BVAT = " << energies[ CHEMPS2_CASPT2_F_SINGLET ] + energies[ CHEMPS2_CASPT2_F_TRIPLET ] << endl; cout << " G or BJAT = " << energies[ CHEMPS2_CASPT2_G_SINGLET ] + energies[ CHEMPS2_CASPT2_G_TRIPLET ] << endl; cout << " H or BJAI = " << energies[ CHEMPS2_CASPT2_H_SINGLET ] + energies[ CHEMPS2_CASPT2_H_TRIPLET ] << endl; cout << "************************************************" << endl; } void CheMPS2::CASPT2::create_f_dots(){ const int LAS = indices->getDMRGcumulative( num_irreps ); f_dot_3dm = new double[ LAS * LAS * LAS * LAS ]; f_dot_2dm = new double[ LAS * LAS ]; f_dot_1dm = 0.0; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int NDMRG = indices->getNDMRG( irrep ); const int NOCC = indices->getNOCC( irrep ); const int jumpx = indices->getDMRGcumulative( irrep ); double value = 0.0; for ( int orb = 0; orb < NDMRG; orb++ ){ value += fock->get( irrep, NOCC + orb, NOCC + orb ) * one_rdm[ jumpx + orb + LAS * ( jumpx + orb ) ]; } f_dot_1dm += value; } for ( int irrep1 = 0; irrep1 < num_irreps; irrep1++ ){ const int lower1 = indices->getDMRGcumulative( irrep1 ); const int upper1 = lower1 + indices->getNDMRG( irrep1 ); for ( int i1 = lower1; i1 < upper1; i1++ ){ for ( int i2 = lower1; i2 < upper1; i2++ ){ double value = 0.0; for ( int irrepx = 0; irrepx < num_irreps; irrepx++ ){ const int NOCCx = indices->getNOCC( irrepx ); const int NDMRGx = indices->getNDMRG( irrepx ); const int jumpx = indices->getDMRGcumulative( irrepx ); for ( int orbx = 0; orbx < NDMRGx; orbx++ ){ value += fock->get( irrepx, NOCCx + orbx, NOCCx + orbx ) * two_rdm[ i1 + LAS * ( jumpx + orbx + LAS * ( i2 + LAS * ( jumpx + orbx ))) ]; } } f_dot_2dm[ i1 + LAS * i2 ] = value; } } } for ( int irrep1 = 0; irrep1 < num_irreps; irrep1++ ){ const int lower1 = indices->getDMRGcumulative( irrep1 ); const int upper1 = lower1 + indices->getNDMRG( irrep1 ); for ( int irrep2 = 0; irrep2 < num_irreps; irrep2++ ){ const int lower2 = indices->getDMRGcumulative( irrep2 ); const int upper2 = lower2 + indices->getNDMRG( irrep2 ); const int irr_12 = Irreps::directProd( irrep1, irrep2 ); for ( int irrep3 = 0; irrep3 < num_irreps; irrep3++ ){ const int irrep4 = Irreps::directProd( irr_12, irrep3 ); const int lower3 = indices->getDMRGcumulative( irrep3 ); const int lower4 = indices->getDMRGcumulative( irrep4 ); const int upper3 = lower3 + indices->getNDMRG( irrep3 ); const int upper4 = lower4 + indices->getNDMRG( irrep4 ); for ( int i1 = lower1; i1 < upper1; i1++ ){ for ( int i2 = lower2; i2 < upper2; i2++ ){ for ( int i3 = lower3; i3 < upper3; i3++ ){ for ( int i4 = lower4; i4 < upper4; i4++ ){ double value = 0.0; for ( int irrepx = 0; irrepx < num_irreps; irrepx++ ){ const int jumpx = indices->getDMRGcumulative( irrepx ); const int NOCCx = indices->getNOCC( irrepx ); const int NDMRGx = indices->getNDMRG( irrepx ); for ( int orbx = 0; orbx < NDMRGx; orbx++ ){ value += ( fock->get( irrepx, NOCCx + orbx, NOCCx + orbx ) * three_rdm[ i1 + LAS*( i2 + LAS*( jumpx + orbx + LAS*( i3 + LAS*( i4 + LAS*( jumpx + orbx ))))) ] ); } } f_dot_3dm[ i1 + LAS * ( i2 + LAS * ( i3 + LAS * i4 )) ] = value; } } } } } } } /* double sum_f_kk = 0.0; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int NOCC = indices->getNOCC( irrep ); for ( int orb = 0; orb < NOCC; orb++ ){ sum_f_kk += fock->get( irrep, orb, orb ); } } const double E_FOCK = 2 * sum_f_kk + f_dot_1dm; cout << "CASPT2 : < 0 | F | 0 > = " << E_FOCK << endl; */ } int CheMPS2::CASPT2::vector_helper(){ int * helper = new int[ CHEMPS2_CASPT2_NUM_CASES * num_irreps ]; /*** Type A : c_tiuv E_ti E_uv | 0 > c_tiuv = vector[ jump[ irrep + num_irreps * CHEMPS2_CASPT2_A ] + count_tuv + size_A[ irrep ] * count_i ] Type C : c_atuv E_at E_uv | 0 > c_atuv = vector[ jump[ irrep + num_irreps * CHEMPS2_CASPT2_C ] + count_tuv + size_C[ irrep ] * count_a ] 1/ (TYPE A) count_i = 0 .. NOCC[ irrep ] (TYPE C) count_a = 0 .. NVIRT[ irrep ] 2/ jump_tuv = 0 irrep_t = 0 .. num_irreps irrep_u = 0 .. num_irreps irrep_v = irrep x irrep_t x irrep_u ---> count_tuv = jump_tuv + t + NDMRG[ irrep_t ] * ( u + NDMRG[ irrep_u ] * v ) jump_tuv += NDMRG[ irrep_t ] * NDMRG[ irrep_u ] * NDMRG[ irrep_v ] */ size_A = new int[ num_irreps ]; size_C = new int[ num_irreps ]; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ int linsize_AC = 0; for ( int irrep_t = 0; irrep_t < num_irreps; irrep_t++ ){ for ( int irrep_u = 0; irrep_u < num_irreps; irrep_u++ ){ const int irrep_v = Irreps::directProd( Irreps::directProd( irrep, irrep_t ), irrep_u ); linsize_AC += indices->getNDMRG( irrep_t ) * indices->getNDMRG( irrep_u ) * indices->getNDMRG( irrep_v ); } } size_A[ irrep ] = linsize_AC; size_C[ irrep ] = linsize_AC; helper[ irrep + num_irreps * CHEMPS2_CASPT2_A ] = size_A[ irrep ] * indices->getNOCC( irrep ); helper[ irrep + num_irreps * CHEMPS2_CASPT2_C ] = size_C[ irrep ] * indices->getNVIRT( irrep ); } /*** Type D1 : c1_aitu E_ai E_tu | 0 > Type D2 : c2_tiau E_ti E_au | 0 > c1_aitu = vector[ jump[ irrep + num_irreps * CHEMPS2_CASPT2_D ] + count_tu + size_D[ irrep ] * count_ai ] c2_tiau = vector[ jump[ irrep + num_irreps * CHEMPS2_CASPT2_D ] + count_tu + D2JUMP + size_D[ irrep ] * count_ai ] D2JUMP = size_D[ irrep ] / 2 1/ jump_ai = 0 irrep_i = 0 .. num_irreps irrep_a = irrep_i x irrep ---> count_ai = jump_ai + i + NOCC[ irrep_i ] * a jump_ai += NOCC[ irrep_i ] * NVIRT[ irrep_a ] 2/ jump_tu = 0 irrep_t = 0 .. num_irreps irrep_u = irrep x irrep_t ---> count_tu = jump_tu + t + NDMRG[ irrep_t ] * u jump_tu += NDMRG[ irrep_t ] * NDMRG[ irrep_u ] */ size_D = new int[ num_irreps ]; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ int jump_tu = 0; for ( int irrep_t = 0; irrep_t < num_irreps; irrep_t++ ){ const int irrep_u = Irreps::directProd( irrep, irrep_t ); const int nact_t = indices->getNDMRG( irrep_t ); const int nact_u = indices->getNDMRG( irrep_u ); jump_tu += nact_t * nact_u; } size_D[ irrep ] = 2 * jump_tu; int jump_ai = 0; for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int irrep_a = Irreps::directProd( irrep_i, irrep ); const int nocc_i = indices->getNOCC( irrep_i ); const int nvirt_a = indices->getNVIRT( irrep_a ); jump_ai += nocc_i * nvirt_a; } helper[ irrep + num_irreps * CHEMPS2_CASPT2_D ] = jump_ai * size_D[ irrep ]; } /*** Type B singlet : c_tiuj ( E_ti E_uj + E_tj E_ui ) / sqrt( 1 + delta_ij ) | 0 > with i <= j and t <= u c_tiuj = vector[ jump[ irrep + num_irreps * CHEMPS2_CASPT2_B_SINGLET ] + count_tu + size_B_singlet[ irrep ] * count_ij ] Type B triplet : c_tiuj ( E_ti E_uj - E_tj E_ui ) / sqrt( 1 + delta_ij ) | 0 > with i < j and t < u c_tiuj = vector[ jump[ irrep + num_irreps * CHEMPS2_CASPT2_B_TRIPLET ] + count_tu + size_B_triplet[ irrep ] * count_ij ] Type F singlet : c_atbu ( E_at E_bu + E_bt E_au ) / sqrt( 1 + delta_ab ) | 0 > with a <= b and t <= u c_atbu = vector[ jump[ irrep + num_irreps * CHEMPS2_CASPT2_F_SINGLET ] + count_tu + size_F_singlet[ irrep ] * count_ab ] Type F triplet : c_atbu ( E_at E_bu - E_bt E_au ) / sqrt( 1 + delta_ab ) | 0 > with a < b and t < u c_atbu = vector[ jump[ irrep + num_irreps * CHEMPS2_CASPT2_F_TRIPLET ] + count_tu + size_F_triplet[ irrep ] * count_ab ] 1/ jump_ab = 0 if ( irrep == 0 ): irrep_ab = 0 .. num_irreps (SINGLET) ---> count_ab = jump_ab + a + b(b+1)/2 (SINGLET) jump_ab += NVIRT[ irrep_ab ] * ( NVIRT[ irrep_ab ] + 1 ) / 2 (TRIPLET) ---> count_ab = jump_ab + a + b(b-1)/2 (TRIPLET) jump_ab += NVIRT[ irrep_ab ] * ( NVIRT[ irrep_ab ] - 1 ) / 2 else: irrep_a = 0 .. num_irreps irrep_b = irrep x irrep_a if ( irrep_a < irrep_b ): ---> count_ab = jump_ab + a + NVIRT[ irrep_a ] * b jump_ab += NVIRT[ irrep_i ] * NVIRT[ irrep_j ] 2/ jump_ij = 0 if irrep == 0: irrep_ij = 0 .. num_irreps (SINGLET) ---> count_ij = jump_ij + i + j(j+1)/2 (SINGLET) jump_ij += NOCC[ irrep_ij ] * ( NOCC[ irrep_ij ] + 1 ) / 2 (TRIPLET) ---> count_ij = jump_ij + i + j(j-1)/2 (TRIPLET) jump_ij += NOCC[ irrep_ij ] * ( NOCC[ irrep_ij ] - 1 ) / 2 else: irrep_i = 0 .. num_irreps irrep_j = irrep x irrep_i if ( irrep_i < irrep_j ): ---> count_ij = jump_ij + i + NOCC[ irrep_i ] * j jump_ij += NOCC[ irrep_i ] * NOCC[ irrep_j ] 3/ jump_tu = 0 if irrep == 0: irrep_tu = 0 .. num_irreps (SINGLET) ---> count_tu = jump_tu + t + u(u+1)/2 (SINGLET) jump_tu += NDMRG[ irrep_tu ] * ( NDMRG[ irrep_tu ] + 1 ) / 2 (TRIPLET) ---> count_tu = jump_tu + t + u(u-1)/2 (TRIPLET) jump_tu += NDMRG[ irrep_tu ] * ( NDMRG[ irrep_tu ] - 1 ) / 2 else: irrep_t = 0 .. num_irreps irrep_u = irrep x irrep_t if ( irrep_t < irrep_u ): ---> count_tu = jump_tu + t + NDMRG[ irrep_t ] * u jump_tu += NDMRG[ irrep_t ] * NDMRG[ irrep_u ] */ size_B_singlet = new int[ num_irreps ]; size_B_triplet = new int[ num_irreps ]; size_F_singlet = new int[ num_irreps ]; size_F_triplet = new int[ num_irreps ]; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ int jump_tu_singlet = 0; int jump_tu_triplet = 0; if ( irrep == 0 ){ for ( int irrep_tu = 0; irrep_tu < num_irreps; irrep_tu++ ){ // irrep_u == irrep_t const int nact_tu = indices->getNDMRG( irrep_tu ); jump_tu_singlet += ( nact_tu * ( nact_tu + 1 )) / 2; jump_tu_triplet += ( nact_tu * ( nact_tu - 1 )) / 2; } } else { for ( int irrep_t = 0; irrep_t < num_irreps; irrep_t++ ){ const int irrep_u = Irreps::directProd( irrep, irrep_t ); if ( irrep_t < irrep_u ){ const int nact_t = indices->getNDMRG( irrep_t ); const int nact_u = indices->getNDMRG( irrep_u ); jump_tu_singlet += nact_t * nact_u; jump_tu_triplet += nact_t * nact_u; } } } size_B_singlet[ irrep ] = jump_tu_singlet; size_B_triplet[ irrep ] = jump_tu_triplet; size_F_singlet[ irrep ] = jump_tu_singlet; size_F_triplet[ irrep ] = jump_tu_triplet; int linsize_B_singlet = 0; int linsize_B_triplet = 0; int linsize_F_singlet = 0; int linsize_F_triplet = 0; if ( irrep == 0 ){ // irrep_i == irrep_j or irrep_a == irrep_b for ( int irrep_ijab = 0; irrep_ijab < num_irreps; irrep_ijab++ ){ const int nocc_ij = indices->getNOCC( irrep_ijab ); linsize_B_singlet += ( nocc_ij * ( nocc_ij + 1 ))/2; linsize_B_triplet += ( nocc_ij * ( nocc_ij - 1 ))/2; const int nvirt_ab = indices->getNVIRT( irrep_ijab ); linsize_F_singlet += ( nvirt_ab * ( nvirt_ab + 1 ))/2; linsize_F_triplet += ( nvirt_ab * ( nvirt_ab - 1 ))/2; } } else { // irrep_i < irrep_j = irrep_i x irrep or irrep_a < irrep_b = irrep_a x irrep for ( int irrep_ai = 0; irrep_ai < num_irreps; irrep_ai++ ){ const int irrep_bj = Irreps::directProd( irrep, irrep_ai ); if ( irrep_ai < irrep_bj ){ const int nocc_i = indices->getNOCC( irrep_ai ); const int nocc_j = indices->getNOCC( irrep_bj ); linsize_B_singlet += nocc_i * nocc_j; linsize_B_triplet += nocc_i * nocc_j; const int nvirt_a = indices->getNVIRT( irrep_ai ); const int nvirt_b = indices->getNVIRT( irrep_bj ); linsize_F_singlet += nvirt_a * nvirt_b; linsize_F_triplet += nvirt_a * nvirt_b; } } } helper[ irrep + num_irreps * CHEMPS2_CASPT2_B_SINGLET ] = linsize_B_singlet * size_B_singlet[ irrep ]; helper[ irrep + num_irreps * CHEMPS2_CASPT2_B_TRIPLET ] = linsize_B_triplet * size_B_triplet[ irrep ]; helper[ irrep + num_irreps * CHEMPS2_CASPT2_F_SINGLET ] = linsize_F_singlet * size_F_singlet[ irrep ]; helper[ irrep + num_irreps * CHEMPS2_CASPT2_F_TRIPLET ] = linsize_F_triplet * size_F_triplet[ irrep ]; } /*** Type E singlet : c_tiaj ( E_ti E_aj + E_tj E_ai ) / sqrt( 1 + delta_ij ) | 0 > with i <= j c_tiaj = vector[ jump[ irrep + num_irreps * CHEMPS2_CASPT2_E_SINGLET ] + count_t + size_E[ irrep ] * count_aij ] Type E triplet : c_tiaj ( E_ti E_aj - E_tj E_ai ) / sqrt( 1 + delta_ij ) | 0 > with i < j c_tiaj = vector[ jump[ irrep + num_irreps * CHEMPS2_CASPT2_E_TRIPLET ] + count_t + size_E[ irrep ] * count_aij ] 1/ jump_aij = 0 irrep_a = 0 .. num_irreps irrep_occ = irrep_a x irrep if ( irrep_occ == 0 ): irrep_ij = 0 .. num_irreps (SINGLET) ---> count_aij = jump_aij + a + NVIRT[ irrep_a ] * ( i + j(j+1)/2 ) (SINGLET) jump_aij += NVIRT[ irrep_a ] * NOCC[ irrep_ij ] * ( NOCC[ irrep_ij ] + 1 ) / 2 (TRIPLET) ---> count_aij = jump_aij + a + NVIRT[ irrep_a ] * ( i + j(j-1)/2 ) (TRIPLET) jump_aij += NVIRT[ irrep_a ] * NOCC[ irrep_ij ] * ( NOCC[ irrep_ij ] - 1 ) / 2 else: irrep_i = 0 .. num_irreps irrep_j = irrep_occ x irrep_i if ( irrep_i < irrep_j ): ---> count_aij = jump_aij + a + NVIRT[ irrep_a ] * ( i + NOCC[ irrep_i ] * j ) jump_aij += NVIRT[ irrep_a ] * NOCC[ irrep_i ] * NOCC[ irrep_j ] 2/ count_t = 0 .. NDMRG[ irrep ] */ size_E = new int[ num_irreps ]; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ size_E[ irrep ] = indices->getNDMRG( irrep ); int linsize_E_singlet = 0; int linsize_E_triplet = 0; for ( int irrep_a = 0; irrep_a < num_irreps; irrep_a++ ){ const int nvirt_a = indices->getNVIRT( irrep_a ); const int irrep_occ = Irreps::directProd( irrep, irrep_a ); if ( irrep_occ == 0 ){ // irrep_i == irrep_j for ( int irrep_ij = 0; irrep_ij < num_irreps; irrep_ij++ ){ const int nocc_ij = indices->getNOCC( irrep_ij ); linsize_E_singlet += ( nvirt_a * nocc_ij * ( nocc_ij + 1 )) / 2; linsize_E_triplet += ( nvirt_a * nocc_ij * ( nocc_ij - 1 )) / 2; } } else { // irrep_i < irrep_j = irrep_i x irrep_occ for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int irrep_j = Irreps::directProd( irrep_occ, irrep_i ); if ( irrep_i < irrep_j ){ const int nocc_i = indices->getNOCC( irrep_i ); const int nocc_j = indices->getNOCC( irrep_j ); linsize_E_singlet += nvirt_a * nocc_i * nocc_j; linsize_E_triplet += nvirt_a * nocc_i * nocc_j; } } } } helper[ irrep + num_irreps * CHEMPS2_CASPT2_E_SINGLET ] = linsize_E_singlet * size_E[ irrep ]; helper[ irrep + num_irreps * CHEMPS2_CASPT2_E_TRIPLET ] = linsize_E_triplet * size_E[ irrep ]; } /*** Type G singlet : c_aibt ( E_ai E_bt + E_bi E_at ) / sqrt( 1 + delta_ab ) | 0 > with a <= b c_aibt = vector[ jump[ irrep + num_irreps * CHEMPS2_CASPT2_G_SINGLET ] + count_t + size_G[ irrep ] * count_abi ] Type G triplet : c_aibt ( E_ai E_bt - E_bi E_at ) / sqrt( 1 + delta_ab ) | 0 > with a < b c_aibt = vector[ jump[ irrep + num_irreps * CHEMPS2_CASPT2_G_TRIPLET ] + count_t + size_G[ irrep ] * count_abi ] 1/ jump_abi = 0 irrep_i = 0 .. num_irreps irrep_virt = irrep_i x irrep if irrep_virt == 0: irrep_ab = 0 .. num_irreps (SINGLET) ---> count_abi = jump_abi + i + NOCC[ irrep_i ] * ( a + b(b+1)/2 ) (SINGLET) jump_abi += NOCC[ irrep_i ] * NVIRT[ irrep_ab ] * ( NVIRT[ irrep_ab ] + 1 ) / 2 (TRIPLET) ---> count_abi = jump_abi + i + NOCC[ irrep_i ] * ( a + b(b-1)/2 ) (TRIPLET) jump_abi += NOCC[ irrep_i ] * NVIRT[ irrep_ab ] * ( NVIRT[ irrep_ab ] - 1 ) / 2 else: irrep_a = 0 .. num_irreps irrep_b = irrep_virt x irrep_a if ( irrep_a < irrep_b ): ---> count_abi = jump_abi + i + NOCC[ irrep_i ] * ( a + NVIRT[ irrep_a ] * b ) jump_abi += NOCC[ irrep_i ] * NVIRT[ irrep_a ] * NVIRT[ irrep_b ] 2/ count_t = 0 .. NDMRG[ irrep ] */ size_G = new int[ num_irreps ]; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ size_G[ irrep ] = indices->getNDMRG( irrep ); int linsize_G_singlet = 0; int linsize_G_triplet = 0; for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int nocc_i = indices->getNOCC( irrep_i ); const int irrep_virt = Irreps::directProd( irrep, irrep_i ); if ( irrep_virt == 0 ){ // irrep_a == irrep_b for ( int irrep_ab = 0; irrep_ab < num_irreps; irrep_ab++ ){ const int nvirt_ab = indices->getNVIRT( irrep_ab ); linsize_G_singlet += ( nocc_i * nvirt_ab * ( nvirt_ab + 1 )) / 2; linsize_G_triplet += ( nocc_i * nvirt_ab * ( nvirt_ab - 1 )) / 2; } } else { // irrep_a < irrep_b = irrep_a x irrep_virt for ( int irrep_a = 0; irrep_a < num_irreps; irrep_a++ ){ const int irrep_b = Irreps::directProd( irrep_virt, irrep_a ); if ( irrep_a < irrep_b ){ const int nvirt_a = indices->getNVIRT( irrep_a ); const int nvirt_b = indices->getNVIRT( irrep_b ); linsize_G_singlet += nocc_i * nvirt_a * nvirt_b; linsize_G_triplet += nocc_i * nvirt_a * nvirt_b; } } } } helper[ irrep + num_irreps * CHEMPS2_CASPT2_G_SINGLET ] = linsize_G_singlet * size_G[ irrep ]; helper[ irrep + num_irreps * CHEMPS2_CASPT2_G_TRIPLET ] = linsize_G_triplet * size_G[ irrep ]; } /*** Type H singlet : c_aibj ( E_ai E_bj + E_bi E_aj ) / sqrt( ( 1 + delta_ij ) * ( 1 + delta_ab ) ) | 0 > with a <= b and i <= j c_aibj = vector[ jump[ irrep + num_irreps * CHEMPS2_CASPT2_H_SINGLET ] + count_aibj ] Type H triplet : c_aibj ( E_ai E_bj - E_bi E_aj ) / sqrt( ( 1 + delta_ij ) * ( 1 + delta_ab ) ) | 0 > with a < b and i < j c_aibj = vector[ jump[ irrep + num_irreps * CHEMPS2_CASPT2_H_TRIPLET ] + count_aibj ] 1/ irrep = 0 .. num_irreps if ( irrep == 0 ): jump_aibj = 0 irrep_ij = 0 .. num_irreps (SINGLET) linsize_ij = NOCC[ irrep_ij ] * ( NOCC[ irrep_ij ] + 1 ) / 2 (TRIPLET) linsize_ij = NOCC[ irrep_ij ] * ( NOCC[ irrep_ij ] - 1 ) / 2 irrep_ab = 0 .. num_irreps (SINGLET) linsize_ab = NVIRT[ irrep_ab ] * ( NVIRT[ irrep_ab ] + 1 ) / 2 (TRIPLET) linsize_ab = NVIRT[ irrep_ab ] * ( NVIRT[ irrep_ab ] - 1 ) / 2 (SINGLET) ---> count_aibj = jump_aibj + i + j(j+1)/2 + linsize_ij * ( a + b(b+1)/2 ) (TRIPLET) ---> count_aibj = jump_aibj + i + j(j-1)/2 + linsize_ij * ( a + b(b-1)/2 ) jump_aibj += linsize_ij * linsize_ab else: jump_aibj = 0 irrep_i = 0 .. num_irreps irrep_j = irrep x irrep_i if ( irrep_i < irrep_j ): irrep_a = 0 .. num_irreps irrep_b = irrep x irrep_a if ( irrep_a < irrep_b ): ---> count_aibj = jump_aibj + i + NOCC[ irrep_i ] * ( j + NOCC[ irrep_j ] * ( a + NVIRT[ irrep_a ] * b ) ) jump_aibj += NOCC[ irrep_i ] * NOCC[ irrep_j ] * NVIRT[ irrep_a ] * NVIRT[ irrep_b ] */ for ( int irrep = 0; irrep < num_irreps; irrep++ ){ int linsize_H_singlet = 0; int linsize_H_triplet = 0; if ( irrep == 0 ){ // irrep_i == irrep_j and irrep_a == irrep_b int linsize_ij_singlet = 0; int linsize_ij_triplet = 0; for ( int irrep_ij = 0; irrep_ij < num_irreps; irrep_ij++ ){ const int nocc_ij = indices->getNOCC( irrep_ij ); linsize_ij_singlet += ( nocc_ij * ( nocc_ij + 1 )) / 2; linsize_ij_triplet += ( nocc_ij * ( nocc_ij - 1 )) / 2; } int linsize_ab_singlet = 0; int linsize_ab_triplet = 0; for ( int irrep_ab = 0; irrep_ab < num_irreps; irrep_ab++ ){ const int nvirt_ab = indices->getNVIRT( irrep_ab ); linsize_ab_singlet += ( nvirt_ab * ( nvirt_ab + 1 )) / 2; linsize_ab_triplet += ( nvirt_ab * ( nvirt_ab - 1 )) / 2; } linsize_H_singlet = linsize_ij_singlet * linsize_ab_singlet; linsize_H_triplet = linsize_ij_triplet * linsize_ab_triplet; } else { // irrep_i < irrep_j = irrep_i x irrep and irrep_a < irrep_b = irrep_a x irrep int linsize_ij = 0; for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int irrep_j = Irreps::directProd( irrep, irrep_i ); if ( irrep_i < irrep_j ){ linsize_ij += indices->getNOCC( irrep_i ) * indices->getNOCC( irrep_j ); } } int linsize_ab = 0; for ( int irrep_a = 0; irrep_a < num_irreps; irrep_a++ ){ const int irrep_b = Irreps::directProd( irrep, irrep_a ); if ( irrep_a < irrep_b ){ linsize_ab += indices->getNVIRT( irrep_a ) * indices->getNVIRT( irrep_b ); } } linsize_H_singlet = linsize_ij * linsize_ab; linsize_H_triplet = linsize_ij * linsize_ab; } helper[ irrep + num_irreps * CHEMPS2_CASPT2_H_SINGLET ] = linsize_H_singlet; helper[ irrep + num_irreps * CHEMPS2_CASPT2_H_TRIPLET ] = linsize_H_triplet; } jump = new int[ CHEMPS2_CASPT2_NUM_CASES * num_irreps + 1 ]; jump[ 0 ] = 0; for ( int cnt = 0; cnt < CHEMPS2_CASPT2_NUM_CASES * num_irreps; cnt++ ){ jump[ cnt+1 ] = jump[ cnt ] + helper[ cnt ]; } delete [] helper; const int total_size = jump[ CHEMPS2_CASPT2_NUM_CASES * num_irreps ]; assert( total_size == vector_length( indices ) ); cout << "CASPT2 : Old size V_SD space = " << total_size << endl; return total_size; } long long CheMPS2::CASPT2::vector_length( const DMRGSCFindices * idx ){ const int NUM_IRREPS = idx->getNirreps(); long long length = 0; for ( int i1 = 0; i1 < NUM_IRREPS; i1++ ){ const long long nocc1 = idx->getNOCC( i1 ); const long long nact1 = idx->getNDMRG( i1 ); const long long nvir1 = idx->getNVIRT( i1 ); for ( int i2 = 0; i2 < NUM_IRREPS; i2++ ){ const long long nocc2 = idx->getNOCC( i2 ); const long long nact2 = idx->getNDMRG( i2 ); for ( int i3 = 0; i3 < NUM_IRREPS; i3++ ){ const int i4 = Irreps::directProd( Irreps::directProd( i1, i2 ), i3 ); const long long nact3 = idx->getNDMRG( i3 ); const long long nvir3 = idx->getNVIRT( i3 ); const long long nocc4 = idx->getNOCC( i4 ); const long long nact4 = idx->getNDMRG( i4 ); const long long nvir4 = idx->getNVIRT( i4 ); length += nocc1 * nact2 * nact3 * nact4; // A: E_ti E_uv | 0 > length += nact1 * nact2 * nact3 * nvir4; // C: E_at E_uv | 0 > length += 2 * nocc1 * nact2 * nact3 * nvir4; // D: E_ai E_tu | 0 > and E_ti E_au | 0 > length += nocc1 * nocc2 * nact3 * nvir4; // E: E_ti E_aj | 0 > length += nocc1 * nact2 * nvir3 * nvir4; // G: E_ai E_bt | 0 > if ( i2 < i4 ){ // 2 < 4 and irrep_2 < irrep_4 length += nact1 * nact3 * nocc2 * nocc4; // B: E_ti E_uj | 0 > length += nvir1 * nvir3 * nact2 * nact4; // F: E_at E_bu | 0 > length += nvir1 * nvir3 * nocc2 * nocc4; // H: E_ai E_bj | 0 > } if ( i2 == i4 ){ // i2 == i4 implies i1 == i3 // 2 < 4 and irrep_2 == irrep_4 length += ( nact1 * nact3 * nocc2 * ( nocc2 - 1 ) ) / 2; // B: E_ti E_uj | 0 > length += ( nvir1 * nvir3 * nact2 * ( nact2 - 1 ) ) / 2; // F: E_at E_bu | 0 > length += ( nvir1 * nvir3 * nocc2 * ( nocc2 - 1 ) ) / 2; // H: E_ai E_bj | 0 > // 2 == 4 and 1 <= 3 length += ( nact1 * ( nact3 + 1 ) * nocc2 ) / 2; // B: E_ti E_uj | 0 > length += ( nvir1 * ( nvir3 + 1 ) * nact2 ) / 2; // F: E_at E_bu | 0 > length += ( nvir1 * ( nvir3 + 1 ) * nocc2 ) / 2; // H: E_ai E_bj | 0 > } } } } return length; } int CheMPS2::CASPT2::recreatehelper1( double * FOCK, double * OVLP, int SIZE, double * work, double * eigs, int lwork ){ if ( SIZE == 0 ){ return SIZE; } // S = U_S eigs_S U_S^T char jobz = 'V'; char uplo = 'U'; int info; dsyev_( &jobz, &uplo, &SIZE, OVLP, &SIZE, eigs, work, &lwork, &info ); // eigs in ascending order // Discard smallest eigenvalues int skip = 0; bool ctu = true; while (( skip < SIZE ) && ( ctu )){ if ( eigs[ skip ] < CheMPS2::CASPT2_OVLP_CUTOFF ){ skip++; } else { ctu = false; } } int NEWSIZE = SIZE - skip; if ( NEWSIZE == 0 ){ return NEWSIZE; } // OVLP <--- U_S eigs_S^{-0.5} for ( int col = skip; col < SIZE; col++ ){ const double prefactor = 1.0 / sqrt( eigs[ col ] ); for ( int row = 0; row < SIZE; row++ ){ OVLP[ row + SIZE * col ] *= prefactor; } } // FOCK <--- FOCK_tilde = eigs_S^{-0.5} U_S^T FOCK U_S eigs_S^{-0.5} char notrans = 'N'; char trans = 'T'; double one = 1.0; double set = 0.0; dgemm_( ¬rans, ¬rans, &SIZE, &NEWSIZE, &SIZE, &one, FOCK, &SIZE, OVLP + skip * SIZE, &SIZE, &set, work, &SIZE ); // work = FOCK * V * eigs^{-0.5} dgemm_( &trans, ¬rans, &NEWSIZE, &NEWSIZE, &SIZE, &one, OVLP + skip * SIZE, &SIZE, work, &SIZE, &set, FOCK, &NEWSIZE ); // FOCK = ( V * eigs^{-0.5} )^T * work // FOCK_tilde = U_F_tilde eigs_F_tilde U_F_tilde^T dsyev_( &jobz, &uplo, &NEWSIZE, FOCK, &NEWSIZE, eigs, work, &lwork, &info ); // eigs in ascending order // OVLP <--- U_S eigs_S^{-0.5} U_F_tilde dgemm_( ¬rans, ¬rans, &SIZE, &NEWSIZE, &NEWSIZE, &one, OVLP + skip * SIZE, &SIZE, FOCK, &NEWSIZE, &set, work, &SIZE ); int size_copy = SIZE * NEWSIZE; int inc1 = 1; dcopy_( &size_copy, work, &inc1, OVLP, &inc1 ); // FOCK <--- eigs_F_tilde dcopy_( &NEWSIZE, eigs, &inc1, FOCK, &inc1 ); return NEWSIZE; } void CheMPS2::CASPT2::recreatehelper2( double * LEFT, double * RIGHT, double ** matrix, double * work, int OLD_LEFT, int NEW_LEFT, int OLD_RIGHT, int NEW_RIGHT, const int number ){ double set = 0.0; double one = 1.0; char trans = 'T'; char notrans = 'N'; for ( int count = 0; count < number; count++ ){ // work <--- LEFT[ old_left, new_left ]^T * matrix[ count ][ old_left, old_right ] dgemm_( &trans, ¬rans, &NEW_LEFT, &OLD_RIGHT, &OLD_LEFT, &one, LEFT, &OLD_LEFT, matrix[ count ], &OLD_LEFT, &set, work, &NEW_LEFT ); // matrix[ count ] <--- work[ new_left, old_right ] * RIGHT[ old_right, new_right ] dgemm_( ¬rans, ¬rans, &NEW_LEFT, &NEW_RIGHT, &OLD_RIGHT, &one, work, &NEW_LEFT, RIGHT, &OLD_RIGHT, &set, matrix[ count ], &NEW_LEFT ); } } void CheMPS2::CASPT2::recreatehelper3( double * OVLP, int OLDSIZE, int NEWSIZE, double * rhs_old, double * rhs_new, const int num_rhs ){ // rhs <-- eigs^{-0.5} V^T rhs int inc1 = 1; double set = 0.0; double one = 1.0; char trans = 'T'; for ( int sector = 0; sector < num_rhs; sector++ ){ dgemv_( &trans, &OLDSIZE, &NEWSIZE, &one, OVLP, &OLDSIZE, rhs_old + OLDSIZE * sector, &inc1, &set, rhs_new + NEWSIZE * sector, &inc1 ); } } void CheMPS2::CASPT2::recreate(){ const int maxsize = get_maxsize(); // Minimum 3 const int lwork = maxsize * maxsize; double * work = new double[ lwork ]; double * eigs = new double[ maxsize ]; int * newsize_A = new int[ num_irreps ]; int * newsize_C = new int[ num_irreps ]; int * newsize_D = new int[ num_irreps ]; int * newsize_E = new int[ num_irreps ]; int * newsize_G = new int[ num_irreps ]; int * newsize_B_singlet = new int[ num_irreps ]; int * newsize_B_triplet = new int[ num_irreps ]; int * newsize_F_singlet = new int[ num_irreps ]; int * newsize_F_triplet = new int[ num_irreps ]; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ newsize_A[ irrep ] = recreatehelper1( FAA[ irrep ], SAA[ irrep ], size_A[ irrep ], work, eigs, lwork ); newsize_C[ irrep ] = recreatehelper1( FCC[ irrep ], SCC[ irrep ], size_C[ irrep ], work, eigs, lwork ); newsize_D[ irrep ] = recreatehelper1( FDD[ irrep ], SDD[ irrep ], size_D[ irrep ], work, eigs, lwork ); newsize_E[ irrep ] = recreatehelper1( FEE[ irrep ], SEE[ irrep ], size_E[ irrep ], work, eigs, lwork ); newsize_G[ irrep ] = recreatehelper1( FGG[ irrep ], SGG[ irrep ], size_G[ irrep ], work, eigs, lwork ); newsize_B_singlet[ irrep ] = recreatehelper1( FBB_singlet[ irrep ], SBB_singlet[ irrep ], size_B_singlet[ irrep ], work, eigs, lwork ); newsize_B_triplet[ irrep ] = recreatehelper1( FBB_triplet[ irrep ], SBB_triplet[ irrep ], size_B_triplet[ irrep ], work, eigs, lwork ); newsize_F_singlet[ irrep ] = recreatehelper1( FFF_singlet[ irrep ], SFF_singlet[ irrep ], size_F_singlet[ irrep ], work, eigs, lwork ); newsize_F_triplet[ irrep ] = recreatehelper1( FFF_triplet[ irrep ], SFF_triplet[ irrep ], size_F_triplet[ irrep ], work, eigs, lwork ); } for ( int IL = 0; IL < num_irreps; IL++ ){ for ( int IR = 0; IR < num_irreps; IR++ ){ const int irrep_w = Irreps::directProd( IL, IR ); const int num_w = indices->getNDMRG( irrep_w ); if ( newsize_A[ IL ] * newsize_D[ IR ] * num_w > 0 ){ recreatehelper2( SAA[ IL ], SDD[ IR ], FAD[ IL ][ IR ], work, size_A[ IL ], newsize_A[ IL ], size_D[ IR ], newsize_D[ IR ], num_w ); } if ( newsize_C[ IL ] * newsize_D[ IR ] * num_w > 0 ){ recreatehelper2( SCC[ IL ], SDD[ IR ], FCD[ IL ][ IR ], work, size_C[ IL ], newsize_C[ IL ], size_D[ IR ], newsize_D[ IR ], num_w ); } if ( newsize_A[ IL ] * newsize_B_singlet[ IR ] * num_w > 0 ){ recreatehelper2( SAA[ IL ], SBB_singlet[ IR ], FAB_singlet[ IL ][ IR ], work, size_A[ IL ], newsize_A[ IL ], size_B_singlet[ IR ], newsize_B_singlet[ IR ], num_w ); } if ( newsize_A[ IL ] * newsize_B_triplet[ IR ] * num_w > 0 ){ recreatehelper2( SAA[ IL ], SBB_triplet[ IR ], FAB_triplet[ IL ][ IR ], work, size_A[ IL ], newsize_A[ IL ], size_B_triplet[ IR ], newsize_B_triplet[ IR ], num_w ); } if ( newsize_C[ IL ] * newsize_F_singlet[ IR ] * num_w > 0 ){ recreatehelper2( SCC[ IL ], SFF_singlet[ IR ], FCF_singlet[ IL ][ IR ], work, size_C[ IL ], newsize_C[ IL ], size_F_singlet[ IR ], newsize_F_singlet[ IR ], num_w ); } if ( newsize_C[ IL ] * newsize_F_triplet[ IR ] * num_w > 0 ){ recreatehelper2( SCC[ IL ], SFF_triplet[ IR ], FCF_triplet[ IL ][ IR ], work, size_C[ IL ], newsize_C[ IL ], size_F_triplet[ IR ], newsize_F_triplet[ IR ], num_w ); } if ( newsize_B_singlet[ IL ] * newsize_E[ IR ] * num_w > 0 ){ recreatehelper2( SBB_singlet[ IL ], SEE[ IR ], FBE_singlet[ IL ][ IR ], work, size_B_singlet[ IL ], newsize_B_singlet[ IL ], size_E[ IR ], newsize_E[ IR ], num_w ); } if ( newsize_B_triplet[ IL ] * newsize_E[ IR ] * num_w > 0 ){ recreatehelper2( SBB_triplet[ IL ], SEE[ IR ], FBE_triplet[ IL ][ IR ], work, size_B_triplet[ IL ], newsize_B_triplet[ IL ], size_E[ IR ], newsize_E[ IR ], num_w ); } if ( newsize_F_singlet[ IL ] * newsize_G[ IR ] * num_w > 0 ){ recreatehelper2( SFF_singlet[ IL ], SGG[ IR ], FFG_singlet[ IL ][ IR ], work, size_F_singlet[ IL ], newsize_F_singlet[ IL ], size_G[ IR ], newsize_G[ IR ], num_w ); } if ( newsize_F_triplet[ IL ] * newsize_G[ IR ] * num_w > 0 ){ recreatehelper2( SFF_triplet[ IL ], SGG[ IR ], FFG_triplet[ IL ][ IR ], work, size_F_triplet[ IL ], newsize_F_triplet[ IL ], size_G[ IR ], newsize_G[ IR ], num_w ); } if ( newsize_D[ IL ] * newsize_E[ IR ] * num_w > 0 ){ recreatehelper2( SDD[ IL ], SEE[ IR ], FDE_singlet[ IL ][ IR ], work, size_D[ IL ], newsize_D[ IL ], size_E[ IR ], newsize_E[ IR ], num_w ); recreatehelper2( SDD[ IL ], SEE[ IR ], FDE_triplet[ IL ][ IR ], work, size_D[ IL ], newsize_D[ IL ], size_E[ IR ], newsize_E[ IR ], num_w ); } if ( newsize_D[ IL ] * newsize_G[ IR ] * num_w > 0 ){ recreatehelper2( SDD[ IL ], SGG[ IR ], FDG_singlet[ IL ][ IR ], work, size_D[ IL ], newsize_D[ IL ], size_G[ IR ], newsize_G[ IR ], num_w ); recreatehelper2( SDD[ IL ], SGG[ IR ], FDG_triplet[ IL ][ IR ], work, size_D[ IL ], newsize_D[ IL ], size_G[ IR ], newsize_G[ IR ], num_w ); } if ( IR == 0 ){ // IL == irrep_w if ( newsize_E[ IL ] * num_w > 0 ){ double one = 1.0; recreatehelper2( SEE[ IL ], &one, FEH[ IL ], work, size_E[ IL ], newsize_E[ IL ], 1, 1, num_w ); } if ( newsize_G[ IL ] * num_w > 0 ){ double one = 1.0; recreatehelper2( SGG[ IL ], &one, FGH[ IL ], work, size_G[ IL ], newsize_G[ IL ], 1, 1, num_w ); } } } } delete [] work; delete [] eigs; double * tempvector_rhs = new double[ jump[ num_irreps * CHEMPS2_CASPT2_NUM_CASES ] ]; int * helper = new int[ num_irreps * CHEMPS2_CASPT2_NUM_CASES ]; for ( int ptr = 0; ptr < num_irreps * CHEMPS2_CASPT2_NUM_CASES; ptr++ ){ helper[ ptr ] = 0; } for ( int irrep = 0; irrep < num_irreps; irrep++ ){ if ( newsize_A[ irrep ] > 0 ){ const int ptr = irrep + num_irreps * CHEMPS2_CASPT2_A; const int num_rhs = ( jump[ ptr + 1 ] - jump[ ptr ] ) / size_A[ irrep ]; assert( num_rhs * size_A[ irrep ] == jump[ ptr + 1 ] - jump[ ptr ] ); helper[ ptr ] = num_rhs * newsize_A[ irrep ]; recreatehelper3( SAA[ irrep ], size_A[ irrep ], newsize_A[ irrep ], vector_rhs + jump[ ptr ], tempvector_rhs + jump[ ptr ], num_rhs ); } if ( newsize_B_singlet[ irrep ] > 0 ){ const int ptr = irrep + num_irreps * CHEMPS2_CASPT2_B_SINGLET; const int num_rhs = ( jump[ ptr + 1 ] - jump[ ptr ] ) / size_B_singlet[ irrep ]; assert( num_rhs * size_B_singlet[ irrep ] == jump[ ptr + 1 ] - jump[ ptr ] ); helper[ ptr ] = num_rhs * newsize_B_singlet[ irrep ]; recreatehelper3( SBB_singlet[ irrep ], size_B_singlet[ irrep ], newsize_B_singlet[ irrep ], vector_rhs + jump[ ptr ], tempvector_rhs + jump[ ptr ], num_rhs ); } if ( newsize_B_triplet[ irrep ] > 0 ){ const int ptr = irrep + num_irreps * CHEMPS2_CASPT2_B_TRIPLET; const int num_rhs = ( jump[ ptr + 1 ] - jump[ ptr ] ) / size_B_triplet[ irrep ]; assert( num_rhs * size_B_triplet[ irrep ] == jump[ ptr + 1 ] - jump[ ptr ] ); helper[ ptr ] = num_rhs * newsize_B_triplet[ irrep ]; recreatehelper3( SBB_triplet[ irrep ], size_B_triplet[ irrep ], newsize_B_triplet[ irrep ], vector_rhs + jump[ ptr ], tempvector_rhs + jump[ ptr ], num_rhs ); } if ( newsize_C[ irrep ] > 0 ){ const int ptr = irrep + num_irreps * CHEMPS2_CASPT2_C; const int num_rhs = ( jump[ ptr + 1 ] - jump[ ptr ] ) / size_C[ irrep ]; assert( num_rhs * size_C[ irrep ] == jump[ ptr + 1 ] - jump[ ptr ] ); helper[ ptr ] = num_rhs * newsize_C[ irrep ]; recreatehelper3( SCC[ irrep ], size_C[ irrep ], newsize_C[ irrep ], vector_rhs + jump[ ptr ], tempvector_rhs + jump[ ptr ], num_rhs ); } if ( newsize_D[ irrep ] > 0 ){ const int ptr = irrep + num_irreps * CHEMPS2_CASPT2_D; const int num_rhs = ( jump[ ptr + 1 ] - jump[ ptr ] ) / size_D[ irrep ]; assert( num_rhs * size_D[ irrep ] == jump[ ptr + 1 ] - jump[ ptr ] ); helper[ ptr ] = num_rhs * newsize_D[ irrep ]; recreatehelper3( SDD[ irrep ], size_D[ irrep ], newsize_D[ irrep ], vector_rhs + jump[ ptr ], tempvector_rhs + jump[ ptr ], num_rhs ); } if ( newsize_E[ irrep ] > 0 ){ const int ptr1 = irrep + num_irreps * CHEMPS2_CASPT2_E_SINGLET; const int num_rhs1 = ( jump[ ptr1 + 1 ] - jump[ ptr1 ] ) / size_E[ irrep ]; assert( num_rhs1 * size_E[ irrep ] == jump[ ptr1 + 1 ] - jump[ ptr1 ] ); helper[ ptr1 ] = num_rhs1 * newsize_E[ irrep ]; recreatehelper3( SEE[ irrep ], size_E[ irrep ], newsize_E[ irrep ], vector_rhs + jump[ ptr1 ], tempvector_rhs + jump[ ptr1 ], num_rhs1 ); const int ptr2 = irrep + num_irreps * CHEMPS2_CASPT2_E_TRIPLET; const int num_rhs2 = ( jump[ ptr2 + 1 ] - jump[ ptr2 ] ) / size_E[ irrep ]; assert( num_rhs2 * size_E[ irrep ] == jump[ ptr2 + 1 ] - jump[ ptr2 ] ); helper[ ptr2 ] = num_rhs2 * newsize_E[ irrep ]; recreatehelper3( SEE[ irrep ], size_E[ irrep ], newsize_E[ irrep ], vector_rhs + jump[ ptr2 ], tempvector_rhs + jump[ ptr2 ], num_rhs2 ); } if ( newsize_F_singlet[ irrep ] > 0 ){ const int ptr = irrep + num_irreps * CHEMPS2_CASPT2_F_SINGLET; const int num_rhs = ( jump[ ptr + 1 ] - jump[ ptr ] ) / size_F_singlet[ irrep ]; assert( num_rhs * size_F_singlet[ irrep ] == jump[ ptr + 1 ] - jump[ ptr ] ); helper[ ptr ] = num_rhs * newsize_F_singlet[ irrep ]; recreatehelper3( SFF_singlet[ irrep ], size_F_singlet[ irrep ], newsize_F_singlet[ irrep ], vector_rhs + jump[ ptr ], tempvector_rhs + jump[ ptr ], num_rhs ); } if ( newsize_F_triplet[ irrep ] > 0 ){ const int ptr = irrep + num_irreps * CHEMPS2_CASPT2_F_TRIPLET; const int num_rhs = ( jump[ ptr + 1 ] - jump[ ptr ] ) / size_F_triplet[ irrep ]; assert( num_rhs * size_F_triplet[ irrep ] == jump[ ptr + 1 ] - jump[ ptr ] ); helper[ ptr ] = num_rhs * newsize_F_triplet[ irrep ]; recreatehelper3( SFF_triplet[ irrep ], size_F_triplet[ irrep ], newsize_F_triplet[ irrep ], vector_rhs + jump[ ptr ], tempvector_rhs + jump[ ptr ], num_rhs ); } if ( newsize_G[ irrep ] > 0 ){ const int ptr1 = irrep + num_irreps * CHEMPS2_CASPT2_G_SINGLET; const int num_rhs1 = ( jump[ ptr1 + 1 ] - jump[ ptr1 ] ) / size_G[ irrep ]; assert( num_rhs1 * size_G[ irrep ] == jump[ ptr1 + 1 ] - jump[ ptr1 ] ); helper[ ptr1 ] = num_rhs1 * newsize_G[ irrep ]; recreatehelper3( SGG[ irrep ], size_G[ irrep ], newsize_G[ irrep ], vector_rhs + jump[ ptr1 ], tempvector_rhs + jump[ ptr1 ], num_rhs1 ); const int ptr2 = irrep + num_irreps * CHEMPS2_CASPT2_G_TRIPLET; const int num_rhs2 = ( jump[ ptr2 + 1 ] - jump[ ptr2 ] ) / size_G[ irrep ]; assert( num_rhs2 * size_G[ irrep ] == jump[ ptr2 + 1 ] - jump[ ptr2 ] ); helper[ ptr2 ] = num_rhs2 * newsize_G[ irrep ]; recreatehelper3( SGG[ irrep ], size_G[ irrep ], newsize_G[ irrep ], vector_rhs + jump[ ptr2 ], tempvector_rhs + jump[ ptr2 ], num_rhs2 ); } const int ptr1 = irrep + num_irreps * CHEMPS2_CASPT2_H_SINGLET; helper[ ptr1 ] = jump[ ptr1 + 1 ] - jump[ ptr1 ]; int inc1 = 1; dcopy_( helper + ptr1, vector_rhs + jump[ ptr1 ], &inc1, tempvector_rhs + jump[ ptr1 ], &inc1 ); const int ptr2 = irrep + num_irreps * CHEMPS2_CASPT2_H_TRIPLET; helper[ ptr2 ] = jump[ ptr2 + 1 ] - jump[ ptr2 ]; dcopy_( helper + ptr2, vector_rhs + jump[ ptr2 ], &inc1, tempvector_rhs + jump[ ptr2 ], &inc1 ); } delete [] vector_rhs; delete [] size_A; size_A = newsize_A; delete [] size_C; size_C = newsize_C; delete [] size_D; size_D = newsize_D; delete [] size_E; size_E = newsize_E; delete [] size_G; size_G = newsize_G; delete [] size_B_singlet; size_B_singlet = newsize_B_singlet; delete [] size_B_triplet; size_B_triplet = newsize_B_triplet; delete [] size_F_singlet; size_F_singlet = newsize_F_singlet; delete [] size_F_triplet; size_F_triplet = newsize_F_triplet; int * newjump = new int[ num_irreps * CHEMPS2_CASPT2_NUM_CASES + 1 ]; newjump[ 0 ] = 0; for ( int cnt = 0; cnt < num_irreps * CHEMPS2_CASPT2_NUM_CASES; cnt++ ){ newjump[ cnt + 1 ] = newjump[ cnt ] + helper[ cnt ]; } vector_rhs = new double[ newjump[ num_irreps * CHEMPS2_CASPT2_NUM_CASES ] ]; int inc1 = 1; for ( int cnt = 0; cnt < num_irreps * CHEMPS2_CASPT2_NUM_CASES; cnt++ ){ dcopy_( helper + cnt, tempvector_rhs + jump[ cnt ], &inc1, vector_rhs + newjump[ cnt ], &inc1 ); } delete [] tempvector_rhs; delete [] helper; delete [] jump; jump = newjump; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ delete [] SAA[ irrep ]; delete [] SCC[ irrep ]; delete [] SDD[ irrep ]; delete [] SEE[ irrep ]; delete [] SGG[ irrep ]; delete [] SBB_singlet[ irrep ]; delete [] SBB_triplet[ irrep ]; delete [] SFF_singlet[ irrep ]; delete [] SFF_triplet[ irrep ]; } delete [] SAA; delete [] SCC; delete [] SDD; delete [] SEE; delete [] SGG; delete [] SBB_singlet; delete [] SBB_triplet; delete [] SFF_singlet; delete [] SFF_triplet; double * temp = NULL; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ temp = new double[ size_A[ irrep ] ]; dcopy_( size_A + irrep, FAA[ irrep ], &inc1, temp, &inc1 ); delete [] FAA[ irrep ]; FAA[ irrep ] = temp; temp = new double[ size_C[ irrep ] ]; dcopy_( size_C + irrep, FCC[ irrep ], &inc1, temp, &inc1 ); delete [] FCC[ irrep ]; FCC[ irrep ] = temp; temp = new double[ size_D[ irrep ] ]; dcopy_( size_D + irrep, FDD[ irrep ], &inc1, temp, &inc1 ); delete [] FDD[ irrep ]; FDD[ irrep ] = temp; temp = new double[ size_E[ irrep ] ]; dcopy_( size_E + irrep, FEE[ irrep ], &inc1, temp, &inc1 ); delete [] FEE[ irrep ]; FEE[ irrep ] = temp; temp = new double[ size_G[ irrep ] ]; dcopy_( size_G + irrep, FGG[ irrep ], &inc1, temp, &inc1 ); delete [] FGG[ irrep ]; FGG[ irrep ] = temp; temp = new double[ size_B_singlet[ irrep ] ]; dcopy_( size_B_singlet + irrep, FBB_singlet[ irrep ], &inc1, temp, &inc1 ); delete [] FBB_singlet[ irrep ]; FBB_singlet[ irrep ] = temp; temp = new double[ size_B_triplet[ irrep ] ]; dcopy_( size_B_triplet + irrep, FBB_triplet[ irrep ], &inc1, temp, &inc1 ); delete [] FBB_triplet[ irrep ]; FBB_triplet[ irrep ] = temp; temp = new double[ size_F_singlet[ irrep ] ]; dcopy_( size_F_singlet + irrep, FFF_singlet[ irrep ], &inc1, temp, &inc1 ); delete [] FFF_singlet[ irrep ]; FFF_singlet[ irrep ] = temp; temp = new double[ size_F_triplet[ irrep ] ]; dcopy_( size_F_triplet + irrep, FFF_triplet[ irrep ], &inc1, temp, &inc1 ); delete [] FFF_triplet[ irrep ]; FFF_triplet[ irrep ] = temp; } const int total_size = jump[ num_irreps * CHEMPS2_CASPT2_NUM_CASES ]; cout << "CASPT2 : New size V_SD space = " << total_size << endl; } int CheMPS2::CASPT2::get_maxsize() const{ int maxsize = 0; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ maxsize = max( max( max( max( max( max( max( max( max( size_A[irrep], size_C[irrep] ), size_D[irrep] ), size_E[irrep] ), size_G[irrep] ), size_B_singlet[irrep] ), size_B_triplet[irrep] ), size_F_singlet[irrep] ), size_F_triplet[irrep] ), maxsize ); } if ( maxsize <= 2 ){ maxsize = 3; } return maxsize; } void CheMPS2::CASPT2::matmat( char totrans, int rowdim, int coldim, int sumdim, double alpha, double * matrix, int ldaM, double * origin, int ldaO, double * target, int ldaT ){ double add = 1.0; char notrans = 'N'; dgemm_( &totrans, ¬rans, &rowdim, &coldim, &sumdim, &alpha, matrix, &ldaM, origin, &ldaO, &add, target, &ldaT ); } void CheMPS2::CASPT2::matvec( double * vector, double * result, double * diag_fock ) const{ /* FOCK | A Bsinglet Btriplet C D1 D2 Esinglet Etriplet Fsinglet Ftriplet Gsinglet Gtriplet Hsinglet Htriplet ---------+------------------------------------------------------------------------------------------------------------------------- A | OK OK OK 0 OK OK GRAD GRAD 0 0 0 0 0 0 Bsinglet | OK OK 0 0 0 0 OK 0 0 0 0 0 0 0 Btriplet | OK 0 OK 0 0 0 0 OK 0 0 0 0 0 0 C | 0 0 0 OK OK OK 0 0 OK OK GRAD GRAD 0 0 D1 | OK 0 0 OK OK OK OK OK 0 0 OK OK GRAD GRAD D2 | OK 0 0 OK OK OK OK OK 0 0 OK OK GRAD GRAD Esinglet | GRAD OK 0 0 OK OK OK 0 0 0 0 0 OK 0 Etriplet | GRAD 0 OK 0 OK OK 0 OK 0 0 0 0 0 OK Fsinglet | 0 0 0 OK 0 0 0 0 OK 0 OK 0 0 0 Ftriplet | 0 0 0 OK 0 0 0 0 0 OK 0 OK 0 0 Gsinglet | 0 0 0 GRAD OK OK 0 0 OK 0 OK 0 OK 0 Gtriplet | 0 0 0 GRAD OK OK 0 0 0 OK 0 OK 0 OK Hsinglet | 0 0 0 0 GRAD GRAD OK 0 0 0 OK 0 OK 0 Htriplet | 0 0 0 0 GRAD GRAD 0 OK 0 0 0 OK 0 OK */ const int vectorlength = jump[ CHEMPS2_CASPT2_NUM_CASES * num_irreps ]; #pragma omp simd for ( int elem = 0; elem < vectorlength; elem++ ){ result[ elem ] = diag_fock[ elem ] * vector[ elem ]; } const int maxlinsize = get_maxsize(); double * workspace = new double[ maxlinsize * maxlinsize ]; const double SQRT2 = sqrt( 2.0 ); // FAD: < A(xjyz) E_wc D(aitu) > = delta_ac delta_ij FAD[ Ij ][ Ii x Ia ][ w ][ (xyz),(tu) ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Ii == Ij == Ix x Iy x Iz const int SIZE_L = size_A[ IL ]; const int nocc_ij = indices->getNOCC( IL ); for ( int IR = 0; IR < num_irreps; IR++ ){ // IR == It x Iu == Ii x Ia const int SIZE_R = size_D[ IR ]; const int Iw = Irreps::directProd( IL, IR ); // Ia == Ic == Iw == IL x IR const int shift = shift_D_nonactive( indices, IL, Iw ); const int nocc_w = indices->getNOCC( Iw ); const int nact_w = indices->getNDMRG( Iw ); const int n_oa_w = nocc_w + nact_w; const int nvir_w = indices->getNVIRT( Iw ); int total_size = SIZE_L * SIZE_R; if ( total_size * nocc_ij * nact_w * nvir_w > 0 ){ for ( int ac = 0; ac < nvir_w; ac++ ){ for ( int cnt = 0; cnt < total_size; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_w; w++ ){ double f_wc = fock->get( Iw, nocc_w + w, n_oa_w + ac ); int inc1 = 1; daxpy_( &total_size, &f_wc, FAD[ IL ][ IR ][ w ], &inc1, workspace, &inc1 ); } const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_A ]; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_D ] + SIZE_R * ( shift + nocc_ij * ac ); matmat( 'N', SIZE_L, nocc_ij, SIZE_R, 1.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, nocc_ij, SIZE_L, 1.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } } } } // FCD: < C(bxyz) E_kw D(aitu) > = delta_ik delta_ab FCD[ Ib ][ Ii x Ia ][ w ][ (xyz),(tu) ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Ia == Ib const int SIZE_L = size_C[ IL ]; const int nvir_ab = indices->getNVIRT( IL ); for ( int IR = 0; IR < num_irreps; IR++ ){ // IR == It x Iu == Ii x Ia const int SIZE_R = size_D[ IR ]; const int Iw = Irreps::directProd( IL, IR ); // Ii == Ik == Iw == IL x IR const int shift = shift_D_nonactive( indices, Iw, IL ); const int nocc_w = indices->getNOCC( Iw ); const int nact_w = indices->getNDMRG( Iw ); int total_size = SIZE_L * SIZE_R; if ( total_size * nvir_ab * nact_w * nocc_w > 0 ){ for ( int ik = 0; ik < nocc_w; ik++ ){ for ( int cnt = 0; cnt < total_size; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_w; w++ ){ double f_kw = fock->get( Iw, ik, nocc_w + w ); int inc1 = 1; daxpy_( &total_size, &f_kw, FCD[ IL ][ IR ][ w ], &inc1, workspace, &inc1 ); } const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_C ]; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_D ] + SIZE_R * ( shift + ik ); const int LDA_R = SIZE_R * nocc_w; matmat( 'N', SIZE_L, nvir_ab, SIZE_R, 1.0, workspace, SIZE_L, vector + ptr_R, LDA_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, nvir_ab, SIZE_L, 1.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, LDA_R ); } } } } // FAB singlet: < A(xlyz) E_kw SB_tiuj > = ( delta_ik delta_jl + delta_jk delta_il ) / sqrt( 1 + delta_ij ) * FAB_singlet[ Il ][ Ii x Ij ][ w ][ (xyz),(tu) ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Il == Ix x Iy x Iz const int SIZE_L = size_A[ IL ]; const int nocc_l = indices->getNOCC( IL ); for ( int IR = 0; IR < num_irreps; IR++ ){ // IR == It x Iu == Ii x Ij const int SIZE_R = size_B_singlet[ IR ]; const int Iw = Irreps::directProd( IL, IR ); // Iw == Ik const int shift = (( Iw < IL ) ? shift_B_nonactive( indices, Iw, IL, +1 ) : shift_B_nonactive( indices, IL, Iw, +1 )); const int nocc_w = indices->getNOCC( Iw ); const int nact_w = indices->getNDMRG( Iw ); int total_size = SIZE_L * SIZE_R; if ( total_size * nocc_l * nact_w * nocc_w > 0 ){ for ( int k = 0; k < nocc_w; k++ ){ for ( int cnt = 0; cnt < total_size; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_w; w++ ){ double f_kw = fock->get( Iw, k, nocc_w + w ); int inc1 = 1; daxpy_( &total_size, &f_kw, FAB_singlet[ IL ][ IR ][ w ], &inc1, workspace, &inc1 ); } if ( IR == 0 ){ // Ii == Ij and Ik == Il if ( k > 0 ){ const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_A ]; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_B_SINGLET ] + SIZE_R * ( shift + ( k * ( k + 1 ) ) / 2 ); matmat( 'N', SIZE_L, k, SIZE_R, 1.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, k, SIZE_L, 1.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } #pragma omp parallel for schedule(static) for ( int l = k; l < nocc_l; l++ ){ const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_A ] + SIZE_L * l; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_B_SINGLET ] + SIZE_R * ( shift + k + ( l * ( l + 1 ) ) / 2 ); const double factor = (( k == l ) ? SQRT2 : 1.0 ); matmat( 'N', SIZE_L, 1, SIZE_R, factor, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, 1, SIZE_L, factor, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } } else { const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_A ]; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_B_SINGLET ] + SIZE_R * ( shift + (( Iw < IL ) ? k : nocc_l * k )); const int LDA_R = (( Iw < IL ) ? SIZE_R * nocc_w : SIZE_R ); matmat( 'N', SIZE_L, nocc_l, SIZE_R, 1.0, workspace, SIZE_L, vector + ptr_R, LDA_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, nocc_l, SIZE_L, 1.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, LDA_R ); } } } } } // FAB triplet: < A(xlyz) E_kw TB_tiuj > = ( delta_ik delta_jl - delta_jk delta_il ) * FAB_triplet[ Il ][ Ii x Ij ][ w ][ (xyz),(tu) ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Il == Ix x Iy x Iz const int SIZE_L = size_A[ IL ]; const int nocc_l = indices->getNOCC( IL ); for ( int IR = 0; IR < num_irreps; IR++ ){ // IR == It x Iu == Ii x Ij const int SIZE_R = size_B_triplet[ IR ]; const int Iw = Irreps::directProd( IL, IR ); // Iw == Ik const int shift = (( Iw < IL ) ? shift_B_nonactive( indices, Iw, IL, -1 ) : shift_B_nonactive( indices, IL, Iw, -1 )); const int nocc_w = indices->getNOCC( Iw ); const int nact_w = indices->getNDMRG( Iw ); int total_size = SIZE_L * SIZE_R; if ( total_size * nocc_l * nact_w * nocc_w > 0 ){ for ( int k = 0; k < nocc_w; k++ ){ for ( int cnt = 0; cnt < total_size; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_w; w++ ){ double f_kw = fock->get( Iw, k, nocc_w + w ); int inc1 = 1; daxpy_( &total_size, &f_kw, FAB_triplet[ IL ][ IR ][ w ], &inc1, workspace, &inc1 ); } if ( IR == 0 ){ // Ii == Ij and Ik == Il if ( k > 0 ){ // ( k > l ---> - delta_jk delta_il ) const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_A ]; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_B_TRIPLET ] + SIZE_R * ( shift + ( k * ( k - 1 ) ) / 2 ); matmat( 'N', SIZE_L, k, SIZE_R, -1.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, k, SIZE_L, -1.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } #pragma omp parallel for schedule(static) for ( int l = k+1; l < nocc_l; l++ ){ const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_A ] + SIZE_L * l; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_B_TRIPLET ] + SIZE_R * ( shift + k + ( l * ( l - 1 ) ) / 2 ); matmat( 'N', SIZE_L, 1, SIZE_R, 1.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); // ( k < l ---> + delta_ik delta_jl ) matmat( 'T', SIZE_R, 1, SIZE_L, 1.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } } else { const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_A ]; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_B_TRIPLET ] + SIZE_R * ( shift + (( Iw < IL ) ? k : nocc_l * k )); const int LDA_R = (( Iw < IL ) ? SIZE_R * nocc_w : SIZE_R ); const double factor = (( Iw < IL ) ? 1.0 : -1.0 ); // ( k < l ---> + delta_ik delta_jl ) and ( k > l ---> - delta_jk delta_il ) matmat( 'N', SIZE_L, nocc_l, SIZE_R, factor, workspace, SIZE_L, vector + ptr_R, LDA_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, nocc_l, SIZE_L, factor, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, LDA_R ); } } } } } // FCF singlet: < C(dxyz) E_wc SF_atbu > = ( delta_ac delta_bd + delta_ad delta_bc ) / sqrt( 1 + delta_ab ) * FCF_singlet[ Id ][ Ia x Ib ][ w ][ (xyz),(tu) ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Id == Ix x Iy x Iz const int SIZE_L = size_C[ IL ]; const int nvir_d = indices->getNVIRT( IL ); for ( int IR = 0; IR < num_irreps; IR++ ){ // IR == It x Iu == Ia x Ib const int SIZE_R = size_F_singlet[ IR ]; const int Iw = Irreps::directProd( IL, IR ); // Iw == Ic const int shift = (( Iw < IL ) ? shift_F_nonactive( indices, Iw, IL, +1 ) : shift_F_nonactive( indices, IL, Iw, +1 )); const int nocc_w = indices->getNOCC( Iw ); const int nact_w = indices->getNDMRG( Iw ); const int n_oa_w = nocc_w + nact_w; const int nvir_w = indices->getNVIRT( Iw ); int total_size = SIZE_L * SIZE_R; if ( total_size * nvir_d * nact_w * nvir_w > 0 ){ for ( int c = 0; c < nvir_w; c++ ){ for ( int cnt = 0; cnt < total_size; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_w; w++ ){ double f_wc = fock->get( Iw, nocc_w + w, n_oa_w + c ); int inc1 = 1; daxpy_( &total_size, &f_wc, FCF_singlet[ IL ][ IR ][ w ], &inc1, workspace, &inc1 ); } if ( IR == 0 ){ // Ia == Ib and Ic == Id if ( c > 0 ){ const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_C ]; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_F_SINGLET ] + SIZE_R * ( shift + ( c * ( c + 1 ) ) / 2 ); matmat( 'N', SIZE_L, c, SIZE_R, 1.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, c, SIZE_L, 1.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } #pragma omp parallel for schedule(static) for ( int d = c; d < nvir_d; d++ ){ const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_C ] + SIZE_L * d; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_F_SINGLET ] + SIZE_R * ( shift + c + ( d * ( d + 1 ) ) / 2 ); const double factor = (( c == d ) ? SQRT2 : 1.0 ); matmat( 'N', SIZE_L, 1, SIZE_R, factor, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, 1, SIZE_L, factor, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } } else { const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_C ]; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_F_SINGLET ] + SIZE_R * ( shift + (( Iw < IL ) ? c : nvir_d * c )); const int LDA_R = (( Iw < IL ) ? SIZE_R * nvir_w : SIZE_R ); matmat( 'N', SIZE_L, nvir_d, SIZE_R, 1.0, workspace, SIZE_L, vector + ptr_R, LDA_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, nvir_d, SIZE_L, 1.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, LDA_R ); } } } } } // FCF triplet: < C(dxyz) E_wc TF_atbu > = ( delta_ac delta_bd - delta_ad delta_bc ) * FCF_triplet[ Id ][ Ia x Ib ][ w ][ (xyz),(tu) ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Id == Ix x Iy x Iz const int SIZE_L = size_C[ IL ]; const int nvir_d = indices->getNVIRT( IL ); for ( int IR = 0; IR < num_irreps; IR++ ){ // IR == It x Iu == Ia x Ib const int SIZE_R = size_F_triplet[ IR ]; const int Iw = Irreps::directProd( IL, IR ); // Iw == Ic const int shift = (( Iw < IL ) ? shift_F_nonactive( indices, Iw, IL, -1 ) : shift_F_nonactive( indices, IL, Iw, -1 )); const int nocc_w = indices->getNOCC( Iw ); const int nact_w = indices->getNDMRG( Iw ); const int n_oa_w = nocc_w + nact_w; const int nvir_w = indices->getNVIRT( Iw ); int total_size = SIZE_L * SIZE_R; if ( total_size * nvir_d * nact_w * nvir_w > 0 ){ for ( int c = 0; c < nvir_w; c++ ){ for ( int cnt = 0; cnt < total_size; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_w; w++ ){ double f_wc = fock->get( Iw, nocc_w + w, n_oa_w + c ); int inc1 = 1; daxpy_( &total_size, &f_wc, FCF_triplet[ IL ][ IR ][ w ], &inc1, workspace, &inc1 ); } if ( IR == 0 ){ // Ia == Ib and Ic == Id if ( c > 0 ){ // ( c > d ---> - delta_ad delta_bc ) const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_C ]; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_F_TRIPLET ] + SIZE_R * ( shift + ( c * ( c - 1 ) ) / 2 ); matmat( 'N', SIZE_L, c, SIZE_R, -1.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, c, SIZE_L, -1.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } #pragma omp parallel for schedule(static) for ( int d = c+1; d < nvir_d; d++ ){ const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_C ] + SIZE_L * d; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_F_TRIPLET ] + SIZE_R * ( shift + c + ( d * ( d - 1 ) ) / 2 ); matmat( 'N', SIZE_L, 1, SIZE_R, 1.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); // ( c < d ---> + delta_ac delta_bd ) matmat( 'T', SIZE_R, 1, SIZE_L, 1.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } } else { const double factor = (( Iw < IL ) ? 1.0 : -1.0 ); // ( c < d ---> + delta_ac delta_bd ) and ( c > d ---> - delta_ad delta_bc ) const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_C ]; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_F_TRIPLET ] + SIZE_R * ( shift + (( Iw < IL ) ? c : nvir_d * c )); const int LDA_R = (( Iw < IL ) ? SIZE_R * nvir_w : SIZE_R ); matmat( 'N', SIZE_L, nvir_d, SIZE_R, factor, workspace, SIZE_L, vector + ptr_R, LDA_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, nvir_d, SIZE_L, factor, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, LDA_R ); } } } } } // FBE singlet: < SB_xkyl E_wc SE_tiaj > = 2 delta_ac delta_ik delta_jl FBE_singlet[ Ik x Il ][ It ][ w ][ xy, t ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Iik x Ijl == Ix x Iy const int SIZE_L = size_B_singlet[ IL ]; for ( int IR = 0; IR < num_irreps; IR++ ){ // IR == It == Iik x Ijl x Iac const int SIZE_R = size_E[ IR ]; const int Iw = Irreps::directProd( IL, IR ); // Iw == Iac const int nocc_w = indices->getNOCC( Iw ); const int nact_w = indices->getNDMRG( Iw ); const int n_oa_w = nocc_w + nact_w; const int nvir_w = indices->getNVIRT( Iw ); int linsize = 0; for ( int Iik = 0; Iik < num_irreps; Iik++ ){ const int Ijl = Irreps::directProd( Iik, IL ); if ( Iik <= Ijl ){ const int nocc_ik = indices->getNOCC( Iik ); linsize += (( IL == 0 ) ? ( nocc_ik * ( nocc_ik + 1 ) ) / 2 : nocc_ik * indices->getNOCC( Ijl ) ); } } const int size_ij = linsize; int total_size = SIZE_L * SIZE_R; if ( total_size * nact_w * nvir_w * size_ij > 0 ){ const int shift_E = shift_E_nonactive( indices, Iw, 0, IL, +1 ); for ( int ac = 0; ac < nvir_w; ac++ ){ for ( int cnt = 0; cnt < total_size; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_w; w++ ){ double f_wc = fock->get( Iw, nocc_w + w, n_oa_w + ac ); int inc1 = 1; daxpy_( &total_size, &f_wc, FBE_singlet[ IL ][ IR ][ w ], &inc1, workspace, &inc1 ); } const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_B_SINGLET ]; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_E_SINGLET ] + SIZE_R * ( shift_E + ac ); const int LDA_R = SIZE_R * nvir_w; matmat( 'N', SIZE_L, size_ij, SIZE_R, 2.0, workspace, SIZE_L, vector + ptr_R, LDA_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, size_ij, SIZE_L, 2.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, LDA_R ); } } } } // FBE triplet: < TB_xkyl E_wc TE_tiaj > = 2 delta_ac delta_ik delta_jl FBE_triplet[ Ik x Il ][ It ][ w ][ xy, t ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Iik x Ijl == Ix x Iy const int SIZE_L = size_B_triplet[ IL ]; for ( int IR = 0; IR < num_irreps; IR++ ){ // IR == It == Iik x Ijl x Iac const int SIZE_R = size_E[ IR ]; const int Iw = Irreps::directProd( IL, IR ); // Iw == Iac const int nocc_w = indices->getNOCC( Iw ); const int nact_w = indices->getNDMRG( Iw ); const int n_oa_w = nocc_w + nact_w; const int nvir_w = indices->getNVIRT( Iw ); int linsize = 0; for ( int Iik = 0; Iik < num_irreps; Iik++ ){ const int Ijl = Irreps::directProd( Iik, IL ); if ( Iik <= Ijl ){ const int nocc_ik = indices->getNOCC( Iik ); linsize += (( IL == 0 ) ? ( nocc_ik * ( nocc_ik - 1 ) ) / 2 : nocc_ik * indices->getNOCC( Ijl ) ); } } const int size_ij = linsize; int total_size = SIZE_L * SIZE_R; if ( total_size * nact_w * nvir_w * size_ij > 0 ){ const int shift_E = shift_E_nonactive( indices, Iw, 0, IL, -1 ); for ( int ac = 0; ac < nvir_w; ac++ ){ for ( int cnt = 0; cnt < total_size; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_w; w++ ){ double f_wc = fock->get( Iw, nocc_w + w, n_oa_w + ac ); int inc1 = 1; daxpy_( &total_size, &f_wc, FBE_triplet[ IL ][ IR ][ w ], &inc1, workspace, &inc1 ); } const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_B_TRIPLET ]; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_E_TRIPLET ] + SIZE_R * ( shift_E + ac ); const int LDA_R = SIZE_R * nvir_w; matmat( 'N', SIZE_L, size_ij, SIZE_R, 2.0, workspace, SIZE_L, vector + ptr_R, LDA_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, size_ij, SIZE_L, 2.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, LDA_R ); } } } } // FFG singlet: < SF_cxdy E_kw SG_aibt > = 2 delta_ac delta_bd delta_ik FFG_singlet[ Ic x Id ][ It ][ w ][ xy, t ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Iac x Ibd == Ix x Iy const int SIZE_L = size_F_singlet[ IL ]; for ( int IR = 0; IR < num_irreps; IR++ ){ // IR == It == Iac x Ibd x Iik const int SIZE_R = size_G[ IR ]; const int Iw = Irreps::directProd( IL, IR ); // Iw == Iik const int nocc_w = indices->getNOCC( Iw ); const int nact_w = indices->getNDMRG( Iw ); int linsize = 0; for ( int Iac = 0; Iac < num_irreps; Iac++ ){ const int Ibd = Irreps::directProd( Iac, IL ); if ( Iac <= Ibd ){ const int nvir_ac = indices->getNVIRT( Iac ); linsize += (( IL == 0 ) ? ( nvir_ac * ( nvir_ac + 1 ) ) / 2 : nvir_ac * indices->getNVIRT( Ibd ) ); } } const int size_ab = linsize; int total_size = SIZE_L * SIZE_R; if ( total_size * nact_w * nocc_w * size_ab > 0 ){ const int shift_G = shift_G_nonactive( indices, Iw, 0, IL, +1 ); for ( int ik = 0; ik < nocc_w; ik++ ){ for ( int cnt = 0; cnt < total_size; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_w; w++ ){ double f_kw = fock->get( Iw, ik, nocc_w + w ); int inc1 = 1; daxpy_( &total_size, &f_kw, FFG_singlet[ IL ][ IR ][ w ], &inc1, workspace, &inc1 ); } const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_F_SINGLET ]; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_G_SINGLET ] + SIZE_R * ( shift_G + ik ); const int LDA_R = SIZE_R * nocc_w; matmat( 'N', SIZE_L, size_ab, SIZE_R, 2.0, workspace, SIZE_L, vector + ptr_R, LDA_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, size_ab, SIZE_L, 2.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, LDA_R ); } } } } // FFG triplet: < TF_cxdy E_kw TG_aibt > = 2 delta_ac delta_bd delta_ik FFG_triplet[ Ic x Id ][ It ][ w ][ xy, t ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Iac x Ibd == Ix x Iy const int SIZE_L = size_F_triplet[ IL ]; for ( int IR = 0; IR < num_irreps; IR++ ){ // IR == It == Iac x Ibd x Iik const int SIZE_R = size_G[ IR ]; const int Iw = Irreps::directProd( IL, IR ); // Iw == Iik const int nocc_w = indices->getNOCC( Iw ); const int nact_w = indices->getNDMRG( Iw ); int linsize = 0; for ( int Iac = 0; Iac < num_irreps; Iac++ ){ const int Ibd = Irreps::directProd( Iac, IL ); if ( Iac <= Ibd ){ const int nvir_ac = indices->getNVIRT( Iac ); linsize += (( IL == 0 ) ? ( nvir_ac * ( nvir_ac - 1 ) ) / 2 : nvir_ac * indices->getNVIRT( Ibd ) ); } } const int size_ab = linsize; int total_size = SIZE_L * SIZE_R; if ( total_size * nact_w * nocc_w * size_ab > 0 ){ const int shift_G = shift_G_nonactive( indices, Iw, 0, IL, -1 ); for ( int ik = 0; ik < nocc_w; ik++ ){ for ( int cnt = 0; cnt < total_size; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_w; w++ ){ double f_kw = fock->get( Iw, ik, nocc_w + w ); int inc1 = 1; daxpy_( &total_size, &f_kw, FFG_triplet[ IL ][ IR ][ w ], &inc1, workspace, &inc1 ); } const int ptr_L = jump[ IL + num_irreps * CHEMPS2_CASPT2_F_TRIPLET ]; const int ptr_R = jump[ IR + num_irreps * CHEMPS2_CASPT2_G_TRIPLET ] + SIZE_R * ( shift_G + ik ); const int LDA_R = SIZE_R * nocc_w; matmat( 'N', SIZE_L, size_ab, SIZE_R, 2.0, workspace, SIZE_L, vector + ptr_R, LDA_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, size_ab, SIZE_L, 2.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, LDA_R ); } } } } // FEH singlet: < SE_xkdl E_wc SH_aibj > = 2 delta_ik delta_jl ( delta_ac delta_bd + delta_ad delta_bc ) / sqrt( 1 + delta_ab ) FEH[ Ix ][ w ][ x ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Ixw == Ic == Iik x Ijl x Id int SIZE = size_E[ IL ]; const int nocc_w = indices->getNOCC( IL ); const int nact_w = indices->getNDMRG( IL ); const int n_oa_w = nocc_w + nact_w; const int nvir_w = indices->getNVIRT( IL ); if ( SIZE * nact_w * nvir_w > 0 ){ for ( int c = 0; c < nvir_w; c++ ){ // workspace_c[ x ] = sum_w f_wc FEH[ Ixw == IL == Ic ][ w ][ x ] for ( int cnt = 0; cnt < SIZE; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_w; w++ ){ double f_wc = fock->get( IL, nocc_w + w, n_oa_w + c ); int inc1 = 1; daxpy_( &SIZE, &f_wc, FEH[ IL ][ w ], &inc1, workspace, &inc1 ); } for ( int Id = 0; Id < num_irreps; Id++ ){ const int Icenter = Irreps::directProd( IL, Id ); const int nvir_d = indices->getNVIRT( Id ); const int LDA_E = SIZE * nvir_d; if ( IL < Id ){ // Ic < Id for ( int Ii = 0; Ii < num_irreps; Ii++ ){ const int Ij = Irreps::directProd( Ii, Icenter ); if ( Ii < Ij ){ const int jump_E = jump[ IL + num_irreps * CHEMPS2_CASPT2_E_SINGLET ] + SIZE * shift_E_nonactive( indices, Id, Ii, Ij, +1 ); const int jump_H = jump[ Icenter + num_irreps * CHEMPS2_CASPT2_H_SINGLET ] + shift_H_nonactive( indices, Ii, Ij, IL, Id, +1 ); const int size_ij = indices->getNOCC( Ii ) * indices->getNOCC( Ij ); #pragma omp parallel for schedule(static) for ( int d = 0; d < nvir_d; d++ ){ const int ptr_H = jump_H + size_ij * ( c + nvir_w * d ); const int ptr_E = jump_E + SIZE * d; matmat( 'N', SIZE, size_ij, 1, 2.0, workspace, SIZE, vector + ptr_H, 1, result + ptr_E, LDA_E ); matmat( 'T', 1, size_ij, SIZE, 2.0, workspace, SIZE, vector + ptr_E, LDA_E, result + ptr_H, 1 ); } } } } if ( IL == Id ){ // Ic == Id == Ia == Ib --> Iik == Ijl for ( int Iij = 0; Iij < num_irreps; Iij++ ){ const int jump_E = jump[ IL + num_irreps * CHEMPS2_CASPT2_E_SINGLET ] + SIZE * shift_E_nonactive( indices, Id, Iij, Iij, +1 ); const int jump_H = jump[ Icenter + num_irreps * CHEMPS2_CASPT2_H_SINGLET ] + shift_H_nonactive( indices, Iij, Iij, IL, Id, +1 ); const int size_ij = ( indices->getNOCC( Iij ) * ( indices->getNOCC( Iij ) + 1 ) ) / 2; #pragma omp parallel for schedule(static) for ( int d = 0; d < c; d++ ){ const int ptr_H = jump_H + size_ij * ( d + ( c * ( c + 1 ) ) / 2 ); const int ptr_E = jump_E + SIZE * d; matmat( 'N', SIZE, size_ij, 1, 2.0, workspace, SIZE, vector + ptr_H, 1, result + ptr_E, LDA_E ); matmat( 'T', 1, size_ij, SIZE, 2.0, workspace, SIZE, vector + ptr_E, LDA_E, result + ptr_H, 1 ); } #pragma omp parallel for schedule(static) for ( int d = c; d < nvir_d; d++ ){ const int ptr_H = jump_H + size_ij * ( c + ( d * ( d + 1 ) ) / 2 ); const int ptr_E = jump_E + SIZE * d; const double factor = 2 * (( c == d ) ? SQRT2 : 1.0 ); matmat( 'N', SIZE, size_ij, 1, factor, workspace, SIZE, vector + ptr_H, 1, result + ptr_E, LDA_E ); matmat( 'T', 1, size_ij, SIZE, factor, workspace, SIZE, vector + ptr_E, LDA_E, result + ptr_H, 1 ); } } } if ( IL > Id ){ // Ic > Id for ( int Ii = 0; Ii < num_irreps; Ii++ ){ const int Ij = Irreps::directProd( Ii, Icenter ); if ( Ii < Ij ){ const int jump_E = jump[ IL + num_irreps * CHEMPS2_CASPT2_E_SINGLET ] + SIZE * shift_E_nonactive( indices, Id, Ii, Ij, +1 ); const int jump_H = jump[ Icenter + num_irreps * CHEMPS2_CASPT2_H_SINGLET ] + shift_H_nonactive( indices, Ii, Ij, Id, IL, +1 ); const int size_ij = indices->getNOCC( Ii ) * indices->getNOCC( Ij ); #pragma omp parallel for schedule(static) for ( int d = 0; d < nvir_d; d++ ){ const int ptr_H = jump_H + size_ij * ( d + nvir_d * c ); const int ptr_E = jump_E + SIZE * d; matmat( 'N', SIZE, size_ij, 1, 2.0, workspace, SIZE, vector + ptr_H, 1, result + ptr_E, LDA_E ); matmat( 'T', 1, size_ij, SIZE, 2.0, workspace, SIZE, vector + ptr_E, LDA_E, result + ptr_H, 1 ); } } } } } } } } // FEH triplet: < TE_xkdl E_wc TH_aibj > = 6 delta_ik delta_jl ( delta_ac delta_bd - delta_ad delta_bc ) / sqrt( 1 + delta_ab ) FEH[ Ix ][ w ][ x ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Ixw == Ic == Iik x Ijl x Id int SIZE = size_E[ IL ]; const int nocc_w = indices->getNOCC( IL ); const int nact_w = indices->getNDMRG( IL ); const int n_oa_w = nocc_w + nact_w; const int nvir_w = indices->getNVIRT( IL ); if ( SIZE * nact_w * nvir_w > 0 ){ for ( int c = 0; c < nvir_w; c++ ){ // workspace_c[ x ] = sum_w f_wc FEH[ Ixw == IL == Ic ][ w ][ x ] for ( int cnt = 0; cnt < SIZE; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_w; w++ ){ double f_wc = fock->get( IL, nocc_w + w, n_oa_w + c ); int inc1 = 1; daxpy_( &SIZE, &f_wc, FEH[ IL ][ w ], &inc1, workspace, &inc1 ); } for ( int Id = 0; Id < num_irreps; Id++ ){ const int Icenter = Irreps::directProd( IL, Id ); const int nvir_d = indices->getNVIRT( Id ); const int LDA_E = SIZE * nvir_d; if ( IL < Id ){ // Ic < Id for ( int Ii = 0; Ii < num_irreps; Ii++ ){ const int Ij = Irreps::directProd( Ii, Icenter ); if ( Ii < Ij ){ const int jump_E = jump[ IL + num_irreps * CHEMPS2_CASPT2_E_TRIPLET ] + SIZE * shift_E_nonactive( indices, Id, Ii, Ij, -1 ); const int jump_H = jump[ Icenter + num_irreps * CHEMPS2_CASPT2_H_TRIPLET ] + shift_H_nonactive( indices, Ii, Ij, IL, Id, -1 ); const int size_ij = indices->getNOCC( Ii ) * indices->getNOCC( Ij ); #pragma omp parallel for schedule(static) for ( int d = 0; d < nvir_d; d++ ){ const int ptr_H = jump_H + size_ij * ( c + nvir_w * d ); const int ptr_E = jump_E + SIZE * d; matmat( 'N', SIZE, size_ij, 1, 6.0, workspace, SIZE, vector + ptr_H, 1, result + ptr_E, LDA_E ); matmat( 'T', 1, size_ij, SIZE, 6.0, workspace, SIZE, vector + ptr_E, LDA_E, result + ptr_H, 1 ); } } } } if ( IL == Id ){ // Ic == Id == Ia == Ib --> Iik == Ijl for ( int Iij = 0; Iij < num_irreps; Iij++ ){ const int jump_E = jump[ IL + num_irreps * CHEMPS2_CASPT2_E_TRIPLET ] + SIZE * shift_E_nonactive( indices, Id, Iij, Iij, -1 ); const int jump_H = jump[ Icenter + num_irreps * CHEMPS2_CASPT2_H_TRIPLET ] + shift_H_nonactive( indices, Iij, Iij, IL, Id, -1 ); const int size_ij = ( indices->getNOCC( Iij ) * ( indices->getNOCC( Iij ) - 1 ) ) / 2; #pragma omp parallel for schedule(static) for ( int d = 0; d < c; d++ ){ const int ptr_H = jump_H + size_ij * ( d + ( c * ( c - 1 ) ) / 2 ); const int ptr_E = jump_E + SIZE * d; matmat( 'N', SIZE, size_ij, 1, -6.0, workspace, SIZE, vector + ptr_H, 1, result + ptr_E, LDA_E ); matmat( 'T', 1, size_ij, SIZE, -6.0, workspace, SIZE, vector + ptr_E, LDA_E, result + ptr_H, 1 ); } #pragma omp parallel for schedule(static) for ( int d = c+1; d < nvir_d; d++ ){ const int ptr_H = jump_H + size_ij * ( c + ( d * ( d - 1 ) ) / 2 ); const int ptr_E = jump_E + SIZE * d; matmat( 'N', SIZE, size_ij, 1, 6.0, workspace, SIZE, vector + ptr_H, 1, result + ptr_E, LDA_E ); matmat( 'T', 1, size_ij, SIZE, 6.0, workspace, SIZE, vector + ptr_E, LDA_E, result + ptr_H, 1 ); } } } if ( IL > Id ){ // Ic > Id for ( int Ii = 0; Ii < num_irreps; Ii++ ){ const int Ij = Irreps::directProd( Ii, Icenter ); if ( Ii < Ij ){ const int jump_E = jump[ IL + num_irreps * CHEMPS2_CASPT2_E_TRIPLET ] + SIZE * shift_E_nonactive( indices, Id, Ii, Ij, -1 ); const int jump_H = jump[ Icenter + num_irreps * CHEMPS2_CASPT2_H_TRIPLET ] + shift_H_nonactive( indices, Ii, Ij, Id, IL, -1 ); const int size_ij = indices->getNOCC( Ii ) * indices->getNOCC( Ij ); #pragma omp parallel for schedule(static) for ( int d = 0; d < nvir_d; d++ ){ const int ptr_H = jump_H + size_ij * ( d + nvir_d * c ); const int ptr_E = jump_E + SIZE * d; matmat( 'N', SIZE, size_ij, 1, -6.0, workspace, SIZE, vector + ptr_H, 1, result + ptr_E, LDA_E ); matmat( 'T', 1, size_ij, SIZE, -6.0, workspace, SIZE, vector + ptr_E, LDA_E, result + ptr_H, 1 ); } } } } } } } } // FGH singlet: < SG_cldx E_kw SH_aibj > = 2 delta_ac delta_bd ( delta_il delta_jk + delta_ik delta_jl ) / sqrt( 1 + delta_ij ) FGH[ Ix ][ w ][ x ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Ixw == Ik == Iac x Ibd x Il int SIZE = size_G[ IL ]; const int nocc_w = indices->getNOCC( IL ); const int nact_w = indices->getNDMRG( IL ); if ( SIZE * nocc_w * nact_w > 0 ){ for ( int k = 0; k < nocc_w; k++ ){ // workspace_k[ x ] = sum_w f_kw FGH[ Ixw == IL == Ik ][ w ][ x ] for ( int cnt = 0; cnt < SIZE; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_w; w++ ){ double f_kw = fock->get( IL, k, nocc_w + w ); int inc1 = 1; daxpy_( &SIZE, &f_kw, FGH[ IL ][ w ], &inc1, workspace, &inc1 ); } for ( int Il = 0; Il < num_irreps; Il++ ){ const int Icenter = Irreps::directProd( IL, Il ); const int nocc_l = indices->getNOCC( Il ); if ( IL < Il ){ // Ik < Il for ( int Ia = 0; Ia < num_irreps; Ia++ ){ const int Ib = Irreps::directProd( Ia, Icenter ); if ( Ia < Ib ){ const int colsize = nocc_l * indices->getNVIRT( Ia ) * indices->getNVIRT( Ib ); if ( colsize > 0 ){ const int jump_G = jump[ IL + num_irreps * CHEMPS2_CASPT2_G_SINGLET ] + SIZE * shift_G_nonactive( indices, Il, Ia, Ib, +1 ); const int jump_H = jump[ Icenter + num_irreps * CHEMPS2_CASPT2_H_SINGLET ] + shift_H_nonactive( indices, IL, Il, Ia, Ib, +1 ) + k; matmat( 'N', SIZE, colsize, 1, 2.0, workspace, SIZE, vector + jump_H, nocc_w, result + jump_G, SIZE ); matmat( 'T', 1, colsize, SIZE, 2.0, workspace, SIZE, vector + jump_G, SIZE, result + jump_H, nocc_w ); } } } } if ( IL == Il ){ // Ik == Il == Ii == Ij --> Iac == Ibd and nocc_l == nocc_w for ( int Iab = 0; Iab < num_irreps; Iab++ ){ const int jump_G = jump[ IL + num_irreps * CHEMPS2_CASPT2_G_SINGLET ] + SIZE * shift_G_nonactive( indices, Il, Iab, Iab, +1 ); const int jump_H = jump[ Icenter + num_irreps * CHEMPS2_CASPT2_H_SINGLET ] + shift_H_nonactive( indices, IL, Il, Iab, Iab, +1 ); const int size_ij = ( nocc_w * ( nocc_w + 1 ) ) / 2; const int size_ab = ( indices->getNVIRT( Iab ) * ( indices->getNVIRT( Iab ) + 1 ) ) / 2; const int LDA_G = SIZE * nocc_l; #pragma omp parallel for schedule(static) for ( int l = 0; l < k; l++ ){ const int ptr_H = jump_H + ( l + ( k * ( k + 1 ) ) / 2 ); const int ptr_G = jump_G + SIZE * l; matmat( 'N', SIZE, size_ab, 1, 2.0, workspace, SIZE, vector + ptr_H, size_ij, result + ptr_G, LDA_G ); matmat( 'T', 1, size_ab, SIZE, 2.0, workspace, SIZE, vector + ptr_G, LDA_G, result + ptr_H, size_ij ); } #pragma omp parallel for schedule(static) for ( int l = k; l < nocc_l; l++ ){ const int ptr_H = jump_H + ( k + ( l * ( l + 1 ) ) / 2 ); const int ptr_G = jump_G + SIZE * l; const double factor = 2 * (( k == l ) ? SQRT2 : 1.0 ); matmat( 'N', SIZE, size_ab, 1, factor, workspace, SIZE, vector + ptr_H, size_ij, result + ptr_G, LDA_G ); matmat( 'T', 1, size_ab, SIZE, factor, workspace, SIZE, vector + ptr_G, LDA_G, result + ptr_H, size_ij ); } } } if ( IL > Il ){ // Ik > Il for ( int Ia = 0; Ia < num_irreps; Ia++ ){ const int Ib = Irreps::directProd( Ia, Icenter ); if ( Ia < Ib ){ const int jump_G = jump[ IL + num_irreps * CHEMPS2_CASPT2_G_SINGLET ] + SIZE * shift_G_nonactive( indices, Il, Ia, Ib, +1 ); const int jump_H = jump[ Icenter + num_irreps * CHEMPS2_CASPT2_H_SINGLET ] + shift_H_nonactive( indices, Il, IL, Ia, Ib, +1 ); const int size_ab = indices->getNVIRT( Ia ) * indices->getNVIRT( Ib ); #pragma omp parallel for schedule(static) for ( int ab = 0; ab < size_ab; ab++ ){ const int ptr_H = jump_H + nocc_l * ( k + nocc_w * ab ); const int ptr_G = jump_G + SIZE * nocc_l * ab; matmat( 'N', SIZE, nocc_l, 1, 2.0, workspace, SIZE, vector + ptr_H, 1, result + ptr_G, SIZE ); matmat( 'T', 1, nocc_l, SIZE, 2.0, workspace, SIZE, vector + ptr_G, SIZE, result + ptr_H, 1 ); } } } } } } } } // FGH triplet: < TG_cldx E_kw TH_aibj > = 6 delta_ac delta_bd ( delta_il delta_jk - delta_ik delta_jl ) / sqrt( 1 + delta_ij ) FGH[ Ix ][ w ][ x ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Ixw == Ik == Iac x Ibd x Il int SIZE = size_G[ IL ]; const int nocc_w = indices->getNOCC( IL ); const int nact_w = indices->getNDMRG( IL ); if ( SIZE * nocc_w * nact_w > 0 ){ for ( int k = 0; k < nocc_w; k++ ){ // workspace_k[ x ] = sum_w f_kw FGH[ Ixw == IL == Ik ][ w ][ x ] for ( int cnt = 0; cnt < SIZE; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_w; w++ ){ double f_kw = fock->get( IL, k, nocc_w + w ); int inc1 = 1; daxpy_( &SIZE, &f_kw, FGH[ IL ][ w ], &inc1, workspace, &inc1 ); } for ( int Il = 0; Il < num_irreps; Il++ ){ const int Icenter = Irreps::directProd( IL, Il ); const int nocc_l = indices->getNOCC( Il ); if ( IL < Il ){ // Ik < Il for ( int Ia = 0; Ia < num_irreps; Ia++ ){ const int Ib = Irreps::directProd( Ia, Icenter ); if ( Ia < Ib ){ const int colsize = nocc_l * indices->getNVIRT( Ia ) * indices->getNVIRT( Ib ); if ( colsize > 0 ){ const int jump_G = jump[ IL + num_irreps * CHEMPS2_CASPT2_G_TRIPLET ] + SIZE * shift_G_nonactive( indices, Il, Ia, Ib, -1 ); const int jump_H = jump[ Icenter + num_irreps * CHEMPS2_CASPT2_H_TRIPLET ] + shift_H_nonactive( indices, IL, Il, Ia, Ib, -1 ) + k; matmat( 'N', SIZE, colsize, 1, -6.0, workspace, SIZE, vector + jump_H, nocc_w, result + jump_G, SIZE ); matmat( 'T', 1, colsize, SIZE, -6.0, workspace, SIZE, vector + jump_G, SIZE, result + jump_H, nocc_w ); } } } } if ( IL == Il ){ // Ik == Il == Ii == Ij --> Iac == Ibd and nocc_l == nocc_w for ( int Iab = 0; Iab < num_irreps; Iab++ ){ const int jump_G = jump[ IL + num_irreps * CHEMPS2_CASPT2_G_TRIPLET ] + SIZE * shift_G_nonactive( indices, Il, Iab, Iab, -1 ); const int jump_H = jump[ Icenter + num_irreps * CHEMPS2_CASPT2_H_TRIPLET ] + shift_H_nonactive( indices, IL, Il, Iab, Iab, -1 ); const int size_ij = ( nocc_w * ( nocc_w - 1 ) ) / 2; const int size_ab = ( indices->getNVIRT( Iab ) * ( indices->getNVIRT( Iab ) - 1 ) ) / 2; const int LDA_G = SIZE * nocc_l; #pragma omp parallel for schedule(static) for ( int l = 0; l < k; l++ ){ const int ptr_H = jump_H + ( l + ( k * ( k - 1 ) ) / 2 ); const int ptr_G = jump_G + SIZE * l; matmat( 'N', SIZE, size_ab, 1, 6.0, workspace, SIZE, vector + ptr_H, size_ij, result + ptr_G, LDA_G ); matmat( 'T', 1, size_ab, SIZE, 6.0, workspace, SIZE, vector + ptr_G, LDA_G, result + ptr_H, size_ij ); } #pragma omp parallel for schedule(static) for ( int l = k+1; l < nocc_l; l++ ){ const int ptr_H = jump_H + ( k + ( l * ( l - 1 ) ) / 2 ); const int ptr_G = jump_G + SIZE * l; matmat( 'N', SIZE, size_ab, 1, -6.0, workspace, SIZE, vector + ptr_H, size_ij, result + ptr_G, LDA_G ); matmat( 'T', 1, size_ab, SIZE, -6.0, workspace, SIZE, vector + ptr_G, LDA_G, result + ptr_H, size_ij ); } } } if ( IL > Il ){ // Ik > Il for ( int Ia = 0; Ia < num_irreps; Ia++ ){ const int Ib = Irreps::directProd( Ia, Icenter ); if ( Ia < Ib ){ const int jump_G = jump[ IL + num_irreps * CHEMPS2_CASPT2_G_TRIPLET ] + SIZE * shift_G_nonactive( indices, Il, Ia, Ib, -1 ); const int jump_H = jump[ Icenter + num_irreps * CHEMPS2_CASPT2_H_TRIPLET ] + shift_H_nonactive( indices, Il, IL, Ia, Ib, -1 ); const int size_ab = indices->getNVIRT( Ia ) * indices->getNVIRT( Ib ); #pragma omp parallel for schedule(static) for ( int ab = 0; ab < size_ab; ab++ ){ const int ptr_H = jump_H + nocc_l * ( k + nocc_w * ab ); const int ptr_G = jump_G + SIZE * nocc_l * ab; matmat( 'N', SIZE, nocc_l, 1, 6.0, workspace, SIZE, vector + ptr_H, 1, result + ptr_G, SIZE ); matmat( 'T', 1, nocc_l, SIZE, 6.0, workspace, SIZE, vector + ptr_G, SIZE, result + ptr_H, 1 ); } } } } } } } } // FDE singlet: < D(blxy) E_kw SE_tiaj > = 1 delta_ab ( delta_ik delta_jl + delta_il delta_jk ) / sqrt( 1 + delta_ij ) FDE_singlet[ Ib x Il ][ It ][ w ][ xy, t ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Ix x Iy == Ib x Il const int SIZE_L = size_D[ IL ]; for ( int IR = 0; IR < num_irreps; IR++ ){ // IR = It = Ia x Ii x Ij const int SIZE_R = size_E[ IR ]; const int Ikw = Irreps::directProd( IL, IR ); // Ikw == Ik == Iw const int nocc_kw = indices->getNOCC( Ikw ); const int nact_kw = indices->getNDMRG( Ikw ); int total_size = SIZE_L * SIZE_R; if ( total_size * nocc_kw * nact_kw > 0 ){ for ( int k = 0; k < nocc_kw; k++ ){ for ( int cnt = 0; cnt < total_size; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_kw; w++ ){ double f_kw = fock->get( Ikw, k, nocc_kw + w ); int inc1 = 1; daxpy_( &total_size, &f_kw, FDE_singlet[ IL ][ IR ][ w ], &inc1, workspace, &inc1 ); } for ( int Iab = 0; Iab < num_irreps; Iab++ ){ const int nvir_ab = indices->getNVIRT( Iab ); const int Il = Irreps::directProd( Iab, IL ); const int nocc_l = indices->getNOCC( Il ); if ( nvir_ab * nocc_l > 0 ){ const int jump_D = jump[ IL + num_irreps * CHEMPS2_CASPT2_D ] + SIZE_L * shift_D_nonactive( indices, Il, Iab ); const int jump_E = jump[ IR + num_irreps * CHEMPS2_CASPT2_E_SINGLET ] + SIZE_R * (( Ikw <= Il ) ? shift_E_nonactive( indices, Iab, Ikw, Il, +1 ) : shift_E_nonactive( indices, Iab, Il, Ikw, +1 )); if ( Ikw == Il ){ // irrep_k == irrep_l #pragma omp parallel for schedule(static) for ( int l = 0; l < nocc_l; l++ ){ const double factor = (( k == l ) ? SQRT2 : 1.0 ); const int ptr_L = jump_D + SIZE_L * l; const int ptr_R = jump_E + SIZE_R * nvir_ab * (( k < l ) ? ( k + ( l * ( l + 1 ) ) / 2 ) : ( l + ( k * ( k + 1 ) ) / 2 )); const int LDA_L = SIZE_L * nocc_l; matmat( 'N', SIZE_L, nvir_ab, SIZE_R, factor, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, LDA_L ); matmat( 'T', SIZE_R, nvir_ab, SIZE_L, factor, workspace, SIZE_L, vector + ptr_L, LDA_L, result + ptr_R, SIZE_R ); } } else { // irrep_k != irrep_l #pragma omp parallel for schedule(static) for ( int l = 0; l < nocc_l; l++ ){ const int ptr_L = jump_D + SIZE_L * l; const int ptr_R = jump_E + SIZE_R * nvir_ab * (( Ikw < Il ) ? ( k + nocc_kw * l ) : ( l + nocc_l * k )); const int LDA_L = SIZE_L * nocc_l; matmat( 'N', SIZE_L, nvir_ab, SIZE_R, 1.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, LDA_L ); matmat( 'T', SIZE_R, nvir_ab, SIZE_L, 1.0, workspace, SIZE_L, vector + ptr_L, LDA_L, result + ptr_R, SIZE_R ); } } } } } } } } // FDE triplet: < D(blxy) E_kw TE_tiaj > = 3 delta_ab ( delta_ik delta_jl - delta_il delta_jk ) / sqrt( 1 + delta_ij ) FDE_triplet[ Ib x Il ][ It ][ w ][ xy, t ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Ix x Iy == Ib x Il const int SIZE_L = size_D[ IL ]; for ( int IR = 0; IR < num_irreps; IR++ ){ // IR = It = Ia x Ii x Ij const int SIZE_R = size_E[ IR ]; const int Ikw = Irreps::directProd( IL, IR ); // Ikw == Ik == Iw const int nocc_kw = indices->getNOCC( Ikw ); const int nact_kw = indices->getNDMRG( Ikw ); int total_size = SIZE_L * SIZE_R; if ( total_size * nocc_kw * nact_kw > 0 ){ for ( int k = 0; k < nocc_kw; k++ ){ for ( int cnt = 0; cnt < total_size; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_kw; w++ ){ double f_kw = fock->get( Ikw, k, nocc_kw + w ); int inc1 = 1; daxpy_( &total_size, &f_kw, FDE_triplet[ IL ][ IR ][ w ], &inc1, workspace, &inc1 ); } for ( int Iab = 0; Iab < num_irreps; Iab++ ){ const int nvir_ab = indices->getNVIRT( Iab ); const int Il = Irreps::directProd( Iab, IL ); const int nocc_l = indices->getNOCC( Il ); if ( nvir_ab * nocc_l > 0 ){ const int jump_D = jump[ IL + num_irreps * CHEMPS2_CASPT2_D ] + SIZE_L * shift_D_nonactive( indices, Il, Iab ); const int jump_E = jump[ IR + num_irreps * CHEMPS2_CASPT2_E_TRIPLET ] + SIZE_R * (( Ikw <= Il ) ? shift_E_nonactive( indices, Iab, Ikw, Il, -1 ) : shift_E_nonactive( indices, Iab, Il, Ikw, -1 )); if ( Ikw == Il ){ // irrep_k == irrep_l #pragma omp parallel for schedule(static) for ( int l = 0; l < k; l++ ){ const int ptr_L = jump_D + SIZE_L * l; const int ptr_R = jump_E + SIZE_R * nvir_ab * ( l + ( k * ( k - 1 ) ) / 2 ); const int LDA_L = SIZE_L * nocc_l; matmat( 'N', SIZE_L, nvir_ab, SIZE_R, -3.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, LDA_L ); matmat( 'T', SIZE_R, nvir_ab, SIZE_L, -3.0, workspace, SIZE_L, vector + ptr_L, LDA_L, result + ptr_R, SIZE_R ); } #pragma omp parallel for schedule(static) for ( int l = k+1; l < nocc_l; l++ ){ const int ptr_L = jump_D + SIZE_L * l; const int ptr_R = jump_E + SIZE_R * nvir_ab * ( k + ( l * ( l - 1 ) ) / 2 ); const int LDA_L = SIZE_L * nocc_l; matmat( 'N', SIZE_L, nvir_ab, SIZE_R, 3.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, LDA_L ); matmat( 'T', SIZE_R, nvir_ab, SIZE_L, 3.0, workspace, SIZE_L, vector + ptr_L, LDA_L, result + ptr_R, SIZE_R ); } } else { // irrep_k != irrep_l #pragma omp parallel for schedule(static) for ( int l = 0; l < nocc_l; l++ ){ const double factor = (( Ikw < Il ) ? 3.0 : -3.0 ); const int ptr_L = jump_D + SIZE_L * l; const int ptr_R = jump_E + SIZE_R * nvir_ab * (( Ikw < Il ) ? ( k + nocc_kw * l ) : ( l + nocc_l * k )); const int LDA_L = SIZE_L * nocc_l; matmat( 'N', SIZE_L, nvir_ab, SIZE_R, factor, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, LDA_L ); matmat( 'T', SIZE_R, nvir_ab, SIZE_L, factor, workspace, SIZE_L, vector + ptr_L, LDA_L, result + ptr_R, SIZE_R ); } } } } } } } } // FDG singlet: < D(djxy) E_wc SG_aibt > = 1 delta_ij ( delta_ac delta_bd + delta_ad delta_bc ) / sqrt( 1 + delta_ab ) FDG_singlet[ Ij x Id ][ It ][ w ][ xy, t ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Ix x Iy == Id x Ij const int SIZE_L = size_D[ IL ]; for ( int IR = 0; IR < num_irreps; IR++ ){ // IR = It = Ia x Ib x Ii const int SIZE_R = size_E[ IR ]; const int Iwc = Irreps::directProd( IL, IR ); // Iwc == Ic == Iw const int nocc_wc = indices->getNOCC( Iwc ); const int nact_wc = indices->getNDMRG( Iwc ); const int n_oa_wc = nocc_wc + nact_wc; const int nvir_wc = indices->getNVIRT( Iwc ); int total_size = SIZE_L * SIZE_R; if ( total_size * nvir_wc * nact_wc > 0 ){ for ( int c = 0; c < nvir_wc; c++ ){ for ( int cnt = 0; cnt < total_size; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_wc; w++ ){ double f_wc = fock->get( Iwc, nocc_wc + w, n_oa_wc + c ); int inc1 = 1; daxpy_( &total_size, &f_wc, FDG_singlet[ IL ][ IR ][ w ], &inc1, workspace, &inc1 ); } for ( int Iij = 0; Iij < num_irreps; Iij++ ){ const int nocc_ij = indices->getNOCC( Iij ); const int Id = Irreps::directProd( Iij, IL ); const int nvir_d = indices->getNVIRT( Id ); if ( nvir_d * nocc_ij > 0 ){ const int jump_D = jump[ IL + num_irreps * CHEMPS2_CASPT2_D ] + SIZE_L * shift_D_nonactive( indices, Iij, Id ); const int jump_G = jump[ IR + num_irreps * CHEMPS2_CASPT2_G_SINGLET ] + SIZE_R * (( Iwc <= Id ) ? shift_G_nonactive( indices, Iij, Iwc, Id, +1 ) : shift_G_nonactive( indices, Iij, Id, Iwc, +1 )); if ( Iwc == Id ){ // irrep_c == irrep_d if ( c > 0 ){ const int ptr_L = jump_D; const int ptr_R = jump_G + SIZE_R * nocc_ij * ( c * ( c + 1 ) ) / 2; matmat( 'N', SIZE_L, c * nocc_ij, SIZE_R, 1.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, c * nocc_ij, SIZE_L, 1.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } #pragma omp parallel for schedule(static) for ( int d = c; d < nvir_d; d++ ){ const double factor = (( c == d ) ? SQRT2 : 1.0 ); const int ptr_L = jump_D + SIZE_L * nocc_ij * d; const int ptr_R = jump_G + SIZE_R * nocc_ij * ( c + ( d * ( d + 1 ) ) / 2 ); matmat( 'N', SIZE_L, nocc_ij, SIZE_R, factor, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, nocc_ij, SIZE_L, factor, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } } else { // irrep_c != irrep_d if ( Iwc < Id ){ #pragma omp parallel for schedule(static) for ( int d = 0; d < nvir_d; d++ ){ const int ptr_L = jump_D + SIZE_L * nocc_ij * d; const int ptr_R = jump_G + SIZE_R * nocc_ij * ( c + nvir_wc * d ); matmat( 'N', SIZE_L, nocc_ij, SIZE_R, 1.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, nocc_ij, SIZE_L, 1.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } } else { const int ptr_L = jump_D; const int ptr_R = jump_G + SIZE_R * nocc_ij * nvir_d * c; matmat( 'N', SIZE_L, nvir_d * nocc_ij, SIZE_R, 1.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, nvir_d * nocc_ij, SIZE_L, 1.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } } } } } } } } // FDG triplet: < D(djxy) E_wc TG_aibt > = 3 delta_ij ( delta_ac delta_bd - delta_ad delta_bc ) / sqrt( 1 + delta_ab ) FDG_triplet[ Ij x Id ][ It ][ w ][ xy, t ] for ( int IL = 0; IL < num_irreps; IL++ ){ // IL == Ix x Iy == Id x Ij const int SIZE_L = size_D[ IL ]; for ( int IR = 0; IR < num_irreps; IR++ ){ // IR = It = Ia x Ib x Ii const int SIZE_R = size_E[ IR ]; const int Iwc = Irreps::directProd( IL, IR ); // Iwc == Ic == Iw const int nocc_wc = indices->getNOCC( Iwc ); const int nact_wc = indices->getNDMRG( Iwc ); const int n_oa_wc = nocc_wc + nact_wc; const int nvir_wc = indices->getNVIRT( Iwc ); int total_size = SIZE_L * SIZE_R; if ( total_size * nvir_wc * nact_wc > 0 ){ for ( int c = 0; c < nvir_wc; c++ ){ for ( int cnt = 0; cnt < total_size; cnt++ ){ workspace[ cnt ] = 0.0; } for ( int w = 0; w < nact_wc; w++ ){ double f_wc = fock->get( Iwc, nocc_wc + w, n_oa_wc + c ); int inc1 = 1; daxpy_( &total_size, &f_wc, FDG_triplet[ IL ][ IR ][ w ], &inc1, workspace, &inc1 ); } for ( int Iij = 0; Iij < num_irreps; Iij++ ){ const int nocc_ij = indices->getNOCC( Iij ); const int Id = Irreps::directProd( Iij, IL ); const int nvir_d = indices->getNVIRT( Id ); if ( nvir_d * nocc_ij > 0 ){ const int jump_D = jump[ IL + num_irreps * CHEMPS2_CASPT2_D ] + SIZE_L * shift_D_nonactive( indices, Iij, Id ); const int jump_G = jump[ IR + num_irreps * CHEMPS2_CASPT2_G_TRIPLET ] + SIZE_R * (( Iwc <= Id ) ? shift_G_nonactive( indices, Iij, Iwc, Id, -1 ) : shift_G_nonactive( indices, Iij, Id, Iwc, -1 )); if ( Iwc == Id ){ // irrep_c == irrep_d if ( c > 0 ){ const int ptr_L = jump_D; const int ptr_R = jump_G + SIZE_R * nocc_ij * ( c * ( c - 1 ) ) / 2; matmat( 'N', SIZE_L, c * nocc_ij, SIZE_R, -3.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, c * nocc_ij, SIZE_L, -3.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } #pragma omp parallel for schedule(static) for ( int d = c+1; d < nvir_d; d++ ){ const int ptr_L = jump_D + SIZE_L * nocc_ij * d; const int ptr_R = jump_G + SIZE_R * nocc_ij * ( c + ( d * ( d - 1 ) ) / 2 ); matmat( 'N', SIZE_L, nocc_ij, SIZE_R, 3.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, nocc_ij, SIZE_L, 3.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } } else { // irrep_c != irrep_d if ( Iwc < Id ){ #pragma omp parallel for schedule(static) for ( int d = 0; d < nvir_d; d++ ){ const int ptr_L = jump_D + SIZE_L * nocc_ij * d; const int ptr_R = jump_G + SIZE_R * nocc_ij * ( c + nvir_wc * d ); matmat( 'N', SIZE_L, nocc_ij, SIZE_R, 3.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, nocc_ij, SIZE_L, 3.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } } else { const int ptr_L = jump_D; const int ptr_R = jump_G + SIZE_R * nocc_ij * nvir_d * c; matmat( 'N', SIZE_L, nvir_d * nocc_ij, SIZE_R, -3.0, workspace, SIZE_L, vector + ptr_R, SIZE_R, result + ptr_L, SIZE_L ); matmat( 'T', SIZE_R, nvir_d * nocc_ij, SIZE_L, -3.0, workspace, SIZE_L, vector + ptr_L, SIZE_L, result + ptr_R, SIZE_R ); } } } } } } } } delete [] workspace; } int CheMPS2::CASPT2::shift_H_nonactive( const DMRGSCFindices * idx, const int irrep_i, const int irrep_j, const int irrep_a, const int irrep_b, const int ST ){ assert( irrep_i <= irrep_j ); assert( irrep_a <= irrep_b ); const int irrep_prod = Irreps::directProd( irrep_i, irrep_j ); const int irrep_virt = Irreps::directProd( irrep_a, irrep_b ); assert( irrep_prod == irrep_virt ); const int n_irreps = idx->getNirreps(); int shift = 0; if ( irrep_prod == 0 ){ for ( int Iij = 0; Iij < n_irreps; Iij++ ){ for ( int Iab = 0; Iab < n_irreps; Iab++ ){ if (( irrep_i == Iij ) && ( irrep_j == Iij ) && ( irrep_a == Iab ) && ( irrep_b == Iab )){ Iij = n_irreps; Iab = n_irreps; } else { shift += ( idx->getNOCC( Iij ) * ( idx->getNOCC( Iij ) + ST ) * idx->getNVIRT( Iab ) * ( idx->getNVIRT( Iab ) + ST ) ) / 4; } } } } else { for ( int Ii = 0; Ii < n_irreps; Ii++ ){ const int Ij = Irreps::directProd( irrep_prod, Ii ); if ( Ii < Ij ){ for ( int Ia = 0; Ia < n_irreps; Ia++ ){ const int Ib = Irreps::directProd( irrep_prod, Ia ); if ( Ia < Ib ){ if (( irrep_i == Ii ) && ( irrep_j == Ij ) && ( irrep_a == Ia ) && ( irrep_b == Ib )){ Ii = n_irreps; Ia = n_irreps; } else { shift += idx->getNOCC( Ii ) * idx->getNOCC( Ij ) * idx->getNVIRT( Ia ) * idx->getNVIRT( Ib ); } } } } } } return shift; } int CheMPS2::CASPT2::shift_G_nonactive( const DMRGSCFindices * idx, const int irrep_i, const int irrep_a, const int irrep_b, const int ST ){ assert( irrep_a <= irrep_b ); const int irrep_virt = Irreps::directProd( irrep_a, irrep_b ); const int irrep_prod = Irreps::directProd( irrep_virt, irrep_i ); const int n_irreps = idx->getNirreps(); int shift = 0; for ( int Ii = 0; Ii < n_irreps; Ii++ ){ const int Ivirt = Irreps::directProd( Ii, irrep_prod ); if ( Ivirt == 0 ){ for ( int Iab = 0; Iab < n_irreps; Iab++ ){ if (( irrep_i == Ii ) && ( irrep_a == Iab ) && ( irrep_b == Iab )){ Ii = n_irreps; Iab = n_irreps; } else { shift += ( idx->getNOCC( Ii ) * idx->getNVIRT( Iab ) * ( idx->getNVIRT( Iab ) + ST ) ) / 2; } } } else { for ( int Ia = 0; Ia < n_irreps; Ia++ ){ const int Ib = Irreps::directProd( Ivirt, Ia ); if ( Ia < Ib ){ if (( irrep_i == Ii ) && ( irrep_a == Ia ) && ( irrep_b == Ib )){ Ii = n_irreps; Ia = n_irreps; } else { shift += idx->getNOCC( Ii ) * idx->getNVIRT( Ia ) * idx->getNVIRT( Ib ); } } } } } return shift; } int CheMPS2::CASPT2::shift_E_nonactive( const DMRGSCFindices * idx, const int irrep_a, const int irrep_i, const int irrep_j, const int ST ){ assert( irrep_i <= irrep_j ); const int irrep_occ = Irreps::directProd( irrep_i, irrep_j ); const int irrep_prod = Irreps::directProd( irrep_occ, irrep_a ); const int n_irreps = idx->getNirreps(); int shift = 0; for ( int Ia = 0; Ia < n_irreps; Ia++ ){ const int Iocc = Irreps::directProd( Ia, irrep_prod ); if ( Iocc == 0 ){ for ( int Iij = 0; Iij < n_irreps; Iij++ ){ if (( irrep_a == Ia ) && ( irrep_i == Iij ) && ( irrep_j == Iij )){ Ia = n_irreps; Iij = n_irreps; } else { shift += ( idx->getNVIRT( Ia ) * idx->getNOCC( Iij ) * ( idx->getNOCC( Iij ) + ST ) ) / 2; } } } else { for ( int Ii = 0; Ii < n_irreps; Ii++ ){ const int Ij = Irreps::directProd( Iocc, Ii ); if ( Ii < Ij ){ if (( irrep_a == Ia ) && ( irrep_i == Ii ) && ( irrep_j == Ij )){ Ia = n_irreps; Ii = n_irreps; } else { shift += idx->getNVIRT( Ia ) * idx->getNOCC( Ii ) * idx->getNOCC( Ij ); } } } } } return shift; } int CheMPS2::CASPT2::shift_F_nonactive( const DMRGSCFindices * idx, const int irrep_a, const int irrep_b, const int ST ){ assert( irrep_a <= irrep_b ); const int irr_prod = Irreps::directProd( irrep_a, irrep_b ); const int n_irreps = idx->getNirreps(); int shift = 0; if ( irr_prod == 0 ){ for ( int Iab = 0; Iab < n_irreps; Iab++ ){ if (( irrep_a == Iab ) && ( irrep_b == Iab )){ Iab = n_irreps; } else { shift += ( idx->getNVIRT( Iab ) * ( idx->getNVIRT( Iab ) + ST ) ) / 2; } } } else { for ( int Ia = 0; Ia < n_irreps; Ia++ ){ const int Ib = Irreps::directProd( Ia, irr_prod ); if ( Ia < Ib ){ if (( irrep_a == Ia ) && ( irrep_b == Ib )){ Ia = n_irreps; } else { shift += idx->getNVIRT( Ia ) * idx->getNVIRT( Ib ); } } } } return shift; } int CheMPS2::CASPT2::shift_B_nonactive( const DMRGSCFindices * idx, const int irrep_i, const int irrep_j, const int ST ){ assert( irrep_i <= irrep_j ); const int irr_prod = Irreps::directProd( irrep_i, irrep_j ); const int n_irreps = idx->getNirreps(); int shift = 0; if ( irr_prod == 0 ){ for ( int Iij = 0; Iij < n_irreps; Iij++ ){ if (( Iij == irrep_i ) && ( Iij == irrep_j )){ Iij = n_irreps; } else { shift += ( idx->getNOCC( Iij ) * ( idx->getNOCC( Iij ) + ST ) ) / 2; } } } else { for ( int Ii = 0; Ii < n_irreps; Ii++ ){ const int Ij = Irreps::directProd( irr_prod, Ii ); if ( Ii < Ij ){ if (( Ii == irrep_i ) && ( Ij == irrep_j )){ Ii = n_irreps; } else { shift += idx->getNOCC( Ii ) * idx->getNOCC( Ij ); } } } } return shift; } int CheMPS2::CASPT2::shift_D_nonactive( const DMRGSCFindices * idx, const int irrep_i, const int irrep_a ){ const int irrep_ia = Irreps::directProd( irrep_i, irrep_a ); const int n_irreps = idx->getNirreps(); int shift = 0; for ( int Ii = 0; Ii < n_irreps; Ii++ ){ const int Ia = Irreps::directProd( irrep_ia, Ii ); if (( Ii == irrep_i ) && ( Ia == irrep_a )){ Ii = n_irreps; } else { shift += idx->getNOCC( Ii ) * idx->getNVIRT( Ia ); } } return shift; } void CheMPS2::CASPT2::diagonal( double * result ) const{ #pragma omp parallel { // FAA: < E_zy E_jx | F | E_ti E_uv > = delta_ij * ( FAA[ Ii ][ xyztuv ] + ( 2 sum_k f_kk - f_ii ) SAA[ Ii ][ xyztuv ] ) for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int SIZE = size_A[ irrep ]; if ( SIZE > 0 ){ const int NOCC = indices->getNOCC( irrep ); #pragma omp for schedule(static) for ( int count = 0; count < NOCC; count++ ){ const double beta = - f_dot_1dm - fock->get( irrep, count, count ); double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_A ] + SIZE * count; #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = FAA[ irrep ][ elem ] + beta; } } } } // FCC: < E_zy E_xb | F | E_at E_uv > = delta_ab * ( FCC[ Ia ][ xyztuv ] + ( 2 sum_k f_kk + f_aa ) SCC[ Ia ][ xyztuv ] ) for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int SIZE = size_C[ irrep ]; if ( SIZE > 0 ){ const int NVIR = indices->getNVIRT( irrep ); const int N_OA = indices->getNOCC( irrep ) + indices->getNDMRG( irrep ); #pragma omp for schedule(static) for ( int count = 0; count < NVIR; count++ ){ const double beta = - f_dot_1dm + fock->get( irrep, N_OA + count, N_OA + count ); double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_C ] + SIZE * count; #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = FCC[ irrep ][ elem ] + beta; } } } } // FDD: < E_yx E_jb | F | E_ai E_tu > = delta_ab delta_ij ( FDD[ xytu] + ( 2 sum_k f_kk + f_aa - f_ii ) SDD[ xytu ] ) for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int SIZE = size_D[ irrep ]; if ( SIZE > 0 ){ int shift = 0; for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int irrep_a = Irreps::directProd( irrep_i, irrep ); const int NOCC_i = indices->getNOCC( irrep_i ); const int N_OA_a = indices->getNOCC( irrep_a ) + indices->getNDMRG( irrep_a ); const int SIZE_ia = NOCC_i * indices->getNVIRT( irrep_a ); #pragma omp for schedule(static) for ( int combined = 0; combined < SIZE_ia; combined++ ){ const int i = combined % NOCC_i; const int a = combined / NOCC_i; const double f_ii = fock->get( irrep_i, i, i ); const double f_aa = fock->get( irrep_a, N_OA_a + a, N_OA_a + a ); const double beta = - f_dot_1dm + f_aa - f_ii; double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_D ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = FDD[ irrep ][ elem ] + beta; } } shift += SIZE_ia; } } } int triangle_idx[] = { 0, 0 }; // FBB singlet: < SB_xkyl | F | SB_tiuj > = 2 delta_ik delta_jl ( FBB_singlet[ Iij ][ xytu ] + ( 2 sum_n f_nn - f_ii - f_jj ) * SBB_singlet[ Iij ][ xytu ] ) { const int SIZE = size_B_singlet[ 0 ]; if ( SIZE > 0 ){ int shift = 0; for ( int irrep_ij = 0; irrep_ij < num_irreps; irrep_ij++ ){ const int nocc_ij = indices->getNOCC( irrep_ij ); const int size_ij = ( nocc_ij * ( nocc_ij + 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined = 0; combined < size_ij; combined++ ){ Special::invert_triangle_two( combined, triangle_idx ); const int i = triangle_idx[ 0 ]; const int j = triangle_idx[ 1 ]; const double f_ii = fock->get( irrep_ij, i, i ); const double f_jj = fock->get( irrep_ij, j, j ); const double beta = - f_dot_1dm - f_ii - f_jj; double * target = result + jump[ num_irreps * CHEMPS2_CASPT2_B_SINGLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 2 * ( FBB_singlet[ 0 ][ elem ] + beta ); } } shift += size_ij; } } } for ( int irrep = 1; irrep < num_irreps; irrep++ ){ const int SIZE = size_B_singlet[ irrep ]; if ( SIZE > 0 ){ int shift = 0; for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int irrep_j = Irreps::directProd( irrep, irrep_i ); if ( irrep_i < irrep_j ){ const int nocc_i = indices->getNOCC( irrep_i ); const int size_ij = nocc_i * indices->getNOCC( irrep_j ); #pragma omp for schedule(static) for ( int combined = 0; combined < size_ij; combined++ ){ const int i = combined % nocc_i; const int j = combined / nocc_i; const double f_ii = fock->get( irrep_i, i, i ); const double f_jj = fock->get( irrep_j, j, j ); const double beta = - f_dot_1dm - f_ii - f_jj; double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_B_SINGLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 2 * ( FBB_singlet[ irrep ][ elem ] + beta ); } } shift += size_ij; } } } } // FBB triplet: < TB_xkyl | F | TB_tiuj > = 2 delta_ik delta_jl ( FBB_triplet[ Iij ][ xytu ] + ( 2 sum_n f_nn - f_ii - f_jj ) * SBB_triplet[ Iij ][ xytu ] ) { const int SIZE = size_B_triplet[ 0 ]; if ( SIZE > 0 ){ int shift = 0; for ( int irrep_ij = 0; irrep_ij < num_irreps; irrep_ij++ ){ const int nocc_ij = indices->getNOCC( irrep_ij ); const int size_ij = ( nocc_ij * ( nocc_ij - 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined = 0; combined < size_ij; combined++ ){ Special::invert_lower_triangle_two( combined, triangle_idx ); const int i = triangle_idx[ 0 ]; const int j = triangle_idx[ 1 ]; const double f_ii = fock->get( irrep_ij, i, i ); const double f_jj = fock->get( irrep_ij, j, j ); const double beta = - f_dot_1dm - f_ii - f_jj; double * target = result + jump[ num_irreps * CHEMPS2_CASPT2_B_TRIPLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 2 * ( FBB_triplet[ 0 ][ elem ] + beta ); } } shift += size_ij; } } } for ( int irrep = 1; irrep < num_irreps; irrep++ ){ const int SIZE = size_B_triplet[ irrep ]; if ( SIZE > 0 ){ int shift = 0; for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int irrep_j = Irreps::directProd( irrep, irrep_i ); if ( irrep_i < irrep_j ){ const int nocc_i = indices->getNOCC( irrep_i ); const int size_ij = nocc_i * indices->getNOCC( irrep_j ); #pragma omp for schedule(static) for ( int combined = 0; combined < size_ij; combined++ ){ const int i = combined % nocc_i; const int j = combined / nocc_i; const double f_ii = fock->get( irrep_i, i, i ); const double f_jj = fock->get( irrep_j, j, j ); const double beta = - f_dot_1dm - f_ii - f_jj; double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_B_TRIPLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 2 * ( FBB_triplet[ irrep ][ elem ] + beta ); } } shift += size_ij; } } } } // FFF singlet: < SF_cxdy | F | SF_atbu > = 2 delta_ac delta_bd ( FFF_singlet[ Iab ][ xytu ] + ( 2 sum_n f_nn + f_aa + f_bb ) * SFF_singlet[ Iab ][ xytu ] ) { const int SIZE = size_F_singlet[ 0 ]; if ( SIZE > 0 ){ int shift = 0; for ( int irrep_ab = 0; irrep_ab < num_irreps; irrep_ab++ ){ const int NVIR_ab = indices->getNVIRT( irrep_ab ); const int N_OA_ab = indices->getNOCC( irrep_ab ) + indices->getNDMRG( irrep_ab ); const int SIZE_ab = ( NVIR_ab * ( NVIR_ab + 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined = 0; combined < SIZE_ab; combined++ ){ Special::invert_triangle_two( combined, triangle_idx ); const int a = triangle_idx[ 0 ]; const int b = triangle_idx[ 1 ]; const double f_aa = fock->get( irrep_ab, N_OA_ab + a, N_OA_ab + a ); const double f_bb = fock->get( irrep_ab, N_OA_ab + b, N_OA_ab + b ); const double beta = - f_dot_1dm + f_aa + f_bb; double * target = result + jump[ num_irreps * CHEMPS2_CASPT2_F_SINGLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 2 * ( FFF_singlet[ 0 ][ elem ] + beta ); } } shift += SIZE_ab; } } } for ( int irrep = 1; irrep < num_irreps; irrep++ ){ const int SIZE = size_F_singlet[ irrep ]; if ( SIZE > 0 ){ int shift = 0; for ( int irrep_a = 0; irrep_a < num_irreps; irrep_a++ ){ const int irrep_b = Irreps::directProd( irrep, irrep_a ); if ( irrep_a < irrep_b ){ const int NVIR_a = indices->getNVIRT( irrep_a ); const int SIZE_ab = NVIR_a * indices->getNVIRT( irrep_b ); const int N_OA_a = indices->getNOCC( irrep_a ) + indices->getNDMRG( irrep_a ); const int N_OA_b = indices->getNOCC( irrep_b ) + indices->getNDMRG( irrep_b ); #pragma omp for schedule(static) for ( int combined = 0; combined < SIZE_ab; combined++ ){ const int a = combined % NVIR_a; const int b = combined / NVIR_a; const double f_aa = fock->get( irrep_a, N_OA_a + a, N_OA_a + a ); const double f_bb = fock->get( irrep_b, N_OA_b + b, N_OA_b + b ); const double beta = - f_dot_1dm + f_aa + f_bb; double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_F_SINGLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 2 * ( FFF_singlet[ irrep ][ elem ] + beta ); } } shift += SIZE_ab; } } } } // FFF triplet: < TF_cxdy | F | TF_atbu > = 2 delta_ac delta_bd ( FFF_triplet[ Iab ][ xytu ] + ( 2 sum_n f_nn + f_aa + f_bb ) * SFF_triplet[ Iab ][ xytu ] ) { const int SIZE = size_F_triplet[ 0 ]; if ( SIZE > 0 ){ int shift = 0; for ( int irrep_ab = 0; irrep_ab < num_irreps; irrep_ab++ ){ const int NVIR_ab = indices->getNVIRT( irrep_ab ); const int N_OA_ab = indices->getNOCC( irrep_ab ) + indices->getNDMRG( irrep_ab ); const int SIZE_ab = ( NVIR_ab * ( NVIR_ab - 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined = 0; combined < SIZE_ab; combined++ ){ Special::invert_lower_triangle_two( combined, triangle_idx ); const int a = triangle_idx[ 0 ]; const int b = triangle_idx[ 1 ]; const double f_aa = fock->get( irrep_ab, N_OA_ab + a, N_OA_ab + a ); const double f_bb = fock->get( irrep_ab, N_OA_ab + b, N_OA_ab + b ); const double beta = - f_dot_1dm + f_aa + f_bb; double * target = result + jump[ num_irreps * CHEMPS2_CASPT2_F_TRIPLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 2 * ( FFF_triplet[ 0 ][ elem ] + beta ); } } shift += SIZE_ab; } } } for ( int irrep = 1; irrep < num_irreps; irrep++ ){ const int SIZE = size_F_triplet[ irrep ]; if ( SIZE > 0 ){ int shift = 0; for ( int irrep_a = 0; irrep_a < num_irreps; irrep_a++ ){ const int irrep_b = Irreps::directProd( irrep, irrep_a ); if ( irrep_a < irrep_b ){ const int NVIR_a = indices->getNVIRT( irrep_a ); const int SIZE_ab = NVIR_a * indices->getNVIRT( irrep_b ); const int N_OA_a = indices->getNOCC( irrep_a ) + indices->getNDMRG( irrep_a ); const int N_OA_b = indices->getNOCC( irrep_b ) + indices->getNDMRG( irrep_b ); #pragma omp for schedule(static) for ( int combined = 0; combined < SIZE_ab; combined++ ){ const int a = combined % NVIR_a; const int b = combined / NVIR_a; const double f_aa = fock->get( irrep_a, N_OA_a + a, N_OA_a + a ); const double f_bb = fock->get( irrep_b, N_OA_b + b, N_OA_b + b ); const double beta = - f_dot_1dm + f_aa + f_bb; double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_F_TRIPLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 2 * ( FFF_triplet[ irrep ][ elem ] + beta ); } } shift += SIZE_ab; } } } } // FEE singlet: < SE_ukbl | F | SE_tiaj > = 2 delta_ab delta_ik delta_jl ( FEE[ It ][ ut ] + ( 2 sum_k f_kk + f_aa - f_ii - f_jj ) SEE[ It ][ ut ] ) for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int SIZE = size_E[ irrep ]; if ( SIZE > 0 ){ int shift = 0; for ( int irrep_a = 0; irrep_a < num_irreps; irrep_a++ ){ const int NVIR_a = indices->getNVIRT( irrep_a ); const int N_OA_a = indices->getNOCC( irrep_a ) + indices->getNDMRG( irrep_a ); const int irrep_occ = Irreps::directProd( irrep_a, irrep ); for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int NOCC_i = indices->getNOCC( irrep_i ); const int irrep_j = Irreps::directProd( irrep_occ, irrep_i ); if ( irrep_i == irrep_j ){ const int SIZE_aij = ( NVIR_a * NOCC_i * ( NOCC_i + 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined = 0; combined < SIZE_aij; combined++ ){ const int a = combined % NVIR_a; Special::invert_triangle_two( combined / NVIR_a, triangle_idx ); const int i = triangle_idx[ 0 ]; const int j = triangle_idx[ 1 ]; const double f_ii = fock->get( irrep_i, i, i ); const double f_jj = fock->get( irrep_j, j, j ); const double f_aa = fock->get( irrep_a, N_OA_a + a, N_OA_a + a ); const double beta = - f_dot_1dm + f_aa - f_ii - f_jj; double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_E_SINGLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 2 * ( FEE[ irrep ][ elem ] + beta ); } } shift += SIZE_aij; } if ( irrep_i < irrep_j ){ const int SIZE_aij = NVIR_a * NOCC_i * indices->getNOCC( irrep_j ); #pragma omp for schedule(static) for ( int combined = 0; combined < SIZE_aij; combined++ ){ const int a = combined % NVIR_a; const int temp = combined / NVIR_a; const int i = temp % NOCC_i; const int j = temp / NOCC_i; const double f_ii = fock->get( irrep_i, i, i ); const double f_jj = fock->get( irrep_j, j, j ); const double f_aa = fock->get( irrep_a, N_OA_a + a, N_OA_a + a ); const double beta = - f_dot_1dm + f_aa - f_ii - f_jj; double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_E_SINGLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 2 * ( FEE[ irrep ][ elem ] + beta ); } } shift += SIZE_aij; } } } } } // FEE triplet: < TE_ukbl | F | TE_tiaj > = 6 delta_ab delta_ik delta_jl ( FEE[ It ][ ut ] + ( 2 sum_k f_kk + f_aa - f_ii - f_jj ) SEE[ It ][ ut ] ) for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int SIZE = size_E[ irrep ]; if ( SIZE > 0 ){ int shift = 0; for ( int irrep_a = 0; irrep_a < num_irreps; irrep_a++ ){ const int NVIR_a = indices->getNVIRT( irrep_a ); const int N_OA_a = indices->getNOCC( irrep_a ) + indices->getNDMRG( irrep_a ); const int irrep_occ = Irreps::directProd( irrep_a, irrep ); for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int NOCC_i = indices->getNOCC( irrep_i ); const int irrep_j = Irreps::directProd( irrep_occ, irrep_i ); if ( irrep_i == irrep_j ){ const int SIZE_aij = ( NVIR_a * NOCC_i * ( NOCC_i - 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined = 0; combined < SIZE_aij; combined++ ){ const int a = combined % NVIR_a; Special::invert_lower_triangle_two( combined / NVIR_a, triangle_idx ); const int i = triangle_idx[ 0 ]; const int j = triangle_idx[ 1 ]; const double f_ii = fock->get( irrep_i, i, i ); const double f_jj = fock->get( irrep_j, j, j ); const double f_aa = fock->get( irrep_a, N_OA_a + a, N_OA_a + a ); const double beta = - f_dot_1dm + f_aa - f_ii - f_jj; double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_E_TRIPLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 6 * ( FEE[ irrep ][ elem ] + beta ); } } shift += SIZE_aij; } if ( irrep_i < irrep_j ){ const int SIZE_aij = NVIR_a * NOCC_i * indices->getNOCC( irrep_j ); #pragma omp for schedule(static) for ( int combined = 0; combined < SIZE_aij; combined++ ){ const int a = combined % NVIR_a; const int temp = combined / NVIR_a; const int i = temp % NOCC_i; const int j = temp / NOCC_i; const double f_ii = fock->get( irrep_i, i, i ); const double f_jj = fock->get( irrep_j, j, j ); const double f_aa = fock->get( irrep_a, N_OA_a + a, N_OA_a + a ); const double beta = - f_dot_1dm + f_aa - f_ii - f_jj; double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_E_TRIPLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 6 * ( FEE[ irrep ][ elem ] + beta ); } } shift += SIZE_aij; } } } } } // FGG singlet: < SG_cjdu | F | SG_aibt > = 2 delta_ij delta_ac delta_bd ( FGG[ It ][ ut ] + ( 2 sum_k f_kk + f_aa + f_bb - f_ii ) SGG[ It ][ ut ] ) for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int SIZE = size_G[ irrep ]; if ( SIZE > 0 ){ int shift = 0; for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int NOCC_i = indices->getNOCC( irrep_i ); const int irrep_vir = Irreps::directProd( irrep_i, irrep ); for ( int irrep_a = 0; irrep_a < num_irreps; irrep_a++ ){ const int NVIR_a = indices->getNVIRT( irrep_a ); const int N_OA_a = indices->getNOCC( irrep_a ) + indices->getNDMRG( irrep_a ); const int irrep_b = Irreps::directProd( irrep_vir, irrep_a ); if ( irrep_a == irrep_b ){ const int SIZE_iab = ( NOCC_i * NVIR_a * ( NVIR_a + 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined = 0; combined < SIZE_iab; combined++ ){ const int i = combined % NOCC_i; Special::invert_triangle_two( combined / NOCC_i, triangle_idx ); const int a = triangle_idx[ 0 ]; const int b = triangle_idx[ 1 ]; const double f_ii = fock->get( irrep_i, i, i ); const double f_aa = fock->get( irrep_a, N_OA_a + a, N_OA_a + a ); const double f_bb = fock->get( irrep_b, N_OA_a + b, N_OA_a + b ); const double beta = - f_dot_1dm + f_aa + f_bb - f_ii; double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_G_SINGLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 2 * ( FGG[ irrep ][ elem ] + beta ); } } shift += SIZE_iab; } if ( irrep_a < irrep_b ){ const int SIZE_iab = NOCC_i * NVIR_a * indices->getNVIRT( irrep_b ); const int N_OA_b = indices->getNOCC( irrep_b ) + indices->getNDMRG( irrep_b ); #pragma omp for schedule(static) for ( int combined = 0; combined < SIZE_iab; combined++ ){ const int i = combined % NOCC_i; const int temp = combined / NOCC_i; const int a = temp % NVIR_a; const int b = temp / NVIR_a; const double f_ii = fock->get( irrep_i, i, i ); const double f_aa = fock->get( irrep_a, N_OA_a + a, N_OA_a + a ); const double f_bb = fock->get( irrep_b, N_OA_b + b, N_OA_b + b ); const double beta = - f_dot_1dm + f_aa + f_bb - f_ii; double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_G_SINGLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 2 * ( FGG[ irrep ][ elem ] + beta ); } } shift += SIZE_iab; } } } } } // FGG triplet: < TG_cjdu | F | TG_aibt > = 6 delta_ij delta_ac delta_bd ( FGG[ It ][ ut ] + ( 2 sum_k f_kk + f_aa + f_bb - f_ii ) SGG[ It ][ ut ] ) for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int SIZE = size_G[ irrep ]; if ( SIZE > 0 ){ int shift = 0; for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int NOCC_i = indices->getNOCC( irrep_i ); const int irrep_vir = Irreps::directProd( irrep_i, irrep ); for ( int irrep_a = 0; irrep_a < num_irreps; irrep_a++ ){ const int NVIR_a = indices->getNVIRT( irrep_a ); const int N_OA_a = indices->getNOCC( irrep_a ) + indices->getNDMRG( irrep_a ); const int irrep_b = Irreps::directProd( irrep_vir, irrep_a ); if ( irrep_a == irrep_b ){ const int SIZE_iab = ( NOCC_i * NVIR_a * ( NVIR_a - 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined = 0; combined < SIZE_iab; combined++ ){ const int i = combined % NOCC_i; Special::invert_lower_triangle_two( combined / NOCC_i, triangle_idx ); const int a = triangle_idx[ 0 ]; const int b = triangle_idx[ 1 ]; const double f_ii = fock->get( irrep_i, i, i ); const double f_aa = fock->get( irrep_a, N_OA_a + a, N_OA_a + a ); const double f_bb = fock->get( irrep_b, N_OA_a + b, N_OA_a + b ); const double beta = - f_dot_1dm + f_aa + f_bb - f_ii; double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_G_TRIPLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 6 * ( FGG[ irrep ][ elem ] + beta ); } } shift += SIZE_iab; } if ( irrep_a < irrep_b ){ const int SIZE_iab = NOCC_i * NVIR_a * indices->getNVIRT( irrep_b ); const int N_OA_b = indices->getNOCC( irrep_b ) + indices->getNDMRG( irrep_b ); #pragma omp for schedule(static) for ( int combined = 0; combined < SIZE_iab; combined++ ){ const int i = combined % NOCC_i; const int temp = combined / NOCC_i; const int a = temp % NVIR_a; const int b = temp / NVIR_a; const double f_ii = fock->get( irrep_i, i, i ); const double f_aa = fock->get( irrep_a, N_OA_a + a, N_OA_a + a ); const double f_bb = fock->get( irrep_b, N_OA_b + b, N_OA_b + b ); const double beta = - f_dot_1dm + f_aa + f_bb - f_ii; double * target = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_G_TRIPLET ] + SIZE * ( shift + combined ); #pragma omp simd for ( int elem = 0; elem < SIZE; elem++ ){ target[ elem ] = 6 * ( FGG[ irrep ][ elem ] + beta ); } } shift += SIZE_iab; } } } } } // FHH singlet and triplet { int shift = 0; for ( int irrep_ij = 0; irrep_ij < num_irreps; irrep_ij++ ){ const int NOCC_ij = indices->getNOCC( irrep_ij ); const int size_ij = ( NOCC_ij * ( NOCC_ij + 1 ) ) / 2; for ( int irrep_ab = 0; irrep_ab < num_irreps; irrep_ab++ ){ const int NVIR_ab = indices->getNVIRT( irrep_ab ); const int N_OA_ab = indices->getNOCC( irrep_ab ) + indices->getNDMRG( irrep_ab ); double * target = result + jump[ num_irreps * CHEMPS2_CASPT2_H_SINGLET ] + shift; const int size_ijab = ( size_ij * NVIR_ab * ( NVIR_ab + 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined = 0; combined < size_ijab; combined++ ){ Special::invert_triangle_two( combined % size_ij, triangle_idx ); const int i = triangle_idx[ 0 ]; const int j = triangle_idx[ 1 ]; Special::invert_triangle_two( combined / size_ij, triangle_idx ); const int a = triangle_idx[ 0 ]; const int b = triangle_idx[ 1 ]; const double f_ii = fock->get( irrep_ij, i, i ); const double f_jj = fock->get( irrep_ij, j, j ); const double f_aa = fock->get( irrep_ab, N_OA_ab + a, N_OA_ab + a ); const double f_bb = fock->get( irrep_ab, N_OA_ab + b, N_OA_ab + b ); const double term = f_aa + f_bb - f_ii - f_jj; target[ combined ] = 4 * term; } shift += size_ijab; } } } { int shift = 0; for ( int irrep_ij = 0; irrep_ij < num_irreps; irrep_ij++ ){ const int NOCC_ij = indices->getNOCC( irrep_ij ); const int size_ij = ( NOCC_ij * ( NOCC_ij - 1 ) ) / 2; for ( int irrep_ab = 0; irrep_ab < num_irreps; irrep_ab++ ){ const int NVIR_ab = indices->getNVIRT( irrep_ab ); const int N_OA_ab = indices->getNOCC( irrep_ab ) + indices->getNDMRG( irrep_ab ); double * target = result + jump[ num_irreps * CHEMPS2_CASPT2_H_TRIPLET ] + shift; const int size_ijab = ( size_ij * NVIR_ab * ( NVIR_ab - 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined = 0; combined < size_ijab; combined++ ){ Special::invert_lower_triangle_two( combined % size_ij, triangle_idx ); const int i = triangle_idx[ 0 ]; const int j = triangle_idx[ 1 ]; Special::invert_lower_triangle_two( combined / size_ij, triangle_idx ); const int a = triangle_idx[ 0 ]; const int b = triangle_idx[ 1 ]; const double f_ii = fock->get( irrep_ij, i, i ); const double f_jj = fock->get( irrep_ij, j, j ); const double f_aa = fock->get( irrep_ab, N_OA_ab + a, N_OA_ab + a ); const double f_bb = fock->get( irrep_ab, N_OA_ab + b, N_OA_ab + b ); const double term = f_aa + f_bb - f_ii - f_jj; target[ combined ] = 12 * term; } shift += size_ijab; } } } for ( int irrep = 1; irrep < num_irreps; irrep++ ){ int shift = 0; for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int irrep_j = Irreps::directProd( irrep, irrep_i ); if ( irrep_i < irrep_j ){ const int NOCC_i = indices->getNOCC( irrep_i ); const int NOCC_j = indices->getNOCC( irrep_j ); for ( int irrep_a = 0; irrep_a < num_irreps; irrep_a++ ){ const int irrep_b = Irreps::directProd( irrep, irrep_a ); if ( irrep_a < irrep_b ){ const int NVIR_a = indices->getNVIRT( irrep_a ); const int N_OA_a = indices->getNOCC( irrep_a ) + indices->getNDMRG( irrep_a ); const int N_OA_b = indices->getNOCC( irrep_b ) + indices->getNDMRG( irrep_b ); double * target_singlet = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_H_SINGLET ] + shift; double * target_triplet = result + jump[ irrep + num_irreps * CHEMPS2_CASPT2_H_TRIPLET ] + shift; const int size_ijab = NOCC_i * NOCC_j * NVIR_a * indices->getNVIRT( irrep_b ); #pragma omp for schedule(static) for ( int combined = 0; combined < size_ijab; combined++ ){ const int i = combined % NOCC_i; const int temp1 = combined / NOCC_i; const int j = temp1 % NOCC_j; const int temp2 = temp1 / NOCC_j; const int a = temp2 % NVIR_a; const int b = temp2 / NVIR_a; const double f_ii = fock->get( irrep_i, i, i ); const double f_jj = fock->get( irrep_j, j, j ); const double f_aa = fock->get( irrep_a, N_OA_a + a, N_OA_a + a ); const double f_bb = fock->get( irrep_b, N_OA_b + b, N_OA_b + b ); const double term = f_aa + f_bb - f_ii - f_jj; target_singlet[ combined ] = 4 * term; target_triplet[ combined ] = 12 * term; } shift += size_ijab; } } } } } } } void CheMPS2::CASPT2::construct_rhs( const DMRGSCFmatrix * oei, const DMRGSCFintegrals * integrals ){ /* VA: < H E_ti E_uv > = sum_w ( t_iw + sum_k [ 2 (iw|kk) - (ik|kw) ] ) [ 2 delta_tw Gamma_uv - Gamma_tuwv - delta_wu Gamma_tv ] + sum_xzy (ix|zy) SAA[ Ii ][ xyztuv ] VB: < H E_ti E_uj > < S_tiuj | H > = sum_xy (ix|jy) SBB_singlet[ It x Iu ][ xytu ] / sqrt( 1 + delta_ij ) = sum_{x<=y} [ (ix|jy) + (iy|jx) ] SBB_singlet[ It x Iu ][ xytu ] * (( x==y ) ? 0.5 : 1.0 ) / sqrt( 1 + delta_ij ) < T_tiuj | H > = sum_xy (ix|jy) SBB_triplet[ It x Iu ][ xytu ] = sum_{x = sum_w ( t_wa + sum_k [ 2 (wa|kk) - (wk|ka) ] - sum_y (wy|ya) ) < E_wt E_uv > + sum_wxy (xy|wa) < E_xy E_wt E_uv > < H E_at E_uv > = sum_w ( t_wa + sum_k [ 2 (wa|kk) - (wk|ka) ] - sum_y (wy|ya) ) [ Gamma_wutv + delta_ut Gamma_wv ] + sum_zxy (zy|xa) SCC[ Ia ][ xyztuv ] VD1: < H E_ai E_tu > = ( t_ia + sum_k [ 2 (ia|kk) - (ik|ka) ] ) [ 2 Gamma_tu ] + sum_xy [ (ia|yx) - 0.5 * (ix|ya) ] SD1D1[ It x Iu ][ xytu ] < H E_ai E_tu > = ( t_ia + sum_k [ 2 (ia|kk) - (ik|ka) ] ) [ 2 Gamma_tu ] + sum_xy (ia|yx) SD1D1[ It x Iu ][ xytu ] + sum_xy (ix|ya) SD2D1[ It x Iu ][ xytu ] VD2: < H E_ti E_au > = ( t_ia + sum_k [ 2 (ia|kk) - (ik|ka) ] ) [ - Gamma_tu ] + sum_xy (ia|xy) [ - Gamma_xtyu ] + sum_xy (iy|xa) [ - Gamma_txyu ] + sum_y [ 2 (it|ya) - (ia|yt) ] Gamma_yu < H E_ti E_au > = ( t_ia + sum_k [ 2 (ia|kk) - (ik|ka) ] ) [ - Gamma_tu ] + sum_xy (ia|yx) SD1D2[ It x Iu ][ xytu ] + sum_xy (ix|ya) SD2D2[ It x Iu ][ xytu ] VE: < H E_ti E_aj > < S_tiaj | H > = sum_w [ (aj|wi) + (ai|wj) ] * 1 * SEE[ It ][ wt ] / sqrt( 1 + delta_ij ) < T_tiaj | H > = sum_w [ (aj|wi) - (ai|wj) ] * 3 * SEE[ It ][ wt ] VF: < H E_at E_bu > < S_atbu | H > = sum_xy (ax|by) SFF_singlet[ It x Iu ][ xytu ] / sqrt( 1 + delta_ab ) = sum_{x<=y} [ (ax|by) + (ay|bx) ] SFF_singlet[ It x Iu ][ xytu ] * (( x==y ) ? 0.5 : 1.0 ) / sqrt( 1 + delta_ab ) < T_atbu | H > = sum_xy (ax|by) SFF_triplet[ It x Iu ][ xytu ] = sum_{x < S_aibt | H > = sum_w [ (ai|bw) + (bi|aw) ] * 1 * SGG[ It ][ wt ] / sqrt( 1 + delta_ab ) < T_aibt | H > = sum_w [ (ai|bw) - (bi|aw) ] * 3 * SGG[ It ][ wt ] VH: < H E_ai E_bj > < S_aibj | H > = 2 * [ (ai|bj) + (aj|bi) ] / sqrt( ( 1 + delta_ij ) * ( 1 + delta_ab ) ) < T_aibj | H > = 6 * [ (ai|bj) - (aj|bi) ] */ const int LAS = indices->getDMRGcumulative( num_irreps ); // First construct MAT[p,q] = ( t_pq + sum_k [ 2 (pq|kk) - (pk|kq) ] ) DMRGSCFmatrix * MAT = new DMRGSCFmatrix( indices ); for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int NORB = indices->getNORB( irrep ); for ( int row = 0; row < NORB; row++ ){ for ( int col = row; col < NORB; col++ ){ double value = oei->get( irrep, row, col ); for ( int irrep_occ = 0; irrep_occ < num_irreps; irrep_occ++ ){ const int NOCC = indices->getNOCC( irrep_occ ); for ( int occ = 0; occ < NOCC; occ++ ){ value += ( 2 * integrals->FourIndexAPI( irrep, irrep_occ, irrep, irrep_occ, row, occ, col, occ ) - integrals->FourIndexAPI( irrep, irrep_occ, irrep_occ, irrep, row, occ, occ, col ) ); // Physics notation at 4-index } } MAT->set( irrep, row, col, value ); MAT->set( irrep, col, row, value ); } } } // and MAT2[p,q] = sum_y (py|yq) DMRGSCFmatrix * MAT2 = new DMRGSCFmatrix( indices ); for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int NORB = indices->getNORB( irrep ); for ( int row = 0; row < NORB; row++ ){ for ( int col = row; col < NORB; col++ ){ double value = 0.0; for ( int irrep_act = 0; irrep_act < num_irreps; irrep_act++ ){ const int NOCC = indices->getNOCC( irrep_act ); const int NACT = indices->getNDMRG( irrep_act ); for ( int act = 0; act < NACT; act++ ){ value += integrals->FourIndexAPI( irrep, irrep_act, irrep_act, irrep, row, NOCC + act, NOCC + act, col ); // Physics notation at 4-index } } MAT2->set( irrep, row, col, value ); MAT2->set( irrep, col, row, value ); } } } vector_rhs = new double[ jump[ num_irreps * CHEMPS2_CASPT2_NUM_CASES ] ]; #pragma omp parallel { const int max_size = get_maxsize(); double * workspace = new double[ max_size ]; // VA for ( int irrep = 0; irrep < num_irreps; irrep++ ){ if ( size_A[ irrep ] > 0 ){ const int NOCC = indices->getNOCC( irrep ); const int NACT = indices->getNDMRG( irrep ); const int d_w = indices->getDMRGcumulative( irrep ); #pragma omp for schedule(static) for ( int count_i = 0; count_i < NOCC; count_i++ ){ double * target = vector_rhs + jump[ irrep + num_irreps * CHEMPS2_CASPT2_A ] + size_A[ irrep ] * count_i; // Fill workspace[ xyz ] with (ix|zy) // Fill target[ tuv ] with sum_w MAT[i,w] [ 2 delta_tw Gamma_uv - Gamma_tuwv - delta_wu Gamma_tv ] // = 2 MAT[i,t] Gamma_uv - MAT[i,u] Gamma_tv - sum_w MAT[i,w] Gamma_tuwv int jump_xyz = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int occ_x = indices->getNOCC( irrep_x ); const int num_x = indices->getNDMRG( irrep_x ); const int d_x = indices->getDMRGcumulative( irrep_x ); for ( int irrep_y = 0; irrep_y < num_irreps; irrep_y++ ){ const int irrep_z = Irreps::directProd( Irreps::directProd( irrep, irrep_x ), irrep_y ); const int occ_y = indices->getNOCC( irrep_y ); const int occ_z = indices->getNOCC( irrep_z ); const int num_y = indices->getNDMRG( irrep_y ); const int num_z = indices->getNDMRG( irrep_z ); const int d_y = indices->getDMRGcumulative( irrep_y ); const int d_z = indices->getDMRGcumulative( irrep_z ); // workspace[ xyz ] = (ix|zy) for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ const double ix_zy = integrals->get_coulomb( irrep, irrep_x, irrep_z, irrep_y, count_i, occ_x + x, occ_z + z, occ_y + y ); workspace[ jump_xyz + x + num_x * ( y + num_y * z ) ] = ix_zy; } } } // target[ tuv ] = - sum_w MAT[i,w] Gamma_tuwv for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ double value = 0.0; for ( int w = 0; w < NACT; w++ ){ value += MAT->get( irrep, count_i, NOCC + w ) * two_rdm[ d_x + x + LAS * ( d_y + y + LAS * ( d_w + w + LAS * ( d_z + z ) ) ) ]; } target[ jump_xyz + x + num_x * ( y + num_y * z ) ] = - value; } } } // target[ tuv ] += 2 MAT[i,t] Gamma_uv if ( irrep_x == irrep ){ for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ target[ jump_xyz + x + num_x * ( y + num_y * z ) ] += 2 * MAT->get( irrep, count_i, occ_x + x ) * one_rdm[ d_y + y + LAS * ( d_z + z ) ]; } } } } // target[ tuv ] -= MAT[i,u] Gamma_tv if ( irrep_y == irrep ){ for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ target[ jump_xyz + x + num_x * ( y + num_y * z ) ] -= MAT->get( irrep, count_i, occ_y + y ) * one_rdm[ d_x + x + LAS * ( d_z + z ) ]; } } } } jump_xyz += num_x * num_y * num_z; } } assert( jump_xyz == size_A[ irrep ] ); // Perform target[ tuv ] += sum_xzy (ix|zy) SAA[ It x Iu x Iv ][ xyztuv ] char notrans = 'N'; int inc1 = 1; double one = 1.0; dgemv_( ¬rans, &jump_xyz, &jump_xyz, &one, SAA[ irrep ], &jump_xyz, workspace, &inc1, &one, target, &inc1 ); } assert( NOCC * size_A[ irrep ] == jump[ 1 + irrep + num_irreps * CHEMPS2_CASPT2_A ] - jump[ irrep + num_irreps * CHEMPS2_CASPT2_A ] ); } } // VC for ( int irrep = 0; irrep < num_irreps; irrep++ ){ if ( size_C[ irrep ] > 0 ){ const int NOCC = indices->getNOCC( irrep ); const int NVIR = indices->getNVIRT( irrep ); const int NACT = indices->getNDMRG( irrep ); const int N_OA = NOCC + NACT; const int d_w = indices->getDMRGcumulative( irrep ); #pragma omp for schedule(static) for ( int count_a = 0; count_a < NVIR; count_a++ ){ double * target = vector_rhs + jump[ irrep + num_irreps * CHEMPS2_CASPT2_C ] + size_C[ irrep ] * count_a; // Fill workspace[ xyz ] with (zy|xa) // Fill target[ tuv ] with sum_w (MAT[w,a] - MAT2[w,a]) [ Gamma_wutv + delta_ut Gamma_wv ] int jump_xyz = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int occ_x = indices->getNOCC( irrep_x ); const int num_x = indices->getNDMRG( irrep_x ); const int d_x = indices->getDMRGcumulative( irrep_x ); for ( int irrep_y = 0; irrep_y < num_irreps; irrep_y++ ){ const int irrep_z = Irreps::directProd( Irreps::directProd( irrep, irrep_x ), irrep_y ); const int occ_y = indices->getNOCC( irrep_y ); const int occ_z = indices->getNOCC( irrep_z ); const int num_y = indices->getNDMRG( irrep_y ); const int num_z = indices->getNDMRG( irrep_z ); const int d_y = indices->getDMRGcumulative( irrep_y ); const int d_z = indices->getDMRGcumulative( irrep_z ); // workspace[ xyz ] = (zy|xa) for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ const double zy_xa = integrals->get_coulomb( irrep_z, irrep_y, irrep_x, irrep, occ_z + z, occ_y + y, occ_x + x, N_OA + count_a ); workspace[ jump_xyz + x + num_x * ( y + num_y * z ) ] = zy_xa; } } } // target[ tuv ] = sum_w ( MAT[w,a] - MAT2[w,a] ) Gamma_wutv for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ double value = 0.0; for ( int w = 0; w < NACT; w++ ){ value += ( ( MAT->get( irrep, NOCC + w, N_OA + count_a ) - MAT2->get( irrep, NOCC + w, N_OA + count_a ) ) * two_rdm[ d_w + w + LAS * ( d_y + y + LAS * ( d_x + x + LAS * ( d_z + z ) ) ) ] ); } target[ jump_xyz + x + num_x * ( y + num_y * z ) ] = value; } } } // target[ tuv ] += sum_w ( MAT[w,a] - MAT2[w,a] ) delta_ut Gamma_wv if (( irrep_z == irrep ) && ( irrep_x == irrep_y )){ for ( int z = 0; z < num_z; z++ ){ // v double value = 0.0; for ( int w = 0; w < NACT; w++ ){ value += ( ( MAT->get( irrep, NOCC + w, N_OA + count_a ) - MAT2->get( irrep, NOCC + w, N_OA + count_a ) ) * one_rdm[ d_w + w + LAS * ( d_z + z ) ] ); } for ( int xy = 0; xy < num_x; xy++ ){ // tu target[ jump_xyz + xy + num_x * ( xy + num_x * z ) ] += value; } } } jump_xyz += num_x * num_y * num_z; } } assert( jump_xyz == size_C[ irrep ] ); // Perform target[ tuv ] += sum_zxy (zy|xa) SCC[ It x Iu x Iv ][ xyztuv ] char notrans = 'N'; int inc1 = 1; double one = 1.0; dgemv_( ¬rans, &jump_xyz, &jump_xyz, &one, SCC[ irrep ], &jump_xyz, workspace, &inc1, &one, target, &inc1 ); } assert( NVIR * size_C[ irrep ] == jump[ 1 + irrep + num_irreps * CHEMPS2_CASPT2_C ] - jump[ irrep + num_irreps * CHEMPS2_CASPT2_C ] ); } } #pragma omp single { delete MAT2; } // VD1 and VD2 for ( int irrep = 0; irrep < num_irreps; irrep++ ){ if ( size_D[ irrep ] > 0 ){ int shift = 0; const int D2JUMP = size_D[ irrep ] / 2; for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int irrep_a = Irreps::directProd( irrep_i, irrep ); assert( shift == shift_D_nonactive( indices, irrep_i, irrep_a ) ); const int NOCC_i = indices->getNOCC( irrep_i ); const int N_OA_a = indices->getNOCC( irrep_a ) + indices->getNDMRG( irrep_a ); const int NVIR_a = indices->getNVIRT( irrep_a ); const int loopsize = NOCC_i * NVIR_a; #pragma omp for schedule(static) for ( int combined = 0; combined < loopsize; combined++ ){ const int count_i = combined % NOCC_i; const int count_a = combined / NOCC_i; double * target = vector_rhs + jump[ irrep + num_irreps * CHEMPS2_CASPT2_D ] + size_D[ irrep ] * ( shift + combined ); const double MAT_ia = ( ( irrep_i == irrep_a ) ? MAT->get( irrep_i, count_i, N_OA_a + count_a ) : 0.0 ); /* Fill workspace[ xy ] with (ia|yx) Fill workspace[ D2JUMP + xy ] with (ix|ya) then ( workspace * SDD )_D1 = sum_xy (ia|yx) SD1D1[ It x Iu ][ xytu ] + sum_xy (ix|ya) SD2D1[ It x Iu ][ xytu ] and ( workspace * SDD )_D2 = sum_xy (ia|yx) SD1D2[ It x Iu ][ xytu ] + sum_xy (ix|ya) SD2D2[ It x Iu ][ xytu ] Fill target[ tu ] = 2 MAT[i,a] Gamma_tu Fill target[ D2JUMP + tu ] = - MAT[i,a] Gamma_tu */ int jump_xy = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int irrep_y = Irreps::directProd( irrep, irrep_x ); const int occ_x = indices->getNOCC( irrep_x ); const int occ_y = indices->getNOCC( irrep_y ); const int num_x = indices->getNDMRG( irrep_x ); const int num_y = indices->getNDMRG( irrep_y ); // workspace[ xy ] = (ia|yx) for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ const double ia_yx = integrals->get_coulomb( irrep_y, irrep_x, irrep_i, irrep_a, occ_y + y, occ_x + x, count_i, N_OA_a + count_a ); workspace[ jump_xy + x + num_x * y ] = ia_yx; } } // workspace[ D2JUMP + xy ] = (ix|ya) for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ const double ix_ya = integrals->get_coulomb( irrep_i, irrep_x, irrep_y, irrep_a, count_i, occ_x + x, occ_y + y, N_OA_a + count_a ); workspace[ D2JUMP + jump_xy + x + num_x * y ] = ix_ya; } } // target[ tu ] = 2 MAT[i,a] Gamma_tu // target[ D2JUMP + tu ] = - MAT[i,a] Gamma_tu if ( irrep == 0 ){ const int d_xy = indices->getDMRGcumulative( irrep_x ); for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ const double value = MAT_ia * one_rdm[ d_xy + x + LAS * ( d_xy + y ) ]; target[ jump_xy + x + num_x * y ] = 2 * value; target[ D2JUMP + jump_xy + x + num_x * y ] = - value; } } } else { for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ target[ jump_xy + x + num_x * y ] = 0.0; target[ D2JUMP + jump_xy + x + num_x * y ] = 0.0; } } } jump_xy += num_x * num_y; } jump_xy = 2 * jump_xy; assert( jump_xy == size_D[ irrep ] ); // Perform target += workspace * SDD[ irrep ] char notrans = 'N'; int inc1 = 1; double one = 1.0; dgemv_( ¬rans, &jump_xy, &jump_xy, &one, SDD[ irrep ], &jump_xy, workspace, &inc1, &one, target, &inc1 ); } shift += loopsize; } assert( shift * size_D[ irrep ] == jump[ 1 + irrep + num_irreps * CHEMPS2_CASPT2_D ] - jump[ irrep + num_irreps * CHEMPS2_CASPT2_D ] ); } } #pragma omp single { delete MAT; } const double SQRT_0p5 = sqrt( 0.5 ); int triangle_idx[] = { 0, 0 }; // VB singlet and triplet if ( size_B_singlet[ 0 ] > 0 ){ // First do irrep == Ii x Ij == Ix x Iy == It x Iu == 0 int shift = 0; // First do SINGLET for ( int irrep_ij = 0; irrep_ij < num_irreps; irrep_ij++ ){ assert( shift == shift_B_nonactive( indices, irrep_ij, irrep_ij, +1 ) ); const int NOCC_ij = indices->getNOCC( irrep_ij ); const int loopsize = ( NOCC_ij * ( NOCC_ij + 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined = 0; combined < loopsize; combined++ ){ Special::invert_triangle_two( combined, triangle_idx ); const int i = triangle_idx[ 0 ]; const int j = triangle_idx[ 1 ]; assert( combined == i + ( j * ( j + 1 ) ) / 2 ); // Fill workspace[ xy ] with [ (ix|jy) + (iy|jx) ] * (( x==y ) ? 0.5 : 1.0 ) int jump_xy = 0; for ( int irrep_xy = 0; irrep_xy < num_irreps; irrep_xy++ ){ const int occ_xy = indices->getNOCC( irrep_xy ); const int num_xy = indices->getNDMRG( irrep_xy ); for ( int x = 0; x < num_xy; x++ ){ for ( int y = x; y < num_xy; y++ ){ // 0 <= x <= y < num_xy const double ix_jy = integrals->get_coulomb( irrep_ij, irrep_xy, irrep_ij, irrep_xy, i, occ_xy + x, j, occ_xy + y ); const double iy_jx = integrals->get_coulomb( irrep_ij, irrep_xy, irrep_ij, irrep_xy, i, occ_xy + y, j, occ_xy + x ); workspace[ jump_xy + x + (y*(y+1))/2 ] = ( ix_jy + iy_jx ) * (( x==y ) ? 0.5 : 1.0 ); } } jump_xy += ( num_xy * ( num_xy + 1 ) ) / 2; } assert( jump_xy == size_B_singlet[ 0 ] ); // Perform target[ tu ] = sum_{x<=y} [ (ix|jy) + (iy|jx) ] SBB_singlet[ It x Iu ][ xytu ] * (( x==y ) ? 0.5 : 1.0 ) / sqrt( 1 + delta_ij ) char notrans = 'N'; int inc1 = 1; double alpha = (( i == j ) ? SQRT_0p5 : 1.0 ); double set = 0.0; double * target = vector_rhs + jump[ num_irreps * CHEMPS2_CASPT2_B_SINGLET ] + size_B_singlet[ 0 ] * ( shift + combined ); dgemv_( ¬rans, &jump_xy, &jump_xy, &alpha, SBB_singlet[ 0 ], &jump_xy, workspace, &inc1, &set, target, &inc1 ); } shift += loopsize; } assert( shift * size_B_singlet[ 0 ] == jump[ 1 + num_irreps * CHEMPS2_CASPT2_B_SINGLET ] - jump[ num_irreps * CHEMPS2_CASPT2_B_SINGLET ] ); } if ( size_B_triplet[ 0 ] > 0 ){ // Then do TRIPLET int shift = 0; for ( int irrep_ij = 0; irrep_ij < num_irreps; irrep_ij++ ){ assert( shift == shift_B_nonactive( indices, irrep_ij, irrep_ij, -1 ) ); const int NOCC_ij = indices->getNOCC( irrep_ij ); const int loopsize = ( NOCC_ij * ( NOCC_ij - 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined = 0; combined < loopsize; combined++ ){ Special::invert_lower_triangle_two( combined, triangle_idx ); const int i = triangle_idx[ 0 ]; const int j = triangle_idx[ 1 ]; assert( combined == i + ( j * ( j - 1 ) ) / 2 ); // Fill workspace[ xy ] with [ (ix|jy) - (iy|jx) ] int jump_xy = 0; for ( int irrep_xy = 0; irrep_xy < num_irreps; irrep_xy++ ){ const int occ_xy = indices->getNOCC( irrep_xy ); const int num_xy = indices->getNDMRG( irrep_xy ); for ( int x = 0; x < num_xy; x++ ){ for ( int y = x+1; y < num_xy; y++ ){ // 0 <= x < y < num_xy const double ix_jy = integrals->get_coulomb( irrep_ij, irrep_xy, irrep_ij, irrep_xy, i, occ_xy + x, j, occ_xy + y ); const double iy_jx = integrals->get_coulomb( irrep_ij, irrep_xy, irrep_ij, irrep_xy, i, occ_xy + y, j, occ_xy + x ); workspace[ jump_xy + x + (y*(y-1))/2 ] = ix_jy - iy_jx; } } jump_xy += ( num_xy * ( num_xy - 1 ) ) / 2; } assert( jump_xy == size_B_triplet[ 0 ] ); // Perform target[ tu ] = sum_{x 0 ){ int shift = 0; for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int irrep_j = Irreps::directProd( irrep, irrep_i ); if ( irrep_i < irrep_j ){ assert( shift == shift_B_nonactive( indices, irrep_i, irrep_j, 0 ) ); const int NOCC_i = indices->getNOCC( irrep_i ); const int NOCC_j = indices->getNOCC( irrep_j ); const int loopsize = NOCC_i * NOCC_j; #pragma omp for schedule(static) for ( int combined = 0; combined < loopsize; combined++ ){ const int i = combined % NOCC_i; const int j = combined / NOCC_i; // Fill workspace[ xy ] with [ (ix|jy) + (iy|jx) ] int jump_xy = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int irrep_y = Irreps::directProd( irrep, irrep_x ); if ( irrep_x < irrep_y ){ const int occ_x = indices->getNOCC( irrep_x ); const int occ_y = indices->getNOCC( irrep_y ); const int num_x = indices->getNDMRG( irrep_x ); const int num_y = indices->getNDMRG( irrep_y ); for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ const double ix_jy = integrals->get_coulomb( irrep_i, irrep_x, irrep_j, irrep_y, i, occ_x + x, j, occ_y + y ); const double iy_jx = integrals->get_coulomb( irrep_i, irrep_y, irrep_j, irrep_x, i, occ_y + y, j, occ_x + x ); workspace[ jump_xy + x + num_x * y ] = ix_jy + iy_jx; } } jump_xy += num_x * num_y; } } assert( jump_xy == size_B_singlet[ irrep ] ); // Perform target[ tu ] = sum_{xgetNOCC( irrep_x ); const int occ_y = indices->getNOCC( irrep_y ); const int num_x = indices->getNDMRG( irrep_x ); const int num_y = indices->getNDMRG( irrep_y ); for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ const double ix_jy = integrals->get_coulomb( irrep_i, irrep_x, irrep_j, irrep_y, i, occ_x + x, j, occ_y + y ); const double iy_jx = integrals->get_coulomb( irrep_i, irrep_y, irrep_j, irrep_x, i, occ_y + y, j, occ_x + x ); workspace[ jump_xy + x + num_x * y ] = ix_jy - iy_jx; } } jump_xy += num_x * num_y; } } assert( jump_xy == size_B_triplet[ irrep ] ); // Perform target[ tu ] = sum_{x 0 ){ // First do irrep == Ii x Ij == Ix x Iy == It x Iu == 0 int shift = 0; // First do SINGLET for ( int irrep_ab = 0; irrep_ab < num_irreps; irrep_ab++ ){ assert( shift == shift_F_nonactive( indices, irrep_ab, irrep_ab, +1 ) ); const int N_OA_ab = indices->getNOCC( irrep_ab ) + indices->getNDMRG( irrep_ab ); const int NVIR_ab = indices->getNVIRT( irrep_ab ); const int loopsize = ( NVIR_ab * ( NVIR_ab + 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined = 0; combined < loopsize; combined++ ){ Special::invert_triangle_two( combined, triangle_idx ); const int a = triangle_idx[ 0 ]; const int b = triangle_idx[ 1 ]; assert( combined == a + ( b * ( b + 1 ) ) / 2 ); // Fill workspace[ xy ] with [ (ax|by) + (ay|bx) ] * (( x==y ) ? 0.5 : 1.0 ) int jump_xy = 0; for ( int irrep_xy = 0; irrep_xy < num_irreps; irrep_xy++ ){ const int occ_xy = indices->getNOCC( irrep_xy ); const int num_xy = indices->getNDMRG( irrep_xy ); for ( int x = 0; x < num_xy; x++ ){ for ( int y = x; y < num_xy; y++ ){ // 0 <= x <= y < num_xy const double ax_by = integrals->get_exchange( irrep_xy, irrep_xy, irrep_ab, irrep_ab, occ_xy + x, occ_xy + y, N_OA_ab + a, N_OA_ab + b ); const double ay_bx = integrals->get_exchange( irrep_xy, irrep_xy, irrep_ab, irrep_ab, occ_xy + y, occ_xy + x, N_OA_ab + a, N_OA_ab + b ); workspace[ jump_xy + x + (y*(y+1))/2 ] = ( ax_by + ay_bx ) * (( x==y ) ? 0.5 : 1.0 ); } } jump_xy += ( num_xy * ( num_xy + 1 ) ) / 2; } assert( jump_xy == size_F_singlet[ 0 ] ); // Perform target[ tu ] = sum_{x<=y} [ (ax|by) + (ay|bx) ] SFF_singlet[ It x Iu ][ xytu ] * (( x==y ) ? 0.5 : 1.0 ) / sqrt( 1 + delta_ab ) char notrans = 'N'; int inc1 = 1; double alpha = (( a == b ) ? SQRT_0p5 : 1.0 ); double set = 0.0; double * target = vector_rhs + jump[ 0 + num_irreps * CHEMPS2_CASPT2_F_SINGLET ] + size_F_singlet[ 0 ] * ( shift + combined ); dgemv_( ¬rans, &jump_xy, &jump_xy, &alpha, SFF_singlet[ 0 ], &jump_xy, workspace, &inc1, &set, target, &inc1 ); } shift += loopsize; } assert( shift * size_F_singlet[ 0 ] == jump[ 1 + num_irreps * CHEMPS2_CASPT2_F_SINGLET ] - jump[ num_irreps * CHEMPS2_CASPT2_F_SINGLET ] ); } if ( size_F_triplet[ 0 ] > 0 ){ // Then do TRIPLET int shift = 0; for ( int irrep_ab = 0; irrep_ab < num_irreps; irrep_ab++ ){ assert( shift == shift_F_nonactive( indices, irrep_ab, irrep_ab, -1 ) ); const int N_OA_ab = indices->getNOCC( irrep_ab ) + indices->getNDMRG( irrep_ab ); const int NVIR_ab = indices->getNVIRT( irrep_ab ); const int loopsize = ( NVIR_ab * ( NVIR_ab - 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined = 0; combined < loopsize; combined++ ){ Special::invert_lower_triangle_two( combined, triangle_idx ); const int a = triangle_idx[ 0 ]; const int b = triangle_idx[ 1 ]; assert( combined == a + ( b * ( b - 1 ) ) / 2 ); // Fill workspace[ xy ] with [ (ax|by) - (ay|bx) ] int jump_xy = 0; for ( int irrep_xy = 0; irrep_xy < num_irreps; irrep_xy++ ){ const int occ_xy = indices->getNOCC( irrep_xy ); const int num_xy = indices->getNDMRG( irrep_xy ); for ( int x = 0; x < num_xy; x++ ){ for ( int y = x+1; y < num_xy; y++ ){ // 0 <= x < y < num_xy const double ax_by = integrals->get_exchange( irrep_xy, irrep_xy, irrep_ab, irrep_ab, occ_xy + x, occ_xy + y, N_OA_ab + a, N_OA_ab + b ); const double ay_bx = integrals->get_exchange( irrep_xy, irrep_xy, irrep_ab, irrep_ab, occ_xy + y, occ_xy + x, N_OA_ab + a, N_OA_ab + b ); workspace[ jump_xy + x + (y*(y-1))/2 ] = ax_by - ay_bx; } } jump_xy += ( num_xy * ( num_xy - 1 ) ) / 2; } assert( jump_xy == size_F_triplet[ 0 ] ); // Perform target[ tu ] = sum_{x 0 ){ int shift = 0; for ( int irrep_a = 0; irrep_a < num_irreps; irrep_a++ ){ const int irrep_b = Irreps::directProd( irrep, irrep_a ); if ( irrep_a < irrep_b ){ assert( shift == shift_F_nonactive( indices, irrep_a, irrep_b, 0 ) ); const int N_OA_a = indices->getNOCC( irrep_a ) + indices->getNDMRG( irrep_a ); const int N_OA_b = indices->getNOCC( irrep_b ) + indices->getNDMRG( irrep_b ); const int NVIR_a = indices->getNVIRT( irrep_a ); const int NVIR_b = indices->getNVIRT( irrep_b ); const int loopsize = NVIR_a * NVIR_b; #pragma omp for schedule(static) for ( int combined = 0; combined < loopsize; combined++ ){ const int a = combined % NVIR_a; const int b = combined / NVIR_a; // Fill workspace[ xy ] with [ (ax|by) + (ay|bx) ] int jump_xy = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int irrep_y = Irreps::directProd( irrep, irrep_x ); if ( irrep_x < irrep_y ){ const int occ_x = indices->getNOCC( irrep_x ); const int occ_y = indices->getNOCC( irrep_y ); const int num_x = indices->getNDMRG( irrep_x ); const int num_y = indices->getNDMRG( irrep_y ); for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ const double ax_by = integrals->get_exchange( irrep_x, irrep_y, irrep_a, irrep_b, occ_x + x, occ_y + y, N_OA_a + a, N_OA_b + b ); const double ay_bx = integrals->get_exchange( irrep_y, irrep_x, irrep_a, irrep_b, occ_y + y, occ_x + x, N_OA_a + a, N_OA_b + b ); workspace[ jump_xy + x + num_x * y ] = ax_by + ay_bx; } } jump_xy += num_x * num_y; } } assert( jump_xy == size_F_singlet[ irrep ] ); // Perform target[ tu ] = sum_{xgetNOCC( irrep_x ); const int occ_y = indices->getNOCC( irrep_y ); const int num_x = indices->getNDMRG( irrep_x ); const int num_y = indices->getNDMRG( irrep_y ); for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ const double ax_by = integrals->get_exchange( irrep_x, irrep_y, irrep_a, irrep_b, occ_x + x, occ_y + y, N_OA_a + a, N_OA_b + b ); const double ay_bx = integrals->get_exchange( irrep_y, irrep_x, irrep_a, irrep_b, occ_y + y, occ_x + x, N_OA_a + a, N_OA_b + b ); workspace[ jump_xy + x + num_x * y ] = ax_by - ay_bx; } } jump_xy += num_x * num_y; } } assert( jump_xy == size_F_triplet[ irrep ] ); // Perform target[ tu ] = sum_{xgetNOCC( irrep ); const int num_t = indices->getNDMRG( irrep ); if ( num_t > 0 ){ double * target_singlet = vector_rhs + jump[ irrep + num_irreps * CHEMPS2_CASPT2_E_SINGLET ]; double * target_triplet = vector_rhs + jump[ irrep + num_irreps * CHEMPS2_CASPT2_E_TRIPLET ]; int shift_singlet = 0; int shift_triplet = 0; for ( int irrep_a = 0; irrep_a < num_irreps; irrep_a++ ){ const int NVIR_a = indices->getNVIRT( irrep_a ); const int N_OA_a = indices->getNOCC( irrep_a ) + indices->getNDMRG( irrep_a ); const int irrep_occ = Irreps::directProd( irrep_a, irrep ); if ( irrep_occ == 0 ){ for ( int irrep_ij = 0; irrep_ij < num_irreps; irrep_ij++ ){ assert( shift_singlet == shift_E_nonactive( indices, irrep_a, irrep_ij, irrep_ij, +1 ) ); assert( shift_triplet == shift_E_nonactive( indices, irrep_a, irrep_ij, irrep_ij, -1 ) ); const int NOCC_ij = indices->getNOCC( irrep_ij ); const int loopsize_singlet = ( NVIR_a * NOCC_ij * ( NOCC_ij + 1 ) ) / 2; const int loopsize_triplet = ( NVIR_a * NOCC_ij * ( NOCC_ij - 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined_singlet = 0; combined_singlet < loopsize_singlet; combined_singlet++ ){ const int a = combined_singlet % NVIR_a; const int remainder = combined_singlet / NVIR_a; Special::invert_triangle_two( remainder, triangle_idx ); const int i = triangle_idx[ 0 ]; const int j = triangle_idx[ 1 ]; const int combined_triplet = a + NVIR_a * ( i + ( j * ( j - 1 ) ) / 2 ); const double ij_factor = (( i == j ) ? SQRT_0p5 : 1.0 ); const int count_aij_singlet = shift_singlet + combined_singlet; const int count_aij_triplet = shift_triplet + combined_triplet; for ( int t = 0; t < num_t; t++ ){ double value_singlet = 0.0; double value_triplet = 0.0; for ( int w = 0; w < num_t; w++ ){ const double SEE_wt = SEE[ irrep ][ w + num_t * t ]; const double aj_wi = integrals->get_coulomb( irrep_ij, irrep, irrep_ij, irrep_a, i, occ_t + w, j, N_OA_a + a ); const double ai_wj = integrals->get_coulomb( irrep_ij, irrep, irrep_ij, irrep_a, j, occ_t + w, i, N_OA_a + a ); value_singlet += SEE_wt * ( aj_wi + ai_wj ); value_triplet += 3 * SEE_wt * ( aj_wi - ai_wj ); } target_singlet[ t + num_t * count_aij_singlet ] = value_singlet * ij_factor; if ( j > i ){ target_triplet[ t + num_t * count_aij_triplet ] = value_triplet; } } } shift_singlet += loopsize_singlet; shift_triplet += loopsize_triplet; } } else { for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int irrep_j = Irreps::directProd( irrep_i, irrep_occ ); if ( irrep_i < irrep_j ){ assert( shift_singlet == shift_E_nonactive( indices, irrep_a, irrep_i, irrep_j, +1 ) ); assert( shift_triplet == shift_E_nonactive( indices, irrep_a, irrep_i, irrep_j, -1 ) ); const int NOCC_i = indices->getNOCC( irrep_i ); const int NOCC_j = indices->getNOCC( irrep_j ); const int loopsize = NOCC_i * NOCC_j * NVIR_a; #pragma omp for schedule(static) for ( int combined = 0; combined < loopsize; combined++ ){ const int a = combined % NVIR_a; const int remainder = combined / NVIR_a; const int i = remainder % NOCC_i; const int j = remainder / NOCC_i; const int count_aij_singlet = shift_singlet + combined; const int count_aij_triplet = shift_triplet + combined; for ( int t = 0; t < num_t; t++ ){ double value_singlet = 0.0; double value_triplet = 0.0; for ( int w = 0; w < num_t; w++ ){ const double SEE_wt = SEE[ irrep ][ w + num_t * t ]; const double aj_wi = integrals->get_coulomb( irrep_i, irrep, irrep_j, irrep_a, i, occ_t + w, j, N_OA_a + a ); const double ai_wj = integrals->get_coulomb( irrep_j, irrep, irrep_i, irrep_a, j, occ_t + w, i, N_OA_a + a ); value_singlet += SEE_wt * ( aj_wi + ai_wj ); value_triplet += 3 * SEE_wt * ( aj_wi - ai_wj ); } target_singlet[ t + num_t * count_aij_singlet ] = value_singlet; target_triplet[ t + num_t * count_aij_triplet ] = value_triplet; } } shift_singlet += loopsize; shift_triplet += loopsize; } } } } assert( shift_singlet * num_t == jump[ 1 + irrep + num_irreps * CHEMPS2_CASPT2_E_SINGLET ] - jump[ irrep + num_irreps * CHEMPS2_CASPT2_E_SINGLET ] ); assert( shift_triplet * num_t == jump[ 1 + irrep + num_irreps * CHEMPS2_CASPT2_E_TRIPLET ] - jump[ irrep + num_irreps * CHEMPS2_CASPT2_E_TRIPLET ] ); } } // VG singlet and triplet for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int occ_t = indices->getNOCC( irrep ); const int num_t = indices->getNDMRG( irrep ); if ( num_t > 0 ){ double * target_singlet = vector_rhs + jump[ irrep + num_irreps * CHEMPS2_CASPT2_G_SINGLET ]; double * target_triplet = vector_rhs + jump[ irrep + num_irreps * CHEMPS2_CASPT2_G_TRIPLET ]; int shift_singlet = 0; int shift_triplet = 0; for ( int irrep_i = 0; irrep_i < num_irreps; irrep_i++ ){ const int NOCC_i = indices->getNOCC( irrep_i ); const int irrep_virt = Irreps::directProd( irrep_i, irrep ); if ( irrep_virt == 0 ){ for ( int irrep_ab = 0; irrep_ab < num_irreps; irrep_ab++ ){ assert( shift_singlet == shift_G_nonactive( indices, irrep_i, irrep_ab, irrep_ab, +1 ) ); assert( shift_triplet == shift_G_nonactive( indices, irrep_i, irrep_ab, irrep_ab, -1 ) ); const int N_OA_ab = indices->getNOCC( irrep_ab ) + indices->getNDMRG( irrep_ab ); const int NVIR_ab = indices->getNVIRT( irrep_ab ); const int loopsize_singlet = ( NOCC_i * NVIR_ab * ( NVIR_ab + 1 ) ) / 2; const int loopsize_triplet = ( NOCC_i * NVIR_ab * ( NVIR_ab - 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined_singlet = 0; combined_singlet < loopsize_singlet; combined_singlet++ ){ const int i = combined_singlet % NOCC_i; const int remainder = combined_singlet / NOCC_i; Special::invert_triangle_two( remainder, triangle_idx ); const int a = triangle_idx[ 0 ]; const int b = triangle_idx[ 1 ]; const int combined_triplet = i + NOCC_i * ( a + ( b * ( b - 1 ) ) / 2 ); const double ab_factor = (( a == b ) ? SQRT_0p5 : 1.0 ); const int count_abi_singlet = shift_singlet + combined_singlet; const int count_abi_triplet = shift_triplet + combined_triplet; for ( int t = 0; t < num_t; t++ ){ double value_singlet = 0.0; double value_triplet = 0.0; for ( int u = 0; u < num_t; u++ ){ const double SGG_ut = SGG[ irrep ][ u + num_t * t ]; const double ai_bu = integrals->get_exchange( irrep_i, irrep, irrep_ab, irrep_ab, i, occ_t + u, N_OA_ab + a, N_OA_ab + b ); const double bi_au = integrals->get_exchange( irrep_i, irrep, irrep_ab, irrep_ab, i, occ_t + u, N_OA_ab + b, N_OA_ab + a ); value_singlet += SGG_ut * ( ai_bu + bi_au ); value_triplet += 3 * SGG_ut * ( ai_bu - bi_au ); } target_singlet[ t + num_t * count_abi_singlet ] = value_singlet * ab_factor; if ( b > a ){ target_triplet[ t + num_t * count_abi_triplet ] = value_triplet; } } } shift_singlet += loopsize_singlet; shift_triplet += loopsize_triplet; } } else { for ( int irrep_a = 0; irrep_a < num_irreps; irrep_a++ ){ const int irrep_b = Irreps::directProd( irrep_a, irrep_virt ); if ( irrep_a < irrep_b ){ assert( shift_singlet == shift_G_nonactive( indices, irrep_i, irrep_a, irrep_b, +1 ) ); assert( shift_triplet == shift_G_nonactive( indices, irrep_i, irrep_a, irrep_b, -1 ) ); const int N_OA_a = indices->getNOCC( irrep_a ) + indices->getNDMRG( irrep_a ); const int N_OA_b = indices->getNOCC( irrep_b ) + indices->getNDMRG( irrep_b ); const int NVIR_a = indices->getNVIRT( irrep_a ); const int NVIR_b = indices->getNVIRT( irrep_b ); const int loopsize = NOCC_i * NVIR_a * NVIR_b; #pragma omp for schedule(static) for ( int combined = 0; combined < loopsize; combined++ ){ const int i = combined % NOCC_i; const int remainder = combined / NOCC_i; const int a = remainder % NVIR_a; const int b = remainder / NVIR_a; const int count_abi_singlet = shift_singlet + combined; const int count_abi_triplet = shift_triplet + combined; for ( int t = 0; t < num_t; t++ ){ double value_singlet = 0.0; double value_triplet = 0.0; for ( int u = 0; u < num_t; u++ ){ const double SGG_ut = SGG[ irrep ][ u + num_t * t ]; const double ai_bu = integrals->get_exchange( irrep_i, irrep, irrep_a, irrep_b, i, occ_t + u, N_OA_a + a, N_OA_b + b ); const double bi_au = integrals->get_exchange( irrep_i, irrep, irrep_b, irrep_a, i, occ_t + u, N_OA_b + b, N_OA_a + a ); value_singlet += SGG_ut * ( ai_bu + bi_au ); value_triplet += 3 * SGG_ut * ( ai_bu - bi_au ); } target_singlet[ t + num_t * count_abi_singlet ] = value_singlet; target_triplet[ t + num_t * count_abi_triplet ] = value_triplet; } } shift_singlet += loopsize; shift_triplet += loopsize; } } } } assert( shift_singlet * num_t == jump[ 1 + irrep + num_irreps * CHEMPS2_CASPT2_G_SINGLET ] - jump[ irrep + num_irreps * CHEMPS2_CASPT2_G_SINGLET ] ); assert( shift_triplet * num_t == jump[ 1 + irrep + num_irreps * CHEMPS2_CASPT2_G_TRIPLET ] - jump[ irrep + num_irreps * CHEMPS2_CASPT2_G_TRIPLET ] ); } } // VH singlet and triplet for ( int irrep = 0; irrep < num_irreps; irrep++ ){ int shift_singlet = 0; int shift_triplet = 0; double * target_singlet = vector_rhs + jump[ irrep + num_irreps * CHEMPS2_CASPT2_H_SINGLET ]; double * target_triplet = vector_rhs + jump[ irrep + num_irreps * CHEMPS2_CASPT2_H_TRIPLET ]; if ( irrep == 0 ){ // irrep_i == irrep_j and irrep_a == irrep_b for ( int irrep_ij = 0; irrep_ij < num_irreps; irrep_ij++ ){ const int nocc_ij = indices->getNOCC( irrep_ij ); const int linsize_ij_singlet = ( nocc_ij * ( nocc_ij + 1 ) ) / 2; const int linsize_ij_triplet = ( nocc_ij * ( nocc_ij - 1 ) ) / 2; for ( int irrep_ab = 0; irrep_ab < num_irreps; irrep_ab++ ){ assert( shift_singlet == shift_H_nonactive( indices, irrep_ij, irrep_ij, irrep_ab, irrep_ab, +1 ) ); assert( shift_triplet == shift_H_nonactive( indices, irrep_ij, irrep_ij, irrep_ab, irrep_ab, -1 ) ); const int nvirt_ab = indices->getNVIRT( irrep_ab ); const int noa_ab = indices->getNOCC( irrep_ab ) + indices->getNDMRG( irrep_ab ); const int linsize_ab_singlet = ( nvirt_ab * ( nvirt_ab + 1 ) ) / 2; const int linsize_ab_triplet = ( nvirt_ab * ( nvirt_ab - 1 ) ) / 2; #pragma omp for schedule(static) for ( int combined_ab_singlet = 0; combined_ab_singlet < linsize_ab_singlet; combined_ab_singlet++ ){ Special::invert_triangle_two( combined_ab_singlet, triangle_idx ); const int a = triangle_idx[ 0 ]; const int b = triangle_idx[ 1 ]; const double ab_factor = (( a == b ) ? SQRT_0p5 : 1.0 ); const int combined_ab_triplet = a + ( b * ( b - 1 ) ) / 2; for ( int i = 0; i < nocc_ij; i++ ){ for ( int j = i; j < nocc_ij; j++ ){ const double ij_factor = (( i == j ) ? SQRT_0p5 : 1.0 ); const int counter_singlet = shift_singlet + i + ( j * ( j + 1 ) ) / 2 + linsize_ij_singlet * combined_ab_singlet; const int counter_triplet = shift_triplet + i + ( j * ( j - 1 ) ) / 2 + linsize_ij_triplet * combined_ab_triplet; const double ai_bj = integrals->get_exchange( irrep_ij, irrep_ij, irrep_ab, irrep_ab, i, j, noa_ab + a, noa_ab + b ); const double aj_bi = integrals->get_exchange( irrep_ij, irrep_ij, irrep_ab, irrep_ab, j, i, noa_ab + a, noa_ab + b ); target_singlet[ counter_singlet ] = 2 * ( ai_bj + aj_bi ) * ij_factor * ab_factor; if ((agetNOCC( irrep_i ); const int nocc_j = indices->getNOCC( irrep_j ); const int linsize_ij = nocc_i * nocc_j; for ( int irrep_a = 0; irrep_a < num_irreps; irrep_a++ ){ const int irrep_b = Irreps::directProd( irrep, irrep_a ); if ( irrep_a < irrep_b ){ assert( shift_singlet == shift_H_nonactive( indices, irrep_i, irrep_j, irrep_a, irrep_b, +1 ) ); assert( shift_triplet == shift_H_nonactive( indices, irrep_i, irrep_j, irrep_a, irrep_b, -1 ) ); const int nvir_a = indices->getNVIRT( irrep_a ); const int nvir_b = indices->getNVIRT( irrep_b ); const int noa_a = indices->getNOCC( irrep_a ) + indices->getNDMRG( irrep_a ); const int noa_b = indices->getNOCC( irrep_b ) + indices->getNDMRG( irrep_b ); const int linsize_ab = nvir_a * nvir_b; #pragma omp for schedule(static) for ( int combined_ab = 0; combined_ab < linsize_ab; combined_ab++ ){ const int a = combined_ab % nvir_a; const int b = combined_ab / nvir_a; for ( int j = 0; j < nocc_j; j++ ){ for ( int i = 0; i < nocc_i; i++ ){ const int count_singlet = shift_singlet + i + nocc_i * ( j + nocc_j * combined_ab ); const int count_triplet = shift_triplet + i + nocc_i * ( j + nocc_j * combined_ab ); const double ai_bj = integrals->get_exchange( irrep_i, irrep_j, irrep_a, irrep_b, i, j, noa_a + a, noa_b + b ); const double aj_bi = integrals->get_exchange( irrep_j, irrep_i, irrep_a, irrep_b, j, i, noa_a + a, noa_b + b ); target_singlet[ count_singlet ] = 2 * ( ai_bj + aj_bi ); target_triplet[ count_triplet ] = 6 * ( ai_bj - aj_bi ); } } } shift_singlet += linsize_ij * linsize_ab; shift_triplet += linsize_ij * linsize_ab; } } } } } assert( shift_singlet == jump[ 1 + irrep + num_irreps * CHEMPS2_CASPT2_H_SINGLET ] - jump[ irrep + num_irreps * CHEMPS2_CASPT2_H_SINGLET ] ); assert( shift_triplet == jump[ 1 + irrep + num_irreps * CHEMPS2_CASPT2_H_TRIPLET ] - jump[ irrep + num_irreps * CHEMPS2_CASPT2_H_TRIPLET ] ); } }// End of #pragma omp parallel } int CheMPS2::CASPT2::jump_AC_active( const DMRGSCFindices * idx, const int irrep_t, const int irrep_u, const int irrep_v ){ const int irrep_tuv = Irreps::directProd( irrep_t, Irreps::directProd( irrep_u, irrep_v ) ); const int n_irreps = idx->getNirreps(); int jump_ac = 0; for ( int It = 0; It < n_irreps; It++ ){ for ( int Iu = 0; Iu < n_irreps; Iu++ ){ const int Iv = Irreps::directProd( irrep_tuv, Irreps::directProd( It, Iu ) ); if (( It == irrep_t ) && ( Iu == irrep_u ) && ( Iv == irrep_v )){ It = n_irreps; Iu = n_irreps; } else { jump_ac += idx->getNDMRG( It ) * idx->getNDMRG( Iu ) * idx->getNDMRG( Iv ); } } } return jump_ac; } int CheMPS2::CASPT2::jump_BF_active( const DMRGSCFindices * idx, const int irrep_t, const int irrep_u, const int ST ){ assert( irrep_t <= irrep_u ); const int irrep_tu = Irreps::directProd( irrep_t, irrep_u ); const int n_irreps = idx->getNirreps(); int jump_bf = 0; if ( irrep_tu == 0 ){ for ( int Itu = 0; Itu < n_irreps; Itu++ ){ if (( Itu == irrep_t ) && ( Itu == irrep_u )){ Itu = n_irreps; } else { jump_bf += ( idx->getNDMRG( Itu ) * ( idx->getNDMRG( Itu ) + ST ) ) / 2; } } } else { for ( int It = 0; It < n_irreps; It++ ){ const int Iu = Irreps::directProd( irrep_tu, It ); if ( It < Iu ){ if (( It == irrep_t ) && ( Iu == irrep_u )){ It = n_irreps; } else { jump_bf += idx->getNDMRG( It ) * idx->getNDMRG( Iu ); } } } } return jump_bf; } void CheMPS2::CASPT2::make_FDE_FDG(){ /* FD1E singlet: < E_yx E_lb E_kw SE_tiaj > = 1 delta_ab ( delta_ik delta_jl + delta_il delta_jk ) / sqrt( 1 + delta_ij ) FD1E_singlet[ Ib x Il ][ It ][ w ][ xy, t ] FD2E singlet: < E_yb E_lx E_kw SE_tiaj > = 1 delta_ab ( delta_ik delta_jl + delta_il delta_jk ) / sqrt( 1 + delta_ij ) FD2E_singlet[ Ib x Il ][ It ][ w ][ xy, t ] FD1E triplet: < E_yx E_lb E_kw TE_tiaj > = 3 delta_ab ( delta_ik delta_jl - delta_il delta_jk ) / sqrt( 1 + delta_ij ) FD1E_triplet[ Ib x Il ][ It ][ w ][ xy, t ] FD2E triplet: < E_yb E_lx E_kw TE_tiaj > = 3 delta_ab ( delta_ik delta_jl - delta_il delta_jk ) / sqrt( 1 + delta_ij ) FD2E_triplet[ Ib x Il ][ It ][ w ][ xy, t ] FD1E_singlet[ Ib x Il ][ It ][ w ][ xy, t ] = ( + 2 delta_tw Gamma_yx - delta_tx Gamma_yw - Gamma_ytxw ) FD2E_singlet[ Ib x Il ][ It ][ w ][ xy, t ] = ( + Gamma_ytxw + Gamma_ytwx - delta_tx Gamma_yw - delta_tw Gamma_yx ) FD1E_triplet[ Ib x Il ][ It ][ w ][ xy, t ] = ( + 2 delta_tw Gamma_yx - delta_tx Gamma_yw - Gamma_ytxw ) FD2E_triplet[ Ib x Il ][ It ][ w ][ xy, t ] = ( + Gamma_ytxw / 3 - Gamma_ytwx / 3 + delta_tx Gamma_yw - delta_tw Gamma_yx ) FD1G singlet: < E_yx E_jd E_wc SG_aibt > = 1 delta_ij ( delta_ac delta_bd + delta_ad delta_bc ) / sqrt( 1 + delta_ab ) FD1G_singlet[ Ij x Id ][ It ][ w ][ xy, t ] FD2G singlet: < E_yd E_jx E_wc SG_aibt > = 1 delta_ij ( delta_ac delta_bd + delta_ad delta_bc ) / sqrt( 1 + delta_ab ) FD2G_singlet[ Ij x Id ][ It ][ w ][ xy, t ] FD1G triplet: < E_yx E_jd E_wc TG_aibt > = 3 delta_ij ( delta_ac delta_bd - delta_ad delta_bc ) / sqrt( 1 + delta_ab ) FD1G_triplet[ Ij x Id ][ It ][ w ][ xy, t ] FD2G triplet: < E_yd E_jx E_wc TG_aibt > = 3 delta_ij ( delta_ac delta_bd - delta_ad delta_bc ) / sqrt( 1 + delta_ab ) FD2G_triplet[ Ij x Id ][ It ][ w ][ xy, t ] FD1G_singlet[ Ij x Id ][ It ][ w ][ xy, t ] = ( + Gamma_ywxt + delta_wx Gamma_yt ) FD2G_singlet[ Ij x Id ][ It ][ w ][ xy, t ] = ( + delta_xw Gamma_yt - Gamma_ywtx - Gamma_ywxt ) FD1G_triplet[ Ij x Id ][ It ][ w ][ xy, t ] = ( - Gamma_ywxt - delta_wx Gamma_yt ) FD2G_triplet[ Ij x Id ][ It ][ w ][ xy, t ] = ( + delta_xw Gamma_yt - Gamma ywtx / 3 + Gamma ywxt / 3 ) */ FDE_singlet = new double***[ num_irreps ]; FDE_triplet = new double***[ num_irreps ]; FDG_singlet = new double***[ num_irreps ]; FDG_triplet = new double***[ num_irreps ]; const int LAS = indices->getDMRGcumulative( num_irreps ); for ( int irrep_left = 0; irrep_left < num_irreps; irrep_left++ ){ const int SIZE_left = size_D[ irrep_left ]; const int D2JUMP = SIZE_left / 2; FDE_singlet[ irrep_left ] = new double**[ num_irreps ]; FDE_triplet[ irrep_left ] = new double**[ num_irreps ]; FDG_singlet[ irrep_left ] = new double**[ num_irreps ]; FDG_triplet[ irrep_left ] = new double**[ num_irreps ]; for ( int irrep_t = 0; irrep_t < num_irreps; irrep_t++ ){ const int SIZE_right = indices->getNDMRG( irrep_t ); const int d_t = indices->getDMRGcumulative( irrep_t ); const int num_t = indices->getNDMRG( irrep_t ); const int irrep_w = Irreps::directProd( irrep_left, irrep_t ); const int d_w = indices->getDMRGcumulative( irrep_w ); const int num_w = indices->getNDMRG( irrep_w ); FDE_singlet[ irrep_left ][ irrep_t ] = new double*[ num_w ]; FDE_triplet[ irrep_left ][ irrep_t ] = new double*[ num_w ]; FDG_singlet[ irrep_left ][ irrep_t ] = new double*[ num_w ]; FDG_triplet[ irrep_left ][ irrep_t ] = new double*[ num_w ]; for ( int w = 0; w < num_w; w++ ){ FDE_singlet[ irrep_left ][ irrep_t ][ w ] = new double[ SIZE_left * SIZE_right ]; FDE_triplet[ irrep_left ][ irrep_t ][ w ] = new double[ SIZE_left * SIZE_right ]; FDG_singlet[ irrep_left ][ irrep_t ][ w ] = new double[ SIZE_left * SIZE_right ]; FDG_triplet[ irrep_left ][ irrep_t ][ w ] = new double[ SIZE_left * SIZE_right ]; double * FDE_sing = FDE_singlet[ irrep_left ][ irrep_t ][ w ]; double * FDE_trip = FDE_triplet[ irrep_left ][ irrep_t ][ w ]; double * FDG_sing = FDG_singlet[ irrep_left ][ irrep_t ][ w ]; double * FDG_trip = FDG_triplet[ irrep_left ][ irrep_t ][ w ]; int jump_row = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int d_x = indices->getDMRGcumulative( irrep_x ); const int num_x = indices->getNDMRG( irrep_x ); const int irrep_y = Irreps::directProd( irrep_left, irrep_x ); const int d_y = indices->getDMRGcumulative( irrep_y ); const int num_y = indices->getNDMRG( irrep_y ); for ( int t = 0; t < num_t; t++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ const double gamma_ytxw = two_rdm[ d_y + y + LAS * ( d_t + t + LAS * ( d_x + x + LAS * ( d_w + w ))) ]; const double gamma_ytwx = two_rdm[ d_y + y + LAS * ( d_t + t + LAS * ( d_w + w + LAS * ( d_x + x ))) ]; FDE_sing[ jump_row + x + num_x * y + SIZE_left * t ] = - gamma_ytxw; FDE_sing[ D2JUMP + jump_row + x + num_x * y + SIZE_left * t ] = + gamma_ytxw + gamma_ytwx; FDE_trip[ jump_row + x + num_x * y + SIZE_left * t ] = - gamma_ytxw; FDE_trip[ D2JUMP + jump_row + x + num_x * y + SIZE_left * t ] = ( gamma_ytxw - gamma_ytwx ) / 3.0; const double gamma_ywtx = two_rdm[ d_y + y + LAS * ( d_w + w + LAS * ( d_t + t + LAS * ( d_x + x ))) ]; const double gamma_ywxt = two_rdm[ d_y + y + LAS * ( d_w + w + LAS * ( d_x + x + LAS * ( d_t + t ))) ]; FDG_sing[ jump_row + x + num_x * y + SIZE_left * t ] = + gamma_ywxt; FDG_sing[ D2JUMP + jump_row + x + num_x * y + SIZE_left * t ] = - gamma_ywxt - gamma_ywtx; FDG_trip[ jump_row + x + num_x * y + SIZE_left * t ] = - gamma_ywxt; FDG_trip[ D2JUMP + jump_row + x + num_x * y + SIZE_left * t ] = ( gamma_ywxt - gamma_ywtx ) / 3.0; } } } if (( irrep_t == irrep_w ) && ( irrep_x == irrep_y )){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_x; y++ ){ const double gamma_yx = one_rdm[ d_y + y + LAS * ( d_x + x ) ]; FDE_sing[ jump_row + x + num_x * y + SIZE_left * w ] += 2 * gamma_yx; FDE_sing[ D2JUMP + jump_row + x + num_x * y + SIZE_left * w ] -= gamma_yx; FDE_trip[ jump_row + x + num_x * y + SIZE_left * w ] += 2 * gamma_yx; FDE_trip[ D2JUMP + jump_row + x + num_x * y + SIZE_left * w ] -= gamma_yx; } } } if (( irrep_t == irrep_x ) && ( irrep_y == irrep_w )){ for ( int y = 0; y < num_y; y++ ){ const double gamma_yw = one_rdm[ d_y + y + LAS * ( d_w + w ) ]; for ( int tx = 0; tx < num_x; tx++ ){ FDE_sing[ jump_row + tx + num_x * y + SIZE_left * tx ] -= gamma_yw; FDE_sing[ D2JUMP + jump_row + tx + num_x * y + SIZE_left * tx ] -= gamma_yw; FDE_trip[ jump_row + tx + num_x * y + SIZE_left * tx ] -= gamma_yw; FDE_trip[ D2JUMP + jump_row + tx + num_x * y + SIZE_left * tx ] += gamma_yw; } } } if (( irrep_t == irrep_y ) && ( irrep_w == irrep_x )){ for ( int t = 0; t < num_t; t++ ){ for ( int y = 0; y < num_y; y++ ){ const double gamma_yt = one_rdm[ d_y + y + LAS * ( d_t + t ) ]; FDG_sing[ jump_row + w + num_x * y + SIZE_left * t ] += gamma_yt; FDG_sing[ D2JUMP + jump_row + w + num_x * y + SIZE_left * t ] += gamma_yt; FDG_trip[ jump_row + w + num_x * y + SIZE_left * t ] -= gamma_yt; FDG_trip[ D2JUMP + jump_row + w + num_x * y + SIZE_left * t ] += gamma_yt; } } } jump_row += num_x * num_y; } } } } } void CheMPS2::CASPT2::make_FEH_FGH(){ /* FEH singlet: < SE_xkdl E_wc SH_aibj > = 2 delta_ik delta_jl ( delta_ac delta_bd + delta_ad delta_bc ) / sqrt( 1 + delta_ab ) FEH[ Ix ][ w ][ x ] FEH triplet: < TE_xkdl E_wc TH_aibj > = 6 delta_ik delta_jl ( delta_ac delta_bd - delta_ad delta_bc ) / sqrt( 1 + delta_ab ) FEH[ Ix ][ w ][ x ] FGH singlet: < SG_cldx E_kw SH_aibj > = 2 delta_ac delta_bd ( delta_il delta_jk + delta_ik delta_jl ) / sqrt( 1 + delta_ij ) FGH[ Ix ][ w ][ x ] FGH triplet: < TG_cldx E_kw TH_aibj > = 6 delta_ac delta_bd ( delta_il delta_jk - delta_ik delta_jl ) / sqrt( 1 + delta_ij ) FGH[ Ix ][ w ][ x ] FEH[ Ix ][ w ][ x ] = + SEE[ Ix ][ xw ] FGH[ Ix ][ w ][ x ] = - SGG[ Ix ][ xw ] */ FEH = new double**[ num_irreps ]; FGH = new double**[ num_irreps ]; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int NACT = indices->getNDMRG( irrep_x ); FEH[ irrep_x ] = new double*[ NACT ]; FGH[ irrep_x ] = new double*[ NACT ]; for ( int w = 0; w < NACT; w++ ){ FEH[ irrep_x ][ w ] = new double[ NACT ]; FGH[ irrep_x ][ w ] = new double[ NACT ]; for ( int x = 0; x < NACT; x++ ){ FEH[ irrep_x ][ w ][ x ] = + SEE[ irrep_x ][ x + NACT * w ]; FGH[ irrep_x ][ w ][ x ] = - SGG[ irrep_x ][ x + NACT * w ]; } } } } void CheMPS2::CASPT2::make_FBE_FFG_singlet(){ /* FBE singlet : < SB_xkyl E_wc SE_tiaj > = 2 delta_ac delta_ik delta_jl FBE_singlet[ Ik x Il ][ It ][ w ][ xy, t ] FFG singlet : < SF_cxdy E_kw SG_aibt > = 2 delta_ac delta_bd delta_ik FFG_singlet[ Ic x Id ][ It ][ w ][ xy, t ] FBE_singlet[ Ik x Il ][ It ][ w ][ xy, t ] = + SBB_singlet[ Ik x Il ][ xy, tw ] FFG_singlet[ Ic x Id ][ It ][ w ][ xy, t ] = - SFF_singlet[ Ic x Id ][ xy, tw ] */ FBE_singlet = new double***[ num_irreps ]; FFG_singlet = new double***[ num_irreps ]; for ( int irrep_left = 0; irrep_left < num_irreps; irrep_left++ ){ assert( size_B_singlet[ irrep_left ] == size_F_singlet[ irrep_left ] ); // At construction const int SIZE_left = size_B_singlet[ irrep_left ]; FBE_singlet[ irrep_left ] = new double**[ num_irreps ]; FFG_singlet[ irrep_left ] = new double**[ num_irreps ]; for ( int irrep_t = 0; irrep_t < num_irreps; irrep_t++ ){ const int SIZE_right = indices->getNDMRG( irrep_t ); const int num_t = indices->getNDMRG( irrep_t ); const int irrep_w = Irreps::directProd( irrep_left, irrep_t ); const int num_w = indices->getNDMRG( irrep_w ); FBE_singlet[ irrep_left ][ irrep_t ] = new double*[ num_w ]; FFG_singlet[ irrep_left ][ irrep_t ] = new double*[ num_w ]; for ( int w = 0; w < num_w; w++ ){ FBE_singlet[ irrep_left ][ irrep_t ][ w ] = new double[ SIZE_left * SIZE_right ]; FFG_singlet[ irrep_left ][ irrep_t ][ w ] = new double[ SIZE_left * SIZE_right ]; double * BEptr = FBE_singlet[ irrep_left ][ irrep_t ][ w ]; double * FGptr = FFG_singlet[ irrep_left ][ irrep_t ][ w ]; if ( irrep_left == 0 ){ // irrep_t == irrep_w const int jump_singlet = jump_BF_active( indices, irrep_t, irrep_w, +1 ); for ( int t = 0; t < w; t++ ){ for ( int xy = 0; xy < SIZE_left; xy++ ){ BEptr[ xy + SIZE_left * t ] = + SBB_singlet[ irrep_left ][ xy + SIZE_left * ( jump_singlet + t + ( w * ( w + 1 ) ) / 2 ) ]; FGptr[ xy + SIZE_left * t ] = - SFF_singlet[ irrep_left ][ xy + SIZE_left * ( jump_singlet + t + ( w * ( w + 1 ) ) / 2 ) ]; } } for ( int t = w; t < num_t; t++ ){ for ( int xy = 0; xy < SIZE_left; xy++ ){ BEptr[ xy + SIZE_left * t ] = + SBB_singlet[ irrep_left ][ xy + SIZE_left * ( jump_singlet + w + ( t * ( t + 1 ) ) / 2 ) ]; FGptr[ xy + SIZE_left * t ] = - SFF_singlet[ irrep_left ][ xy + SIZE_left * ( jump_singlet + w + ( t * ( t + 1 ) ) / 2 ) ]; } } } else { // irrep_t != irrep_w if ( irrep_t < irrep_w ){ const int jump_singlet = jump_BF_active( indices, irrep_t, irrep_w, +1 ); for ( int t = 0; t < num_t; t++ ){ for ( int xy = 0; xy < SIZE_left; xy++ ){ BEptr[ xy + SIZE_left * t ] = + SBB_singlet[ irrep_left ][ xy + SIZE_left * ( jump_singlet + t + num_t * w ) ]; FGptr[ xy + SIZE_left * t ] = - SFF_singlet[ irrep_left ][ xy + SIZE_left * ( jump_singlet + t + num_t * w ) ]; } } } else { const int jump_singlet = jump_BF_active( indices, irrep_w, irrep_t, +1 ); for ( int t = 0; t < num_t; t++ ){ for ( int xy = 0; xy < SIZE_left; xy++ ){ BEptr[ xy + SIZE_left * t ] = + SBB_singlet[ irrep_left ][ xy + SIZE_left * ( jump_singlet + w + num_w * t ) ]; FGptr[ xy + SIZE_left * t ] = - SFF_singlet[ irrep_left ][ xy + SIZE_left * ( jump_singlet + w + num_w * t ) ]; } } } } } } } } void CheMPS2::CASPT2::make_FBE_FFG_triplet(){ /* FBE triplet : < TB_xkyl E_wc TE_tiaj > = 2 delta_ac delta_ik delta_jl FBE_triplet[ Ik x Il ][ It ][ w ][ xy, t ] FFG triplet : < TF_cxdy E_kw TG_aibt > = 2 delta_ac delta_bd delta_ik FFG_triplet[ Ic x Id ][ It ][ w ][ xy, t ] FBE_triplet[ Ik x Il ][ It ][ w ][ xy, t ] = + SBB_triplet[ Ik x Il ][ xy, tw ] FFG_triplet[ Ic x Id ][ It ][ w ][ xy, t ] = + SFF_triplet[ Ic x Id ][ xy, tw ] */ FBE_triplet = new double***[ num_irreps ]; FFG_triplet = new double***[ num_irreps ]; for ( int irrep_left = 0; irrep_left < num_irreps; irrep_left++ ){ assert( size_B_triplet[ irrep_left ] == size_F_triplet[ irrep_left ] ); // At construction const int SIZE_left = size_B_triplet[ irrep_left ]; FBE_triplet[ irrep_left ] = new double**[ num_irreps ]; FFG_triplet[ irrep_left ] = new double**[ num_irreps ]; for ( int irrep_t = 0; irrep_t < num_irreps; irrep_t++ ){ const int SIZE_right = indices->getNDMRG( irrep_t ); const int num_t = indices->getNDMRG( irrep_t ); const int irrep_w = Irreps::directProd( irrep_left, irrep_t ); const int num_w = indices->getNDMRG( irrep_w ); FBE_triplet[ irrep_left ][ irrep_t ] = new double*[ num_w ]; FFG_triplet[ irrep_left ][ irrep_t ] = new double*[ num_w ]; for ( int w = 0; w < num_w; w++ ){ FBE_triplet[ irrep_left ][ irrep_t ][ w ] = new double[ SIZE_left * SIZE_right ]; FFG_triplet[ irrep_left ][ irrep_t ][ w ] = new double[ SIZE_left * SIZE_right ]; double * BEptr = FBE_triplet[ irrep_left ][ irrep_t ][ w ]; double * FGptr = FFG_triplet[ irrep_left ][ irrep_t ][ w ]; if ( irrep_left == 0 ){ // irrep_t == irrep_w const int jump_triplet = jump_BF_active( indices, irrep_t, irrep_w, -1 ); for ( int t = 0; t < w; t++ ){ for ( int xy = 0; xy < SIZE_left; xy++ ){ BEptr[ xy + SIZE_left * t ] = + SBB_triplet[ irrep_left ][ xy + SIZE_left * ( jump_triplet + t + ( w * ( w - 1 ) ) / 2 ) ]; FGptr[ xy + SIZE_left * t ] = + SFF_triplet[ irrep_left ][ xy + SIZE_left * ( jump_triplet + t + ( w * ( w - 1 ) ) / 2 ) ]; } } for ( int xy = 0; xy < SIZE_left; xy++ ){ BEptr[ xy + SIZE_left * w ] = 0.0; FGptr[ xy + SIZE_left * w ] = 0.0; } for ( int t = w+1; t < num_t; t++ ){ for ( int xy = 0; xy < SIZE_left; xy++ ){ BEptr[ xy + SIZE_left * t ] = - SBB_triplet[ irrep_left ][ xy + SIZE_left * ( jump_triplet + w + ( t * ( t - 1 ) ) / 2 ) ]; FGptr[ xy + SIZE_left * t ] = - SFF_triplet[ irrep_left ][ xy + SIZE_left * ( jump_triplet + w + ( t * ( t - 1 ) ) / 2 ) ]; } } } else { // irrep_t != irrep_w if ( irrep_t < irrep_w ){ const int jump_triplet = jump_BF_active( indices, irrep_t, irrep_w, -1 ); for ( int t = 0; t < num_t; t++ ){ for ( int xy = 0; xy < SIZE_left; xy++ ){ BEptr[ xy + SIZE_left * t ] = + SBB_triplet[ irrep_left ][ xy + SIZE_left * ( jump_triplet + t + num_t * w ) ]; FGptr[ xy + SIZE_left * t ] = + SFF_triplet[ irrep_left ][ xy + SIZE_left * ( jump_triplet + t + num_t * w ) ]; } } } else { const int jump_triplet = jump_BF_active( indices, irrep_w, irrep_t, -1 ); for ( int t = 0; t < num_t; t++ ){ for ( int xy = 0; xy < SIZE_left; xy++ ){ BEptr[ xy + SIZE_left * t ] = - SBB_triplet[ irrep_left ][ xy + SIZE_left * ( jump_triplet + w + num_w * t ) ]; FGptr[ xy + SIZE_left * t ] = - SFF_triplet[ irrep_left ][ xy + SIZE_left * ( jump_triplet + w + num_w * t ) ]; } } } } } } } } void CheMPS2::CASPT2::make_FAB_FCF_singlet(){ /* FAB singlet : < E_zy E_lx | E_kw | SB_tiuj > = ( delta_ik delta_jl + delta_jk delta_il ) / sqrt( 1 + delta_ij ) * FAB_singlet[ Il ][ Ii x Ij ][ w ][ xyz, tu ] FCF singlet : < E_zy E_xd | E_wc | SF_atbu > = ( delta_ac delta_bd + delta_ad delta_bc ) / sqrt( 1 + delta_ab ) * FCF_singlet[ Id ][ Ia x Ib ][ w ][ xyz, tu ] FAB_singlet[ Il ][ Ii x Ij ][ w ][ xyz, tu ] = ( + 2 delta_tw delta_ux Gamma_zy + 2 delta_uw delta_tx Gamma_zy - delta_tw Gamma_zuyx - delta_tw delta_uy Gamma_zx - delta_uw Gamma_ztyx - delta_uw delta_ty Gamma_zx - SAA[ Il ][ xyz, utw ] - SAA[ Il ][ xyz, tuw ] ) FCF_singlet[ Id ][ Ia x Ib ][ w ][ xyz, tu ] = ( + SCC[ Id ][ xyz, uwt ] + SCC[ Id ][ xyz, twu ] - delta_uw Gamma_zxyt - delta_uw delta_xy Gamma_zt - delta_tw Gamma_zxyu - delta_tw delta_xy Gamma_zu ) */ FAB_singlet = new double***[ num_irreps ]; FCF_singlet = new double***[ num_irreps ]; const int LAS = indices->getDMRGcumulative( num_irreps ); for ( int irrep_left = 0; irrep_left < num_irreps; irrep_left++ ){ assert( size_A[ irrep_left ] == size_C[ irrep_left ] ); // At construction const int SIZE_left = size_A[ irrep_left ]; FAB_singlet[ irrep_left ] = new double**[ num_irreps ]; FCF_singlet[ irrep_left ] = new double**[ num_irreps ]; { // irrep_right == 0 assert( size_B_singlet[ 0 ] == size_F_singlet[ 0 ] ); // At construction const int SIZE_right = size_B_singlet[ 0 ]; const int num_w = indices->getNDMRG( irrep_left ); // irrep_w == irrep_left x irrep_right = irrep_left FAB_singlet[ irrep_left ][ 0 ] = new double*[ num_w ]; FCF_singlet[ irrep_left ][ 0 ] = new double*[ num_w ]; for ( int w = 0; w < num_w; w++ ){ FAB_singlet[ irrep_left ][ 0 ][ w ] = new double[ SIZE_left * SIZE_right ]; FCF_singlet[ irrep_left ][ 0 ][ w ] = new double[ SIZE_left * SIZE_right ]; double * ABptr = FAB_singlet[ irrep_left ][ 0 ][ w ]; double * CFptr = FCF_singlet[ irrep_left ][ 0 ][ w ]; int jump_col = 0; for ( int irrep_ut = 0; irrep_ut < num_irreps; irrep_ut++ ){ const int d_ut = indices->getDMRGcumulative( irrep_ut ); const int num_ut = indices->getNDMRG( irrep_ut ); assert( jump_col == jump_BF_active( indices, irrep_ut, irrep_ut, +1 ) ); const int jump_AB = jump_AC_active( indices, irrep_ut, irrep_ut, irrep_left ); const int jump_CF = jump_AC_active( indices, irrep_ut, irrep_left, irrep_ut ); for ( int t = 0; t < num_ut; t++ ){ for ( int u = t; u < num_ut; u++ ){ // 0 <= t <= u < num_ut for ( int xyz = 0; xyz < SIZE_left; xyz++ ){ ABptr[ xyz + SIZE_left * ( jump_col + t + ( u * ( u + 1 ) ) / 2 ) ] = ( - SAA[ irrep_left ][ xyz + SIZE_left * ( jump_AB + u + num_ut * ( t + num_ut * w )) ] - SAA[ irrep_left ][ xyz + SIZE_left * ( jump_AB + t + num_ut * ( u + num_ut * w )) ] ); CFptr[ xyz + SIZE_left * ( jump_col + t + ( u * ( u + 1 ) ) / 2 ) ] = ( + SCC[ irrep_left ][ xyz + SIZE_left * ( jump_CF + u + num_ut * ( w + num_w * t )) ] + SCC[ irrep_left ][ xyz + SIZE_left * ( jump_CF + t + num_ut * ( w + num_w * u )) ] ); } } } int jump_row = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int d_x = indices->getDMRGcumulative( irrep_x ); const int num_x = indices->getNDMRG( irrep_x ); for ( int irrep_y = 0; irrep_y < num_irreps; irrep_y++ ){ const int irrep_z = Irreps::directProd( Irreps::directProd( irrep_left, irrep_x ), irrep_y ); const int d_y = indices->getDMRGcumulative( irrep_y ); const int num_y = indices->getNDMRG( irrep_y ); const int d_z = indices->getDMRGcumulative( irrep_z ); const int num_z = indices->getNDMRG( irrep_z ); assert( jump_row == jump_AC_active( indices, irrep_x, irrep_y, irrep_z ) ); if ( irrep_ut == irrep_left ){ // FAB_singlet[ xyz,tu ] -= delta_tw Gamma_zuyx for ( int u = w; u < num_ut; u++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zuyx = two_rdm[ d_z + z + LAS * ( d_ut + u + LAS * ( d_y + y + LAS * ( d_x + x ))) ]; ABptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + w + ( u * ( u + 1 ) ) / 2 ) ] -= gamma_zuyx; } } } } // FAB_singlet[ xyz,tu ] -= delta_tw delta_uy Gamma_zx if ( irrep_ut == irrep_y ){ for ( int x = 0; x < num_x; x++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zx = one_rdm[ d_z + z + LAS * ( d_x + x ) ]; for ( int uy = w; uy < num_y; uy++ ){ ABptr[ jump_row + x + num_x * ( uy + num_y * z ) + SIZE_left * ( jump_col + w + ( uy * ( uy + 1 ) ) / 2 ) ] -= gamma_zx; } } } } // FAB_singlet[ xyz,tu ] += 2 delta_tw delta_ux Gamma_zy if ( irrep_ut == irrep_x ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zy = one_rdm[ d_z + z + LAS * ( d_y + y ) ]; for ( int ux = w; ux < num_x; ux++ ){ ABptr[ jump_row + ux + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + w + ( ux * ( ux + 1 ) ) / 2 ) ] += 2 * gamma_zy; } } } } // FCF_singlet[ xyz,tu ] -= delta_tw Gamma_zxyu for ( int u = w; u < num_ut; u++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zxyu = two_rdm[ d_z + z + LAS * ( d_x + x + LAS * ( d_y + y + LAS * ( d_ut + u ))) ]; CFptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + w + ( u * ( u + 1 ) ) / 2 ) ] -= gamma_zxyu; } } } } // FCF_singlet[ xyz,tu ] -= delta_tw delta_xy Gamma_zu if ( irrep_x == irrep_y ){ for ( int u = w; u < num_ut; u++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zu = one_rdm[ d_z + z + LAS * ( d_ut + u ) ]; for ( int xy = 0; xy < num_x; xy++ ){ CFptr[ jump_row + xy + num_x * ( xy + num_x * z ) + SIZE_left * ( jump_col + w + ( u * ( u + 1 ) ) / 2 ) ] -= gamma_zu; } } } } // FAB_singlet[ xyz,tu ] -= delta_uw Gamma_ztyx for ( int t = 0; t <= w; t++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_ztyx = two_rdm[ d_z + z + LAS * ( d_ut + t + LAS * ( d_y + y + LAS * ( d_x + x ))) ]; ABptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + t + ( w * ( w + 1 ) ) / 2 ) ] -= gamma_ztyx; } } } } // FAB_singlet[ xyz,tu ] -= delta_uw delta_ty Gamma_zx if ( irrep_ut == irrep_y ){ for ( int x = 0; x < num_x; x++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zx = one_rdm[ d_z + z + LAS * ( d_x + x ) ]; for ( int ty = 0; ty <= w; ty++ ){ ABptr[ jump_row + x + num_x * ( ty + num_y * z ) + SIZE_left * ( jump_col + ty + ( w * ( w + 1 ) ) / 2 ) ] -= gamma_zx; } } } } // FAB_singlet[ xyz,tu ] += 2 delta_uw delta_tx Gamma_zy if ( irrep_ut == irrep_x ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zy = one_rdm[ d_z + z + LAS * ( d_y + y ) ]; for ( int tx = 0; tx <= w; tx++ ){ ABptr[ jump_row + tx + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + tx + ( w * ( w + 1 ) ) / 2 ) ] += 2 * gamma_zy; } } } } // FCF_singlet[ xyz,tu ] -= delta_uw Gamma_zxyt for ( int t = 0; t <= w; t++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zxyt = two_rdm[ d_z + z + LAS * ( d_x + x + LAS * ( d_y + y + LAS * ( d_ut + t ))) ]; CFptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + t + ( w * ( w + 1 ) ) / 2 ) ] -= gamma_zxyt; } } } } // FCF_singlet[ xyz,tu ] -= delta_uw delta_xy Gamma_zt if ( irrep_x == irrep_y ){ for ( int t = 0; t <= w; t++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zt = one_rdm[ d_z + z + LAS * ( d_ut + t ) ]; for ( int xy = 0; xy < num_x; xy++ ){ CFptr[ jump_row + xy + num_x * ( xy + num_x * z ) + SIZE_left * ( jump_col + t + ( w * ( w + 1 ) ) / 2 ) ] -= gamma_zt; } } } } } jump_row += num_x * num_y * num_z; } } jump_col += ( num_ut * ( num_ut + 1 ) ) / 2; } } } for ( int irrep_right = 1; irrep_right < num_irreps; irrep_right++ ){ assert( size_B_singlet[ irrep_right ] == size_F_singlet[ irrep_right ] ); // At construction const int SIZE_right = size_B_singlet[ irrep_right ]; const int irrep_w = Irreps::directProd( irrep_left, irrep_right ); const int num_w = indices->getNDMRG( irrep_w ); FAB_singlet[ irrep_left ][ irrep_right ] = new double*[ num_w ]; FCF_singlet[ irrep_left ][ irrep_right ] = new double*[ num_w ]; for ( int w = 0; w < num_w; w++ ){ FAB_singlet[ irrep_left ][ irrep_right ][ w ] = new double[ SIZE_left * SIZE_right ]; FCF_singlet[ irrep_left ][ irrep_right ][ w ] = new double[ SIZE_left * SIZE_right ]; double * ABptr = FAB_singlet[ irrep_left ][ irrep_right ][ w ]; double * CFptr = FCF_singlet[ irrep_left ][ irrep_right ][ w ]; int jump_col = 0; for ( int irrep_t = 0; irrep_t < num_irreps; irrep_t++ ){ const int irrep_u = Irreps::directProd( irrep_right, irrep_t ); if ( irrep_t < irrep_u ){ const int d_t = indices->getDMRGcumulative( irrep_t ); const int num_t = indices->getNDMRG( irrep_t ); const int d_u = indices->getDMRGcumulative( irrep_u ); const int num_u = indices->getNDMRG( irrep_u ); assert( jump_col == jump_BF_active( indices, irrep_t, irrep_u, +1 ) ); const int jump_AB1 = jump_AC_active( indices, irrep_u, irrep_t, irrep_w ); const int jump_AB2 = jump_AC_active( indices, irrep_t, irrep_u, irrep_w ); const int jump_CF1 = jump_AC_active( indices, irrep_u, irrep_w, irrep_t ); const int jump_CF2 = jump_AC_active( indices, irrep_t, irrep_w, irrep_u ); for ( int t = 0; t < num_t; t++ ){ for ( int u = 0; u < num_u; u++ ){ for ( int xyz = 0; xyz < SIZE_left; xyz++ ){ ABptr[ xyz + SIZE_left * ( jump_col + t + num_t * u ) ] = ( - SAA[ irrep_left ][ xyz + SIZE_left * ( jump_AB1 + u + num_u * ( t + num_t * w )) ] - SAA[ irrep_left ][ xyz + SIZE_left * ( jump_AB2 + t + num_t * ( u + num_u * w )) ] ); CFptr[ xyz + SIZE_left * ( jump_col + t + num_t * u ) ] = ( + SCC[ irrep_left ][ xyz + SIZE_left * ( jump_CF1 + u + num_u * ( w + num_w * t )) ] + SCC[ irrep_left ][ xyz + SIZE_left * ( jump_CF2 + t + num_t * ( w + num_w * u )) ] ); } } } int jump_row = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int d_x = indices->getDMRGcumulative( irrep_x ); const int num_x = indices->getNDMRG( irrep_x ); for ( int irrep_y = 0; irrep_y < num_irreps; irrep_y++ ){ const int irrep_z = Irreps::directProd( Irreps::directProd( irrep_left, irrep_x ), irrep_y ); const int d_y = indices->getDMRGcumulative( irrep_y ); const int num_y = indices->getNDMRG( irrep_y ); const int d_z = indices->getDMRGcumulative( irrep_z ); const int num_z = indices->getNDMRG( irrep_z ); assert( jump_row == jump_AC_active( indices, irrep_x, irrep_y, irrep_z ) ); if ( irrep_t == irrep_w ){ // FAB_singlet[ xyz,tu ] -= delta_tw Gamma_zuyx for ( int u = 0; u < num_u; u++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zuyx = two_rdm[ d_z + z + LAS * ( d_u + u + LAS * ( d_y + y + LAS * ( d_x + x ))) ]; ABptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + w + num_w * u ) ] -= gamma_zuyx; } } } } // FAB_singlet[ xyz,tu ] -= delta_tw delta_uy Gamma_zx if ( irrep_u == irrep_y ){ for ( int x = 0; x < num_x; x++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zx = one_rdm[ d_z + z + LAS * ( d_x + x ) ]; for ( int uy = 0; uy < num_y; uy++ ){ ABptr[ jump_row + x + num_x * ( uy + num_y * z ) + SIZE_left * ( jump_col + w + num_w * uy ) ] -= gamma_zx; } } } } // FAB_singlet[ xyz,tu ] += 2 delta_tw delta_ux Gamma_zy if ( irrep_u == irrep_x ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zy = one_rdm[ d_z + z + LAS * ( d_y + y ) ]; for ( int ux = 0; ux < num_x; ux++ ){ ABptr[ jump_row + ux + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + w + num_w * ux ) ] += 2 * gamma_zy; } } } } // FCF_singlet[ xyz,tu ] -= delta_tw Gamma_zxyu for ( int u = 0; u < num_u; u++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zxyu = two_rdm[ d_z + z + LAS * ( d_x + x + LAS * ( d_y + y + LAS * ( d_u + u ))) ]; CFptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + w + num_w * u ) ] -= gamma_zxyu; } } } } // FCF_singlet[ xyz,tu ] -= delta_tw delta_xy Gamma_zu if ( irrep_x == irrep_y ){ for ( int u = 0; u < num_u; u++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zu = one_rdm[ d_z + z + LAS * ( d_u + u ) ]; for ( int xy = 0; xy < num_x; xy++ ){ CFptr[ jump_row + xy + num_x * ( xy + num_x * z ) + SIZE_left * ( jump_col + w + num_w * u ) ] -= gamma_zu; } } } } } if ( irrep_u == irrep_w ){ // FAB_singlet[ xyz,tu ] -= delta_uw Gamma_ztyx for ( int t = 0; t < num_t; t++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_ztyx = two_rdm[ d_z + z + LAS * ( d_t + t + LAS * ( d_y + y + LAS * ( d_x + x ))) ]; ABptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + t + num_t * w ) ] -= gamma_ztyx; } } } } // FAB_singlet[ xyz,tu ] -= delta_uw delta_ty Gamma_zx if ( irrep_t == irrep_y ){ for ( int x = 0; x < num_x; x++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zx = one_rdm[ d_z + z + LAS * ( d_x + x ) ]; for ( int ty = 0; ty < num_y; ty++ ){ ABptr[ jump_row + x + num_x * ( ty + num_y * z ) + SIZE_left * ( jump_col + ty + num_y * w ) ] -= gamma_zx; } } } } // FAB_singlet[ xyz,tu ] += 2 delta_uw delta_tx Gamma_zy if ( irrep_t == irrep_x ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zy = one_rdm[ d_z + z + LAS * ( d_y + y ) ]; for ( int tx = 0; tx < num_x; tx++ ){ ABptr[ jump_row + tx + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + tx + num_x * w ) ] += 2 * gamma_zy; } } } } // FCF_singlet[ xyz,tu ] -= delta_uw Gamma_zxyt for ( int t = 0; t < num_t; t++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zxyt = two_rdm[ d_z + z + LAS * ( d_x + x + LAS * ( d_y + y + LAS * ( d_t + t ))) ]; CFptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + t + num_t * w ) ] -= gamma_zxyt; } } } } // FCF_singlet[ xyz,tu ] -= delta_uw delta_xy Gamma_zt if ( irrep_x == irrep_y ){ for ( int t = 0; t < num_t; t++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zt = one_rdm[ d_z + z + LAS * ( d_t + t ) ]; for ( int xy = 0; xy < num_x; xy++ ){ CFptr[ jump_row + xy + num_x * ( xy + num_x * z ) + SIZE_left * ( jump_col + t + num_t * w ) ] -= gamma_zt; } } } } } jump_row += num_x * num_y * num_z; } } jump_col += num_t * num_u; } } } } } } void CheMPS2::CASPT2::make_FAB_FCF_triplet(){ /* FAB triplet : < E_zy E_lx | E_kw | TB_tiuj > = ( delta_ik delta_jl - delta_jk delta_il ) / sqrt( 1 + delta_ij ) * FAB_triplet[ Il ][ Ii x Ij ][ w ][ xyz, tu ] FCF triplet : < E_zy E_xd | E_wc | TF_atbu > = ( delta_ac delta_bd - delta_ad delta_bc ) / sqrt( 1 + delta_ab ) * FCF_triplet[ Id ][ Ia x Ib ][ w ][ xyz, tu ] FAB_triplet[ Il ][ Ii x Ij ][ w ][ xyz, tu ] = ( + 6 delta_tw delta_ux Gamma_zy - 6 delta_uw delta_tx Gamma_zy - 3 delta_tw Gamma_zuyx - 3 delta_tw delta_uy Gamma_zx + 3 delta_uw Gamma_ztyx + 3 delta_uw delta_ty Gamma_zx - SAA[ Il ][ xyz, utw ] + SAA[ Il ][ xyz, tuw ] ) FCF_triplet[ Id ][ Ia x Ib ][ w ][ xyz, tu ] = ( + SCC[ Id ][ xyz, uwt ] - SCC[ Id ][ xyz, twu ] - delta_uw Gamma_zxyt - delta_uw delta_xy Gamma_zt + delta_tw Gamma_zxyu + delta_tw delta_xy Gamma_zu ) */ FAB_triplet = new double***[ num_irreps ]; FCF_triplet = new double***[ num_irreps ]; const int LAS = indices->getDMRGcumulative( num_irreps ); for ( int irrep_left = 0; irrep_left < num_irreps; irrep_left++ ){ assert( size_A[ irrep_left ] == size_C[ irrep_left ] ); // At construction const int SIZE_left = size_A[ irrep_left ]; FAB_triplet[ irrep_left ] = new double**[ num_irreps ]; FCF_triplet[ irrep_left ] = new double**[ num_irreps ]; { // irrep_right == 0 assert( size_B_triplet[ 0 ] == size_F_triplet[ 0 ] ); // At construction const int SIZE_right = size_B_triplet[ 0 ]; const int num_w = indices->getNDMRG( irrep_left ); FAB_triplet[ irrep_left ][ 0 ] = new double*[ num_w ]; FCF_triplet[ irrep_left ][ 0 ] = new double*[ num_w ]; for ( int w = 0; w < num_w; w++ ){ FAB_triplet[ irrep_left ][ 0 ][ w ] = new double[ SIZE_left * SIZE_right ]; FCF_triplet[ irrep_left ][ 0 ][ w ] = new double[ SIZE_left * SIZE_right ]; double * ABptr = FAB_triplet[ irrep_left ][ 0 ][ w ]; double * CFptr = FCF_triplet[ irrep_left ][ 0 ][ w ]; int jump_col = 0; for ( int irrep_ut = 0; irrep_ut < num_irreps; irrep_ut++ ){ const int d_ut = indices->getDMRGcumulative( irrep_ut ); const int num_ut = indices->getNDMRG( irrep_ut ); assert( jump_col == jump_BF_active( indices, irrep_ut, irrep_ut, -1 ) ); const int jump_AB = jump_AC_active( indices, irrep_ut, irrep_ut, irrep_left ); const int jump_CF = jump_AC_active( indices, irrep_ut, irrep_left, irrep_ut ); for ( int t = 0; t < num_ut; t++ ){ for ( int u = t+1; u < num_ut; u++ ){ // 0 <= t < u < num_ut for ( int xyz = 0; xyz < SIZE_left; xyz++ ){ ABptr[ xyz + SIZE_left * ( jump_col + t + ( u * ( u - 1 ) ) / 2 ) ] = ( - SAA[ irrep_left ][ xyz + SIZE_left * ( jump_AB + u + num_ut * ( t + num_ut * w )) ] + SAA[ irrep_left ][ xyz + SIZE_left * ( jump_AB + t + num_ut * ( u + num_ut * w )) ] ); CFptr[ xyz + SIZE_left * ( jump_col + t + ( u * ( u - 1 ) ) / 2 ) ] = ( + SCC[ irrep_left ][ xyz + SIZE_left * ( jump_CF + u + num_ut * ( w + num_w * t )) ] - SCC[ irrep_left ][ xyz + SIZE_left * ( jump_CF + t + num_ut * ( w + num_w * u )) ] ); } } } int jump_row = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int d_x = indices->getDMRGcumulative( irrep_x ); const int num_x = indices->getNDMRG( irrep_x ); for ( int irrep_y = 0; irrep_y < num_irreps; irrep_y++ ){ const int irrep_z = Irreps::directProd( Irreps::directProd( irrep_left, irrep_x ), irrep_y ); const int d_y = indices->getDMRGcumulative( irrep_y ); const int num_y = indices->getNDMRG( irrep_y ); const int d_z = indices->getDMRGcumulative( irrep_z ); const int num_z = indices->getNDMRG( irrep_z ); assert( jump_row == jump_AC_active( indices, irrep_x, irrep_y, irrep_z ) ); if ( irrep_ut == irrep_left ){ // FAB_triplet[ xyz,tu ] -= 3 delta_tw Gamma_zuyx for ( int u = w+1; u < num_ut; u++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zuyx = two_rdm[ d_z + z + LAS * ( d_ut + u + LAS * ( d_y + y + LAS * ( d_x + x ))) ]; ABptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + w + ( u * ( u - 1 ) ) / 2 ) ] -= 3 * gamma_zuyx; } } } } // FAB_triplet[ xyz,tu ] -= 3 delta_tw delta_uy Gamma_zx if ( irrep_ut == irrep_y ){ for ( int x = 0; x < num_x; x++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zx = one_rdm[ d_z + z + LAS * ( d_x + x ) ]; for ( int uy = w+1; uy < num_y; uy++ ){ ABptr[ jump_row + x + num_x * ( uy + num_y * z ) + SIZE_left * ( jump_col + w + ( uy * ( uy - 1 ) ) / 2 ) ] -= 3 * gamma_zx; } } } } // FAB_triplet[ xyz,tu ] += 6 delta_tw delta_ux Gamma_zy if ( irrep_ut == irrep_x ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zy = one_rdm[ d_z + z + LAS * ( d_y + y ) ]; for ( int ux = w+1; ux < num_x; ux++ ){ ABptr[ jump_row + ux + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + w + ( ux * ( ux - 1 ) ) / 2 ) ] += 6 * gamma_zy; } } } } // FCF_triplet[ xyz,tu ] += delta_tw Gamma_zxyu for ( int u = w+1; u < num_ut; u++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zxyu = two_rdm[ d_z + z + LAS * ( d_x + x + LAS * ( d_y + y + LAS * ( d_ut + u ))) ]; CFptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + w + ( u * ( u - 1 ) ) / 2 ) ] += gamma_zxyu; } } } } // FCF_triplet[ xyz,tu ] += delta_tw delta_xy Gamma_zu if ( irrep_x == irrep_y ){ for ( int u = w+1; u < num_ut; u++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zu = one_rdm[ d_z + z + LAS * ( d_ut + u ) ]; for ( int xy = 0; xy < num_x; xy++ ){ CFptr[ jump_row + xy + num_x * ( xy + num_x * z ) + SIZE_left * ( jump_col + w + ( u * ( u - 1 ) ) / 2 ) ] += gamma_zu; } } } } // FAB_triplet[ xyz,tu ] += 3 delta_uw Gamma_ztyx for ( int t = 0; t < w; t++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_ztyx = two_rdm[ d_z + z + LAS * ( d_ut + t + LAS * ( d_y + y + LAS * ( d_x + x ))) ]; ABptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + t + ( w * ( w - 1 ) ) / 2 ) ] += 3 * gamma_ztyx; } } } } // FAB_triplet[ xyz,tu ] += 3 delta_uw delta_ty Gamma_zx if ( irrep_ut == irrep_y ){ for ( int x = 0; x < num_x; x++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zx = one_rdm[ d_z + z + LAS * ( d_x + x ) ]; for ( int ty = 0; ty < w; ty++ ){ ABptr[ jump_row + x + num_x * ( ty + num_y * z ) + SIZE_left * ( jump_col + ty + ( w * ( w - 1 ) ) / 2 ) ] += 3 * gamma_zx; } } } } // FAB_triplet[ xyz,tu ] -= 6 delta_uw delta_tx Gamma_zy if ( irrep_ut == irrep_x ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zy = one_rdm[ d_z + z + LAS * ( d_y + y ) ]; for ( int tx = 0; tx < w; tx++ ){ ABptr[ jump_row + tx + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + tx + ( w * ( w - 1 ) ) / 2 ) ] -= 6 * gamma_zy; } } } } // FCF_triplet[ xyz,tu ] -= delta_uw Gamma_zxyt for ( int t = 0; t < w; t++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zxyt = two_rdm[ d_z + z + LAS * ( d_x + x + LAS * ( d_y + y + LAS * ( d_ut + t ))) ]; CFptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + t + ( w * ( w - 1 ) ) / 2 ) ] -= gamma_zxyt; } } } } // FCF_triplet[ xyz,tu ] -= delta_uw delta_xy Gamma_zt if ( irrep_x == irrep_y ){ for ( int t = 0; t < w; t++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zt = one_rdm[ d_z + z + LAS * ( d_ut + t ) ]; for ( int xy = 0; xy < num_x; xy++ ){ CFptr[ jump_row + xy + num_x * ( xy + num_x * z ) + SIZE_left * ( jump_col + t + ( w * ( w - 1 ) ) / 2 ) ] -= gamma_zt; } } } } } jump_row += num_x * num_y * num_z; } } jump_col += ( num_ut * ( num_ut - 1 ) ) / 2; } } } for ( int irrep_right = 1; irrep_right < num_irreps; irrep_right++ ){ assert( size_B_triplet[ irrep_right ] == size_F_triplet[ irrep_right ] ); // At construction const int SIZE_right = size_B_triplet[ irrep_right ]; const int irrep_w = Irreps::directProd( irrep_left, irrep_right ); const int num_w = indices->getNDMRG( irrep_w ); FAB_triplet[ irrep_left ][ irrep_right ] = new double*[ num_w ]; FCF_triplet[ irrep_left ][ irrep_right ] = new double*[ num_w ]; for ( int w = 0; w < num_w; w++ ){ FAB_triplet[ irrep_left ][ irrep_right ][ w ] = new double[ SIZE_left * SIZE_right ]; FCF_triplet[ irrep_left ][ irrep_right ][ w ] = new double[ SIZE_left * SIZE_right ]; double * ABptr = FAB_triplet[ irrep_left ][ irrep_right ][ w ]; double * CFptr = FCF_triplet[ irrep_left ][ irrep_right ][ w ]; int jump_col = 0; for ( int irrep_t = 0; irrep_t < num_irreps; irrep_t++ ){ const int irrep_u = Irreps::directProd( irrep_right, irrep_t ); if ( irrep_t < irrep_u ){ const int d_t = indices->getDMRGcumulative( irrep_t ); const int num_t = indices->getNDMRG( irrep_t ); const int d_u = indices->getDMRGcumulative( irrep_u ); const int num_u = indices->getNDMRG( irrep_u ); assert( jump_col == jump_BF_active( indices, irrep_t, irrep_u, -1 ) ); const int jump_AB1 = jump_AC_active( indices, irrep_u, irrep_t, irrep_w ); const int jump_AB2 = jump_AC_active( indices, irrep_t, irrep_u, irrep_w ); const int jump_CF1 = jump_AC_active( indices, irrep_u, irrep_w, irrep_t ); const int jump_CF2 = jump_AC_active( indices, irrep_t, irrep_w, irrep_u ); for ( int t = 0; t < num_t; t++ ){ for ( int u = 0; u < num_u; u++ ){ for ( int xyz = 0; xyz < SIZE_left; xyz++ ){ ABptr[ xyz + SIZE_left * ( jump_col + t + num_t * u ) ] = ( - SAA[ irrep_left ][ xyz + SIZE_left * ( jump_AB1 + u + num_u * ( t + num_t * w )) ] + SAA[ irrep_left ][ xyz + SIZE_left * ( jump_AB2 + t + num_t * ( u + num_u * w )) ] ); CFptr[ xyz + SIZE_left * ( jump_col + t + num_t * u ) ] = ( + SCC[ irrep_left ][ xyz + SIZE_left * ( jump_CF1 + u + num_u * ( w + num_w * t )) ] - SCC[ irrep_left ][ xyz + SIZE_left * ( jump_CF2 + t + num_t * ( w + num_w * u )) ] ); } } } int jump_row = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int d_x = indices->getDMRGcumulative( irrep_x ); const int num_x = indices->getNDMRG( irrep_x ); for ( int irrep_y = 0; irrep_y < num_irreps; irrep_y++ ){ const int irrep_z = Irreps::directProd( Irreps::directProd( irrep_left, irrep_x ), irrep_y ); const int d_y = indices->getDMRGcumulative( irrep_y ); const int num_y = indices->getNDMRG( irrep_y ); const int d_z = indices->getDMRGcumulative( irrep_z ); const int num_z = indices->getNDMRG( irrep_z ); assert( jump_row == jump_AC_active( indices, irrep_x, irrep_y, irrep_z ) ); if ( irrep_t == irrep_w ){ // FAB_triplet[ xyz,tu ] -= 3 delta_tw Gamma_zuyx for ( int u = 0; u < num_u; u++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zuyx = two_rdm[ d_z + z + LAS * ( d_u + u + LAS * ( d_y + y + LAS * ( d_x + x ))) ]; ABptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + w + num_w * u ) ] -= 3 * gamma_zuyx; } } } } // FAB_triplet[ xyz,tu ] -= 3 delta_tw delta_uy Gamma_zx if ( irrep_u == irrep_y ){ for ( int x = 0; x < num_x; x++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zx = one_rdm[ d_z + z + LAS * ( d_x + x ) ]; for ( int uy = 0; uy < num_y; uy++ ){ ABptr[ jump_row + x + num_x * ( uy + num_y * z ) + SIZE_left * ( jump_col + w + num_w * uy ) ] -= 3 * gamma_zx; } } } } // FAB_triplet[ xyz,tu ] += 6 delta_tw delta_ux Gamma_zy if ( irrep_u == irrep_x ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zy = one_rdm[ d_z + z + LAS * ( d_y + y ) ]; for ( int ux = 0; ux < num_x; ux++ ){ ABptr[ jump_row + ux + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + w + num_w * ux ) ] += 6 * gamma_zy; } } } } // FCF_triplet[ xyz,tu ] += delta_tw Gamma_zxyu for ( int u = 0; u < num_u; u++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zxyu = two_rdm[ d_z + z + LAS * ( d_x + x + LAS * ( d_y + y + LAS * ( d_u + u ))) ]; CFptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + w + num_w * u ) ] += gamma_zxyu; } } } } // FCF_triplet[ xyz,tu ] += delta_tw delta_xy Gamma_zu if ( irrep_x == irrep_y ){ for ( int u = 0; u < num_u; u++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zu = one_rdm[ d_z + z + LAS * ( d_u + u ) ]; for ( int xy = 0; xy < num_x; xy++ ){ CFptr[ jump_row + xy + num_x * ( xy + num_x * z ) + SIZE_left * ( jump_col + w + num_w * u ) ] += gamma_zu; } } } } } if ( irrep_u == irrep_w ){ // FAB_triplet[ xyz,tu ] += 3 * delta_uw Gamma_ztyx for ( int t = 0; t < num_t; t++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_ztyx = two_rdm[ d_z + z + LAS * ( d_t + t + LAS * ( d_y + y + LAS * ( d_x + x ))) ]; ABptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + t + num_t * w ) ] += 3 * gamma_ztyx; } } } } // FAB_triplet[ xyz,tu ] += 3 * delta_uw delta_ty Gamma_zx if ( irrep_t == irrep_y ){ for ( int x = 0; x < num_x; x++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zx = one_rdm[ d_z + z + LAS * ( d_x + x ) ]; for ( int ty = 0; ty < num_y; ty++ ){ ABptr[ jump_row + x + num_x * ( ty + num_y * z ) + SIZE_left * ( jump_col + ty + num_y * w ) ] += 3 * gamma_zx; } } } } // FAB_triplet[ xyz,tu ] -= 6 delta_uw delta_tx Gamma_zy if ( irrep_t == irrep_x ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zy = one_rdm[ d_z + z + LAS * ( d_y + y ) ]; for ( int tx = 0; tx < num_x; tx++ ){ ABptr[ jump_row + tx + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + tx + num_x * w ) ] -= 6 * gamma_zy; } } } } // FCF_triplet[ xyz,tu ] -= delta_uw Gamma_zxyt for ( int t = 0; t < num_t; t++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zxyt = two_rdm[ d_z + z + LAS * ( d_x + x + LAS * ( d_y + y + LAS * ( d_t + t ))) ]; CFptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + t + num_t * w ) ] -= gamma_zxyt; } } } } // FCF_triplet[ xyz,tu ] -= delta_uw delta_xy Gamma_zt if ( irrep_x == irrep_y ){ for ( int t = 0; t < num_t; t++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zt = one_rdm[ d_z + z + LAS * ( d_t + t ) ]; for ( int xy = 0; xy < num_x; xy++ ){ CFptr[ jump_row + xy + num_x * ( xy + num_x * z ) + SIZE_left * ( jump_col + t + num_t * w ) ] -= gamma_zt; } } } } } jump_row += num_x * num_y * num_z; } } jump_col += num_t * num_u; } } } } } } void CheMPS2::CASPT2::make_FAD_FCD(){ /* FAD1: < E_zy E_jx E_wc E_ai E_tu > = delta_ac delta_ij FAD1[ Ij ][ Ii x Ia ][ w ][ xyz, tu ] FAD2: < E_zy E_jx E_wc E_ti E_au > = delta_ac delta_ij FAD2[ Ij ][ Ii x Ia ][ w ][ xyz, tu ] FCD1: < E_zy E_xb E_kw E_ai E_tu > = delta_ik delta_ab FCD1[ Ib ][ Ii x Ia ][ w ][ xyz, tu ] FCD2: < E_zy E_xb E_kw E_ti E_au > = delta_ik delta_ab FCD2[ Ib ][ Ii x Ia ][ w ][ xyz, tu ] FAD1[ Ij ][ Ii x Ia ][ w ][ xyz, tu ] = + SAA[ Ij ][ xyzwtu ] FAD2[ Ij ][ Ii x Ia ][ w ][ xyz, tu ] = + SAA[ Ij ][ xyztwu ] FCD1[ Ib ][ Ii x Ia ][ w ][ xyz, tu ] = - SCC[ Ib ][ xyzwtu ] FCD2[ Ib ][ Ii x Ia ][ w ][ xyz, tu ] = ( + 2 delta_tw Gamma_zxyu + 2 delta_tw delta_xy Gamma_zu + delta_tu Gamma_zxyw + delta_tu delta_xy Gamma_zw - SCC[ Ib ][ xyzutw ] ) */ FAD = new double***[ num_irreps ]; FCD = new double***[ num_irreps ]; const int LAS = indices->getDMRGcumulative( num_irreps ); for ( int irrep_left = 0; irrep_left < num_irreps; irrep_left++ ){ assert( size_A[ irrep_left ] == size_C[ irrep_left ] ); // At construction const int SIZE_left = size_A[ irrep_left ]; FAD[ irrep_left ] = new double**[ num_irreps ]; FCD[ irrep_left ] = new double**[ num_irreps ]; for ( int irrep_right = 0; irrep_right < num_irreps; irrep_right++ ){ const int SIZE_right = size_D[ irrep_right ]; const int D2JUMP = SIZE_right / 2; const int irrep_w = Irreps::directProd( irrep_left, irrep_right ); const int d_w = indices->getDMRGcumulative( irrep_w ); const int num_w = indices->getNDMRG( irrep_w ); FAD[ irrep_left ][ irrep_right ] = new double*[ num_w ]; FCD[ irrep_left ][ irrep_right ] = new double*[ num_w ]; for ( int w = 0; w < num_w; w++ ){ FAD[ irrep_left ][ irrep_right ][ w ] = new double[ SIZE_left * SIZE_right ]; FCD[ irrep_left ][ irrep_right ][ w ] = new double[ SIZE_left * SIZE_right ]; double * AD1ptr = FAD[ irrep_left ][ irrep_right ][ w ]; double * AD2ptr = FAD[ irrep_left ][ irrep_right ][ w ] + SIZE_left * D2JUMP; double * CD1ptr = FCD[ irrep_left ][ irrep_right ][ w ]; double * CD2ptr = FCD[ irrep_left ][ irrep_right ][ w ] + SIZE_left * D2JUMP; int jump_col = 0; for ( int irrep_t = 0; irrep_t < num_irreps; irrep_t++ ){ const int irrep_u = Irreps::directProd( irrep_right, irrep_t ); const int num_t = indices->getNDMRG( irrep_t ); const int d_u = indices->getDMRGcumulative( irrep_u ); const int num_u = indices->getNDMRG( irrep_u ); const int jump_AD1 = jump_AC_active( indices, irrep_w, irrep_t, irrep_u ); const int jump_AD2 = jump_AC_active( indices, irrep_t, irrep_w, irrep_u ); const int jump_CD2 = jump_AC_active( indices, irrep_u, irrep_t, irrep_w ); for ( int t = 0; t < num_t; t++ ){ for ( int u = 0; u < num_u; u++ ){ for ( int xyz = 0; xyz < SIZE_left; xyz++ ){ AD1ptr[ xyz + SIZE_left * ( jump_col + t + num_t * u ) ] = + SAA[ irrep_left ][ xyz + SIZE_left * ( jump_AD1 + w + num_w * ( t + num_t * u )) ]; AD2ptr[ xyz + SIZE_left * ( jump_col + t + num_t * u ) ] = + SAA[ irrep_left ][ xyz + SIZE_left * ( jump_AD2 + t + num_t * ( w + num_w * u )) ]; CD1ptr[ xyz + SIZE_left * ( jump_col + t + num_t * u ) ] = - SCC[ irrep_left ][ xyz + SIZE_left * ( jump_AD1 + w + num_w * ( t + num_t * u )) ]; CD2ptr[ xyz + SIZE_left * ( jump_col + t + num_t * u ) ] = - SCC[ irrep_left ][ xyz + SIZE_left * ( jump_CD2 + u + num_u * ( t + num_t * w )) ]; } } } int jump_row = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int d_x = indices->getDMRGcumulative( irrep_x ); const int num_x = indices->getNDMRG( irrep_x ); for ( int irrep_y = 0; irrep_y < num_irreps; irrep_y++ ){ const int irrep_z = Irreps::directProd( Irreps::directProd( irrep_left, irrep_x ), irrep_y ); const int d_y = indices->getDMRGcumulative( irrep_y ); const int num_y = indices->getNDMRG( irrep_y ); const int d_z = indices->getDMRGcumulative( irrep_z ); const int num_z = indices->getNDMRG( irrep_z ); assert( jump_row == jump_AC_active( indices, irrep_x, irrep_y, irrep_z ) ); if ( irrep_t == irrep_w ){ // + 2 delta_tw Gamma_zxyu for ( int u = 0; u < num_u; u++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zxyu = two_rdm[ d_z + z + LAS * ( d_x + x + LAS * ( d_y + y + LAS * ( d_u + u ))) ]; CD2ptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + w + num_t * u ) ] += 2 * gamma_zxyu; } } } } // + 2 delta_tw delta_xy Gamma_zu if ( irrep_x == irrep_y ){ for ( int u = 0; u < num_u; u++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zu = one_rdm[ d_z + z + LAS * ( d_u + u ) ]; for ( int xy = 0; xy < num_x; xy++ ){ CD2ptr[ jump_row + xy + num_x * ( xy + num_x * z ) + SIZE_left * ( jump_col + w + num_t * u ) ] += 2 * gamma_zu; } } } } } if ( irrep_t == irrep_u ){ // + delta_tu Gamma_zxyw for ( int tu = 0; tu < num_u; tu++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zxyw = two_rdm[ d_z + z + LAS * ( d_x + x + LAS * ( d_y + y + LAS * ( d_w + w ))) ]; CD2ptr[ jump_row + x + num_x * ( y + num_y * z ) + SIZE_left * ( jump_col + tu + num_u * tu ) ] += gamma_zxyw; } } } } // + delta_tu delta_xy Gamma_zw if ( irrep_x == irrep_y ){ for ( int z = 0; z < num_z; z++ ){ const double gamma_zw = one_rdm[ d_z + z + LAS * ( d_w + w ) ]; for ( int tu = 0; tu < num_u; tu++ ){ for ( int xy = 0; xy < num_x; xy++ ){ CD2ptr[ jump_row + xy + num_x * ( xy + num_x * z ) + SIZE_left * ( jump_col + tu + num_u * tu ) ] += gamma_zw; } } } } } jump_row += num_x * num_y * num_z; } } jump_col += num_t * num_u; } } } } } void CheMPS2::CASPT2::make_AA_CC( const bool OVLP, const double IPEA ){ /* SAA: < E_zy E_jx | 1 | E_ti E_uv > = delta_ij ( SAA[ Ii ][ xyztuv ] ) FAA: < E_zy E_jx | F | E_ti E_uv > = delta_ij ( FAA[ Ii ][ xyztuv ] + ( 2 sum_k f_kk - f_ii ) SAA[ Ii ][ xyztuv ] ) SAA[ Ii ][ xyztuv ] = ( - Gamma_{ztuyxv} + 2 delta_tx Gamma_{zuyv} - delta_uy Gamma_{tzxv} - delta_ty Gamma_{zuxv} - delta_ux Gamma_{ztyv} + ( 2 delta_tx delta_uy - delta_ux delta_ty ) Gamma_{zv} ) FAA[ Ii ][ xyztuv ] = ( - f_dot_4dm[ ztuyxv ] + ( f_tt + f_uu + f_xx + f_yy ) SAA[ Ii ][ xyztuv ] + 2 delta_tx ( f_dot_3dm[ zuyv ] - f_tt Gamma_{zuyv} ) - delta_uy ( f_dot_3dm[ ztvx ] - f_uu Gamma_{ztvx} ) - delta_ty ( f_dot_3dm[ zuxv ] - f_tt Gamma_{zuxv} ) - delta_ux ( f_dot_3dm[ ztyv ] - f_uu Gamma_{ztyv} ) + ( 2 delta_tx delta_uy - delta_ux delta_ty ) ( f_dot_2dm[ zv ] - ( f_tt + f_uu ) Gamma_{zv} ) ) SCC: < E_zy E_xb | 1 | E_at E_uv > = delta_ab ( SCC[ Ia ][ xyztuv ] ) FCC: < E_zy E_xb | F | E_at E_uv > = delta_ab ( FCC[ Ia ][ xyztuv ] + ( 2 sum_k f_kk + f_aa ) SCC[ Ia ][ xyztuv ] ) SCC[ Ia ][ xyztuv ] = ( + Gamma_{zxuytv} + delta_uy Gamma_{xztv} + delta_xy Gamma_{zutv} + delta_ut Gamma_{zxyv} + delta_ut delta_xy Gamma_{zv} ) FCC[ Ia ][ xyztuv ] = ( + f_dot_4dm[ zxuytv ] + ( f_uu + f_yy ) SCC[ Ia ][ xyztuv ] + delta_uy ( f_dot_3dm[ xztv ] - f_uu Gamma_{xztv} ) + delta_xy ( f_dot_3dm[ zutv ] - f_xx Gamma_{zutv} ) + delta_ut ( f_dot_3dm[ zxyv ] - f_tt Gamma_{zxyv} ) + delta_ut delta_xy ( f_dot_2dm[ zv ] - ( f_tt + f_xx ) Gamma_{zv} ) ) */ if ( OVLP ){ SAA = new double*[ num_irreps ]; SCC = new double*[ num_irreps ]; } else { FAA = new double*[ num_irreps ]; FCC = new double*[ num_irreps ]; } const int LAS = indices->getDMRGcumulative( num_irreps ); for ( int irrep = 0; irrep < num_irreps; irrep++ ){ assert( size_A[ irrep ] == size_C[ irrep ] ); // At construction const int SIZE = size_A[ irrep ]; if ( OVLP ){ SAA[ irrep ] = new double[ SIZE * SIZE ]; SCC[ irrep ] = new double[ SIZE * SIZE ]; } else { FAA[ irrep ] = new double[ SIZE * SIZE ]; FCC[ irrep ] = new double[ SIZE * SIZE ]; } int jump_col = 0; for ( int irrep_t = 0; irrep_t < num_irreps; irrep_t++ ){ const int d_t = indices->getDMRGcumulative( irrep_t ); const int num_t = indices->getNDMRG( irrep_t ); const int nocc_t = indices->getNOCC( irrep_t ); for ( int irrep_u = 0; irrep_u < num_irreps; irrep_u++ ){ const int d_u = indices->getDMRGcumulative( irrep_u ); const int num_u = indices->getNDMRG( irrep_u ); const int nocc_u = indices->getNOCC( irrep_u ); const int irrep_v = Irreps::directProd( Irreps::directProd( irrep, irrep_t ), irrep_u ); const int d_v = indices->getDMRGcumulative( irrep_v ); const int num_v = indices->getNDMRG( irrep_v ); int jump_row = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int d_x = indices->getDMRGcumulative( irrep_x ); const int num_x = indices->getNDMRG( irrep_x ); const int nocc_x = indices->getNOCC( irrep_x ); for ( int irrep_y = 0; irrep_y < num_irreps; irrep_y++ ){ const int d_y = indices->getDMRGcumulative( irrep_y ); const int num_y = indices->getNDMRG( irrep_y ); const int nocc_y = indices->getNOCC( irrep_y ); const int irrep_z = Irreps::directProd( Irreps::directProd( irrep, irrep_x ), irrep_y ); const int d_z = indices->getDMRGcumulative( irrep_z ); const int num_z = indices->getNDMRG( irrep_z ); // SAA: - Gamma_{ztuyxv} // FAA: - f_dot_4dm[ ztuyxv ] + ( f_tt + f_uu + f_xx + f_yy ) SAA[ Ii ][ xyztuv ] if ( OVLP ){ #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int u = 0; u < num_u; u++ ){ for ( int t = 0; t < num_t; t++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ const int ptr = jump_row + x + num_x * ( y + num_y * z ) + SIZE * ( jump_col + t + num_t * ( u + num_u * v ) ); SAA[ irrep ][ ptr ] = - three_rdm[ d_z + z + LAS * ( d_t + t + LAS * ( d_u + u + LAS * ( d_y + y + LAS * ( d_x + x + LAS * ( d_v + v ))))) ]; } } } } } } } else { #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int u = 0; u < num_u; u++ ){ const double f_uu = fock->get( irrep_u, nocc_u + u, nocc_u + u ); for ( int t = 0; t < num_t; t++ ){ const double f_tt = fock->get( irrep_t, nocc_t + t, nocc_t + t ); for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ const double f_yy = fock->get( irrep_y, nocc_y + y, nocc_y + y ); for ( int x = 0; x < num_x; x++ ){ const double f_xx = fock->get( irrep_x, nocc_x + x, nocc_x + x ); const int ptr = jump_row + x + num_x * ( y + num_y * z ) + SIZE * ( jump_col + t + num_t * ( u + num_u * v ) ); FAA[ irrep ][ ptr ] = - f_dot_4dm[ d_z + z + LAS * ( d_t + t + LAS * ( d_u + u + LAS * ( d_y + y + LAS * ( d_x + x + LAS * ( d_v + v ))))) ] + ( f_tt + f_uu + f_xx + f_yy ) * SAA[ irrep ][ ptr ]; } } } } } } } // SCC: + Gamma_{zxuytv} // FCC: + f_dot_4dm[ zxuytv ] + ( f_uu + f_yy ) SCC[ Ia ][ xyztuv ] if ( OVLP ){ #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int u = 0; u < num_u; u++ ){ for ( int t = 0; t < num_t; t++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ const int ptr = jump_row + x + num_x * ( y + num_y * z ) + SIZE * ( jump_col + t + num_t * ( u + num_u * v ) ); SCC[ irrep ][ ptr ] = three_rdm[ d_z + z + LAS * ( d_x + x + LAS * ( d_u + u + LAS * ( d_y + y + LAS * ( d_t + t + LAS * ( d_v + v ))))) ]; } } } } } } } else { #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int u = 0; u < num_u; u++ ){ const double f_uu = fock->get( irrep_u, nocc_u + u, nocc_u + u ); for ( int t = 0; t < num_t; t++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ const double f_yy = fock->get( irrep_y, nocc_y + y, nocc_y + y ); for ( int x = 0; x < num_x; x++ ){ const int ptr = jump_row + x + num_x * ( y + num_y * z ) + SIZE * ( jump_col + t + num_t * ( u + num_u * v ) ); FCC[ irrep ][ ptr ] = f_dot_4dm[ d_z + z + LAS * ( d_x + x + LAS * ( d_u + u + LAS * ( d_y + y + LAS * ( d_t + t + LAS * ( d_v + v ))))) ] + ( f_yy + f_uu ) * SCC[ irrep ][ ptr ]; } } } } } } } // SAA: + 2 delta_tx Gamma_{zuyv} // FAA: + 2 delta_tx ( f_dot_3dm[ zuyv ] - f_tt Gamma_{zuyv} ) if ( irrep_t == irrep_x ){ if ( OVLP ){ #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int u = 0; u < num_u; u++ ){ for ( int xt = 0; xt < num_t; xt++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ SAA[ irrep ][ jump_row + xt + num_x * ( y + num_y * z ) + SIZE * ( jump_col + xt + num_t * ( u + num_u * v ) ) ] += 2 * two_rdm[ d_z + z + LAS * ( d_u + u + LAS * ( d_y + y + LAS * ( d_v + v ))) ]; } } } } } } else { #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int u = 0; u < num_u; u++ ){ for ( int tx = 0; tx < num_t; tx++ ){ const double f_tt = fock->get( irrep_t, nocc_t + tx, nocc_t + tx ); for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ FAA[ irrep ][ jump_row + tx + num_x * ( y + num_y * z ) + SIZE * ( jump_col + tx + num_t * ( u + num_u * v ) ) ] += 2 * ( f_dot_3dm[ d_z + z + LAS * ( d_u + u + LAS * ( d_y + y + LAS * ( d_v + v ))) ] - f_tt * two_rdm[ d_z + z + LAS * ( d_u + u + LAS * ( d_y + y + LAS * ( d_v + v ))) ] ); } } } } } } } // SAA: - delta_uy Gamma_{ztvx} // FAA: - delta_uy ( f_dot_3dm[ ztvx ] - f_uu Gamma_{ztvx} ) if ( irrep_u == irrep_y ){ if ( OVLP ){ #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int uy = 0; uy < num_u; uy++ ){ for ( int t = 0; t < num_t; t++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int x = 0; x < num_x; x++ ){ SAA[ irrep ][ jump_row + x + num_x * ( uy + num_y * z ) + SIZE * ( jump_col + t + num_t * ( uy + num_u * v ) ) ] -= two_rdm[ d_t + t + LAS * ( d_z + z + LAS * ( d_x + x + LAS * ( d_v + v ))) ]; } } } } } } else { #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int uy = 0; uy < num_u; uy++ ){ const double f_uu = fock->get( irrep_u, nocc_u + uy, nocc_u + uy ); for ( int t = 0; t < num_t; t++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int x = 0; x < num_x; x++ ){ FAA[ irrep ][ jump_row + x + num_x * ( uy + num_y * z ) + SIZE * ( jump_col + t + num_t * ( uy + num_u * v ) ) ] -= ( f_dot_3dm[ d_t + t + LAS * ( d_z + z + LAS * ( d_x + x + LAS * ( d_v + v ))) ] - f_uu * two_rdm[ d_t + t + LAS * ( d_z + z + LAS * ( d_x + x + LAS * ( d_v + v ))) ] ); } } } } } } } // SAA: - delta_ty Gamma_{zuxv} // FAA: - delta_ty ( f_dot_3dm[ zuxv ] - f_tt Gamma_{zuxv} ) if ( irrep_t == irrep_y ){ if ( OVLP ){ #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int u = 0; u < num_u; u++ ){ for ( int ty = 0; ty < num_t; ty++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int x = 0; x < num_x; x++ ){ SAA[ irrep ][ jump_row + x + num_x * ( ty + num_y * z ) + SIZE * ( jump_col + ty + num_t * ( u + num_u * v ) ) ] -= two_rdm[ d_z + z + LAS * ( d_u + u + LAS * ( d_x + x + LAS * ( d_v + v ))) ]; } } } } } } else { #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int u = 0; u < num_u; u++ ){ for ( int ty = 0; ty < num_t; ty++ ){ const double f_tt = fock->get( irrep_t, nocc_t + ty, nocc_t + ty ); for ( int z = 0; z < num_z; z++ ){ for ( int x = 0; x < num_x; x++ ){ FAA[ irrep ][ jump_row + x + num_x * ( ty + num_y * z ) + SIZE * ( jump_col + ty + num_t * ( u + num_u * v ) ) ] -= ( f_dot_3dm[ d_z + z + LAS * ( d_u + u + LAS * ( d_x + x + LAS * ( d_v + v ))) ] - f_tt * two_rdm[ d_z + z + LAS * ( d_u + u + LAS * ( d_x + x + LAS * ( d_v + v ))) ] ); } } } } } } } // SAA: - delta_ux Gamma_{ztyv} // FAA: - delta_ux ( f_dot_3dm[ ztyv ] - f_uu Gamma_{ztyv} ) if ( irrep_u == irrep_x ){ if ( OVLP ){ #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int ux = 0; ux < num_u; ux++ ){ for ( int t = 0; t < num_t; t++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ SAA[ irrep ][ jump_row + ux + num_x * ( y + num_y * z ) + SIZE * ( jump_col + t + num_t * ( ux + num_u * v ) ) ] -= two_rdm[ d_z + z + LAS * ( d_t + t + LAS * ( d_y + y + LAS * ( d_v + v ))) ]; } } } } } } else { #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int ux = 0; ux < num_u; ux++ ){ const double f_uu = fock->get( irrep_u, nocc_u + ux, nocc_u + ux ); for ( int t = 0; t < num_t; t++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ FAA[ irrep ][ jump_row + ux + num_x * ( y + num_y * z ) + SIZE * ( jump_col + t + num_t * ( ux + num_u * v ) ) ] -= ( f_dot_3dm[ d_z + z + LAS * ( d_t + t + LAS * ( d_y + y + LAS * ( d_v + v ))) ] - f_uu * two_rdm[ d_z + z + LAS * ( d_t + t + LAS * ( d_y + y + LAS * ( d_v + v ))) ] ); } } } } } } } // SCC: + delta_uy Gamma_{xztv} // FCC: + delta_uy ( f_dot_3dm[ xztv ] - f_uu Gamma_{xztv} ) if ( irrep_u == irrep_y ){ if ( OVLP ){ #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int uy = 0; uy < num_u; uy++ ){ for ( int t = 0; t < num_t; t++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int x = 0; x < num_x; x++ ){ SCC[ irrep ][ jump_row + x + num_x * ( uy + num_y * z ) + SIZE * ( jump_col + t + num_t * ( uy + num_u * v ) ) ] += two_rdm[ d_x + x + LAS * ( d_z + z + LAS * ( d_t + t + LAS * ( d_v + v ))) ]; } } } } } } else { #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int uy = 0; uy < num_y; uy++ ){ const double f_uu = fock->get( irrep_y, nocc_y + uy, nocc_y + uy ); for ( int t = 0; t < num_t; t++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int x = 0; x < num_x; x++ ){ FCC[ irrep ][ jump_row + x + num_x * ( uy + num_y * z ) + SIZE * ( jump_col + t + num_t * ( uy + num_y * v ) ) ] += ( f_dot_3dm[ d_x + x + LAS * ( d_z + z + LAS * ( d_t + t + LAS * ( d_v + v ))) ] - f_uu * two_rdm[ d_x + x + LAS * ( d_z + z + LAS * ( d_t + t + LAS * ( d_v + v ))) ] ); } } } } } } } // SCC: + delta_xy Gamma_{zutv} // FCC: + delta_xy ( f_dot_3dm[ zutv ] - f_xx Gamma_{zutv} ) if ( irrep_x == irrep_y ){ if ( OVLP ){ #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int u = 0; u < num_u; u++ ){ for ( int t = 0; t < num_t; t++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int xy = 0; xy < num_x; xy++ ){ SCC[ irrep ][ jump_row + xy + num_x * ( xy + num_y * z ) + SIZE * ( jump_col + t + num_t * ( u + num_u * v ) ) ] += two_rdm[ d_z + z + LAS * ( d_u + u + LAS * ( d_t + t + LAS * ( d_v + v ))) ]; } } } } } } else { #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int u = 0; u < num_u; u++ ){ for ( int t = 0; t < num_t; t++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int xy = 0; xy < num_x; xy++ ){ const double f_xx = fock->get( irrep_x, nocc_x + xy, nocc_x + xy ); FCC[ irrep ][ jump_row + xy + num_x * ( xy + num_x * z ) + SIZE * ( jump_col + t + num_t * ( u + num_u * v ) ) ] += ( f_dot_3dm[ d_z + z + LAS * ( d_u + u + LAS * ( d_t + t + LAS * ( d_v + v ))) ] - f_xx * two_rdm[ d_z + z + LAS * ( d_u + u + LAS * ( d_t + t + LAS * ( d_v + v ))) ] ); } } } } } } } // SCC: + delta_ut Gamma_{zxyv} // FCC: + delta_ut ( f_dot_3dm[ zxyv ] - f_tt Gamma_{zxyv} ) if ( irrep_u == irrep_t ){ if ( OVLP ){ #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int ut = 0; ut < num_u; ut++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ SCC[ irrep ][ jump_row + x + num_x * ( y + num_y * z ) + SIZE * ( jump_col + ut + num_t * ( ut + num_u * v ) ) ] += two_rdm[ d_z + z + LAS * ( d_x + x + LAS * ( d_y + y + LAS * ( d_v + v ))) ]; } } } } } } else { #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int ut = 0; ut < num_u; ut++ ){ const double f_tt = fock->get( irrep_t, nocc_t + ut, nocc_t + ut ); for ( int z = 0; z < num_z; z++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ FCC[ irrep ][ jump_row + x + num_x * ( y + num_y * z ) + SIZE * ( jump_col + ut + num_u * ( ut + num_u * v ) ) ] += ( f_dot_3dm[ d_z + z + LAS * ( d_x + x + LAS * ( d_y + y + LAS * ( d_v + v ))) ] - f_tt * two_rdm[ d_z + z + LAS * ( d_x + x + LAS * ( d_y + y + LAS * ( d_v + v ))) ] ); } } } } } } } // SAA: + 2 delta_tx delta_uy Gamma_{zv} // FAA: + 2 delta_tx delta_uy ( f_dot_2dm[ zv ] - ( f_tt + f_uu ) Gamma_{zv} ) if (( irrep_t == irrep_x ) && ( irrep_u == irrep_y ) && ( irrep_z == irrep_v )){ if ( OVLP ){ #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int uy = 0; uy < num_u; uy++ ){ for ( int xt = 0; xt < num_t; xt++ ){ SAA[ irrep ][ jump_row + xt + num_x * ( uy + num_y * z ) + SIZE * ( jump_col + xt + num_t * ( uy + num_u * v ) ) ] += 2 * one_rdm[ d_z + z + LAS * ( d_v + v ) ]; } } } } } else { #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int uy = 0; uy < num_u; uy++ ){ const double f_uu = fock->get( irrep_u, nocc_u + uy, nocc_u + uy ); for ( int xt = 0; xt < num_t; xt++ ){ const double f_tt = fock->get( irrep_t, nocc_t + xt, nocc_t + xt ); FAA[ irrep ][ jump_row + xt + num_x * ( uy + num_y * z ) + SIZE * ( jump_col + xt + num_t * ( uy + num_u * v ) ) ] += 2 * ( f_dot_2dm[ d_z + z + LAS * ( d_v + v ) ] - ( f_tt + f_uu ) * one_rdm[ d_z + z + LAS * ( d_v + v ) ] ); } } } } } } // SAA: - delta_ux delta_ty Gamma_{zv} // FAA: - delta_ux delta_ty ( f_dot_2dm[ zv ] - ( f_tt + f_uu ) Gamma_{zv} ) if (( irrep_u == irrep_x ) && ( irrep_t == irrep_y ) && ( irrep_z == irrep_v )){ if ( OVLP ){ #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int ux = 0; ux < num_u; ux++ ){ for ( int ty = 0; ty < num_t; ty++ ){ SAA[ irrep ][ jump_row + ux + num_x * ( ty + num_y * z ) + SIZE * ( jump_col + ty + num_t * ( ux + num_u * v ) ) ] -= one_rdm[ d_z + z + LAS * ( d_v + v ) ]; } } } } } else { #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int ux = 0; ux < num_u; ux++ ){ const double f_uu = fock->get( irrep_u, nocc_u + ux, nocc_u + ux ); for ( int ty = 0; ty < num_t; ty++ ){ const double f_tt = fock->get( irrep_t, nocc_t + ty, nocc_t + ty ); FAA[ irrep ][ jump_row + ux + num_x * ( ty + num_y * z ) + SIZE * ( jump_col + ty + num_t * ( ux + num_u * v ) ) ] -= ( f_dot_2dm[ d_z + z + LAS * ( d_v + v ) ] - ( f_tt + f_uu ) * one_rdm[ d_z + z + LAS * ( d_v + v ) ] ); } } } } } } // SCC: + delta_ut delta_xy Gamma_{zv} // FCC: + delta_ut delta_xy ( f_dot_2dm[ zv ] - ( f_tt + f_xx ) Gamma_{zv} ) if (( irrep_u == irrep_t ) && ( irrep_x == irrep_y ) && ( irrep_z == irrep_v )){ if ( OVLP ){ #pragma omp parallel for schedule(static) for ( int v = 0; v < num_z; v++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int tu = 0; tu < num_t; tu++ ){ for ( int xy = 0; xy < num_x; xy++ ){ SCC[ irrep ][ jump_row + xy + num_x * ( xy + num_x * z ) + SIZE * ( jump_col + tu + num_t * ( tu + num_t * v ) ) ] += one_rdm[ d_z + z + LAS * ( d_v + v ) ]; } } } } } else { #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ for ( int z = 0; z < num_z; z++ ){ for ( int tu = 0; tu < num_t; tu++ ){ const double f_tt = fock->get( irrep_t, nocc_t + tu, nocc_t + tu ); for ( int xy = 0; xy < num_x; xy++ ){ const double f_xx = fock->get( irrep_x, nocc_x + xy, nocc_x + xy ); FCC[ irrep ][ jump_row + xy + num_x * ( xy + num_x * z ) + SIZE * ( jump_col + tu + num_t * ( tu + num_t * v ) ) ] += ( f_dot_2dm[ d_z + z + LAS * ( d_v + v ) ] - ( f_tt + f_xx ) * one_rdm[ d_z + z + LAS * ( d_v + v ) ] ); } } } } } } jump_row += num_x * num_y * num_z; } } if (( OVLP == false ) && ( fabs( IPEA ) > 0.0 )){ // A: E_ti E_uv | 0 > ---> t: excitation into, u: excitation into, v: excitation out of // C: E_at E_uv | 0 > ---> t: excitation out of, u: excitation into, v: excitation out of #pragma omp parallel for schedule(static) for ( int v = 0; v < num_v; v++ ){ const double gamma_vv = one_rdm[ ( d_v + v ) * ( 1 + LAS ) ]; for ( int u = 0; u < num_u; u++ ){ const double gamma_uu = one_rdm[ ( d_u + u ) * ( 1 + LAS ) ]; for ( int t = 0; t < num_t; t++ ){ const double gamma_tt = one_rdm[ ( d_t + t ) * ( 1 + LAS ) ]; const double ipea_A_tuv = 0.5 * IPEA * ( 2.0 + gamma_tt + gamma_uu - gamma_vv ); const double ipea_C_tuv = 0.5 * IPEA * ( 4.0 - gamma_tt + gamma_uu - gamma_vv ); const int ptr = ( jump_col + t + num_t * ( u + num_u * v ) ) * ( 1 + SIZE ); FAA[ irrep ][ ptr ] += ipea_A_tuv * SAA[ irrep ][ ptr ]; FCC[ irrep ][ ptr ] += ipea_C_tuv * SCC[ irrep ][ ptr ]; } } } } jump_col += num_t * num_u * num_v; } } } } void CheMPS2::CASPT2::make_DD( const bool OVLP, const double IPEA ){ /* SDD: < D(bjxy) | 1 | D(aitu) > = delta_ab delta_ij ( SDD[ It x Iu ][ xytu ] ) FDD: < D(bjxy) | F | D(aitu) > = delta_ab delta_ij ( FDD[ It x Iu ][ xytu ] + ( 2 sum_k f_kk + f_aa - f_ii ) SDD[ It x Iu ][ xytu ] ) SD1D1[ It x Iu ][ xytu ] = ( + 2 * Gamma_{ytxu} + 2 * delta_tx Gamma_{yu} ) FD1D1[ It x Iu ][ xytu ] = ( + 2 * f_dot_3dm[ ytxu ] + ( f_xx + f_tt ) SD1D1[ It x Iu ][ xytu ] + 2 * delta_tx ( f_dot_2dm[ yu ] - f_tt Gamma_{yu} ) ) SD2D2[ It x Iu ][ xytu ] = ( - Gamma_{ytux} + 2 * delta_tx Gamma_{yu} ) FD2D2[ It x Iu ][ xytu ] = ( - f_dot_3dm[ ytux ] + ( f_xx + f_tt ) SD2D2[ It x Iu ][ xytu ] + 2 * delta_tx ( f_dot_2dm[ yu ] - f_tt Gamma_{yu} ) ) SD1D2[ It x Iu ][ xytu ] = ( - Gamma_{ytxu} - delta_tx Gamma_{yu} ) FD1D2[ It x Iu ][ xytu ] = ( - f_dot_3dm[ ytxu ] + ( f_xx + f_tt ) SD1D2[ It x Iu ][ xytu ] - delta_tx ( f_dot_2dm[ yu ] - f_tt Gamma_{yu} ) ) SD2D1[ It x Iu ][ xytu ] = ( - Gamma_{ytxu} - delta_tx Gamma_{yu} ) FD2D1[ It x Iu ][ xytu ] = ( - f_dot_3dm[ ytxu ] + ( f_xx + f_tt ) SD2D1[ It x Iu ][ xytu ] - delta_tx ( f_dot_2dm[ yu ] - f_tt Gamma_{yu} ) ) */ if ( OVLP ){ SDD = new double*[ num_irreps ]; } else { FDD = new double*[ num_irreps ]; } const int LAS = indices->getDMRGcumulative( num_irreps ); for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int SIZE = size_D[ irrep ]; const int D2JUMP = SIZE / 2; if ( OVLP ){ SDD[ irrep ] = new double[ SIZE * SIZE ]; } else { FDD[ irrep ] = new double[ SIZE * SIZE ]; } int jump_col = 0; for ( int irrep_t = 0; irrep_t < num_irreps; irrep_t++ ){ const int d_t = indices->getDMRGcumulative( irrep_t ); const int num_t = indices->getNDMRG( irrep_t ); const int nocc_t = indices->getNOCC( irrep_t ); const int irrep_u = Irreps::directProd( irrep, irrep_t ); const int d_u = indices->getDMRGcumulative( irrep_u ); const int num_u = indices->getNDMRG( irrep_u ); int jump_row = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int d_x = indices->getDMRGcumulative( irrep_x ); const int num_x = indices->getNDMRG( irrep_x ); const int nocc_x = indices->getNOCC( irrep_x ); const int irrep_y = Irreps::directProd( irrep, irrep_x ); const int d_y = indices->getDMRGcumulative( irrep_y ); const int num_y = indices->getNDMRG( irrep_y ); if ( OVLP ){ #pragma omp parallel for schedule(static) for ( int u = 0; u < num_u; u++ ){ for ( int t = 0; t < num_t; t++ ){ for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ const double gamma_ytxu = two_rdm[ d_y + y + LAS * ( d_t + t + LAS * ( d_x + x + LAS * ( d_u + u ))) ]; const double gamma_ytux = two_rdm[ d_t + t + LAS * ( d_y + y + LAS * ( d_x + x + LAS * ( d_u + u ))) ]; const int ptr = jump_row + x + num_x * y + SIZE * ( jump_col + t + num_t * u ); SDD[ irrep ][ ptr ] = 2 * gamma_ytxu; SDD[ irrep ][ ptr + SIZE * D2JUMP ] = - gamma_ytxu; SDD[ irrep ][ ptr + D2JUMP ] = - gamma_ytxu; SDD[ irrep ][ ptr + D2JUMP + SIZE * D2JUMP ] = - gamma_ytux; } } } } } else { #pragma omp parallel for schedule(static) for ( int u = 0; u < num_u; u++ ){ for ( int t = 0; t < num_t; t++ ){ const double f_tt = fock->get( irrep_t, nocc_t + t, nocc_t + t ); for ( int y = 0; y < num_y; y++ ){ for ( int x = 0; x < num_x; x++ ){ const double f_xx = fock->get( irrep_x, nocc_x + x, nocc_x + x ); const double f_3dm_ytxu = f_dot_3dm[ d_y + y + LAS * ( d_t + t + LAS * ( d_x + x + LAS * ( d_u + u ))) ]; const double f_3dm_ytux = f_dot_3dm[ d_t + t + LAS * ( d_y + y + LAS * ( d_x + x + LAS * ( d_u + u ))) ]; const int ptr = jump_row + x + num_x * y + SIZE * ( jump_col + t + num_t * u ); FDD[ irrep ][ ptr ] = 2 * f_3dm_ytxu + ( f_xx + f_tt ) * SDD[ irrep ][ ptr ]; FDD[ irrep ][ ptr + SIZE * D2JUMP ] = - f_3dm_ytxu + ( f_xx + f_tt ) * SDD[ irrep ][ ptr + SIZE * D2JUMP ]; FDD[ irrep ][ ptr + D2JUMP ] = - f_3dm_ytxu + ( f_xx + f_tt ) * SDD[ irrep ][ ptr + D2JUMP ]; FDD[ irrep ][ ptr + D2JUMP + SIZE * D2JUMP ] = - f_3dm_ytux + ( f_xx + f_tt ) * SDD[ irrep ][ ptr + D2JUMP + SIZE * D2JUMP ]; } } } } } if (( irrep_x == irrep_t ) && ( irrep_y == irrep_u )){ if ( OVLP ){ #pragma omp parallel for schedule(static) for ( int u = 0; u < num_y; u++ ){ for ( int xt = 0; xt < num_x; xt++ ){ for ( int y = 0; y < num_y; y++ ){ const double gamma_yu = one_rdm[ d_y + y + LAS * ( d_y + u ) ]; const int ptr = jump_row + xt + num_x * y + SIZE * ( jump_col + xt + num_x * u ); SDD[ irrep ][ ptr ] += 2 * gamma_yu; SDD[ irrep ][ ptr + SIZE * D2JUMP ] -= gamma_yu; SDD[ irrep ][ ptr + D2JUMP ] -= gamma_yu; SDD[ irrep ][ ptr + D2JUMP + SIZE * D2JUMP ] += 2 * gamma_yu; } } } } else { #pragma omp parallel for schedule(static) for ( int u = 0; u < num_y; u++ ){ for ( int xt = 0; xt < num_x; xt++ ){ const double f_tt = fock->get( irrep_t, nocc_t + xt, nocc_t + xt ); for ( int y = 0; y < num_y; y++ ){ const double val_yu = ( f_dot_2dm[ d_y + y + LAS * ( d_y + u ) ] - f_tt * one_rdm[ d_y + y + LAS * ( d_y + u ) ] ); const int ptr = jump_row + xt + num_x * y + SIZE * ( jump_col + xt + num_x * u ); FDD[ irrep ][ ptr ] += 2 * val_yu; FDD[ irrep ][ ptr + SIZE * D2JUMP ] -= val_yu; FDD[ irrep ][ ptr + D2JUMP ] -= val_yu; FDD[ irrep ][ ptr + D2JUMP + SIZE * D2JUMP ] += 2 * val_yu; } } } } } jump_row += num_x * num_y; } if (( OVLP == false ) && ( fabs( IPEA ) > 0.0 )){ // D1: E_ai E_tu | 0 > ---> t: excitation into, u excitation out of // D2: E_ti E_au | 0 > ---> t: excitation into, u excitation out of #pragma omp parallel for schedule(static) for ( int u = 0; u < num_u; u++ ){ const double gamma_uu = one_rdm[ ( d_u + u ) * ( 1 + LAS ) ]; for ( int t = 0; t < num_t; t++ ){ const double gamma_tt = one_rdm[ ( d_t + t ) * ( 1 + LAS ) ]; const double ipea_tu = 0.5 * IPEA * ( 2.0 + gamma_tt - gamma_uu ); const int ptr1 = ( jump_col + t + num_t * u ) * ( 1 + SIZE ); const int ptr2 = ( D2JUMP + jump_col + t + num_t * u ) * ( 1 + SIZE ); FDD[ irrep ][ ptr1 ] += ipea_tu * SDD[ irrep ][ ptr1 ]; FDD[ irrep ][ ptr2 ] += ipea_tu * SDD[ irrep ][ ptr2 ]; } } } jump_col += num_t * num_u; } } } void CheMPS2::CASPT2::make_BB_FF_singlet( const bool OVLP, const double IPEA ){ /* | SB_tiuj > = ( E_ti E_uj + E_tj E_ui ) / sqrt( 1 + delta_ij ) | 0 > with i <= j and t <= u SBB singlet: < SB_xkyl | 1 | SB_tiuj > = 2 delta_ik delta_jl ( SBB_singlet[ Itu ][ xytu ] ) FBB singlet: < SB_xkyl | F | SB_tiuj > = 2 delta_ik delta_jl ( FBB_singlet[ Itu ][ xytu ] + ( 2 sum_n f_nn - f_ii - f_jj ) * SBB_singlet[ Itu ][ xytu ] ) SBB_singlet[ Itu ][ xytu ] = ( + Gamma_{utyx} + Gamma_{utxy} + 2 ( delta_uy delta_tx + delta_ux delta_ty ) - delta_uy Gamma_{tx} - delta_tx Gamma_{uy} - delta_ux Gamma_{ty} - delta_ty Gamma_{ux} ) FBB_singlet[ Itu ][ xytu ] = ( + f_dot_3dm[ utyx ] + f_dot_3dm[ tuyx ] + ( f_tt + f_uu + f_xx + f_yy ) SBB_singlet[ xytu ] + 2 ( delta_uy delta_tx + delta_ux delta_ty ) ( f_dot_1dm - f_tt - f_uu ) - delta_uy ( f_dot_2dm[ tx ] - f_uu Gamma_{tx} ) - delta_tx ( f_dot_2dm[ uy ] - f_tt Gamma_{uy} ) - delta_ux ( f_dot_2dm[ ty ] - f_uu Gamma_{ty} ) - delta_ty ( f_dot_2dm[ ux ] - f_tt Gamma_{ux} ) ) | SF_atbu > = ( E_at E_bu + E_bt E_au ) / sqrt( 1 + delta_ab ) | 0 > with a <= b and t <= u SFF singlet: < SF_cxdy | 1 | SF_atbu > = 2 delta_ac delta_bd ( SFF_singlet[ Itu ][ xytu ] ) FFF singlet: < SF_cxdy | F | SF_atbu > = 2 delta_ac delta_bd ( FFF_singlet[ Iab ][ xytu ] + ( 2 sum_n f_nn + f_aa + f_bb ) * SFF_singlet[ Iab ][ xytu ] ) SFF_singlet[ Itu ][ xytu ] = ( + Gamma_{yxut} + Gamma_{yxtu} ) FFF_singlet[ Itu ][ xytu ] = ( + f_dot_3dm[ yxut ] + f_dot_3dm[ yxtu ] ) */ if ( OVLP ){ SBB_singlet = new double*[ num_irreps ]; SFF_singlet = new double*[ num_irreps ]; } else { FBB_singlet = new double*[ num_irreps ]; FFF_singlet = new double*[ num_irreps ]; } const int LAS = indices->getDMRGcumulative( num_irreps ); { // First do irrep == Iia x Ijb == 0 --> It == Iu and Ix == Iy assert( size_B_singlet[ 0 ] == size_F_singlet[ 0 ] ); // At construction const int SIZE = size_B_singlet[ 0 ]; if ( OVLP ){ SBB_singlet[ 0 ] = new double[ SIZE * SIZE ]; SFF_singlet[ 0 ] = new double[ SIZE * SIZE ]; } else { FBB_singlet[ 0 ] = new double[ SIZE * SIZE ]; FFF_singlet[ 0 ] = new double[ SIZE * SIZE ]; } int jump_col = 0; for ( int irrep_ut = 0; irrep_ut < num_irreps; irrep_ut++ ){ const int d_ut = indices->getDMRGcumulative( irrep_ut ); const int num_ut = indices->getNDMRG( irrep_ut ); const int nocc_ut = indices->getNOCC( irrep_ut ); int jump_row = 0; for ( int irrep_xy = 0; irrep_xy < num_irreps; irrep_xy++ ){ const int d_xy = indices->getDMRGcumulative( irrep_xy ); const int num_xy = indices->getNDMRG( irrep_xy ); const int nocc_xy = indices->getNOCC( irrep_xy ); const int shift = jump_row + SIZE * jump_col; // SBB singlet: + Gamma_{utyx} + Gamma_{utxy} // SFF singlet: + Gamma_{yxut} + Gamma_{yxtu} // FBB singlet: + f_dot_3dm[ utyx ] + f_dot_3dm[ tuyx ] + ( f_tt + f_uu + f_xx + f_yy ) SBB_singlet[ xytu ] // FFF singlet: + f_dot_3dm[ yxut ] + f_dot_3dm[ yxtu ] if ( OVLP ){ for ( int t = 0; t < num_ut; t++ ){ for ( int u = t; u < num_ut; u++ ){ // 0 <= t <= u < num_ut for ( int x = 0; x < num_xy; x++ ){ for ( int y = x; y < num_xy; y++ ){ // 0 <= x <= y < num_xy const double value = ( two_rdm[ d_xy + x + LAS * ( d_xy + y + LAS * ( d_ut + t + LAS * ( d_ut + u ))) ] + two_rdm[ d_xy + x + LAS * ( d_xy + y + LAS * ( d_ut + u + LAS * ( d_ut + t ))) ] ); const int ptr = shift + x + ( y * ( y + 1 ) ) / 2 + SIZE * ( t + ( u * ( u + 1 ) ) / 2 ); SBB_singlet[ 0 ][ ptr ] = value; SFF_singlet[ 0 ][ ptr ] = value; } } } } } else { for ( int t = 0; t < num_ut; t++ ){ const double f_tt = fock->get( irrep_ut, nocc_ut + t, nocc_ut + t ); for ( int u = t; u < num_ut; u++ ){ // 0 <= t <= u < num_ut const double f_uu = fock->get( irrep_ut, nocc_ut + u, nocc_ut + u ); for ( int x = 0; x < num_xy; x++ ){ const double f_xx = fock->get( irrep_xy, nocc_xy + x, nocc_xy + x ); for ( int y = x; y < num_xy; y++ ){ // 0 <= x <= y < num_xy const double f_yy = fock->get( irrep_xy, nocc_xy + y, nocc_xy + y ); const int ptr = shift + x + ( y * ( y + 1 ) ) / 2 + SIZE * ( t + ( u * ( u + 1 ) ) / 2 ); const double fdotsum = ( f_dot_3dm[ d_xy + x + LAS * ( d_xy + y + LAS * ( d_ut + t + LAS * ( d_ut + u ))) ] + f_dot_3dm[ d_xy + x + LAS * ( d_xy + y + LAS * ( d_ut + u + LAS * ( d_ut + t ))) ] ); FBB_singlet[ 0 ][ ptr ] = fdotsum + ( f_tt + f_uu + f_xx + f_yy ) * SBB_singlet[ 0 ][ ptr ]; FFF_singlet[ 0 ][ ptr ] = fdotsum; } } } } } if ( irrep_ut == irrep_xy ){ // All four irreps are equal: num_ut = num_xy and d_ut = d_xy // SBB singlet: + 2 ( delta_uy delta_tx + delta_ux delta_ty ) // FBB singlet: + 2 ( delta_uy delta_tx + delta_ux delta_ty ) ( f_dot_1dm - ( f_tt + f_uu ) ) if ( OVLP ){ for ( int t = 0; t < num_ut; t++ ){ SBB_singlet[ 0 ][ shift + t + ( t * ( t + 1 ) ) / 2 + SIZE * ( t + ( t * ( t + 1 ) ) / 2 ) ] += 4.0; for ( int u = t+1; u < num_ut; u++ ){ SBB_singlet[ 0 ][ shift + t + ( u * ( u + 1 ) ) / 2 + SIZE * ( t + ( u * ( u + 1 ) ) / 2 ) ] += 2.0; } } } else { for ( int t = 0; t < num_ut; t++ ){ const double f_tt = fock->get( irrep_ut, nocc_ut + t, nocc_ut + t ); FBB_singlet[ 0 ][ shift + t + ( t * ( t + 1 ) ) / 2 + SIZE * ( t + ( t * ( t + 1 ) ) / 2 ) ] += 4 * ( f_dot_1dm - 2 * f_tt ); for ( int u = t+1; u < num_ut; u++ ){ const double f_uu = fock->get( irrep_ut, nocc_ut + u, nocc_ut + u ); FBB_singlet[ 0 ][ shift + t + ( u * ( u + 1 ) ) / 2 + SIZE * ( t + ( u * ( u + 1 ) ) / 2 ) ] += 2 * ( f_dot_1dm - f_tt - f_uu ); } } } // SBB singlet: - delta_uy Gamma_{tx} // FBB singlet: - delta_uy ( f_dot_2dm[ tx ] - f_uu Gamma_{tx} ) if ( OVLP ){ for ( int uy = 0; uy < num_ut; uy++ ){ for ( int t = 0; t <= uy; t++ ){ // 0 <= t <= uy < num_ut for ( int x = 0; x <= uy; x++ ){ // 0 <= x <= uy < num_ut const double gamma_tx = one_rdm[ d_ut + t + LAS * ( d_ut + x ) ]; SBB_singlet[ 0 ][ shift + x + ( uy * ( uy + 1 ) ) / 2 + SIZE * ( t + ( uy * ( uy + 1 ) ) / 2 ) ] -= gamma_tx; } } } } else { for ( int uy = 0; uy < num_ut; uy++ ){ const double f_uu = fock->get( irrep_ut, nocc_ut + uy, nocc_ut + uy ); for ( int t = 0; t <= uy; t++ ){ // 0 <= t <= uy < num_ut for ( int x = 0; x <= uy; x++ ){ // 0 <= x <= uy < num_ut const double val_tx = ( f_dot_2dm[ d_ut + t + LAS * ( d_ut + x ) ] - f_uu * one_rdm[ d_ut + t + LAS * ( d_ut + x ) ] ); FBB_singlet[ 0 ][ shift + x + ( uy * ( uy + 1 ) ) / 2 + SIZE * ( t + ( uy * ( uy + 1 ) ) / 2 ) ] -= val_tx; } } } } // SBB singlet: - delta_tx Gamma_{uy} // FBB singlet: - delta_tx ( f_dot_2dm[ uy ] - f_tt Gamma_{uy} ) if ( OVLP ){ for ( int tx = 0; tx < num_ut; tx++ ){ for ( int u = tx; u < num_ut; u++ ){ // 0 <= tx <= u < num_ut for ( int y = tx; y < num_ut; y++ ){ // 0 <= tx <= y < num_xy = num_ut const double gamma_uy = one_rdm[ d_ut + u + LAS * ( d_ut + y ) ]; SBB_singlet[ 0 ][ shift + tx + ( y * ( y + 1 ) ) / 2 + SIZE * ( tx + ( u * ( u + 1 ) ) / 2 ) ] -= gamma_uy; } } } } else { for ( int tx = 0; tx < num_ut; tx++ ){ const double f_tt = fock->get( irrep_ut, nocc_ut + tx, nocc_ut + tx ); for ( int u = tx; u < num_ut; u++ ){ // 0 <= tx <= u < num_ut for ( int y = tx; y < num_ut; y++ ){ // 0 <= tx <= y < num_xy = num_ut const double val_uy = ( f_dot_2dm[ d_ut + u + LAS * ( d_ut + y ) ] - f_tt * one_rdm[ d_ut + u + LAS * ( d_ut + y ) ] ); FBB_singlet[ 0 ][ shift + tx + ( y * ( y + 1 ) ) / 2 + SIZE * ( tx + ( u * ( u + 1 ) ) / 2 ) ] -= val_uy; } } } } // SBB singlet: - delta_ux Gamma_{ty} // FBB singlet: - delta_ux ( f_dot_2dm[ ty ] - f_uu Gamma_{ty} ) if ( OVLP ){ for ( int ux = 0; ux < num_ut; ux++ ){ for ( int t = 0; t <= ux; t++ ){ // 0 <= t <= ux < num_ut for ( int y = ux; y < num_ut; y++ ){ // 0 <= ux <= y < num_xy = num_ut const double gamma_ty = one_rdm[ d_ut + t + LAS * ( d_ut + y ) ]; SBB_singlet[ 0 ][ shift + ux + ( y * ( y + 1 ) ) / 2 + SIZE * ( t + ( ux * ( ux + 1 ) ) / 2 ) ] -= gamma_ty; } } } } else { for ( int ux = 0; ux < num_ut; ux++ ){ const double f_uu = fock->get( irrep_ut, nocc_ut + ux, nocc_ut + ux ); for ( int t = 0; t <= ux; t++ ){ // 0 <= t <= ux < num_ut for ( int y = ux; y < num_ut; y++ ){ // 0 <= ux <= y < num_xy = num_ut const double val_ty = ( f_dot_2dm[ d_ut + t + LAS * ( d_ut + y ) ] - f_uu * one_rdm[ d_ut + t + LAS * ( d_ut + y ) ] ); FBB_singlet[ 0 ][ shift + ux + ( y * ( y + 1 ) ) / 2 + SIZE * ( t + ( ux * ( ux + 1 ) ) / 2 ) ] -= val_ty; } } } } // SBB singlet: - delta_ty Gamma_{ux} // FBB singlet: - delta_ty ( f_dot_2dm[ ux ] - f_tt Gamma_{ux} ) if ( OVLP ){ for ( int ty = 0; ty < num_ut; ty++ ){ for ( int u = ty; u < num_ut; u++ ){ // 0 <= ty <= u < num_ut for ( int x = 0; x <= ty; x++ ){ // 0 <= x <= ty < num_ut const double gamma_ux = one_rdm[ d_ut + u + LAS * ( d_ut + x ) ]; SBB_singlet[ 0 ][ shift + x + ( ty * ( ty + 1 ) ) / 2 + SIZE * ( ty + ( u * ( u + 1 ) ) / 2 ) ] -= gamma_ux; } } } } else { for ( int ty = 0; ty < num_ut; ty++ ){ const double f_tt = fock->get( irrep_ut, nocc_ut + ty, nocc_ut + ty ); for ( int u = ty; u < num_ut; u++ ){ // 0 <= ty <= u < num_ut for ( int x = 0; x <= ty; x++ ){ // 0 <= x <= ty < num_ut const double val_ux = ( f_dot_2dm[ d_ut + u + LAS * ( d_ut + x ) ] - f_tt * one_rdm[ d_ut + u + LAS * ( d_ut + x ) ] ); FBB_singlet[ 0 ][ shift + x + ( ty * ( ty + 1 ) ) / 2 + SIZE * ( ty + ( u * ( u + 1 ) ) / 2 ) ] -= val_ux; } } } } } jump_row += ( num_xy * ( num_xy + 1 ) ) / 2; } if (( OVLP == false ) && ( fabs( IPEA ) > 0.0 )){ // B: E_ti E_uj | 0 > ---> tu: excitation into // F: E_at E_bu | 0 > ---> tu: excitation out of for ( int u = 0; u < num_ut; u++ ){ const double gamma_uu = one_rdm[ ( d_ut + u ) * ( 1 + LAS ) ]; for ( int t = 0; t <= u; t++ ){ // 0 <= t <= u < num_ut const double gamma_tt = one_rdm[ ( d_ut + t ) * ( 1 + LAS ) ]; const double ipea_B_tu = 0.5 * IPEA * ( gamma_tt + gamma_uu ); const double ipea_F_tu = 0.5 * IPEA * ( 4.0 - gamma_tt - gamma_uu ); const int ptr = ( jump_col + t + ( u * ( u + 1 ) ) / 2 ) * ( 1 + SIZE ); FBB_singlet[ 0 ][ ptr ] += ipea_B_tu * SBB_singlet[ 0 ][ ptr ]; FFF_singlet[ 0 ][ ptr ] += ipea_F_tu * SFF_singlet[ 0 ][ ptr ]; } } } jump_col += ( num_ut * ( num_ut + 1 ) ) / 2; } } for ( int irrep = 1; irrep < num_irreps; irrep++ ){ // Then do irrep == Iia x Ijb != 0 --> It != Iu and Ix != Iy assert( size_B_singlet[ irrep ] == size_F_singlet[ irrep ] ); // At construction const int SIZE = size_B_singlet[ irrep ]; if ( OVLP ){ SBB_singlet[ irrep ] = new double[ SIZE * SIZE ]; SFF_singlet[ irrep ] = new double[ SIZE * SIZE ]; } else { FBB_singlet[ irrep ] = new double[ SIZE * SIZE ]; FFF_singlet[ irrep ] = new double[ SIZE * SIZE ]; } int jump_col = 0; for ( int irrep_t = 0; irrep_t < num_irreps; irrep_t++ ){ const int irrep_u = Irreps::directProd( irrep, irrep_t ); if ( irrep_t < irrep_u ){ const int d_t = indices->getDMRGcumulative( irrep_t ); const int num_t = indices->getNDMRG( irrep_t ); const int nocc_t = indices->getNOCC( irrep_t ); const int d_u = indices->getDMRGcumulative( irrep_u ); const int num_u = indices->getNDMRG( irrep_u ); const int nocc_u = indices->getNOCC( irrep_u ); int jump_row = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int irrep_y = Irreps::directProd( irrep, irrep_x ); if ( irrep_x < irrep_y ){ const int d_x = indices->getDMRGcumulative( irrep_x ); const int num_x = indices->getNDMRG( irrep_x ); const int nocc_x = indices->getNOCC( irrep_x ); const int d_y = indices->getDMRGcumulative( irrep_y ); const int num_y = indices->getNDMRG( irrep_y ); const int nocc_y = indices->getNOCC( irrep_y ); const int shift = jump_row + SIZE * jump_col; // SBB singlet: + Gamma_{utyx} + Gamma_{utxy} // SFF singlet: + Gamma_{yxut} + Gamma_{yxtu} // FBB singlet: + f_dot_3dm[ utyx ] + f_dot_3dm[ tuyx ] + ( f_tt + f_uu + f_xx + f_yy ) SBB_singlet[ xytu ] // FFF singlet: + f_dot_3dm[ yxut ] + f_dot_3dm[ yxtu ] if ( OVLP ){ for ( int t = 0; t < num_t; t++ ){ for ( int u = 0; u < num_u; u++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ const double value = ( two_rdm[ d_x + x + LAS * ( d_y + y + LAS * ( d_t + t + LAS * ( d_u + u ))) ] + two_rdm[ d_x + x + LAS * ( d_y + y + LAS * ( d_u + u + LAS * ( d_t + t ))) ] ); const int ptr = shift + x + num_x * y + SIZE * ( t + num_t * u ); SBB_singlet[ irrep ][ ptr ] = value; SFF_singlet[ irrep ][ ptr ] = value; } } } } } else { for ( int t = 0; t < num_t; t++ ){ const double f_tt = fock->get( irrep_t, nocc_t + t, nocc_t + t ); for ( int u = 0; u < num_u; u++ ){ const double f_uu = fock->get( irrep_u, nocc_u + u, nocc_u + u ); for ( int x = 0; x < num_x; x++ ){ const double f_xx = fock->get( irrep_x, nocc_x + x, nocc_x + x ); for ( int y = 0; y < num_y; y++ ){ const double f_yy = fock->get( irrep_y, nocc_y + y, nocc_y + y ); const int ptr = shift + x + num_x * y + SIZE * ( t + num_t * u ); const double fdotsum = ( f_dot_3dm[ d_x + x + LAS * ( d_y + y + LAS * ( d_t + t + LAS * ( d_u + u ))) ] + f_dot_3dm[ d_x + x + LAS * ( d_y + y + LAS * ( d_u + u + LAS * ( d_t + t ))) ] ); FBB_singlet[ irrep ][ ptr ] = fdotsum + ( f_xx + f_yy + f_tt + f_uu ) * SBB_singlet[ irrep ][ ptr ]; FFF_singlet[ irrep ][ ptr ] = fdotsum; } } } } } if (( irrep_u == irrep_y ) && ( irrep_t == irrep_x )){ // num_t == num_x and num_u == num_y // SBB singlet: + 2 delta_uy delta_tx // FBB singlet: + 2 delta_uy delta_tx ( f_dot_1dm - f_tt - f_uu ) if ( OVLP ){ for ( int xt = 0; xt < num_x; xt++ ){ for ( int yu = 0; yu < num_y; yu++ ){ SBB_singlet[ irrep ][ shift + xt + num_x * yu + SIZE * ( xt + num_x * yu ) ] += 2.0; } } } else { for ( int xt = 0; xt < num_x; xt++ ){ const double f_tt = fock->get( irrep_x, nocc_x + xt, nocc_x + xt ); for ( int yu = 0; yu < num_y; yu++ ){ const double f_uu = fock->get( irrep_y, nocc_y + yu, nocc_y + yu ); FBB_singlet[ irrep ][ shift + xt + num_x * yu + SIZE * ( xt + num_x * yu ) ] += 2 * ( f_dot_1dm - f_tt - f_uu ); } } } // SBB singlet: - delta_tx Gamma_{uy} // FBB singlet: - delta_tx ( f_dot_2dm[ uy ] - f_tt Gamma_{uy} ) if ( OVLP ){ for ( int xt = 0; xt < num_x; xt++ ){ for ( int u = 0; u < num_y; u++ ){ for ( int y = 0; y < num_y; y++ ){ const double gamma_uy = one_rdm[ d_u + u + LAS * ( d_u + y ) ]; SBB_singlet[ irrep ][ shift + xt + num_x * y + SIZE * ( xt + num_x * u ) ] -= gamma_uy; } } } } else { for ( int xt = 0; xt < num_x; xt++ ){ const double f_tt = fock->get( irrep_x, nocc_x + xt, nocc_x + xt ); for ( int u = 0; u < num_y; u++ ){ for ( int y = 0; y < num_y; y++ ){ const double val_uy = ( f_dot_2dm[ d_u + u + LAS * ( d_u + y ) ] - f_tt * one_rdm[ d_u + u + LAS * ( d_u + y ) ] ); FBB_singlet[ irrep ][ shift + xt + num_x * y + SIZE * ( xt + num_x * u ) ] -= val_uy; } } } } // SBB singlet: - delta_uy Gamma_{tx} // FBB singlet: - delta_uy ( f_dot_2dm[ tx ] - f_uu Gamma_{tx} ) if ( OVLP ){ for ( int yu = 0; yu < num_y; yu++ ){ for ( int t = 0; t < num_x; t++ ){ for ( int x = 0; x < num_x; x++ ){ const double gamma_tx = one_rdm[ d_t + t + LAS * ( d_t + x ) ]; SBB_singlet[ irrep ][ shift + x + num_x * yu + SIZE * ( t + num_t * yu ) ] -= gamma_tx; } } } } else { for ( int yu = 0; yu < num_y; yu++ ){ const double f_uu = fock->get( irrep_y, nocc_y + yu, nocc_y + yu ); for ( int t = 0; t < num_x; t++ ){ for ( int x = 0; x < num_x; x++ ){ const double val_tx = ( f_dot_2dm[ d_t + t + LAS * ( d_t + x ) ] - f_uu * one_rdm[ d_t + t + LAS * ( d_t + x ) ] ); FBB_singlet[ irrep ][ shift + x + num_x * yu + SIZE * ( t + num_t * yu ) ] -= val_tx; } } } } } jump_row += num_x * num_y; } } if (( OVLP == false ) && ( fabs( IPEA ) > 0.0 )){ // B: E_ti E_uj | 0 > ---> tu: excitation into // F: E_at E_bu | 0 > ---> tu: excitation out of for ( int u = 0; u < num_u; u++ ){ const double gamma_uu = one_rdm[ ( d_u + u ) * ( 1 + LAS ) ]; for ( int t = 0; t < num_t; t++ ){ const double gamma_tt = one_rdm[ ( d_t + t ) * ( 1 + LAS ) ]; const double ipea_B_tu = 0.5 * IPEA * ( gamma_tt + gamma_uu ); const double ipea_F_tu = 0.5 * IPEA * ( 4.0 - gamma_tt - gamma_uu ); const int ptr = ( jump_col + t + num_t * u ) * ( 1 + SIZE ); FBB_singlet[ irrep ][ ptr ] += ipea_B_tu * SBB_singlet[ irrep ][ ptr ]; FFF_singlet[ irrep ][ ptr ] += ipea_F_tu * SFF_singlet[ irrep ][ ptr ]; } } } jump_col += num_t * num_u; } } } } void CheMPS2::CASPT2::make_BB_FF_triplet( const bool OVLP, const double IPEA ){ /* | TB_tiuj > = ( E_ti E_uj - E_tj E_ui ) / sqrt( 1 + delta_ij ) | 0 > with i < j and t < u SBB triplet: < TB_xkyl | 1 | TB_tiuj > = 2 delta_ik delta_jl ( SBB_triplet[ Itu ][ xytu ] ) FBB triplet: < TB_xkyl | F | TB_tiuj > = 2 delta_ik delta_jl ( FBB_triplet[ Itu ][ xytu ] + ( 2 sum_n f_nn - f_ii - f_jj ) * SBB_triplet[ Itu ][ xytu ] ) SBB_triplet[ Itu ][ xytu ] = ( + Gamma_{utyx} - Gamma_{utxy} + 6 delta_uy delta_tx - 6 delta_ux delta_ty - 3 delta_uy Gamma_{tx} - 3 delta_tx Gamma_{uy} + 3 delta_ux Gamma_{ty} + 3 delta_ty Gamma_{ux} ) FBB_triplet[ Itu ][ xytu ] = ( + f_dot_3dm[ utyx ] - f_dot_3dm[ tuyx ] + ( f_tt + f_uu + f_xx + f_yy ) SBB_triplet[ xytu ] + 6 delta_uy delta_tx ( f_dot_1dm - f_tt - f_uu ) - 6 delta_ux delta_ty ( f_dot_1dm - f_tt - f_uu ) - 3 delta_uy ( f_dot_2dm[ tx ] - f_uu Gamma_{tx} ) - 3 delta_tx ( f_dot_2dm[ uy ] - f_tt Gamma_{uy} ) + 3 delta_ux ( f_dot_2dm[ ty ] - f_uu Gamma_{ty} ) + 3 delta_ty ( f_dot_2dm[ ux ] - f_tt Gamma_{ux} ) ) | TF_atbu > = ( E_at E_bu - E_bt E_au ) / sqrt( 1 + delta_ab ) | 0 > with a < b and t < u SFF triplet: < TF_cxdy | 1 | TF_atbu > = 2 delta_ac delta_bd ( SFF_triplet[ Itu ][ xytu ] ) FFF triplet: < TF_cxdy | F | TF_atbu > = 2 delta_ac delta_bd ( FFF_triplet[ Itu ][ xytu ] + ( 2 sum_n f_nn + f_aa + f_bb ) * SFF_triplet[ Itu ][ xytu ] ) SFF_triplet[ Itu ][ xytu ] = ( + Gamma_{yxut} - Gamma_{yxtu} ) FFF_triplet[ Itu ][ xytu ] = ( + f_dot_3dm[ yxut ] - f_dot_3dm[ yxtu ] ) */ if ( OVLP ){ SBB_triplet = new double*[ num_irreps ]; SFF_triplet = new double*[ num_irreps ]; } else { FBB_triplet = new double*[ num_irreps ]; FFF_triplet = new double*[ num_irreps ]; } const int LAS = indices->getDMRGcumulative( num_irreps ); { // First do irrep == Iia x Ijb == 0 --> It == Iu and Ix == Iy assert( size_B_triplet[ 0 ] == size_F_triplet[ 0 ] ); // At construction const int SIZE = size_B_triplet[ 0 ]; if ( OVLP ){ SBB_triplet[ 0 ] = new double[ SIZE * SIZE ]; SFF_triplet[ 0 ] = new double[ SIZE * SIZE ]; } else { FBB_triplet[ 0 ] = new double[ SIZE * SIZE ]; FFF_triplet[ 0 ] = new double[ SIZE * SIZE ]; } int jump_col = 0; for ( int irrep_ut = 0; irrep_ut < num_irreps; irrep_ut++ ){ const int d_ut = indices->getDMRGcumulative( irrep_ut ); const int num_ut = indices->getNDMRG( irrep_ut ); const int nocc_ut = indices->getNOCC( irrep_ut ); int jump_row = 0; for ( int irrep_xy = 0; irrep_xy < num_irreps; irrep_xy++ ){ const int d_xy = indices->getDMRGcumulative( irrep_xy ); const int num_xy = indices->getNDMRG( irrep_xy ); const int nocc_xy = indices->getNOCC( irrep_xy ); const int shift = jump_row + SIZE * jump_col; // SBB triplet: + Gamma_{utyx} - Gamma_{utxy} // SFF triplet: + Gamma_{yxut} - Gamma_{yxtu} // FBB triplet: + f_dot_3dm[ utyx ] - f_dot_3dm[ tuyx ] + ( f_tt + f_uu + f_xx + f_yy ) SBB_triplet[ xytu ] // FFF triplet: + f_dot_3dm[ yxut ] - f_dot_3dm[ yxtu ] if ( OVLP ){ for ( int t = 0; t < num_ut; t++ ){ for ( int u = t+1; u < num_ut; u++ ){ // 0 <= t < u < num_ut for ( int x = 0; x < num_xy; x++ ){ for ( int y = x+1; y < num_xy; y++ ){ // 0 <= x < y < num_xy const int ptr = shift + x + ( y * ( y - 1 ) ) / 2 + SIZE * ( t + ( u * ( u - 1 ) ) / 2 ); const double value = ( two_rdm[ d_xy + x + LAS * ( d_xy + y + LAS * ( d_ut + t + LAS * ( d_ut + u ))) ] - two_rdm[ d_xy + x + LAS * ( d_xy + y + LAS * ( d_ut + u + LAS * ( d_ut + t ))) ] ); SBB_triplet[ 0 ][ ptr ] = value; SFF_triplet[ 0 ][ ptr ] = value; } } } } } else { for ( int t = 0; t < num_ut; t++ ){ const double f_tt = fock->get( irrep_ut, nocc_ut + t, nocc_ut + t ); for ( int u = t+1; u < num_ut; u++ ){ // 0 <= t < u < num_ut const double f_uu = fock->get( irrep_ut, nocc_ut + u, nocc_ut + u ); for ( int x = 0; x < num_xy; x++ ){ const double f_xx = fock->get( irrep_xy, nocc_xy + x, nocc_xy + x ); for ( int y = x+1; y < num_xy; y++ ){ // 0 <= x < y < num_xy const double f_yy = fock->get( irrep_xy, nocc_xy + y, nocc_xy + y ); const int ptr = shift + x + ( y * ( y - 1 ) ) / 2 + SIZE * ( t + ( u * ( u - 1 ) ) / 2 ); const double fdotdiff = ( f_dot_3dm[ d_xy + x + LAS * ( d_xy + y + LAS * ( d_ut + t + LAS * ( d_ut + u ))) ] - f_dot_3dm[ d_xy + x + LAS * ( d_xy + y + LAS * ( d_ut + u + LAS * ( d_ut + t ))) ] ); FBB_triplet[ 0 ][ ptr ] = fdotdiff + ( f_tt + f_uu + f_xx + f_yy ) * SBB_triplet[ 0 ][ ptr ]; FFF_triplet[ 0 ][ ptr ] = fdotdiff; } } } } } if ( irrep_ut == irrep_xy ){ // All four irreps are equal --> num_ut == num_xy // SBB triplet: + 6 ( delta_uy delta_tx - delta_ux delta_ty ) // FBB triplet: + 6 ( delta_uy delta_tx - delta_ux delta_ty ) ( f_dot_1dm - f_tt - f_uu ) if ( OVLP ){ for ( int tx = 0; tx < num_ut; tx++ ){ for ( int uy = tx+1; uy < num_ut; uy++ ){ SBB_triplet[ 0 ][ shift + tx + ( uy * ( uy - 1 ) ) / 2 + SIZE * ( tx + ( uy * ( uy - 1 ) ) / 2 ) ] += 6.0; } } } else { for ( int tx = 0; tx < num_ut; tx++ ){ const double f_tt = fock->get( irrep_ut, nocc_ut + tx, nocc_ut + tx ); for ( int uy = tx+1; uy < num_ut; uy++ ){ const double f_uu = fock->get( irrep_ut, nocc_ut + uy, nocc_ut + uy ); FBB_triplet[ 0 ][ shift + tx + ( uy * ( uy - 1 ) ) / 2 + SIZE * ( tx + ( uy * ( uy - 1 ) ) / 2 ) ] += 6 * ( f_dot_1dm - f_tt - f_uu ); } } } // SBB triplet: - 3 delta_uy Gamma_{tx} // FBB triplet: - 3 delta_uy ( f_dot_2dm[ tx ] - f_yu Gamma_{tx} ) if ( OVLP ){ for ( int uy = 0; uy < num_ut; uy++ ){ for ( int t = 0; t < uy; t++ ){ // 0 <= t < uy < num_ut for ( int x = 0; x < uy; x++ ){ // 0 <= x < uy < num_ut const double gamma_tx = one_rdm[ d_ut + t + LAS * ( d_xy + x ) ]; SBB_triplet[ 0 ][ shift + x + ( uy * ( uy - 1 ) ) / 2 + SIZE * ( t + ( uy * ( uy - 1 ) ) / 2 ) ] -= 3 * gamma_tx; } } } } else { for ( int uy = 0; uy < num_ut; uy++ ){ const double f_uu = fock->get( irrep_ut, nocc_ut + uy, nocc_ut + uy ); for ( int t = 0; t < uy; t++ ){ // 0 <= t < uy < num_ut for ( int x = 0; x < uy; x++ ){ // 0 <= x < uy < num_ut const double val_tx = ( f_dot_2dm[ d_ut + t + LAS * ( d_ut + x ) ] - f_uu * one_rdm[ d_ut + t + LAS * ( d_ut + x ) ] ); FBB_triplet[ 0 ][ shift + x + ( uy * ( uy - 1 ) ) / 2 + SIZE * ( t + ( uy * ( uy - 1 ) ) / 2 ) ] -= 3 * val_tx; } } } } // SBB triplet: - 3 delta_tx Gamma_{uy} // FBB triplet: - 3 delta_tx ( f_dot_2dm[ uy ] - f_tt Gamma_{uy} ) if ( OVLP ){ for ( int tx = 0; tx < num_ut; tx++ ){ for ( int u = tx+1; u < num_ut; u++ ){ // 0 <= tx < u < num_ut for ( int y = tx+1; y < num_ut; y++ ){ // 0 <= tx < y < num_xy = num_ut const double gamma_uy = one_rdm[ d_ut + u + LAS * ( d_xy + y ) ]; SBB_triplet[ 0 ][ shift + tx + ( y * ( y - 1 ) ) / 2 + SIZE * ( tx + ( u * ( u - 1 ) ) / 2 ) ] -= 3 * gamma_uy; } } } } else { for ( int tx = 0; tx < num_ut; tx++ ){ const double f_tt = fock->get( irrep_ut, nocc_ut + tx, nocc_ut + tx ); for ( int u = tx+1; u < num_ut; u++ ){ // 0 <= tx < u < num_ut for ( int y = tx+1; y < num_ut; y++ ){ // 0 <= tx < y < num_xy = num_ut const double val_uy = ( f_dot_2dm[ d_ut + u + LAS * ( d_ut + y ) ] - f_tt * one_rdm[ d_ut + u + LAS * ( d_ut + y ) ] ); FBB_triplet[ 0 ][ shift + tx + ( y * ( y - 1 ) ) / 2 + SIZE * ( tx + ( u * ( u - 1 ) ) / 2 ) ] -= 3 * val_uy; } } } } // SBB triplet: + 3 delta_ux Gamma_{ty} // FBB triplet: + 3 delta_ux ( f_dot_2dm[ ty ] - f_uu Gamma_{ty} ) if ( OVLP ){ for ( int ux = 0; ux < num_ut; ux++ ){ for ( int t = 0; t < ux; t++ ){ // 0 <= t < ux < num_ut for ( int y = ux+1; y < num_ut; y++ ){ // 0 <= ux < y < num_xy = num_ut const double gamma_ty = one_rdm[ d_ut + t + LAS * ( d_xy + y ) ]; SBB_triplet[ 0 ][ shift + ux + ( y * ( y - 1 ) ) / 2 + SIZE * ( t + ( ux * ( ux - 1 ) ) / 2 ) ] += 3 * gamma_ty; } } } } else { for ( int ux = 0; ux < num_ut; ux++ ){ const double f_uu = fock->get( irrep_ut, nocc_ut + ux, nocc_ut + ux ); for ( int t = 0; t < ux; t++ ){ // 0 <= t < ux < num_ut for ( int y = ux+1; y < num_ut; y++ ){ // 0 <= ux < y < num_xy = num_ut const double val_ty = ( f_dot_2dm[ d_ut + t + LAS * ( d_ut + y ) ] - f_uu * one_rdm[ d_ut + t + LAS * ( d_ut + y ) ] ); FBB_triplet[ 0 ][ shift + ux + ( y * ( y - 1 ) ) / 2 + SIZE * ( t + ( ux * ( ux - 1 ) ) / 2 ) ] += 3 * val_ty; } } } } // SBB triplet: + 3 delta_ty Gamma_{ux} // FBB triplet: + 3 delta_ty ( f_dot_2dm[ ux ] - f_tt Gamma_{ux} ) if ( OVLP ){ for ( int ty = 0; ty < num_ut; ty++ ){ for ( int u = ty+1; u < num_ut; u++ ){ // 0 <= ty < u < num_ut for ( int x = 0; x < ty; x++ ){ // 0 <= x < ty < num_ut const double gamma_ux = one_rdm[ d_ut + u + LAS * ( d_xy + x ) ]; SBB_triplet[ 0 ][ shift + x + ( ty * ( ty - 1 ) ) / 2 + SIZE * ( ty + ( u * ( u - 1 ) ) / 2 ) ] += 3 * gamma_ux; } } } } else { for ( int ty = 0; ty < num_ut; ty++ ){ const double f_tt = fock->get( irrep_ut, nocc_ut + ty, nocc_ut + ty ); for ( int u = ty+1; u < num_ut; u++ ){ // 0 <= ty < u < num_ut for ( int x = 0; x < ty; x++ ){ // 0 <= x < ty < num_ut const double val_ux = ( f_dot_2dm[ d_ut + u + LAS * ( d_ut + x ) ] - f_tt * one_rdm[ d_ut + u + LAS * ( d_ut + x ) ] ); FBB_triplet[ 0 ][ shift + x + ( ty * ( ty - 1 ) ) / 2 + SIZE * ( ty + ( u * ( u - 1 ) ) / 2 ) ] += 3 * val_ux; } } } } } jump_row += ( num_xy * ( num_xy - 1 ) ) / 2; } if (( OVLP == false ) && ( fabs( IPEA ) > 0.0 )){ // B: E_ti E_uj | 0 > ---> tu: excitation into // F: E_at E_bu | 0 > ---> tu: excitation out of for ( int u = 0; u < num_ut; u++ ){ const double gamma_uu = one_rdm[ ( d_ut + u ) * ( 1 + LAS ) ]; for ( int t = 0; t < u; t++ ){ // 0 <= t < u < num_ut const double gamma_tt = one_rdm[ ( d_ut + t ) * ( 1 + LAS ) ]; const double ipea_B_tu = 0.5 * IPEA * ( gamma_tt + gamma_uu ); const double ipea_F_tu = 0.5 * IPEA * ( 4.0 - gamma_tt - gamma_uu ); const int ptr = ( jump_col + t + ( u * ( u - 1 ) ) / 2 ) * ( 1 + SIZE ); FBB_triplet[ 0 ][ ptr ] += ipea_B_tu * SBB_triplet[ 0 ][ ptr ]; FFF_triplet[ 0 ][ ptr ] += ipea_F_tu * SFF_triplet[ 0 ][ ptr ]; } } } jump_col += ( num_ut * ( num_ut - 1 ) ) / 2; } } for ( int irrep = 1; irrep < num_irreps; irrep++ ){ // Then do irrep == Iia x Ijb != 0 --> It != Iu and Ix != Iy assert( size_B_triplet[ irrep ] == size_F_triplet[ irrep ] ); // At construction const int SIZE = size_B_triplet[ irrep ]; if ( OVLP ){ SBB_triplet[ irrep ] = new double[ SIZE * SIZE ]; SFF_triplet[ irrep ] = new double[ SIZE * SIZE ]; } else { FBB_triplet[ irrep ] = new double[ SIZE * SIZE ]; FFF_triplet[ irrep ] = new double[ SIZE * SIZE ]; } int jump_col = 0; for ( int irrep_t = 0; irrep_t < num_irreps; irrep_t++ ){ const int irrep_u = Irreps::directProd( irrep, irrep_t ); if ( irrep_t < irrep_u ){ const int d_t = indices->getDMRGcumulative( irrep_t ); const int num_t = indices->getNDMRG( irrep_t ); const int nocc_t = indices->getNOCC( irrep_t ); const int d_u = indices->getDMRGcumulative( irrep_u ); const int num_u = indices->getNDMRG( irrep_u ); const int nocc_u = indices->getNOCC( irrep_u ); int jump_row = 0; for ( int irrep_x = 0; irrep_x < num_irreps; irrep_x++ ){ const int irrep_y = Irreps::directProd( irrep, irrep_x ); if ( irrep_x < irrep_y ){ const int d_x = indices->getDMRGcumulative( irrep_x ); const int num_x = indices->getNDMRG( irrep_x ); const int nocc_x = indices->getNOCC( irrep_x ); const int d_y = indices->getDMRGcumulative( irrep_y ); const int num_y = indices->getNDMRG( irrep_y ); const int nocc_y = indices->getNOCC( irrep_y ); const int shift = jump_row + SIZE * jump_col; // SBB triplet: + Gamma_{utyx} - Gamma_{utxy} // SFF triplet: + Gamma_{yxut} - Gamma_{yxtu} // FBB triplet: + f_dot_3dm[ utyx ] - f_dot_3dm[ tuyx ] + ( f_tt + f_uu + f_xx + f_yy ) SBB_triplet[ xytu ] // FFF triplet: + f_dot_3dm[ yxut ] - f_dot_3dm[ yxtu ] if ( OVLP ){ for ( int t = 0; t < num_t; t++ ){ for ( int u = 0; u < num_u; u++ ){ for ( int x = 0; x < num_x; x++ ){ for ( int y = 0; y < num_y; y++ ){ const int ptr = shift + x + num_x * y + SIZE * ( t + num_t * u ); const double value = ( two_rdm[ d_x + x + LAS * ( d_y + y + LAS * ( d_t + t + LAS * ( d_u + u ))) ] - two_rdm[ d_x + x + LAS * ( d_y + y + LAS * ( d_u + u + LAS * ( d_t + t ))) ] ); SBB_triplet[ irrep ][ ptr ] = value; SFF_triplet[ irrep ][ ptr ] = value; } } } } } else { for ( int t = 0; t < num_t; t++ ){ const double f_tt = fock->get( irrep_t, nocc_t + t, nocc_t + t ); for ( int u = 0; u < num_u; u++ ){ const double f_uu = fock->get( irrep_u, nocc_u + u, nocc_u + u ); for ( int x = 0; x < num_x; x++ ){ const double f_xx = fock->get( irrep_x, nocc_x + x, nocc_x + x ); for ( int y = 0; y < num_y; y++ ){ const double f_yy = fock->get( irrep_y, nocc_y + y, nocc_y + y ); const int ptr = shift + x + num_x * y + SIZE * ( t + num_t * u ); const double fdotdiff = ( f_dot_3dm[ d_x + x + LAS * ( d_y + y + LAS * ( d_t + t + LAS * ( d_u + u ))) ] - f_dot_3dm[ d_x + x + LAS * ( d_y + y + LAS * ( d_u + u + LAS * ( d_t + t ))) ] ); FBB_triplet[ irrep ][ ptr ] = fdotdiff + ( f_tt + f_uu + f_xx + f_yy ) * SBB_triplet[ irrep ][ ptr ]; FFF_triplet[ irrep ][ ptr ] = fdotdiff; } } } } } if (( irrep_u == irrep_y ) && ( irrep_t == irrep_x )){ // --> num_t == num_x and num_u == num_y // SBB triplet: + 6 delta_uy delta_tx // FBB triplet: + 6 delta_uy delta_tx ( f_dot_1dm - f_tt - f_uu ) if ( OVLP ){ for ( int xt = 0; xt < num_x; xt++ ){ for ( int yu = 0; yu < num_y; yu++ ){ SBB_triplet[ irrep ][ shift + xt + num_x * yu + SIZE * ( xt + num_x * yu ) ] += 6.0; } } } else { for ( int xt = 0; xt < num_x; xt++ ){ const double f_tt = fock->get( irrep_x, nocc_x + xt, nocc_x + xt ); for ( int yu = 0; yu < num_y; yu++ ){ const double f_uu = fock->get( irrep_y, nocc_y + yu, nocc_y + yu ); FBB_triplet[ irrep ][ shift + xt + num_x * yu + SIZE * ( xt + num_x * yu ) ] += 6 * ( f_dot_1dm - f_tt - f_uu ); } } } // SBB triplet: - 3 delta_tx Gamma_{uy} // FBB triplet: - 3 delta_tx ( f_dot_2dm[ uy ] - f_tt Gamma_{uy} ) if ( OVLP ){ for ( int xt = 0; xt < num_x; xt++ ){ for ( int u = 0; u < num_y; u++ ){ for ( int y = 0; y < num_y; y++ ){ const double gamma_uy = one_rdm[ d_u + u + LAS * ( d_y + y ) ]; SBB_triplet[ irrep ][ shift + xt + num_x * y + SIZE * ( xt + num_x * u ) ] -= 3 * gamma_uy; } } } } else { for ( int xt = 0; xt < num_x; xt++ ){ const double f_tt = fock->get( irrep_x, nocc_x + xt, nocc_x + xt ); for ( int u = 0; u < num_y; u++ ){ for ( int y = 0; y < num_y; y++ ){ const double val_uy = ( f_dot_2dm[ d_u + u + LAS * ( d_u + y ) ] - f_tt * one_rdm[ d_u + u + LAS * ( d_u + y ) ] ); FBB_triplet[ irrep ][ shift + xt + num_x * y + SIZE * ( xt + num_x * u ) ] -= 3 * val_uy; } } } } // SBB triplet: - 3 delta_uy Gamma_{tx} // FBB triplet: - 3 delta_uy ( f_dot_2dm[ tx ] - f_uu Gamma_{tx} ) if ( OVLP ){ for ( int yu = 0; yu < num_y; yu++ ){ for ( int t = 0; t < num_x; t++ ){ for ( int x = 0; x < num_x; x++ ){ const double gamma_tx = one_rdm[ d_t + t + LAS * ( d_x + x ) ]; SBB_triplet[ irrep ][ shift + x + num_x * yu + SIZE * ( t + num_x * yu ) ] -= 3 * gamma_tx; } } } } else { for ( int yu = 0; yu < num_y; yu++ ){ const double f_uu = fock->get( irrep_y, nocc_y + yu, nocc_y + yu ); for ( int t = 0; t < num_x; t++ ){ for ( int x = 0; x < num_x; x++ ){ const double val_tx = ( f_dot_2dm[ d_t + t + LAS * ( d_t + x ) ] - f_uu * one_rdm[ d_t + t + LAS * ( d_t + x ) ] ); FBB_triplet[ irrep ][ shift + x + num_x * yu + SIZE * ( t + num_x * yu ) ] -= 3 * val_tx; } } } } } jump_row += num_x * num_y; } } if (( OVLP == false ) && ( fabs( IPEA ) > 0.0 )){ // B: E_ti E_uj | 0 > ---> tu: excitation into // F: E_at E_bu | 0 > ---> tu: excitation out of for ( int u = 0; u < num_u; u++ ){ const double gamma_uu = one_rdm[ ( d_u + u ) * ( 1 + LAS ) ]; for ( int t = 0; t < num_t; t++ ){ const double gamma_tt = one_rdm[ ( d_t + t ) * ( 1 + LAS ) ]; const double ipea_B_tu = 0.5 * IPEA * ( gamma_tt + gamma_uu ); const double ipea_F_tu = 0.5 * IPEA * ( 4.0 - gamma_tt - gamma_uu ); const int ptr = ( jump_col + t + num_t * u ) * ( 1 + SIZE ); FBB_triplet[ irrep ][ ptr ] += ipea_B_tu * SBB_triplet[ irrep ][ ptr ]; FFF_triplet[ irrep ][ ptr ] += ipea_F_tu * SFF_triplet[ irrep ][ ptr ]; } } } jump_col += num_t * num_u; } } } } void CheMPS2::CASPT2::make_EE_GG( const bool OVLP, const double IPEA ){ /* | SE_tiaj > = ( E_ti E_aj + E_tj E_ai ) / sqrt( 1 + delta_ij ) | 0 > with i <= j | TE_tiaj > = ( E_ti E_aj - E_tj E_ai ) / sqrt( 1 + delta_ij ) | 0 > with i < j < SE_ukbl | 1 | SE_tiaj > = 2 delta_ab delta_ik delta_jl ( SEE[ It ][ ut ] ) < SE_ukbl | F | SE_tiaj > = 2 delta_ab delta_ik delta_jl ( FEE[ It ][ ut ] + ( 2 sum_k f_kk + f_aa - f_ii - f_jj ) SEE[ It ][ ut ] ) < TE_ukbl | 1 | TE_tiaj > = 6 delta_ab delta_ik delta_jl ( SEE[ It ][ ut ] ) < TE_ukbl | F | TE_tiaj > = 6 delta_ab delta_ik delta_jl ( FEE[ It ][ ut ] + ( 2 sum_k f_kk + f_aa - f_ii - f_jj ) SEE[ It ][ ut ] ) SEE[ It ][ ut ] = ( + 2 delta_tu - Gamma_tu ) FEE[ It ][ ut ] = ( + 2 * delta_ut * ( f_dot_1dm + f_tt ) - f_dot_2dm[ It ][ tu ] - ( f_tt + f_uu ) Gamma_ut ) | SG_aibt > = ( E_ai E_bt + E_bi E_at ) / sqrt( 1 + delta_ab ) | 0 > with a <= b | TG_aibt > = ( E_ai E_bt - E_bi E_at ) / sqrt( 1 + delta_ab ) | 0 > with a < b < SG_cjdu | 1 | SG_aibt > = 2 delta_ij delta_ac delta_bd ( SGG[ It ][ ut ] ) < SG_cjdu | F | SG_aibt > = 2 delta_ij delta_ac delta_bd ( FGG[ It ][ ut ] + ( 2 sum_k f_kk + f_aa + f_bb - f_ii ) SGG[ It ][ ut ] ) < TG_cjdu | 1 | TG_aibt > = 6 delta_ij delta_ac delta_bd ( SGG[ It ][ ut ] ) < TG_cjdu | F | TG_aibt > = 6 delta_ij delta_ac delta_bd ( FGG[ It ][ ut ] + ( 2 sum_k f_kk + f_aa + f_bb - f_ii ) SGG[ It ][ ut ] ) SGG[ It ][ ut ] = ( + Gamma_ut ) FGG[ It ][ ut ] = ( + f_dot_2dm[ It ][ ut ] ) */ if ( OVLP ){ SEE = new double*[ num_irreps ]; SGG = new double*[ num_irreps ]; } else { FEE = new double*[ num_irreps ]; FGG = new double*[ num_irreps ]; } const int LAS = indices->getDMRGcumulative( num_irreps ); for ( int irrep_ut = 0; irrep_ut < num_irreps; irrep_ut++ ){ const int d_ut = indices->getDMRGcumulative( irrep_ut ); const int SIZE = indices->getNDMRG( irrep_ut ); const int NOCC = indices->getNOCC( irrep_ut ); if ( OVLP ){ SEE[ irrep_ut ] = new double[ SIZE * SIZE ]; SGG[ irrep_ut ] = new double[ SIZE * SIZE ]; for ( int t = 0; t < SIZE; t++ ){ for ( int u = 0; u < SIZE; u++ ){ const double gamma_ut = one_rdm[ d_ut + u + LAS * ( d_ut + t ) ]; SEE[ irrep_ut ][ u + SIZE * t ] = - gamma_ut; SGG[ irrep_ut ][ u + SIZE * t ] = gamma_ut; } SEE[ irrep_ut ][ t + SIZE * t ] += 2.0; } } else { FEE[ irrep_ut ] = new double[ SIZE * SIZE ]; FGG[ irrep_ut ] = new double[ SIZE * SIZE ]; for ( int t = 0; t < SIZE; t++ ){ const double f_tt = fock->get( irrep_ut, NOCC + t, NOCC + t ); for ( int u = 0; u < SIZE; u++ ){ const double f_uu = fock->get( irrep_ut, NOCC + u, NOCC + u ); const double gamma_ut = one_rdm[ d_ut + u + LAS * ( d_ut + t ) ]; const double fdot2_ut = f_dot_2dm[ d_ut + u + LAS * ( d_ut + t ) ]; FEE[ irrep_ut ][ u + SIZE * t ] = - fdot2_ut - ( f_tt + f_uu ) * gamma_ut; FGG[ irrep_ut ][ u + SIZE * t ] = fdot2_ut; } FEE[ irrep_ut ][ t + SIZE * t ] += 2 * ( f_dot_1dm + f_tt ); } if ( fabs( IPEA ) > 0.0 ){ // E: E_ti E_aj | 0 > ---> t: excitation into // G: E_ai E_bt | 0 > ---> t: excitation out of for ( int t = 0; t < SIZE; t++ ){ const double gamma_tt = one_rdm[ ( d_ut + t ) * ( 1 + LAS ) ]; const double ipea_E_t = 0.5 * IPEA * ( gamma_tt ); const double ipea_G_t = 0.5 * IPEA * ( 2.0 - gamma_tt ); const int ptr = t * ( 1 + SIZE ); FEE[ irrep_ut ][ ptr ] += ipea_E_t * SEE[ irrep_ut ][ ptr ]; FGG[ irrep_ut ][ ptr ] += ipea_G_t * SGG[ irrep_ut ][ ptr ]; } } } } } CheMPS2-1.8.9/CheMPS2/CASSCF.cpp000066400000000000000000000462761336564451100155300ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include "CASSCF.h" #include "Lapack.h" #include "Special.h" #include "MPIchemps2.h" using std::string; using std::ifstream; using std::cout; using std::endl; using std::max; CheMPS2::CASSCF::CASSCF( Hamiltonian * ham_in, int * docc, int * socc, int * nocc, int * ndmrg, int * nvirt, const string new_tmp_folder ){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif NUCL_ORIG = ham_in->getEconst(); TMAT_ORIG = ham_in->getTmat(); VMAT_ORIG = ham_in->getVmat(); L = ham_in->getL(); SymmInfo.setGroup( ham_in->getNGroup() ); num_irreps = SymmInfo.getNumberOfIrreps(); successful_solve = false; if (( am_i_master ) && ( docc != NULL ) && ( socc != NULL )){ cout << "DOCC = [ "; for ( int irrep = 0; irrep < num_irreps-1; irrep++ ){ cout << docc[ irrep ] << " , "; } cout << docc[ num_irreps - 1 ] << " ]" << endl; cout << "SOCC = [ "; for ( int irrep = 0; irrep < num_irreps-1; irrep++ ){ cout << socc[ irrep ] << " , "; } cout << socc[ num_irreps - 1 ] << " ]" << endl; } for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int norb_in = nocc[ irrep ] + ndmrg[ irrep ] + nvirt[ irrep ]; const int norb_ham = VMAT_ORIG->get_irrep_size( irrep ); if (( norb_ham != norb_in ) && ( am_i_master )){ cout << "CASSCF::CASSCF : nocc[" << irrep << "] + ndmrg[" << irrep << "] + nvirt[" << irrep << "] = " << norb_in << " and in the Hamiltonian norb[" << irrep << "] = " << norb_ham << "." << endl; } assert( norb_ham == norb_in ); } iHandler = new DMRGSCFindices( L, SymmInfo.getGroupNumber(), nocc, ndmrg, nvirt ); unitary = new DMRGSCFunitary( iHandler ); // Allocate space for the DMRG 1DM and 2DM nOrbDMRG = iHandler->getDMRGcumulative( num_irreps ); DMRG1DM = new double[nOrbDMRG * nOrbDMRG]; DMRG2DM = new double[nOrbDMRG * nOrbDMRG * nOrbDMRG * nOrbDMRG]; // To store the F-matrix and Q-matrix(occ,act) theFmatrix = new DMRGSCFmatrix( iHandler ); theFmatrix->clear(); theQmatOCC = new DMRGSCFmatrix( iHandler ); theQmatOCC->clear(); theQmatACT = new DMRGSCFmatrix( iHandler ); theQmatACT->clear(); theQmatWORK= new DMRGSCFmatrix( iHandler ); theQmatWORK->clear(); theTmatrix = new DMRGSCFmatrix( iHandler ); theTmatrix->clear(); if ( am_i_master ){ if (( docc != NULL ) && ( socc != NULL )){ checkHF( docc, socc ); } // Print the MO info. This requires the iHandler to be created... iHandler->Print(); cout << "DMRGSCF::setupStart : Number of variables in the x-matrix = " << unitary->getNumVariablesX() << endl; } this->tmp_folder = new_tmp_folder; } CheMPS2::CASSCF::~CASSCF(){ delete [] DMRG1DM; delete [] DMRG2DM; //The following objects depend on iHandler: delete them first delete theFmatrix; delete theQmatOCC; delete theQmatACT; delete theQmatWORK; delete theTmatrix; delete unitary; delete iHandler; } int CheMPS2::CASSCF::get_num_irreps(){ return num_irreps; } void CheMPS2::CASSCF::copy2DMover( TwoDM * theDMRG2DM, const int LAS, double * two_dm ){ for ( int i1 = 0; i1 < LAS; i1++ ){ for ( int i2 = 0; i2 < LAS; i2++ ){ for ( int i3 = 0; i3 < LAS; i3++ ){ for ( int i4 = 0; i4 < LAS; i4++ ){ // The assignment has been changed to an addition for state-averaged calculations! two_dm[ i1 + LAS * ( i2 + LAS * ( i3 + LAS * i4 ) ) ] += theDMRG2DM->getTwoDMA_HAM( i1, i2, i3, i4 ); } } } } } void CheMPS2::CASSCF::setDMRG1DM( const int num_elec, const int LAS, double * one_dm, double * two_dm ){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif if ( am_i_master ){ const double prefactor = 1.0 / ( num_elec - 1 ); for ( int cnt1 = 0; cnt1 < LAS; cnt1++ ){ for ( int cnt2 = cnt1; cnt2 < LAS; cnt2++ ){ double value = 0.0; for ( int sum = 0; sum < LAS; sum++ ){ value += two_dm[ cnt1 + LAS * ( sum + LAS * ( cnt2 + LAS * sum ) ) ]; } one_dm[ cnt1 + LAS * cnt2 ] = prefactor * value; one_dm[ cnt2 + LAS * cnt1 ] = one_dm[ cnt1 + LAS * cnt2 ]; } } } #ifdef CHEMPS2_MPI_COMPILATION MPIchemps2::broadcast_array_double( one_dm, LAS * LAS, MPI_CHEMPS2_MASTER ); #endif } void CheMPS2::CASSCF::fillLocalizedOrbitalRotations( DMRGSCFunitary * umat, DMRGSCFindices * idx, double * eigenvecs ){ const int n_irreps = idx->getNirreps(); const int tot_dmrg = idx->getDMRGcumulative( n_irreps ); const int size = tot_dmrg * tot_dmrg; for ( int cnt = 0; cnt < size; cnt++ ){ eigenvecs[ cnt ] = 0.0; } int passed = 0; for ( int irrep = 0; irrep < n_irreps; irrep++ ){ const int NDMRG = idx->getNDMRG( irrep ); if ( NDMRG > 0 ){ double * Ublock = umat->getBlock( irrep ); double * Eblock = eigenvecs + passed * ( 1 + tot_dmrg ); for ( int row = 0; row < NDMRG; row++ ){ for ( int col = 0; col < NDMRG; col++ ){ Eblock[ row + tot_dmrg * col ] = Ublock[ col + NDMRG * row ]; //Eigs = Unit^T } } } passed += NDMRG; } } void CheMPS2::CASSCF::rotateOldToNew( DMRGSCFmatrix * myMatrix ){ for ( int irrep = 0; irrep < num_irreps; irrep++ ){ int NORB = iHandler->getNORB( irrep ); if ( NORB > 0 ){ double * Umat = unitary->getBlock( irrep ); double * work = theQmatWORK->getBlock( irrep ); double * block = myMatrix->getBlock( irrep ); double one = 1.0; double set = 0.0; char trans = 'T'; char notrans = 'N'; dgemm_( ¬rans, ¬rans, &NORB, &NORB, &NORB, &one, Umat, &NORB, block, &NORB, &set, work, &NORB ); dgemm_( ¬rans, &trans, &NORB, &NORB, &NORB, &one, work, &NORB, Umat, &NORB, &set, block, &NORB ); } } } void CheMPS2::CASSCF::constructCoulombAndExchangeMatrixInOrigIndices( DMRGSCFmatrix * density, DMRGSCFmatrix * result ){ for ( int irrepQ = 0; irrepQ < num_irreps; irrepQ++ ){ const int linearsizeQ = iHandler->getNORB( irrepQ ); const int triangsizeQ = ( linearsizeQ * ( linearsizeQ + 1 ) ) / 2; int myindices[ 2 ]; #pragma omp parallel for schedule(static) for ( int combinedindex = 0; combinedindex < triangsizeQ; combinedindex++ ){ Special::invert_triangle_two( combinedindex, myindices ); const int rowQ = myindices[ 0 ]; const int colQ = myindices[ 1 ]; double value = 0.0; for ( int irrepN = 0; irrepN < num_irreps; irrepN++ ){ const int linearsizeN = iHandler->getNORB( irrepN ); for ( int rowN = 0; rowN < linearsizeN; rowN++ ){ value += density->get( irrepN, rowN, rowN ) * ( VMAT_ORIG->get( irrepQ, irrepN, irrepQ, irrepN, rowQ, rowN, colQ, rowN ) - 0.5 * VMAT_ORIG->get( irrepQ, irrepQ, irrepN, irrepN, rowQ, colQ, rowN, rowN ) ); for ( int colN = rowN + 1; colN < linearsizeN; colN++ ){ value += density->get( irrepN, rowN, colN ) * ( 2 * VMAT_ORIG->get( irrepQ, irrepN, irrepQ, irrepN, rowQ, rowN, colQ, colN ) - 0.5 * VMAT_ORIG->get( irrepQ, irrepQ, irrepN, irrepN, rowQ, colQ, rowN, colN ) - 0.5 * VMAT_ORIG->get( irrepQ, irrepQ, irrepN, irrepN, rowQ, colQ, colN, rowN ) ); } } } result->set( irrepQ, rowQ, colQ, value ); result->set( irrepQ, colQ, rowQ, value ); } } } void CheMPS2::CASSCF::buildQmatOCC(){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif if ( am_i_master ){ for ( int irrep = 0; irrep < num_irreps; irrep++ ){ int NORB = iHandler->getNORB( irrep ); if ( NORB > 0 ){ int NOCC = iHandler->getNOCC( irrep ); double two = 2.0; double set = 0.0; char trans = 'T'; char notrans = 'N'; double * Umat = unitary->getBlock( irrep ); double * work = theQmatWORK->getBlock( irrep ); dgemm_( &trans, ¬rans, &NORB, &NORB, &NOCC, &two, Umat, &NORB, Umat, &NORB, &set, work, &NORB ); } } constructCoulombAndExchangeMatrixInOrigIndices( theQmatWORK, theQmatOCC ); rotateOldToNew( theQmatOCC ); } #ifdef CHEMPS2_MPI_COMPILATION theQmatOCC->broadcast( MPI_CHEMPS2_MASTER ); #endif } void CheMPS2::CASSCF::buildQmatACT(){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif if ( am_i_master ){ for ( int irrep = 0; irrep < num_irreps; irrep++ ){ int NORB = iHandler->getNORB( irrep ); if ( NORB > 0 ){ int NACT = iHandler->getNDMRG( irrep ); double one = 1.0; double set = 0.0; char trans = 'T'; char notrans = 'N'; double * Umat = unitary->getBlock( irrep ) + iHandler->getNOCC( irrep ); double * work = theQmatWORK->getBlock( irrep ); double * work2 = theQmatACT->getBlock( irrep ); double * RDM = DMRG1DM + iHandler->getDMRGcumulative( irrep ) * ( 1 + nOrbDMRG ); dgemm_( &trans, ¬rans, &NORB, &NACT, &NACT, &one, Umat, &NORB, RDM, &nOrbDMRG, &set, work2, &NORB ); dgemm_( ¬rans, ¬rans, &NORB, &NORB, &NACT, &one, work2, &NORB, Umat, &NORB, &set, work, &NORB ); } } constructCoulombAndExchangeMatrixInOrigIndices( theQmatWORK, theQmatACT ); rotateOldToNew( theQmatACT ); } #ifdef CHEMPS2_MPI_COMPILATION theQmatACT->broadcast( MPI_CHEMPS2_MASTER ); #endif } void CheMPS2::CASSCF::buildTmatrix(){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif if ( am_i_master ){ for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int NumORB = iHandler->getNORB( irrep ); for ( int row = 0; row < NumORB; row++ ){ for ( int col = 0; col < NumORB; col++ ){ theTmatrix->set( irrep, row, col, TMAT_ORIG->get( irrep, row, col ) ); } } } rotateOldToNew( theTmatrix ); } #ifdef CHEMPS2_MPI_COMPILATION theTmatrix->broadcast( MPI_CHEMPS2_MASTER ); #endif } void CheMPS2::CASSCF::fillConstAndTmatDMRG( Hamiltonian * HamDMRG ) const{ //Constant part of the energy double constant = NUCL_ORIG; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int NOCC = iHandler->getNOCC( irrep ); for ( int occ = 0; occ < NOCC; occ++ ){ constant += ( 2 * theTmatrix->get( irrep, occ, occ ) + theQmatOCC->get( irrep, occ, occ ) ); } } HamDMRG->setEconst( constant ); //One-body terms: diagonal in the irreps for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int JUMP = iHandler->getDMRGcumulative( irrep ); const int NACT = iHandler->getNDMRG( irrep ); const int NOCC = iHandler->getNOCC( irrep ); for ( int cnt1 = 0; cnt1 < NACT; cnt1++ ){ for ( int cnt2 = cnt1; cnt2 < NACT; cnt2++ ){ HamDMRG->setTmat( JUMP + cnt1, JUMP + cnt2, ( theTmatrix->get( irrep, NOCC + cnt1, NOCC + cnt2 ) + theQmatOCC->get( irrep, NOCC + cnt1, NOCC + cnt2 ) ) ); } } } } void CheMPS2::CASSCF::copy_active( double * origin, DMRGSCFmatrix * result, const DMRGSCFindices * idx, const bool one_rdm ){ result->clear(); const int n_irreps = idx->getNirreps(); const int tot_dmrg = idx->getDMRGcumulative( n_irreps ); int passed = 0; for ( int irrep = 0; irrep < n_irreps; irrep++ ){ const int NOCC = idx->getNOCC( irrep ); const int NACT = idx->getNDMRG( irrep ); if ( one_rdm ){ for ( int orb = 0; orb < NOCC; orb++ ){ result->set( irrep, orb, orb, 2.0 ); } } for ( int row = 0; row < NACT; row++ ){ for ( int col = 0; col < NACT; col++ ){ result->set( irrep, NOCC + row, NOCC + col, origin[ passed + row + tot_dmrg * ( passed + col ) ] ); } } passed += NACT; } assert( passed == tot_dmrg ); } void CheMPS2::CASSCF::copy_active( const DMRGSCFmatrix * origin, double * result, const DMRGSCFindices * idx ){ const int n_irreps = idx->getNirreps(); const int tot_dmrg = idx->getDMRGcumulative( n_irreps ); for ( int cnt = 0; cnt < tot_dmrg * tot_dmrg; cnt++ ){ result[ cnt ] = 0.0; } int passed = 0; for ( int irrep = 0; irrep < n_irreps; irrep++ ){ const int NOCC = idx->getNOCC( irrep ); const int NACT = idx->getNDMRG( irrep ); for ( int row = 0; row < NACT; row++ ){ for ( int col = 0; col < NACT; col++ ){ result[ passed + row + tot_dmrg * ( passed + col ) ] = origin->get( irrep, NOCC + row, NOCC + col ); } } passed += NACT; } assert( passed == tot_dmrg ); } void CheMPS2::CASSCF::block_diagonalize( const char space, const DMRGSCFmatrix * Mat, DMRGSCFunitary * Umat, double * work1, double * work2, const DMRGSCFindices * idx, const bool invert, double * two_dm, double * three_dm, double * contract ){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif const int n_irreps = idx->getNirreps(); const int tot_dmrg = idx->getDMRGcumulative( n_irreps ); if ( am_i_master ){ for ( int irrep = 0; irrep < n_irreps; irrep++ ){ int NTOTAL = idx->getNORB( irrep ); int NROTATE = (( space == 'O' ) ? idx->getNOCC( irrep ) : (( space == 'A' ) ? idx->getNDMRG( irrep ) : idx->getNVIRT( irrep ))); int NSHIFT = (( space == 'O' ) ? 0 : (( space == 'A' ) ? idx->getNOCC( irrep ) : NTOTAL - NROTATE )); int NJUMP = idx->getDMRGcumulative( irrep ); if ( NROTATE > 1 ){ // Diagonalize the relevant block of Mat { for ( int row = 0; row < NROTATE; row++ ){ for ( int col = 0; col < NROTATE; col++ ){ work1[ row + NROTATE * col ] = Mat->get( irrep, NSHIFT + row, NSHIFT + col ); } } char jobz = 'V'; char uplo = 'U'; int info; int size = max( 3 * NROTATE - 1, NROTATE * NROTATE ); dsyev_( &jobz, &uplo, &NROTATE, work1, &NROTATE, work2 + size, work2, &size, &info ); } // Invert the order (large to small) if ( invert ){ for ( int col = 0; col < NROTATE / 2; col++ ){ for ( int row = 0; row < NROTATE; row++ ){ const double temp = work1[ row + NROTATE * ( NROTATE - 1 - col ) ]; work1[ row + NROTATE * ( NROTATE - 1 - col ) ] = work1[ row + NROTATE * col ]; work1[ row + NROTATE * col ] = temp; } } } // Adjust the u-matrix accordingly double * umatrix = Umat->getBlock( irrep ) + NSHIFT; for ( int row = 0; row < NROTATE; row++ ){ for ( int col = 0; col < NTOTAL; col++ ){ work2[ row + NROTATE * col ] = umatrix[ row + NTOTAL * col ]; } } char trans = 'T'; char notrans = 'N'; double one = 1.0; double set = 0.0; dgemm_( &trans, ¬rans, &NROTATE, &NTOTAL, &NROTATE, &one, work1, &NROTATE, work2, &NROTATE, &set, umatrix, &NTOTAL ); // Adjust the two_dm, three_dm, and contract objects accordingly if ( space == 'A' ){ if ( two_dm != NULL ){ rotate_active_space_object( 4, two_dm, work2, work1, tot_dmrg, NJUMP, NROTATE ); } if ( three_dm != NULL ){ rotate_active_space_object( 6, three_dm, work2, work1, tot_dmrg, NJUMP, NROTATE ); } if ( contract != NULL ){ rotate_active_space_object( 6, contract, work2, work1, tot_dmrg, NJUMP, NROTATE ); } } } } } #ifdef CHEMPS2_MPI_COMPILATION Umat->broadcast( MPI_CHEMPS2_MASTER ); if ( space == 'A' ){ if ( two_dm != NULL ){ MPIchemps2::broadcast_array_double( two_dm, tot_dmrg * tot_dmrg * tot_dmrg * tot_dmrg, MPI_CHEMPS2_MASTER ); } if ( three_dm != NULL ){ MPIchemps2::broadcast_array_double( three_dm, tot_dmrg * tot_dmrg * tot_dmrg * tot_dmrg * tot_dmrg * tot_dmrg, MPI_CHEMPS2_MASTER ); } if ( contract != NULL ){ MPIchemps2::broadcast_array_double( contract, tot_dmrg * tot_dmrg * tot_dmrg * tot_dmrg * tot_dmrg * tot_dmrg, MPI_CHEMPS2_MASTER ); } } #endif } void CheMPS2::CASSCF::rotate_active_space_object( const int num_indices, double * object, double * work, double * rotation, const int LAS, const int NJUMP, const int NROTATE ){ assert( num_indices >= 2 ); assert( num_indices <= 6 ); int power[] = { 1, LAS, LAS * LAS, LAS * LAS * LAS, LAS * LAS * LAS * LAS, LAS * LAS * LAS * LAS * LAS, LAS * LAS * LAS * LAS * LAS * LAS }; for ( int rot_index = num_indices - 1; rot_index >= 0; rot_index-- ){ for ( int block = 0; block < power[ num_indices - 1 - rot_index ]; block++ ){ double * mat = object + power[ rot_index ] * NJUMP + power[ rot_index + 1 ] * block; int ROTDIM = NROTATE; char notrans = 'N'; double one = 1.0; double set = 0.0; dgemm_( ¬rans, ¬rans, power + rot_index, &ROTDIM, &ROTDIM, &one, mat, power + rot_index, rotation, &ROTDIM, &set, work, power + rot_index ); int size = power[ rot_index ] * NROTATE; int inc1 = 1; dcopy_( &size, work, &inc1, mat, &inc1 ); } } } CheMPS2-1.8.9/CheMPS2/CASSCFdebug.cpp000066400000000000000000000123261336564451100165240ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include "CASSCF.h" using std::cout; using std::endl; void CheMPS2::CASSCF::checkHF( int * docc, int * socc ){ double EnergyHF = NUCL_ORIG; cout << "Single particle energy levels : " << endl; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ for ( int orb = 0; orb < iHandler->getNORB( irrep ); orb++ ){ double SPenergy = TMAT_ORIG->get( irrep, orb, orb ); const int num_beta = (( orb < docc[ irrep ] ) ? 1 : 0 ); const int num_alpha = (( orb < docc[ irrep ] + socc[ irrep ] ) ? 1 : 0 ); const int num_total = num_alpha + num_beta; EnergyHF += num_total * TMAT_ORIG->get( irrep, orb, orb ); for ( int irrep2 = 0; irrep2 < num_irreps; irrep2++ ){ for ( int orb2 = 0; orb2 < iHandler->getNORB( irrep2 ); orb2++ ){ const int num_beta2 = (( orb2 < docc[ irrep2 ] ) ? 1 : 0 ); const int num_alpha2 = (( orb2 < docc[ irrep2 ] + socc[ irrep2 ] ) ? 1 : 0 ); const int num_total2 = num_alpha2 + num_beta2; SPenergy += ( num_total2 * VMAT_ORIG->get( irrep, irrep2, irrep, irrep2, orb, orb2, orb, orb2 ) - num_alpha2 * VMAT_ORIG->get( irrep, irrep, irrep2, irrep2, orb, orb, orb2, orb2 ) ); EnergyHF += 0.5 * num_total * num_total2 * VMAT_ORIG->get( irrep, irrep2, irrep, irrep2, orb, orb2, orb, orb2 ); EnergyHF -= 0.5 * ( num_alpha * num_alpha2 + num_beta * num_beta2 ) * VMAT_ORIG->get( irrep, irrep, irrep2, irrep2, orb, orb, orb2, orb2 ); } } cout << " Orb " << iHandler->getOrigNOCCstart( irrep ) + orb << " : "<< orb + 1 << SymmInfo.getIrrepName(irrep) << " = " << SPenergy << endl; } } cout << "HF energy = " << EnergyHF << endl; } void CheMPS2::CASSCF::coeff_fe2( DMRG * theDMRG ){ /* For the iron dimer: int NOCC[] = { 5, 0, 2, 2, 0, 5, 2, 2 }; // 36 core electrons int NDMRG[] = { 6, 2, 3, 3, 2, 6, 3, 3 }; // 16 active space electrons, 28 active space orbitals */ assert( nOrbDMRG == 28 ); // Ag B1g B2g B3g Au B1u B2u B3u int coeff0[] = { 2, 2, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 2, 0, 0, 2, 0, 0 }; int coeff1[] = { 2, 1, 1, 0, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 1, 0, 2, 1, 1, 0, 0, 0, 2, 0, 0, 1, 0, 0 }; int coeff2[] = { 2, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 2, 0, 0, 1, 0, 2, 1, 1, 0, 0, 0, 1, 0, 0, 2, 0, 0 }; int coeff3[] = { 2, 2, 1, 0, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0 }; int coeff4[] = { 2, 1, 1, 0, 0, 0, 2, 0, 2, 0, 0, 1, 0, 0, 1, 0, 2, 1, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0 }; int coeff5[] = { 2, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 2, 0, 0, 1, 0, 2, 1, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0 }; int coeff6[] = { 2, 2, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 2, 1, 1, 0, 0, 0, 2, 0, 0, 2, 0, 0 }; int coeff7[] = { 2, 2, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0 }; const double value0 = theDMRG->getSpecificCoefficient( coeff0 ); const double value1 = theDMRG->getSpecificCoefficient( coeff1 ); const double value2 = theDMRG->getSpecificCoefficient( coeff2 ); cout << "Coeff of main contribution ^9 Sigma_g^- = " << value0 << endl; cout << "Coeff of | pi_x > excitation ^9 Sigma_g^- = " << value1 << endl; cout << "Coeff of | pi_y > excitation ^9 Sigma_g^- = " << value2 << endl; const double value3 = theDMRG->getSpecificCoefficient( coeff3 ); const double value4 = theDMRG->getSpecificCoefficient( coeff4 ); const double value5 = theDMRG->getSpecificCoefficient( coeff5 ); cout << "Coeff of main contribution ^7 Delta_u = " << value3 << endl; cout << "Coeff of | pi_x > excitation ^7 Delta_u = " << value4 << endl; cout << "Coeff of | pi_y > excitation ^7 Delta_u = " << value5 << endl; const double value6 = theDMRG->getSpecificCoefficient( coeff6 ); const double value7 = theDMRG->getSpecificCoefficient( coeff7 ); cout << "Coeff of main contrib anion ^8 Sigma_u^- = " << value6 << endl; cout << "Coeff of main contrib cation ^8 Sigma_u^- = " << value7 << endl; } CheMPS2-1.8.9/CheMPS2/CASSCFnewtonraphson.cpp000066400000000000000000001422631336564451100203470ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include "CASSCF.h" #include "Lapack.h" #include "DMRGSCFrotations.h" #include "EdmistonRuedenberg.h" #include "Davidson.h" #include "FCI.h" #include "MPIchemps2.h" using std::string; using std::ifstream; using std::cout; using std::endl; using std::max; void CheMPS2::CASSCF::delete_file( const string filename ){ struct stat file_info; const int thestat = stat( filename.c_str(), &file_info ); if ( thestat == 0 ){ const string temp = "rm " + filename; int info = system( temp.c_str() ); cout << "Info on system( " << temp << " ) = " << info << endl; } else { cout << "No file " << filename << " found." << endl; } } double CheMPS2::CASSCF::solve( const int Nelectrons, const int TwoS, const int Irrep, ConvergenceScheme * OptScheme, const int rootNum, DMRGSCFoptions * scf_options ){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif const int num_elec = Nelectrons - 2 * iHandler->getNOCCsum(); assert( num_elec >= 0 ); assert(( OptScheme != NULL ) || ( rootNum == 1 )); // Convergence variables double gradNorm = 1.0; double updateNorm = 1.0; double * gradient = NULL; if ( am_i_master ){ gradient = new double[ unitary->getNumVariablesX() ]; for ( int cnt = 0; cnt < unitary->getNumVariablesX(); cnt++ ){ gradient[ cnt ] = 0.0; } } double * diis_vec = NULL; double Energy = 1e8; // The CheMPS2::Problem for the inner DMRG calculation Hamiltonian * HamDMRG = new Hamiltonian( nOrbDMRG, SymmInfo.getGroupNumber(), iHandler->getIrrepOfEachDMRGorbital() ); Problem * Prob = new Problem( HamDMRG, TwoS, num_elec, Irrep ); Prob->SetupReorderD2h(); // Doesn't matter if the group isn't D2h, Prob checks it. // Determine the maximum NORB( irrep ) and the max_block_size for the ERI orbital rotation const int maxlinsize = iHandler->getNORBmax(); const long long fullsize = ((long long) maxlinsize ) * ((long long) maxlinsize ) * ((long long) maxlinsize ) * ((long long) maxlinsize ); const string tmp_filename = tmp_folder + "/" + CheMPS2::DMRGSCF_eri_storage_name; const int dmrgsize_power4 = nOrbDMRG * nOrbDMRG * nOrbDMRG * nOrbDMRG; // For ( ERI rotation, update unitary, block diagonalize, orbital localization ) DMRGSCFintegrals * theRotatedTEI = new DMRGSCFintegrals( iHandler ); DMRGSCFwtilde * wmattilde = new DMRGSCFwtilde( iHandler ); const int temp_work_size = (( fullsize > CheMPS2::DMRGSCF_max_mem_eri_tfo ) ? CheMPS2::DMRGSCF_max_mem_eri_tfo : fullsize ); const int work_mem_size = max( max( temp_work_size , maxlinsize * maxlinsize * 4 ) , dmrgsize_power4 ); double * mem1 = new double[ work_mem_size ]; double * mem2 = new double[ work_mem_size ]; // Only MASTER process has Edmiston-Ruedenberg active space localizer EdmistonRuedenberg * theLocalizer = NULL; if (( scf_options->getWhichActiveSpace() >= 2 ) && ( am_i_master )){ theLocalizer = new EdmistonRuedenberg( HamDMRG->getVmat(), iHandler->getGroupNumber() ); } // Load unitary from disk if ( scf_options->getStoreUnitary() ){ if ( am_i_master ){ struct stat file_info; int master_stat = stat( (scf_options->getUnitaryStorageName()).c_str(), &file_info ); if ( master_stat == 0 ){ unitary->loadU( scf_options->getUnitaryStorageName() ); } } #ifdef CHEMPS2_MPI_COMPILATION unitary->broadcast( MPI_CHEMPS2_MASTER ); // Unitary was set to the identity at construction #endif } // Only master has DIIS; load DIIS from disk DIIS * diis = NULL; if (( scf_options->getDoDIIS() ) && ( scf_options->getStoreDIIS() ) && ( am_i_master )){ struct stat file_info; int master_stat = stat( (scf_options->getDIISStorageName()).c_str(), &file_info ); if ( master_stat == 0 ){ const int diis_vec_size = iHandler->getROTparamsize(); diis = new DIIS( diis_vec_size, unitary->getNumVariablesX(), scf_options->getNumDIISVecs() ); diis->loadDIIS( scf_options->getDIISStorageName() ); diis_vec = new double[ diis_vec_size ]; } } int nIterations = 0; /******************************* *** Actual DMRGSCF loops *** *******************************/ while (( gradNorm > scf_options->getGradientThreshold() ) && ( nIterations < scf_options->getMaxIterations() )){ nIterations++; // Update the unitary transformation if (( unitary->getNumVariablesX() > 0 ) && ( am_i_master )){ unitary->updateUnitary( mem1, mem2, gradient, true, true ); //multiply = compact = true if (( scf_options->getDoDIIS() ) && ( updateNorm <= scf_options->getDIISGradientBranch() )){ if ( scf_options->getWhichActiveSpace() == 1 ){ cout << "DMRGSCF::solve : DIIS has started. Active space not rotated to NOs anymore!" << endl; } if ( scf_options->getWhichActiveSpace() == 2 ){ cout << "DMRGSCF::solve : DIIS has started. Active space not rotated to localized orbitals anymore!" << endl; } if ( scf_options->getWhichActiveSpace() == 3 ){ cout << "DMRGSCF::solve : DIIS has started. Active space not ordered according to the Fiedler vector of the exchange matrix anymore!" << endl; } if ( diis == NULL ){ const int diis_vec_size = iHandler->getROTparamsize(); diis = new DIIS( diis_vec_size, unitary->getNumVariablesX(), scf_options->getNumDIISVecs() ); diis_vec = new double[ diis_vec_size ]; unitary->makeSureAllBlocksDetOne( mem1, mem2 ); } unitary->getLog( diis_vec, mem1, mem2 ); diis->appendNew( gradient, diis_vec ); diis->calculateParam( diis_vec ); unitary->updateUnitary( mem1, mem2, diis_vec, false, false ); //multiply = compact = false } } if (( am_i_master ) && ( scf_options->getStoreUnitary() ) && ( gradNorm != 1.0 )){ unitary->saveU( scf_options->getUnitaryStorageName() ); } if (( am_i_master ) && ( scf_options->getStoreDIIS() ) && ( updateNorm != 1.0 ) && ( diis != NULL )){ diis->saveDIIS( scf_options->getDIISStorageName() ); } int master_diis = (( diis != NULL ) ? 1 : 0 ); #ifdef CHEMPS2_MPI_COMPILATION MPIchemps2::broadcast_array_int( &master_diis, 1, MPI_CHEMPS2_MASTER ); unitary->broadcast( MPI_CHEMPS2_MASTER ); #endif // Fill HamDMRG buildTmatrix(); buildQmatOCC(); fillConstAndTmatDMRG( HamDMRG ); if ( am_i_master ){ DMRGSCFrotations::rotate( VMAT_ORIG, HamDMRG->getVmat(), NULL, 'A', 'A', 'A', 'A', iHandler, unitary, mem1, mem2, work_mem_size, tmp_filename ); } #ifdef CHEMPS2_MPI_COMPILATION HamDMRG->getVmat()->broadcast( MPI_CHEMPS2_MASTER ); #endif // Localize the active space and reorder the orbitals within each irrep based on the exchange matrix if (( scf_options->getWhichActiveSpace() == 2 ) && ( master_diis == 0 )){ // When the DIIS has started: stop if ( am_i_master ){ theLocalizer->Optimize(mem1, mem2, scf_options->getStartLocRandom()); theLocalizer->FiedlerExchange(maxlinsize, mem1, mem2); fillLocalizedOrbitalRotations(theLocalizer->getUnitary(), iHandler, mem1); unitary->rotateActiveSpaceVectors(mem1, mem2); } #ifdef CHEMPS2_MPI_COMPILATION unitary->broadcast( MPI_CHEMPS2_MASTER ); #endif buildTmatrix(); //With an updated unitary, the Qocc, Tmat, and HamDMRG objects need to be updated as well. buildQmatOCC(); fillConstAndTmatDMRG( HamDMRG ); if ( am_i_master ){ DMRGSCFrotations::rotate( VMAT_ORIG, HamDMRG->getVmat(), NULL, 'A', 'A', 'A', 'A', iHandler, unitary, mem1, mem2, work_mem_size, tmp_filename ); cout << "DMRGSCF::solve : Rotated the active space to localized orbitals, sorted according to the exchange matrix." << endl; } #ifdef CHEMPS2_MPI_COMPILATION HamDMRG->getVmat()->broadcast( MPI_CHEMPS2_MASTER ); #endif } // Reorder the orbitals based on the Fiedler vector of the exchange matrix if (( scf_options->getWhichActiveSpace() == 3 ) && ( master_diis == 0 )){ // When the DIIS has started: stop int * dmrg2ham = new int[ nOrbDMRG ]; if ( am_i_master ){ theLocalizer->FiedlerGlobal( dmrg2ham ); } #ifdef CHEMPS2_MPI_COMPILATION MPIchemps2::broadcast_array_int( dmrg2ham, nOrbDMRG, MPI_CHEMPS2_MASTER ); #endif Prob->setup_reorder_custom( dmrg2ham ); delete [] dmrg2ham; } if (( OptScheme == NULL ) && ( rootNum == 1 )){ // Do FCI, and calculate the 2DM if ( am_i_master ){ const int nalpha = ( num_elec + TwoS ) / 2; const int nbeta = ( num_elec - TwoS ) / 2; const double workmem = 1000.0; // 1GB const int verbose = 2; CheMPS2::FCI * theFCI = new CheMPS2::FCI( HamDMRG, nalpha, nbeta, Irrep, workmem, verbose ); double * inoutput = new double[ theFCI->getVecLength(0) ]; theFCI->ClearVector( theFCI->getVecLength(0), inoutput ); inoutput[ theFCI->LowestEnergyDeterminant() ] = 1.0; Energy = theFCI->GSDavidson( inoutput ); theFCI->Fill2RDM( inoutput, DMRG2DM ); delete theFCI; delete [] inoutput; } #ifdef CHEMPS2_MPI_COMPILATION MPIchemps2::broadcast_array_double( &Energy, 1, MPI_CHEMPS2_MASTER ); MPIchemps2::broadcast_array_double( DMRG2DM, dmrgsize_power4, MPI_CHEMPS2_MASTER ); #endif } else { // Do the DMRG sweeps, and calculate the 2DM assert( OptScheme != NULL ); for ( int cnt = 0; cnt < dmrgsize_power4; cnt++ ){ DMRG2DM[ cnt ] = 0.0; } // Clear the 2-RDM ( to allow for state-averaged calculations ) DMRG * theDMRG = new DMRG( Prob, OptScheme, CheMPS2::DMRG_storeMpsOnDisk, tmp_folder ); for ( int state = 0; state < rootNum; state++ ){ if ( state > 0 ){ theDMRG->newExcitation( fabs( Energy ) ); } Energy = theDMRG->Solve(); if ( scf_options->getStateAveraging() ){ // When SA-DMRGSCF: 2DM += current 2DM theDMRG->calc2DMandCorrelations(); copy2DMover( theDMRG->get2DM(), nOrbDMRG, DMRG2DM ); } if (( state == 0 ) && ( rootNum > 1 )){ theDMRG->activateExcitations( rootNum - 1 ); } } if ( !( scf_options->getStateAveraging() )){ // When SS-DMRGSCF: 2DM += last 2DM theDMRG->calc2DMandCorrelations(); copy2DMover( theDMRG->get2DM(), nOrbDMRG, DMRG2DM ); } if (( scf_options->getDumpCorrelations() ) && ( am_i_master )){ theDMRG->getCorrelations()->Print(); } if (CheMPS2::DMRG_storeMpsOnDisk){ theDMRG->deleteStoredMPS(); } if (CheMPS2::DMRG_storeRenormOptrOnDisk){ theDMRG->deleteStoredOperators(); } delete theDMRG; if (( scf_options->getStateAveraging() ) && ( rootNum > 1 )){ const double averagingfactor = 1.0 / rootNum; for ( int cnt = 0; cnt < dmrgsize_power4; cnt++ ){ DMRG2DM[ cnt ] *= averagingfactor; } } } setDMRG1DM( num_elec, nOrbDMRG, DMRG1DM, DMRG2DM ); // Possibly rotate the active space to the natural orbitals if (( scf_options->getWhichActiveSpace() == 1 ) && ( master_diis == 0 )){ // When the DIIS has started: stop copy_active( DMRG1DM, theQmatWORK, iHandler, true ); block_diagonalize( 'A', theQmatWORK, unitary, mem1, mem2, iHandler, true, DMRG2DM, NULL, NULL ); // Unitary is updated and DMRG2DM rotated setDMRG1DM( num_elec, nOrbDMRG, DMRG1DM, DMRG2DM ); buildTmatrix(); // With an updated unitary, the Qocc and Tmat matrices need to be updated as well. buildQmatOCC(); if ( am_i_master ){ cout << "DMRGSCF::solve : Rotated the active space to natural orbitals, sorted according to the NOON." << endl; } } if (( nIterations == scf_options->getMaxIterations() ) && ( am_i_master ) && ( scf_options->getStoreUnitary() )){ unitary->saveU( scf_options->getUnitaryStorageName() ); } // Calculate the matrix elements needed to calculate the gradient and hessian buildQmatACT(); if ( am_i_master ){ DMRGSCFrotations::rotate( VMAT_ORIG, NULL, theRotatedTEI, 'C', 'C', 'F', 'F', iHandler, unitary, mem1, mem2, work_mem_size, tmp_filename ); DMRGSCFrotations::rotate( VMAT_ORIG, NULL, theRotatedTEI, 'C', 'V', 'C', 'V', iHandler, unitary, mem1, mem2, work_mem_size, tmp_filename ); buildFmat( theFmatrix, theTmatrix, theQmatOCC, theQmatACT, iHandler, theRotatedTEI, DMRG2DM, DMRG1DM ); buildWtilde( wmattilde, theTmatrix, theQmatOCC, theQmatACT, iHandler, theRotatedTEI, DMRG2DM, DMRG1DM ); augmentedHessianNR( theFmatrix, wmattilde, iHandler, unitary, gradient, &updateNorm, &gradNorm ); // On return the gradient contains the update } #ifdef CHEMPS2_MPI_COMPILATION MPIchemps2::broadcast_array_double( &updateNorm, 1, MPI_CHEMPS2_MASTER ); MPIchemps2::broadcast_array_double( &gradNorm, 1, MPI_CHEMPS2_MASTER ); #endif } delete [] mem1; delete [] mem2; delete theRotatedTEI; delete wmattilde; if ( am_i_master ){ delete_file( tmp_filename ); } delete Prob; delete HamDMRG; if ( gradient != NULL ){ delete [] gradient; } if ( diis_vec != NULL ){ delete [] diis_vec; } if ( diis != NULL ){ delete diis; } if ( theLocalizer != NULL ){ delete theLocalizer; } successful_solve = true; return Energy; } void CheMPS2::CASSCF::augmentedHessianNR( DMRGSCFmatrix * localFmat, DMRGSCFwtilde * localwtilde, const DMRGSCFindices * localIdx, const DMRGSCFunitary * localUmat, double * theupdate, double * updateNorm, double * gradNorm ){ /* A good read to understand (1) how the augmented Hessian arises from a rational function optimization (2) where the parameter lambda in Eq. (22) of Yanai, IJQC 109, 2178-2190 (2009) comes from (3) why the smallest algebraic eigenvalue + corresponding eigenvector should be retained for minimizations Banerjee, Adams, Simons, Shepard, "Search for stationary points on surfaces", J. Phys. Chem. 1985, volume 89, pages 52-57, doi:10.1021/j100247a015 */ //Calculate the gradient const int x_linearlength = localUmat->getNumVariablesX(); gradNorm[ 0 ] = construct_gradient( localFmat, localIdx, theupdate ); //Find the lowest eigenvalue and corresponding eigenvector of the augmented hessian { Davidson deBoskabouter( x_linearlength + 1, CheMPS2::DAVIDSON_NUM_VEC, CheMPS2::DAVIDSON_NUM_VEC_KEEP, CheMPS2::DAVIDSON_FCI_RTOL, CheMPS2::DAVIDSON_PRECOND_CUTOFF, false ); // No debug printing double ** whichpointers = new double*[ 2 ]; char instruction = deBoskabouter.FetchInstruction( whichpointers ); assert( instruction == 'A' ); diag_hessian( localFmat, localwtilde, localIdx, whichpointers[ 1 ] ); whichpointers[ 1 ][ x_linearlength ] = 0.0; for ( int cnt = 0; cnt < x_linearlength; cnt++ ){ // Initial guess = [ -gradient / diag(hessian) , 1 ] const double denom = ( whichpointers[ 1 ][ cnt ] > CheMPS2::DAVIDSON_PRECOND_CUTOFF ) ? whichpointers[ 1 ][ cnt ] : CheMPS2::DAVIDSON_PRECOND_CUTOFF; whichpointers[ 0 ][ cnt ] = - theupdate[ cnt ] / denom; } whichpointers[ 0 ][ x_linearlength ] = 1.0; instruction = deBoskabouter.FetchInstruction( whichpointers ); while ( instruction == 'B' ){ augmented_hessian( localFmat, localwtilde, localIdx, whichpointers[ 0 ], whichpointers[ 1 ], theupdate, x_linearlength ); instruction = deBoskabouter.FetchInstruction( whichpointers ); } assert( instruction == 'C' ); double scalar = 1.0 / whichpointers[ 0 ][ x_linearlength ]; cout << "DMRGSCF::augmentedHessianNR : Augmented Hessian update found with " << deBoskabouter.GetNumMultiplications() << " Davidson iterations." << endl; if ( CheMPS2::DMRGSCF_debugPrint ){ cout << "DMRGSCF::augmentedHessianNR : Lowest eigenvalue = " << whichpointers[ 1 ][ 0 ] << endl; cout << "DMRGSCF::augmentedHessianNR : The last number of the eigenvector (which will be rescaled to one) = " << scalar << endl; } for ( int cnt = 0; cnt < x_linearlength; cnt++ ){ theupdate[ cnt ] = scalar * whichpointers[ 0 ][ cnt ]; } delete [] whichpointers; } //Calculate the update norm updateNorm[ 0 ] = 0.0; for ( int cnt = 0; cnt < x_linearlength; cnt++ ){ updateNorm[ 0 ] += theupdate[ cnt ] * theupdate[ cnt ]; } updateNorm[ 0 ] = sqrt( updateNorm[ 0 ] ); cout << "DMRGSCF::augmentedHessianNR : Norm of the update = " << updateNorm[ 0 ] << endl; } double CheMPS2::CASSCF::construct_gradient( DMRGSCFmatrix * Fmatrix, const DMRGSCFindices * idx, double * gradient ){ const int n_irreps = idx->getNirreps(); int jump = 0; for ( int irrep = 0; irrep < n_irreps; irrep++ ){ const int NORB = idx->getNORB( irrep ); const int NOCC = idx->getNOCC( irrep ); const int NACT = idx->getNDMRG( irrep ); const int NVIR = idx->getNVIRT( irrep ); const int N_OA = NOCC + NACT; double * FMAT = Fmatrix->getBlock( irrep ); // Type 0: act-occ for ( int occ = 0; occ < NOCC; occ++ ){ for ( int act = 0; act < NACT; act++ ){ gradient[ jump + act + NACT * occ ] = 2 * ( FMAT[ NOCC + act + NORB * occ ] - FMAT[ occ + NORB * ( NOCC + act ) ] ); } } jump += NOCC * NACT; // Type 1: vir-act for ( int act = 0; act < NACT; act++ ){ for ( int vir = 0; vir < NVIR; vir++ ){ gradient[ jump + vir + NVIR * act ] = 2 * ( FMAT[ N_OA + vir + NORB * ( NOCC + act ) ] - FMAT[ NOCC + act + NORB * ( N_OA + vir ) ] ); } } jump += NACT * NVIR; // Type 2: vir-occ for ( int occ = 0; occ < NOCC; occ++ ){ for ( int vir = 0; vir < NVIR; vir++ ){ gradient[ jump + vir + NVIR * occ ] = 2 * ( FMAT[ N_OA + vir + NORB * occ ] - FMAT[ occ + NORB * ( N_OA + vir ) ] ); } } jump += NOCC * NVIR; } double gradient_norm = 0.0; for ( int cnt = 0; cnt < jump; cnt++ ){ gradient_norm += gradient[ cnt ] * gradient[ cnt ]; } gradient_norm = sqrt( gradient_norm ); cout << "DMRGSCF::construct_gradient : Norm of the gradient = " << gradient_norm << endl; return gradient_norm; } void CheMPS2::CASSCF::augmented_hessian( DMRGSCFmatrix * Fmatrix, DMRGSCFwtilde * Wtilde, const DMRGSCFindices * idx, double * origin, double * target, double * gradient, const int linsize ){ for ( int cnt = 0; cnt < linsize; cnt++ ){ target[ cnt ] = gradient[ cnt ] * origin[ linsize ]; } add_hessian( Fmatrix, Wtilde, idx, origin, target ); target[ linsize ] = 0.0; for ( int cnt = 0; cnt < linsize; cnt++ ){ target[ linsize ] += gradient[ cnt ] * origin[ cnt ]; } } void CheMPS2::CASSCF::diag_hessian( DMRGSCFmatrix * Fmatrix, const DMRGSCFwtilde * Wtilde, const DMRGSCFindices * idx, double * diagonal ){ const int n_irreps = idx->getNirreps(); int jump = 0; for ( int irrep = 0; irrep < n_irreps; irrep++ ){ const int NORB = idx->getNORB( irrep ); const int NOCC = idx->getNOCC( irrep ); const int NACT = idx->getNDMRG( irrep ); const int NVIR = idx->getNVIRT( irrep ); const int N_OA = NOCC + NACT; double * FMAT = Fmatrix->getBlock( irrep ); for ( int occ = 0; occ < NOCC; occ++ ){ const double F_occ = FMAT[ occ * ( NORB + 1 ) ]; for ( int act = 0; act < NACT; act++ ){ const double F_act = FMAT[ ( NOCC + act ) * ( NORB + 1 ) ]; diagonal[ jump + act + NACT * occ ] = - 2 * ( F_occ + F_act ) + ( Wtilde->get( irrep, irrep, NOCC + act, occ, NOCC + act, occ ) - Wtilde->get( irrep, irrep, NOCC + act, occ, occ, NOCC + act ) - Wtilde->get( irrep, irrep, occ, NOCC + act, NOCC + act, occ ) + Wtilde->get( irrep, irrep, occ, NOCC + act, occ, NOCC + act ) ); } } jump += NOCC * NACT; for ( int act = 0; act < NACT; act++ ){ const double F_act = FMAT[ ( NOCC + act ) * ( NORB + 1 ) ]; for ( int vir = 0; vir < NVIR; vir++ ){ const double F_vir = FMAT[ ( N_OA + vir ) * ( NORB + 1 ) ]; diagonal[ jump + vir + NVIR * act ] = - 2 * ( F_act + F_vir ) + Wtilde->get( irrep, irrep, NOCC + act, N_OA + vir, NOCC + act, N_OA + vir ); } } jump += NACT * NVIR; for ( int occ = 0; occ < NOCC; occ++ ){ const double F_occ = FMAT[ occ * ( NORB + 1 ) ]; for ( int vir = 0; vir < NVIR; vir++ ){ const double F_vir = FMAT[ ( N_OA + vir ) * ( NORB + 1 ) ]; diagonal[ jump + vir + NVIR * occ ] = - 2 * ( F_occ + F_vir ) + Wtilde->get( irrep, irrep, occ, N_OA + vir, occ, N_OA + vir ); } } jump += NOCC * NVIR; } } void CheMPS2::CASSCF::add_hessian( DMRGSCFmatrix * Fmatrix, DMRGSCFwtilde * Wtilde, const DMRGSCFindices * idx, double * origin, double * target ){ const int n_irreps = idx->getNirreps(); int jump = 0; for ( int irrep = 0; irrep < n_irreps; irrep++ ){ const int NORB = idx->getNORB( irrep ); const int NOCC = idx->getNOCC( irrep ); const int NACT = idx->getNDMRG( irrep ); const int NVIR = idx->getNVIRT( irrep ); const int N_OA = NOCC + NACT; double * FMAT = Fmatrix->getBlock( irrep ); const int ptr_AO = jump; const int ptr_VA = jump + NACT * NOCC; const int ptr_VO = jump + NACT * NOCC + NVIR * NACT; // OpenMP parallelism via dgemm_ DGEMM_WRAP( +1.0, 'T', 'N', origin + ptr_VA, FMAT + N_OA, target + ptr_AO, NACT, NOCC, NVIR, NVIR, NORB, NACT ); DGEMM_WRAP( +1.0, 'T', 'T', origin + ptr_VA, FMAT + NORB * N_OA, target + ptr_AO, NACT, NOCC, NVIR, NVIR, NORB, NACT ); DGEMM_WRAP( -1.0, 'N', 'N', origin + ptr_AO, FMAT, target + ptr_AO, NACT, NOCC, NOCC, NACT, NORB, NACT ); DGEMM_WRAP( -1.0, 'N', 'T', origin + ptr_AO, FMAT, target + ptr_AO, NACT, NOCC, NOCC, NACT, NORB, NACT ); DGEMM_WRAP( -1.0, 'N', 'N', FMAT + NOCC + NORB * NOCC, origin + ptr_AO, target + ptr_AO, NACT, NOCC, NACT, NORB, NACT, NACT ); DGEMM_WRAP( -1.0, 'T', 'N', FMAT + NOCC + NORB * NOCC, origin + ptr_AO, target + ptr_AO, NACT, NOCC, NACT, NORB, NACT, NACT ); DGEMM_WRAP( -1.0, 'N', 'N', FMAT + NOCC + NORB * N_OA, origin + ptr_VO, target + ptr_AO, NACT, NOCC, NVIR, NORB, NVIR, NACT ); DGEMM_WRAP( -1.0, 'T', 'N', FMAT + N_OA + NORB * NOCC, origin + ptr_VO, target + ptr_AO, NACT, NOCC, NVIR, NORB, NVIR, NACT ); DGEMM_WRAP( +1.0, 'N', 'T', FMAT + N_OA, origin + ptr_AO, target + ptr_VA, NVIR, NACT, NOCC, NORB, NACT, NVIR ); DGEMM_WRAP( +1.0, 'T', 'T', FMAT + NORB * N_OA, origin + ptr_AO, target + ptr_VA, NVIR, NACT, NOCC, NORB, NACT, NVIR ); DGEMM_WRAP( -1.0, 'N', 'N', origin + ptr_VO, FMAT + NORB * NOCC, target + ptr_VA, NVIR, NACT, NOCC, NVIR, NORB, NVIR ); DGEMM_WRAP( -1.0, 'N', 'T', origin + ptr_VO, FMAT + NOCC, target + ptr_VA, NVIR, NACT, NOCC, NVIR, NORB, NVIR ); DGEMM_WRAP( -1.0, 'N', 'N', origin + ptr_VA, FMAT + NOCC + NORB * NOCC, target + ptr_VA, NVIR, NACT, NACT, NVIR, NORB, NVIR ); DGEMM_WRAP( -1.0, 'N', 'T', origin + ptr_VA, FMAT + NOCC + NORB * NOCC, target + ptr_VA, NVIR, NACT, NACT, NVIR, NORB, NVIR ); DGEMM_WRAP( -1.0, 'N', 'N', FMAT + N_OA + NORB * N_OA, origin + ptr_VA, target + ptr_VA, NVIR, NACT, NVIR, NORB, NVIR, NVIR ); DGEMM_WRAP( -1.0, 'T', 'N', FMAT + N_OA + NORB * N_OA, origin + ptr_VA, target + ptr_VA, NVIR, NACT, NVIR, NORB, NVIR, NVIR ); DGEMM_WRAP( -1.0, 'N', 'N', origin + ptr_VO, FMAT, target + ptr_VO, NVIR, NOCC, NOCC, NVIR, NORB, NVIR ); DGEMM_WRAP( -1.0, 'N', 'T', origin + ptr_VO, FMAT, target + ptr_VO, NVIR, NOCC, NOCC, NVIR, NORB, NVIR ); DGEMM_WRAP( -1.0, 'N', 'N', origin + ptr_VA, FMAT + NOCC, target + ptr_VO, NVIR, NOCC, NACT, NVIR, NORB, NVIR ); DGEMM_WRAP( -1.0, 'N', 'T', origin + ptr_VA, FMAT + NORB * NOCC, target + ptr_VO, NVIR, NOCC, NACT, NVIR, NORB, NVIR ); DGEMM_WRAP( -1.0, 'N', 'N', FMAT + N_OA + NORB * N_OA, origin + ptr_VO, target + ptr_VO, NVIR, NOCC, NVIR, NORB, NVIR, NVIR ); DGEMM_WRAP( -1.0, 'T', 'N', FMAT + N_OA + NORB * N_OA, origin + ptr_VO, target + ptr_VO, NVIR, NOCC, NVIR, NORB, NVIR, NVIR ); DGEMM_WRAP( -1.0, 'N', 'N', FMAT + N_OA + NORB * NOCC, origin + ptr_AO, target + ptr_VO, NVIR, NOCC, NACT, NORB, NACT, NVIR ); DGEMM_WRAP( -1.0, 'T', 'N', FMAT + NOCC + NORB * N_OA, origin + ptr_AO, target + ptr_VO, NVIR, NOCC, NACT, NORB, NACT, NVIR ); jump += NACT * NOCC + NVIR * NACT + NVIR * NOCC; } #pragma omp parallel { int jump_row = 0; for ( int irrep_row = 0; irrep_row < n_irreps; irrep_row++ ){ const int NORB_row = idx->getNORB( irrep_row ); const int NOCC_row = idx->getNOCC( irrep_row ); const int NACT_row = idx->getNDMRG( irrep_row ); const int NVIR_row = idx->getNVIRT( irrep_row ); const int N_OA_row = NOCC_row + NACT_row; double * resAO = target + jump_row; double * resVA = resAO + NACT_row * NOCC_row; double * resVO = resVA + NVIR_row * NACT_row; int jump_col = 0; for ( int irrep_col = 0; irrep_col < n_irreps; irrep_col++ ){ const int NOCC_col = idx->getNOCC( irrep_col ); const int NACT_col = idx->getNDMRG( irrep_col ); const int NVIR_col = idx->getNVIRT( irrep_col ); const int N_OA_col = NOCC_col + NACT_col; double * vecAO = origin + jump_col; double * vecVA = vecAO + NACT_col * NOCC_col; double * vecVO = vecVA + NVIR_col * NACT_col; #pragma omp for schedule(static) for ( int act_row = 0; act_row < NACT_row; act_row++ ){ for ( int occ_col = 0; occ_col < NOCC_col; occ_col++ ){ double * mat = Wtilde->getBlock( irrep_row, irrep_col, NOCC_row + act_row, occ_col ); DGEMV_WRAP( -1.0, mat + NORB_row * NOCC_col, resAO + act_row, vecAO + NACT_col * occ_col, NOCC_row, NACT_col, NORB_row, NACT_row, 1 ); DGEMV_WRAP( -1.0, mat + NORB_row * N_OA_col, resAO + act_row, vecVO + NVIR_col * occ_col, NOCC_row, NVIR_col, NORB_row, NACT_row, 1 ); DGEMV_WRAP( 1.0, mat + N_OA_row + NORB_row * NOCC_col, resVA + NVIR_row * act_row, vecAO + NACT_col * occ_col, NVIR_row, NACT_col, NORB_row, 1, 1 ); DGEMV_WRAP( 1.0, mat + N_OA_row + NORB_row * N_OA_col, resVA + NVIR_row * act_row, vecVO + NVIR_col * occ_col, NVIR_row, NVIR_col, NORB_row, 1, 1 ); } for ( int act_col = 0; act_col < NACT_col; act_col++ ){ double * mat = Wtilde->getBlock( irrep_row, irrep_col, NOCC_row + act_row, NOCC_col + act_col ); DGEMV_WRAP( 1.0, mat, resAO + act_row, vecAO + act_col, NOCC_row, NOCC_col, NORB_row, NACT_row, NACT_col ); DGEMV_WRAP( -1.0, mat + NORB_row * N_OA_col, resAO + act_row, vecVA + NVIR_col * act_col, NOCC_row, NVIR_col, NORB_row, NACT_row, 1 ); DGEMV_WRAP( -1.0, mat + N_OA_row, resVA + NVIR_row * act_row, vecAO + act_col, NVIR_row, NOCC_col, NORB_row, 1, NACT_col ); DGEMV_WRAP( 1.0, mat + N_OA_row + NORB_row * N_OA_col, resVA + NVIR_row * act_row, vecVA + NVIR_col * act_col, NVIR_row, NVIR_col, NORB_row, 1, 1 ); } } #pragma omp for schedule(static) for ( int occ_row = 0; occ_row < NOCC_row; occ_row++ ){ for ( int occ_col = 0; occ_col < NOCC_col; occ_col++ ){ double * mat = Wtilde->getBlock( irrep_row, irrep_col, occ_row, occ_col ); DGEMV_WRAP( 1.0, mat + NOCC_row + NORB_row * NOCC_col, resAO + NACT_row * occ_row, vecAO + NACT_col * occ_col, NACT_row, NACT_col, NORB_row, 1, 1 ); DGEMV_WRAP( 1.0, mat + NOCC_row + NORB_row * N_OA_col, resAO + NACT_row * occ_row, vecVO + NVIR_col * occ_col, NACT_row, NVIR_col, NORB_row, 1, 1 ); DGEMV_WRAP( 1.0, mat + N_OA_row + NORB_row * NOCC_col, resVO + NVIR_row * occ_row, vecAO + NACT_col * occ_col, NVIR_row, NACT_col, NORB_row, 1, 1 ); DGEMV_WRAP( 1.0, mat + N_OA_row + NORB_row * N_OA_col, resVO + NVIR_row * occ_row, vecVO + NVIR_col * occ_col, NVIR_row, NVIR_col, NORB_row, 1, 1 ); } for ( int act_col = 0; act_col < NACT_col; act_col++ ){ double * mat = Wtilde->getBlock( irrep_row, irrep_col, occ_row, NOCC_col + act_col ); DGEMV_WRAP( -1.0, mat + NOCC_row, resAO + NACT_row * occ_row, vecAO + act_col, NACT_row, NOCC_col, NORB_row, 1, NACT_col ); DGEMV_WRAP( 1.0, mat + NOCC_row + NORB_row * N_OA_col, resAO + NACT_row * occ_row, vecVA + NVIR_col * act_col, NACT_row, NVIR_col, NORB_row, 1, 1 ); DGEMV_WRAP( -1.0, mat + N_OA_row, resVO + NVIR_row * occ_row, vecAO + act_col, NVIR_row, NOCC_col, NORB_row, 1, NACT_col ); DGEMV_WRAP( 1.0, mat + N_OA_row + NORB_row * N_OA_col, resVO + NVIR_row * occ_row, vecVA + NVIR_col * act_col, NVIR_row, NVIR_col, NORB_row, 1, 1 ); } } jump_col += NACT_col * NOCC_col + NVIR_col * NACT_col + NVIR_col * NOCC_col; } jump_row += NACT_row * NOCC_row + NVIR_row * NACT_row + NVIR_row * NOCC_row; } } } void CheMPS2::CASSCF::DGEMM_WRAP( double prefactor, char transA, char transB, double * A, double * B, double * C, int m, int n, int k, int lda, int ldb, int ldc ){ if ( m * k * n == 0 ){ return; } double add = 1.0; dgemm_( &transA, &transB, &m, &n, &k, &prefactor, A, &lda, B, &ldb, &add, C, &ldc ); } void CheMPS2::CASSCF::DGEMV_WRAP( double prefactor, double * matrix, double * result, double * vector, int rowdim, int coldim, int ldmat, int incres, int incvec ){ if ( rowdim * coldim == 0 ){ return; } char notrans = 'N'; double add = 1.0; dgemv_( ¬rans, &rowdim, &coldim, &prefactor, matrix, &ldmat, vector, &incvec, &add, result, &incres ); } void CheMPS2::CASSCF::buildWtilde(DMRGSCFwtilde * localwtilde, const DMRGSCFmatrix * localTmat, const DMRGSCFmatrix * localJKocc, const DMRGSCFmatrix * localJKact, const DMRGSCFindices * localIdx, const DMRGSCFintegrals * theInts, double * local2DM, double * local1DM){ localwtilde->clear(); const int numIrreps = localIdx->getNirreps(); const int totOrbDMRG = localIdx->getDMRGcumulative( numIrreps ); for (int irrep_pq = 0; irrep_pq < numIrreps; irrep_pq++){ const int NumOCCpq = localIdx->getNOCC( irrep_pq ); const int NumDMRGpq = localIdx->getNDMRG( irrep_pq ); const int NumORBpq = localIdx->getNORB( irrep_pq ); const int NumCOREpq = NumOCCpq + NumDMRGpq; //If irrep_pq == irrep_rs and P == R occupied --> QS only active or virtual #pragma omp parallel for schedule(static) for (int relindexP = 0; relindexP < NumOCCpq; relindexP++){ double * subblock = localwtilde->getBlock( irrep_pq, irrep_pq, relindexP, relindexP); for (int relindexS = NumOCCpq; relindexS < NumORBpq; relindexS++){ for (int relindexQ = NumOCCpq; relindexQ < NumORBpq; relindexQ++){ subblock[ relindexQ + NumORBpq * relindexS ] += 4 * ( localTmat->get( irrep_pq, relindexQ, relindexS) + localJKocc->get(irrep_pq, relindexQ, relindexS) + localJKact->get(irrep_pq, relindexQ, relindexS) ); } } } //If irrep_pq == irrep_rs and P,R active --> QS only occupied or virtual #pragma omp parallel for schedule(static) for (int combined = 0; combined < NumDMRGpq*NumDMRGpq; combined++){ const int relindexP = NumOCCpq + ( combined % NumDMRGpq ); const int relindexR = NumOCCpq + ( combined / NumDMRGpq ); double * subblock = localwtilde->getBlock( irrep_pq, irrep_pq, relindexP, relindexR ); const int DMRGindexP = relindexP - NumOCCpq + localIdx->getDMRGcumulative( irrep_pq ); const int DMRGindexR = relindexR - NumOCCpq + localIdx->getDMRGcumulative( irrep_pq ); const double OneDMvalue = local1DM[ DMRGindexP + totOrbDMRG * DMRGindexR ]; for (int relindexS = 0; relindexS < NumOCCpq; relindexS++){ for (int relindexQ = 0; relindexQ < NumOCCpq; relindexQ++){ subblock[ relindexQ + NumORBpq * relindexS ] += 2 * OneDMvalue * ( localTmat->get( irrep_pq, relindexQ, relindexS) + localJKocc->get(irrep_pq, relindexQ, relindexS) ); } for (int relindexQ = NumCOREpq; relindexQ < NumORBpq; relindexQ++){ subblock[ relindexQ + NumORBpq * relindexS ] += 2 * OneDMvalue * ( localTmat->get( irrep_pq, relindexQ, relindexS) + localJKocc->get(irrep_pq, relindexQ, relindexS) ); } } for (int relindexS = NumCOREpq; relindexS < NumORBpq; relindexS++){ for (int relindexQ = 0; relindexQ < NumOCCpq; relindexQ++){ subblock[ relindexQ + NumORBpq * relindexS ] += 2 * OneDMvalue * ( localTmat->get( irrep_pq, relindexQ, relindexS) + localJKocc->get(irrep_pq, relindexQ, relindexS) ); } for (int relindexQ = NumCOREpq; relindexQ < NumORBpq; relindexQ++){ subblock[ relindexQ + NumORBpq * relindexS ] += 2 * OneDMvalue * ( localTmat->get( irrep_pq, relindexQ, relindexS) + localJKocc->get(irrep_pq, relindexQ, relindexS) ); } } } for (int irrep_rs = 0; irrep_rs < numIrreps; irrep_rs++){ const int NumOCCrs = localIdx->getNOCC( irrep_rs ); const int NumDMRGrs = localIdx->getNDMRG( irrep_rs ); const int NumORBrs = localIdx->getNORB( irrep_rs ); const int NumCORErs = NumOCCrs + NumDMRGrs; const int productirrep = Irreps::directProd( irrep_pq, irrep_rs ); // P and R occupied --> QS only active or virtual #pragma omp parallel for schedule(static) for (int combined = 0; combined < NumOCCpq*NumOCCrs; combined++){ const int relindexP = combined % NumOCCpq; const int relindexR = combined / NumOCCpq; double * subblock = localwtilde->getBlock( irrep_pq, irrep_rs, relindexP, relindexR); for (int relindexS = NumOCCrs; relindexS < NumORBrs; relindexS++){ for (int relindexQ = NumOCCpq; relindexQ < NumORBpq; relindexQ++){ subblock[ relindexQ + NumORBpq * relindexS ] += 4 * ( 4 * theInts->FourIndexAPI(irrep_pq, irrep_rs, irrep_pq, irrep_rs, relindexQ, relindexS, relindexP, relindexR) - theInts->FourIndexAPI(irrep_pq, irrep_pq, irrep_rs, irrep_rs, relindexQ, relindexP, relindexS, relindexR) - theInts->FourIndexAPI(irrep_pq, irrep_rs, irrep_rs, irrep_pq, relindexQ, relindexS, relindexR, relindexP) ); } } } // End combined P and R occupied // P and R active --> QS only occupied or virtual #pragma omp parallel for schedule(static) for (int combined = 0; combined < NumDMRGpq*NumDMRGrs; combined++){ const int relindexP = NumOCCpq + ( combined % NumDMRGpq ); const int relindexR = NumOCCrs + ( combined / NumDMRGpq ); double * subblock = localwtilde->getBlock( irrep_pq, irrep_rs, relindexP, relindexR ); const int DMRGindexP = relindexP - NumOCCpq + localIdx->getDMRGcumulative( irrep_pq ); const int DMRGindexR = relindexR - NumOCCrs + localIdx->getDMRGcumulative( irrep_rs ); for (int irrep_alpha = 0; irrep_alpha < numIrreps; irrep_alpha++){ const int irrep_beta = Irreps::directProd( irrep_alpha, productirrep ); const int NumDMRGalpha = localIdx->getNDMRG( irrep_alpha ); const int NumDMRGbeta = localIdx->getNDMRG( irrep_beta ); for (int alpha = 0; alpha < NumDMRGalpha; alpha++){ const int DMRGalpha = localIdx->getDMRGcumulative( irrep_alpha ) + alpha; const int relalpha = localIdx->getNOCC( irrep_alpha ) + alpha; for (int beta = 0; beta < NumDMRGbeta; beta++){ const int DMRGbeta = localIdx->getDMRGcumulative( irrep_beta ) + beta; const int relbeta = localIdx->getNOCC( irrep_beta ) + beta; const double TwoDMvalue1 = local2DM[ DMRGindexR + totOrbDMRG * ( DMRGalpha + totOrbDMRG * ( DMRGindexP + totOrbDMRG * DMRGbeta ) ) ]; const double TwoDMvalue23 = local2DM[ DMRGindexR + totOrbDMRG * ( DMRGalpha + totOrbDMRG * ( DMRGbeta + totOrbDMRG * DMRGindexP ) ) ] + local2DM[ DMRGindexR + totOrbDMRG * ( DMRGindexP + totOrbDMRG * ( DMRGbeta + totOrbDMRG * DMRGalpha ) ) ]; for (int relindexS = 0; relindexS < NumOCCrs; relindexS++){ for (int relindexQ = 0; relindexQ < NumOCCpq; relindexQ++){ subblock[ relindexQ + NumORBpq * relindexS ] += 2 * ( TwoDMvalue1 * theInts->FourIndexAPI( irrep_pq, irrep_alpha, irrep_rs, irrep_beta, relindexQ, relalpha, relindexS, relbeta) + TwoDMvalue23 * theInts->FourIndexAPI( irrep_pq, irrep_rs, irrep_alpha, irrep_beta, relindexQ, relindexS, relalpha, relbeta) ); } for (int relindexQ = NumCOREpq; relindexQ < NumORBpq; relindexQ++){ subblock[ relindexQ + NumORBpq * relindexS ] += 2 * ( TwoDMvalue1 * theInts->FourIndexAPI( irrep_pq, irrep_alpha, irrep_rs, irrep_beta, relindexQ, relalpha, relindexS, relbeta) + TwoDMvalue23 * theInts->FourIndexAPI( irrep_pq, irrep_rs, irrep_alpha, irrep_beta, relindexQ, relindexS, relalpha, relbeta) ); } } for (int relindexS = NumCORErs; relindexS < NumORBrs; relindexS++){ for (int relindexQ = 0; relindexQ < NumOCCpq; relindexQ++){ subblock[ relindexQ + NumORBpq * relindexS ] += 2 * ( TwoDMvalue1 * theInts->FourIndexAPI( irrep_pq, irrep_alpha, irrep_rs, irrep_beta, relindexQ, relalpha, relindexS, relbeta) + TwoDMvalue23 * theInts->FourIndexAPI( irrep_pq, irrep_rs, irrep_alpha, irrep_beta, relindexQ, relindexS, relalpha, relbeta) ); } for (int relindexQ = NumCOREpq; relindexQ < NumORBpq; relindexQ++){ subblock[ relindexQ + NumORBpq * relindexS ] += 2 * ( TwoDMvalue1 * theInts->FourIndexAPI( irrep_pq, irrep_alpha, irrep_rs, irrep_beta, relindexQ, relalpha, relindexS, relbeta) + TwoDMvalue23 * theInts->FourIndexAPI( irrep_pq, irrep_rs, irrep_alpha, irrep_beta, relindexQ, relindexS, relalpha, relbeta) ); } } } } } } // End combined P and R active // P active and R occupied --> Q occupied or virtual // S active or virtual #pragma omp parallel for schedule(static) for (int combined = 0; combined < NumDMRGpq*NumOCCrs; combined++){ const int relindexP = NumOCCpq + ( combined % NumDMRGpq ); const int relindexR = combined / NumDMRGpq; double * subblock = localwtilde->getBlock( irrep_pq, irrep_rs, relindexP, relindexR ); const int DMRGindexP = relindexP - NumOCCpq + localIdx->getDMRGcumulative( irrep_pq ); for (int alpha = 0; alpha < NumDMRGpq; alpha++){ const int DMRGalpha = localIdx->getDMRGcumulative( irrep_pq ) + alpha; const int relalpha = localIdx->getNOCC( irrep_pq ) + alpha; const double OneDMvalue = local1DM[ DMRGalpha + totOrbDMRG * DMRGindexP ]; for (int relindexS = NumOCCrs; relindexS < NumORBrs; relindexS++){ for (int relindexQ = 0; relindexQ < NumOCCpq; relindexQ++){ subblock[ relindexQ + NumORBpq * relindexS ] += 2 * OneDMvalue * ( 4 * theInts->FourIndexAPI( irrep_pq, irrep_rs, irrep_pq, irrep_rs, relindexQ, relindexS, relalpha, relindexR) - theInts->FourIndexAPI( irrep_pq, irrep_pq, irrep_rs, irrep_rs, relindexQ, relalpha, relindexS, relindexR) - theInts->FourIndexAPI( irrep_pq, irrep_rs, irrep_rs, irrep_pq, relindexQ, relindexS, relindexR, relalpha) ); } for (int relindexQ = NumCOREpq; relindexQ < NumORBpq; relindexQ++){ subblock[ relindexQ + NumORBpq * relindexS ] += 2 * OneDMvalue * ( 4 * theInts->FourIndexAPI( irrep_pq, irrep_rs, irrep_pq, irrep_rs, relindexQ, relindexS, relalpha, relindexR) - theInts->FourIndexAPI( irrep_pq, irrep_pq, irrep_rs, irrep_rs, relindexQ, relalpha, relindexS, relindexR) - theInts->FourIndexAPI( irrep_pq, irrep_rs, irrep_rs, irrep_pq, relindexQ, relindexS, relindexR, relalpha) ); } } } } // End combined P active and R occupied // P occupied and R active --> Q active or virtual // S occupied or virtual #pragma omp parallel for schedule(static) for (int combined = 0; combined < NumOCCpq*NumDMRGrs; combined++){ const int relindexP = combined % NumOCCpq; const int relindexR = NumOCCrs + ( combined / NumOCCpq ); double * subblock = localwtilde->getBlock( irrep_pq, irrep_rs, relindexP, relindexR ); const int DMRGindexR = relindexR - NumOCCrs + localIdx->getDMRGcumulative( irrep_rs ); for (int beta = 0; beta < NumDMRGrs; beta++){ const int DMRGbeta = localIdx->getDMRGcumulative( irrep_rs ) + beta; const int relbeta = localIdx->getNOCC( irrep_rs ) + beta; const double OneDMvalue = local1DM[ DMRGindexR + totOrbDMRG * DMRGbeta ]; for (int relindexQ = NumOCCpq; relindexQ < NumORBpq; relindexQ++){ for (int relindexS = 0; relindexS < NumOCCrs; relindexS++){ subblock[ relindexQ + NumORBpq * relindexS ] += 2 * OneDMvalue * ( 4 * theInts->FourIndexAPI( irrep_pq, irrep_rs, irrep_pq, irrep_rs, relindexQ, relindexS, relindexP, relbeta) - theInts->FourIndexAPI( irrep_pq, irrep_pq, irrep_rs, irrep_rs, relindexQ, relindexP, relindexS, relbeta) - theInts->FourIndexAPI( irrep_pq, irrep_rs, irrep_rs, irrep_pq, relindexQ, relindexS, relbeta, relindexP) ); } for (int relindexS = NumCORErs; relindexS < NumORBrs; relindexS++){ subblock[ relindexQ + NumORBpq * relindexS ] += 2 * OneDMvalue * ( 4 * theInts->FourIndexAPI( irrep_pq, irrep_rs, irrep_pq, irrep_rs, relindexQ, relindexS, relindexP, relbeta) - theInts->FourIndexAPI( irrep_pq, irrep_pq, irrep_rs, irrep_rs, relindexQ, relindexP, relindexS, relbeta) - theInts->FourIndexAPI( irrep_pq, irrep_rs, irrep_rs, irrep_pq, relindexQ, relindexS, relbeta, relindexP) ); } } } } // End combined P occupied and R active } } } void CheMPS2::CASSCF::buildFmat(DMRGSCFmatrix * localFmat, const DMRGSCFmatrix * localTmat, const DMRGSCFmatrix * localJKocc, const DMRGSCFmatrix * localJKact, const DMRGSCFindices * localIdx, const DMRGSCFintegrals * theInts, double * local2DM, double * local1DM){ localFmat->clear(); const int numIrreps = localIdx->getNirreps(); const int totOrbDMRG = localIdx->getDMRGcumulative( numIrreps ); for (int irrep_pq = 0; irrep_pq < numIrreps; irrep_pq++){ const int NumORB = localIdx->getNORB( irrep_pq ); const int NumOCC = localIdx->getNOCC( irrep_pq ); const int NumDMRG = localIdx->getNDMRG( irrep_pq ); const int NumOCCDMRG = NumOCC + NumDMRG; #pragma omp parallel for schedule(static) for (int p = 0; p < NumOCC; p++){ for (int q = 0; q < NumORB; q++){ localFmat->set( irrep_pq, p, q, 2 * ( localTmat->get( irrep_pq, q, p ) + localJKocc->get( irrep_pq, q, p ) + localJKact->get( irrep_pq, q, p ) ) ); } } #pragma omp parallel for schedule(static) for (int p = NumOCC; p < NumOCCDMRG; p++){ const int DMRGindex_p = p - NumOCC + localIdx->getDMRGcumulative( irrep_pq ); //One-body terms --> matrix multiplication? for (int r = NumOCC; r < NumOCCDMRG; r++){ const double OneDMvalue = local1DM[ DMRGindex_p + totOrbDMRG * ( DMRGindex_p + r - p ) ]; for (int q = 0; q < NumORB; q++){ localFmat->getBlock(irrep_pq)[ p + NumORB * q ] += OneDMvalue * ( localTmat->get( irrep_pq, q, r ) + localJKocc->get( irrep_pq, q, r) ); } } //Two-body terms --> matrix multiplication possible? for (int irrep_r = 0; irrep_r < numIrreps; irrep_r++){ const int irrep_product = Irreps::directProd(irrep_pq, irrep_r); for (int irrep_s = 0; irrep_s < numIrreps; irrep_s++){ const int irrep_t = Irreps::directProd(irrep_product, irrep_s); for (int r = localIdx->getNOCC(irrep_r); r < localIdx->getNOCC(irrep_r) + localIdx->getNDMRG(irrep_r); r++){ const int DMRGindex_r = r - localIdx->getNOCC( irrep_r ) + localIdx->getDMRGcumulative( irrep_r ); for (int s = localIdx->getNOCC(irrep_s); s < localIdx->getNOCC(irrep_s) + localIdx->getNDMRG(irrep_s); s++){ const int DMRGindex_s = s - localIdx->getNOCC( irrep_s ) + localIdx->getDMRGcumulative( irrep_s ); for (int t = localIdx->getNOCC(irrep_t); t < localIdx->getNOCC(irrep_t) + localIdx->getNDMRG(irrep_t); t++){ const int DMRGindex_t = t - localIdx->getNOCC( irrep_t ) + localIdx->getDMRGcumulative( irrep_t ); const double TwoDMvalue = local2DM[ DMRGindex_p + totOrbDMRG * ( DMRGindex_r + totOrbDMRG * ( DMRGindex_s + totOrbDMRG * DMRGindex_t ) ) ]; for (int q = 0; q < NumORB; q++){ localFmat->getBlock(irrep_pq)[ p + NumORB * q ] += TwoDMvalue * theInts->FourIndexAPI(irrep_pq, irrep_r, irrep_s, irrep_t, q, r, s, t); } } } } } } } } } CheMPS2-1.8.9/CheMPS2/CASSCFpt2.cpp000066400000000000000000000460401336564451100161430ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include "CASSCF.h" #include "DMRG.h" #include "FCI.h" #include "DMRGSCFrotations.h" #include "Lapack.h" #include "Cumulant.h" #include "CASPT2.h" #include "MPIchemps2.h" #include "EdmistonRuedenberg.h" using std::string; using std::ifstream; using std::cout; using std::endl; using std::max; void CheMPS2::CASSCF::write_f4rdm_checkpoint( const string f4rdm_file, int * hamorb1, int * hamorb2, const int tot_dmrg_power6, double * contract ){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif if ( am_i_master ){ hid_t file_id = H5Fcreate( f4rdm_file.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT ); hid_t group_id = H5Gcreate( file_id, "/F4RDM", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT ); hsize_t dimarray1 = 1; hid_t dataspace1_id = H5Screate_simple( 1, &dimarray1, NULL ); hid_t dataset1_id = H5Dcreate( group_id, "hamorb1", H5T_NATIVE_INT, dataspace1_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT ); H5Dwrite( dataset1_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, hamorb1 ); H5Dclose( dataset1_id ); H5Sclose( dataspace1_id ); hsize_t dimarray2 = 1; hid_t dataspace2_id = H5Screate_simple( 1, &dimarray2, NULL ); hid_t dataset2_id = H5Dcreate( group_id, "hamorb2", H5T_NATIVE_INT, dataspace2_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT ); H5Dwrite( dataset2_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, hamorb2 ); H5Dclose( dataset2_id ); H5Sclose( dataspace2_id ); hsize_t dimarray3 = tot_dmrg_power6; hid_t dataspace3_id = H5Screate_simple( 1, &dimarray3, NULL ); hid_t dataset3_id = H5Dcreate( group_id, "contract", H5T_NATIVE_DOUBLE, dataspace3_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT ); H5Dwrite( dataset3_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, contract ); H5Dclose( dataset3_id ); H5Sclose( dataspace3_id ); H5Gclose( group_id ); H5Fclose( file_id ); cout << "Created F.4-RDM checkpoint file " << f4rdm_file << " at next orbitals ( " << hamorb1[ 0 ] << " , " << hamorb2[ 0 ] << " )." << endl; } } bool CheMPS2::CASSCF::read_f4rdm_checkpoint( const string f4rdm_file, int * hamorb1, int * hamorb2, const int tot_dmrg_power6, double * contract ){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif // Check whether the file exists int exists = 0; if ( am_i_master ){ struct stat file_info; const int file_stat = stat( f4rdm_file.c_str(), &file_info ); if ( file_stat == 0 ){ exists = 1; } } #ifdef CHEMPS2_MPI_COMPILATION MPIchemps2::broadcast_array_int( &exists, 1, MPI_CHEMPS2_MASTER ); #endif if ( exists == 0 ){ return false; // Not loaded } if ( am_i_master ){ hid_t file_id = H5Fopen( f4rdm_file.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT ); hid_t group_id = H5Gopen( file_id, "/F4RDM", H5P_DEFAULT ); hid_t dataset1_id = H5Dopen( group_id, "hamorb1", H5P_DEFAULT ); H5Dread( dataset1_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, hamorb1 ); H5Dclose( dataset1_id ); hid_t dataset2_id = H5Dopen( group_id, "hamorb2", H5P_DEFAULT ); H5Dread( dataset2_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, hamorb2 ); H5Dclose( dataset2_id ); hid_t dataset3_id = H5Dopen( group_id, "contract", H5P_DEFAULT ); H5Dread( dataset3_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, contract ); H5Dclose( dataset3_id ); H5Gclose( group_id ); H5Fclose( file_id ); } #ifdef CHEMPS2_MPI_COMPILATION MPIchemps2::broadcast_array_int( hamorb1, 1, MPI_CHEMPS2_MASTER ); MPIchemps2::broadcast_array_int( hamorb2, 1, MPI_CHEMPS2_MASTER ); MPIchemps2::broadcast_array_double( contract, tot_dmrg_power6, MPI_CHEMPS2_MASTER ); #endif return true; // Loaded } void CheMPS2::CASSCF::fock_dot_4rdm( double * fockmx, CheMPS2::DMRG * dmrgsolver, CheMPS2::Hamiltonian * ham, int next_orb1, int next_orb2, double * work, double * result, const bool CHECKPOINT, const bool PSEUDOCANONICAL ){ const int LAS = ham->getL(); int size = LAS * LAS * LAS * LAS * LAS * LAS; int inc1 = 1; for ( int diag = 0; diag < LAS; diag++ ){ if (( next_orb1 == diag ) && ( next_orb2 == diag )){ double prefactor = 0.5 * fockmx[ diag + LAS * diag ]; if ( fabs( prefactor ) > 0.0 ){ dmrgsolver->Symm4RDM( work, diag, diag, false ); daxpy_( &size, &prefactor, work, &inc1, result, &inc1 ); } if ( diag == LAS - 1 ){ next_orb1 = 0; next_orb2 = 1; } else { next_orb1 = diag + 1; next_orb2 = diag + 1; } if ( CHECKPOINT ){ write_f4rdm_checkpoint( CheMPS2::DMRGSCF_f4rdm_name, &next_orb1, &next_orb2, size, result ); } } } if ( PSEUDOCANONICAL == false ){ for ( int orb1 = 0; orb1 < LAS; orb1++ ){ for ( int orb2 = orb1 + 1; orb2 < LAS; orb2++ ){ if (( next_orb1 == orb1 ) && ( next_orb2 == orb2 )){ double prefactor = 0.5 * ( fockmx[ orb1 + LAS * orb2 ] + fockmx[ orb2 + LAS * orb1 ] ); if (( ham->getOrbitalIrrep( orb1 ) == ham->getOrbitalIrrep( orb2 ) ) && ( fabs( prefactor ) > 0.0 )){ dmrgsolver->Symm4RDM( work, orb1, orb2, false ); daxpy_( &size, &prefactor, work, &inc1, result, &inc1 ); } if ( orb2 == LAS - 1 ){ next_orb1 = next_orb1 + 1; next_orb2 = next_orb1 + 1; } else { next_orb2 = next_orb2 + 1; } if (( ham->getOrbitalIrrep( orb1 ) == ham->getOrbitalIrrep( orb2 ) ) && ( CHECKPOINT )){ write_f4rdm_checkpoint( CheMPS2::DMRGSCF_f4rdm_name, &next_orb1, &next_orb2, size, result ); } } } } } } double CheMPS2::CASSCF::caspt2( const int Nelectrons, const int TwoS, const int Irrep, ConvergenceScheme * OptScheme, const int rootNum, DMRGSCFoptions * scf_options, const double IPEA, const double IMAG, const bool PSEUDOCANONICAL, const bool CHECKPOINT, const bool CUMULANT ){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif const int num_elec = Nelectrons - 2 * iHandler->getNOCCsum(); assert( num_elec >= 0 ); if ( CASPT2::vector_length( iHandler ) == 0 ){ if ( am_i_master ){ cout << "CheMPS2::CASSCF::caspt2 : There are no CASPT2 excitations between the CORE, ACTIVE, and VIRTUAL orbital spaces." << endl; } return 0.0; } //Determine the maximum NORB(irrep) and the max_block_size for the ERI orbital rotation const int maxlinsize = iHandler->getNORBmax(); const long long fullsize = ((long long) maxlinsize ) * ((long long) maxlinsize ) * ((long long) maxlinsize ) * ((long long) maxlinsize ); const string tmp_filename = tmp_folder + "/" + CheMPS2::DMRGSCF_eri_storage_name; const int dmrgsize_power4 = nOrbDMRG * nOrbDMRG * nOrbDMRG * nOrbDMRG; //For (ERI rotation, update unitary, block diagonalize, orbital localization) DMRGSCFintegrals * theRotatedTEI = new DMRGSCFintegrals( iHandler ); const int temp_work_size = (( fullsize > CheMPS2::DMRGSCF_max_mem_eri_tfo ) ? CheMPS2::DMRGSCF_max_mem_eri_tfo : fullsize ); const int work_mem_size = max( max( temp_work_size , maxlinsize * maxlinsize * 4 ) , dmrgsize_power4 ); const int tot_dmrg_power6 = dmrgsize_power4 * nOrbDMRG * nOrbDMRG; double * mem1 = new double[ work_mem_size ]; double * mem2 = new double[ ( PSEUDOCANONICAL ) ? work_mem_size : max( work_mem_size, tot_dmrg_power6 ) ]; // If you did not run CheMPS2::CASSCF::solve, you NEED to load the unitary from disk if ( successful_solve == false ){ assert( scf_options->getStoreUnitary() ); if ( am_i_master ){ struct stat file_info; const int file_stat = stat( (scf_options->getUnitaryStorageName()).c_str(), &file_info ); assert( file_stat == 0 ); unitary->loadU( scf_options->getUnitaryStorageName() ); } #ifdef CHEMPS2_MPI_COMPILATION unitary->broadcast( MPI_CHEMPS2_MASTER ); #endif } else { // Rotate to pseudocanonical orbitals if ( PSEUDOCANONICAL ){ // successful_solve needs to be true, because the 1-RDM is needed for buildQmatACT(); buildTmatrix(); buildQmatOCC(); buildQmatACT(); construct_fock( theFmatrix, theTmatrix, theQmatOCC, theQmatACT, iHandler ); block_diagonalize( 'O', theFmatrix, unitary, mem1, mem2, iHandler, false, NULL, NULL, NULL ); block_diagonalize( 'A', theFmatrix, unitary, mem1, mem2, iHandler, false, NULL, NULL, NULL ); block_diagonalize( 'V', theFmatrix, unitary, mem1, mem2, iHandler, false, NULL, NULL, NULL ); if (( am_i_master ) && ( scf_options->getStoreUnitary() )){ unitary->saveU( scf_options->getUnitaryStorageName() ); } } } // Fill active space Hamiltonian Hamiltonian * HamAS = new Hamiltonian( nOrbDMRG, SymmInfo.getGroupNumber(), iHandler->getIrrepOfEachDMRGorbital() ); Problem * Prob = new Problem( HamAS, TwoS, num_elec, Irrep ); Prob->SetupReorderD2h(); // Doesn't matter if the group isn't D2h, Prob checks it. buildTmatrix(); buildQmatOCC(); fillConstAndTmatDMRG( HamAS ); if ( am_i_master ){ DMRGSCFrotations::rotate( VMAT_ORIG, HamAS->getVmat(), NULL, 'A', 'A', 'A', 'A', iHandler, unitary, mem1, mem2, work_mem_size, tmp_filename ); } #ifdef CHEMPS2_MPI_COMPILATION HamAS->getVmat()->broadcast( MPI_CHEMPS2_MASTER ); #endif // Reorder the orbitals based on the Fiedler vector of the exchange matrix if ( scf_options->getWhichActiveSpace() == 3 ){ int * dmrg2ham = new int[ nOrbDMRG ]; if ( am_i_master ){ EdmistonRuedenberg * theLocalizer = new EdmistonRuedenberg( HamAS->getVmat(), iHandler->getGroupNumber() ); theLocalizer->FiedlerGlobal( dmrg2ham ); delete theLocalizer; } #ifdef CHEMPS2_MPI_COMPILATION MPIchemps2::broadcast_array_int( dmrg2ham, nOrbDMRG, MPI_CHEMPS2_MASTER ); #endif Prob->setup_reorder_custom( dmrg2ham ); delete [] dmrg2ham; } double E_CASSCF = 0.0; double * three_dm = new double[ tot_dmrg_power6 ]; double * contract = new double[ tot_dmrg_power6 ]; for ( int cnt = 0; cnt < tot_dmrg_power6; cnt++ ){ contract[ cnt ] = 0.0; } int next_hamorb1 = 0; int next_hamorb2 = 0; const bool make_checkpt = (( CUMULANT == false ) && ( CHECKPOINT )); bool checkpt_loaded = false; if ( make_checkpt ){ assert(( OptScheme != NULL ) || ( rootNum > 1 )); checkpt_loaded = read_f4rdm_checkpoint( CheMPS2::DMRGSCF_f4rdm_name, &next_hamorb1, &next_hamorb2, tot_dmrg_power6, contract ); } // Solve the active space problem if (( OptScheme == NULL ) && ( rootNum == 1 )){ // Do FCI if ( am_i_master ){ const int nalpha = ( num_elec + TwoS ) / 2; const int nbeta = ( num_elec - TwoS ) / 2; const double workmem = 1000.0; // 1GB const int verbose = 2; CheMPS2::FCI * theFCI = new CheMPS2::FCI( HamAS, nalpha, nbeta, Irrep, workmem, verbose ); double * inoutput = new double[ theFCI->getVecLength(0) ]; theFCI->ClearVector( theFCI->getVecLength(0), inoutput ); inoutput[ theFCI->LowestEnergyDeterminant() ] = 1.0; E_CASSCF = theFCI->GSDavidson( inoutput ); theFCI->Fill2RDM( inoutput, DMRG2DM ); // 2-RDM theFCI->Fill3RDM( inoutput, three_dm ); // 3-RDM setDMRG1DM( num_elec, nOrbDMRG, DMRG1DM, DMRG2DM ); // 1-RDM buildQmatACT(); construct_fock( theFmatrix, theTmatrix, theQmatOCC, theQmatACT, iHandler ); copy_active( theFmatrix, mem2, iHandler ); // Fock theFCI->Fock4RDM( inoutput, three_dm, mem2, contract ); // trace( Fock * 4-RDM ) delete theFCI; delete [] inoutput; } #ifdef CHEMPS2_MPI_COMPILATION MPIchemps2::broadcast_array_double( &E_CASSCF, 1, MPI_CHEMPS2_MASTER ); MPIchemps2::broadcast_array_double( DMRG2DM, dmrgsize_power4, MPI_CHEMPS2_MASTER ); MPIchemps2::broadcast_array_double( three_dm, tot_dmrg_power6, MPI_CHEMPS2_MASTER ); MPIchemps2::broadcast_array_double( contract, tot_dmrg_power6, MPI_CHEMPS2_MASTER ); setDMRG1DM( num_elec, nOrbDMRG, DMRG1DM, DMRG2DM ); #endif } else { // Do the DMRG sweeps assert( OptScheme != NULL ); for ( int cnt = 0; cnt < dmrgsize_power4; cnt++ ){ DMRG2DM[ cnt ] = 0.0; } // Clear the 2-RDM CheMPS2::DMRG * theDMRG = new DMRG( Prob, OptScheme, make_checkpt, tmp_folder ); for ( int state = 0; state < rootNum; state++ ){ if ( state > 0 ){ theDMRG->newExcitation( fabs( E_CASSCF ) ); } if ( checkpt_loaded == false ){ E_CASSCF = theDMRG->Solve(); } if (( state == 0 ) && ( rootNum > 1 )){ theDMRG->activateExcitations( rootNum - 1 ); } } theDMRG->calc_rdms_and_correlations( true ); copy2DMover( theDMRG->get2DM(), nOrbDMRG, DMRG2DM ); // 2-RDM setDMRG1DM( num_elec, nOrbDMRG, DMRG1DM, DMRG2DM ); // 1-RDM buildQmatACT(); construct_fock( theFmatrix, theTmatrix, theQmatOCC, theQmatACT, iHandler ); copy_active( theFmatrix, mem2, iHandler ); // Fock if ( CUMULANT ){ CheMPS2::Cumulant::gamma4_fock_contract_ham( Prob, theDMRG->get3DM(), theDMRG->get2DM(), mem2, contract ); } else { fock_dot_4rdm( mem2, theDMRG, HamAS, next_hamorb1, next_hamorb2, three_dm, contract, make_checkpt, PSEUDOCANONICAL ); } theDMRG->get3DM()->fill_ham_index( 1.0, false, three_dm, 0, nOrbDMRG ); if (( CheMPS2::DMRG_storeMpsOnDisk ) && ( make_checkpt == false )){ theDMRG->deleteStoredMPS(); } if ( CheMPS2::DMRG_storeRenormOptrOnDisk ){ theDMRG->deleteStoredOperators(); } delete theDMRG; } delete Prob; delete HamAS; if ( PSEUDOCANONICAL == false ){ if ( am_i_master ){ cout << "CASPT2 : Deviation from pseudocanonical = " << deviation_from_blockdiag( theFmatrix, iHandler ) << endl; } block_diagonalize( 'O', theFmatrix, unitary, mem1, mem2, iHandler, false, NULL, NULL, NULL ); block_diagonalize( 'A', theFmatrix, unitary, mem1, mem2, iHandler, false, DMRG2DM, three_dm, contract ); // 2-RDM, 3-RDM, and trace( Fock * cu(4)-4-RDM ) block_diagonalize( 'V', theFmatrix, unitary, mem1, mem2, iHandler, false, NULL, NULL, NULL ); setDMRG1DM( num_elec, nOrbDMRG, DMRG1DM, DMRG2DM ); // 1-RDM buildTmatrix(); buildQmatOCC(); buildQmatACT(); construct_fock( theFmatrix, theTmatrix, theQmatOCC, theQmatACT, iHandler ); // Fock } // Calculate the matrix elements needed to calculate the CASPT2 V-vector if ( am_i_master ){ DMRGSCFrotations::rotate( VMAT_ORIG, NULL, theRotatedTEI, 'C', 'C', 'F', 'F', iHandler, unitary, mem1, mem2, work_mem_size, tmp_filename ); DMRGSCFrotations::rotate( VMAT_ORIG, NULL, theRotatedTEI, 'C', 'V', 'C', 'V', iHandler, unitary, mem1, mem2, work_mem_size, tmp_filename ); delete_file( tmp_filename ); } delete [] mem1; delete [] mem2; double E_CASPT2 = 0.0; if ( am_i_master ){ cout << "CASPT2 : Deviation from pseudocanonical = " << deviation_from_blockdiag( theFmatrix, iHandler ) << endl; CheMPS2::CASPT2 * myCASPT2 = new CheMPS2::CASPT2( iHandler, theRotatedTEI, theTmatrix, theFmatrix, DMRG1DM, DMRG2DM, three_dm, contract, IPEA ); delete theRotatedTEI; delete [] three_dm; delete [] contract; E_CASPT2 = myCASPT2->solve( IMAG ); delete myCASPT2; } else { delete theRotatedTEI; delete [] three_dm; delete [] contract; } #ifdef CHEMPS2_MPI_COMPILATION MPIchemps2::broadcast_array_double( &E_CASPT2, 1, MPI_CHEMPS2_MASTER ); #endif return E_CASPT2; } void CheMPS2::CASSCF::construct_fock( DMRGSCFmatrix * Fock, const DMRGSCFmatrix * Tmat, const DMRGSCFmatrix * Qocc, const DMRGSCFmatrix * Qact, const DMRGSCFindices * idx ){ const int n_irreps = idx->getNirreps(); for ( int irrep = 0; irrep < n_irreps; irrep++ ){ const int NORB = idx->getNORB( irrep ); for (int row = 0; row < NORB; row++){ for (int col = 0; col < NORB; col++){ Fock->set( irrep, row, col, Tmat->get( irrep, row, col ) + Qocc->get( irrep, row, col ) + Qact->get( irrep, row, col ) ); } } } } double CheMPS2::CASSCF::deviation_from_blockdiag( DMRGSCFmatrix * matrix, const DMRGSCFindices * idx ){ double rms_deviation = 0.0; const int n_irreps = idx->getNirreps(); for ( int irrep = 0; irrep < n_irreps; irrep++ ){ const int NOCC = idx->getNOCC( irrep ); for ( int row = 0; row < NOCC; row++ ){ for ( int col = row + 1; col < NOCC; col++ ){ rms_deviation += matrix->get( irrep, row, col ) * matrix->get( irrep, row, col ); rms_deviation += matrix->get( irrep, col, row ) * matrix->get( irrep, col, row ); } } const int NACT = idx->getNDMRG( irrep ); for ( int row = 0; row < NACT; row++ ){ for ( int col = row + 1; col < NACT; col++ ){ rms_deviation += matrix->get( irrep, NOCC + row, NOCC + col ) * matrix->get( irrep, NOCC + row, NOCC + col ); rms_deviation += matrix->get( irrep, NOCC + col, NOCC + row ) * matrix->get( irrep, NOCC + col, NOCC + row ); } } const int NVIR = idx->getNVIRT( irrep ); const int N_OA = NOCC + NACT; for ( int row = 0; row < NVIR; row++ ){ for ( int col = row + 1; col < NVIR; col++ ){ rms_deviation += matrix->get( irrep, N_OA + row, N_OA + col ) * matrix->get( irrep, N_OA + row, N_OA + col ); rms_deviation += matrix->get( irrep, N_OA + col, N_OA + row ) * matrix->get( irrep, N_OA + col, N_OA + row ); } } } rms_deviation = sqrt( rms_deviation ); return rms_deviation; } CheMPS2-1.8.9/CheMPS2/CMakeLists.txt000066400000000000000000000154271336564451100166140ustar00rootroot00000000000000cmake_policy (SET CMP0022 NEW) cmake_policy (SET CMP0028 NEW) set (CHEMPS2LIB_SOURCE_FILES "CASPT2.cpp" "CASSCF.cpp" "CASSCFdebug.cpp" "CASSCFnewtonraphson.cpp" "CASSCFpt2.cpp" "ConjugateGradient.cpp" "ConvergenceScheme.cpp" "Correlations.cpp" "Cumulant.cpp" "Davidson.cpp" "DIIS.cpp" "DMRG.cpp" "DMRGfock.cpp" "DMRGmpsio.cpp" "DMRGoperators.cpp" "DMRGoperators3RDM.cpp" "DMRGSCFindices.cpp" "DMRGSCFintegrals.cpp" "DMRGSCFmatrix.cpp" "DMRGSCFoptions.cpp" "DMRGSCFrotations.cpp" "DMRGSCFunitary.cpp" "DMRGSCFwtilde.cpp" "DMRGtechnics.cpp" "EdmistonRuedenberg.cpp" "Excitation.cpp" "FCI.cpp" "FourIndex.cpp" "Hamiltonian.cpp" "Heff.cpp" "HeffDiagonal.cpp" "HeffDiagrams1.cpp" "HeffDiagrams2.cpp" "HeffDiagrams3.cpp" "HeffDiagrams4.cpp" "HeffDiagrams5.cpp" "Initialize.cpp" "Irreps.cpp" "Molden.cpp" "PrintLicense.cpp" "Problem.cpp" "Sobject.cpp" "SyBookkeeper.cpp" "Tensor3RDM.cpp" "TensorF0.cpp" "TensorF1.cpp" "TensorGYZ.cpp" "TensorKM.cpp" "TensorL.cpp" "TensorO.cpp" "TensorOperator.cpp" "TensorQ.cpp" "TensorS0.cpp" "TensorS1.cpp" "TensorT.cpp" "TensorX.cpp" "ThreeDM.cpp" "TwoDM.cpp" "TwoIndex.cpp" "Wigner.cpp") add_library (chemps2-base OBJECT ${CHEMPS2LIB_SOURCE_FILES}) target_include_directories (chemps2-base PRIVATE ${CheMPS2_SOURCE_DIR}/CheMPS2/include/chemps2 $) if (BUILD_FPIC OR NOT STATIC_ONLY) set_target_properties (chemps2-base PROPERTIES POSITION_INDEPENDENT_CODE 1) endif() if (NOT STATIC_ONLY) add_library (chemps2-shared SHARED $) target_link_libraries (chemps2-shared PRIVATE ${LIBC_INTERJECT}) target_link_libraries (chemps2-shared PUBLIC tgt::lapack tgt::hdf5) set_target_properties (chemps2-shared PROPERTIES SOVERSION ${CheMPS2_LIB_SOVERSION} MACOSX_RPATH ON OUTPUT_NAME "chemps2" EXPORT_NAME "chemps2") endif() if (NOT SHARED_ONLY) add_library (chemps2-static STATIC $) target_link_libraries (chemps2-static PRIVATE ${LIBC_INTERJECT}) target_link_libraries (chemps2-static PUBLIC tgt::lapack tgt::hdf5) set_target_properties (chemps2-static PROPERTIES OUTPUT_NAME "chemps2" EXPORT_NAME "chemps2") endif() if (STATIC_ONLY) add_library (chemps2-lib ALIAS chemps2-static) else () add_library (chemps2-lib ALIAS chemps2-shared) endif() add_executable (chemps2-bin executable.cpp) target_link_libraries (chemps2-bin chemps2-lib ${LIBC_INTERJECT}) set_target_properties (chemps2-bin PROPERTIES OUTPUT_NAME "chemps2") # <<< Install >>> if (NOT STATIC_ONLY) install (TARGETS chemps2-shared chemps2-bin EXPORT "${PROJECT_NAME}Targets-shared" LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() if (NOT SHARED_ONLY) install (TARGETS chemps2-static chemps2-bin EXPORT "${PROJECT_NAME}Targets-static" ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() install (DIRECTORY include/chemps2/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/chemps2 FILES_MATCHING PATTERN "*.h") # <<< Export interface >>> if (NOT STATIC_ONLY) if (APPLE) set_target_properties(chemps2-shared PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") endif() target_compile_definitions (chemps2-shared INTERFACE USING_${PROJECT_NAME}) target_include_directories (chemps2-shared INTERFACE $ $ $) endif() if (NOT SHARED_ONLY) target_compile_definitions (chemps2-static INTERFACE USING_${PROJECT_NAME}) target_include_directories (chemps2-static INTERFACE $ $ $) endif() # <<< Export Config >>> # explicit "share" not "DATADIR" for CMake search path set (CMAKECONFIG_INSTALL_DIR "share/cmake/${PROJECT_NAME}") if (NOT STATIC_ONLY) install (EXPORT "${PROJECT_NAME}Targets-shared" NAMESPACE "${PROJECT_NAME}::" DESTINATION ${CMAKECONFIG_INSTALL_DIR}) endif() if (NOT SHARED_ONLY) install (EXPORT "${PROJECT_NAME}Targets-static" NAMESPACE "${PROJECT_NAME}::" DESTINATION ${CMAKECONFIG_INSTALL_DIR}) endif() CheMPS2-1.8.9/CheMPS2/CheMPS2logo.pdf000066400000000000000000000100541336564451100165600ustar00rootroot00000000000000%PDF-1.5 %µí®û 3 0 obj << /Length 4 0 R /Filter /FlateDecode >> stream xœ+ä*ä2T0B©k ghjnj®œË¥Ÿh ^¬ _aªà’Ï„Êè ` endstream endobj 4 0 obj 46 endobj 2 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /XObject << /x5 5 0 R >> >> endobj 6 0 obj << /Type /Page /Parent 1 0 R /MediaBox [ 0 0 385.595581 64.84243 ] /Contents 3 0 R /Group << /Type /Group /S /Transparency /CS /DeviceRGB >> /Resources 2 0 R >> endobj 5 0 obj << /Length 8 0 R /Filter /FlateDecode /Type /XObject /Subtype /Form /BBox [ 0 0 386 65 ] /Group << /Type /Group /S /Transparency /CS /DeviceRGB >> /Resources 7 0 R >> stream xœuYË®%5 Üç+úhâ¼óHH,€%b]šY ,ø}ªl'Ý÷ÜAÝSN:qìò#™/!üï§ïŽo‹Çÿ„|¶‡ZÏØÇÑòÓñùyv™GKçãøt¤Sb=r:s€’9{k€øXz:ðìÀ??B‡[™:üÏv¥ãŒqp»vÖX®ï÷"Îð•5Ú)ãHýL©c‰ÔÎ<+5N}é`vùû#WlP2÷½bv†³v òè Û8¤bÖÊ9Z?®…ƒd|=u1šA`œ”¡ö, búÀ¯¶Ç?APž„<ê™ÓåjÆrŽ`‘ZõsÃ8^œúmƒéû@~$ÐÅ0¦óÄ3¯ Ø­Gx£©ÀÄY°ÑÀRñĉ¹|…ºyœ† —3ߟœ2 ø|`¹*Äs¤ÅÒYG[ûÃÓpHXê„#„œ¨½Ü0«Ÿ®[”Ÿ (W儲!79“ˆC®^ô0†‰hÁÚϨK*mÁKOÚ*,¼& 37ï½oˆ£æn¦vA<Ëäzð¸À£8Q.T¦Ÿ97R‹\¹^iôéx ?áp Å bÏA\¤Їgƒ©o0±Ðú©†æ- !µ’TÂ\0õ$7  9¯e.¸``s'ãX¤/ŒÓP'(°~u×ë9=¬Ï 18‚>kä…á‚Ø•,]êÅ J\[PÁýeUb.TܸàqE”*L*ÀQÄ|ê("ç,Ïôl;NÕ²X†(Τ +ÂT3­1D28ëY¨Âý¾ÅE<Î&4@)Øb"ê:ÓÏ,¤0Ã4M]ˆÁ…ˆë R# ¶L‚ÑÌH øs£Ò¶ s;Ka|÷|fì‡p­ÒH޽ Ž‹sÄfAÐ:¼d‡”ÇÂ@$K†j ÔBC5¼®Å`väúhPßX¡a ÅÐÔ—P@°Î\¹‚3Ï…BŠÐÔæÃnô§«höÆž¥Ìc¹bÀZ#;œñJ#áܦ†ÁÂHÅí˜Q}²72 ‹âo0h¿ÉX+21a"‰Í#¡Pƒ9RÈ„Ö õlˆ¬às-Ó¬aGÆÌ…†=æˆÌÔ€ùÆêqû$e/]¸hìÃìj¬®öEjø³e!D“ n÷vrUÉìLÕ]dJAŽqŒÌ– c˦’,µDf0ß]ÇŸòØ[Ó3+¼V¤£E› D /’‹m2Â:rMA“ é$[XÄø‘×÷thHʉ]ÿ (žÔuŸÚxâ‚ÙmwŽ\2Äž 1.“¢ {HDÑÉ݉·VZ¬äI´¢Ú(ô¢†Nö°1Ò•«í4°ŸÂ½,’DñèðRB1<ÆY[ˤMºÒÎ×âô¤.ð4'±k¨: §7KQHµzº@¢h³ÕÙJl¸µqcE|N${QÔd»›$¡H[ó1)Q5XÁHa~¨‹ Ûg+= MŠyaO@Ùè,¿äž#0¢eóƒaÛŒ‡Íì¾ *=5«.¾}E=8kC w×F} &e,ÚXVvXú£'±ÆÖç‡W Œ7ÂÌå¶ý>Q§÷ @#4#9kÃÃF:± 2Ä¢ 9 «Ú!,çi&i¦j ë2»B0È£B¿u ÃK™¦½Ç¹ª!d7x¦Þ› JQ©Jß1YŠ™‡&‹œv=Hì§Ìì5§û‚½c½ˆ¶ð8 C–µ¨­BŒþUƒÞk2áÂ@¯ø¡”që½û`ð`Ï_<4{QŠÁ¸¼ˆ{@3p«ô}aM(Ç\WÄ®U°hŸféâ†'q}ešþ^X o³ã Ùq_·u@ÇATv'¼å1Á&ÓÆ1çg-D.àöäÃz ¿æd}6áU÷ReˆÅp¸òÌ–[9¤œ¬i9ÚâîùYù—õôe Ÿb”4àË“6C)7}‘óö8¦¼ê{iæêœ‡È)Ú9úv|²2[(bcû]̬ET˜,lñv‡U×~Í •‡fÿÏ|ííü?†i^­…÷¾3á ~»¼ÊÝ…¹y‡u˜Tù³¸€‹v½HŽM{|ƒøŒÑxÝÑæ&ùÓ“ /ìÈ¢ìœß2µR$äV-¾N°Þtè7a|Ðãð¹…]1Éù~ÿ)Goh·ì-ú¦¤_ƒ buFkpŒùÆî5Ž"ÈÌ{âÁ©hʸ€ˆîN¨_2ç õ¡Ê!³Ö‡˜CârÈå¾°¼ æ%ØñßE{¥GŠpÉN"þÉ+Þ™Ë7}ä‡W5 z<ÙéŠ9Þ‹Žwí¼Ã[KŸ>Hî“ñy¢Ì‚‡^/J@­™´ ÁÉŒpè5³z+’fÕË–l¶nƹ ,NΪç†E½íó“FäM“„ïf×nêïëÓ{~f 4õž¡àÂ"SJ0ANvá°Léid-ØôA-óÅ:êóR’© ‘k|b(öérÞ <ãrF‚xG¶áô¦g ª¶tÙ^6³vÊ\ˆ…ÿÌ LÆE˜[W>ZðJu ¾ú‚YDóvpŒù’ôÉqO(ÚQàs&–ŒÞ¤h~éöB­ÑXÛÁKhÍAŸZì Êz0_‚hOô7d¤roV©>M›©Ožeê‹Â²M~ÀûsúÐ<¶ÕqLÈàp{i'í±×êɯÐŽOo—Jô}WH‹Ìg3&ÑvmÃbO{[ãô-ÚZæ¬÷•qçêM7xÓ›ÅÿfÁª”°›d:•.H|³±­EcÍ ïëØ‹V X³µ±äL‡ý¼Ž^J.„jÔùôÅ[dÔ d]0xA½¶„M€º˾呡,™ÃÿÑ&M{?sA`ÌñaÄoîÚ3ßu ¬n²·——•_‚'ÍÛ¯9ç- ÜéÃîN˜ôÆNd VÞËÙ²×AX¹S%¿Wþ[›ÜùðöoáÇðº}ß endstream endobj 8 0 obj 2785 endobj 7 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> >> endobj 1 0 obj << /Type /Pages /Kids [ 6 0 R ] /Count 1 >> endobj 9 0 obj << /Creator (cairo 1.10.2 (http://cairographics.org)) /Producer (cairo 1.10.2 (http://cairographics.org)) >> endobj 10 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 11 0000000000 65535 f 0000003590 00000 n 0000000159 00000 n 0000000015 00000 n 0000000138 00000 n 0000000471 00000 n 0000000259 00000 n 0000003518 00000 n 0000003495 00000 n 0000003655 00000 n 0000003782 00000 n trailer << /Size 11 /Root 10 0 R /Info 9 0 R >> startxref 3835 %%EOF CheMPS2-1.8.9/CheMPS2/CheMPS2logo.png000066400000000000000000000074701336564451100166030ustar00rootroot00000000000000‰PNG  IHDRÊ"rFGsBIT|dˆ pHYs-ã-ã‘RHtEXtSoftwarewww.inkscape.org›î<µIDATxœí{ôUÇ?ß>ˆP(””ò¨˜ZI‚–‰ðQf©«·aZVføH«ÄØC3Ì ‰Y–š¦"hˆšHa–ŠJ±L4Ÿ¿ä¥ìþØg~÷p™;÷Þ¹¿Ÿ²ø®5kfÎÙsξ3³ÏÙ¯3WfF-Hš|9*²Œ}^]²_ œbfSkvÜIô@QÑ+föRWñS I}¶¨h¹™½ê¼£ê’ef¶¬|l•Õ¤nÀ–Uõ/™Ù+%ô» ðöªâçÍlM³m†™ånÀ`à5`5ðtØþ¶g¢íÙ°=¶çÃöB´½ꎮÕognÀJ\“íâ®æ©Š¿ö*þ¦Fu½«ê ø^‹øÈìØ>¥~\IýÒöÐÎ|¥ ñÑìë¤Y Œ’½¾föHgô œ ÜŽ—½HÒÀQÀùf¶¼L†$ g5%ƒ|ð—püï2ùˆðÑèø'4Çÿ ÇmXÒ¶À®ÀnÀ»ðAö`þ»’¾{×g9·Ï^À'ÀN@àaà!`¦™½Ðæ Š¤ñÀ^À à(IG–ÀßZàL3ûcJç_À§Ùn¡l{3[RB¿µð°™Í©ç‚ $ÞÜÜ]3’>Ülifs£ò2.y Iý€Ã]€mm€ÍªÈÖàšÂSøË>ÓÌþ‘TÆíKÊRM˜Ù=Y|¤ðu0 Ø=ƒä¸ªþ“@ß»hÛ9}n|8cìögIš\dfk󦻸šT=啱MËès`ð³@·´“T›•À¸nbô›¾^"?Ûâ/뢔º›IW½Èhk0 WŸ †„ç—qµ..«Þ{¥´{éªW!•„Ï–‹oû‡g7áó±GÕïmHõ6nˆÚœì ŒÅg”¤þ´Zª× pðݺz±¸7­ÂÌV÷IJ¦Ù;Jì·x_t<øQ³ JÚ W-¶ÂÕŽFÛÙ8 ü,NÆGS€÷™Ù¿$µ[[ûŸ>˜Ð³$}ÉÌ®j”Ÿ*ÞvÇgËkãÌ쵨úf+àV\8˜Œ÷¦N|Ž'gUõ›¤‹€Ÿ_&Jº5UP$mœˆ4G›Ù¢¬ÃÃþÍ&(M!¼°WEíþ½Ávv®Àm•=,òIÚ>®À3[KÅ)³¸@ÒüE~;> Ït‹™=ßOQÿƒq5õ`lÕKÚ3{ZÒÅTŸg›é7ÂvÀ2`B¢Î¥ô½ZÒ7ðAæÀ˜¶4Bàà-À…-$ÁÍø‘pú†I=€@rHªvÖ‹ó©ŒvЀ HêÌúã£uµ uû°_$ÁÙ“Ê Ú w*4‹S^À­¶ëøÉ°¿øU }‹;‰²œ˜»½çÎ × Š¤½Oá£Ë%1W>ˆ™Ï˜ÙC]ÐQ솾—Ee{4Ú˜¤¯âúqÿhdF9è Œ1³´Qx»°¸VCæÇßDE{6ÀO$õÄmp¼ã¶×P3{±™¾˜cEAòÄã:pA Sÿ´pú]3û_ÌÕ‰7‹}2סï®*«’öÃÝð× Å+¨Ã½a°“™]›ÒÏ[¨'k JÀ Ññ¿à'Æ0\SØ7h™0³ÌìOy4-Fr¯«žQÆàÞˆ¿—v*K¼Ye4nÞ¼ʆÕÛˆ¤]€™À߀#BÕ?óT£,˜Ù%f–%`‹ JÏè¸Y÷÷Âèø½À9’ŠÄòº ƒÂ~~‡ ÿô™átl#©YO͇Ãé’v•tФßJš%é4Iýëh¯MÒa’¦JºCÒ=’¦5kKb8p[гUC¬\´-ñ»÷ê¬v Õ ò5Ç*þ‘Iµ.urž™55x™Ù3ÀuQÑ·€{%½¿™v[0Û} œÎê$I«$5Õ¯0s^ƒð‡™Y’ò10"ûOüe!”¹5†â6Åh3»¯ ÂsAÅæÙï—46ÜŸ.CÐ&‡ÓšÙ’dF¹gv MxnJ@"(/â/Ъªúîa¿3ÉtÜy`Šßþ[ßÚƒAµ…GÄ)û¸þ—¸3ÆÌfGÕ± <Ý9ýn $*εx”t > Œ6³\úF`f3÷àÐÄÓט <$ixÖµ€ÓqCþy‚9Ò&i4®’<‡äçHêžÙD‹òo÷ãéf–6¢&ÑâG3ÚèÌÀ…à×f––Üx ®v<Ø «CðéxNRŒçÅátd oÎñ$ʉf6£ª.¶¿žj¿,¼O‚G‰¤mð™{‡ÏÆIŒ£'å AÒç©ÈÃŒ8(ÙFŵ .I¯'IzWç±TÔ®ß[ú¢©øL±œl×fâ1{å={\. çW4’Ù膫2›Q?.Ôß’ÓÆƒæ2|tî´è»Pö0nWÜ“S¿8ô¿ ªüØP>èžsýÂ@÷xM]ÙÃf'*Ù°Gáû×pŸÆáƽë|^¹Ùø˜déîWgÛFüލªk*{8£¿RY¼·_Ú°.M ¼>MÆÝ•Izý°VE £Ý#FwÍ ¹+Ô§®ŽÄg›Wi`e]‚2 ϟʪ?;zÀ»‡²#ñ÷ùÀæ5Ú*\;7‡¦A95Ð,z”ôÌj Ê÷Âù“ ´}ItûVÕ•*(¸ÍùRhóQ`›4ºÄëuîñ:w©N åÓ‚ºÑjì‰g¨>cÑB¡A †{¬~•ï‘õ#,ö¢xÔ¹0$ Âc;WçÅê××%ÂõìEø‹œ©Î„ûœÄ‡Jõxá¹{×Y kØ âaßȪÏ~a½y²%´'n—o†¯AÙÛÌžH£m0Ͼ7¦§à¹øâÒö…V1aDØg‡àºãM¼’ŽÀ]‹ ž â5ÉÍ‘’´yð²ÕƒñÀå–“œgfó©,Ã=O(\ Œ4³çj´ß‡Š ·×É[&‚»ø€ô•u3¥#ä×ÝŠÏP q/ÓGæÏÀ3†ÀGï$ûý°˜¨•H ùÛ3ê÷ û8vñÜ¥€™­¤’ò¾uVG’¶ý|8‹&åš~À§ñåµäÈmŠOé#-ÝÕ]8Û ÌûÌ&ϲn´eÏâñ¨èªÄ+‚‹qÏ×3+]3t8nnôÀ=|ÃkÍ\‚bž)œ¬dœ†î¿ÃWÚÚ †¡c]GâÒÍ”$wW¸fg|¹ì¬*º$óù¤ ¬š› L7÷°¤Ñ´I:_R칚 ÜhÅ>t1Ïýjö7³Ô˜O âu#[¼¦o×L3{5—²\LŽwf‡%©´›¤ÙxöÀÞi*xôeÜû¹ ð{üÕÎ’¯2lÚp»á)$ýqCw%0  ã)Řú{"‡æLü£áAÑyÀºî¸gé W•xr(ÑNḋQ1$ÁÓSÖ¦õ—Ãï®ÀÀ:ïÃQ¿/áym'áñŒ†ŒyƒJšÅ #include #include #include "ConjugateGradient.h" using std::cout; using std::endl; CheMPS2::ConjugateGradient::ConjugateGradient( const int veclength_in, const double RTOL_in, const double DIAG_CUTOFF_in, const bool print_in ){ veclength = veclength_in; RTOL = RTOL_in; DIAG_CUTOFF = DIAG_CUTOFF_in; print = print_in; state = 'I'; num_matvec = 0; XVEC = new double[ veclength ]; PRECON = new double[ veclength ]; RHS = new double[ veclength ]; WORK = new double[ veclength ]; RESID = new double[ veclength ]; PVEC = new double[ veclength ]; OPVEC = new double[ veclength ]; } CheMPS2::ConjugateGradient::~ConjugateGradient(){ delete [] XVEC; delete [] PRECON; delete [] RHS; delete [] WORK; delete [] RESID; delete [] PVEC; delete [] OPVEC; } int CheMPS2::ConjugateGradient::get_num_matvec() const{ return num_matvec; } char CheMPS2::ConjugateGradient::step( double ** pointers ){ /* Possible states: - I : just created the class - G : the guess has been set in XVEC, the diagonal in PRECON, and the right-hand side in RHS - H : the PRECON, RESID, and XVEC have been set to start the iterations of ( PRECON * operator * PRECON ) * XVEC = RESID = PRECON * RHS - J : at start-up OPVEC contains operator * PRECON * XVEC - K : OPVEC, RESID, PVEC have just been set, as well as rnorm and rkT_rk - L : OPVEC contains operator * PRECON * x_k - Y : XVEC contains x = operator^{-1} * rhs, and OPVEC contains operator * XVEC - Z : the converged signal has been given to the user, nothing remains to be done Possible instructions: - A : copy the guess to pointers[0], the diagonal of the operator to pointers[1], and the right-hand side of the problem to pointers[2] - B : perform pointers[1] = operator * pointers[0] - C : pointers[0] contains the solution; pointers[1][0] the residual norm - D : there was an error */ if ( state == 'I' ){ pointers[0] = XVEC; pointers[1] = PRECON; pointers[2] = RHS; state = 'G'; return 'A'; } if ( state == 'G' ){ stepG2H(); state = 'H'; } if ( state == 'H' ){ apply_precon( XVEC, WORK ); pointers[0] = WORK; pointers[1] = OPVEC; state = 'J'; num_matvec++; return 'B'; } if ( state == 'J' ){ stepJ2K(); state = 'K'; } if ( state == 'L' ){ stepL2K(); state = 'K'; } if ( state == 'K' ){ if ( rnorm >= RTOL ){ apply_precon( PVEC, WORK ); // WORK = PRECON * PVEC pointers[0] = WORK; pointers[1] = OPVEC; state = 'L'; } else { apply_precon( XVEC ); pointers[0] = XVEC; pointers[1] = OPVEC; state = 'Y'; } num_matvec++; return 'B'; } if ( state == 'Y' ){ stepY2Z(); pointers[0] = XVEC; pointers[1] = WORK; pointers[1][0] = rnorm; state = 'Z'; return 'C'; } return 'D'; } void CheMPS2::ConjugateGradient::stepL2K(){ apply_precon( OPVEC ); // OPVEC_old = ( PRECON * operator * PRECON ) * PVEC_old const double alpha = rdotr / inprod( PVEC, OPVEC ); // alpha = RESID_old^T * RESID_old / ( PVEC_old^T * ( PRECON * operator * PRECON ) * PVEC_old ) for ( int elem = 0; elem < veclength; elem++ ){ XVEC[ elem ] = XVEC[ elem ] + alpha * PVEC[ elem ]; // XVEC_new <-- XVEC_old + alpha * PVEC_old } for ( int elem = 0; elem < veclength; elem++ ){ RESID[ elem ] = RESID[ elem ] - alpha * OPVEC[ elem ]; // RESID_new <-- RESID_old - alpha * ( PRECON * operator * PRECON ) * PVEC_old } const double new_rdotr = inprod( RESID ); const double beta = new_rdotr / rdotr; // beta = RESID_new^T * RESID_new / ( RESID_old^T * RESID_old ) for ( int elem = 0; elem < veclength; elem++ ){ PVEC[ elem ] = RESID[ elem ] + beta * PVEC[ elem ]; // PVEC_new = RESID_new + beta * PVEC_old } rdotr = new_rdotr; rnorm = sqrt( rdotr ); if ( print ){ cout << "ConjugateGradient : After " << num_matvec << " matrix-vector products, the residual of p*O*p * x = p*RHS is " << rnorm << endl; } } void CheMPS2::ConjugateGradient::stepY2Z(){ rnorm = 0.0; for ( int elem = 0; elem < veclength; elem++ ){ const double diff = OPVEC[ elem ] - RHS[ elem ]; rnorm += diff * diff; } rnorm = sqrt( rnorm ); if ( print ){ cout << "ConjugateGradient : At convergence the residual of O * x = RHS is " << rnorm << endl; } } void CheMPS2::ConjugateGradient::stepJ2K(){ apply_precon( OPVEC ); // OPVEC = ( PRECON * operator * PRECON ) * XVEC for ( int elem = 0; elem < veclength; elem++ ){ RESID[ elem ] = RESID[ elem ] - OPVEC[ elem ]; // RESID = ( precon * RHS ) - ( precon * operator * precon ) * XVEC } for ( int elem = 0; elem < veclength; elem++ ){ PVEC[ elem ] = RESID[ elem ]; // PVEC = RESID } rdotr = inprod( RESID ); rnorm = sqrt( rdotr ); } void CheMPS2::ConjugateGradient::stepG2H(){ // PRECON = 1 / sqrt( diag ( operator ) ) for ( int elem = 0; elem < veclength; elem++ ){ if ( PRECON[ elem ] < DIAG_CUTOFF ){ PRECON[ elem ] = DIAG_CUTOFF; } PRECON[ elem ] = 1.0 / sqrt( PRECON[ elem ] ); } // RESID = PRECON * RHS apply_precon( RHS, RESID ); // XVEC = guess / PRECON for ( int elem = 0; elem < veclength; elem++ ){ XVEC[ elem ] = XVEC[ elem ] / PRECON[ elem ]; } } double CheMPS2::ConjugateGradient::inprod( double * vector ){ double inproduct = 0.0; for ( int elem = 0; elem < veclength; elem++ ){ inproduct += vector[ elem ] * vector[ elem ]; } return inproduct; } double CheMPS2::ConjugateGradient::inprod( double * vector, double * othervector ){ double inproduct = 0.0; for ( int elem = 0; elem < veclength; elem++ ){ inproduct += vector[ elem ] * othervector[ elem ]; } return inproduct; } void CheMPS2::ConjugateGradient::apply_precon( double * vector ){ for ( int elem = 0; elem < veclength; elem++ ){ vector[ elem ] = PRECON[ elem ] * vector[ elem ]; } } void CheMPS2::ConjugateGradient::apply_precon( double * vector, double * result ){ for ( int elem = 0; elem < veclength; elem++ ){ result[ elem ] = PRECON[ elem ] * vector[ elem ]; } } CheMPS2-1.8.9/CheMPS2/ConvergenceScheme.cpp000066400000000000000000000055131336564451100201360ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include "ConvergenceScheme.h" CheMPS2::ConvergenceScheme::ConvergenceScheme( const int num_instructions ){ this->num_instructions = num_instructions; assert( num_instructions > 0 ); num_D = new int[ num_instructions ]; energy_convergence = new double[ num_instructions ]; num_max_sweeps = new int[ num_instructions ]; noise_prefac = new double[ num_instructions ]; dvdson_rtol = new double[ num_instructions ]; } CheMPS2::ConvergenceScheme::~ConvergenceScheme(){ delete [] num_D; delete [] energy_convergence; delete [] num_max_sweeps; delete [] noise_prefac; delete [] dvdson_rtol; } int CheMPS2::ConvergenceScheme::get_number() const{ return num_instructions; } void CheMPS2::ConvergenceScheme::set_instruction( const int instruction, const int D, const double energy_conv, const int max_sweeps, const double noise_prefactor, const double davidson_rtol ){ assert( instruction >= 0 ); assert( instruction < num_instructions ); assert( D > 0 ); assert( energy_conv > 0.0 ); assert( max_sweeps > 0 ); assert( davidson_rtol > 0.0 ); num_D[ instruction ] = D; energy_convergence[ instruction ] = energy_conv; num_max_sweeps[ instruction ] = max_sweeps; noise_prefac[ instruction ] = noise_prefactor; dvdson_rtol[ instruction ] = davidson_rtol; } int CheMPS2::ConvergenceScheme::get_D( const int instruction ) const{ return num_D[ instruction ]; } double CheMPS2::ConvergenceScheme::get_energy_conv( const int instruction ) const{ return energy_convergence[ instruction ]; } int CheMPS2::ConvergenceScheme::get_max_sweeps( const int instruction ) const{ return num_max_sweeps[ instruction ]; } double CheMPS2::ConvergenceScheme::get_noise_prefactor( const int instruction ) const{ return noise_prefac[ instruction ]; } double CheMPS2::ConvergenceScheme::get_dvdson_rtol( const int instruction ) const{ return dvdson_rtol[ instruction ]; } CheMPS2-1.8.9/CheMPS2/Correlations.cpp000066400000000000000000000670131336564451100172220ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include "Correlations.h" #include "Lapack.h" #include "MPIchemps2.h" using std::cout; using std::endl; using std::max; using std::min; CheMPS2::Correlations::Correlations(const SyBookkeeper * denBKIn, const Problem * ProbIn, TwoDM * the2DMin){ denBK = denBKIn; Prob = ProbIn; the2DM = the2DMin; L = denBK->gL(); Cspin = new double[L*L]; Cdens = new double[L*L]; Cspinflip = new double[L*L]; Cdirad = new double[L*L]; MutInfo = new double[L*L]; for (int cnt=0; cntgetTwoDMB_DMRG(row,col,row,col); } Cspin[row + L*row] += the2DM->get1RDM_DMRG(row, row); } //Density for (int row=0; rowgetTwoDMA_DMRG(row,col,row,col) - the2DM->get1RDM_DMRG(row, row) * the2DM->get1RDM_DMRG(col, col); } Cdens[row + L*row] += the2DM->get1RDM_DMRG(row, row); } //Spin-flip for (int row=0; rowgetTwoDMB_DMRG(row,col,col,row) - the2DM->getTwoDMA_DMRG(row,col,col,row) ); } Cspinflip[row + L*row] += the2DM->get1RDM_DMRG(row, row); } //Singlet diradical: partial fill for (int row=0; rowget1RDM_DMRG(row, row) - the2DM->getTwoDMA_DMRG(row,row,row,row) ) * ( the2DM->get1RDM_DMRG(col, col) - the2DM->getTwoDMA_DMRG(col,col,col,col) ); } } } double CheMPS2::Correlations::getCspin_DMRG(const int row, const int col) const{ return Cspin[row + L*col]; } double CheMPS2::Correlations::getCspin_HAM(const int row, const int col) const{ //Prob assumes you use DMRG orbs... f1 converts HAM orbs to DMRG orbs if ( Prob->gReorder() ){ return getCspin_DMRG( Prob->gf1(row), Prob->gf1(col) ); } return getCspin_DMRG( row, col ); } double CheMPS2::Correlations::getCdens_DMRG(const int row, const int col) const{ return Cdens[row + L*col]; } double CheMPS2::Correlations::getCdens_HAM(const int row, const int col) const{ //Prob assumes you use DMRG orbs... f1 converts HAM orbs to DMRG orbs if ( Prob->gReorder() ){ return getCdens_DMRG( Prob->gf1(row), Prob->gf1(col) ); } return getCdens_DMRG( row, col ); } double CheMPS2::Correlations::getCspinflip_DMRG(const int row, const int col) const{ return Cspinflip[row + L*col]; } double CheMPS2::Correlations::getCspinflip_HAM(const int row, const int col) const{ //Prob assumes you use DMRG orbs... f1 converts HAM orbs to DMRG orbs if ( Prob->gReorder() ){ return getCspinflip_DMRG( Prob->gf1(row), Prob->gf1(col) ); } return getCspinflip_DMRG( row, col ); } double CheMPS2::Correlations::getCdirad_DMRG(const int row, const int col) const{ return Cdirad[row + L*col]; } double CheMPS2::Correlations::getCdirad_HAM(const int row, const int col) const{ //Prob assumes you use DMRG orbs... f1 converts HAM orbs to DMRG orbs if ( Prob->gReorder() ){ return getCdirad_DMRG( Prob->gf1(row), Prob->gf1(col) ); } return getCdirad_DMRG( row, col ); } double CheMPS2::Correlations::getMutualInformation_DMRG(const int row, const int col) const{ return MutInfo[row + L*col]; } double CheMPS2::Correlations::getMutualInformation_HAM(const int row, const int col) const{ //Prob assumes you use DMRG orbs... f1 converts HAM orbs to DMRG orbs if ( Prob->gReorder() ){ return getMutualInformation_DMRG( Prob->gf1(row), Prob->gf1(col) ); } return getMutualInformation_DMRG( row, col ); } double CheMPS2::Correlations::SingleOrbitalEntropy_DMRG(const int index) const{ const double val4 = 0.5 * the2DM->getTwoDMA_DMRG(index,index,index,index); const double val23 = 0.5 * ( the2DM->get1RDM_DMRG(index, index) - the2DM->getTwoDMA_DMRG(index,index,index,index) ); const double val1 = 1.0 - val4 - 2*val23; double entropy = 0.0; if (val1 > CheMPS2::CORRELATIONS_discardEig){ entropy -= val1 * log(val1 ); } if (val23 > CheMPS2::CORRELATIONS_discardEig){ entropy -= 2 * val23 * log(val23); } if (val4 > CheMPS2::CORRELATIONS_discardEig){ entropy -= val4 * log(val4 ); } return entropy; } double CheMPS2::Correlations::SingleOrbitalEntropy_HAM(const int index) const{ if ( Prob->gReorder() ){ return SingleOrbitalEntropy_DMRG( Prob->gf1(index) ); } return SingleOrbitalEntropy_DMRG( index ); } double CheMPS2::Correlations::MutualInformationDistance(const double power) const{ double Idist = 0.0; for (int row=0; rowgIndex(); const int MAXDIM = max(denBK->gMaxDimAtBound(theindex), denBK->gMaxDimAtBound(theindex+1)); double * workmem = new double[MAXDIM*MAXDIM]; int lindimRDM = 16; double * RDM = new double[lindimRDM*lindimRDM]; int lwork = 3*lindimRDM - 1; double * work = new double[lwork]; double * eigs = new double[lindimRDM]; const double prefactorSpin = 1.0/(Prob->gTwoS() + 1.0); const double sqrt_one_half = sqrt(0.5); for (int previousindex=0; previousindexgIrrep(previousindex) == denBK->gIrrep(theindex)) ? true : false; const double diag1 = diagram3(denT, Gtensors[previousindex], workmem) * prefactorSpin * 0.5 * sqrt_one_half; const double diag2 = 0.125 * ( the2DM->getTwoDMB_DMRG(previousindex,theindex,theindex,previousindex) - the2DM->getTwoDMA_DMRG(previousindex,theindex,theindex,previousindex) ); const double val1 = diagram1(denT, Ytensors[previousindex], workmem) * prefactorSpin; //1x1 block N=0, Sz=0 const double val2 = diagram2(denT, Ztensors[previousindex], workmem) * prefactorSpin; //1x1 block N=4, Sz=0 const double val3 = diag1 + diag2; //1x1 block N=2, Sz=2*sigma const double val4 = diagram1(denT, Gtensors[previousindex], workmem) * prefactorSpin * sqrt_one_half; //2x2 block N=1, alpha_LL const double val5 = diagram3(denT, Ytensors[previousindex], workmem) * prefactorSpin * 0.5; //2x2 block N=1, alpha_RR const double val6 = (equalIrreps) ? ( diagram4(denT, Ktensors[previousindex], workmem) * prefactorSpin * 0.5 ) : 0.0 ; //2x2 block N=1, alpha_LR const double val7 = diagram2(denT, Gtensors[previousindex], workmem) * prefactorSpin * sqrt_one_half; //2x2 block N=3, alpha_LL const double val8 = diagram3(denT, Ztensors[previousindex], workmem) * prefactorSpin * 0.5; //2x2 block N=3, alpha_RR const double val9 = (equalIrreps) ? ( diagram5(denT, Mtensors[previousindex], workmem) * prefactorSpin * 0.5 ) : 0.0 ; //2x2 block N=3, alpha_LR //4x4 block N=2, Sz=0 const double alpha = diagram2(denT, Ytensors[previousindex], workmem) * prefactorSpin; const double gamma = diagram1(denT, Ztensors[previousindex], workmem) * prefactorSpin; const double beta = diag1 - diag2; const double lambda = 2*diag2; const double delta = (equalIrreps) ? ( - diagram5(denT, Ktensors[previousindex], workmem) * prefactorSpin * 0.5 ) : 0.0; const double epsilon = (equalIrreps) ? ( diagram4(denT, Mtensors[previousindex], workmem) * prefactorSpin * 0.5 ) : 0.0; const double kappa = 0.5 * the2DM->getTwoDMA_DMRG(previousindex,previousindex,theindex,theindex); /* [ val1 ] [ val4 val6 ] [ val6 val5 ] [ val4 val6 ] [ val6 val5 ] [ val3 ] [ alpha delta -delta kappa ] [ delta beta lambda epsilon ] [ -delta lambda beta -epsilon ] [ kappa epsilon -epsilon gamma ] [ val3 ] [ val7 val9 ] [ val9 val8 ] [ val7 val9 ] [ val9 val8 ] [ val2 ] */ for (int cnt=0; cntgetTwoDMA_DMRG(previousindex,previousindex,previousindex,previousindex); const double RDM_1orb_prev_23 = 0.5 * ( the2DM->get1RDM_DMRG(previousindex, previousindex) - the2DM->getTwoDMA_DMRG(previousindex,previousindex,previousindex,previousindex) ); const double RDM_1orb_prev_1 = 1.0 - RDM_1orb_prev_4 - 2*RDM_1orb_prev_23; const double RDM_1orb_curr_4 = 0.5 * the2DM->getTwoDMA_DMRG(theindex,theindex,theindex,theindex); const double RDM_1orb_curr_23 = 0.5 * ( the2DM->get1RDM_DMRG(theindex, theindex) - the2DM->getTwoDMA_DMRG(theindex,theindex,theindex,theindex) ); const double RDM_1orb_curr_1 = 1.0 - RDM_1orb_curr_4 - 2*RDM_1orb_curr_23; cout << " Correlations::FillSite : Looking at DMRG sites (" << previousindex << "," << theindex << ")." << endl; //Check 1 : full trace double fulltrace = 0.0; for (int cnt=0; cntgReorder()) ? Prob->gf1(row) : row; int col2 = (Prob->gReorder()) ? Prob->gf1(col) : col; if (table[row2 + L*col2] < 0.0){ thestream << prefix << table[row2 + L*col2]; } else { thestream << prefix << " " << table[row2 + L*col2]; } } } thestream << "\n"; } thestream << "\n"; } cout << thestream.str(); } void CheMPS2::Correlations::Print(const int precision, const int columnsPerLine) const{ cout << "--------------------------------------------------------" << endl; cout << "Spin correlation function = 4 * ( < S_i^z S_j^z > - < S_i^z > * < S_j^z > ) \nHamiltonian index order is used!\n" << endl; PrintTableNice( Cspin , precision, columnsPerLine ); cout << "--------------------------------------------------------" << endl; cout << "Spin-flip correlation function = < S_i^+ S_j^- > + < S_i^- S_j^+ > \nHamiltonian index order is used!\n" << endl; PrintTableNice( Cspinflip , precision, columnsPerLine); cout << "--------------------------------------------------------" << endl; cout << "Density correlation function = < n_i n_j > - < n_i > * < n_j > \nHamiltonian index order is used!\n" << endl; PrintTableNice( Cdens , precision, columnsPerLine ); cout << "--------------------------------------------------------" << endl; cout << "Singlet diradical correlation function = < d_i,up d_j,down > + < d_i,down d_j,up > - < d_i,up > * < d_j,down > - < d_i,down > * < d_j,up > \nHamiltonian index order is used!\n" << endl; PrintTableNice( Cdirad , precision, columnsPerLine ); cout << "--------------------------------------------------------" << endl; cout << "Two-orbital mutual information = 0.5 * ( s1(i) + s1(j) - s2(i,j) ) * ( 1 - delta(i,j) ) \nHamiltonian index order is used!\n" << endl; PrintTableNice( MutInfo , precision, columnsPerLine ); cout << "--------------------------------------------------------" << endl; } CheMPS2-1.8.9/CheMPS2/Cumulant.cpp000066400000000000000000000747131336564451100163530ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include "Cumulant.h" /*void CheMPS2::Cumulant::gamma4_fock_contract_ham_slow(const Problem * prob, const ThreeDM * the3DM, const TwoDM * the2DM, double * fock, double * result){ struct timeval start, end; gettimeofday(&start, NULL); const int L = prob->gL(); for ( int cnt = 0; cnt < L*L*L*L*L*L; cnt++ ){ result[ cnt ] = 0.0; } int * irreps = new int[ L ]; for ( int orb = 0; orb < L; orb++ ){ irreps[ orb ] = prob->gIrrep(( prob->gReorder() ) ? prob->gf1( orb ) : orb ); } #pragma omp parallel for schedule(dynamic) for ( int i = 0; i < L; i++ ){ for ( int j = i; j < L; j++ ){ for ( int k = i; k < L; k++ ){ const int irrep_ijk = Irreps::directProd( Irreps::directProd( irreps[ i ], irreps[ j ] ), irreps[ k ] ); for ( int p = i; p < L; p++ ){ for ( int q = i; q < L; q++ ){ for ( int r = q; r < L; r++ ){ const int irrep_pqr = Irreps::directProd( Irreps::directProd( irreps[ p ], irreps[ q ] ), irreps[ r ] ); if ( irrep_ijk == irrep_pqr ){ double value = 0.0; for ( int l = 0; l < L; l++ ){ for ( int s = 0; s < L; s++ ){ if ( irreps[ l ] == irreps[ s ] ){ value += fock[ l + L * s ] * gamma4_ham(prob, the3DM, the2DM, i, j, k, l, p, q, r, s); } } } result[ i + L * ( j + L * ( k + L * ( p + L * ( q + L * r )))) ] = value; result[ i + L * ( k + L * ( j + L * ( p + L * ( r + L * q )))) ] = value; result[ j + L * ( i + L * ( k + L * ( q + L * ( p + L * r )))) ] = value; result[ k + L * ( i + L * ( j + L * ( r + L * ( p + L * q )))) ] = value; result[ j + L * ( k + L * ( i + L * ( q + L * ( r + L * p )))) ] = value; result[ k + L * ( j + L * ( i + L * ( r + L * ( q + L * p )))) ] = value; result[ p + L * ( q + L * ( r + L * ( i + L * ( j + L * k )))) ] = value; result[ p + L * ( r + L * ( q + L * ( i + L * ( k + L * j )))) ] = value; result[ q + L * ( p + L * ( r + L * ( j + L * ( i + L * k )))) ] = value; result[ r + L * ( p + L * ( q + L * ( k + L * ( i + L * j )))) ] = value; result[ q + L * ( r + L * ( p + L * ( j + L * ( k + L * i )))) ] = value; result[ r + L * ( q + L * ( p + L * ( k + L * ( j + L * i )))) ] = value; } } } } } } } delete [] irreps; gettimeofday(&end, NULL); const double elapsed = (end.tv_sec - start.tv_sec) + 1e-6 * (end.tv_usec - start.tv_usec); std::cout << "Cumulant :: Contraction of cu(4)-4RDM with CASPT2 Fock operator took " << elapsed << " seconds." << std::endl; }*/ void CheMPS2::Cumulant::gamma4_fock_contract_ham(const Problem * prob, const ThreeDM * the3DM, const TwoDM * the2DM, double * fock, double * result){ struct timeval start, end; gettimeofday(&start, NULL); const int L = prob->gL(); /* Clear result */ for ( int cnt = 0; cnt < L*L*L*L*L*L; cnt++ ){ result[ cnt ] = 0.0; } /* Construct an array with the orbital irreps in Hamiltonian indices */ int * irreps = new int[ L ]; for ( int orb = 0; orb < L; orb++ ){ irreps[ orb ] = prob->gIrrep(( prob->gReorder() ) ? prob->gf1( orb ) : orb ); } /* Helper arrays with partial (mult) or full (dot) contractions of objects with the CASPT2 Fock operator */ double * G3dotF = new double[ L*L*L*L ]; double * lambda2 = new double[ L*L*L*L ]; double * G2multF = new double[ L*L*L*L ]; double * L2multF = new double[ L*L*L*L ]; double * gamma1 = new double[ L*L ]; double * G1multF = new double[ L*L ]; double * G2dotF = new double[ L*L ]; double * L2dotF = new double[ L*L ]; for ( int cnt = 0; cnt < L*L*L*L; cnt++ ){ G3dotF[ cnt ] = 0.0; } for ( int cnt = 0; cnt < L*L*L*L; cnt++ ){ lambda2[ cnt ] = 0.0; } for ( int cnt = 0; cnt < L*L*L*L; cnt++ ){ G2multF[ cnt ] = 0.0; } for ( int cnt = 0; cnt < L*L*L*L; cnt++ ){ L2multF[ cnt ] = 0.0; } for ( int cnt = 0; cnt < L*L; cnt++ ){ gamma1[ cnt ] = 0.0; } for ( int cnt = 0; cnt < L*L; cnt++ ){ G1multF[ cnt ] = 0.0; } for ( int cnt = 0; cnt < L*L; cnt++ ){ G2dotF[ cnt ] = 0.0; } for ( int cnt = 0; cnt < L*L; cnt++ ){ L2dotF[ cnt ] = 0.0; } double G1dotF = 0.0; /* Fill gamma1 */ for ( int i = 0; i < L; i++ ){ for ( int j = i; j < L; j++ ){ const double value = the2DM->get1RDM_HAM( i, j ); gamma1[ i + L * j ] = value; gamma1[ j + L * i ] = value; } } /* Build G3dotF[i,j,p,q] = sum_[l,s] Gamma3[i,j,l,p,q,s] F[l,s] Build lambda2[i,j,p,q] = Lambda2[i,j,p,q] */ for ( int i = 0; i < L; i++ ){ for ( int j = i; j < L; j++ ){ const int irrep_ij = Irreps::directProd( irreps[ i ], irreps[ j ] ); for ( int p = i; p < L; p++ ){ for ( int q = i; q < L; q++ ){ const int irrep_pq = Irreps::directProd( irreps[ p ], irreps[ q ] ); if ( irrep_ij == irrep_pq ){ { // sum_[l,s] Gamma3[i,j,l,p,q,s] F[l,s] double value = 0.0; for ( int l = 0; l < L; l++ ){ for ( int s = 0; s < L; s++ ){ if ( irreps[ l ] == irreps[ s ] ){ value += the3DM->get_ham_index(i,j,l,p,q,s) * fock[ l + L * s ]; } } } G3dotF[ i + L * ( j + L * ( p + L * q )) ] = value; G3dotF[ j + L * ( i + L * ( q + L * p )) ] = value; G3dotF[ p + L * ( q + L * ( i + L * j )) ] = value; G3dotF[ q + L * ( p + L * ( j + L * i )) ] = value; } { // Lambda2[i,j,p,q] const double val_lambda = the2DM->getTwoDMA_HAM( i, j, p, q ) - gamma1[ i + L * p ] * gamma1[ j + L * q ] + gamma1[ i + L * q ] * gamma1[ j + L * p ] * 0.5; lambda2[ i + L * ( j + L * ( p + L * q )) ] = val_lambda; lambda2[ j + L * ( i + L * ( q + L * p )) ] = val_lambda; lambda2[ p + L * ( q + L * ( i + L * j )) ] = val_lambda; lambda2[ q + L * ( p + L * ( j + L * i )) ] = val_lambda; } } } } } } /* Build G1multF[i,j] = sum_[p] Gamma1[i,p] F[p,j] Build G1dotF = sum_[i,j] Gamma1[i,j] F[j,i] */ for ( int i = 0; i < L; i++ ){ for ( int j = 0; j < L; j++ ){ if ( irreps[ i ] == irreps[ j ] ){ double value = 0.0; for ( int p = 0; p < L; p++ ){ if ( irreps[ j ] == irreps[ p ] ){ value += gamma1[ i + L * p ] * fock[ p + L * j ]; } } G1multF[ i + L * j ] = value; } } G1dotF += G1multF[ i * ( L + 1 ) ]; } /* Build G2dotF[i,j] = sum_[p,q] Gamma2[i,p,j,q] F[p,q] Build L2dotF[i,j] = sum_[p,q] Lambda2[i,p,j,q] F[p,q] */ for ( int i = 0; i < L; i++ ){ for ( int j = i; j < L; j++ ){ if ( irreps[ i ] == irreps[ j ] ){ double val_gamma = 0.0; double val_lambda = 0.0; for ( int p = 0; p < L; p++ ){ for ( int q = 0; q < L; q++ ){ if ( irreps[ p ] == irreps[ q ] ){ val_gamma += fock[ p + L * q ] * the2DM->getTwoDMA_HAM( i, p, j, q ); val_lambda += fock[ p + L * q ] * lambda2[ i + L * ( p + L * ( j + L * q )) ]; } } } G2dotF[ i + L * j ] = val_gamma; G2dotF[ j + L * i ] = val_gamma; L2dotF[ i + L * j ] = val_lambda; L2dotF[ j + L * i ] = val_lambda; } } } /* Build G2multF[i,s,j,k] = sum_[l] Gamma2[i,l,j,k] F[l,s] Build L2multF[i,s,j,k] = sum_[l] Lambda2[i,l,j,k] F[l,s] */ for ( int i = 0; i < L; i++ ){ for ( int j = 0; j < L; j++ ){ const int irrep_ij = Irreps::directProd( irreps[ i ], irreps[ j ] ); for ( int k = 0; k < L; k++ ){ for ( int s = 0; s < L; s++ ){ const int irrep_ks = Irreps::directProd( irreps[ k ], irreps[ s ] ); if ( irrep_ij == irrep_ks ){ double val_gamma = 0.0; double val_lambda = 0.0; for ( int l = 0; l < L; l++ ){ if ( irreps[ l ] == irreps[ s ] ){ val_gamma += fock[ l + L * s ] * the2DM->getTwoDMA_HAM( i, l, j, k ); val_lambda += fock[ l + L * s ] * lambda2[ i + L * ( l + L * ( j + L * k ) ) ]; } } G2multF[ i + L * ( s + L * ( j + L * k ) ) ] = val_gamma; L2multF[ i + L * ( s + L * ( j + L * k ) ) ] = val_lambda; } } } } } /* Fill result */ #pragma omp parallel for schedule(dynamic) for ( int i = 0; i < L; i++ ){ for ( int j = i; j < L; j++ ){ for ( int k = i; k < L; k++ ){ const int irrep_ijk = Irreps::directProd( Irreps::directProd( irreps[ i ], irreps[ j ] ), irreps[ k ] ); for ( int p = i; p < L; p++ ){ for ( int q = i; q < L; q++ ){ for ( int r = q; r < L; r++ ){ const int irrep_pqr = Irreps::directProd( Irreps::directProd( irreps[ p ], irreps[ q ] ), irreps[ r ] ); if ( irrep_ijk == irrep_pqr ){ double dm3_contribution = 0.0; double gamma2_part1 = 0.0; double gamma2_part2 = 0.0; double lambda2_part1 = 0.0; double lambda2_part2 = 0.0; for ( int ls = 0; ls < L; ls++ ){ dm3_contribution += ( the3DM->get_ham_index( ls, j, k, p, q, r ) * G1multF[ i + L * ls ] + the3DM->get_ham_index( i, ls, k, p, q, r ) * G1multF[ j + L * ls ] + the3DM->get_ham_index( i, j, ls, p, q, r ) * G1multF[ k + L * ls ] + the3DM->get_ham_index( i, j, k, ls, q, r ) * G1multF[ p + L * ls ] + the3DM->get_ham_index( i, j, k, p, ls, r ) * G1multF[ q + L * ls ] + the3DM->get_ham_index( i, j, k, p, q, ls ) * G1multF[ r + L * ls ] ); gamma2_part1 += ( the2DM->getTwoDMA_HAM( i, j, p, ls ) * G2multF[ k + L * ( ls + L * ( r + L * q )) ] + the2DM->getTwoDMA_HAM( i, j, ls, q ) * G2multF[ k + L * ( ls + L * ( r + L * p )) ] + the2DM->getTwoDMA_HAM( i, k, p, ls ) * G2multF[ j + L * ( ls + L * ( q + L * r )) ] + the2DM->getTwoDMA_HAM( i, k, ls, r ) * G2multF[ j + L * ( ls + L * ( q + L * p )) ] + the2DM->getTwoDMA_HAM( k, j, ls, q ) * G2multF[ i + L * ( ls + L * ( p + L * r )) ] + the2DM->getTwoDMA_HAM( k, j, r, ls ) * G2multF[ i + L * ( ls + L * ( p + L * q )) ] ); gamma2_part2 += ( the2DM->getTwoDMA_HAM( i, j, r, ls ) * ( G2multF[ k + L * ( ls + L * ( p + L * q )) ] + 0.5 * G2multF[ k + L * ( ls + L * ( q + L * p )) ] ) + the2DM->getTwoDMA_HAM( i, j, ls, r ) * ( G2multF[ k + L * ( ls + L * ( q + L * p )) ] + 0.5 * G2multF[ k + L * ( ls + L * ( p + L * q )) ] ) + the2DM->getTwoDMA_HAM( i, k, q, ls ) * ( G2multF[ j + L * ( ls + L * ( p + L * r )) ] + 0.5 * G2multF[ j + L * ( ls + L * ( r + L * p )) ] ) + the2DM->getTwoDMA_HAM( i, k, ls, q ) * ( G2multF[ j + L * ( ls + L * ( r + L * p )) ] + 0.5 * G2multF[ j + L * ( ls + L * ( p + L * r )) ] ) + the2DM->getTwoDMA_HAM( k, j, p, ls ) * ( G2multF[ i + L * ( ls + L * ( r + L * q )) ] + 0.5 * G2multF[ i + L * ( ls + L * ( q + L * r )) ] ) + the2DM->getTwoDMA_HAM( k, j, ls, p ) * ( G2multF[ i + L * ( ls + L * ( q + L * r )) ] + 0.5 * G2multF[ i + L * ( ls + L * ( r + L * q )) ] ) ); lambda2_part1 += ( lambda2[ i + L * ( j + L * ( p + L * ls )) ] * L2multF[ k + L * ( ls + L * ( r + L * q )) ] + lambda2[ i + L * ( j + L * ( ls + L * q )) ] * L2multF[ k + L * ( ls + L * ( r + L * p )) ] + lambda2[ i + L * ( k + L * ( p + L * ls )) ] * L2multF[ j + L * ( ls + L * ( q + L * r )) ] + lambda2[ i + L * ( k + L * ( ls + L * r )) ] * L2multF[ j + L * ( ls + L * ( q + L * p )) ] + lambda2[ k + L * ( j + L * ( ls + L * q )) ] * L2multF[ i + L * ( ls + L * ( p + L * r )) ] + lambda2[ k + L * ( j + L * ( r + L * ls )) ] * L2multF[ i + L * ( ls + L * ( p + L * q )) ] ); lambda2_part2 += ( lambda2[ i + L * ( j + L * ( r + L * ls )) ] * ( L2multF[ k + L * ( ls + L * ( p + L * q )) ] + 0.5 * L2multF[ k + L * ( ls + L * ( q + L * p )) ] ) + lambda2[ i + L * ( j + L * ( ls + L * r )) ] * ( L2multF[ k + L * ( ls + L * ( q + L * p )) ] + 0.5 * L2multF[ k + L * ( ls + L * ( p + L * q )) ] ) + lambda2[ i + L * ( k + L * ( q + L * ls )) ] * ( L2multF[ j + L * ( ls + L * ( p + L * r )) ] + 0.5 * L2multF[ j + L * ( ls + L * ( r + L * p )) ] ) + lambda2[ i + L * ( k + L * ( ls + L * q )) ] * ( L2multF[ j + L * ( ls + L * ( r + L * p )) ] + 0.5 * L2multF[ j + L * ( ls + L * ( p + L * r )) ] ) + lambda2[ k + L * ( j + L * ( p + L * ls )) ] * ( L2multF[ i + L * ( ls + L * ( r + L * q )) ] + 0.5 * L2multF[ i + L * ( ls + L * ( q + L * r )) ] ) + lambda2[ k + L * ( j + L * ( ls + L * p )) ] * ( L2multF[ i + L * ( ls + L * ( q + L * r )) ] + 0.5 * L2multF[ i + L * ( ls + L * ( r + L * q )) ] ) ); } const double contracted_value = ( the3DM->get_ham_index( i, j, k, p, q, r ) * G1dotF + G3dotF[ i + L * ( j + L * ( p + L * q )) ] * gamma1[ k + L * r ] - 0.5 * G3dotF[ i + L * ( j + L * ( r + L * q )) ] * gamma1[ k + L * p ] - 0.5 * G3dotF[ i + L * ( j + L * ( p + L * r )) ] * gamma1[ k + L * q ] + G3dotF[ i + L * ( k + L * ( p + L * r )) ] * gamma1[ j + L * q ] - 0.5 * G3dotF[ i + L * ( k + L * ( q + L * r )) ] * gamma1[ j + L * p ] - 0.5 * G3dotF[ i + L * ( k + L * ( p + L * q )) ] * gamma1[ j + L * r ] + G3dotF[ j + L * ( k + L * ( q + L * r )) ] * gamma1[ i + L * p ] - 0.5 * G3dotF[ j + L * ( k + L * ( p + L * r )) ] * gamma1[ i + L * q ] - 0.5 * G3dotF[ j + L * ( k + L * ( q + L * p )) ] * gamma1[ i + L * r ] - 0.5 * dm3_contribution - the2DM->getTwoDMA_HAM( i, j, p, q ) * G2dotF[ k + L * r ] + 0.5 * the2DM->getTwoDMA_HAM( i, j, p, r ) * G2dotF[ k + L * q ] + 0.5 * the2DM->getTwoDMA_HAM( i, j, r, q ) * G2dotF[ k + L * p ] - the2DM->getTwoDMA_HAM( i, k, p, r ) * G2dotF[ j + L * q ] + 0.5 * the2DM->getTwoDMA_HAM( i, k, p, q ) * G2dotF[ j + L * r ] + 0.5 * the2DM->getTwoDMA_HAM( i, k, q, r ) * G2dotF[ j + L * p ] - the2DM->getTwoDMA_HAM( k, j, r, q ) * G2dotF[ i + L * p ] + 0.5 * the2DM->getTwoDMA_HAM( k, j, p, q ) * G2dotF[ i + L * r ] + 0.5 * the2DM->getTwoDMA_HAM( k, j, r, p ) * G2dotF[ i + L * q ] + 0.5 * gamma2_part1 - gamma2_part2 / 3.0 + 2 * lambda2[ i + L * ( j + L * ( p + L * q )) ] * L2dotF[ k + L * r ] - lambda2[ i + L * ( j + L * ( p + L * r )) ] * L2dotF[ k + L * q ] - lambda2[ i + L * ( j + L * ( r + L * q )) ] * L2dotF[ k + L * p ] + 2 * lambda2[ i + L * ( k + L * ( p + L * r )) ] * L2dotF[ j + L * q ] - lambda2[ i + L * ( k + L * ( p + L * q )) ] * L2dotF[ j + L * r ] - lambda2[ i + L * ( k + L * ( q + L * r )) ] * L2dotF[ j + L * p ] + 2 * lambda2[ k + L * ( j + L * ( r + L * q )) ] * L2dotF[ i + L * p ] - lambda2[ k + L * ( j + L * ( p + L * q )) ] * L2dotF[ i + L * r ] - lambda2[ k + L * ( j + L * ( r + L * p )) ] * L2dotF[ i + L * q ] - lambda2_part1 + lambda2_part2 / 1.5 ); result[ i + L * ( j + L * ( k + L * ( p + L * ( q + L * r )))) ] = contracted_value; result[ i + L * ( k + L * ( j + L * ( p + L * ( r + L * q )))) ] = contracted_value; result[ j + L * ( i + L * ( k + L * ( q + L * ( p + L * r )))) ] = contracted_value; result[ k + L * ( i + L * ( j + L * ( r + L * ( p + L * q )))) ] = contracted_value; result[ j + L * ( k + L * ( i + L * ( q + L * ( r + L * p )))) ] = contracted_value; result[ k + L * ( j + L * ( i + L * ( r + L * ( q + L * p )))) ] = contracted_value; result[ p + L * ( q + L * ( r + L * ( i + L * ( j + L * k )))) ] = contracted_value; result[ p + L * ( r + L * ( q + L * ( i + L * ( k + L * j )))) ] = contracted_value; result[ q + L * ( p + L * ( r + L * ( j + L * ( i + L * k )))) ] = contracted_value; result[ r + L * ( p + L * ( q + L * ( k + L * ( i + L * j )))) ] = contracted_value; result[ q + L * ( r + L * ( p + L * ( j + L * ( k + L * i )))) ] = contracted_value; result[ r + L * ( q + L * ( p + L * ( k + L * ( j + L * i )))) ] = contracted_value; } } } } } } } delete [] G3dotF; delete [] lambda2; delete [] G2multF; delete [] L2multF; delete [] gamma1; delete [] G1multF; delete [] G2dotF; delete [] L2dotF; delete [] irreps; gettimeofday(&end, NULL); const double elapsed = (end.tv_sec - start.tv_sec) + 1e-6 * (end.tv_usec - start.tv_usec); std::cout << "Cumulant :: Contraction of cu(4)-4RDM with CASPT2 Fock operator took " << elapsed << " seconds." << std::endl; } double CheMPS2::Cumulant::lambda2_ham(const TwoDM * the2DM, const int i, const int j, const int p, const int q){ const double value = the2DM->getTwoDMA_HAM( i, j, p, q ) - the2DM->get1RDM_HAM( i, p ) * the2DM->get1RDM_HAM( j, q ) + the2DM->get1RDM_HAM( i, q ) * the2DM->get1RDM_HAM( j, p ) * 0.5; return value; } double CheMPS2::Cumulant::gamma4_ham(const Problem * prob, const ThreeDM * the3DM, const TwoDM * the2DM, const int i, const int j, const int k, const int l, const int p, const int q, const int r, const int s){ //Prob assumes you use DMRG orbs... f1 converts HAM orbs to DMRG orbs const int irrep_i = prob->gIrrep(( prob->gReorder() ) ? prob->gf1( i ) : i ); const int irrep_j = prob->gIrrep(( prob->gReorder() ) ? prob->gf1( j ) : j ); const int irrep_k = prob->gIrrep(( prob->gReorder() ) ? prob->gf1( k ) : k ); const int irrep_l = prob->gIrrep(( prob->gReorder() ) ? prob->gf1( l ) : l ); const int irrep_p = prob->gIrrep(( prob->gReorder() ) ? prob->gf1( p ) : p ); const int irrep_q = prob->gIrrep(( prob->gReorder() ) ? prob->gf1( q ) : q ); const int irrep_r = prob->gIrrep(( prob->gReorder() ) ? prob->gf1( r ) : r ); const int irrep_s = prob->gIrrep(( prob->gReorder() ) ? prob->gf1( s ) : s ); const int irrep_ij = Irreps::directProd( irrep_i, irrep_j ); const int irrep_kl = Irreps::directProd( irrep_k, irrep_l ); const int irrep_pq = Irreps::directProd( irrep_p, irrep_q ); const int irrep_rs = Irreps::directProd( irrep_r, irrep_s ); if ( Irreps::directProd( irrep_ij, irrep_kl ) != Irreps::directProd( irrep_pq, irrep_rs ) ){ return 0.0; } const double part1 = ( the3DM->get_ham_index(i,j,k,p,q,r) * the2DM->get1RDM_HAM(l,s) - 0.5 * the3DM->get_ham_index(i,j,k,s,q,r) * the2DM->get1RDM_HAM(l,p) - 0.5 * the3DM->get_ham_index(i,j,k,p,s,r) * the2DM->get1RDM_HAM(l,q) - 0.5 * the3DM->get_ham_index(i,j,k,p,q,s) * the2DM->get1RDM_HAM(l,r) + the3DM->get_ham_index(i,j,l,p,q,s) * the2DM->get1RDM_HAM(k,r) - 0.5 * the3DM->get_ham_index(i,j,l,r,q,s) * the2DM->get1RDM_HAM(k,p) - 0.5 * the3DM->get_ham_index(i,j,l,p,r,s) * the2DM->get1RDM_HAM(k,q) - 0.5 * the3DM->get_ham_index(i,j,l,p,q,r) * the2DM->get1RDM_HAM(k,s) + the3DM->get_ham_index(i,k,l,p,r,s) * the2DM->get1RDM_HAM(j,q) - 0.5 * the3DM->get_ham_index(i,k,l,q,r,s) * the2DM->get1RDM_HAM(j,p) - 0.5 * the3DM->get_ham_index(i,k,l,p,q,s) * the2DM->get1RDM_HAM(j,r) - 0.5 * the3DM->get_ham_index(i,k,l,p,r,q) * the2DM->get1RDM_HAM(j,s) + the3DM->get_ham_index(j,k,l,q,r,s) * the2DM->get1RDM_HAM(i,p) - 0.5 * the3DM->get_ham_index(j,k,l,p,r,s) * the2DM->get1RDM_HAM(i,q) - 0.5 * the3DM->get_ham_index(j,k,l,q,p,s) * the2DM->get1RDM_HAM(i,r) - 0.5 * the3DM->get_ham_index(j,k,l,q,r,p) * the2DM->get1RDM_HAM(i,s) ); const double part2 = ( the2DM->getTwoDMA_HAM(i,j,p,q) * the2DM->getTwoDMA_HAM(k,l,r,s) - the2DM->getTwoDMA_HAM(i,j,p,r) * the2DM->getTwoDMA_HAM(k,l,q,s) * 0.5 - the2DM->getTwoDMA_HAM(i,j,p,s) * the2DM->getTwoDMA_HAM(k,l,r,q) * 0.5 - the2DM->getTwoDMA_HAM(i,j,r,q) * the2DM->getTwoDMA_HAM(k,l,p,s) * 0.5 - the2DM->getTwoDMA_HAM(i,j,s,q) * the2DM->getTwoDMA_HAM(k,l,r,p) * 0.5 + the2DM->getTwoDMA_HAM(i,j,r,s) * the2DM->getTwoDMA_HAM(k,l,p,q) / 3.0 + the2DM->getTwoDMA_HAM(i,j,r,s) * the2DM->getTwoDMA_HAM(k,l,q,p) / 6.0 + the2DM->getTwoDMA_HAM(i,j,s,r) * the2DM->getTwoDMA_HAM(k,l,p,q) / 6.0 + the2DM->getTwoDMA_HAM(i,j,s,r) * the2DM->getTwoDMA_HAM(k,l,q,p) / 3.0 + the2DM->getTwoDMA_HAM(i,k,p,r) * the2DM->getTwoDMA_HAM(j,l,q,s) - the2DM->getTwoDMA_HAM(i,k,p,q) * the2DM->getTwoDMA_HAM(j,l,r,s) * 0.5 - the2DM->getTwoDMA_HAM(i,k,p,s) * the2DM->getTwoDMA_HAM(j,l,q,r) * 0.5 - the2DM->getTwoDMA_HAM(i,k,q,r) * the2DM->getTwoDMA_HAM(j,l,p,s) * 0.5 - the2DM->getTwoDMA_HAM(i,k,s,r) * the2DM->getTwoDMA_HAM(j,l,q,p) * 0.5 + the2DM->getTwoDMA_HAM(i,k,q,s) * the2DM->getTwoDMA_HAM(j,l,p,r) / 3.0 + the2DM->getTwoDMA_HAM(i,k,s,q) * the2DM->getTwoDMA_HAM(j,l,p,r) / 6.0 + the2DM->getTwoDMA_HAM(i,k,q,s) * the2DM->getTwoDMA_HAM(j,l,r,p) / 6.0 + the2DM->getTwoDMA_HAM(i,k,s,q) * the2DM->getTwoDMA_HAM(j,l,r,p) / 3.0 + the2DM->getTwoDMA_HAM(i,l,p,s) * the2DM->getTwoDMA_HAM(k,j,r,q) - the2DM->getTwoDMA_HAM(i,l,p,r) * the2DM->getTwoDMA_HAM(k,j,s,q) * 0.5 - the2DM->getTwoDMA_HAM(i,l,p,q) * the2DM->getTwoDMA_HAM(k,j,r,s) * 0.5 - the2DM->getTwoDMA_HAM(i,l,r,s) * the2DM->getTwoDMA_HAM(k,j,p,q) * 0.5 - the2DM->getTwoDMA_HAM(i,l,q,s) * the2DM->getTwoDMA_HAM(k,j,r,p) * 0.5 + the2DM->getTwoDMA_HAM(i,l,r,q) * the2DM->getTwoDMA_HAM(k,j,p,s) / 3.0 + the2DM->getTwoDMA_HAM(i,l,q,r) * the2DM->getTwoDMA_HAM(k,j,p,s) / 6.0 + the2DM->getTwoDMA_HAM(i,l,r,q) * the2DM->getTwoDMA_HAM(k,j,s,p) / 6.0 + the2DM->getTwoDMA_HAM(i,l,q,r) * the2DM->getTwoDMA_HAM(k,j,s,p) / 3.0 ); const double part3 = ( lambda2_ham(the2DM,i,j,p,q) * lambda2_ham(the2DM,k,l,r,s) - lambda2_ham(the2DM,i,j,p,r) * lambda2_ham(the2DM,k,l,q,s) * 0.5 - lambda2_ham(the2DM,i,j,p,s) * lambda2_ham(the2DM,k,l,r,q) * 0.5 - lambda2_ham(the2DM,i,j,r,q) * lambda2_ham(the2DM,k,l,p,s) * 0.5 - lambda2_ham(the2DM,i,j,s,q) * lambda2_ham(the2DM,k,l,r,p) * 0.5 + lambda2_ham(the2DM,i,j,r,s) * lambda2_ham(the2DM,k,l,p,q) / 3.0 + lambda2_ham(the2DM,i,j,r,s) * lambda2_ham(the2DM,k,l,q,p) / 6.0 + lambda2_ham(the2DM,i,j,s,r) * lambda2_ham(the2DM,k,l,p,q) / 6.0 + lambda2_ham(the2DM,i,j,s,r) * lambda2_ham(the2DM,k,l,q,p) / 3.0 + lambda2_ham(the2DM,i,k,p,r) * lambda2_ham(the2DM,j,l,q,s) - lambda2_ham(the2DM,i,k,p,q) * lambda2_ham(the2DM,j,l,r,s) * 0.5 - lambda2_ham(the2DM,i,k,p,s) * lambda2_ham(the2DM,j,l,q,r) * 0.5 - lambda2_ham(the2DM,i,k,q,r) * lambda2_ham(the2DM,j,l,p,s) * 0.5 - lambda2_ham(the2DM,i,k,s,r) * lambda2_ham(the2DM,j,l,q,p) * 0.5 + lambda2_ham(the2DM,i,k,q,s) * lambda2_ham(the2DM,j,l,p,r) / 3.0 + lambda2_ham(the2DM,i,k,s,q) * lambda2_ham(the2DM,j,l,p,r) / 6.0 + lambda2_ham(the2DM,i,k,q,s) * lambda2_ham(the2DM,j,l,r,p) / 6.0 + lambda2_ham(the2DM,i,k,s,q) * lambda2_ham(the2DM,j,l,r,p) / 3.0 + lambda2_ham(the2DM,i,l,p,s) * lambda2_ham(the2DM,k,j,r,q) - lambda2_ham(the2DM,i,l,p,r) * lambda2_ham(the2DM,k,j,s,q) * 0.5 - lambda2_ham(the2DM,i,l,p,q) * lambda2_ham(the2DM,k,j,r,s) * 0.5 - lambda2_ham(the2DM,i,l,r,s) * lambda2_ham(the2DM,k,j,p,q) * 0.5 - lambda2_ham(the2DM,i,l,q,s) * lambda2_ham(the2DM,k,j,r,p) * 0.5 + lambda2_ham(the2DM,i,l,r,q) * lambda2_ham(the2DM,k,j,p,s) / 3.0 + lambda2_ham(the2DM,i,l,q,r) * lambda2_ham(the2DM,k,j,p,s) / 6.0 + lambda2_ham(the2DM,i,l,r,q) * lambda2_ham(the2DM,k,j,s,p) / 6.0 + lambda2_ham(the2DM,i,l,q,r) * lambda2_ham(the2DM,k,j,s,p) / 3.0 ); return ( part1 - part2 + 2 * part3 ); } CheMPS2-1.8.9/CheMPS2/DIIS.cpp000066400000000000000000000236261336564451100153100ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include "MyHDF5.h" #include "Lapack.h" #include "DIIS.h" using std::string; using std::ifstream; using std::cout; using std::endl; CheMPS2::DIIS::DIIS(const int numVarsParamIn, const int numVarsErrorIn, const int numVecsIn){ numVarsParam = numVarsParamIn; numVarsError = numVarsErrorIn; numVecs = numVecsIn; errorVectors = new double*[numVecs]; paramVectors = new double*[numVecs]; currentNumVecs = 0; lastLinco = new double[numVarsParam]; } CheMPS2::DIIS::~DIIS(){ for (int cnt=0; cnt work for (int cnt=0; cnt work+lindim char trans = 'T'; char notra = 'N'; int one = 1; double alpha = 1.0; double beta = 0.0; dgemm_(&trans, ¬ra, &lindim, &one, &lindim, &alpha, matrix, &lindim, work, &lindim, &beta, work+lindim, &lindim); //Step 3: (1/eigs) V^T [vec(0), 1] --> work+lindim for (int cnt=0; cnt work dgemm_(¬ra, ¬ra, &lindim, &one, &lindim, &alpha, matrix, &lindim, work+lindim, &lindim, &beta, work, &lindim); //Fill newParam and make a copy in lastLinco for (int cnt=0; cnt older vectors) : "; for (int cnt=0; cnt=0 ); //Create just enough storage for the vectors to be loaded if (currentNumVecs < currentNumVecsBIS){ for (int cnt=currentNumVecs; cnt currentNumVecsBIS){ for (int cnt=currentNumVecs; cnt>currentNumVecsBIS; cnt--){ delete [] errorVectors[cnt-1]; delete [] paramVectors[cnt-1]; } currentNumVecs = currentNumVecsBIS; } for (int cnt=0; cnt #include #include #include #include #include #include #include #include #include "DMRG.h" #include "MPIchemps2.h" using std::cout; using std::endl; CheMPS2::DMRG::DMRG( Problem * ProbIn, ConvergenceScheme * OptSchemeIn, const bool makechkpt, const string tmpfolder, int * occupancies ){ #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ){ PrintLicense(); } #else PrintLicense(); #endif assert( ProbIn->checkConsistency() ); Prob = ProbIn; L = Prob->gL(); Prob->construct_mxelem(); OptScheme = OptSchemeIn; thePID = getpid(); //PID is unique for each MPI process nStates = 1; Ltensors = new TensorL ** [ L - 1 ]; F0tensors = new TensorF0 *** [ L - 1 ]; F1tensors = new TensorF1 *** [ L - 1 ]; S0tensors = new TensorS0 *** [ L - 1 ]; S1tensors = new TensorS1 *** [ L - 1 ]; Atensors = new TensorOperator *** [ L - 1 ]; Btensors = new TensorOperator *** [ L - 1 ]; Ctensors = new TensorOperator *** [ L - 1 ]; Dtensors = new TensorOperator *** [ L - 1 ]; Qtensors = new TensorQ ** [ L - 1 ]; Xtensors = new TensorX * [ L - 1 ]; isAllocated = new int[ L - 1 ]; // 0 not allocated; 1 moving right; 2 moving left tensor_3rdm_a_J0_doublet = NULL; tensor_3rdm_a_J1_doublet = NULL; tensor_3rdm_a_J1_quartet = NULL; tensor_3rdm_b_J0_doublet = NULL; tensor_3rdm_b_J1_doublet = NULL; tensor_3rdm_b_J1_quartet = NULL; tensor_3rdm_c_J0_doublet = NULL; tensor_3rdm_c_J1_doublet = NULL; tensor_3rdm_c_J1_quartet = NULL; tensor_3rdm_d_J0_doublet = NULL; tensor_3rdm_d_J1_doublet = NULL; tensor_3rdm_d_J1_quartet = NULL; Gtensors = NULL; Ytensors = NULL; Ztensors = NULL; Ktensors = NULL; Mtensors = NULL; for ( int cnt = 0; cnt < L - 1; cnt++ ){ isAllocated[ cnt ] = 0; } for ( int timecnt = 0; timecnt < CHEMPS2_TIME_VECLENGTH; timecnt++ ){ timings[ timecnt ] = 0.0; } num_double_write_disk = 0; num_double_read_disk = 0; the2DM = NULL; the3DM = NULL; theCorr = NULL; Exc_activated = false; makecheckpoints = makechkpt; tempfolder = tmpfolder; setupBookkeeperAndMPS( occupancies ); PreSolve(); } void CheMPS2::DMRG::setupBookkeeperAndMPS( int * occupancies ){ denBK = new SyBookkeeper( Prob, OptScheme->get_D( 0 ) ); assert( denBK->IsPossible() ); std::stringstream sstream; sstream << CheMPS2::DMRG_MPS_storage_prefix << nStates-1 << ".h5"; MPSstoragename.assign( sstream.str() ); struct stat stFileInfo; int intStat = stat( MPSstoragename.c_str(), &stFileInfo ); loadedMPS = (( makecheckpoints ) && ( intStat==0 )) ? true : false; #ifdef CHEMPS2_MPI_COMPILATION assert( MPIchemps2::all_booleans_equal( loadedMPS ) ); #endif if ( loadedMPS ){ loadDIM( MPSstoragename, denBK ); } // Convert occupancies from HAM to DMRG orbitals if (( occupancies != NULL ) && ( Prob->gReorder() )){ int * tmp_cpy_occ = new int[ L ]; for ( int cnt = 0; cnt < L; cnt++ ){ tmp_cpy_occ[ cnt ] = occupancies[ cnt ]; } for ( int cnt = 0; cnt < L; cnt++ ){ occupancies[ cnt ] = tmp_cpy_occ[ Prob->gf2( cnt ) ]; } delete [] tmp_cpy_occ; } // Set to ROHF dimensions /*if (( !loadedMPS ) && ( occupancies != NULL )){ int left_n = 0; int left_i = 0; int left_2s = 0; for ( int site = 0; site < denBK->gL(); site++ ){ for ( int N = denBK->gNmin( site ); N <= denBK->gNmax( site ); N++ ){ for ( int TwoS = denBK->gTwoSmin( site, N ); TwoS <= denBK->gTwoSmax( site, N ); TwoS+=2 ){ for ( int Irrep = 0; Irrep < denBK->getNumberOfIrreps(); Irrep++ ){ denBK->SetDim( site, N, TwoS, Irrep, 0 ); } } } denBK->SetDim( site, left_n, left_2s, left_i, 1 ); left_n = left_n + occupancies[ site ]; left_i = (( occupancies[ site ] == 1 ) ? Irreps::directProd( left_i, Prob->gIrrep( site ) ) : left_i ); left_2s = (( occupancies[ site ] == 1 ) ? ( left_2s + 1 ) : left_2s ); } assert( left_n == Prob->gN() ); assert( left_i == Prob->gIrrep() ); assert( left_2s == Prob->gTwoS() ); }*/ MPS = new TensorT * [ L ]; for ( int cnt = 0; cnt < L; cnt++ ){ MPS[ cnt ] = new TensorT( cnt, denBK ); } if ( loadedMPS ){ bool isConverged; loadMPS( MPSstoragename, MPS, &isConverged ); #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ) #endif { cout << "Loaded MPS " << MPSstoragename << " converged y/n? : " << isConverged << endl; } } else { #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif if ( occupancies == NULL ){ for ( int site = 0; site < L; site++ ){ if ( am_i_master ){ MPS[ site ]->random(); } left_normalize( MPS[ site ], NULL ); } } else { assert( Prob->check_rohf_occ( occupancies ) ); // Check compatibility int left_n = 0; int left_i = 0; int left_2s = 0; for ( int site = 0; site < L; site++ ){ const int right_n = left_n + occupancies[ site ]; const int right_i = (( occupancies[ site ] == 1 ) ? Irreps::directProd( left_i, Prob->gIrrep( site ) ) : left_i ); const int right_2s = (( occupancies[ site ] == 1 ) ? ( left_2s + 1 ) : left_2s ); const int dimL = denBK->gCurrentDim( site, left_n, left_2s, left_i ); const int dimR = denBK->gCurrentDim( site + 1, right_n, right_2s, right_i ); assert( dimL > 0 ); assert( dimR > 0 ); if ( am_i_master ){ MPS[ site ]->random(); for ( int NL = right_n - 2; NL <= right_n; NL++ ){ const int DS = (( right_n == NL + 1 ) ? 1 : 0 ); const int IL = (( right_n == NL + 1 ) ? Irreps::directProd( right_i, Prob->gIrrep( site ) ) : right_i ); for ( int TwoSL = right_2s - DS; TwoSL <= right_2s + DS; TwoSL+=2 ){ const int dimL2 = denBK->gCurrentDim( site, NL, TwoSL, IL ); if ( dimL2 > 0 ){ double * space = MPS[ site ]->gStorage( NL, TwoSL, IL, right_n, right_2s, right_i ); for ( int row = 0; row < dimL2; row++ ){ space[ row + dimL2 * 0 ] = 0.0; } if (( NL == left_n ) && ( TwoSL == left_2s ) && ( IL == left_i )){ space[ 0 + dimL * 0 ] = 42; } } } } } left_normalize( MPS[ site ], NULL ); left_n = right_n; left_i = right_i; left_2s = right_2s; } assert( left_n == Prob->gN() ); assert( left_i == Prob->gIrrep() ); assert( left_2s == Prob->gTwoS() ); } } } CheMPS2::DMRG::~DMRG(){ if ( the2DM != NULL ){ delete the2DM; } if ( the3DM != NULL ){ delete the3DM; } if ( theCorr != NULL ){ delete theCorr; } deleteAllBoundaryOperators(); delete [] Ltensors; delete [] F0tensors; delete [] F1tensors; delete [] S0tensors; delete [] S1tensors; delete [] Atensors; delete [] Btensors; delete [] Ctensors; delete [] Dtensors; delete [] Qtensors; delete [] Xtensors; delete [] isAllocated; for ( int site = 0; site < L; site++ ){ delete MPS[ site ]; } delete [] MPS; if ( Exc_activated ){ delete [] Exc_Eshifts; for ( int state = 0; state < nStates - 1; state++ ){ #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_specific_excitation( L, state ) == MPIchemps2::mpi_rank() ) #endif { for ( int orb = 0; orb < L; orb++ ){ delete Exc_MPSs[ state ][ orb ]; } delete [] Exc_MPSs[ state ]; delete Exc_BKs[ state ]; delete [] Exc_Overlaps[ state ]; // The rest is allocated and deleted at DMRGoperators.cpp } } delete [] Exc_MPSs; delete [] Exc_BKs; delete [] Exc_Overlaps; } delete denBK; } void CheMPS2::DMRG::PreSolve(){ deleteAllBoundaryOperators(); for ( int cnt = 0; cnt < L - 2; cnt++ ){ updateMovingRightSafeFirstTime( cnt ); } TotalMinEnergy = 1e8; MaxDiscWeightLastSweep = 0.0; } double CheMPS2::DMRG::Solve(){ bool change = ( TotalMinEnergy < 1e8 ) ? true : false; // 1 sweep from right to left: fixed virtual dimensions double Energy = 0.0; #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif for ( int instruction = 0; instruction < OptScheme->get_number(); instruction++ ){ int nIterations = 0; double EnergyPrevious = Energy + 10 * OptScheme->get_energy_conv( instruction ); // Guarantees that there's always at least 1 left-right sweep while (( fabs( Energy - EnergyPrevious ) > OptScheme->get_energy_conv( instruction ) ) && ( nIterations < OptScheme->get_max_sweeps( instruction ) )){ for ( int timecnt = 0; timecnt < CHEMPS2_TIME_VECLENGTH; timecnt++ ){ timings[ timecnt ] = 0.0; } num_double_write_disk = 0; num_double_read_disk = 0; struct timeval start, end; EnergyPrevious = Energy; gettimeofday( &start, NULL ); Energy = sweepleft( change, instruction, am_i_master ); // Only relevant call in this block of code gettimeofday( &end, NULL ); double elapsed = ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); if ( am_i_master ){ cout << "******************************************************************" << endl; cout << "*** Information on left sweep " << nIterations << " of instruction " << instruction << ":" << endl; cout << "*** Elapsed wall time = " << elapsed << " seconds" << endl; cout << "*** |--> S.join = " << timings[ CHEMPS2_TIME_S_JOIN ] << " seconds" << endl; cout << "*** |--> S.solve = " << timings[ CHEMPS2_TIME_S_SOLVE ] << " seconds" << endl; cout << "*** |--> S.split = " << timings[ CHEMPS2_TIME_S_SPLIT ] << " seconds" << endl; print_tensor_update_performance(); cout << "*** Minimum energy = " << LastMinEnergy << endl; cout << "*** Maximum discarded weight = " << MaxDiscWeightLastSweep << endl; } if ( Exc_activated ){ calc_overlaps( false ); } if ( am_i_master ){ cout << "******************************************************************" << endl; } change = true; //rest of sweeps: variable virtual dimensions for ( int timecnt = 0; timecnt < CHEMPS2_TIME_VECLENGTH; timecnt++ ){ timings[ timecnt ] = 0.0; } num_double_write_disk = 0; num_double_read_disk = 0; gettimeofday( &start, NULL ); Energy = sweepright( change, instruction, am_i_master ); // Only relevant call in this block of code gettimeofday( &end, NULL ); elapsed = ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); if ( am_i_master ){ cout << "******************************************************************" << endl; cout << "*** Information on right sweep " << nIterations << " of instruction " << instruction << ":" << endl; cout << "*** Elapsed wall time = " << elapsed << " seconds" << endl; cout << "*** |--> S.join = " << timings[ CHEMPS2_TIME_S_JOIN ] << " seconds" << endl; cout << "*** |--> S.solve = " << timings[ CHEMPS2_TIME_S_SOLVE ] << " seconds" << endl; cout << "*** |--> S.split = " << timings[ CHEMPS2_TIME_S_SPLIT ] << " seconds" << endl; print_tensor_update_performance(); cout << "*** Minimum energy = " << LastMinEnergy << endl; cout << "*** Maximum discarded weight = " << MaxDiscWeightLastSweep << endl; cout << "*** Energy difference with respect to previous leftright sweep = " << fabs(Energy-EnergyPrevious) << endl; } if ( Exc_activated ){ calc_overlaps( true ); } if ( am_i_master ){ cout << "******************************************************************" << endl; if ( makecheckpoints ){ saveMPS( MPSstoragename, MPS, denBK, false ); } // Only the master proc makes MPS checkpoints !! } nIterations++; } if ( am_i_master ){ cout << "*** Information on completed instruction " << instruction << ":" << endl; cout << "*** The reduced virtual dimension DSU(2) = " << OptScheme->get_D(instruction) << endl; cout << "*** The total number of reduced MPS variables = " << get_num_mps_var() << endl; cout << "*** Minimum energy encountered during all instructions = " << TotalMinEnergy << endl; cout << "*** Minimum energy encountered during the last sweep = " << LastMinEnergy << endl; cout << "*** Maximum discarded weight during the last sweep = " << MaxDiscWeightLastSweep << endl; cout << "******************************************************************" << endl; } } return TotalMinEnergy; } double CheMPS2::DMRG::sweepleft( const bool change, const int instruction, const bool am_i_master ){ double Energy = 0.0; const double noise_level = fabs( OptScheme->get_noise_prefactor( instruction ) ) * MaxDiscWeightLastSweep; const double dvdson_rtol = OptScheme->get_dvdson_rtol( instruction ); const int vir_dimension = OptScheme->get_D( instruction ); MaxDiscWeightLastSweep = 0.0; LastMinEnergy = 1e8; for ( int index = L - 2; index > 0; index-- ){ Energy = solve_site( index, dvdson_rtol, noise_level, vir_dimension, am_i_master, false, change ); if ( Energy < TotalMinEnergy ){ TotalMinEnergy = Energy; } if ( Energy < LastMinEnergy ){ LastMinEnergy = Energy; } if ( am_i_master ){ cout << "Energy at sites (" << index << ", " << index + 1 << ") is " << Energy << endl; } // Prepare for next step struct timeval start, end; gettimeofday( &start, NULL ); updateMovingLeftSafe( index ); gettimeofday( &end, NULL ); timings[ CHEMPS2_TIME_TENS_TOTAL ] += ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); } return Energy; } double CheMPS2::DMRG::sweepright( const bool change, const int instruction, const bool am_i_master ){ double Energy = 0.0; const double noise_level = fabs( OptScheme->get_noise_prefactor( instruction ) ) * MaxDiscWeightLastSweep; const double dvdson_rtol = OptScheme->get_dvdson_rtol( instruction ); const int vir_dimension = OptScheme->get_D( instruction ); MaxDiscWeightLastSweep = 0.0; LastMinEnergy = 1e8; for ( int index = 0; index < L - 2; index++ ){ Energy = solve_site( index, dvdson_rtol, noise_level, vir_dimension, am_i_master, true, change ); if ( Energy < TotalMinEnergy ){ TotalMinEnergy = Energy; } if ( Energy < LastMinEnergy ){ LastMinEnergy = Energy; } if ( am_i_master ){ cout << "Energy at sites (" << index << ", " << index + 1 << ") is " << Energy << endl; } // Prepare for next step struct timeval start, end; gettimeofday( &start, NULL ); updateMovingRightSafe( index ); gettimeofday( &end, NULL ); timings[ CHEMPS2_TIME_TENS_TOTAL ] += ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); } return Energy; } double CheMPS2::DMRG::solve_site( const int index, const double dvdson_rtol, const double noise_level, const int virtual_dimension, const bool am_i_master, const bool moving_right, const bool change ){ struct timeval start, end; // Construct two-site object S. Each MPI process joins the MPS tensors. Before a matrix-vector multiplication the vector is broadcasted anyway. gettimeofday( &start, NULL ); Sobject * denS = new Sobject( index, denBK ); denS->Join( MPS[ index ], MPS[ index + 1 ] ); gettimeofday( &end, NULL ); timings[ CHEMPS2_TIME_S_JOIN ] += ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); // Feed everything to the solver. Each MPI process returns the correct energy. Only MPI_CHEMPS2_MASTER has the correct denS solution. gettimeofday( &start, NULL ); Heff Solver( denBK, Prob, dvdson_rtol ); double ** VeffTilde = NULL; if ( Exc_activated ){ VeffTilde = prepare_excitations( denS ); } double Energy = Solver.SolveDAVIDSON( denS, Ltensors, Atensors, Btensors, Ctensors, Dtensors, S0tensors, S1tensors, F0tensors, F1tensors, Qtensors, Xtensors, nStates - 1, VeffTilde ); Energy += Prob->gEconst(); if ( Exc_activated ){ cleanup_excitations( VeffTilde ); } gettimeofday( &end, NULL ); timings[ CHEMPS2_TIME_S_SOLVE ] += ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); // Decompose the S-object. MPI_CHEMPS2_MASTER decomposes denS. Each MPI process returns the correct discWeight. Each MPI process has the new MPS tensors set. gettimeofday( &start, NULL ); if (( noise_level > 0.0 ) && ( am_i_master )){ denS->addNoise( noise_level ); } const double discWeight = denS->Split( MPS[ index ], MPS[ index + 1 ], virtual_dimension, moving_right, change ); delete denS; if ( discWeight > MaxDiscWeightLastSweep ){ MaxDiscWeightLastSweep = discWeight; } gettimeofday( &end, NULL ); timings[ CHEMPS2_TIME_S_SPLIT ] += ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); return Energy; } int CheMPS2::DMRG::get_num_mps_var() const{ int num_var = 0; for ( int site = 0; site < L; site++ ){ num_var += MPS[ site ]->gKappa2index( MPS[ site ]->gNKappa() ); } return num_var; } void CheMPS2::DMRG::activateExcitations( const int maxExcIn ){ Exc_activated = true; maxExc = maxExcIn; Exc_Eshifts = new double[ maxExc ]; Exc_MPSs = new TensorT ** [ maxExc ]; Exc_BKs = new SyBookkeeper * [ maxExc ]; Exc_Overlaps = new TensorO ** [ maxExc ]; } void CheMPS2::DMRG::newExcitation( const double EshiftIn ){ assert( Exc_activated ); assert( nStates - 1 < maxExc ); if ( the2DM != NULL ){ delete the2DM; the2DM = NULL; } if ( the3DM != NULL ){ delete the3DM; the3DM = NULL; } if ( theCorr != NULL ){ delete theCorr; theCorr = NULL; } deleteAllBoundaryOperators(); Exc_Eshifts[ nStates - 1 ] = EshiftIn; #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_specific_excitation( L, nStates - 1 ) == MPIchemps2::mpi_rank() ){ #endif Exc_MPSs[ nStates - 1 ] = MPS; Exc_BKs[ nStates - 1 ] = denBK; Exc_Overlaps[ nStates - 1 ] = new TensorO*[ L - 1 ]; #ifdef CHEMPS2_MPI_COMPILATION } else { for ( int site = 0; site < L; site++ ){ delete MPS[ site ]; } delete [] MPS; delete denBK; } #endif nStates++; setupBookkeeperAndMPS(); PreSolve(); } CheMPS2-1.8.9/CheMPS2/DMRGSCFindices.cpp000066400000000000000000000121301336564451100171700ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include "DMRGSCFindices.h" using std::cout; using std::endl; using std::max; CheMPS2::DMRGSCFindices::DMRGSCFindices(const int L, const int Group, int * NOCCin, int * NDMRGin, int * NVIRTin){ this->L = L; SymmInfo.setGroup(Group); this->Nirreps = SymmInfo.getNumberOfIrreps(); NORB = new int[Nirreps]; NOCC = new int[Nirreps]; NDMRG = new int[Nirreps]; NVIRT = new int[Nirreps]; NORBcumulative = new int[Nirreps+1]; NDMRGcumulative = new int[Nirreps+1]; int totalNumOrbs = 0; NORBcumulative[0] = 0; NDMRGcumulative[0] = 0; for (int irrep=0; irrep=0 ); assert( NDMRGin[irrep]>=0 ); assert( NVIRTin[irrep]>=0 ); NORB[ irrep] = NOCCin[ irrep] + NDMRGin[irrep] + NVIRTin[irrep]; NOCC[ irrep] = NOCCin[ irrep]; NDMRG[irrep] = NDMRGin[irrep]; NVIRT[irrep] = NVIRTin[irrep]; totalNumOrbs += NORB[irrep]; NORBcumulative[ irrep+1] = NORBcumulative[ irrep] + NORB[irrep]; NDMRGcumulative[irrep+1] = NDMRGcumulative[irrep] + NDMRG[irrep]; } assert( totalNumOrbs==L ); irrepOfEachDMRGorbital = new int[NDMRGcumulative[Nirreps]]; irrepOfEachOrbital = new int[L]; for (int irrep=0; irrep #include "DMRGSCFintegrals.h" CheMPS2::DMRGSCFintegrals::DMRGSCFintegrals(DMRGSCFindices * iHandler){ numberOfIrreps = iHandler->getNirreps(); NCORE = new int[ numberOfIrreps ]; NVIRTUAL = new int[ numberOfIrreps ]; NTOTAL = new int[ numberOfIrreps ]; for (int irrep = 0; irrep < numberOfIrreps; irrep++){ NCORE[ irrep ] = iHandler->getNOCC( irrep ) + iHandler->getNDMRG( irrep ); NVIRTUAL[ irrep ] = iHandler->getNVIRT( irrep ); NTOTAL[ irrep ] = iHandler->getNORB( irrep ); } coulomb_size = calcNumCoulombElements( true ); exchange_size = calcNumExchangeElements( true ); coulomb_array = new double[ coulomb_size ]; exchange_array = new double[ exchange_size ]; } long long CheMPS2::DMRGSCFintegrals::calcNumCoulombElements(const bool allocate){ // The object sizes long long theSize = 0; if (allocate){ coulomb_ptr = new long long***[ numberOfIrreps ]; } for (int I_cc = 0; I_cc < numberOfIrreps; I_cc++){ // Loop the irrep I_cc = I_c1 x I_c2 = I_a1 x I_a2 if (allocate){ coulomb_ptr[ I_cc ] = new long long**[ numberOfIrreps ]; } for (int I_c1 = 0; I_c1 < numberOfIrreps; I_c1++){ const int I_c2 = Irreps::directProd( I_cc , I_c1 ); if ( ( NCORE[ I_c1 ] > 0 ) && ( NCORE[ I_c2 ] > 0 ) && ( I_c1 <= I_c2 ) ){ if (allocate){ coulomb_ptr[ I_cc ][ I_c1 ] = new long long*[ numberOfIrreps ]; } for (int I_a1 = 0; I_a1 < numberOfIrreps; I_a1++){ const int I_a2 = Irreps::directProd( I_cc, I_a1 ); if ( ( NTOTAL[ I_a1 ] > 0 ) && ( NTOTAL[ I_a2 ] > 0 ) && ( I_a1 <= I_a2 ) ){ if ( I_cc == 0 ){ // I_c1 == I_c2 and I_a1 == I_a2 if (allocate){ const long long coretriangle = ( NCORE[ I_c1 ] * ( NCORE[ I_c1 ] + 1 ) ) / 2; const long long alltriangle = ( NTOTAL[ I_a1 ] * ( NTOTAL[ I_a1 ] + 1 ) ) / 2; coulomb_ptr[ I_cc ][ I_c1 ][ I_a1 ] = new long long[ coretriangle ]; for (int combinedcore = 0; combinedcore < coretriangle; combinedcore++){ coulomb_ptr[ I_cc ][ I_c1 ][ I_a1 ][ combinedcore ] = theSize; theSize += alltriangle; } } else { delete [] coulomb_ptr[ I_cc ][ I_c1 ][ I_a1 ]; } } else { // I_c1 < I_c2 and I_a1 < I_a2 if (allocate){ const long long coresquare = NCORE[ I_c1 ] * NCORE[ I_c2 ]; const long long allsquare = NTOTAL[ I_a1 ] * NTOTAL[ I_a2 ]; coulomb_ptr[ I_cc ][ I_c1 ][ I_a1 ] = new long long[ coresquare ]; for (int combinedcore = 0; combinedcore < coresquare; combinedcore++){ coulomb_ptr[ I_cc ][ I_c1 ][ I_a1 ][ combinedcore ] = theSize; theSize += allsquare; } } else { delete [] coulomb_ptr[ I_cc ][ I_c1 ][ I_a1 ]; } } } } if (!allocate){ delete [] coulomb_ptr[ I_cc ][ I_c1 ]; } } } if (!allocate){ delete [] coulomb_ptr[ I_cc ]; } } if (!allocate){ delete [] coulomb_ptr; } return theSize; } long long CheMPS2::DMRGSCFintegrals::calcNumExchangeElements(const bool allocate){ // The object sizes long long theSize = 0; if (allocate){ exchange_ptr = new long long***[ numberOfIrreps ]; } for (int I_cc = 0; I_cc < numberOfIrreps; I_cc++){ // Loop the irrep I_cc = I_c1 x I_c2 = I_v1 x I_v2 if (allocate){ exchange_ptr[ I_cc ] = new long long**[ numberOfIrreps ]; } for (int I_c1 = 0; I_c1 < numberOfIrreps; I_c1++){ const int I_c2 = Irreps::directProd( I_cc , I_c1 ); if ( ( NCORE[ I_c1 ] > 0 ) && ( NCORE[ I_c2 ] > 0 ) && ( I_c1 <= I_c2 ) ){ if (allocate){ exchange_ptr[ I_cc ][ I_c1 ] = new long long*[ numberOfIrreps ]; } for (int I_v1 = 0; I_v1 < numberOfIrreps; I_v1++){ const int I_v2 = Irreps::directProd( I_cc, I_v1 ); if ( ( NTOTAL[ I_v1 ] > 0 ) && ( NTOTAL[ I_v2 ] > 0 ) ){ // Here no I_v1 <= I_v2 !! const long long virtualsquare = NVIRTUAL[ I_v1 ] * NVIRTUAL[ I_v2 ]; if ( I_cc == 0 ){ // I_c1 == I_c2 and I_v1 == I_v2 if (allocate){ const long long coretriangle = ( NCORE[ I_c1 ] * ( NCORE[ I_c1 ] + 1 ) ) / 2; exchange_ptr[ I_cc ][ I_c1 ][ I_v1 ] = new long long[ coretriangle ]; for (int combinedcore = 0; combinedcore < coretriangle; combinedcore++){ exchange_ptr[ I_cc ][ I_c1 ][ I_v1 ][ combinedcore ] = theSize; theSize += virtualsquare; } } else { delete [] exchange_ptr[ I_cc ][ I_c1 ][ I_v1 ]; } } else { // I_c1 < I_c2 and I_v1 != I_v2 if (allocate){ const long long coresquare = NCORE[ I_c1 ] * NCORE[ I_c2 ]; exchange_ptr[ I_cc ][ I_c1 ][ I_v1 ] = new long long[ coresquare ]; for (int combinedcore = 0; combinedcore < coresquare; combinedcore++){ exchange_ptr[ I_cc ][ I_c1 ][ I_v1 ][ combinedcore ] = theSize; theSize += virtualsquare; } } else { delete [] exchange_ptr[ I_cc ][ I_c1 ][ I_v1 ]; } } } } if (!allocate){ delete [] exchange_ptr[ I_cc ][ I_c1 ]; } } } if (!allocate){ delete [] exchange_ptr[ I_cc ]; } } if (!allocate){ delete [] exchange_ptr; } return theSize; } CheMPS2::DMRGSCFintegrals::~DMRGSCFintegrals(){ delete [] coulomb_array; delete [] exchange_array; calcNumCoulombElements( false ); calcNumExchangeElements( false ); delete [] NCORE; delete [] NVIRTUAL; delete [] NTOTAL; } void CheMPS2::DMRGSCFintegrals::clear(){ for (long long counter = 0; counter < coulomb_size; counter++){ coulomb_array[ counter ] = 0.0; } for (long long counter = 0; counter < exchange_size; counter++){ exchange_array[ counter ] = 0.0; } } long long CheMPS2::DMRGSCFintegrals::get_coulomb_ptr( const int Ic1, const int Ic2, const int Ia1, const int Ia2, const int c1, const int c2, const int a1, const int a2 ) const{ const int Icc = Irreps::directProd( Ic1, Ic2 ); assert( Icc == Irreps::directProd( Ia1, Ia2 ) ); if ( Icc == 0 ){ // Ic1 == Ic2 and Ia1 == Ia2 const int index_c = ( c1 <= c2 ) ? c1 + (c2 * ( c2 + 1 ))/2 : c2 + (c1 * ( c1 + 1 ))/2 ; const int index_a = ( a1 <= a2 ) ? a1 + (a2 * ( a2 + 1 ))/2 : a2 + (a1 * ( a1 + 1 ))/2 ; return coulomb_ptr[ Icc ][ Ic1 ][ Ia1 ][ index_c ] + index_a ; } // Ic1 != Ic2 and Ia1 != Ia2 const int irrep_c = ( Ic1 < Ic2 ) ? Ic1 : Ic2 ; const int irrep_a = ( Ia1 < Ia2 ) ? Ia1 : Ia2 ; const int index_c = ( Ic1 < Ic2 ) ? c1 + NCORE[ Ic1 ] * c2 : c2 + NCORE[ Ic2 ] * c1 ; const int index_a = ( Ia1 < Ia2 ) ? a1 + NTOTAL[ Ia1 ] * a2 : a2 + NTOTAL[ Ia2 ] * a1 ; return coulomb_ptr[ Icc ][ irrep_c ][ irrep_a ][ index_c ] + index_a ; } void CheMPS2::DMRGSCFintegrals::set_coulomb(const int Ic1, const int Ic2, const int Ia1, const int Ia2, const int c1, const int c2, const int a1, const int a2, const double val){ coulomb_array[ get_coulomb_ptr( Ic1, Ic2, Ia1, Ia2, c1, c2, a1, a2 ) ] = val; } void CheMPS2::DMRGSCFintegrals::add_coulomb(const int Ic1, const int Ic2, const int Ia1, const int Ia2, const int c1, const int c2, const int a1, const int a2, const double val){ coulomb_array[ get_coulomb_ptr( Ic1, Ic2, Ia1, Ia2, c1, c2, a1, a2 ) ] += val; } double CheMPS2::DMRGSCFintegrals::get_coulomb(const int Ic1, const int Ic2, const int Ia1, const int Ia2, const int c1, const int c2, const int a1, const int a2) const{ return coulomb_array[ get_coulomb_ptr( Ic1, Ic2, Ia1, Ia2, c1, c2, a1, a2 ) ]; } long long CheMPS2::DMRGSCFintegrals::get_exchange_ptr( const int Ic1, const int Ic2, const int Iv1, const int Iv2, const int c1, const int c2, const int v1, const int v2 ) const{ const int Icc = Irreps::directProd( Ic1, Ic2 ); assert( Icc == Irreps::directProd( Iv1, Iv2 ) ); if ( Icc == 0 ){ // Ic1 == Ic2 and Iv1 == Iv2 if ( c1 <= c2 ){ return exchange_ptr[ Icc ][ Ic1 ][ Iv1 ][ c1 + (c2 * ( c2 + 1 ))/2 ] + v1 - NCORE[ Iv1 ] + NVIRTUAL[ Iv1 ] * ( v2 - NCORE[ Iv2 ] ) ; } else { return exchange_ptr[ Icc ][ Ic2 ][ Iv2 ][ c2 + (c1 * ( c1 + 1 ))/2 ] + v2 - NCORE[ Iv2 ] + NVIRTUAL[ Iv2 ] * ( v1 - NCORE[ Iv1 ] ) ; } } else { // Ic1 != Ic2 if ( Ic1 < Ic2 ){ return exchange_ptr[ Icc ][ Ic1 ][ Iv1 ][ c1 + NCORE[ Ic1 ] * c2 ] + v1 - NCORE[ Iv1 ] + NVIRTUAL[ Iv1 ] * ( v2 - NCORE[ Iv2 ] ) ; } else { return exchange_ptr[ Icc ][ Ic2 ][ Iv2 ][ c2 + NCORE[ Ic2 ] * c1 ] + v2 - NCORE[ Iv2 ] + NVIRTUAL[ Iv2 ] * ( v1 - NCORE[ Iv1 ] ) ; } } return -1; } void CheMPS2::DMRGSCFintegrals::set_exchange(const int Ic1, const int Ic2, const int Iv1, const int Iv2, const int c1, const int c2, const int v1, const int v2, const double val){ exchange_array[ get_exchange_ptr( Ic1, Ic2, Iv1, Iv2, c1, c2, v1, v2 ) ] = val; } void CheMPS2::DMRGSCFintegrals::add_exchange(const int Ic1, const int Ic2, const int Iv1, const int Iv2, const int c1, const int c2, const int v1, const int v2, const double val){ exchange_array[ get_exchange_ptr( Ic1, Ic2, Iv1, Iv2, c1, c2, v1, v2 ) ] += val; } double CheMPS2::DMRGSCFintegrals::get_exchange(const int Ic1, const int Ic2, const int Iv1, const int Iv2, const int c1, const int c2, const int v1, const int v2) const{ return exchange_array[ get_exchange_ptr( Ic1, Ic2, Iv1, Iv2, c1, c2, v1, v2 ) ]; } double CheMPS2::DMRGSCFintegrals::FourIndexAPI(const int I1, const int I2, const int I3, const int I4, const int index1, const int index2, const int index3, const int index4) const{ assert( Irreps::directProd( I1, I2 ) == Irreps::directProd( I3, I4 ) ); const bool core1 = ( index1 < NCORE[I1] ) ? true : false; const bool core2 = ( index2 < NCORE[I2] ) ? true : false; const bool core3 = ( index3 < NCORE[I3] ) ? true : false; const bool core4 = ( index4 < NCORE[I4] ) ? true : false; const int numCore = ( ( core1 ) ? 1 : 0 ) + ( ( core2 ) ? 1 : 0 ) + ( ( core3 ) ? 1 : 0 ) + ( ( core4 ) ? 1 : 0 ); assert( numCore >= 2 ); if ( numCore == 4 ){ return get_coulomb(I1, I3, I2, I4, index1, index3, index2, index4); } if ( numCore == 3 ){ if (( !core1 ) || ( !core3 )){ return get_coulomb(I2, I4, I1, I3, index2, index4, index1, index3); } if (( !core2 ) || ( !core4 )){ return get_coulomb(I1, I3, I2, I4, index1, index3, index2, index4); } } if ( numCore == 2 ){ if ( !core1 ){ if ( !core2 ){ return get_exchange(I3, I4, I1, I2, index3, index4, index1, index2); } if ( !core3 ){ return get_coulomb( I2, I4, I1, I3, index2, index4, index1, index3); } if ( !core4 ){ return get_exchange(I3, I2, I1, I4, index3, index2, index1, index4); } } if ( !core2 ){ if ( !core3 ){ return get_exchange(I4, I1, I2, I3, index4, index1, index2, index3); } if ( !core4 ){ return get_coulomb( I1, I3, I2, I4, index1, index3, index2, index4); } } return get_exchange(I1, I2, I3, I4, index1, index2, index3, index4); } assert( 0 == 1 ); return 0.0; } CheMPS2-1.8.9/CheMPS2/DMRGSCFmatrix.cpp000066400000000000000000000116401336564451100170630ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include "MyHDF5.h" #include "DMRGSCFmatrix.h" #include "MPIchemps2.h" using std::string; CheMPS2::DMRGSCFmatrix::DMRGSCFmatrix( const DMRGSCFindices * iHandler ){ this->iHandler = iHandler; this->num_irreps = iHandler->getNirreps(); entries = new double*[ num_irreps ]; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int NORB = iHandler->getNORB( irrep ); entries[ irrep ] = new double[ NORB * NORB ]; } } CheMPS2::DMRGSCFmatrix::~DMRGSCFmatrix(){ for ( int irrep = 0; irrep < num_irreps; irrep++ ){ delete [] entries[ irrep ]; } delete [] entries; } void CheMPS2::DMRGSCFmatrix::set( const int irrep, const int p, const int q, const double val ){ entries[ irrep ][ p + iHandler->getNORB( irrep ) * q ] = val; } void CheMPS2::DMRGSCFmatrix::clear(){ for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int size = iHandler->getNORB( irrep ) * iHandler->getNORB( irrep ); for ( int counter = 0; counter < size; counter++ ){ entries[ irrep ][ counter ] = 0.0; } } } void CheMPS2::DMRGSCFmatrix::identity(){ clear(); for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int NORB = iHandler->getNORB( irrep ); for ( int diag = 0; diag < NORB; diag++ ){ entries[ irrep ][ ( NORB + 1 ) * diag ] = 1.0; } } } double CheMPS2::DMRGSCFmatrix::get( const int irrep, const int p, const int q ) const{ return entries[ irrep ][ p + iHandler->getNORB( irrep ) * q ]; } double * CheMPS2::DMRGSCFmatrix::getBlock( const int irrep ){ return entries[ irrep ]; } double CheMPS2::DMRGSCFmatrix::rms_deviation( const DMRGSCFmatrix * other ) const{ // Should in principle check whether iHandler matches double rms_diff = 0.0; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int NORB = iHandler->getNORB( irrep ); for ( int row = 0; row < NORB; row++ ){ for ( int col = 0; col < NORB; col++ ){ const double diff = this->get( irrep, row, col ) - other->get( irrep, row, col ); rms_diff += diff * diff; } } } rms_diff = sqrt( rms_diff ); return rms_diff; } void CheMPS2::DMRGSCFmatrix::write( const string filename, const DMRGSCFindices * idx, double ** storage ){ hid_t file_id = H5Fcreate( filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT ); hid_t group_id = H5Gcreate( file_id, "/Data", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT ); for ( int irrep = 0; irrep < idx->getNirreps(); irrep++ ){ std::stringstream irrepname; irrepname << "irrep_" << irrep; hsize_t dimarray = idx->getNORB( irrep ) * idx->getNORB( irrep ); hid_t dataspace_id = H5Screate_simple( 1, &dimarray, NULL ); hid_t dataset_id = H5Dcreate( group_id, irrepname.str().c_str(), H5T_IEEE_F64LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT ); H5Dwrite( dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, storage[ irrep ] ); H5Dclose( dataset_id ); H5Sclose( dataspace_id ); } H5Gclose( group_id ); H5Fclose( file_id ); } void CheMPS2::DMRGSCFmatrix::read( const string filename, const int n_irreps, double ** storage ){ hid_t file_id = H5Fopen( filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT ); hid_t group_id = H5Gopen( file_id, "/Data", H5P_DEFAULT ); for ( int irrep = 0; irrep < n_irreps; irrep++ ){ std::stringstream irrepname; irrepname << "irrep_" << irrep; hid_t dataset_id = H5Dopen( group_id, irrepname.str().c_str(), H5P_DEFAULT ); H5Dread( dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, storage[ irrep ] ); H5Dclose( dataset_id ); } H5Gclose( group_id ); H5Fclose( file_id ); } #ifdef CHEMPS2_MPI_COMPILATION void CheMPS2::DMRGSCFmatrix::broadcast( const int ROOT ){ for ( int irrep = 0; irrep < num_irreps; irrep++ ){ const int NORB = iHandler->getNORB( irrep ); const int size = NORB * NORB; if ( size > 0 ){ MPIchemps2::broadcast_array_double( entries[ irrep ], size, ROOT ); } } } #endif CheMPS2-1.8.9/CheMPS2/DMRGSCFoptions.cpp000066400000000000000000000111101336564451100172420ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "DMRGSCFoptions.h" CheMPS2::DMRGSCFoptions::DMRGSCFoptions(){ DoDIIS = CheMPS2::DMRGSCF_doDIIS; DIISGradientBranch = CheMPS2::DMRGSCF_DIISgradientBranch; NumDIISVecs = CheMPS2::DMRGSCF_numDIISvecs; StoreDIIS = CheMPS2::DMRGSCF_storeDIIS; DIISStorageName = CheMPS2::DMRGSCF_diis_storage_name; MaxIterations = CheMPS2::DMRGSCF_maxIterations; GradientThreshold = CheMPS2::DMRGSCF_gradientNormThreshold; StoreUnitary = CheMPS2::DMRGSCF_storeUnitary; UnitaryStorageName = CheMPS2::DMRGSCF_unitary_storage_name; StateAveraging = CheMPS2::DMRGSCF_stateAveraged; WhichActiveSpace = CheMPS2::DMRGSCF_whichActiveSpace; DumpCorrelations = CheMPS2::DMRGSCF_dumpCorrelations; StartLocRandom = CheMPS2::DMRGSCF_startLocRandom; } CheMPS2::DMRGSCFoptions::~DMRGSCFoptions(){ } bool CheMPS2::DMRGSCFoptions::getDoDIIS() const{ return DoDIIS; } double CheMPS2::DMRGSCFoptions::getDIISGradientBranch() const{ return DIISGradientBranch; } int CheMPS2::DMRGSCFoptions::getNumDIISVecs() const{ return NumDIISVecs; } bool CheMPS2::DMRGSCFoptions::getStoreDIIS() const{ return StoreDIIS; } string CheMPS2::DMRGSCFoptions::getDIISStorageName() const{ return DIISStorageName; } int CheMPS2::DMRGSCFoptions::getMaxIterations() const{ return MaxIterations; } double CheMPS2::DMRGSCFoptions::getGradientThreshold() const{ return GradientThreshold; } bool CheMPS2::DMRGSCFoptions::getStoreUnitary() const{ return StoreUnitary; } string CheMPS2::DMRGSCFoptions::getUnitaryStorageName() const{ return UnitaryStorageName; } bool CheMPS2::DMRGSCFoptions::getStateAveraging() const{ return StateAveraging; } int CheMPS2::DMRGSCFoptions::getWhichActiveSpace() const{ return WhichActiveSpace; } bool CheMPS2::DMRGSCFoptions::getDumpCorrelations() const{ return DumpCorrelations; } bool CheMPS2::DMRGSCFoptions::getStartLocRandom() const{ return StartLocRandom; } void CheMPS2::DMRGSCFoptions::setDoDIIS(const bool DoDIIS_in){ DoDIIS = DoDIIS_in; } void CheMPS2::DMRGSCFoptions::setDIISGradientBranch(const double DIISGradientBranch_in){ DIISGradientBranch = DIISGradientBranch_in; } void CheMPS2::DMRGSCFoptions::setNumDIISVecs(const int NumDIISVecs_in){ NumDIISVecs = NumDIISVecs_in; } void CheMPS2::DMRGSCFoptions::setStoreDIIS(const bool StoreDIIS_in){ StoreDIIS = StoreDIIS_in; } void CheMPS2::DMRGSCFoptions::setDIISStorageName(const string DIISStorageName_in){ DIISStorageName = DIISStorageName_in; } void CheMPS2::DMRGSCFoptions::setMaxIterations(const int MaxIterations_in){ MaxIterations = MaxIterations_in; } void CheMPS2::DMRGSCFoptions::setGradientThreshold(const double GradientThreshold_in){ GradientThreshold = GradientThreshold_in; } void CheMPS2::DMRGSCFoptions::setStoreUnitary(const bool StoreUnitary_in){ StoreUnitary = StoreUnitary_in; } void CheMPS2::DMRGSCFoptions::setUnitaryStorageName(const string UnitaryStorageName_in){ UnitaryStorageName = UnitaryStorageName_in; } void CheMPS2::DMRGSCFoptions::setStateAveraging(const bool StateAveraging_in){ StateAveraging = StateAveraging_in; } void CheMPS2::DMRGSCFoptions::setWhichActiveSpace(const int WhichActiveSpace_in){ WhichActiveSpace = WhichActiveSpace_in; } void CheMPS2::DMRGSCFoptions::setDumpCorrelations(const bool DumpCorrelations_in){ DumpCorrelations = DumpCorrelations_in; } void CheMPS2::DMRGSCFoptions::setStartLocRandom(const bool StartLocRandom_in){ StartLocRandom = StartLocRandom_in; } CheMPS2-1.8.9/CheMPS2/DMRGSCFrotations.cpp000066400000000000000000000514511336564451100176050ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include "DMRGSCFrotations.h" #include "Lapack.h" using std::min; using std::max; using std::string; void CheMPS2::DMRGSCFrotations::fetch( double * eri, const FourIndex * ORIG_VMAT, const int irrep1, const int irrep2, const int irrep3, const int irrep4, DMRGSCFindices * idx, const int start, const int stop, const bool pack ){ if ( pack ){ assert( irrep1 == irrep2 ); assert( irrep3 == irrep4 ); const int NORB12 = idx->getNORB( irrep1 ); const int NORB34 = idx->getNORB( irrep3 ); int counter = 0; // counter = cnt3 + ( cnt4 * ( cnt4 + 1 )) / 2 for ( int cnt4 = 0; cnt4 < NORB34; cnt4++ ){ for ( int cnt3 = 0; cnt3 <= cnt4; cnt3++ ){ if (( start <= counter ) && ( counter < stop )){ for ( int cnt2 = 0; cnt2 < NORB12; cnt2++ ){ for ( int cnt1 = 0; cnt1 < NORB12; cnt1++ ){ eri[ cnt1 + NORB12 * ( cnt2 + NORB12 * ( counter - start ) ) ] = ORIG_VMAT->get( irrep1, irrep3, irrep2, irrep4, cnt1, cnt3, cnt2, cnt4 ); // Indices (12) and indices (34) are Coulomb pairs } } } counter++; } } } else { assert( Irreps::directProd( irrep1, irrep2 ) == Irreps::directProd( irrep3, irrep4 ) ); const int NORB1 = idx->getNORB( irrep1 ); const int NORB2 = idx->getNORB( irrep2 ); const int NORB3 = idx->getNORB( irrep3 ); const int NORB4 = idx->getNORB( irrep4 ); int counter = 0; // counter = cnt3 + NORB3 * cnt4 for ( int cnt4 = 0; cnt4 < NORB4; cnt4++ ){ for ( int cnt3 = 0; cnt3 < NORB3; cnt3++ ){ if (( start <= counter ) && ( counter < stop )){ for ( int cnt2 = 0; cnt2 < NORB2; cnt2++ ){ for ( int cnt1 = 0; cnt1 < NORB1; cnt1++ ){ eri[ cnt1 + NORB1 * ( cnt2 + NORB2 * ( counter - start ) ) ] = ORIG_VMAT->get( irrep1, irrep3, irrep2, irrep4, cnt1, cnt3, cnt2, cnt4 ); // Indices (12) and indices (34) are Coulomb pairs } } } counter++; } } } } void CheMPS2::DMRGSCFrotations::write( double * eri, FourIndex * NEW_VMAT, DMRGSCFintegrals * ROT_TEI, const char space1, const char space2, const char space3, const char space4, const int irrep1, const int irrep2, const int irrep3, const int irrep4, DMRGSCFindices * idx, const int start, const int stop, const bool pack ){ bool written = false; if (( space1 == space2 ) && ( space1 == space3 ) && ( space1 == space4 )){ // All four spaces equal if ( pack ){ assert( irrep1 == irrep2 ); assert( irrep3 == irrep4 ); const int NEW12 = dimension( idx, irrep1, space1 ); const int NEW34 = dimension( idx, irrep3, space3 ); const int SIZE = stop - start; int counter = 0; // counter = cnt1 + ( cnt2 * ( cnt2 + 1 )) / 2 for ( int cnt2 = 0; cnt2 < NEW12; cnt2++ ){ for ( int cnt1 = 0; cnt1 <= cnt2; cnt1++ ){ if (( start <= counter ) && ( counter < stop )){ for ( int cnt4 = 0; cnt4 < NEW34; cnt4++ ){ for ( int cnt3 = 0; cnt3 <= cnt4; cnt3++ ){ NEW_VMAT->set( irrep1, irrep3, irrep2, irrep4, cnt1, cnt3, cnt2, cnt4, eri[ ( counter - start ) + SIZE * ( cnt3 + NEW34 * cnt4 ) ] ); // Indices (12) and indices (34) are Coulomb pairs } } } counter++; } } written = true; } else { assert( Irreps::directProd( irrep1, irrep2 ) == Irreps::directProd( irrep3, irrep4 ) ); const int NEW1 = dimension( idx, irrep1, space1 ); const int NEW2 = dimension( idx, irrep2, space2 ); const int NEW3 = dimension( idx, irrep3, space3 ); const int NEW4 = dimension( idx, irrep4, space4 ); const int SIZE = stop - start; int counter = 0; // counter = cnt1 + NEW1 * cnt2 for ( int cnt2 = 0; cnt2 < NEW2; cnt2++ ){ for ( int cnt1 = 0; cnt1 < NEW1; cnt1++ ){ if (( start <= counter ) && ( counter < stop )){ for ( int cnt4 = 0; cnt4 < NEW4; cnt4++ ){ for ( int cnt3 = 0; cnt3 < NEW3; cnt3++ ){ NEW_VMAT->set( irrep1, irrep3, irrep2, irrep4, cnt1, cnt3, cnt2, cnt4, eri[ ( counter - start ) + SIZE * ( cnt3 + NEW3 * cnt4 ) ] ); // Indices (12) and indices (34) are Coulomb pairs } } } counter++; } } written = true; } } if (( space1 == 'C' ) && ( space2 == 'C' ) && ( space3 == 'F' ) && ( space4 == 'F' )){ if ( pack ){ assert( irrep1 == irrep2 ); assert( irrep3 == irrep4 ); const int NEW12 = dimension( idx, irrep1, space1 ); const int NEW34 = dimension( idx, irrep3, space3 ); const int SIZE = stop - start; int counter = 0; // counter = cnt1 + ( cnt2 * ( cnt2 + 1 )) / 2 for ( int cnt2 = 0; cnt2 < NEW12; cnt2++ ){ for ( int cnt1 = 0; cnt1 <= cnt2; cnt1++ ){ if (( start <= counter ) && ( counter < stop )){ for ( int cnt4 = 0; cnt4 < NEW34; cnt4++ ){ for ( int cnt3 = 0; cnt3 <= cnt4; cnt3++ ){ ROT_TEI->set_coulomb( irrep1, irrep2, irrep3, irrep4, cnt1, cnt2, cnt3, cnt4, eri[ ( counter - start ) + SIZE * ( cnt3 + NEW34 * cnt4 ) ] ); // Indices (12) and indices (34) are Coulomb pairs } } } counter++; } } written = true; } else { assert( Irreps::directProd( irrep1, irrep2 ) == Irreps::directProd( irrep3, irrep4 ) ); const int NEW1 = dimension( idx, irrep1, space1 ); const int NEW2 = dimension( idx, irrep2, space2 ); const int NEW3 = dimension( idx, irrep3, space3 ); const int NEW4 = dimension( idx, irrep4, space4 ); const int SIZE = stop - start; int counter = 0; // counter = cnt1 + NEW1 * cnt2 for ( int cnt2 = 0; cnt2 < NEW2; cnt2++ ){ for ( int cnt1 = 0; cnt1 < NEW1; cnt1++ ){ if (( start <= counter ) && ( counter < stop )){ for ( int cnt4 = 0; cnt4 < NEW4; cnt4++ ){ for ( int cnt3 = 0; cnt3 < NEW3; cnt3++ ){ ROT_TEI->set_coulomb( irrep1, irrep2, irrep3, irrep4, cnt1, cnt2, cnt3, cnt4, eri[ ( counter - start ) + SIZE * ( cnt3 + NEW3 * cnt4 ) ] ); // Indices (12) and indices (34) are Coulomb pairs } } } counter++; } } written = true; } } if (( space1 == 'C' ) && ( space2 == 'V' ) && ( space3 == 'C' ) && ( space4 == 'V' )){ // ( C V | C V ) assert( pack == false ); assert( Irreps::directProd( irrep1, irrep2 ) == Irreps::directProd( irrep3, irrep4 ) ); const int NEW1 = dimension( idx, irrep1, space1 ); const int NEW2 = dimension( idx, irrep2, space2 ); const int NEW3 = dimension( idx, irrep3, space3 ); const int NEW4 = dimension( idx, irrep4, space4 ); const int JUMP2 = jump( idx, irrep2, space2 ); const int JUMP4 = jump( idx, irrep4, space4 ); const int SIZE = stop - start; int counter = 0; // counter = cnt1 + NEW1 * cnt2 for ( int cnt2 = 0; cnt2 < NEW2; cnt2++ ){ for ( int cnt1 = 0; cnt1 < NEW1; cnt1++ ){ if (( start <= counter ) && ( counter < stop )){ for ( int cnt4 = 0; cnt4 < NEW4; cnt4++ ){ for ( int cnt3 = 0; cnt3 < NEW3; cnt3++ ){ ROT_TEI->set_exchange( irrep1, irrep3, irrep2, irrep4, cnt1, cnt3, JUMP2 + cnt2, JUMP4 + cnt4, eri[ ( counter - start ) + SIZE * ( cnt3 + NEW3 * cnt4 ) ] ); // Indices (12) and indices (34) are Coulomb pairs } } } counter++; } } written = true; } assert( written == true ); } void CheMPS2::DMRGSCFrotations::blockwise_first( double * origin, double * target, int orig1, int dim2, const int dim34, double * umat1, int new1, int lda1 ){ char notrans = 'N'; double one = 1.0; double set = 0.0; int right_dim = dim2 * dim34; dgemm_( ¬rans, ¬rans, &new1, &right_dim, &orig1, &one, umat1, &lda1, origin, &orig1, &set, target, &new1 ); } void CheMPS2::DMRGSCFrotations::blockwise_second( double * origin, double * target, int dim1, int orig2, const int dim34, double * umat2, int new2, int lda2 ){ char trans = 'T'; char notrans = 'N'; double one = 1.0; double set = 0.0; const int jump_old = dim1 * orig2; const int jump_new = dim1 * new2; #pragma omp parallel for schedule(static) for ( int index = 0; index < dim34; index++ ){ dgemm_( ¬rans, &trans, &dim1, &new2, &orig2, &one, origin + jump_old * index, &dim1, umat2, &lda2, &set, target + jump_new * index, &dim1 ); } } void CheMPS2::DMRGSCFrotations::blockwise_third( double * origin, double * target, const int dim12, int orig3, const int dim4, double * umat3, int new3, int lda3 ){ char trans = 'T'; char notrans = 'N'; double one = 1.0; double set = 0.0; int left_dim = dim12; const int jump_old = dim12 * orig3; const int jump_new = dim12 * new3; #pragma omp parallel for schedule(static) for ( int index = 0; index < dim4; index++ ){ dgemm_( ¬rans, &trans, &left_dim, &new3, &orig3, &one, origin + jump_old * index, &left_dim, umat3, &lda3, &set, target + jump_new * index, &left_dim ); } } void CheMPS2::DMRGSCFrotations::blockwise_fourth( double * origin, double * target, const int dim12, int dim3, int orig4, double * umat4, int new4, int lda4 ){ char trans = 'T'; char notrans = 'N'; double one = 1.0; double set = 0.0; int left_dim = dim12 * dim3; dgemm_( ¬rans, &trans, &left_dim, &new4, &orig4, &one, origin, &left_dim, umat4, &lda4, &set, target, &left_dim ); } void CheMPS2::DMRGSCFrotations::open_file( hid_t * file_id, hid_t * dspc_id, hid_t * dset_id, const int first, const int second, const string filename ){ file_id[0] = H5Fcreate( filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT ); hsize_t fdim_h5[] = { (hsize_t) second, (hsize_t) first }; // C is row major: [ col + ncol * row ] is assumed dspc_id[0] = H5Screate_simple( 2, fdim_h5, NULL ); dset_id[0] = H5Dcreate( file_id[0], "storage", H5T_NATIVE_DOUBLE, dspc_id[0], H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT ); } void CheMPS2::DMRGSCFrotations::close_file( hid_t file_id, hid_t dspc_id, hid_t dset_id ){ H5Dclose( dset_id ); H5Sclose( dspc_id ); H5Fclose( file_id ); } void CheMPS2::DMRGSCFrotations::write_file( hid_t dspc_id, hid_t dset_id, double * eri, const int start, const int size, const int first_write ){ hsize_t stride_h5[] = { 1, 1 }; hsize_t count_h5[] = { 1, 1 }; hsize_t start_h5[] = { (hsize_t) start, 0 }; hsize_t block_h5[] = { (hsize_t) size, (hsize_t) first_write }; H5Sselect_hyperslab( dspc_id, H5S_SELECT_SET, start_h5, stride_h5, count_h5, block_h5 ); hsize_t mem_h5 = size * first_write; // Should be OK to multiply as integers as it is smaller than mem_size hid_t mem_id = H5Screate_simple( 1, &mem_h5, NULL ); H5Dwrite( dset_id, H5T_NATIVE_DOUBLE, mem_id, dspc_id, H5P_DEFAULT, eri ); H5Sclose( mem_id ); } void CheMPS2::DMRGSCFrotations::read_file( hid_t dspc_id, hid_t dset_id, double * eri, const int start, const int size, const int second_read ){ hsize_t stride_h5[] = { 1, 1 }; hsize_t count_h5[] = { 1, 1 }; hsize_t start_h5[] = { 0, (hsize_t) start }; hsize_t block_h5[] = { (hsize_t) second_read, (hsize_t) size }; H5Sselect_hyperslab( dspc_id, H5S_SELECT_SET, start_h5, stride_h5, count_h5, block_h5 ); hsize_t mem_h5 = second_read * size; // Should be OK to multiply as integers as it is smaller than mem_size hid_t mem_id = H5Screate_simple( 1, &mem_h5, NULL ); H5Dread( dset_id, H5T_NATIVE_DOUBLE, mem_id, dspc_id, H5P_DEFAULT, eri ); H5Sclose( mem_id ); } int CheMPS2::DMRGSCFrotations::dimension( DMRGSCFindices * idx, const int irrep, const char space ){ if ( space == 'O' ){ return idx->getNOCC( irrep ); } if ( space == 'A' ){ return idx->getNDMRG( irrep ); } if ( space == 'V' ){ return idx->getNVIRT( irrep ); } if ( space == 'C' ){ return ( idx->getNOCC( irrep ) + idx->getNDMRG( irrep ) ); } if ( space == 'F' ){ return idx->getNORB( irrep ); } return -1; } int CheMPS2::DMRGSCFrotations::jump( DMRGSCFindices * idx, const int irrep, const char space ){ if ( space == 'A' ){ return idx->getNOCC( irrep ); } if ( space == 'V' ){ return idx->getNOCC( irrep ) + idx->getNDMRG( irrep ); } return 0; // O, F, C } void CheMPS2::DMRGSCFrotations::unpackage_second( double * mem1, double * mem2, const int SIZE, const int ORIG ){ #pragma omp parallel for schedule(static) for ( int cnt4 = 0; cnt4 < ORIG; cnt4++ ){ for ( int cnt3 = 0; cnt3 < ORIG; cnt3++ ){ const int combined = (( cnt3 < cnt4 ) ? ( cnt3 + ( cnt4 * ( cnt4 + 1 )) / 2 ) : ( cnt4 + ( cnt3 * ( cnt3 + 1 )) / 2 )); #pragma omp simd for ( int cnt12 = 0; cnt12 < SIZE; cnt12++ ){ mem2[ cnt12 + SIZE * ( cnt3 + ORIG * cnt4 ) ] = mem1[ cnt12 + SIZE * combined ]; } } } } void CheMPS2::DMRGSCFrotations::package_first( double * mem1, double * mem2, const int NEW, const int PACKED, const int SIZE ){ #pragma omp parallel for schedule(static) for ( int cnt34 = 0; cnt34 < SIZE; cnt34++ ){ for ( int cnt2 = 0; cnt2 < NEW; cnt2++ ){ #pragma omp simd for ( int cnt1 = 0; cnt1 <= cnt2; cnt1++ ){ mem2[ cnt1 + ( cnt2 * ( cnt2 + 1 ))/2 + PACKED * cnt34 ] = mem1[ cnt1 + NEW * ( cnt2 + NEW * cnt34 ) ]; } } } } void CheMPS2::DMRGSCFrotations::rotate( const FourIndex * ORIG_VMAT, FourIndex * NEW_VMAT, DMRGSCFintegrals * ROT_TEI, const char space1, const char space2, const char space3, const char space4, DMRGSCFindices * idx, DMRGSCFunitary * umat, double * mem1, double * mem2, const int mem_size, const string filename ){ /* Matrix elements ( 1 2 | 3 4 ) */ assert(( space1 == 'O' ) || ( space1 == 'A' ) || ( space1 == 'V' ) || ( space1 == 'C' ) || ( space1 == 'F' )); assert(( space2 == 'O' ) || ( space2 == 'A' ) || ( space2 == 'V' ) || ( space2 == 'C' ) || ( space2 == 'F' )); assert(( space3 == 'O' ) || ( space3 == 'A' ) || ( space3 == 'V' ) || ( space3 == 'C' ) || ( space3 == 'F' )); assert(( space4 == 'O' ) || ( space4 == 'A' ) || ( space4 == 'V' ) || ( space4 == 'C' ) || ( space4 == 'F' )); const int num_irreps = idx->getNirreps(); const bool equal12 = ( space1 == space2 ); const bool equal34 = ( space3 == space4 ); const bool eightfold = (( space1 == space3 ) && ( space2 == space4 )); for ( int irrep1 = 0; irrep1 < num_irreps; irrep1++ ){ for ( int irrep2 = (( equal12 ) ? irrep1 : 0 ); irrep2 < num_irreps; irrep2++ ){ // irrep2 >= irrep1 if space1 == space2 const int product_symm = Irreps::directProd( irrep1, irrep2 ); for ( int irrep3 = (( eightfold ) ? irrep1 : 0 ); irrep3 < num_irreps; irrep3++ ){ const int irrep4 = Irreps::directProd( product_symm, irrep3 ); if ( irrep4 >= (( equal34 ) ? irrep3 : 0 ) ){ // irrep4 >= irrep3 if space3 == space4 const int NEW1 = dimension( idx, irrep1, space1 ); const int NEW2 = dimension( idx, irrep2, space2 ); const int NEW3 = dimension( idx, irrep3, space3 ); const int NEW4 = dimension( idx, irrep4, space4 ); if (( NEW1 > 0 ) && ( NEW2 > 0 ) && ( NEW3 > 0 ) && ( NEW4 > 0 )){ const int ORIG1 = idx->getNORB( irrep1 ); const int ORIG2 = idx->getNORB( irrep2 ); const int ORIG3 = idx->getNORB( irrep3 ); const int ORIG4 = idx->getNORB( irrep4 ); double * umat1 = umat->getBlock( irrep1 ) + jump( idx, irrep1, space1 ); double * umat2 = umat->getBlock( irrep2 ) + jump( idx, irrep2, space2 ); double * umat3 = umat->getBlock( irrep3 ) + jump( idx, irrep3, space3 ); double * umat4 = umat->getBlock( irrep4 ) + jump( idx, irrep4, space4 ); const int block_size1 = mem_size / ( ORIG1 * ORIG2 ); // Floor of amount of times orig( first ) fits in mem_size const int block_size2 = mem_size / ( ORIG3 * ORIG4 ); // Floor of amount of times orig( second ) fits in mem_size assert( block_size1 > 0 ); assert( block_size2 > 0 ); const bool pack_first = (( equal12 ) && ( irrep1 == irrep2 )); const bool pack_second = (( equal34 ) && ( irrep3 == irrep4 )); const int first_size = (( pack_first ) ? ( NEW1 * ( NEW1 + 1 )) / 2 : NEW1 * NEW2 ); const int second_size = (( pack_second ) ? ( ORIG3 * ( ORIG3 + 1 )) / 2 : ORIG3 * ORIG4 ); const bool io_free = (( block_size1 >= second_size ) && ( block_size2 >= first_size )); hid_t file_id, dspc_id, dset_id; if ( io_free == false ){ assert( filename.compare( "edmistonruedenberg" ) != 0 ); open_file( &file_id, &dspc_id, &dset_id, first_size, second_size, filename ); } // First half transformation int start = 0; while ( start < second_size ){ const int stop = min( start + block_size1, second_size ); const int size = stop - start; fetch( mem1, ORIG_VMAT, irrep1, irrep2, irrep3, irrep4, idx, start, stop, pack_second ); blockwise_first( mem1, mem2, ORIG1, ORIG2, size, umat1, NEW1, ORIG1 ); blockwise_second( mem2, mem1, NEW1, ORIG2, size, umat2, NEW2, ORIG2 ); if ( pack_first ){ package_first( mem1, mem2, NEW1, first_size, size ); double * temp = mem1; mem1 = mem2; mem2 = temp; } if ( io_free == false ){ write_file( dspc_id, dset_id, mem1, start, size, first_size ); } start += size; } assert( start == second_size ); // Do the second half transformation start = 0; while ( start < first_size ){ const int stop = min( start + block_size2, first_size ); const int size = stop - start; if ( io_free == false ){ read_file( dspc_id, dset_id, mem1, start, size, second_size ); } if ( pack_second ){ unpackage_second( mem1, mem2, size, ORIG3 ); double * temp = mem1; mem1 = mem2; mem2 = temp; } blockwise_fourth( mem1, mem2, size, ORIG3, ORIG4, umat4, NEW4, ORIG4 ); blockwise_third( mem2, mem1, size, ORIG3, NEW4, umat3, NEW3, ORIG3 ); write( mem1, NEW_VMAT, ROT_TEI, space1, space2, space3, space4, irrep1, irrep2, irrep3, irrep4, idx, start, stop, pack_first ); start += size; } assert( start == first_size ); if ( io_free == false ){ close_file( file_id, dspc_id, dset_id ); } } } } } } } CheMPS2-1.8.9/CheMPS2/DMRGSCFunitary.cpp000066400000000000000000000437441336564451100172640ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include "Lapack.h" #include "DMRGSCFunitary.h" using std::cout; using std::endl; CheMPS2::DMRGSCFunitary::DMRGSCFunitary( const DMRGSCFindices * iHandler ) : DMRGSCFmatrix( iHandler ){ this->identity(); //Find the unique indices for OCC-ACT, OCC-VIRT, and ACT-VIRT rotations x_linearlength = 0; jumper = new int*[ num_irreps ]; for ( int irrep = 0; irrep < num_irreps; irrep++ ){ jumper[ irrep ] = new int[ 3 ]; const int NOCC = iHandler->getNOCC( irrep ); const int NACT = iHandler->getNDMRG( irrep ); const int NVIR = iHandler->getNVIRT( irrep ); jumper[ irrep ][ 0 ] = x_linearlength; x_linearlength += NOCC * NACT; jumper[ irrep ][ 1 ] = x_linearlength; x_linearlength += NACT * NVIR; jumper[ irrep ][ 2 ] = x_linearlength; x_linearlength += NOCC * NVIR; } } CheMPS2::DMRGSCFunitary::~DMRGSCFunitary(){ for ( int irrep = 0; irrep < num_irreps; irrep++ ){ delete [] jumper[ irrep ]; } delete [] jumper; } int CheMPS2::DMRGSCFunitary::getNumVariablesX() const{ return x_linearlength; } void CheMPS2::DMRGSCFunitary::buildSkewSymmX( const int irrep, double * result, double * Xelem, const bool compact ) const{ const int linsize = iHandler->getNORB( irrep ); const int NOCC = iHandler->getNOCC( irrep ); const int NACT = iHandler->getNDMRG( irrep ); const int NVIR = iHandler->getNVIRT( irrep ); for ( int cnt = 0; cnt < linsize * linsize; cnt++ ){ result[ cnt ] = 0.0; } if ( compact ){ for ( int occ = 0; occ < NOCC; occ++ ){ for ( int act = 0; act < NACT; act++ ){ const int xsolindex = jumper[ irrep ][ 0 ] + act + NACT * occ; const int index1 = NOCC + act; result[ index1 + linsize * occ ] = Xelem[ xsolindex ]; result[ occ + linsize * index1 ] = - Xelem[ xsolindex ]; } } for ( int act = 0; act < NACT; act++ ){ for ( int vir = 0; vir < NVIR; vir++ ){ const int xsolindex = jumper[ irrep ][ 1 ] + vir + NVIR * act; const int index1 = NOCC + NACT + vir; const int index2 = NOCC + act; result[ index1 + linsize * index2 ] = Xelem[ xsolindex ]; result[ index2 + linsize * index1 ] = - Xelem[ xsolindex ]; } } for ( int occ = 0; occ < NOCC; occ++ ){ for ( int vir = 0; vir < NVIR; vir++ ){ const int xsolindex = jumper[ irrep ][ 2 ] + vir + NVIR * occ; const int index1 = NOCC + NACT + vir; result[ index1 + linsize * occ ] = Xelem[ xsolindex ]; result[ occ + linsize * index1 ] = - Xelem[ xsolindex ]; } } } else { //NOT compact int jump = 0; for ( int cnt = 0; cnt < irrep; cnt++ ){ const int NORBx = iHandler->getNORB( cnt ); jump += ( NORBx * ( NORBx - 1 ) ) / 2; } for ( int row = 0; row < linsize; row++ ){ for ( int col = row+1; col < linsize; col++ ){ result[ row + linsize * col ] = Xelem[ jump + row + ( col * ( col - 1 ) ) / 2 ]; result[ col + linsize * row ] = - Xelem[ jump + row + ( col * ( col - 1 ) ) / 2 ]; } } } } void CheMPS2::DMRGSCFunitary::updateUnitary( double * temp1, double * temp2, double * vector, const bool multiply, const bool compact ){ for ( int irrep = 0; irrep < num_irreps; irrep++ ){ int linsize = iHandler->getNORB(irrep); int size = linsize * linsize; if ( linsize > 1 ){ //linsize is op z'n minst 2 dus temp1, temp1+size, temp1+2*size,temp1+3*size zijn zeker ok double * xblock = temp1; //linsize*linsize double * Bmat = temp1 + size; //linsize*linsize double * work1 = temp1 + 2 * size; //linsize*linsize double * work2 = temp1 + 3 * size; //linsize*linsize double * workLARGE = temp2; //4*size int lworkLARGE = 4 * size; //4*size = 4*linsize*linsize > 3*linsize-1 // Construct the antisymmetric x-matrix buildSkewSymmX( irrep, xblock, vector, compact ); //Bmat <= xblock * xblock char notrans = 'N'; double one = 1.0; double set = 0.0; dgemm_( ¬rans, ¬rans, &linsize, &linsize, &linsize, &one, xblock, &linsize, xblock, &linsize, &set, Bmat, &linsize ); //Bmat * work1 * Bmat^T <= xblock * xblock char uplo = 'U'; char jobz = 'V'; int info; dsyev_( &jobz, &uplo, &linsize, Bmat, &linsize, work1, workLARGE, &lworkLARGE, &info ); //work2 <= Bmat^T * xblock * Bmat dgemm_( ¬rans, ¬rans, &linsize, &linsize, &linsize, &one, xblock, &linsize, Bmat, &linsize, &set, work1, &linsize ); char trans = 'T'; dgemm_( &trans, ¬rans, &linsize, &linsize, &linsize, &one, Bmat, &linsize, work1, &linsize, &set, work2, &linsize ); if (CheMPS2::DMRGSCF_debugPrint){ cout << " DMRGSCFunitary::updateUnitary : Lambdas of irrep block " << irrep << " : " << endl; for (int cnt=0; cntgetNirreps() ]; for (int irrep = 0; irrep < iHandler->getNirreps(); irrep++){ Nocc_dmrg[ irrep ] = iHandler->getNOCC( irrep ) + iHandler->getNDMRG( irrep ); } wmattilde = new double***[ iHandler->getNirreps() ]; for (int irrep_pq = 0; irrep_pq < iHandler->getNirreps(); irrep_pq++){ wmattilde[ irrep_pq ] = new double**[ iHandler->getNirreps() ]; for (int irrep_rs = 0; irrep_rs < iHandler->getNirreps(); irrep_rs++){ const unsigned int sizeblock_pr = Nocc_dmrg[ irrep_pq ] * Nocc_dmrg[ irrep_rs ]; const unsigned int sizeblock_qs = iHandler->getNORB( irrep_pq ) * iHandler->getNORB( irrep_rs ); wmattilde[ irrep_pq ][ irrep_rs ] = new double*[ sizeblock_pr ]; for (unsigned int combined_pr = 0; combined_pr < sizeblock_pr; combined_pr++){ wmattilde[ irrep_pq ][ irrep_rs ][ combined_pr ] = new double[ sizeblock_qs ]; } } } } CheMPS2::DMRGSCFwtilde::~DMRGSCFwtilde(){ for (int irrep_pq = 0; irrep_pq < iHandler->getNirreps(); irrep_pq++){ for (int irrep_rs = 0; irrep_rs < iHandler->getNirreps(); irrep_rs++){ const unsigned int sizeblock_pr = Nocc_dmrg[ irrep_pq ] * Nocc_dmrg[ irrep_rs ]; for (unsigned int combined_pr = 0; combined_pr < sizeblock_pr; combined_pr++){ delete [] wmattilde[ irrep_pq ][ irrep_rs ][ combined_pr ]; } delete [] wmattilde[ irrep_pq ][ irrep_rs ]; } delete [] wmattilde[ irrep_pq ]; } delete [] wmattilde; delete [] Nocc_dmrg; } void CheMPS2::DMRGSCFwtilde::clear(){ for (int irrep_pq = 0; irrep_pq < iHandler->getNirreps(); irrep_pq++){ for (int irrep_rs = 0; irrep_rs < iHandler->getNirreps(); irrep_rs++){ const unsigned int sizeblock_pr = Nocc_dmrg[ irrep_pq ] * Nocc_dmrg[ irrep_rs ]; const unsigned int sizeblock_qs = iHandler->getNORB( irrep_pq ) * iHandler->getNORB( irrep_rs ); for (unsigned int combined_pr = 0; combined_pr < sizeblock_pr; combined_pr++){ for (unsigned int combined_qs = 0; combined_qs < sizeblock_qs; combined_qs++){ wmattilde[ irrep_pq ][ irrep_rs ][ combined_pr ][ combined_qs ] = 0.0; } } } } } void CheMPS2::DMRGSCFwtilde::set(const int irrep_pq, const int irrep_rs, const int p, const int q, const int r, const int s, const double val){ wmattilde[ irrep_pq ][ irrep_rs ][ p + Nocc_dmrg[ irrep_pq ] * r ][ q + iHandler->getNORB(irrep_pq) * s ] = val; } double CheMPS2::DMRGSCFwtilde::get(const int irrep_pq, const int irrep_rs, const int p, const int q, const int r, const int s) const{ return wmattilde[ irrep_pq ][ irrep_rs ][ p + Nocc_dmrg[ irrep_pq ] * r ][ q + iHandler->getNORB(irrep_pq) * s ]; } double * CheMPS2::DMRGSCFwtilde::getBlock(const int irrep_pq, const int irrep_rs, const int p, const int r){ return wmattilde[ irrep_pq ][ irrep_rs ][ p + Nocc_dmrg[ irrep_pq ] * r ]; } CheMPS2-1.8.9/CheMPS2/DMRGfock.cpp000066400000000000000000000455471336564451100161620ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include #include #include "DMRG.h" #include "Lapack.h" #include "Heff.h" #include "MPIchemps2.h" #include "Excitation.h" using std::cout; using std::endl; using std::min; using std::max; void CheMPS2::DMRG::Symm4RDM( double * output, const int Y, const int Z, const bool last_case ){ struct timeval start, end; gettimeofday( &start, NULL ); assert( the3DM != NULL ); symm_4rdm_helper( output, Y, Z, 1.0, 1.0, false, 0.5 ); // output = 0.5 * 3rdm[ ( 1 + E_{YZ} + E_{ZY} ) | 0 > ] symm_4rdm_helper( output, Y, Z, 1.0, 0.0, true, -0.5 ); // output = 0.5 * ( 3rdm[ ( 1 + E_{YZ} + E_{ZY} ) | 0 > ] - 3rdm[ E_{YZ} + E_{ZY} | 0 > ] ) for ( int r = 0; r < L; r++ ){ for ( int q = 0; q < L; q++ ){ for ( int p = 0; p < L; p++ ){ for ( int k = 0; k < L; k++ ){ for ( int j = 0; j < L; j++ ){ for ( int i = 0; i < L; i++ ){ output[ i + L * ( j + L * ( k + L * ( p + L * ( q + L * r )))) ] -= 0.5 * the3DM->get_ham_index( i, j, k, p, q, r ); } output[ Y + L * ( j + L * ( k + L * ( p + L * ( q + L * r )))) ] -= 0.5 * the3DM->get_ham_index( Z, j, k, p, q, r ); output[ Z + L * ( j + L * ( k + L * ( p + L * ( q + L * r )))) ] -= 0.5 * the3DM->get_ham_index( Y, j, k, p, q, r ); output[ j + L * ( Y + L * ( k + L * ( p + L * ( q + L * r )))) ] -= 0.5 * the3DM->get_ham_index( j, Z, k, p, q, r ); output[ j + L * ( Z + L * ( k + L * ( p + L * ( q + L * r )))) ] -= 0.5 * the3DM->get_ham_index( j, Y, k, p, q, r ); output[ j + L * ( k + L * ( Y + L * ( p + L * ( q + L * r )))) ] -= 0.5 * the3DM->get_ham_index( j, k, Z, p, q, r ); output[ j + L * ( k + L * ( Z + L * ( p + L * ( q + L * r )))) ] -= 0.5 * the3DM->get_ham_index( j, k, Y, p, q, r ); output[ j + L * ( k + L * ( p + L * ( Y + L * ( q + L * r )))) ] -= 0.5 * the3DM->get_ham_index( j, k, p, Z, q, r ); output[ j + L * ( k + L * ( p + L * ( Z + L * ( q + L * r )))) ] -= 0.5 * the3DM->get_ham_index( j, k, p, Y, q, r ); output[ j + L * ( k + L * ( p + L * ( q + L * ( Y + L * r )))) ] -= 0.5 * the3DM->get_ham_index( k, j, p, Z, q, r ); output[ j + L * ( k + L * ( p + L * ( q + L * ( Z + L * r )))) ] -= 0.5 * the3DM->get_ham_index( k, j, p, Y, q, r ); output[ j + L * ( k + L * ( p + L * ( q + L * ( r + L * Y )))) ] -= 0.5 * the3DM->get_ham_index( p, j, k, Z, q, r ); output[ j + L * ( k + L * ( p + L * ( q + L * ( r + L * Z )))) ] -= 0.5 * the3DM->get_ham_index( p, j, k, Y, q, r ); } } } } } if ( last_case ){ PreSolve(); } // Need to set up the renormalized operators again to continue sweeping gettimeofday( &end, NULL ); const double elapsed = ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ) #endif { cout << "CheMPS2::DMRG::Symm4RDM( " << Y << " , " << Z << " ) : Elapsed wall time = " << elapsed << " seconds." << endl; } } void CheMPS2::DMRG::symm_4rdm_helper( double * output, const int ham_orb1, const int ham_orb2, const double alpha, const double beta, const bool add, const double factor ){ // Figure out the DMRG orbitals, in order assert( ham_orb1 >= 0 ); assert( ham_orb2 >= 0 ); assert( ham_orb1 < L ); assert( ham_orb2 < L ); const int first_dmrg_orb = (( Prob->gReorder() ) ? Prob->gf1( ham_orb1 ) : ham_orb1 ); const int second_dmrg_orb = (( Prob->gReorder() ) ? Prob->gf1( ham_orb2 ) : ham_orb2 ); const int dmrg_orb1 = (( first_dmrg_orb <= second_dmrg_orb ) ? first_dmrg_orb : second_dmrg_orb ); const int dmrg_orb2 = (( first_dmrg_orb <= second_dmrg_orb ) ? second_dmrg_orb : first_dmrg_orb ); // Make a back-up of the entirely left-normalized MPS and the corresponding bookkeeper SyBookkeeper * oldBK = denBK; if ( dmrg_orb1 != dmrg_orb2 ){ denBK = new SyBookkeeper( *oldBK ); } TensorT ** backup_mps = new TensorT * [ L ]; for ( int orbital = 0; orbital < L; orbital++ ){ backup_mps[ orbital ] = MPS[ orbital ]; MPS[ orbital ] = new TensorT( orbital, denBK ); // denBK is now a DIFFERENT pointer than backup_mps[ orbital ]->gBK() int totalsize = MPS[ orbital ]->gKappa2index( MPS[ orbital ]->gNKappa() ); int inc1 = 1; dcopy_( &totalsize, backup_mps[ orbital ]->gStorage(), &inc1, MPS[ orbital ]->gStorage(), &inc1 ); } deleteAllBoundaryOperators(); // Change the gauge so that the non-orthonormal MPS tensor is on site dmrg_orb2 for ( int siteindex = L - 1; siteindex > dmrg_orb2; siteindex-- ){ right_normalize( MPS[ siteindex - 1 ], MPS[ siteindex ] ); updateMovingLeftSafeFirstTime( siteindex - 1 ); } // Solve solve_fock( dmrg_orb1, dmrg_orb2, alpha, beta ); // Further right normalize the wavefunction except for the first MPS tensor ( contains the norm ) for ( int siteindex = dmrg_orb2; siteindex > 0; siteindex-- ){ right_normalize( MPS[ siteindex - 1 ], MPS[ siteindex ] ); updateMovingLeftSafeFirstTime( siteindex - 1 ); } ThreeDM * helper3rdm = new ThreeDM( denBK, Prob, false ); tensor_3rdm_a_J0_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_a_J1_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_a_J1_quartet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_b_J0_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_b_J1_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_b_J1_quartet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_c_J0_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_c_J1_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_c_J1_quartet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_d_J0_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_d_J1_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_d_J1_quartet = new Tensor3RDM****[ L - 1 ]; // Leftmost contribution to the helper3rdm helper3rdm->fill_site( MPS[ 0 ], Ltensors, F0tensors, F1tensors, S0tensors, S1tensors, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); // Other contributions to the helper3rdm for ( int siteindex = 1; siteindex < L; siteindex++ ){ /* Change the MPS gauge */ left_normalize( MPS[ siteindex - 1 ], MPS[ siteindex ] ); /* Update the required renormalized operators */ update_safe_3rdm_operators( siteindex ); updateMovingRightSafe2DM( siteindex - 1 ); /* Current contribution to helper3rdm */ helper3rdm->fill_site( MPS[ siteindex ], Ltensors, F0tensors, F1tensors, S0tensors, S1tensors, tensor_3rdm_a_J0_doublet[ siteindex - 1 ], tensor_3rdm_a_J1_doublet[ siteindex - 1 ], tensor_3rdm_a_J1_quartet[ siteindex - 1 ], tensor_3rdm_b_J0_doublet[ siteindex - 1 ], tensor_3rdm_b_J1_doublet[ siteindex - 1 ], tensor_3rdm_b_J1_quartet[ siteindex - 1 ], tensor_3rdm_c_J0_doublet[ siteindex - 1 ], tensor_3rdm_c_J1_doublet[ siteindex - 1 ], tensor_3rdm_c_J1_quartet[ siteindex - 1 ], tensor_3rdm_d_J0_doublet[ siteindex - 1 ], tensor_3rdm_d_J1_doublet[ siteindex - 1 ], tensor_3rdm_d_J1_quartet[ siteindex - 1 ] ); } // Collect all data #ifdef CHEMPS2_MPI_COMPILATION helper3rdm->mpi_allreduce(); #endif // Copy the contributions helper3rdm->correct_higher_multiplicities(); delete_3rdm_operators( L - 1 ); delete [] tensor_3rdm_a_J0_doublet; delete [] tensor_3rdm_a_J1_doublet; delete [] tensor_3rdm_a_J1_quartet; delete [] tensor_3rdm_b_J0_doublet; delete [] tensor_3rdm_b_J1_doublet; delete [] tensor_3rdm_b_J1_quartet; delete [] tensor_3rdm_c_J0_doublet; delete [] tensor_3rdm_c_J1_doublet; delete [] tensor_3rdm_c_J1_quartet; delete [] tensor_3rdm_d_J0_doublet; delete [] tensor_3rdm_d_J1_doublet; delete [] tensor_3rdm_d_J1_quartet; helper3rdm->fill_ham_index( factor, add, output, 0, L ); // Throw out the changed MPS and place back the original left-normalized MPS for ( int orbital = 0; orbital < L; orbital++ ){ delete MPS[ orbital ]; MPS[ orbital ] = backup_mps[ orbital ]; } delete [] backup_mps; if ( dmrg_orb1 != dmrg_orb2 ){ delete denBK; denBK = oldBK; } delete helper3rdm; deleteAllBoundaryOperators(); } void CheMPS2::DMRG::solve_fock( const int dmrg_orb1, const int dmrg_orb2, const double alpha, const double beta ){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif if ( dmrg_orb1 == dmrg_orb2 ){ MPS[ dmrg_orb1 ]->number_operator( 2 * alpha, beta ); // alpha * ( E_zz + E_zz ) + beta * 1 return; } double sweep_inproduct = 0.0; if ( dmrg_orb1 + 1 == dmrg_orb2 ){ Sobject * newS = new Sobject( dmrg_orb1, denBK ); if ( am_i_master ){ Sobject * oldS = new Sobject( dmrg_orb1, denBK ); oldS->Join( MPS[ dmrg_orb1 ], MPS[ dmrg_orb2 ] ); sweep_inproduct = Excitation::matvec( denBK, denBK, dmrg_orb1, dmrg_orb2, alpha, alpha, beta, newS, oldS, NULL, NULL, NULL ); delete oldS; } // MPI_CHEMPS2_MASTER decomposes newS. Each MPI process returns the correct discarded_weight. Each MPI process has the new MPS tensors set. const double discarded_weight = newS->Split( MPS[ dmrg_orb1 ], MPS[ dmrg_orb2 ], OptScheme->get_D( OptScheme->get_number() - 1 ), true, true ); delete newS; } if ( dmrg_orb1 + 1 < dmrg_orb2 ){ SyBookkeeper * newBK = denBK; denBK = new SyBookkeeper( *newBK ); newBK->restart( dmrg_orb1 + 1, dmrg_orb2, OptScheme->get_D( OptScheme->get_number() - 1 ) ); TensorT ** old_mps = new TensorT * [ L ]; for ( int orbital = dmrg_orb1; orbital <= dmrg_orb2; orbital++ ){ old_mps[ orbital ] = MPS[ orbital ]; old_mps[ orbital ]->sBK( denBK ); MPS[ orbital ] = new TensorT( orbital, newBK ); MPS[ orbital ]->random(); left_normalize( MPS[ orbital ], NULL ); // MPI_CHEMPS2_MASTER broadcasts MPS[ orbital ] ( left-normalized ). } TensorO ** overlaps = NULL; TensorL ** regular = NULL; TensorL ** trans = NULL; if ( am_i_master ){ overlaps = new TensorO*[ L - 1 ]; regular = new TensorL*[ L - 1 ]; trans = new TensorL*[ L - 1 ]; for ( int cnt = 0; cnt < L - 1; cnt++ ){ overlaps[ cnt ] = NULL; regular[ cnt ] = NULL; trans[ cnt ] = NULL; } for ( int orbital = dmrg_orb1; orbital < dmrg_orb2 - 1; orbital++ ){ solve_fock_update_helper( orbital, dmrg_orb1, dmrg_orb2, true, MPS, old_mps, newBK, denBK, overlaps, regular, trans ); } } // Sweeps bool change = false; for ( int instruction = 0; instruction < OptScheme->get_number(); instruction++ ){ int num_iterations = 0; double previous_inproduct = sweep_inproduct + 10 * OptScheme->get_energy_conv( instruction ); while (( fabs( sweep_inproduct - previous_inproduct ) > OptScheme->get_energy_conv( instruction ) ) && ( num_iterations < OptScheme->get_max_sweeps( instruction ) )){ { const double noise_level = fabs( OptScheme->get_noise_prefactor( instruction ) ) * MaxDiscWeightLastSweep; MaxDiscWeightLastSweep = 0.0; for ( int index = dmrg_orb2 - 1; index > dmrg_orb1; index-- ){ Sobject * newS = new Sobject( index, newBK ); if ( am_i_master ){ Sobject * oldS = new Sobject( index, denBK ); oldS->Join( old_mps[ index ], old_mps[ index + 1 ] ); sweep_inproduct = Excitation::matvec( newBK, denBK, dmrg_orb1, dmrg_orb2, alpha, alpha, beta, newS, oldS, overlaps, regular, trans ); delete oldS; if ( noise_level > 0.0 ){ newS->addNoise( noise_level ); } } // MPI_CHEMPS2_MASTER decomposes newS. Each MPI process returns the correct discarded_weight. Each MPI process has the new MPS tensors set. const double discarded_weight = newS->Split( MPS[ index ], MPS[ index + 1 ], OptScheme->get_D( instruction ), false, change ); if ( discarded_weight > MaxDiscWeightLastSweep ){ MaxDiscWeightLastSweep = discarded_weight; } delete newS; if ( am_i_master ){ solve_fock_update_helper( index, dmrg_orb1, dmrg_orb2, false, MPS, old_mps, newBK, denBK, overlaps, regular, trans ); } } } change = true; { const double noise_level = fabs( OptScheme->get_noise_prefactor( instruction ) ) * MaxDiscWeightLastSweep; MaxDiscWeightLastSweep = 0.0; for ( int index = dmrg_orb1; index < dmrg_orb2 - 1; index++ ){ Sobject * newS = new Sobject( index, newBK ); if ( am_i_master ){ Sobject * oldS = new Sobject( index, denBK ); oldS->Join( old_mps[ index ], old_mps[ index + 1 ] ); sweep_inproduct = Excitation::matvec( newBK, denBK, dmrg_orb1, dmrg_orb2, alpha, alpha, beta, newS, oldS, overlaps, regular, trans ); delete oldS; if ( noise_level > 0.0 ){ newS->addNoise( noise_level ); } } // MPI_CHEMPS2_MASTER decomposes newS. Each MPI process returns the correct discarded_weight. Each MPI process has the new MPS tensors set. const double discarded_weight = newS->Split( MPS[ index ], MPS[ index + 1 ], OptScheme->get_D( instruction ), true, change ); if ( discarded_weight > MaxDiscWeightLastSweep ){ MaxDiscWeightLastSweep = discarded_weight; } delete newS; if ( am_i_master ){ solve_fock_update_helper( index, dmrg_orb1, dmrg_orb2, true, MPS, old_mps, newBK, denBK, overlaps, regular, trans ); } } } #ifdef CHEMPS2_MPI_COMPILATION CheMPS2::MPIchemps2::broadcast_array_double( &sweep_inproduct, 1, MPI_CHEMPS2_MASTER ); #endif previous_inproduct = sweep_inproduct; num_iterations++; } } if ( am_i_master ){ for ( int index = 0; index < L - 1; index++ ){ if ( overlaps[ index ] != NULL ){ delete overlaps[ index ]; } if ( regular[ index ] != NULL ){ delete regular[ index ]; } if ( trans[ index ] != NULL ){ delete trans[ index ]; } } delete [] overlaps; delete [] regular; delete [] trans; } for ( int orbital = dmrg_orb1; orbital <= dmrg_orb2; orbital++ ){ delete old_mps[ orbital ]; } delete [] old_mps; delete denBK; denBK = newBK; } if ( am_i_master ){ const double rdm_inproduct = 2 * alpha * the2DM->get1RDM_DMRG( dmrg_orb1, dmrg_orb2 ) + beta; cout << "DMRG::solve_fock : Accuracy = " << fabs( sweep_inproduct / ( Prob->gTwoS() + 1 ) - rdm_inproduct ) << endl; } } void CheMPS2::DMRG::solve_fock_update_helper( const int index, const int dmrg_orb1, const int dmrg_orb2, const bool moving_right, TensorT ** new_mps, TensorT ** old_mps, SyBookkeeper * new_bk, SyBookkeeper * old_bk, TensorO ** overlaps, TensorL ** regular, TensorL ** trans ){ if ( overlaps[ index ] != NULL ){ delete overlaps[ index ]; } if ( regular[ index ] != NULL ){ delete regular[ index ]; } if ( trans[ index ] != NULL ){ delete trans[ index ]; } const int Idiff = new_bk->gIrrep( dmrg_orb1 ); assert( Idiff == new_bk->gIrrep( dmrg_orb2 ) ); overlaps[ index ] = new TensorO( index + 1, moving_right, new_bk, old_bk ); regular[ index ] = new TensorL( index + 1, Idiff, moving_right, new_bk, old_bk ); trans[ index ] = new TensorL( index + 1, Idiff, moving_right, old_bk, new_bk ); if ( moving_right ){ if ( index == dmrg_orb1 ){ overlaps[ index ]->create( new_mps[ index ], old_mps[ index ] ); regular[ index ]->create( new_mps[ index ], old_mps[ index ], NULL, NULL ); trans[ index ]->create( old_mps[ index ], new_mps[ index ], NULL, NULL ); } else { const int dimL = std::max( new_bk->gMaxDimAtBound( index ), old_bk->gMaxDimAtBound( index ) ); const int dimR = std::max( new_bk->gMaxDimAtBound( index + 1 ), old_bk->gMaxDimAtBound( index + 1 ) ); double * workmem = new double[ dimL * dimR ]; overlaps[ index ]->update( overlaps[ index - 1 ], new_mps[ index ], old_mps[ index ], workmem ); regular[ index ]->update( regular[ index - 1 ], new_mps[ index ], old_mps[ index ], workmem ); trans[ index ]->update( trans[ index - 1 ], old_mps[ index ], new_mps[ index ], workmem ); delete [] workmem; } } else { if ( index + 1 == dmrg_orb2 ){ overlaps[ index ]->create( new_mps[ index + 1 ], old_mps[ index + 1 ] ); regular[ index ]->create( new_mps[ index + 1 ], old_mps[ index + 1 ], NULL, NULL ); trans[ index ]->create( old_mps[ index + 1 ], new_mps[ index + 1 ], NULL, NULL ); } else { const int dimL = std::max( new_bk->gMaxDimAtBound( index + 1 ), old_bk->gMaxDimAtBound( index + 1 ) ); const int dimR = std::max( new_bk->gMaxDimAtBound( index + 2 ), old_bk->gMaxDimAtBound( index + 2 ) ); double * workmem = new double[ dimL * dimR ]; overlaps[ index ]->update( overlaps[ index + 1 ], new_mps[ index + 1 ], old_mps[ index + 1 ], workmem ); regular[ index ]->update( regular[ index + 1 ], new_mps[ index + 1 ], old_mps[ index + 1 ], workmem ); trans[ index ]->update( trans[ index + 1 ], old_mps[ index + 1 ], new_mps[ index + 1 ], workmem ); delete [] workmem; } } } CheMPS2-1.8.9/CheMPS2/DMRGmpsio.cpp000066400000000000000000000151771336564451100163630ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include "DMRG.h" void CheMPS2::DMRG::saveMPS(const std::string name, TensorT ** MPSlocation, SyBookkeeper * BKlocation, bool isConverged) const{ //The hdf5 file hid_t file_id = H5Fcreate(name.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); //Whether the MPS was converged or not hid_t group_id = H5Gcreate(file_id, "/Convergence", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); hsize_t dimarray = 1; //One integer hid_t dataspace_id = H5Screate_simple(1, &dimarray, NULL); hid_t dataset_id = H5Dcreate(group_id, "Converged_yn", H5T_STD_I32LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); int toWrite = (isConverged)?1:0; H5Dwrite(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &toWrite); H5Dclose(dataset_id); H5Sclose(dataspace_id); H5Gclose(group_id); //The current virtual dimensions for (int bound=0; bound<=BKlocation->gL(); bound++){ for (int N=BKlocation->gNmin(bound); N<=BKlocation->gNmax(bound); N++){ for (int TwoS=BKlocation->gTwoSmin(bound,N); TwoS<=BKlocation->gTwoSmax(bound,N); TwoS+=2){ for (int Irrep=0; IrrepgetNumberOfIrreps(); Irrep++){ std::stringstream sstream; sstream << "/VirtDim_" << bound << "_" << N << "_" << TwoS << "_" << Irrep; hid_t group_id2 = H5Gcreate(file_id, sstream.str().c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); hsize_t dimarray2 = 1; //One integer hid_t dataspace_id2 = H5Screate_simple(1, &dimarray2, NULL); hid_t dataset_id2 = H5Dcreate(group_id2, "Value", H5T_STD_I32LE, dataspace_id2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); int toWrite2 = BKlocation->gCurrentDim(bound,N,TwoS,Irrep); H5Dwrite(dataset_id2, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &toWrite2); H5Dclose(dataset_id2); H5Sclose(dataspace_id2); H5Gclose(group_id2); } } } } //The MPS for (int site=0; sitegL(); site++){ std::stringstream sstream; sstream << "/MPS_" << site; hid_t group_id3 = H5Gcreate(file_id, sstream.str().c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); hsize_t dimarray3 = MPSlocation[site]->gKappa2index(MPSlocation[site]->gNKappa()); //An array of doubles hid_t dataspace_id3 = H5Screate_simple(1, &dimarray3, NULL); hid_t dataset_id3 = H5Dcreate(group_id3, "Values", H5T_IEEE_F64LE, dataspace_id3, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); H5Dwrite(dataset_id3, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, MPSlocation[site]->gStorage()); H5Dclose(dataset_id3); H5Sclose(dataspace_id3); H5Gclose(group_id3); } H5Fclose(file_id); } void CheMPS2::DMRG::loadDIM(const std::string name, SyBookkeeper * BKlocation){ //The hdf5 file hid_t file_id = H5Fopen(name.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); //The current virtual dimensions for (int bound=0; bound<=BKlocation->gL(); bound++){ for (int N=BKlocation->gNmin(bound); N<=BKlocation->gNmax(bound); N++){ for (int TwoS=BKlocation->gTwoSmin(bound,N); TwoS<=BKlocation->gTwoSmax(bound,N); TwoS+=2){ for (int Irrep=0; IrrepgetNumberOfIrreps(); Irrep++){ std::stringstream sstream; sstream << "/VirtDim_" << bound << "_" << N << "_" << TwoS << "_" << Irrep; hid_t group_id2 = H5Gopen(file_id, sstream.str().c_str(), H5P_DEFAULT); hid_t dataset_id2 = H5Dopen(group_id2, "Value", H5P_DEFAULT); int toRead; H5Dread(dataset_id2, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &toRead); BKlocation->SetDim(bound, N, TwoS, Irrep, toRead); H5Dclose(dataset_id2); H5Gclose(group_id2); } } } } H5Fclose(file_id); } void CheMPS2::DMRG::loadMPS(const std::string name, TensorT ** MPSlocation, bool * isConverged){ //The hdf5 file hid_t file_id = H5Fopen(name.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); //Whether the MPS was converged or not hid_t group_id = H5Gopen(file_id, "/Convergence", H5P_DEFAULT); hid_t dataset_id = H5Dopen(group_id, "Converged_yn", H5P_DEFAULT); int toRead; H5Dread(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &toRead); isConverged[0] = (toRead==0)?false:true; H5Dclose(dataset_id); H5Gclose(group_id); //The MPS for (int site=0; sitegStorage()); H5Dclose(dataset_id3); H5Gclose(group_id3); } H5Fclose(file_id); } void CheMPS2::DMRG::deleteStoredMPS(){ std::stringstream thestream; thestream << "rm " << CheMPS2::DMRG_MPS_storage_prefix << "*.h5"; int info = system(thestream.str().c_str()); std::cout << "Info on DMRG::MPS rm call to system: " << info << std::endl; } CheMPS2-1.8.9/CheMPS2/DMRGoperators.cpp000066400000000000000000002062571336564451100172530ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include "DMRG.h" #include "Lapack.h" #include "MPIchemps2.h" #include "Special.h" void CheMPS2::DMRG::updateMovingRightSafeFirstTime(const int cnt){ if (isAllocated[cnt]==2){ deleteTensors(cnt, false); isAllocated[cnt]=0; } if (isAllocated[cnt]==0){ allocateTensors(cnt, true); isAllocated[cnt]=1; } updateMovingRight(cnt); if (CheMPS2::DMRG_storeRenormOptrOnDisk){ if (cnt>0){ if (isAllocated[cnt-1]==1){ OperatorsOnDisk(cnt-1, true, true); deleteTensors(cnt-1, true); isAllocated[cnt-1]=0; } } } } void CheMPS2::DMRG::updateMovingLeftSafeFirstTime(const int cnt){ if (isAllocated[cnt]==1){ deleteTensors(cnt, true); isAllocated[cnt]=0; } if (isAllocated[cnt]==0){ allocateTensors(cnt, false); isAllocated[cnt]=2; } updateMovingLeft(cnt); if (CheMPS2::DMRG_storeRenormOptrOnDisk){ if (cnt+10){ if (isAllocated[cnt-1]==1){ OperatorsOnDisk(cnt-1, true, true); deleteTensors(cnt-1, true); isAllocated[cnt-1]=0; } } if (cnt+1=0){ if (isAllocated[cnt-1]==1){ deleteTensors(cnt-1, true); isAllocated[cnt-1]=0; } } if (cnt-2>=0){ if (isAllocated[cnt-2]==2){ deleteTensors(cnt-2, false); isAllocated[cnt-2]=0; } if (isAllocated[cnt-2]==0){ allocateTensors(cnt-2, true); isAllocated[cnt-2]=1; } OperatorsOnDisk(cnt-2, true, false); } } } void CheMPS2::DMRG::updateMovingRightSafe2DM(const int cnt){ if (isAllocated[cnt]==2){ deleteTensors(cnt, false); isAllocated[cnt]=0; } if (isAllocated[cnt]==0){ allocateTensors(cnt, true); isAllocated[cnt]=1; } updateMovingRight(cnt); if (CheMPS2::DMRG_storeRenormOptrOnDisk){ if (cnt>0){ if (isAllocated[cnt-1]==1){ OperatorsOnDisk(cnt-1, true, true); deleteTensors(cnt-1, true); isAllocated[cnt-1]=0; } } if (cnt+1=0){ if (isAllocated[cnt-1]==2){ deleteTensors(cnt-1, false); isAllocated[cnt-1]=0; } if (isAllocated[cnt-1]==0){ allocateTensors(cnt-1, true); isAllocated[cnt-1]=1; } OperatorsOnDisk(cnt-1, true, false); } } } void CheMPS2::DMRG::deleteAllBoundaryOperators(){ for (int cnt=0; cntgMaxDimAtBound( index ); const int dimR = denBK->gMaxDimAtBound( index + 1 ); #ifdef CHEMPS2_MPI_COMPILATION const int MPIRANK = MPIchemps2::mpi_rank(); #endif #pragma omp parallel { double * workmem = new double[ dimL * dimR ]; //Ltensors : all processes own all Ltensors #pragma omp for schedule(static) nowait for ( int cnt2 = 0; cnt2 < index + 1; cnt2++ ){ if ( cnt2 == 0 ){ Ltensors[ index ][ cnt2 ]->create( MPS[ index ] ); } else { Ltensors[ index ][ cnt2 ]->update( Ltensors[ index - 1 ][ cnt2 - 1 ], MPS[ index ], MPS[ index ], workmem ); } } // Two-operator tensors : certain processes own certain two-operator tensors const int k1 = index + 1; const int upperbound1 = ( k1 * ( k1 + 1 ) ) / 2; int result[ 2 ]; // After this parallel region, WAIT because F0,F1,S0,S1[ index ][ cnt2 ][ cnt3 == 0 ] is required for the complementary operators #ifdef CHEMPS2_MPI_COMPILATION #pragma omp for schedule(dynamic) #else #pragma omp for schedule(static) #endif for ( int global = 0; global < upperbound1; global++ ){ Special::invert_triangle_two( global, result ); const int cnt2 = index - result[ 1 ]; const int cnt3 = result[ 0 ]; #ifdef CHEMPS2_MPI_COMPILATION const int siteindex1 = index - cnt3 - cnt2; const int siteindex2 = index - cnt3; #endif if ( cnt3 == 0 ){ // Every MPI process owns the Operator[ index ][ cnt2 ][ cnt3 == 0 ] if ( cnt2 == 0 ){ F0tensors[ index ][ cnt2 ][ cnt3 ]->makenew( MPS[ index ] ); F1tensors[ index ][ cnt2 ][ cnt3 ]->makenew( MPS[ index ] ); S0tensors[ index ][ cnt2 ][ cnt3 ]->makenew( MPS[ index ] ); // S1[ index ][ 0 ][ cnt3 ] doesn't exist } else { F0tensors[ index ][ cnt2 ][ cnt3 ]->makenew( Ltensors[ index - 1 ][ cnt2 - 1 ], MPS[ index ], workmem ); F1tensors[ index ][ cnt2 ][ cnt3 ]->makenew( Ltensors[ index - 1 ][ cnt2 - 1 ], MPS[ index ], workmem ); S0tensors[ index ][ cnt2 ][ cnt3 ]->makenew( Ltensors[ index - 1 ][ cnt2 - 1 ], MPS[ index ], workmem ); S1tensors[ index ][ cnt2 ][ cnt3 ]->makenew( Ltensors[ index - 1 ][ cnt2 - 1 ], MPS[ index ], workmem ); } } else { #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_cdf( L, siteindex1, siteindex2 ) == MPIRANK ) #endif { F0tensors[ index ][ cnt2 ][ cnt3 ]->update( F0tensors[ index - 1 ][ cnt2 ][ cnt3 - 1 ], MPS[ index ], MPS[ index ], workmem ); F1tensors[ index ][ cnt2 ][ cnt3 ]->update( F1tensors[ index - 1 ][ cnt2 ][ cnt3 - 1 ], MPS[ index ], MPS[ index ], workmem ); } #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_absigma( siteindex1, siteindex2 ) == MPIRANK ) #endif { S0tensors[ index ][ cnt2 ][ cnt3 ]->update( S0tensors[ index - 1 ][ cnt2 ][ cnt3 - 1 ], MPS[ index ], MPS[ index ], workmem ); if ( cnt2 > 0 ){ S1tensors[ index ][ cnt2 ][ cnt3 ]->update( S1tensors[ index - 1 ][ cnt2 ][ cnt3 - 1 ], MPS[ index ], MPS[ index ], workmem ); } } } } // Complementary two-operator tensors : certain processes own certain complementary two-operator tensors const int k2 = L - 1 - index; const int upperbound2 = ( k2 * ( k2 + 1 ) ) / 2; #ifdef CHEMPS2_MPI_COMPILATION #pragma omp for schedule(dynamic) #else #pragma omp for schedule(static) nowait #endif for ( int global = 0; global < upperbound2; global++ ){ Special::invert_triangle_two( global, result ); const int cnt2 = k2 - 1 - result[ 1 ]; const int cnt3 = result[ 0 ]; const int siteindex1 = index + 1 + cnt3; const int siteindex2 = index + 1 + cnt2 + cnt3; const int irrep_prod = Irreps::directProd( denBK->gIrrep( siteindex1 ), denBK->gIrrep( siteindex2 ) ); #ifdef CHEMPS2_MPI_COMPILATION const bool do_absigma = ( MPIchemps2::owner_absigma( siteindex1, siteindex2 ) == MPIRANK ); const bool do_cdf = ( MPIchemps2::owner_cdf( L, siteindex1, siteindex2 ) == MPIRANK ); #endif if ( index == 0 ){ #ifdef CHEMPS2_MPI_COMPILATION if ( do_absigma ) #endif { Atensors[ index ][ cnt2 ][ cnt3 ]->clear(); if ( cnt2 > 0 ){ Btensors[ index ][ cnt2 ][ cnt3 ]->clear(); } } #ifdef CHEMPS2_MPI_COMPILATION if ( do_cdf ) #endif { Ctensors[ index ][ cnt2 ][ cnt3 ]->clear(); Dtensors[ index ][ cnt2 ][ cnt3 ]->clear(); } } else { #ifdef CHEMPS2_MPI_COMPILATION if ( do_absigma ) #endif { Atensors[ index ][ cnt2 ][ cnt3 ]->update( Atensors[ index - 1 ][ cnt2 ][ cnt3 + 1 ], MPS[ index ], MPS[ index ], workmem ); if ( cnt2 > 0 ){ Btensors[ index ][ cnt2 ][ cnt3 ]->update( Btensors[ index - 1 ][ cnt2 ][ cnt3 + 1 ], MPS[ index ], MPS[ index ], workmem ); } } #ifdef CHEMPS2_MPI_COMPILATION if ( do_cdf ) #endif { Ctensors[ index ][ cnt2 ][ cnt3 ]->update( Ctensors[ index - 1 ][ cnt2 ][ cnt3 + 1 ], MPS[ index ], MPS[ index ], workmem ); Dtensors[ index ][ cnt2 ][ cnt3 ]->update( Dtensors[ index - 1 ][ cnt2 ][ cnt3 + 1 ], MPS[ index ], MPS[ index ], workmem ); } } for ( int num = 0; num < index + 1; num++ ){ if ( irrep_prod == S0tensors[ index ][ num ][ 0 ]->get_irrep() ){ // Then the matrix elements are not 0 due to symm. #ifdef CHEMPS2_MPI_COMPILATION if ( do_absigma ) #endif { double alpha = Prob->gMxElement( index - num, index, siteindex1, siteindex2 ); if (( cnt2 == 0 ) && ( num == 0 )){ alpha *= 0.5; } if (( cnt2 > 0 ) && ( num > 0 )){ alpha += Prob->gMxElement( index - num, index, siteindex2, siteindex1 ); } Atensors[ index ][ cnt2 ][ cnt3 ]->daxpy( alpha, S0tensors[ index ][ num ][ 0 ] ); if (( num > 0 ) && ( cnt2 > 0 )){ alpha = Prob->gMxElement( index - num, index, siteindex1, siteindex2 ) - Prob->gMxElement( index - num, index, siteindex2, siteindex1 ); Btensors[ index ][ cnt2 ][ cnt3 ]->daxpy( alpha, S1tensors[ index ][ num ][ 0 ]); } } #ifdef CHEMPS2_MPI_COMPILATION if ( do_cdf ) #endif { double alpha = 2 * Prob->gMxElement( index - num, siteindex1, index, siteindex2 ) - Prob->gMxElement( index - num, siteindex1, siteindex2, index ); Ctensors[ index ][ cnt2 ][ cnt3 ]->daxpy( alpha, F0tensors[ index ][ num ][ 0 ] ); alpha = - Prob->gMxElement( index - num, siteindex1, siteindex2, index ); // Second line for Ctensors Dtensors[ index ][ cnt2 ][ cnt3 ]->daxpy( alpha, F1tensors[ index ][ num ][ 0 ] ); if ( num > 0 ){ alpha = 2 * Prob->gMxElement( index - num, siteindex2, index, siteindex1 ) - Prob->gMxElement( index - num, siteindex2, siteindex1, index ); Ctensors[ index ][ cnt2 ][ cnt3 ]->daxpy_transpose_tensorCD( alpha, F0tensors[ index ][ num ][ 0 ] ); alpha = - Prob->gMxElement( index - num, siteindex2, siteindex1, index ); // Second line for Ctensors Dtensors[ index ][ cnt2 ][ cnt3 ]->daxpy_transpose_tensorCD( alpha, F1tensors[ index ][ num ][ 0 ] ); } } } } } // Qtensors : certain processes own certain Qtensors --- You don't want to locally parallellize when sending and receiving buffers! #ifdef CHEMPS2_MPI_COMPILATION #pragma omp single #else #pragma omp for schedule(static) nowait #endif for ( int cnt2 = 0; cnt2 < L - 1 - index; cnt2++ ){ #ifdef CHEMPS2_MPI_COMPILATION const int siteindex = index + 1 + cnt2; // Corresponds to this site const int owner_q = MPIchemps2::owner_q( L, siteindex ); #endif if ( index == 0 ){ #ifdef CHEMPS2_MPI_COMPILATION if ( owner_q == MPIRANK ) #endif { Qtensors[ index ][ cnt2 ]->clear(); Qtensors[ index ][ cnt2 ]->AddTermSimple( MPS[ index ] ); } } else { #ifdef CHEMPS2_MPI_COMPILATION const int owner_absigma = MPIchemps2::owner_absigma( index, siteindex ); const int owner_cdf = MPIchemps2::owner_cdf( L, index, siteindex ); if (( owner_q == owner_absigma ) && ( owner_q == owner_cdf ) && ( owner_q == MPIRANK )){ // No MPI needed #endif double * workmemBIS = new double[ dimL * dimL ]; Qtensors[ index ][ cnt2 ]->update( Qtensors[ index - 1 ][ cnt2 + 1 ], MPS[ index ], MPS[ index ], workmem ); Qtensors[ index ][ cnt2 ]->AddTermSimple( MPS[ index ] ); Qtensors[ index ][ cnt2 ]->AddTermsL( Ltensors[ index - 1 ], MPS[ index ], workmemBIS, workmem ); Qtensors[ index ][ cnt2 ]->AddTermsAB( Atensors[ index - 1 ][ cnt2 + 1 ][ 0 ], Btensors[ index - 1 ][ cnt2 + 1 ][ 0 ], MPS[ index ], workmemBIS, workmem ); Qtensors[ index ][ cnt2 ]->AddTermsCD( Ctensors[ index - 1 ][ cnt2 + 1 ][ 0 ], Dtensors[ index - 1 ][ cnt2 + 1 ][ 0 ], MPS[ index ], workmemBIS, workmem ); delete [] workmemBIS; #ifdef CHEMPS2_MPI_COMPILATION } else { // There's going to have to be some communication if (( owner_q == MPIRANK ) || ( owner_absigma == MPIRANK ) || ( owner_cdf == MPIRANK )){ TensorQ * tempQ = new TensorQ( index + 1, denBK->gIrrep( siteindex ), true, denBK, Prob, siteindex ); tempQ->clear(); // Everyone creates his/her piece double * workmemBIS = new double[ dimL * dimL ]; if ( owner_q == MPIRANK ){ tempQ->update( Qtensors[ index - 1 ][ cnt2 + 1 ], MPS[ index ], MPS[ index ], workmem ); tempQ->AddTermSimple( MPS[ index ] ); tempQ->AddTermsL( Ltensors[ index - 1 ], MPS[ index ], workmemBIS, workmem ); } if ( owner_absigma == MPIRANK ){ tempQ->AddTermsAB( Atensors[ index - 1 ][ cnt2 + 1 ][ 0 ], Btensors[ index - 1 ][ cnt2 + 1 ][ 0 ], MPS[ index ], workmemBIS, workmem ); } if ( owner_cdf == MPIRANK ){ tempQ->AddTermsCD( Ctensors[ index - 1 ][ cnt2 + 1 ][ 0 ], Dtensors[ index - 1 ][ cnt2 + 1 ][ 0 ], MPS[ index ], workmemBIS, workmem ); } delete [] workmemBIS; // Add everything to owner_q's Qtensors[index][cnt2]: replace later with custom communication group? int inc = 1; int arraysize = tempQ->gKappa2index( tempQ->gNKappa() ); double alpha = 1.0; if ( owner_q == MPIRANK ){ dcopy_( &arraysize, tempQ->gStorage(), &inc, Qtensors[ index ][ cnt2 ]->gStorage(), &inc ); } if ( owner_q != owner_absigma ){ MPIchemps2::sendreceive_tensor( tempQ, owner_absigma, owner_q, 2 * siteindex ); if ( owner_q == MPIRANK ){ daxpy_( &arraysize, &alpha, tempQ->gStorage(), &inc, Qtensors[ index ][ cnt2 ]->gStorage(), &inc ); } } if (( owner_q != owner_cdf ) && ( owner_absigma != owner_cdf )){ MPIchemps2::sendreceive_tensor( tempQ, owner_cdf, owner_q, 2 * siteindex + 1 ); if ( owner_q == MPIRANK ){ daxpy_( &arraysize, &alpha, tempQ->gStorage(), &inc, Qtensors[ index ][ cnt2 ]->gStorage(), &inc ); } } delete tempQ; } } #endif } } delete [] workmem; } //Xtensors #ifdef CHEMPS2_MPI_COMPILATION const int owner_x = MPIchemps2::owner_x(); #endif if ( index == 0 ){ #ifdef CHEMPS2_MPI_COMPILATION if ( owner_x == MPIRANK ) #endif { Xtensors[ index ]->update( MPS[ index ] ); } } else { #ifdef CHEMPS2_MPI_COMPILATION //Make sure that owner_x has all required tensors to construct X. Not as optimal as Q-tensor case, but easier hack. const int owner_q = MPIchemps2::owner_q( L, index ); const int owner_absigma = MPIchemps2::owner_absigma( index, index ); const int owner_cdf = MPIchemps2::owner_cdf( L, index, index ); const int Idiff = 0; // Irreps::directProd( denBK->gIrrep( index ), denBK->gIrrep( index ) ); if ( owner_x != owner_q ){ if ( owner_x == MPIRANK ){ Qtensors[ index - 1 ][ 0 ] = new TensorQ( index, denBK->gIrrep( index ), true, denBK, Prob, index ); } if (( owner_x == MPIRANK ) || ( owner_q == MPIRANK )){ MPIchemps2::sendreceive_tensor( Qtensors[ index - 1 ][ 0 ], owner_q, owner_x, 3 * L + 3 ); } } if ( owner_x != owner_absigma ){ if ( owner_x == MPIRANK ){ Atensors[ index - 1 ][ 0 ][ 0 ] = new TensorOperator( index, 0, 2, Idiff, true, true, false, denBK, denBK ); } if (( owner_x == MPIRANK ) || ( owner_absigma == MPIRANK )){ MPIchemps2::sendreceive_tensor( Atensors[ index - 1 ][ 0 ][ 0 ], owner_absigma, owner_x, 3 * L + 4 ); } } if ( owner_x != owner_cdf ){ if ( owner_x == MPIRANK ){ Ctensors[ index - 1 ][ 0 ][ 0 ] = new TensorOperator( index, 0, 0, Idiff, true, true, false, denBK, denBK ); Dtensors[ index - 1 ][ 0 ][ 0 ] = new TensorOperator( index, 2, 0, Idiff, true, true, false, denBK, denBK ); } if (( owner_x == MPIRANK ) || ( owner_cdf == MPIRANK )){ MPIchemps2::sendreceive_tensor( Ctensors[ index - 1 ][ 0 ][ 0 ], owner_cdf, owner_x, 3 * L + 5 ); MPIchemps2::sendreceive_tensor( Dtensors[ index - 1 ][ 0 ][ 0 ], owner_cdf, owner_x, 3 * L + 6 ); } } if ( owner_x == MPIRANK ){ #endif Xtensors[ index ]->update( MPS[ index ], Ltensors[ index - 1 ], Xtensors[ index - 1 ], Qtensors[ index - 1 ][ 0 ], Atensors[ index - 1 ][ 0 ][ 0 ], Ctensors[ index - 1 ][ 0 ][ 0 ], Dtensors[ index - 1 ][ 0 ][ 0 ] ); #ifdef CHEMPS2_MPI_COMPILATION if ( owner_x != owner_q ){ delete Qtensors[ index - 1 ][ 0 ]; } if ( owner_x != owner_absigma ){ delete Atensors[ index - 1 ][ 0 ][ 0 ]; } if ( owner_x != owner_cdf ){ delete Ctensors[ index - 1 ][ 0 ][ 0 ]; delete Dtensors[ index - 1 ][ 0 ][ 0 ]; } } #endif } //Otensors : certain processes own certain excitations if ( Exc_activated ){ for ( int state = 0; state < nStates-1; state++ ){ #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_specific_excitation( L, state ) == MPIRANK ) #endif { if ( index == 0 ){ Exc_Overlaps[ state ][ index ]->create( MPS[ index ], Exc_MPSs[ state ][ index ] ); } else { Exc_Overlaps[ state ][ index ]->update_ownmem( MPS[ index ], Exc_MPSs[ state ][ index ], Exc_Overlaps[ state ][ index - 1 ] ); } } } } gettimeofday( &end, NULL ); timings[ CHEMPS2_TIME_TENS_CALC ] += ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); } void CheMPS2::DMRG::updateMovingLeft( const int index ){ struct timeval start, end; gettimeofday( &start, NULL ); const int dimL = denBK->gMaxDimAtBound( index + 1 ); const int dimR = denBK->gMaxDimAtBound( index + 2 ); #ifdef CHEMPS2_MPI_COMPILATION const int MPIRANK = MPIchemps2::mpi_rank(); #endif #pragma omp parallel { double * workmem = new double[ dimL * dimR ]; // Ltensors : all processes own all Ltensors #pragma omp for schedule(static) nowait for ( int cnt2 = 0; cnt2 < L - 1 - index; cnt2++ ){ if ( cnt2 == 0 ){ Ltensors[ index ][ cnt2 ]->create( MPS[ index + 1 ] ); } else { Ltensors[ index ][ cnt2 ]->update( Ltensors[ index + 1 ][ cnt2 - 1 ], MPS[ index + 1 ], MPS[ index + 1 ], workmem ); } } // Two-operator tensors : certain processes own certain two-operator tensors const int k1 = L - 1 - index; const int upperbound1 = ( k1 * ( k1 + 1 ) ) / 2; int result[ 2 ]; // After this parallel region, WAIT because F0,F1,S0,S1[ index ][ cnt2 ][ cnt3 == 0 ] is required for the complementary operators #ifdef CHEMPS2_MPI_COMPILATION #pragma omp for schedule(dynamic) #else #pragma omp for schedule(static) #endif for ( int global = 0; global < upperbound1; global++ ){ Special::invert_triangle_two( global, result ); const int cnt2 = k1 - 1 - result[ 1 ]; const int cnt3 = result[ 0 ]; #ifdef CHEMPS2_MPI_COMPILATION const int siteindex1 = index + 1 + cnt3; const int siteindex2 = index + 1 + cnt2 + cnt3; #endif if ( cnt3 == 0 ){ // Every MPI process owns the Operator[ index ][ cnt2 ][ cnt3==0 ] if ( cnt2 == 0 ){ F0tensors[ index ][ cnt2 ][ cnt3 ]->makenew( MPS[ index + 1 ] ); F1tensors[ index ][ cnt2 ][ cnt3 ]->makenew( MPS[ index + 1 ] ); S0tensors[ index ][ cnt2 ][ cnt3 ]->makenew( MPS[ index + 1 ] ); //S1[index][0] doesn't exist } else { F0tensors[ index ][ cnt2 ][ cnt3 ]->makenew( Ltensors[ index + 1 ][ cnt2 - 1 ], MPS[ index + 1 ], workmem ); F1tensors[ index ][ cnt2 ][ cnt3 ]->makenew( Ltensors[ index + 1 ][ cnt2 - 1 ], MPS[ index + 1 ], workmem ); S0tensors[ index ][ cnt2 ][ cnt3 ]->makenew( Ltensors[ index + 1 ][ cnt2 - 1 ], MPS[ index + 1 ], workmem ); S1tensors[ index ][ cnt2 ][ cnt3 ]->makenew( Ltensors[ index + 1 ][ cnt2 - 1 ], MPS[ index + 1 ], workmem ); } } else { #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_cdf( L, siteindex1, siteindex2 ) == MPIRANK ) #endif { F0tensors[ index ][ cnt2 ][ cnt3 ]->update( F0tensors[ index + 1 ][ cnt2 ][ cnt3 - 1 ], MPS[ index + 1 ], MPS[ index + 1 ], workmem ); F1tensors[ index ][ cnt2 ][ cnt3 ]->update( F1tensors[ index + 1 ][ cnt2 ][ cnt3 - 1 ], MPS[ index + 1 ], MPS[ index + 1 ], workmem ); } #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_absigma( siteindex1, siteindex2 ) == MPIRANK ) #endif { S0tensors[ index ][ cnt2 ][ cnt3 ]->update( S0tensors[ index + 1 ][ cnt2 ][ cnt3 - 1 ], MPS[ index + 1 ], MPS[ index + 1 ], workmem ); if ( cnt2 > 0 ){ S1tensors[ index ][ cnt2 ][ cnt3 ]->update( S1tensors[ index + 1 ][ cnt2 ][ cnt3 - 1 ], MPS[ index + 1 ], MPS[ index + 1 ], workmem ); } } } } // Complementary two-operator tensors : certain processes own certain complementary two-operator tensors const int k2 = index + 1; const int upperbound2 = ( k2 * ( k2 + 1 ) ) / 2; #ifdef CHEMPS2_MPI_COMPILATION #pragma omp for schedule(dynamic) #else #pragma omp for schedule(static) nowait #endif for ( int global = 0; global < upperbound2; global++ ){ Special::invert_triangle_two( global, result ); const int cnt2 = k2 - 1 - result[ 1 ]; const int cnt3 = result[ 0 ]; const int siteindex1 = index - cnt3 - cnt2; const int siteindex2 = index - cnt3; const int irrep_prod = Irreps::directProd( denBK->gIrrep( siteindex1 ), denBK->gIrrep( siteindex2 ) ); #ifdef CHEMPS2_MPI_COMPILATION const bool do_absigma = ( MPIchemps2::owner_absigma( siteindex1, siteindex2 ) == MPIRANK ); const bool do_cdf = ( MPIchemps2::owner_cdf( L, siteindex1, siteindex2 ) == MPIRANK ); #endif if ( index == L - 2 ){ #ifdef CHEMPS2_MPI_COMPILATION if ( do_absigma ) #endif { Atensors[ index ][ cnt2 ][ cnt3 ]->clear(); if ( cnt2 > 0 ){ Btensors[ index ][ cnt2 ][ cnt3 ]->clear(); } } #ifdef CHEMPS2_MPI_COMPILATION if ( do_cdf ) #endif { Ctensors[ index ][ cnt2 ][ cnt3 ]->clear(); Dtensors[ index ][ cnt2 ][ cnt3 ]->clear(); } } else { #ifdef CHEMPS2_MPI_COMPILATION if ( do_absigma ) #endif { Atensors[ index ][ cnt2 ][ cnt3 ]->update( Atensors[ index + 1 ][ cnt2 ][ cnt3 + 1 ], MPS[ index + 1 ], MPS[ index + 1 ], workmem ); if ( cnt2 > 0 ){ Btensors[ index ][ cnt2 ][ cnt3 ]->update( Btensors[ index + 1 ][ cnt2 ][ cnt3 + 1 ], MPS[ index + 1 ], MPS[ index + 1 ], workmem ); } } #ifdef CHEMPS2_MPI_COMPILATION if ( do_cdf ) #endif { Ctensors[ index ][ cnt2 ][ cnt3 ]->update( Ctensors[ index + 1 ][ cnt2 ][ cnt3 + 1 ], MPS[ index + 1 ], MPS[ index + 1 ], workmem ); Dtensors[ index ][ cnt2 ][ cnt3 ]->update( Dtensors[ index + 1 ][ cnt2 ][ cnt3 + 1 ], MPS[ index + 1 ], MPS[ index + 1 ], workmem ); } } for ( int num = 0; num < L - index - 1; num++ ){ if ( irrep_prod == S0tensors[ index ][ num ][ 0 ]->get_irrep() ){ // Then the matrix elements are not 0 due to symm. #ifdef CHEMPS2_MPI_COMPILATION if ( do_absigma ) #endif { double alpha = Prob->gMxElement( siteindex1, siteindex2, index + 1, index + 1 + num ); if (( cnt2 == 0 ) && ( num == 0 )) alpha *= 0.5; if (( cnt2 > 0 ) && ( num > 0 )) alpha += Prob->gMxElement( siteindex1, siteindex2, index + 1 + num, index + 1 ); Atensors[ index ][ cnt2 ][ cnt3 ]->daxpy( alpha, S0tensors[ index ][ num ][ 0 ]); if (( num > 0 ) && ( cnt2 > 0 )){ alpha = Prob->gMxElement( siteindex1, siteindex2, index + 1, index + 1 + num ) - Prob->gMxElement( siteindex1, siteindex2, index + 1 + num, index + 1 ); Btensors[ index ][ cnt2 ][ cnt3 ]->daxpy( alpha, S1tensors[ index ][ num ][ 0 ] ); } } #ifdef CHEMPS2_MPI_COMPILATION if ( do_cdf ) #endif { double alpha = 2 * Prob->gMxElement( siteindex1, index + 1, siteindex2, index + 1 + num ) - Prob->gMxElement( siteindex1, index + 1, index + 1 + num, siteindex2 ); Ctensors[ index ][ cnt2 ][ cnt3 ]->daxpy( alpha, F0tensors[ index ][ num ][ 0 ]); alpha = - Prob->gMxElement( siteindex1, index + 1, index + 1 + num, siteindex2 ); // Second line for Ctensors Dtensors[ index ][ cnt2 ][ cnt3 ]->daxpy( alpha, F1tensors[ index ][ num ][ 0 ]); if ( num > 0 ){ alpha = 2 * Prob->gMxElement( siteindex1, index + 1 + num, siteindex2, index + 1 ) - Prob->gMxElement( siteindex1, index + 1 + num, index + 1, siteindex2 ); Ctensors[ index ][ cnt2 ][ cnt3 ]->daxpy_transpose_tensorCD( alpha, F0tensors[ index ][ num ][ 0 ] ); alpha = - Prob->gMxElement( siteindex1, index + 1 + num, index + 1, siteindex2 ); // Second line for Ctensors Dtensors[ index ][ cnt2 ][ cnt3 ]->daxpy_transpose_tensorCD( alpha, F1tensors[ index ][ num ][ 0 ] ); } } } } } // Qtensors : certain processes own certain Qtensors --- You don't want to locally parallellize when sending and receiving buffers! #ifdef CHEMPS2_MPI_COMPILATION #pragma omp single #else #pragma omp for schedule(static) nowait #endif for ( int cnt2 = 0; cnt2 < index + 1; cnt2++ ){ #ifdef CHEMPS2_MPI_COMPILATION const int siteindex = index - cnt2; // Corresponds to this site const int owner_q = MPIchemps2::owner_q( L, siteindex ); #endif if ( index == L - 2 ){ #ifdef CHEMPS2_MPI_COMPILATION if ( owner_q == MPIRANK ) #endif { Qtensors[ index ][ cnt2 ]->clear(); Qtensors[ index ][ cnt2 ]->AddTermSimple( MPS[ index + 1 ] ); } } else { #ifdef CHEMPS2_MPI_COMPILATION const int owner_absigma = MPIchemps2::owner_absigma( siteindex, index + 1 ); const int owner_cdf = MPIchemps2::owner_cdf( L, siteindex, index + 1 ); if (( owner_q == owner_absigma ) && ( owner_q == owner_cdf ) && ( owner_q == MPIRANK )){ // No MPI needed #endif double * workmemBIS = new double[ dimR * dimR ]; Qtensors[ index ][ cnt2 ]->update( Qtensors[ index + 1 ][ cnt2 + 1 ], MPS[ index + 1 ], MPS[ index + 1 ], workmem ); Qtensors[ index ][ cnt2 ]->AddTermSimple( MPS[ index + 1 ] ); Qtensors[ index ][ cnt2 ]->AddTermsL( Ltensors[ index + 1 ], MPS[ index + 1 ], workmemBIS, workmem ); Qtensors[ index ][ cnt2 ]->AddTermsAB( Atensors[ index + 1 ][ cnt2 + 1 ][ 0 ], Btensors[ index + 1 ][ cnt2 + 1 ][ 0 ], MPS[ index + 1 ], workmemBIS, workmem ); Qtensors[ index ][ cnt2 ]->AddTermsCD( Ctensors[ index + 1 ][ cnt2 + 1 ][ 0 ], Dtensors[ index + 1 ][ cnt2 + 1 ][ 0 ], MPS[ index + 1 ], workmemBIS, workmem ); delete [] workmemBIS; #ifdef CHEMPS2_MPI_COMPILATION } else { // There's going to have to be some communication if (( owner_q == MPIRANK ) || ( owner_absigma == MPIRANK ) || ( owner_cdf == MPIRANK )){ TensorQ * tempQ = new TensorQ( index + 1, denBK->gIrrep( siteindex ), false, denBK, Prob, siteindex ); tempQ->clear(); // Everyone creates his/her piece double * workmemBIS = new double[ dimR * dimR ]; if ( owner_q == MPIRANK ){ tempQ->update( Qtensors[ index + 1 ][ cnt2 + 1 ], MPS[ index + 1 ], MPS[ index + 1 ], workmem ); tempQ->AddTermSimple( MPS[ index + 1 ] ); tempQ->AddTermsL( Ltensors[ index + 1 ], MPS[ index + 1 ], workmemBIS, workmem ); } if ( owner_absigma == MPIRANK ){ tempQ->AddTermsAB( Atensors[ index + 1 ][ cnt2 + 1 ][ 0 ], Btensors[ index + 1 ][ cnt2 + 1 ][ 0 ], MPS[ index + 1 ], workmemBIS, workmem ); } if ( owner_cdf == MPIRANK ){ tempQ->AddTermsCD( Ctensors[ index + 1 ][ cnt2 + 1 ][ 0 ], Dtensors[ index + 1 ][ cnt2 + 1 ][ 0 ], MPS[ index + 1 ], workmemBIS, workmem ); } delete [] workmemBIS; // Add everything to owner_q's Qtensors[index][cnt2]: replace later with custom communication group? int inc = 1; int arraysize = tempQ->gKappa2index( tempQ->gNKappa() ); double alpha = 1.0; if ( owner_q == MPIRANK ){ dcopy_( &arraysize, tempQ->gStorage(), &inc, Qtensors[index][cnt2]->gStorage(), &inc ); } if ( owner_q != owner_absigma ){ MPIchemps2::sendreceive_tensor( tempQ, owner_absigma, owner_q, 2 * siteindex ); if ( owner_q == MPIRANK ){ daxpy_( &arraysize, &alpha, tempQ->gStorage(), &inc, Qtensors[ index ][ cnt2 ]->gStorage(), &inc ); } } if (( owner_q != owner_cdf ) && ( owner_absigma != owner_cdf )){ MPIchemps2::sendreceive_tensor( tempQ, owner_cdf, owner_q, 2 * siteindex + 1 ); if ( owner_q == MPIRANK ){ daxpy_( &arraysize, &alpha, tempQ->gStorage(), &inc, Qtensors[ index ][ cnt2 ]->gStorage(), &inc ); } } delete tempQ; } } #endif } } delete [] workmem; } //Xtensors #ifdef CHEMPS2_MPI_COMPILATION const int owner_x = MPIchemps2::owner_x(); #endif if ( index == L - 2 ){ #ifdef CHEMPS2_MPI_COMPILATION if ( owner_x == MPIRANK ) #endif { Xtensors[ index ]->update( MPS[ index + 1 ] ); } } else { #ifdef CHEMPS2_MPI_COMPILATION //Make sure that owner_x has all required tensors to construct X. Not as optimal as Q-tensor case, but easier hack. const int owner_q = MPIchemps2::owner_q( L, index + 1 ); const int owner_absigma = MPIchemps2::owner_absigma( index + 1, index + 1 ); const int owner_cdf = MPIchemps2::owner_cdf( L, index + 1, index + 1 ); const int Idiff = 0; // Irreps::directProd( denBK->gIrrep( index + 1 ), denBK->gIrrep( index + 1 ) ); if ( owner_x != owner_q ){ if ( owner_x == MPIRANK ){ Qtensors[ index + 1 ][ 0 ] = new TensorQ( index + 2, denBK->gIrrep( index + 1 ), false, denBK, Prob, index + 1 ); } if (( owner_x == MPIRANK ) || ( owner_q == MPIRANK )){ MPIchemps2::sendreceive_tensor( Qtensors[ index + 1 ][ 0 ], owner_q, owner_x, 3 * L + 3 ); } } if ( owner_x != owner_absigma ){ if ( owner_x == MPIRANK ){ Atensors[ index + 1 ][ 0 ][ 0 ] = new TensorOperator( index + 2, 0, 2, Idiff, false, true, false, denBK, denBK ); } if (( owner_x == MPIRANK ) || ( owner_absigma == MPIRANK )){ MPIchemps2::sendreceive_tensor( Atensors[ index + 1 ][ 0 ][ 0 ], owner_absigma, owner_x, 3 * L + 4 ); } } if ( owner_x != owner_cdf ){ if ( owner_x == MPIRANK ){ Ctensors[ index + 1 ][ 0 ][ 0 ] = new TensorOperator( index + 2, 0, 0, Idiff, false, true, false, denBK, denBK ); Dtensors[ index + 1 ][ 0 ][ 0 ] = new TensorOperator( index + 2, 2, 0, Idiff, false, false, false, denBK, denBK ); } if (( owner_x == MPIRANK ) || ( owner_cdf == MPIRANK )){ MPIchemps2::sendreceive_tensor( Ctensors[ index + 1 ][ 0 ][ 0 ], owner_cdf, owner_x, 3 * L + 5 ); MPIchemps2::sendreceive_tensor( Dtensors[ index + 1 ][ 0 ][ 0 ], owner_cdf, owner_x, 3 * L + 6 ); } } if ( owner_x == MPIRANK ){ #endif Xtensors[ index ]->update( MPS[ index + 1 ], Ltensors[ index + 1 ], Xtensors[ index + 1 ], Qtensors[ index + 1 ][ 0 ], Atensors[ index + 1 ][ 0 ][ 0 ], Ctensors[ index + 1 ][ 0 ][ 0 ], Dtensors[ index + 1 ][ 0 ][ 0 ] ); #ifdef CHEMPS2_MPI_COMPILATION if ( owner_x != owner_q ){ delete Qtensors[ index + 1 ][ 0 ]; } if ( owner_x != owner_absigma ){ delete Atensors[ index + 1 ][ 0 ][ 0 ]; } if ( owner_x != owner_cdf ){ delete Ctensors[ index + 1 ][ 0 ][ 0 ]; delete Dtensors[ index + 1 ][ 0 ][ 0 ]; } } #endif } //Otensors if ( Exc_activated ){ for ( int state = 0; state < nStates - 1; state++ ){ #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_specific_excitation( L, state ) == MPIRANK ) #endif { if ( index == L - 2 ){ Exc_Overlaps[ state ][ index ]->create( MPS[ index + 1 ], Exc_MPSs[ state ][ index + 1 ] ); } else { Exc_Overlaps[ state ][ index ]->update_ownmem( MPS[ index + 1 ], Exc_MPSs[ state ][ index + 1 ], Exc_Overlaps[ state ][ index + 1 ] ); } } } } gettimeofday( &end, NULL ); timings[ CHEMPS2_TIME_TENS_CALC ] += ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); } void CheMPS2::DMRG::allocateTensors(const int index, const bool movingRight){ struct timeval start, end; gettimeofday(&start, NULL); #ifdef CHEMPS2_MPI_COMPILATION const int MPIRANK = MPIchemps2::mpi_rank(); #endif if (movingRight){ // Ltensors : all processes own all Ltensors // To right: Ltens[cnt][cnt2] = operator on site cnt-cnt2; at boundary cnt+1 Ltensors[ index ] = new TensorL * [ index + 1 ]; for ( int cnt2 = 0; cnt2 < index + 1; cnt2++ ){ Ltensors[ index ][ cnt2 ] = new TensorL( index + 1, denBK->gIrrep( index - cnt2 ), movingRight, denBK, denBK ); } //Two-operator tensors : certain processes own certain two-operator tensors //To right: F0tens[cnt][cnt2][cnt3] = operators on sites cnt-cnt3-cnt2 and cnt-cnt3; at boundary cnt+1 F0tensors[index] = new TensorF0 ** [index+1]; F1tensors[index] = new TensorF1 ** [index+1]; S0tensors[index] = new TensorS0 ** [index+1]; S1tensors[index] = new TensorS1 ** [index+1]; for (int cnt2=0; cnt2<(index+1); cnt2++){ F0tensors[index][cnt2] = new TensorF0 * [index-cnt2+1]; F1tensors[index][cnt2] = new TensorF1 * [index-cnt2+1]; S0tensors[index][cnt2] = new TensorS0 * [index-cnt2+1]; if (cnt2>0){ S1tensors[index][cnt2] = new TensorS1 * [index-cnt2+1]; } for (int cnt3=0; cnt3<(index-cnt2+1); cnt3++){ const int Iprod = Irreps::directProd(denBK->gIrrep(index-cnt2-cnt3),denBK->gIrrep(index-cnt3)); #ifdef CHEMPS2_MPI_COMPILATION if (( cnt3 == 0 ) || ( MPIchemps2::owner_cdf(L, index-cnt2-cnt3, index-cnt3) == MPIRANK )){ #endif F0tensors[index][cnt2][cnt3] = new TensorF0(index+1,Iprod,movingRight,denBK); F1tensors[index][cnt2][cnt3] = new TensorF1(index+1,Iprod,movingRight,denBK); #ifdef CHEMPS2_MPI_COMPILATION } else { F0tensors[index][cnt2][cnt3] = NULL; F1tensors[index][cnt2][cnt3] = NULL; } if (( cnt3 == 0 ) || ( MPIchemps2::owner_absigma(index-cnt2-cnt3, index-cnt3) == MPIRANK )){ #endif S0tensors[index][cnt2][cnt3] = new TensorS0(index+1,Iprod,movingRight,denBK); if (cnt2>0){ S1tensors[index][cnt2][cnt3] = new TensorS1(index+1,Iprod,movingRight,denBK); } #ifdef CHEMPS2_MPI_COMPILATION } else { S0tensors[index][cnt2][cnt3] = NULL; if (cnt2>0){ S1tensors[index][cnt2][cnt3] = NULL; } } #endif } } //Complementary two-operator tensors : certain processes own certain complementary two-operator tensors //To right: Atens[cnt][cnt2][cnt3] = operators on sites cnt+1+cnt3 and cnt+1+cnt2+cnt3; at boundary cnt+1 Atensors[index] = new TensorOperator ** [L-1-index]; Btensors[index] = new TensorOperator ** [L-1-index]; Ctensors[index] = new TensorOperator ** [L-1-index]; Dtensors[index] = new TensorOperator ** [L-1-index]; for (int cnt2=0; cnt20){ Btensors[index][cnt2] = new TensorOperator * [L-1-index-cnt2]; } Ctensors[index][cnt2] = new TensorOperator * [L-1-index-cnt2]; Dtensors[index][cnt2] = new TensorOperator * [L-1-index-cnt2]; for (int cnt3=0; cnt3gIrrep(index+1+cnt2+cnt3),denBK->gIrrep(index+1+cnt3)); #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_absigma(index+1+cnt3, index+1+cnt2+cnt3) == MPIRANK ){ #endif Atensors[index][cnt2][cnt3] = new TensorOperator( index+1, 0, 2, Idiff, movingRight, true, false, denBK, denBK ); if (cnt2>0){ Btensors[index][cnt2][cnt3] = new TensorOperator( index+1, 2, 2, Idiff, movingRight, true, false, denBK, denBK ); } #ifdef CHEMPS2_MPI_COMPILATION } else { Atensors[index][cnt2][cnt3] = NULL; if (cnt2>0){ Btensors[index][cnt2][cnt3] = NULL; } } if ( MPIchemps2::owner_cdf(L, index+1+cnt3, index+1+cnt2+cnt3) == MPIRANK ){ #endif Ctensors[index][cnt2][cnt3] = new TensorOperator( index+1, 0, 0, Idiff, movingRight, true, false, denBK, denBK ); Dtensors[index][cnt2][cnt3] = new TensorOperator( index+1, 2, 0, Idiff, movingRight, movingRight, false, denBK, denBK ); #ifdef CHEMPS2_MPI_COMPILATION } else { Ctensors[index][cnt2][cnt3] = NULL; Dtensors[index][cnt2][cnt3] = NULL; } #endif } } //Qtensors //To right: Qtens[cnt][cnt2] = operator on site cnt+1+cnt2; at boundary cnt+1 Qtensors[index] = new TensorQ * [L-1-index]; for (int cnt2=0; cnt2gIrrep(index+1+cnt2),movingRight,denBK,Prob,index+1+cnt2); #ifdef CHEMPS2_MPI_COMPILATION } else { Qtensors[index][cnt2] = NULL; } #endif } //Xtensors : a certain process owns the Xtensors #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_x() == MPIRANK ){ #endif Xtensors[index] = new TensorX(index+1,movingRight,denBK,Prob); #ifdef CHEMPS2_MPI_COMPILATION } else { Xtensors[index] = NULL; } #endif //Otensors : certain processes own certain excitations if (Exc_activated){ for (int state=0; stategIrrep( index + 1 + cnt2 ), movingRight, denBK, denBK ); } //Two-operator tensors : certain processes own certain two-operator tensors //To left: F0tens[cnt][cnt2][cnt3] = operators on sites cnt+1+cnt3 and cnt+1+cnt3+cnt2; at boundary cnt+1 F0tensors[index] = new TensorF0 ** [L-1-index]; F1tensors[index] = new TensorF1 ** [L-1-index]; S0tensors[index] = new TensorS0 ** [L-1-index]; S1tensors[index] = new TensorS1 ** [L-1-index]; for (int cnt2=0; cnt20){ S1tensors[index][cnt2] = new TensorS1 * [L-1-index-cnt2]; } for (int cnt3=0; cnt3gIrrep(index+1+cnt3),denBK->gIrrep(index+1+cnt2+cnt3)); #ifdef CHEMPS2_MPI_COMPILATION if (( cnt3 == 0 ) || ( MPIchemps2::owner_cdf(L, index+1+cnt3, index+1+cnt2+cnt3) == MPIRANK )){ #endif F0tensors[index][cnt2][cnt3] = new TensorF0(index+1,Iprod,movingRight,denBK); F1tensors[index][cnt2][cnt3] = new TensorF1(index+1,Iprod,movingRight,denBK); #ifdef CHEMPS2_MPI_COMPILATION } else { F0tensors[index][cnt2][cnt3] = NULL; F1tensors[index][cnt2][cnt3] = NULL; } if (( cnt3 == 0 ) || ( MPIchemps2::owner_absigma(index+1+cnt3, index+1+cnt2+cnt3) == MPIRANK )){ #endif S0tensors[index][cnt2][cnt3] = new TensorS0(index+1,Iprod,movingRight,denBK); if (cnt2>0){ S1tensors[index][cnt2][cnt3] = new TensorS1(index+1,Iprod,movingRight,denBK); } #ifdef CHEMPS2_MPI_COMPILATION } else { S0tensors[index][cnt2][cnt3] = NULL; if (cnt2>0){ S1tensors[index][cnt2][cnt3] = NULL; } } #endif } } //Complementary two-operator tensors : certain processes own certain complementary two-operator tensors //To left: Atens[cnt][cnt2][cnt3] = operators on sites cnt-cnt2-cnt3 and cnt-cnt3; at boundary cnt+1 Atensors[index] = new TensorOperator ** [index+1]; Btensors[index] = new TensorOperator ** [index+1]; Ctensors[index] = new TensorOperator ** [index+1]; Dtensors[index] = new TensorOperator ** [index+1]; for (int cnt2=0; cnt20){ Btensors[index][cnt2] = new TensorOperator * [index + 1 - cnt2]; } Ctensors[index][cnt2] = new TensorOperator * [index + 1 - cnt2]; Dtensors[index][cnt2] = new TensorOperator * [index + 1 - cnt2]; for (int cnt3=0; cnt3gIrrep(index-cnt2-cnt3),denBK->gIrrep(index-cnt3)); #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_absigma(index-cnt2-cnt3, index-cnt3) == MPIRANK ){ #endif Atensors[index][cnt2][cnt3] = new TensorOperator( index+1, 0, 2, Idiff, movingRight, true, false, denBK, denBK ); if (cnt2>0){ Btensors[index][cnt2][cnt3] = new TensorOperator( index+1, 2, 2, Idiff, movingRight, true, false, denBK, denBK ); } #ifdef CHEMPS2_MPI_COMPILATION } else { Atensors[index][cnt2][cnt3] = NULL; if (cnt2>0){ Btensors[index][cnt2][cnt3] = NULL; } } if ( MPIchemps2::owner_cdf(L, index-cnt2-cnt3, index-cnt3) == MPIRANK ){ #endif Ctensors[index][cnt2][cnt3] = new TensorOperator( index+1, 0, 0, Idiff, movingRight, true, false, denBK, denBK ); Dtensors[index][cnt2][cnt3] = new TensorOperator( index+1, 2, 0, Idiff, movingRight, movingRight, false, denBK, denBK ); #ifdef CHEMPS2_MPI_COMPILATION } else { Ctensors[index][cnt2][cnt3] = NULL; Dtensors[index][cnt2][cnt3] = NULL; } #endif } } //Qtensors : certain processes own certain Qtensors //To left: Qtens[cnt][cnt2] = operator on site cnt-cnt2; at boundary cnt+1 Qtensors[index] = new TensorQ*[index+1]; for (int cnt2=0; cnt2gIrrep(index-cnt2),movingRight,denBK,Prob,index-cnt2); #ifdef CHEMPS2_MPI_COMPILATION } else { Qtensors[index][cnt2] = NULL; } #endif } //Xtensors : a certain process owns the Xtensors #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_x() == MPIRANK ){ #endif Xtensors[index] = new TensorX(index+1,movingRight,denBK,Prob); #ifdef CHEMPS2_MPI_COMPILATION } else { Xtensors[index] = NULL; } #endif //Otensors : certain processes own certain excitations if ( Exc_activated ){ for ( int state = 0; state < nStates - 1; state++ ){ #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_specific_excitation( L, state ) == MPIRANK ) #endif { Exc_Overlaps[ state ][ index ] = new TensorO( index + 1, movingRight, denBK, Exc_BKs[ state ] ); } } } } gettimeofday(&end, NULL); timings[ CHEMPS2_TIME_TENS_ALLOC ] += (end.tv_sec - start.tv_sec) + 1e-6 * (end.tv_usec - start.tv_usec); } void CheMPS2::DMRG::MY_HDF5_READ_BATCH( const hid_t file_id, const int number, Tensor ** batch, const long long totalsize, const std::string tag ){ const hid_t group_id = H5Gopen(file_id, tag.c_str(), H5P_DEFAULT); const hsize_t dimarray = totalsize; const hid_t dataspace_id = H5Screate_simple(1, &dimarray, NULL); const hid_t dataset_id = H5Dopen(group_id, "storage", H5P_DEFAULT); long long offset = 0; for (int cnt=0; cntgKappa2index(batch[cnt]->gNKappa()); if ( tensor_size > 0 ){ const hsize_t start = offset; const hsize_t count = tensor_size; H5Sselect_hyperslab(dataspace_id, H5S_SELECT_SET, &start, NULL, &count, NULL); const hid_t memspace_id = H5Screate_simple(1, &count, NULL); H5Dread(dataset_id, H5T_NATIVE_DOUBLE, memspace_id, dataspace_id, H5P_DEFAULT, batch[cnt]->gStorage()); H5Sclose(memspace_id); offset += tensor_size; } } H5Dclose(dataset_id); H5Sclose(dataspace_id); H5Gclose(group_id); assert( totalsize == offset ); num_double_read_disk += totalsize; } void CheMPS2::DMRG::MY_HDF5_WRITE_BATCH( const hid_t file_id, const int number, Tensor ** batch, const long long totalsize, const std::string tag ){ const hid_t group_id = H5Gcreate(file_id, tag.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); const hsize_t dimarray = totalsize; const hid_t dataspace_id = H5Screate_simple(1, &dimarray, NULL); const hid_t dataset_id = H5Dcreate(group_id, "storage", H5T_NATIVE_DOUBLE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); /* Switch from H5T_IEEE_F64LE to H5T_NATIVE_DOUBLE to avoid processing of the doubles --> only MPS checkpoint is reused in between calculations anyway */ long long offset = 0; for (int cnt=0; cntgKappa2index(batch[cnt]->gNKappa()); if ( tensor_size > 0 ){ const hsize_t start = offset; const hsize_t count = tensor_size; H5Sselect_hyperslab(dataspace_id, H5S_SELECT_SET, &start, NULL, &count, NULL); const hid_t memspace_id = H5Screate_simple(1, &count, NULL); H5Dwrite(dataset_id, H5T_NATIVE_DOUBLE, memspace_id, dataspace_id, H5P_DEFAULT, batch[cnt]->gStorage()); H5Sclose(memspace_id); offset += tensor_size; } } H5Dclose(dataset_id); H5Sclose(dataspace_id); H5Gclose(group_id); assert( totalsize == offset ); num_double_write_disk += totalsize; } void CheMPS2::DMRG::OperatorsOnDisk(const int index, const bool movingRight, const bool store){ /* By working with hyperslabs and batches of tensors, there are exactly 11 groups which need to be written to the file ( 12 when there are excitations ). */ struct timeval start, end; gettimeofday(&start, NULL); const int Nbound = movingRight ? index+1 : L-1-index; const int Cbound = movingRight ? L-1-index : index+1; #ifdef CHEMPS2_MPI_COMPILATION const int MPIRANK = MPIchemps2::mpi_rank(); #endif std::stringstream thefilename; //The PID is different for each MPI process thefilename << tempfolder << "/" << CheMPS2::DMRG_OPERATOR_storage_prefix << thePID << "_index_" << index << ".h5"; //The hdf5 file const hid_t file_id = ( store ) ? H5Fcreate( thefilename.str().c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT ) : H5Fopen( thefilename.str().c_str(), H5F_ACC_RDONLY, H5P_DEFAULT ); //Ltensors : all processes own all Ltensors { long long totalsizeL = 0; Tensor ** batchL = new Tensor*[ Nbound ]; for (int cnt2=0; cnt2gKappa2index(Ltensors[index][cnt2]->gNKappa()); batchL[cnt2] = Ltensors[index][cnt2]; } if ( totalsizeL > 0 ){ const std::string tag = "Ltensors"; if ( store ){ MY_HDF5_WRITE_BATCH( file_id, Nbound, batchL, totalsizeL, tag ); } else{ MY_HDF5_READ_BATCH( file_id, Nbound, batchL, totalsizeL, tag ); } } delete [] batchL; } //Renormalized two-operator tensors : certain processes own certain two-operator tensors { long long totalsizeF0 = 0; int numF0 = 0; Tensor ** batchF0 = new Tensor*[ (Nbound*(Nbound + 1))/2 ]; long long totalsizeF1 = 0; int numF1 = 0; Tensor ** batchF1 = new Tensor*[ (Nbound*(Nbound + 1))/2 ]; long long totalsizeS0 = 0; int numS0 = 0; Tensor ** batchS0 = new Tensor*[ (Nbound*(Nbound + 1))/2 ]; long long totalsizeS1 = 0; int numS1 = 0; Tensor ** batchS1 = new Tensor*[ (Nbound*(Nbound + 1))/2 ]; for (int cnt2=0; cnt2gKappa2index(batchF0[numF0]->gNKappa()); numF0++; batchF1[numF1] = F1tensors[index][cnt2][cnt3]; totalsizeF1 += batchF1[numF1]->gKappa2index(batchF1[numF1]->gNKappa()); numF1++; } #ifdef CHEMPS2_MPI_COMPILATION if (( cnt3 == 0 ) || ( MPIchemps2::owner_absigma(siteindex1, siteindex2) == MPIRANK )) #endif { batchS0[numS0] = S0tensors[index][cnt2][cnt3]; totalsizeS0 += batchS0[numS0]->gKappa2index(batchS0[numS0]->gNKappa()); numS0++; if (cnt2>0){ batchS1[numS1] = S1tensors[index][cnt2][cnt3]; totalsizeS1 += batchS1[numS1]->gKappa2index(batchS1[numS1]->gNKappa()); numS1++; } } } } if ( totalsizeF0 > 0 ){ const std::string tag = "F0tensors"; if ( store ){ MY_HDF5_WRITE_BATCH( file_id, numF0, batchF0, totalsizeF0, tag ); } else{ MY_HDF5_READ_BATCH( file_id, numF0, batchF0, totalsizeF0, tag ); } } if ( totalsizeF1 > 0 ){ const std::string tag = "F1tensors"; if ( store ){ MY_HDF5_WRITE_BATCH( file_id, numF1, batchF1, totalsizeF1, tag ); } else{ MY_HDF5_READ_BATCH( file_id, numF1, batchF1, totalsizeF1, tag ); } } if ( totalsizeS0 > 0 ){ const std::string tag = "S0tensors"; if ( store ){ MY_HDF5_WRITE_BATCH( file_id, numS0, batchS0, totalsizeS0, tag ); } else{ MY_HDF5_READ_BATCH( file_id, numS0, batchS0, totalsizeS0, tag ); } } if ( totalsizeS1 > 0 ){ const std::string tag = "S1tensors"; if ( store ){ MY_HDF5_WRITE_BATCH( file_id, numS1, batchS1, totalsizeS1, tag ); } else{ MY_HDF5_READ_BATCH( file_id, numS1, batchS1, totalsizeS1, tag ); } } delete [] batchF0; delete [] batchF1; delete [] batchS0; delete [] batchS1; } //Complementary two-operator tensors : certain processes own certain complementary two-operator tensors { long long totalsizeA = 0; int numA = 0; Tensor ** batchA = new Tensor*[ (Cbound*(Cbound + 1))/2 ]; long long totalsizeB = 0; int numB = 0; Tensor ** batchB = new Tensor*[ (Cbound*(Cbound + 1))/2 ]; long long totalsizeC = 0; int numC = 0; Tensor ** batchC = new Tensor*[ (Cbound*(Cbound + 1))/2 ]; long long totalsizeD = 0; int numD = 0; Tensor ** batchD = new Tensor*[ (Cbound*(Cbound + 1))/2 ]; for (int cnt2=0; cnt2gKappa2index(batchA[numA]->gNKappa()); numA++; if (cnt2>0){ batchB[numB] = Btensors[index][cnt2][cnt3]; totalsizeB += batchB[numB]->gKappa2index(batchB[numB]->gNKappa()); numB++; } } #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_cdf(L, siteindex1, siteindex2) == MPIRANK ) #endif { batchC[numC] = Ctensors[index][cnt2][cnt3]; totalsizeC += batchC[numC]->gKappa2index(batchC[numC]->gNKappa()); numC++; batchD[numD] = Dtensors[index][cnt2][cnt3]; totalsizeD += batchD[numD]->gKappa2index(batchD[numD]->gNKappa()); numD++; } } } if ( totalsizeA > 0 ){ const std::string tag = "Atensors"; if ( store ){ MY_HDF5_WRITE_BATCH( file_id, numA, batchA, totalsizeA, tag ); } else{ MY_HDF5_READ_BATCH( file_id, numA, batchA, totalsizeA, tag ); } } if ( totalsizeB > 0 ){ const std::string tag = "Btensors"; if ( store ){ MY_HDF5_WRITE_BATCH( file_id, numB, batchB, totalsizeB, tag ); } else{ MY_HDF5_READ_BATCH( file_id, numB, batchB, totalsizeB, tag ); } } if ( totalsizeC > 0 ){ const std::string tag = "Ctensors"; if ( store ){ MY_HDF5_WRITE_BATCH( file_id, numC, batchC, totalsizeC, tag ); } else{ MY_HDF5_READ_BATCH( file_id, numC, batchC, totalsizeC, tag ); } } if ( totalsizeD > 0 ){ const std::string tag = "Dtensors"; if ( store ){ MY_HDF5_WRITE_BATCH( file_id, numD, batchD, totalsizeD, tag ); } else{ MY_HDF5_READ_BATCH( file_id, numD, batchD, totalsizeD, tag ); } } delete [] batchA; delete [] batchB; delete [] batchC; delete [] batchD; } //Complementary Q-tensors : certain processes own certain complementary Q-tensors { long long totalsizeQ = 0; int numQ = 0; Tensor ** batchQ = new Tensor*[ Cbound ]; for (int cnt2=0; cnt2gKappa2index(batchQ[numQ]->gNKappa()); numQ++; } } if ( totalsizeQ > 0 ){ const std::string tag = "Qtensors"; if ( store ){ MY_HDF5_WRITE_BATCH( file_id, numQ, batchQ, totalsizeQ, tag ); } else{ MY_HDF5_READ_BATCH( file_id, numQ, batchQ, totalsizeQ, tag ); } } delete [] batchQ; } //Complementary X-tensor : one process owns the X-tensors #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_x() == MPIRANK ) #endif { Tensor ** batchX = new Tensor*[ 1 ]; const long long totalsizeX = Xtensors[index]->gKappa2index(Xtensors[index]->gNKappa()); batchX[0] = Xtensors[index]; if ( totalsizeX > 0 ){ const std::string tag = "Xtensors"; if ( store ){ MY_HDF5_WRITE_BATCH( file_id, 1, batchX, totalsizeX, tag ); } else{ MY_HDF5_READ_BATCH( file_id, 1, batchX, totalsizeX, tag ); } } delete [] batchX; } //O-tensors : certain processes own certain excitations if (Exc_activated){ long long totalsizeO = 0; int numO = 0; Tensor ** batchO = new Tensor*[ nStates-1 ]; for (int state=0; stategKappa2index(batchO[numO]->gNKappa()); numO++; } } if ( totalsizeO > 0 ){ const std::string tag = "Otensors"; if ( store ){ MY_HDF5_WRITE_BATCH( file_id, numO, batchO, totalsizeO, tag ); } else{ MY_HDF5_READ_BATCH( file_id, numO, batchO, totalsizeO, tag ); } } delete [] batchO; } H5Fclose(file_id); gettimeofday(&end, NULL); if ( store ){ timings[ CHEMPS2_TIME_DISK_WRITE ] += (end.tv_sec - start.tv_sec) + 1e-6 * (end.tv_usec - start.tv_usec); } else { timings[ CHEMPS2_TIME_DISK_READ ] += (end.tv_sec - start.tv_sec) + 1e-6 * (end.tv_usec - start.tv_usec); } } void CheMPS2::DMRG::deleteTensors(const int index, const bool movingRight){ struct timeval start, end; gettimeofday(&start, NULL); const int Nbound = movingRight ? index+1 : L-1-index; const int Cbound = movingRight ? L-1-index : index+1; #ifdef CHEMPS2_MPI_COMPILATION const int MPIRANK = MPIchemps2::mpi_rank(); #endif //Ltensors : all processes own all Ltensors for (int cnt2=0; cnt20){ delete S1tensors[index][cnt2][cnt3]; } } } delete [] F0tensors[index][cnt2]; delete [] F1tensors[index][cnt2]; delete [] S0tensors[index][cnt2]; if (cnt2>0){ delete [] S1tensors[index][cnt2]; } } delete [] F0tensors[index]; delete [] F1tensors[index]; delete [] S0tensors[index]; delete [] S1tensors[index]; //Complementary two-operator tensors : certain processes own certain complementary two-operator tensors for (int cnt2=0; cnt20){ delete Btensors[index][cnt2][cnt3]; } } #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_cdf(L, siteindex1, siteindex2) == MPIRANK ) #endif { delete Ctensors[index][cnt2][cnt3]; delete Dtensors[index][cnt2][cnt3]; } } delete [] Atensors[index][cnt2]; if (cnt2>0){ delete [] Btensors[index][cnt2]; } delete [] Ctensors[index][cnt2]; delete [] Dtensors[index][cnt2]; } delete [] Atensors[index]; delete [] Btensors[index]; delete [] Ctensors[index]; delete [] Dtensors[index]; //Qtensors : certain processes own certain Qtensors for (int cnt2=0; cnt2 #include #include #include "DMRG.h" #include "MPIchemps2.h" #include "Special.h" void CheMPS2::DMRG::update_safe_3rdm_operators(const int boundary){ /* indices 0 <= j <= k <= l < boundary tensor_3rdm[ boundary - 1 == index ][ k - j ][ l - k ][ boundary - 1 - l ] ************************** * anni / anni / anni * ************************** 1/ j == k == l is forbidden ( no three annihilators on the same site ) 2/ if j == k, J1 must be zero ( Sigma_J1 does not exist then ) 3/ if k == l, J2 must be 1/2 tensor_3rdm_a_J0_doublet --> j <= k < l & j < k == l ( or NOT j == k == l ) tensor_3rdm_a_J1_doublet --> j < k <= l tensor_3rdm_a_J1_quartet --> j < k < l ************************** * anni / anni / crea * ************************** 1/ j <= k < l is allowed ( k == l is part of tensor_3rdm_c ) 2/ if j == k, J1 must be zero ( Sigma_J1 does not exist then ) tensor_3rdm_b_J0_doublet --> j <= k < l tensor_3rdm_b_J1_doublet --> j < k < l tensor_3rdm_b_J1_quartet --> j < k < l ************************** * anni / crea / anni * ************************** 1/ j == k == l is forbidden ( j == k == l is part of tensor_3rdm_d ) tensor_3rdm_c_J0_doublet --> j <= k < l & j < k == l ( or NOT j == k == l ) tensor_3rdm_c_J1_doublet --> j <= k < l & j < k == l ( or NOT j == k == l ) tensor_3rdm_c_J1_quartet --> j <= k < l & j < k == l ( or NOT j == k == l ) ************************** * crea / anni / anni * ************************** 1/ j <= k <= l is allowed 2/ if k == l, J2 must be 1/2 tensor_3rdm_d_J0_doublet --> j <= k <= l tensor_3rdm_d_J1_doublet --> j <= k <= l tensor_3rdm_d_J1_quartet --> j <= k < l */ allocate_3rdm_operators( boundary ); update_3rdm_operators( boundary ); if ( boundary >= 2 ){ delete_3rdm_operators( boundary - 1 ); } } void CheMPS2::DMRG::update_3rdm_operators(const int boundary){ struct timeval start, end; gettimeofday(&start, NULL); const int index = boundary - 1; const int dimL = denBK->gMaxDimAtBound(boundary-1); const int dimR = denBK->gMaxDimAtBound(boundary); #ifdef CHEMPS2_MPI_COMPILATION const int MPIRANK = MPIchemps2::mpi_rank(); #endif #pragma omp parallel { double * workmem = new double[dimL*dimR]; #ifdef CHEMPS2_MPI_COMPILATION //######( loop j<=k<=l MPI )######// /* Strategy for MPI: - outer loop is (j,k) - everyone has a temporary duplicate of S_jk and F_jk */ for ( int orb_j = 0; orb_j < boundary; orb_j++ ){ for ( int orb_k = orb_j; orb_k < boundary; orb_k++ ){ const int irrjk = Irreps::directProd( denBK->gIrrep( orb_j ), denBK->gIrrep( orb_k ) ); const int cnt1 = orb_k - orb_j; #pragma omp single if ( orb_k < index-1 ){ // All processes own Fx/Sx[ index - 1 ][ k - j ][ index - 1 - k == 0 ] const int own_S_jk = MPIchemps2::owner_absigma( orb_j, orb_k ); const int own_F_jk = MPIchemps2::owner_cdf( L, orb_j, orb_k ); if ( MPIRANK != own_F_jk ){ F0tensors[index-1][cnt1][index-orb_k-1] = new TensorF0( index, irrjk, true, denBK ); F1tensors[index-1][cnt1][index-orb_k-1] = new TensorF1( index, irrjk, true, denBK ); } if ( MPIRANK != own_S_jk ){ S0tensors[index-1][cnt1][index-orb_k-1] = new TensorS0( index, irrjk, true, denBK ); if ( cnt1 > 0 ){ S1tensors[index-1][cnt1][index-orb_k-1] = new TensorS1( index, irrjk, true, denBK ); }} MPIchemps2::broadcast_tensor( F0tensors[index-1][cnt1][index-orb_k-1], own_F_jk ); MPIchemps2::broadcast_tensor( F1tensors[index-1][cnt1][index-orb_k-1], own_F_jk ); MPIchemps2::broadcast_tensor( S0tensors[index-1][cnt1][index-orb_k-1], own_S_jk ); if ( cnt1 > 0 ){ MPIchemps2::broadcast_tensor( S1tensors[index-1][cnt1][index-orb_k-1], own_S_jk ); } } #pragma omp for schedule(dynamic) for ( int orb_l = orb_k; orb_l < boundary; orb_l++ ){ if ( MPIchemps2::owner_3rdm_diagram( L, orb_j, orb_k, orb_l ) == MPIRANK ){ const int cnt2 = orb_l - orb_k; const int cnt3 = index - orb_l; #else //######( loop j<=k<=l MPI )######// const int upperbound = (boundary*(boundary+1)*(boundary+2))/6; int jkl[] = { 0, 0, 0 }; #pragma omp for schedule(static) for ( int global = 0; global < upperbound; global++ ){ Special::invert_triangle_three( global, jkl ); const int orb_j = jkl[ 0 ]; const int orb_k = jkl[ 1 ]; const int orb_l = jkl[ 2 ]; const int recalculate_global = orb_j + (orb_k*(orb_k+1))/2 + (orb_l*(orb_l+1)*(orb_l+2))/6; assert( global == recalculate_global ); const int cnt1 = orb_k - orb_j; const int cnt2 = orb_l - orb_k; const int cnt3 = index - orb_l; #endif //######( loop j<=k<=l MPI )######// /* PERFORM THE UPDATES */ if ( cnt3 == 0 ){ // Create tensors if ( cnt2 > 0 ){ tensor_3rdm_a_J0_doublet[index][cnt1][cnt2][0]->a1(S0tensors[index-1][cnt1][cnt2-1], MPS[index], workmem); if (cnt1>0){ tensor_3rdm_a_J1_doublet[index][cnt1][cnt2][0]->a1(S1tensors[index-1][cnt1][cnt2-1], MPS[index], workmem); tensor_3rdm_a_J1_quartet[index][cnt1][cnt2][0]->a1(S1tensors[index-1][cnt1][cnt2-1], MPS[index], workmem); } tensor_3rdm_b_J0_doublet[index][cnt1][cnt2][0]->b1(S0tensors[index-1][cnt1][cnt2-1], MPS[index], workmem); if (cnt1>0){ tensor_3rdm_b_J1_doublet[index][cnt1][cnt2][0]->b1(S1tensors[index-1][cnt1][cnt2-1], MPS[index], workmem); tensor_3rdm_b_J1_quartet[index][cnt1][cnt2][0]->b1(S1tensors[index-1][cnt1][cnt2-1], MPS[index], workmem); } tensor_3rdm_c_J0_doublet[index][cnt1][cnt2][0]->c1(F0tensors[index-1][cnt1][cnt2-1], MPS[index], workmem); tensor_3rdm_c_J1_doublet[index][cnt1][cnt2][0]->c1(F1tensors[index-1][cnt1][cnt2-1], MPS[index], workmem); tensor_3rdm_c_J1_quartet[index][cnt1][cnt2][0]->c1(F1tensors[index-1][cnt1][cnt2-1], MPS[index], workmem); tensor_3rdm_d_J0_doublet[index][cnt1][cnt2][0]->d1(F0tensors[index-1][cnt1][cnt2-1], MPS[index], workmem); tensor_3rdm_d_J1_doublet[index][cnt1][cnt2][0]->d1(F1tensors[index-1][cnt1][cnt2-1], MPS[index], workmem); tensor_3rdm_d_J1_quartet[index][cnt1][cnt2][0]->d1(F1tensors[index-1][cnt1][cnt2-1], MPS[index], workmem); } else { if ( cnt1 > 0 ){ tensor_3rdm_a_J0_doublet[index][cnt1][0][0]->extra2(Ltensors[index-1][cnt1-1], MPS[index], workmem); tensor_3rdm_a_J1_doublet[index][cnt1][0][0]->extra2(Ltensors[index-1][cnt1-1], MPS[index], workmem); tensor_3rdm_c_J0_doublet[index][cnt1][0][0]->extra4(Ltensors[index-1][cnt1-1], MPS[index], workmem); tensor_3rdm_c_J1_doublet[index][cnt1][0][0]->extra4(Ltensors[index-1][cnt1-1], MPS[index], workmem); tensor_3rdm_c_J1_quartet[index][cnt1][0][0]->extra4(Ltensors[index-1][cnt1-1], MPS[index], workmem); tensor_3rdm_d_J0_doublet[index][cnt1][0][0]->extra3(Ltensors[index-1][cnt1-1], MPS[index], workmem); tensor_3rdm_d_J1_doublet[index][cnt1][0][0]->extra3(Ltensors[index-1][cnt1-1], MPS[index], workmem); } else { tensor_3rdm_d_J0_doublet[index][0][0][0]->extra1(MPS[index]); tensor_3rdm_d_J1_doublet[index][0][0][0]->extra1(MPS[index]); } } } else { // Update tensors if (cnt1+cnt2>0){ tensor_3rdm_a_J0_doublet[index][cnt1][cnt2][cnt3]->update(tensor_3rdm_a_J0_doublet[index-1][cnt1][cnt2][cnt3-1], MPS[index], MPS[index], workmem); } if (cnt1>0) { tensor_3rdm_a_J1_doublet[index][cnt1][cnt2][cnt3]->update(tensor_3rdm_a_J1_doublet[index-1][cnt1][cnt2][cnt3-1], MPS[index], MPS[index], workmem); } if (cnt1*cnt2>0){ tensor_3rdm_a_J1_quartet[index][cnt1][cnt2][cnt3]->update(tensor_3rdm_a_J1_quartet[index-1][cnt1][cnt2][cnt3-1], MPS[index], MPS[index], workmem); } if (cnt2>0) { tensor_3rdm_b_J0_doublet[index][cnt1][cnt2][cnt3]->update(tensor_3rdm_b_J0_doublet[index-1][cnt1][cnt2][cnt3-1], MPS[index], MPS[index], workmem); } if (cnt1*cnt2>0){ tensor_3rdm_b_J1_doublet[index][cnt1][cnt2][cnt3]->update(tensor_3rdm_b_J1_doublet[index-1][cnt1][cnt2][cnt3-1], MPS[index], MPS[index], workmem); } if (cnt1*cnt2>0){ tensor_3rdm_b_J1_quartet[index][cnt1][cnt2][cnt3]->update(tensor_3rdm_b_J1_quartet[index-1][cnt1][cnt2][cnt3-1], MPS[index], MPS[index], workmem); } if (cnt1+cnt2>0){ tensor_3rdm_c_J0_doublet[index][cnt1][cnt2][cnt3]->update(tensor_3rdm_c_J0_doublet[index-1][cnt1][cnt2][cnt3-1], MPS[index], MPS[index], workmem); } if (cnt1+cnt2>0){ tensor_3rdm_c_J1_doublet[index][cnt1][cnt2][cnt3]->update(tensor_3rdm_c_J1_doublet[index-1][cnt1][cnt2][cnt3-1], MPS[index], MPS[index], workmem); } if (cnt1+cnt2>0){ tensor_3rdm_c_J1_quartet[index][cnt1][cnt2][cnt3]->update(tensor_3rdm_c_J1_quartet[index-1][cnt1][cnt2][cnt3-1], MPS[index], MPS[index], workmem); } tensor_3rdm_d_J0_doublet[index][cnt1][cnt2][cnt3]->update(tensor_3rdm_d_J0_doublet[index-1][cnt1][cnt2][cnt3-1], MPS[index], MPS[index], workmem); tensor_3rdm_d_J1_doublet[index][cnt1][cnt2][cnt3]->update(tensor_3rdm_d_J1_doublet[index-1][cnt1][cnt2][cnt3-1], MPS[index], MPS[index], workmem); if (cnt2>0) { tensor_3rdm_d_J1_quartet[index][cnt1][cnt2][cnt3]->update(tensor_3rdm_d_J1_quartet[index-1][cnt1][cnt2][cnt3-1], MPS[index], MPS[index], workmem); } } #ifdef CHEMPS2_MPI_COMPILATION //######( close loop j<=k<=l MPI )######// } } #pragma omp single if ( orb_k < index - 1 ){ // All processes own Fx/Sx[ index - 1 ][ k - j ][ index - 1 - k == 0 ] const int own_S_jk = MPIchemps2::owner_absigma( orb_j, orb_k ); const int own_F_jk = MPIchemps2::owner_cdf( L, orb_j, orb_k ); if ( MPIRANK != own_F_jk ){ delete F0tensors[index-1][cnt1][index-orb_k-1]; F0tensors[index-1][cnt1][index-orb_k-1] = NULL; delete F1tensors[index-1][cnt1][index-orb_k-1]; F1tensors[index-1][cnt1][index-orb_k-1] = NULL; } if ( MPIRANK != own_S_jk ){ delete S0tensors[index-1][cnt1][index-orb_k-1]; S0tensors[index-1][cnt1][index-orb_k-1] = NULL; if ( cnt1 > 0 ){ delete S1tensors[index-1][cnt1][index-orb_k-1]; S1tensors[index-1][cnt1][index-orb_k-1] = NULL; }} } } } #else //######( close loop j<=k<=l MPI )######// } #endif //######( close loop j<=k<=l MPI )######// delete [] workmem; } gettimeofday(&end, NULL); timings[ CHEMPS2_TIME_TENS_CALC ] += (end.tv_sec - start.tv_sec) + 1e-6 * (end.tv_usec - start.tv_usec); } void CheMPS2::DMRG::allocate_3rdm_operators(const int boundary){ struct timeval start, end; gettimeofday(&start, NULL); #ifdef CHEMPS2_MPI_COMPILATION const int MPIRANK = MPIchemps2::mpi_rank(); #endif const int index = boundary - 1; tensor_3rdm_a_J0_doublet[ index ] = new Tensor3RDM***[ boundary ]; tensor_3rdm_a_J1_doublet[ index ] = new Tensor3RDM***[ boundary ]; tensor_3rdm_a_J1_quartet[ index ] = new Tensor3RDM***[ boundary ]; tensor_3rdm_b_J0_doublet[ index ] = new Tensor3RDM***[ boundary ]; tensor_3rdm_b_J1_doublet[ index ] = new Tensor3RDM***[ boundary ]; tensor_3rdm_b_J1_quartet[ index ] = new Tensor3RDM***[ boundary ]; tensor_3rdm_c_J0_doublet[ index ] = new Tensor3RDM***[ boundary ]; tensor_3rdm_c_J1_doublet[ index ] = new Tensor3RDM***[ boundary ]; tensor_3rdm_c_J1_quartet[ index ] = new Tensor3RDM***[ boundary ]; tensor_3rdm_d_J0_doublet[ index ] = new Tensor3RDM***[ boundary ]; tensor_3rdm_d_J1_doublet[ index ] = new Tensor3RDM***[ boundary ]; tensor_3rdm_d_J1_quartet[ index ] = new Tensor3RDM***[ boundary ]; for ( int cnt1 = 0; cnt1 < boundary; cnt1++ ){ // cnt1 = k - j < boundary tensor_3rdm_a_J0_doublet[ index ][ cnt1 ] = new Tensor3RDM**[ boundary - cnt1 ]; tensor_3rdm_a_J1_doublet[ index ][ cnt1 ] = new Tensor3RDM**[ boundary - cnt1 ]; tensor_3rdm_a_J1_quartet[ index ][ cnt1 ] = new Tensor3RDM**[ boundary - cnt1 ]; tensor_3rdm_b_J0_doublet[ index ][ cnt1 ] = new Tensor3RDM**[ boundary - cnt1 ]; tensor_3rdm_b_J1_doublet[ index ][ cnt1 ] = new Tensor3RDM**[ boundary - cnt1 ]; tensor_3rdm_b_J1_quartet[ index ][ cnt1 ] = new Tensor3RDM**[ boundary - cnt1 ]; tensor_3rdm_c_J0_doublet[ index ][ cnt1 ] = new Tensor3RDM**[ boundary - cnt1 ]; tensor_3rdm_c_J1_doublet[ index ][ cnt1 ] = new Tensor3RDM**[ boundary - cnt1 ]; tensor_3rdm_c_J1_quartet[ index ][ cnt1 ] = new Tensor3RDM**[ boundary - cnt1 ]; tensor_3rdm_d_J0_doublet[ index ][ cnt1 ] = new Tensor3RDM**[ boundary - cnt1 ]; tensor_3rdm_d_J1_doublet[ index ][ cnt1 ] = new Tensor3RDM**[ boundary - cnt1 ]; tensor_3rdm_d_J1_quartet[ index ][ cnt1 ] = new Tensor3RDM**[ boundary - cnt1 ]; for ( int cnt2 = 0; cnt2 < boundary - cnt1; cnt2++ ){ // cnt2 = l - k < boundary - k = boundary - cnt1 - j <= boundary - cnt1 tensor_3rdm_a_J0_doublet[ index ][ cnt1 ][ cnt2 ] = new Tensor3RDM*[ boundary - cnt1 - cnt2 ]; tensor_3rdm_a_J1_doublet[ index ][ cnt1 ][ cnt2 ] = new Tensor3RDM*[ boundary - cnt1 - cnt2 ]; tensor_3rdm_a_J1_quartet[ index ][ cnt1 ][ cnt2 ] = new Tensor3RDM*[ boundary - cnt1 - cnt2 ]; tensor_3rdm_b_J0_doublet[ index ][ cnt1 ][ cnt2 ] = new Tensor3RDM*[ boundary - cnt1 - cnt2 ]; tensor_3rdm_b_J1_doublet[ index ][ cnt1 ][ cnt2 ] = new Tensor3RDM*[ boundary - cnt1 - cnt2 ]; tensor_3rdm_b_J1_quartet[ index ][ cnt1 ][ cnt2 ] = new Tensor3RDM*[ boundary - cnt1 - cnt2 ]; tensor_3rdm_c_J0_doublet[ index ][ cnt1 ][ cnt2 ] = new Tensor3RDM*[ boundary - cnt1 - cnt2 ]; tensor_3rdm_c_J1_doublet[ index ][ cnt1 ][ cnt2 ] = new Tensor3RDM*[ boundary - cnt1 - cnt2 ]; tensor_3rdm_c_J1_quartet[ index ][ cnt1 ][ cnt2 ] = new Tensor3RDM*[ boundary - cnt1 - cnt2 ]; tensor_3rdm_d_J0_doublet[ index ][ cnt1 ][ cnt2 ] = new Tensor3RDM*[ boundary - cnt1 - cnt2 ]; tensor_3rdm_d_J1_doublet[ index ][ cnt1 ][ cnt2 ] = new Tensor3RDM*[ boundary - cnt1 - cnt2 ]; tensor_3rdm_d_J1_quartet[ index ][ cnt1 ][ cnt2 ] = new Tensor3RDM*[ boundary - cnt1 - cnt2 ]; for ( int cnt3 = 0; cnt3 < boundary - cnt1 - cnt2; cnt3++ ){ // cnt3 = boundary - 1 - l < boundary - ( l - k ) - ( k - j ) = boundary - cnt1 - cnt2 const int orb_l = boundary - 1 - cnt3; const int orb_k = orb_l - cnt2; const int orb_j = orb_k - cnt1; const int irr = Irreps::directProd( Irreps::directProd( denBK->gIrrep( orb_j ), denBK->gIrrep( orb_k ) ), denBK->gIrrep( orb_l ) ); #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_3rdm_diagram( L, orb_j, orb_k, orb_l ) == MPIRANK ){ #endif tensor_3rdm_a_J0_doublet[index][cnt1][cnt2][cnt3] = (cnt1+cnt2>0) ? new Tensor3RDM(boundary, 0, 1, 3, irr, true, denBK) : NULL; // NOT j == k == l tensor_3rdm_a_J1_doublet[index][cnt1][cnt2][cnt3] = (cnt1>0) ? new Tensor3RDM(boundary, 2, 1, 3, irr, true, denBK) : NULL; // j < k <= l tensor_3rdm_a_J1_quartet[index][cnt1][cnt2][cnt3] = (cnt1*cnt2>0) ? new Tensor3RDM(boundary, 2, 3, 3, irr, true, denBK) : NULL; // j < k < l tensor_3rdm_b_J0_doublet[index][cnt1][cnt2][cnt3] = (cnt2>0) ? new Tensor3RDM(boundary, 0, 1, 1, irr, true, denBK) : NULL; // j <= k < l tensor_3rdm_b_J1_doublet[index][cnt1][cnt2][cnt3] = (cnt1*cnt2>0) ? new Tensor3RDM(boundary, 2, 1, 1, irr, true, denBK) : NULL; // j < k < l tensor_3rdm_b_J1_quartet[index][cnt1][cnt2][cnt3] = (cnt1*cnt2>0) ? new Tensor3RDM(boundary, 2, 3, 1, irr, true, denBK) : NULL; // j < k < l tensor_3rdm_c_J0_doublet[index][cnt1][cnt2][cnt3] = (cnt1+cnt2>0) ? new Tensor3RDM(boundary, 0, 1, 1, irr, true, denBK) : NULL; // NOT j == k == l tensor_3rdm_c_J1_doublet[index][cnt1][cnt2][cnt3] = (cnt1+cnt2>0) ? new Tensor3RDM(boundary, 2, 1, 1, irr, true, denBK) : NULL; // NOT j == k == l tensor_3rdm_c_J1_quartet[index][cnt1][cnt2][cnt3] = (cnt1+cnt2>0) ? new Tensor3RDM(boundary, 2, 3, 1, irr, true, denBK) : NULL; // NOT j == k == l tensor_3rdm_d_J0_doublet[index][cnt1][cnt2][cnt3] = new Tensor3RDM(boundary, 0, 1, 1, irr, false, denBK); // j <= k <= l tensor_3rdm_d_J1_doublet[index][cnt1][cnt2][cnt3] = new Tensor3RDM(boundary, 2, 1, 1, irr, false, denBK); // j <= k <= l tensor_3rdm_d_J1_quartet[index][cnt1][cnt2][cnt3] = (cnt2>0) ? new Tensor3RDM(boundary, 2, 3, 1, irr, false, denBK) : NULL; // j <= k < l #ifdef CHEMPS2_MPI_COMPILATION } else { tensor_3rdm_a_J0_doublet[index][cnt1][cnt2][cnt3] = NULL; tensor_3rdm_a_J1_doublet[index][cnt1][cnt2][cnt3] = NULL; tensor_3rdm_a_J1_quartet[index][cnt1][cnt2][cnt3] = NULL; tensor_3rdm_b_J0_doublet[index][cnt1][cnt2][cnt3] = NULL; tensor_3rdm_b_J1_doublet[index][cnt1][cnt2][cnt3] = NULL; tensor_3rdm_b_J1_quartet[index][cnt1][cnt2][cnt3] = NULL; tensor_3rdm_c_J0_doublet[index][cnt1][cnt2][cnt3] = NULL; tensor_3rdm_c_J1_doublet[index][cnt1][cnt2][cnt3] = NULL; tensor_3rdm_c_J1_quartet[index][cnt1][cnt2][cnt3] = NULL; tensor_3rdm_d_J0_doublet[index][cnt1][cnt2][cnt3] = NULL; tensor_3rdm_d_J1_doublet[index][cnt1][cnt2][cnt3] = NULL; tensor_3rdm_d_J1_quartet[index][cnt1][cnt2][cnt3] = NULL; } #endif } } } gettimeofday(&end, NULL); timings[ CHEMPS2_TIME_TENS_ALLOC ] += (end.tv_sec - start.tv_sec) + 1e-6 * (end.tv_usec - start.tv_usec); } void CheMPS2::DMRG::delete_3rdm_operators(const int boundary){ struct timeval start, end; gettimeofday(&start, NULL); #ifdef CHEMPS2_MPI_COMPILATION const int MPIRANK = MPIchemps2::mpi_rank(); #endif const int index = boundary - 1; for ( int cnt1 = 0; cnt1 < boundary; cnt1++ ){ // cnt1 = k - j < boundary for ( int cnt2 = 0; cnt2 < boundary - cnt1; cnt2++ ){ // cnt2 = l - k < boundary - k = boundary - cnt1 - j <= boundary - cnt1 for ( int cnt3 = 0; cnt3 < boundary - cnt1 - cnt2; cnt3++ ){ // cnt3 = boundary - 1 - l < boundary - ( l - k ) - ( k - j ) = boundary - cnt1 - cnt2 const int orb_l = boundary - 1 - cnt3; const int orb_k = orb_l - cnt2; const int orb_j = orb_k - cnt1; #ifdef CHEMPS2_MPI_COMPILATION if ( MPIchemps2::owner_3rdm_diagram( L, orb_j, orb_k, orb_l ) == MPIRANK ) #endif { if (cnt1+cnt2>0){ delete tensor_3rdm_a_J0_doublet[index][cnt1][cnt2][cnt3]; } if (cnt1>0) { delete tensor_3rdm_a_J1_doublet[index][cnt1][cnt2][cnt3]; } if (cnt1*cnt2>0){ delete tensor_3rdm_a_J1_quartet[index][cnt1][cnt2][cnt3]; } if (cnt2>0) { delete tensor_3rdm_b_J0_doublet[index][cnt1][cnt2][cnt3]; } if (cnt1*cnt2>0){ delete tensor_3rdm_b_J1_doublet[index][cnt1][cnt2][cnt3]; } if (cnt1*cnt2>0){ delete tensor_3rdm_b_J1_quartet[index][cnt1][cnt2][cnt3]; } if (cnt1+cnt2>0){ delete tensor_3rdm_c_J0_doublet[index][cnt1][cnt2][cnt3]; } if (cnt1+cnt2>0){ delete tensor_3rdm_c_J1_doublet[index][cnt1][cnt2][cnt3]; } if (cnt1+cnt2>0){ delete tensor_3rdm_c_J1_quartet[index][cnt1][cnt2][cnt3]; } delete tensor_3rdm_d_J0_doublet[index][cnt1][cnt2][cnt3]; delete tensor_3rdm_d_J1_doublet[index][cnt1][cnt2][cnt3]; if (cnt2>0) { delete tensor_3rdm_d_J1_quartet[index][cnt1][cnt2][cnt3]; } } } delete [] tensor_3rdm_a_J0_doublet[ index ][ cnt1 ][ cnt2 ]; delete [] tensor_3rdm_a_J1_doublet[ index ][ cnt1 ][ cnt2 ]; delete [] tensor_3rdm_a_J1_quartet[ index ][ cnt1 ][ cnt2 ]; delete [] tensor_3rdm_b_J0_doublet[ index ][ cnt1 ][ cnt2 ]; delete [] tensor_3rdm_b_J1_doublet[ index ][ cnt1 ][ cnt2 ]; delete [] tensor_3rdm_b_J1_quartet[ index ][ cnt1 ][ cnt2 ]; delete [] tensor_3rdm_c_J0_doublet[ index ][ cnt1 ][ cnt2 ]; delete [] tensor_3rdm_c_J1_doublet[ index ][ cnt1 ][ cnt2 ]; delete [] tensor_3rdm_c_J1_quartet[ index ][ cnt1 ][ cnt2 ]; delete [] tensor_3rdm_d_J0_doublet[ index ][ cnt1 ][ cnt2 ]; delete [] tensor_3rdm_d_J1_doublet[ index ][ cnt1 ][ cnt2 ]; delete [] tensor_3rdm_d_J1_quartet[ index ][ cnt1 ][ cnt2 ]; } delete [] tensor_3rdm_a_J0_doublet[ index ][ cnt1 ]; delete [] tensor_3rdm_a_J1_doublet[ index ][ cnt1 ]; delete [] tensor_3rdm_a_J1_quartet[ index ][ cnt1 ]; delete [] tensor_3rdm_b_J0_doublet[ index ][ cnt1 ]; delete [] tensor_3rdm_b_J1_doublet[ index ][ cnt1 ]; delete [] tensor_3rdm_b_J1_quartet[ index ][ cnt1 ]; delete [] tensor_3rdm_c_J0_doublet[ index ][ cnt1 ]; delete [] tensor_3rdm_c_J1_doublet[ index ][ cnt1 ]; delete [] tensor_3rdm_c_J1_quartet[ index ][ cnt1 ]; delete [] tensor_3rdm_d_J0_doublet[ index ][ cnt1 ]; delete [] tensor_3rdm_d_J1_doublet[ index ][ cnt1 ]; delete [] tensor_3rdm_d_J1_quartet[ index ][ cnt1 ]; } delete [] tensor_3rdm_a_J0_doublet[ index ]; delete [] tensor_3rdm_a_J1_doublet[ index ]; delete [] tensor_3rdm_a_J1_quartet[ index ]; delete [] tensor_3rdm_b_J0_doublet[ index ]; delete [] tensor_3rdm_b_J1_doublet[ index ]; delete [] tensor_3rdm_b_J1_quartet[ index ]; delete [] tensor_3rdm_c_J0_doublet[ index ]; delete [] tensor_3rdm_c_J1_doublet[ index ]; delete [] tensor_3rdm_c_J1_quartet[ index ]; delete [] tensor_3rdm_d_J0_doublet[ index ]; delete [] tensor_3rdm_d_J1_doublet[ index ]; delete [] tensor_3rdm_d_J1_quartet[ index ]; gettimeofday(&end, NULL); timings[ CHEMPS2_TIME_TENS_FREE ] += (end.tv_sec - start.tv_sec) + 1e-6 * (end.tv_usec - start.tv_usec); } void CheMPS2::DMRG::update_correlations_tensors(const int siteindex){ struct timeval start, end; const int dimL = denBK->gMaxDimAtBound(siteindex-1); const int dimR = denBK->gMaxDimAtBound(siteindex); double * workmemLR = new double[dimL*dimR]; for ( int previousindex = 0; previousindex < siteindex-1; previousindex++ ){ gettimeofday(&start, NULL); TensorGYZ * newG = new TensorGYZ(siteindex, 'G', denBK); TensorGYZ * newY = new TensorGYZ(siteindex, 'Y', denBK); TensorGYZ * newZ = new TensorGYZ(siteindex, 'Z', denBK); TensorKM * newK = new TensorKM( siteindex, 'K', denBK->gIrrep(previousindex), denBK ); TensorKM * newM = new TensorKM( siteindex, 'M', denBK->gIrrep(previousindex), denBK ); gettimeofday(&end, NULL); timings[ CHEMPS2_TIME_TENS_ALLOC ] += (end.tv_sec - start.tv_sec) + 1e-6 * (end.tv_usec - start.tv_usec); gettimeofday(&start, NULL); newG->update(Gtensors[previousindex], MPS[siteindex-1], MPS[siteindex-1], workmemLR); newY->update(Ytensors[previousindex], MPS[siteindex-1], MPS[siteindex-1], workmemLR); newZ->update(Ztensors[previousindex], MPS[siteindex-1], MPS[siteindex-1], workmemLR); newK->update(Ktensors[previousindex], MPS[siteindex-1], MPS[siteindex-1], workmemLR); newM->update(Mtensors[previousindex], MPS[siteindex-1], MPS[siteindex-1], workmemLR); gettimeofday(&end, NULL); timings[ CHEMPS2_TIME_TENS_CALC ] += (end.tv_sec - start.tv_sec) + 1e-6 * (end.tv_usec - start.tv_usec); gettimeofday(&start, NULL); delete Gtensors[previousindex]; delete Ytensors[previousindex]; delete Ztensors[previousindex]; delete Ktensors[previousindex]; delete Mtensors[previousindex]; gettimeofday(&end, NULL); timings[ CHEMPS2_TIME_TENS_FREE ] += (end.tv_sec - start.tv_sec) + 1e-6 * (end.tv_usec - start.tv_usec); Gtensors[previousindex] = newG; Ytensors[previousindex] = newY; Ztensors[previousindex] = newZ; Ktensors[previousindex] = newK; Mtensors[previousindex] = newM; } delete [] workmemLR; gettimeofday(&start, NULL); Gtensors[siteindex-1] = new TensorGYZ(siteindex, 'G', denBK); Ytensors[siteindex-1] = new TensorGYZ(siteindex, 'Y', denBK); Ztensors[siteindex-1] = new TensorGYZ(siteindex, 'Z', denBK); Ktensors[siteindex-1] = new TensorKM( siteindex, 'K', denBK->gIrrep(siteindex-1), denBK ); Mtensors[siteindex-1] = new TensorKM( siteindex, 'M', denBK->gIrrep(siteindex-1), denBK ); gettimeofday(&end, NULL); timings[ CHEMPS2_TIME_TENS_ALLOC ] += (end.tv_sec - start.tv_sec) + 1e-6 * (end.tv_usec - start.tv_usec); gettimeofday(&start, NULL); Gtensors[siteindex-1]->construct(MPS[siteindex-1]); Ytensors[siteindex-1]->construct(MPS[siteindex-1]); Ztensors[siteindex-1]->construct(MPS[siteindex-1]); Ktensors[siteindex-1]->construct(MPS[siteindex-1]); Mtensors[siteindex-1]->construct(MPS[siteindex-1]); gettimeofday(&end, NULL); timings[ CHEMPS2_TIME_TENS_CALC ] += (end.tv_sec - start.tv_sec) + 1e-6 * (end.tv_usec - start.tv_usec); } CheMPS2-1.8.9/CheMPS2/DMRGtechnics.cpp000066400000000000000000000702041336564451100170240ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include #include #include "DMRG.h" #include "Lapack.h" #include "Heff.h" #include "MPIchemps2.h" #include "Wigner.h" #include "Special.h" using std::cout; using std::endl; void CheMPS2::DMRG::calc_rdms_and_correlations( const bool do_3rdm, const bool disk_3rdm ){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif // Reset timings for ( int timecnt = 0; timecnt < CHEMPS2_TIME_VECLENGTH; timecnt++ ){ timings[ timecnt ] = 0.0; } num_double_write_disk = 0; num_double_read_disk = 0; struct timeval start_global, end_global, start_part, end_part; gettimeofday( &start_global, NULL ); // Get the whole MPS into left-canonical form gettimeofday( &start_part, NULL ); left_normalize( MPS[ L - 2 ], MPS[ L - 1 ] ); left_normalize( MPS[ L - 1 ], NULL ); gettimeofday( &end_part, NULL ); timings[ CHEMPS2_TIME_S_SPLIT ] += ( end_part.tv_sec - start_part.tv_sec ) + 1e-6 * ( end_part.tv_usec - start_part.tv_usec ); if ( am_i_master ){ if ( do_3rdm ){ cout << "****************************************************" << endl; cout << "*** 2-RDM, 3-RDM, and Correlations calculation ***" << endl; cout << "****************************************************" << endl; } else { cout << "********************************************" << endl; cout << "*** 2-RDM and Correlations calculation ***" << endl; cout << "********************************************" << endl; } } // Make the renormalized operators one site further ( one-dot ) gettimeofday( &start_part, NULL ); updateMovingRightSafe( L - 2 ); gettimeofday( &end_part, NULL ); timings[ CHEMPS2_TIME_TENS_TOTAL ] += ( end_part.tv_sec - start_part.tv_sec ) + 1e-6 * ( end_part.tv_usec - start_part.tv_usec ); // Calculate the 2DM if ( the2DM != NULL ){ delete the2DM; the2DM = NULL; } the2DM = new TwoDM( denBK, Prob ); for ( int siteindex = L - 1; siteindex >= 0; siteindex-- ){ gettimeofday( &start_part, NULL ); // Specific 2-RDM entries are internally added per MPI processes; after which an allreduce is called the2DM->FillSite( MPS[ siteindex ], Ltensors, F0tensors, F1tensors, S0tensors, S1tensors ); gettimeofday( &end_part, NULL ); timings[ CHEMPS2_TIME_S_SOLVE ] += ( end_part.tv_sec - start_part.tv_sec ) + 1e-6 * ( end_part.tv_usec - start_part.tv_usec ); if ( siteindex > 0 ){ gettimeofday( &start_part, NULL ); right_normalize( MPS[ siteindex - 1 ], MPS[ siteindex ] ); gettimeofday( &end_part, NULL ); timings[ CHEMPS2_TIME_S_SPLIT ] += ( end_part.tv_sec - start_part.tv_sec ) + 1e-6 * ( end_part.tv_usec - start_part.tv_usec ); gettimeofday( &start_part, NULL ); updateMovingLeftSafe2DM( siteindex - 1 ); gettimeofday( &end_part, NULL ); timings[ CHEMPS2_TIME_TENS_TOTAL ] += ( end_part.tv_sec - start_part.tv_sec ) + 1e-6 * ( end_part.tv_usec - start_part.tv_usec ); } } #ifdef CHEMPS2_MPI_COMPILATION gettimeofday( &start_part, NULL ); the2DM->mpi_allreduce(); gettimeofday( &end_part, NULL ); timings[ CHEMPS2_TIME_S_SOLVE ] += ( end_part.tv_sec - start_part.tv_sec ) + 1e-6 * ( end_part.tv_usec - start_part.tv_usec ); #endif the2DM->correct_higher_multiplicities(); // Trace, energy, and NOON if ( am_i_master ){ cout << " N(N-1) = " << denBK->gN() * ( denBK->gN() - 1 ) << endl; cout << " Double trace of DMRG 2-RDM = " << the2DM->trace() << endl; cout << " Econst + 0.5 * trace(2DM-A * Ham) = " << the2DM->energy() << endl; the2DM->print_noon(); } // Calculate the 3DM and Correlations if ( the3DM != NULL ){ delete the3DM; the3DM = NULL; } if ( theCorr != NULL ){ delete theCorr; theCorr = NULL; } if ( do_3rdm ){ the3DM = new ThreeDM( denBK, Prob, disk_3rdm ); } theCorr = new Correlations( denBK, Prob, the2DM ); if ( am_i_master ){ Gtensors = new TensorGYZ*[ L - 1 ]; Ytensors = new TensorGYZ*[ L - 1 ]; Ztensors = new TensorGYZ*[ L - 1 ]; Ktensors = new TensorKM *[ L - 1 ]; Mtensors = new TensorKM *[ L - 1 ]; } if ( do_3rdm ){ tensor_3rdm_a_J0_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_a_J1_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_a_J1_quartet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_b_J0_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_b_J1_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_b_J1_quartet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_c_J0_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_c_J1_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_c_J1_quartet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_d_J0_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_d_J1_doublet = new Tensor3RDM****[ L - 1 ]; tensor_3rdm_d_J1_quartet = new Tensor3RDM****[ L - 1 ]; // Calculate the leftmost site contribution to the 3-RDM gettimeofday( &start_part, NULL ); the3DM->fill_site( MPS[ 0 ], Ltensors, F0tensors, F1tensors, S0tensors, S1tensors, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); gettimeofday( &end_part, NULL ); timings[ CHEMPS2_TIME_S_SOLVE ] += ( end_part.tv_sec - start_part.tv_sec ) + 1e-6 * ( end_part.tv_usec - start_part.tv_usec ); } for ( int siteindex = 1; siteindex < L; siteindex++ ){ // Change MPS gauge gettimeofday( &start_part, NULL ); left_normalize( MPS[ siteindex - 1 ], MPS[ siteindex ] ); gettimeofday( &end_part, NULL ); timings[ CHEMPS2_TIME_S_SPLIT ] += ( end_part.tv_sec - start_part.tv_sec ) + 1e-6 * ( end_part.tv_usec - start_part.tv_usec ); // Update 2-RDM, 3-RDM, and Correlations tensors gettimeofday( &start_part, NULL ); if ( do_3rdm ){ update_safe_3rdm_operators( siteindex ); } updateMovingRightSafe2DM( siteindex - 1 ); if ( am_i_master ){ update_correlations_tensors( siteindex ); } gettimeofday( &end_part, NULL ); timings[ CHEMPS2_TIME_TENS_TOTAL ] += ( end_part.tv_sec - start_part.tv_sec ) + 1e-6 * ( end_part.tv_usec - start_part.tv_usec ); // Calculate Correlation and 3-RDM diagrams. Specific contributions per MPI process. Afterwards an MPI allreduce/bcast is required. gettimeofday( &start_part, NULL ); if ( am_i_master ){ theCorr->FillSite( MPS[ siteindex ], Gtensors, Ytensors, Ztensors, Ktensors, Mtensors ); } if ( do_3rdm ){ the3DM->fill_site( MPS[ siteindex ], Ltensors, F0tensors, F1tensors, S0tensors, S1tensors, tensor_3rdm_a_J0_doublet[ siteindex - 1 ], tensor_3rdm_a_J1_doublet[ siteindex - 1 ], tensor_3rdm_a_J1_quartet[ siteindex - 1 ], tensor_3rdm_b_J0_doublet[ siteindex - 1 ], tensor_3rdm_b_J1_doublet[ siteindex - 1 ], tensor_3rdm_b_J1_quartet[ siteindex - 1 ], tensor_3rdm_c_J0_doublet[ siteindex - 1 ], tensor_3rdm_c_J1_doublet[ siteindex - 1 ], tensor_3rdm_c_J1_quartet[ siteindex - 1 ], tensor_3rdm_d_J0_doublet[ siteindex - 1 ], tensor_3rdm_d_J1_doublet[ siteindex - 1 ], tensor_3rdm_d_J1_quartet[ siteindex - 1 ] ); } gettimeofday( &end_part, NULL ); timings[ CHEMPS2_TIME_S_SOLVE ] += ( end_part.tv_sec - start_part.tv_sec ) + 1e-6 * ( end_part.tv_usec - start_part.tv_usec ); } // Delete the renormalized operators from boundary L-2 and load the ones from boundary L-3 gettimeofday( &start_part, NULL ); assert( isAllocated[ L - 2 ] == 1 ); // Renormalized operators exist on the last boundary (L-2) and are moving to the right. assert( isAllocated[ L - 3 ] == 0 ); // Renormalized operators do not exist on boundary L-3. deleteTensors( L - 2, true ); isAllocated[ L - 2 ] = 0; // Delete the renormalized operators on the last boundary (L-2). allocateTensors( L - 3, true ); isAllocated[ L - 3 ] = 1; // Create the renormalized operators on boundary L-3. OperatorsOnDisk( L - 3, true, false ); // Load the renormalized operators on boundary L-3. gettimeofday( &end_part, NULL ); timings[ CHEMPS2_TIME_TENS_TOTAL ] += ( end_part.tv_sec - start_part.tv_sec ) + 1e-6 * ( end_part.tv_usec - start_part.tv_usec ); #ifdef CHEMPS2_MPI_COMPILATION gettimeofday( &start_part, NULL ); theCorr->mpi_broadcast(); if (do_3rdm){ the3DM->mpi_allreduce(); } gettimeofday( &end_part, NULL ); timings[ CHEMPS2_TIME_S_SOLVE ] += ( end_part.tv_sec - start_part.tv_sec ) + 1e-6 * ( end_part.tv_usec - start_part.tv_usec ); #endif if ( do_3rdm ){ the3DM->correct_higher_multiplicities(); delete_3rdm_operators( L - 1 ); delete [] tensor_3rdm_a_J0_doublet; delete [] tensor_3rdm_a_J1_doublet; delete [] tensor_3rdm_a_J1_quartet; delete [] tensor_3rdm_b_J0_doublet; delete [] tensor_3rdm_b_J1_doublet; delete [] tensor_3rdm_b_J1_quartet; delete [] tensor_3rdm_c_J0_doublet; delete [] tensor_3rdm_c_J1_doublet; delete [] tensor_3rdm_c_J1_quartet; delete [] tensor_3rdm_d_J0_doublet; delete [] tensor_3rdm_d_J1_doublet; delete [] tensor_3rdm_d_J1_quartet; } if ( am_i_master ){ for ( int previousindex = 0; previousindex < L - 1; previousindex++ ){ delete Gtensors[ previousindex ]; delete Ytensors[ previousindex ]; delete Ztensors[ previousindex ]; delete Ktensors[ previousindex ]; delete Mtensors[ previousindex ]; } delete [] Gtensors; delete [] Ytensors; delete [] Ztensors; delete [] Ktensors; delete [] Mtensors; } gettimeofday( &end_global, NULL ); const double elapsed_global = ( end_global.tv_sec - start_global.tv_sec ) + 1e-6 * ( end_global.tv_usec - start_global.tv_usec ); if ( am_i_master ){ cout << " Single-orbital entropies (Hamiltonian index order is used!) = [ "; for ( int index = 0; index < L - 1; index++ ){ cout << theCorr->SingleOrbitalEntropy_HAM( index ) << " , "; } cout << theCorr->SingleOrbitalEntropy_HAM( L - 1 ) << " ]." << endl; for ( int power = 0; power <= 2; power++ ){ cout << " Idistance(" << power << ") = " << theCorr->MutualInformationDistance( (double) power ) << endl; } if ( do_3rdm ){ cout << " N(N-1)(N-2) = " << denBK->gN() * ( denBK->gN() - 1 ) * ( denBK->gN() - 2 ) << endl; cout << " Triple trace of DMRG 3-RDM = " << the3DM->trace() << endl; cout << "***********************************************************" << endl; cout << "*** Timing information 2-RDM, 3-RDM, and Correlations ***" << endl; cout << "***********************************************************" << endl; } else { cout << "***************************************************" << endl; cout << "*** Timing information 2-RDM and Correlations ***" << endl; cout << "***************************************************" << endl; } cout << "*** Elapsed wall time = " << elapsed_global << " seconds" << endl; cout << "*** |--> MPS gauge change = " << timings[ CHEMPS2_TIME_S_SPLIT ] << " seconds" << endl; cout << "*** |--> Diagram calc = " << timings[ CHEMPS2_TIME_S_SOLVE ] << " seconds" << endl; print_tensor_update_performance(); if ( do_3rdm ){ cout << "***********************************************************" << endl; } else { cout << "***************************************************" << endl; } } } void CheMPS2::DMRG::print_tensor_update_performance() const{ cout << "*** |--> Tensor update = " << timings[ CHEMPS2_TIME_TENS_TOTAL ] << " seconds" << endl; cout << "*** |--> create = " << timings[ CHEMPS2_TIME_TENS_ALLOC ] << " seconds" << endl; cout << "*** |--> destroy = " << timings[ CHEMPS2_TIME_TENS_FREE ] << " seconds" << endl; cout << "*** |--> disk write = " << timings[ CHEMPS2_TIME_DISK_WRITE ] << " seconds" << endl; cout << "*** |--> disk read = " << timings[ CHEMPS2_TIME_DISK_READ ] << " seconds" << endl; cout << "*** |--> calc = " << timings[ CHEMPS2_TIME_TENS_CALC ] << " seconds" << endl; cout << "*** Disk write bandwidth = " << num_double_write_disk * sizeof(double) / ( timings[ CHEMPS2_TIME_DISK_WRITE ] * 1048576 ) << " MB/s" << endl; cout << "*** Disk read bandwidth = " << num_double_read_disk * sizeof(double) / ( timings[ CHEMPS2_TIME_DISK_READ ] * 1048576 ) << " MB/s" << endl; } void CheMPS2::DMRG::left_normalize( TensorT * left_mps, TensorT * right_mps ){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif if ( am_i_master ){ const int siteindex = left_mps->gIndex(); const SyBookkeeper * theBK = left_mps->gBK(); // (J,N,I) = (0,0,0) and (moving_right, prime_last, jw_phase) = (true, true, false) TensorOperator * temp = new TensorOperator( siteindex + 1, 0, 0, 0, true, true, false, theBK, theBK ); left_mps->QR( temp ); if ( right_mps != NULL ){ right_mps->LeftMultiply( temp ); } delete temp; } #ifdef CHEMPS2_MPI_COMPILATION MPIchemps2::broadcast_tensor( left_mps, MPI_CHEMPS2_MASTER ); if ( right_mps != NULL ){ MPIchemps2::broadcast_tensor( right_mps, MPI_CHEMPS2_MASTER ); } #endif } void CheMPS2::DMRG::right_normalize( TensorT * left_mps, TensorT * right_mps ){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif if ( am_i_master ){ const int siteindex = right_mps->gIndex(); const SyBookkeeper * theBK = right_mps->gBK(); // (J,N,I) = (0,0,0) and (moving_right, prime_last, jw_phase) = (true, true, false) TensorOperator * temp = new TensorOperator( siteindex, 0, 0, 0, true, true, false, theBK, theBK ); right_mps->LQ( temp ); if ( left_mps != NULL ){ left_mps->RightMultiply( temp ); } delete temp; } #ifdef CHEMPS2_MPI_COMPILATION MPIchemps2::broadcast_tensor( right_mps, MPI_CHEMPS2_MASTER ); if ( left_mps != NULL ){ MPIchemps2::broadcast_tensor( left_mps, MPI_CHEMPS2_MASTER ); } #endif } double CheMPS2::DMRG::getSpecificCoefficient(int * coeff) const{ int * alpha = new int[ L ]; int * beta = new int[ L ]; for ( int orb=0; orb= 0 ) && ( coeff[orb] <= 2 ) ); if ( coeff[orb] == 0 ){ alpha[orb] = 0; beta[orb] = 0; } if ( coeff[orb] == 1 ){ alpha[orb] = 1; beta[orb] = 0; } if ( coeff[orb] == 2 ){ alpha[orb] = 1; beta[orb] = 1; } } const double FCIcoeff = getFCIcoefficient( alpha, beta ); delete [] alpha; delete [] beta; return FCIcoeff; } double CheMPS2::DMRG::getFCIcoefficient(int * alpha, int * beta, const bool mpi_chemps2_master_only) const{ //DMRGcoeff = alpha/beta[Hamindex = Prob->gf2(DMRGindex)] //Check if it's possible { int nTot = 0; int twoSz = 0; int iTot = 0; for (int DMRGindex=0; DMRGindexgReorder()) ? Prob->gf2(DMRGindex) : DMRGindex; assert( ( alpha[HamIndex] == 0 ) || ( alpha[HamIndex] == 1 ) ); assert( ( beta[HamIndex] == 0 ) || ( beta[HamIndex] == 1 ) ); nTot += alpha[HamIndex] + beta[HamIndex]; twoSz += alpha[HamIndex] - beta[HamIndex]; if ((alpha[HamIndex]+beta[HamIndex])==1){ iTot = Irreps::directProd(iTot,denBK->gIrrep(DMRGindex)); } } if ( Prob->gN() != nTot ){ cout << "DMRG::getFCIcoefficient : Ndesired = " << Prob->gN() << " and Ntotal in alpha and beta strings = " << nTot << endl; return 0.0; } // 2Sz can be -Prob->2S() ; -Prob->2S()+2 ; -Prob->2S()+4 ; ... ; Prob->2S() if ( ( Prob->gTwoS() < twoSz ) || ( twoSz < -Prob->gTwoS() ) || ( ( Prob->gTwoS() - twoSz ) % 2 != 0 ) ){ cout << "DMRG::getFCIcoefficient : 2Sdesired = " << Prob->gTwoS() << " and 2Sz in alpha and beta strings = " << twoSz << endl; return 0.0; } if ( Prob->gIrrep() != iTot ){ cout << "DMRG::getFCIcoefficient : Idesired = " << Prob->gIrrep() << " and Irrep of alpha and beta strings = " << iTot << endl; return 0.0; } } double theCoeff = 2.0; // A FCI coefficient always lies in between -1.0 and 1.0 #ifdef CHEMPS2_MPI_COMPILATION if (( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ) || ( mpi_chemps2_master_only == false )) #endif { //Construct necessary arrays int Dmax = 1; for (int DMRGindex=1; DMRGindexgTotDimAtBound(DMRGindex); if (DtotBound>Dmax){ Dmax = DtotBound; } } double * arrayL = new double[Dmax]; double * arrayR = new double[Dmax]; int * twoSL = new int[L]; int * twoSR = new int[L]; int * jumpL = new int[L+1]; int * jumpR = new int[L+1]; //Start the iterator int num_SL = 0; jumpL[num_SL] = 0; int dimFirst = 1; jumpL[num_SL+1] = jumpL[num_SL] + dimFirst; twoSL[num_SL] = 0; num_SL++; arrayL[0] = 1.0; int NL = 0; int IL = 0; int twoSLz = 0; for (int DMRGindex=0; DMRGindexgReorder()) ? Prob->gf2(DMRGindex) : DMRGindex; const int Nlocal = alpha[HamIndex] + beta[HamIndex]; const int twoSzloc = alpha[HamIndex] - beta[HamIndex]; //The right symmetry sectors const int NR = NL + Nlocal; const int twoSRz = twoSLz + twoSzloc; const int IR = (( Nlocal == 1 ) ? (Irreps::directProd(IL,denBK->gIrrep(DMRGindex))) : IL); int num_SR = 0; jumpR[num_SR] = 0; const int spread = ( ( Nlocal == 1 ) ? 1 : 0 ); for ( int cntSL = 0; cntSL < num_SL; cntSL++ ){ for ( int TwoSRattempt = twoSL[cntSL] - spread; TwoSRattempt <= twoSL[cntSL] + spread; TwoSRattempt+=2 ){ bool encountered = false; for ( int cntSR = 0; cntSR < num_SR; cntSR++ ){ if ( twoSR[cntSR] == TwoSRattempt ){ encountered = true; } } if ( encountered == false ){ const int dimR = denBK->gCurrentDim(DMRGindex+1,NR,TwoSRattempt,IR); if ( dimR > 0 ){ jumpR[num_SR+1] = jumpR[num_SR] + dimR; twoSR[num_SR] = TwoSRattempt; num_SR++; } } } } assert( jumpR[num_SR] <= Dmax ); for ( int cntSR = 0; cntSR < num_SR; cntSR++ ){ int TwoSRvalue = twoSR[ cntSR ]; int dimR = jumpR[ cntSR+1 ] - jumpR[ cntSR ]; for ( int TwoSLvalue = TwoSRvalue - spread; TwoSLvalue <= TwoSRvalue + spread; TwoSLvalue += 2 ){ int indexSL = -1; for ( int cntSL = 0; cntSL < num_SL; cntSL++ ){ if ( twoSL[cntSL] == TwoSLvalue ){ indexSL = cntSL; cntSL = num_SL; //exit loop } } if ( indexSL != -1 ){ int dimL = jumpL[ indexSL+1 ] - jumpL[ indexSL ]; double * Tblock = MPS[DMRGindex]->gStorage(NL,TwoSLvalue,IL,NR,TwoSRvalue,IR); double prefactor = sqrt( TwoSRvalue + 1 ) * Wigner::wigner3j(TwoSLvalue, spread, TwoSRvalue, twoSLz, twoSzloc, -twoSRz) * Special::phase( -TwoSLvalue + spread - twoSRz ); double add2array = 1.0; char notrans = 'N'; dgemm_( ¬rans, ¬rans, &dimFirst, &dimR, &dimL, &prefactor, arrayL + jumpL[indexSL], &dimFirst, Tblock, &dimL, &add2array, arrayR + jumpR[cntSR], &dimFirst); } } } //Swap L <--> R { double * temp = arrayR; arrayR = arrayL; arrayL = temp; int * temp2 = twoSR; twoSR = twoSL; twoSL = temp2; temp2 = jumpR; jumpR = jumpL; jumpL = temp2; num_SL = num_SR; NL = NR; IL = IR; twoSLz = twoSRz; } } theCoeff = arrayL[0]; assert( num_SL == 1 ); assert( jumpL[1] == 1 ); assert( twoSL[0] == Prob->gTwoS() ); assert( NL == Prob->gN() ); assert( IL == Prob->gIrrep() ); delete [] arrayL; delete [] arrayR; delete [] twoSL; delete [] twoSR; delete [] jumpL; delete [] jumpR; } #ifdef CHEMPS2_MPI_COMPILATION if ( mpi_chemps2_master_only ){ MPIchemps2::broadcast_array_double( &theCoeff, 1, MPI_CHEMPS2_MASTER ); } #endif return theCoeff; } double ** CheMPS2::DMRG::prepare_excitations(Sobject * denS){ double ** VeffTilde = new double*[nStates-1]; for (int state=0; stategKappa2index(denS->gNKappa())]; calcVeffTilde(VeffTilde[state], denS, state); #ifdef CHEMPS2_MPI_COMPILATION } else { VeffTilde[state] = NULL; } #endif } return VeffTilde; } void CheMPS2::DMRG::cleanup_excitations(double ** VeffTilde) const{ for (int state=0; stategKappa2index(currentS->gNKappa()); for (int cnt=0; cntgIndex(); const int dimL = std::max(denBK->gMaxDimAtBound(index), Exc_BKs[state_number]->gMaxDimAtBound(index) ); const int dimR = std::max(denBK->gMaxDimAtBound(index+2), Exc_BKs[state_number]->gMaxDimAtBound(index+2) ); double * workmem = new double[dimL * dimR]; //Construct Sup Sobject * Sup = new Sobject( index, Exc_BKs[ state_number ] ); Sup->Join(Exc_MPSs[state_number][index],Exc_MPSs[state_number][index+1]); //Construct VeffTilde const double prefactor = sqrt(Exc_Eshifts[state_number]) / (Prob->gTwoS() + 1.0); for (int ikappa=0; ikappagNKappa(); ikappa++){ int NL = currentS->gNL(ikappa); int TwoSL = currentS->gTwoSL(ikappa); int IL = currentS->gIL(ikappa); int N1 = currentS->gN1(ikappa); int N2 = currentS->gN2(ikappa); int TwoJ = currentS->gTwoJ(ikappa); int NR = currentS->gNR(ikappa); int TwoSR = currentS->gTwoSR(ikappa); int IR = currentS->gIR(ikappa); //Check if block also exists for other MPS int kappaSup = Sup->gKappa(NL, TwoSL, IL, N1, N2, TwoJ, NR, TwoSR, IR); if (kappaSup!=-1){ int dimLdown = denBK->gCurrentDim(index, NL,TwoSL,IL); int dimLup = Exc_BKs[state_number]->gCurrentDim(index, NL,TwoSL,IL); int dimRdown = denBK->gCurrentDim(index+2,NR,TwoSR,IR); int dimRup = Exc_BKs[state_number]->gCurrentDim(index+2,NR,TwoSR,IR); //Do sqrt( (TwoJR+1) * Eshift ) / (TwoStarget+1) times (OL * Sup)_{block} --> workmem double * SupPart = Sup->gStorage() + Sup->gKappa2index(kappaSup); double alpha = prefactor * sqrt(TwoSR+1.0); if (index==0){ int dimBlock = dimLup * dimRup; int inc = 1; dcopy_(&dimBlock,SupPart,&inc,workmem,&inc); dscal_(&dimBlock,&alpha,workmem,&inc); } else { char notrans = 'N'; double beta = 0.0; double * Opart = Exc_Overlaps[state_number][index-1]->gStorage(NL,TwoSL,IL,NL,TwoSL,IL); dgemm_(¬rans,¬rans,&dimLdown,&dimRup,&dimLup,&alpha,Opart,&dimLdown,SupPart,&dimLup,&beta,workmem,&dimLdown); } //Do (workmem * OR)_{block} --> result + jumpCurrentS int jumpCurrentS = currentS->gKappa2index(ikappa); if (index==L-2){ int dimBlock = dimLdown * dimRdown; int inc = 1; dcopy_(&dimBlock, workmem, &inc, result + jumpCurrentS, &inc); } else { char trans = 'T'; char notrans = 'N'; alpha = 1.0; double beta = 0.0; //set double * Opart = Exc_Overlaps[state_number][index+1]->gStorage(NR,TwoSR,IR,NR,TwoSR,IR); dgemm_(¬rans,&trans,&dimLdown,&dimRdown,&dimRup,&alpha,workmem,&dimLdown,Opart,&dimRdown,&beta,result+jumpCurrentS,&dimLdown); } } } //Deallocate everything delete Sup; delete [] workmem; } void CheMPS2::DMRG::calc_overlaps( const bool moving_right ){ for ( int state = 0; state < nStates - 1; state++ ){ double overlap; #ifdef CHEMPS2_MPI_COMPILATION const int OWNER = MPIchemps2::owner_specific_excitation( L, state ); if ( OWNER == MPIchemps2::mpi_rank() ){ #endif if ( moving_right ){ TensorO * first = new TensorO( L - 1, moving_right, denBK, Exc_BKs[ state ] ); TensorO * second = new TensorO( L, moving_right, denBK, Exc_BKs[ state ] ); first->update_ownmem( MPS[ L - 2 ], Exc_MPSs[ state ][ L - 2 ], Exc_Overlaps[ state ][ L - 3 ] ); second->update_ownmem( MPS[ L - 1 ], Exc_MPSs[ state ][ L - 1 ], first ); overlap = second->gStorage()[ 0 ]; delete second; delete first; } else { TensorO * first = new TensorO( 1, moving_right, denBK, Exc_BKs[ state ] ); TensorO * second = new TensorO( 0, moving_right, denBK, Exc_BKs[ state ] ); first->update_ownmem( MPS[ 1 ], Exc_MPSs[ state ][ 1 ], Exc_Overlaps[ state ][ 1 ] ); second->update_ownmem( MPS[ 0 ], Exc_MPSs[ state ][ 0 ], first ); overlap = second->gStorage()[ 0 ] / ( Prob->gTwoS() + 1 ); delete second; delete first; } #ifdef CHEMPS2_MPI_COMPILATION } MPIchemps2::broadcast_array_double( &overlap, 1, OWNER ); if ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ) #endif { cout << "*** The overlap < " << nStates-1 << " | " << state << " > = " << overlap << endl; } } } CheMPS2-1.8.9/CheMPS2/Davidson.cpp000066400000000000000000000513501336564451100163220ustar00rootroot00000000000000/* CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry Copyright (C) 2013-2018 Sebastian Wouters This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include "Davidson.h" #include "Lapack.h" using std::cout; using std::endl; CheMPS2::Davidson::Davidson( const int veclength, const int MAX_NUM_VEC, const int NUM_VEC_KEEP, const double RTOL, const double DIAG_CUTOFF, const bool debug_print, const char problem_type ){ assert( ( problem_type == 'E' ) || ( problem_type == 'L' ) ); this->debug_print = debug_print; this->veclength = veclength; this->problem_type = problem_type; this->MAX_NUM_VEC = MAX_NUM_VEC; this->NUM_VEC_KEEP = NUM_VEC_KEEP; this->DIAG_CUTOFF = DIAG_CUTOFF; this->RTOL = RTOL; state = 'I'; // nitialized Davidson nMultiplications = 0; // To store the vectors and the matrix x vectors num_vec = 0; vecs = new double*[ MAX_NUM_VEC ]; Hvecs = new double*[ MAX_NUM_VEC ]; num_allocated = 0; // The projected problem mxM = new double[ MAX_NUM_VEC * MAX_NUM_VEC ]; mxM_eigs = new double[ MAX_NUM_VEC ]; mxM_vecs = new double[ MAX_NUM_VEC * MAX_NUM_VEC ]; mxM_lwork = 3 * MAX_NUM_VEC - 1; mxM_work = new double[ mxM_lwork ]; mxM_rhs = (( problem_type == 'L' ) ? new double[ MAX_NUM_VEC ] : NULL ); // Vector spaces diag = new double[ veclength ]; t_vec = new double[ veclength ]; u_vec = new double[ veclength ]; work_vec = new double[ veclength ]; RHS = (( problem_type == 'L' ) ? new double[ veclength ] : NULL ); // For the deflation Reortho_Lowdin = NULL; Reortho_Overlap_eigs = NULL; Reortho_Overlap = NULL; Reortho_Eigenvecs = NULL; } CheMPS2::Davidson::~Davidson(){ for (int cnt = 0; cnt < num_allocated; cnt++){ delete [] vecs[cnt]; delete [] Hvecs[cnt]; } delete [] vecs; delete [] Hvecs; delete [] mxM; delete [] mxM_eigs; delete [] mxM_vecs; delete [] mxM_work; if ( mxM_rhs != NULL ){ delete [] mxM_rhs; } delete [] diag; delete [] t_vec; delete [] u_vec; delete [] work_vec; if ( RHS != NULL ){ delete [] RHS; } if ( Reortho_Lowdin != NULL ){ delete [] Reortho_Lowdin; } if ( Reortho_Overlap_eigs != NULL ){ delete [] Reortho_Overlap_eigs; } if ( Reortho_Overlap != NULL ){ delete [] Reortho_Overlap; } if ( Reortho_Eigenvecs != NULL ){ delete [] Reortho_Eigenvecs; } } int CheMPS2::Davidson::GetNumMultiplications() const{ return nMultiplications; } char CheMPS2::Davidson::FetchInstruction( double ** pointers ){ /* Possible states: - I : just initialized - U : just before the big loop, the initial guess and the diagonal are set - N : a new vector has just been added to the list and a matrix-vector multiplication has been performed - F : the space has been deflated and a few matrix-vector multiplications are required - C : convergence was reached Possible instructions: - A : copy the initial guess to pointers[0], the diagonal to pointers[1], and if problem_type=='L' the right-hand side of the linear problem to pointers[2] - B : perform pointers[1] = symmetric matrix times pointers[0] - C : copy the converged solution from pointers[0] back; pointers[1][0] contains the converged energy if problem_type=='E' and the residual norm if problem_type=='L' - D : there was an error */ if ( state == 'I' ){ pointers[ 0 ] = t_vec; pointers[ 1 ] = diag; if ( problem_type == 'L' ){ pointers[ 2 ] = RHS; } state = 'U'; return 'A'; } if ( state == 'U' ){ SafetyCheckGuess(); AddNewVec(); pointers[ 0 ] = vecs[ num_vec ]; pointers[ 1 ] = Hvecs[ num_vec ]; nMultiplications++; state = 'N'; return 'B'; } if ( state == 'N' ){ const double rnorm = DiagonalizeSmallMatrixAndCalcResidual(); // if ( debug_print ){ cout << "WARNING AT DAVIDSON : Current residual norm = " << rnorm << endl; } if ( rnorm > RTOL ){ // Not yet converged CalculateNewVec(); if ( num_vec == MAX_NUM_VEC ){ Deflation(); pointers[ 0 ] = vecs[ num_vec ]; pointers[ 1 ] = Hvecs[ num_vec ]; nMultiplications++; num_vec++; state = 'F'; return 'B'; } AddNewVec(); pointers[ 0 ] = vecs[ num_vec ]; pointers[ 1 ] = Hvecs[ num_vec ]; nMultiplications++; state = 'N'; return 'B'; } else { // Converged state = 'C'; pointers[ 0 ] = u_vec; pointers[ 1 ] = work_vec; if ( problem_type == 'E' ){ work_vec[ 0 ] = mxM_eigs[ 0 ]; } if ( problem_type == 'L' ){ work_vec[ 0 ] = rnorm; } return 'C'; } } if ( state == 'F' ){ if ( num_vec == NUM_VEC_KEEP ){ MxMafterDeflation(); AddNewVec(); pointers[ 0 ] = vecs[ num_vec ]; pointers[ 1 ] = Hvecs[ num_vec ]; nMultiplications++; state = 'N'; return 'B'; } else { pointers[ 0 ] = vecs[ num_vec ]; pointers[ 1 ] = Hvecs[ num_vec ]; nMultiplications++; num_vec++; state = 'F'; return 'B'; } } return 'D'; } double CheMPS2::Davidson::FrobeniusNorm( double * current_vector ){ char frobenius = 'F'; int inc1 = 1; const double twonorm = dlange_( &frobenius, &veclength, &inc1, current_vector, &veclength, NULL ); // Work is not referenced for Frobenius norm return twonorm; } void CheMPS2::Davidson::SafetyCheckGuess(){ const double twonorm = FrobeniusNorm( t_vec ); if ( twonorm == 0.0 ){ for ( int cnt = 0; cnt < veclength; cnt++ ){ t_vec[ cnt ] = ( (double) rand() ) / RAND_MAX; } if ( debug_print ){ cout << "WARNING AT DAVIDSON : Initial guess was a zero-vector. Now it is overwritten with random numbers." << endl; } } } void CheMPS2::Davidson::AddNewVec(){ int inc1 = 1; // Orthogonalize the new vector w.r.t. the old basis for ( int cnt = 0; cnt < num_vec; cnt++ ){ double minus_overlap = - ddot_( &veclength, t_vec, &inc1, vecs[ cnt ], &inc1 ); daxpy_( &veclength, &minus_overlap, vecs[ cnt ], &inc1, t_vec, &inc1 ); } // Normalize the new vector double alpha = 1.0 / FrobeniusNorm( t_vec ); dscal_( &veclength, &alpha, t_vec, &inc1 ); // The new vector becomes part of vecs if ( num_vec < num_allocated ){ double * temp = vecs[ num_vec ]; vecs[ num_vec ] = t_vec; t_vec = temp; } else { vecs[ num_allocated ] = t_vec; Hvecs[ num_allocated ] = new double[ veclength ]; t_vec = new double[ veclength ]; num_allocated++; } } double CheMPS2::Davidson::DiagonalizeSmallMatrixAndCalcResidual(){ int inc1 = 1; if ( problem_type == 'E' ){ // EIGENVALUE PROBLEM // mxM contains V^T . A . V for ( int cnt = 0; cnt < num_vec; cnt++ ){ mxM[ cnt + MAX_NUM_VEC * num_vec ] = ddot_( &veclength, vecs[ num_vec ], &inc1, Hvecs[ cnt ], &inc1 ); mxM[ num_vec + MAX_NUM_VEC * cnt ] = mxM[ cnt + MAX_NUM_VEC * num_vec ]; } mxM[ num_vec + MAX_NUM_VEC * num_vec ] = ddot_( &veclength, vecs[ num_vec ], &inc1, Hvecs[ num_vec ], &inc1 ); } else { // LINEAR PROBLEM // mxM contains V^T . A^T . A . V for ( int cnt = 0; cnt < num_vec; cnt++ ){ mxM[ cnt + MAX_NUM_VEC * num_vec ] = ddot_( &veclength, Hvecs[ num_vec ], &inc1, Hvecs[ cnt ], &inc1 ); mxM[ num_vec + MAX_NUM_VEC * cnt ] = mxM[ cnt + MAX_NUM_VEC * num_vec ]; } mxM[ num_vec + MAX_NUM_VEC * num_vec ] = ddot_( &veclength, Hvecs[ num_vec ], &inc1, Hvecs[ num_vec ], &inc1 ); // mxM_rhs contains V^T . A^T . RHS mxM_rhs[ num_vec ] = ddot_( &veclength, Hvecs[ num_vec ], &inc1, RHS, &inc1 ); } // When t-vec was added to vecs, the number of vecs was actually increased by one. Now the number is incremented. num_vec++; // Diagonalize mxM ( always ) char jobz = 'V'; char uplo = 'U'; int info; for ( int cnt1 = 0; cnt1 < num_vec; cnt1++ ){ for ( int cnt2 = 0; cnt2 < num_vec; cnt2++ ){ mxM_vecs[ cnt1 + MAX_NUM_VEC * cnt2 ] = mxM[ cnt1 + MAX_NUM_VEC * cnt2 ]; } } dsyev_( &jobz, &uplo, &num_vec, mxM_vecs, &MAX_NUM_VEC, mxM_eigs, mxM_work, &mxM_lwork, &info ); // Ascending order of eigenvalues // If problem_type == linear, solve the linear problem in least-squares sense! if ( problem_type == 'L' ){ double one = 1.0; double set = 0.0; char trans = 'T'; char notra = 'N'; dgemm_( &trans, ¬ra, &num_vec, &inc1, &num_vec, &one, mxM_vecs, &MAX_NUM_VEC, mxM_rhs, &MAX_NUM_VEC, &set, mxM_work, &MAX_NUM_VEC ); // mxM_work = mxM_vecs^T * mxM_rhs for ( int cnt = 0; cnt < num_vec; cnt++ ){ double current_eigenvalue = mxM_eigs[ cnt ]; if ( fabs( current_eigenvalue ) < DIAG_CUTOFF ){ current_eigenvalue = DIAG_CUTOFF * (( current_eigenvalue < 0.0 ) ? -1 : 1 ); if ( debug_print ){ cout << "WARNING AT DAVIDSON : The eigenvalue " << mxM_eigs[ cnt ] << " to solve Ax = b has been overwritten with " << current_eigenvalue << "." << endl; } } mxM_work[ cnt ] = mxM_work[ cnt ] / current_eigenvalue; } dgemm_( ¬ra, ¬ra, &num_vec, &inc1, &num_vec, &one, mxM_vecs, &MAX_NUM_VEC, mxM_work, &MAX_NUM_VEC, &set, mxM_work + MAX_NUM_VEC, &MAX_NUM_VEC ); for ( int cnt = 0; cnt < num_vec; cnt++ ){ mxM_vecs[ cnt ] = mxM_work[ MAX_NUM_VEC + cnt ]; } // mxM_vecs = U * eigs^{-1} * U^T * RHS } // Calculate u and r. r is stored in t_vec, u in u_vec. for ( int cnt = 0; cnt < veclength; cnt++ ){ t_vec[ cnt ] = 0.0; } for ( int cnt = 0; cnt < veclength; cnt++ ){ u_vec[ cnt ] = 0.0; } for ( int cnt = 0; cnt < num_vec; cnt++ ){ double alpha = mxM_vecs[ cnt ]; // Eigenvector with lowest eigenvalue, hence mxM_vecs[ cnt + MAX_NUM_VEC * 0 ] daxpy_( &veclength, &alpha, Hvecs[ cnt ], &inc1, t_vec, &inc1 ); daxpy_( &veclength, &alpha, vecs[ cnt ], &inc1, u_vec, &inc1 ); } if ( problem_type == 'E' ){ // t_vec = H * x - lambda * x double alpha = - mxM_eigs[ 0 ]; daxpy_( &veclength, &alpha, u_vec, &inc1, t_vec, &inc1 ); } else { // t_vec = H * x - RHS double alpha = -1.0; daxpy_( &veclength, &alpha, RHS, &inc1, t_vec, &inc1 ); } // Calculate the norm of r const double rnorm = FrobeniusNorm( t_vec ); //cout << " Davidson :: rnorm = " << rnorm << endl; return rnorm; } void CheMPS2::Davidson::CalculateNewVec(){ int inc1 = 1; const double shift = (( problem_type == 'E' ) ? mxM_eigs[ 0 ] : 0.0 ); // Calculate the new t_vec based on the residual of the lowest eigenvalue, to add to the vecs. for ( int cnt = 0; cnt < veclength; cnt++ ){ const double difference = diag[ cnt ] - shift; const double fabsdiff = fabs( difference ); if ( fabsdiff > DIAG_CUTOFF ){ work_vec[ cnt ] = u_vec[ cnt ] / difference; // work_vec = K^(-1) u_vec } else { work_vec[ cnt ] = u_vec[ cnt ] / DIAG_CUTOFF; if ( debug_print ){ cout << "WARNING AT DAVIDSON : fabs( precon[" << cnt << "] ) = " << fabsdiff << endl; } } } double alpha = - ddot_( &veclength, work_vec, &inc1, t_vec, &inc1 ) / ddot_( &veclength, work_vec, &inc1, u_vec, &inc1 ); // alpha = - (u^T K^(-1) r) / (u^T K^(-1) u) daxpy_( &veclength, &alpha, u_vec, &inc1, t_vec, &inc1 ); // t_vec = r - (u^T K^(-1) r) / (u^T K^(-1) u) u for ( int cnt = 0; cnt < veclength; cnt++ ){ const double difference = diag[ cnt ] - shift; const double fabsdiff = fabs( difference ); if ( fabsdiff > DIAG_CUTOFF ){ t_vec[ cnt ] = - t_vec[ cnt ] / difference; // t_vec = - K^(-1) (r - (u^T K^(-1) r) / (u^T K^(-1) u) u) } else { t_vec[ cnt ] = - t_vec[ cnt ] / DIAG_CUTOFF; } } } void CheMPS2::Davidson::Deflation(){ int inc1 = 1; // When the maximum number of vectors is reached: construct the one with lowest eigenvalue & restart if ( NUM_VEC_KEEP <= 1 ){ double alpha = 1.0 / FrobeniusNorm( u_vec ); dscal_( &veclength, &alpha, u_vec, &inc1 ); dcopy_( &veclength, u_vec, &inc1, vecs[ 0 ], &inc1 ); } else { if ( problem_type == 'L' ){ SolveLinearSystemDeflation( NUM_VEC_KEEP ); } if ( Reortho_Eigenvecs == NULL ){ Reortho_Eigenvecs = new double[ veclength * NUM_VEC_KEEP ]; } if ( Reortho_Overlap == NULL ){ Reortho_Overlap = new double[ NUM_VEC_KEEP * NUM_VEC_KEEP ]; } if ( Reortho_Overlap_eigs == NULL ){ Reortho_Overlap_eigs = new double[ NUM_VEC_KEEP ]; } if ( Reortho_Lowdin == NULL ){ Reortho_Lowdin = new double[ NUM_VEC_KEEP * NUM_VEC_KEEP ]; } // Construct the lowest NUM_VEC_KEEP eigenvectors dcopy_( &veclength, u_vec, &inc1, Reortho_Eigenvecs, &inc1 ); for ( int cnt = 1; cnt < NUM_VEC_KEEP; cnt++ ){ for ( int irow = 0; irow < veclength; irow++ ){ Reortho_Eigenvecs[ irow + veclength * cnt ] = 0.0; for ( int ivec = 0; ivec < MAX_NUM_VEC; ivec++ ){ Reortho_Eigenvecs[ irow + veclength * cnt ] += vecs[ ivec ][ irow ] * mxM_vecs[ ivec + MAX_NUM_VEC * cnt ]; } } } // Calculate the overlap matrix char trans = 'T'; char notr = 'N'; double one = 1.0; double zero = 0.0; //set dgemm_( &trans, ¬r, &NUM_VEC_KEEP, &NUM_VEC_KEEP, &veclength, &one, Reortho_Eigenvecs, &veclength, Reortho_Eigenvecs, &veclength, &zero, Reortho_Overlap, &NUM_VEC_KEEP ); // Calculate the Lowdin tfo char jobz = 'V'; char uplo = 'U'; int info; dsyev_( &jobz, &uplo, &NUM_VEC_KEEP, Reortho_Overlap, &NUM_VEC_KEEP, Reortho_Overlap_eigs, mxM_work, &mxM_lwork, &info ); // Ascending order of eigs for ( int icnt = 0; icnt < NUM_VEC_KEEP; icnt++ ){ Reortho_Overlap_eigs[ icnt ] = pow( Reortho_Overlap_eigs[ icnt ], -0.25 ); dscal_( &NUM_VEC_KEEP, Reortho_Overlap_eigs + icnt, Reortho_Overlap + NUM_VEC_KEEP * icnt, &inc1 ); } dgemm_( ¬r, &trans, &NUM_VEC_KEEP, &NUM_VEC_KEEP, &NUM_VEC_KEEP, &one, Reortho_Overlap, &NUM_VEC_KEEP, Reortho_Overlap, &NUM_VEC_KEEP, &zero, Reortho_Lowdin, &NUM_VEC_KEEP ); // Reortho: Put the Lowdin tfo eigenvecs in vecs for ( int ivec = 0; ivec < NUM_VEC_KEEP; ivec++ ){ for ( int loop = 0; loop < veclength; loop++ ){ vecs[ ivec ][ loop ] = 0.0; } for ( int ivec2 = 0; ivec2 < NUM_VEC_KEEP; ivec2++ ){ daxpy_( &veclength, Reortho_Lowdin + ivec2 + NUM_VEC_KEEP * ivec, Reortho_Eigenvecs + veclength * ivec2, &inc1, vecs[ ivec ], &inc1 ); } } } num_vec = 0; } void CheMPS2::Davidson::SolveLinearSystemDeflation( const int NUM_SOLUTIONS ){ assert( problem_type == 'L' ); assert( num_vec == MAX_NUM_VEC ); assert( NUM_SOLUTIONS <= MAX_NUM_VEC ); assert( 2 <= NUM_SOLUTIONS ); double * work1 = new double[ MAX_NUM_VEC * MAX_NUM_VEC ]; // projector double * work3 = new double[ MAX_NUM_VEC * MAX_NUM_VEC ]; // projector times mxM_rhs double * work2 = new double[ MAX_NUM_VEC * NUM_SOLUTIONS ]; // solutions for ( int solution = 0; solution < NUM_SOLUTIONS; solution++ ){ // work1 = ( 1 - sum_j v_j v_j^T ) = projector for ( int cntr = 0; cntr < MAX_NUM_VEC * MAX_NUM_VEC; cntr++ ){ work1[ cntr ] = 0.0; } for ( int diag = 0; diag < MAX_NUM_VEC; diag++ ){ work1[ diag * ( 1 + MAX_NUM_VEC ) ] = 1.0; } for ( int prev = 0; prev < solution; prev++ ){ for ( int col = 0; col < MAX_NUM_VEC; col++ ){ for ( int row = 0; row < MAX_NUM_VEC; row++ ){ work1[ row + MAX_NUM_VEC * col ] -= work2[ row + MAX_NUM_VEC * prev ] * work2[ col + MAX_NUM_VEC * prev ]; } } } // work3 = ( 1 - sum_j v_j v_j^T ) * [ U^T * A^T * b ] = work1 * mxM_rhs // mxM_vecs = ( 1 - sum_j v_j v_j^T ) * [ U^T * A^T * A * U ] * ( 1 - sum_j v_j v_j^T ) = work1 * mxM * work1 { double one = 1.0; double set = 0.0; char notrans = 'N'; int inc1 = 1; dgemm_( ¬rans, ¬rans, &MAX_NUM_VEC, &MAX_NUM_VEC, &MAX_NUM_VEC, &one, work1, &MAX_NUM_VEC, mxM, &MAX_NUM_VEC, &set, work3, &MAX_NUM_VEC ); dgemm_( ¬rans, ¬rans, &MAX_NUM_VEC, &MAX_NUM_VEC, &MAX_NUM_VEC, &one, work3, &MAX_NUM_VEC, work1, &MAX_NUM_VEC, &set, mxM_vecs, &MAX_NUM_VEC ); dgemm_( ¬rans, ¬rans, &MAX_NUM_VEC, &inc1, &MAX_NUM_VEC, &one, work1, &MAX_NUM_VEC, mxM_rhs, &MAX_NUM_VEC, &set, work3, &MAX_NUM_VEC ); } // Diagonalize mxM_vecs = V * lambda * V^T ===> Ascending order of eigenvalues & ( V, lambda ) = ( mxM_vecs, mxM_eigs ) { char jobz = 'V'; char uplo = 'U'; int info; dsyev_( &jobz, &uplo, &MAX_NUM_VEC, mxM_vecs, &MAX_NUM_VEC, mxM_eigs, mxM_work, &mxM_lwork, &info ); } // work2[ :, solution ] = [ ( 1 - sum_j v_j v_j^T ) * [ U^T * A^T * A * U ] * ( 1 - sum_j v_j v_j^T ) ]^{-1} * ( 1 - sum_j v_j v_j^T ) * [ U^T * A^T * b ] = V * lambda^{-1} * V^T * work3 { double one = 1.0; double set = 0.0; char trans = 'T'; char notrans = 'N'; int inc1 = 1; dgemm_( &trans, ¬rans, &MAX_NUM_VEC, &inc1, &MAX_NUM_VEC, &one, mxM_vecs, &MAX_NUM_VEC, work3, &MAX_NUM_VEC, &set, mxM_work, &MAX_NUM_VEC ); for ( int diag = 0; diag < MAX_NUM_VEC; diag++ ){ if ( diag < solution ){ mxM_work[ diag ] = 0.0; // PSEUDOINVERSE } else { double current_eigenvalue = mxM_eigs[ diag ]; if ( fabs( current_eigenvalue ) < DIAG_CUTOFF ){ current_eigenvalue = DIAG_CUTOFF * (( current_eigenvalue < 0.0 ) ? -1 : 1 ); if ( debug_print ){ cout << "WARNING AT DAVIDSON : The eigenvalue " << mxM_eigs[ diag ] << " to solve Ax = b has been overwritten with " << current_eigenvalue << "." << endl; } } mxM_work[ diag ] = mxM_work[ diag ] / current_eigenvalue; } } dgemm_( ¬rans, ¬rans, &MAX_NUM_VEC, &inc1, &MAX_NUM_VEC, &one, mxM_vecs, &MAX_NUM_VEC, mxM_work, &MAX_NUM_VEC, &set, work2 + MAX_NUM_VEC * solution, &MAX_NUM_VEC ); } // Normalize work2[ :, solution ] { int inc1 = 1; double * ptr = work2 + MAX_NUM_VEC * solution; const double twonorm = sqrt( ddot_( &MAX_NUM_VEC, ptr, &inc1, ptr, &inc1 ) ); /*if ( debug_print ){ cout << "Davidson :: Deflation :: Norm of solution " << solution << " = " << twonorm << endl; }*/ double factor = 1.0 / twonorm; dscal_( &MAX_NUM_VEC, &factor, ptr, &inc1 ); } } // Copy over work2 to mxM_vecs { int inc1 = 1; int size = MAX_NUM_VEC * NUM_SOLUTIONS; dcopy_( &size, work2, &inc1, mxM_vecs, &inc1 ); } delete [] work1; delete [] work2; delete [] work3; } void CheMPS2::Davidson::MxMafterDeflation(){ int inc1 = 1; if ( problem_type == 'E' ){ // EIGENVALUE PROBLEM // mxM contains V^T . A . V for ( int ivec = 0; ivec < NUM_VEC_KEEP; ivec++ ){ for ( int ivec2 = ivec; ivec2 < NUM_VEC_KEEP; ivec2++ ){ mxM[ ivec + MAX_NUM_VEC * ivec2 ] = ddot_( &veclength, vecs[ ivec ], &inc1, Hvecs[ ivec2 ], &inc1 ); mxM[ ivec2 + MAX_NUM_VEC * ivec ] = mxM[ ivec + MAX_NUM_VEC * ivec2 ]; } } } else { // LINEAR PROBLEM // mxM contains V^T . A^T . A . V for ( int ivec = 0; ivec < NUM_VEC_KEEP; ivec++ ){ for ( int ivec2 = ivec; ivec2 < NUM_VEC_KEEP; ivec2++ ){ mxM[ ivec + MAX_NUM_VEC * ivec2 ] = ddot_( &veclength, Hvecs[ ivec ], &inc1, Hvecs[ ivec2 ], &inc1 ); mxM[ ivec2 + MAX_NUM_VEC * ivec ] = mxM[ ivec + MAX_NUM_VEC * ivec2 ]; } } // mxM_rhs contains V^T . A^T . RHS for ( int ivec = 0; ivec < NUM_VEC_KEEP; ivec++ ){ mxM_rhs[ ivec ] = ddot_( &veclength, Hvecs[ ivec ], &inc1, RHS, &inc1 ); } } } CheMPS2-1.8.9/CheMPS2/Doxyfile.in000066400000000000000000003135771336564451100161760ustar00rootroot00000000000000# Doxyfile 1.8.9.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "CheMPS2" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. PROJECT_LOGO = @CheMPS2_SOURCE_DIR@/CheMPS2/CheMPS2logo.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = @CheMPS2_BINARY_DIR@/ # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = NO # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = @CheMPS2_SOURCE_DIR@/CheMPS2 # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. HIDE_COMPOUND_REFERENCE= NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong or incomplete # parameter documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. # Note: If this tag is empty the current directory is searched. INPUT = @CheMPS2_SOURCE_DIR@/CheMPS2/include/chemps2 \ @CheMPS2_SOURCE_DIR@/CheMPS2/ \ @CheMPS2_SOURCE_DIR@ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank the # following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, # *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, # *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. FILE_PATTERNS = # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = @CheMPS2_SOURCE_DIR@ # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = README.md #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the # clang parser (see: http://clang.llvm.org/) for more accurate parsing at the # cost of reduced performance. This can be particularly helpful with template # rich C++ code for which doxygen's built-in parser lacks the necessary type # information. # Note: The availability of this option depends on whether or not doxygen was # compiled with the --with-libclang option. # The default value is: NO. CLANG_ASSISTED_PARSING = NO # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories # specified with INPUT and INCLUDE_PATH. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_OPTIONS = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = YES # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://www.mathjax.org/mathjax # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /