diff --git a/.github/workflows/fortran-build.yml b/.github/workflows/fortran-build.yml index d615ca138..d8c9c6045 100644 --- a/.github/workflows/fortran-build.yml +++ b/.github/workflows/fortran-build.yml @@ -1,9 +1,7 @@ name: CI on: [push, pull_request] - env: - BUILD_DIR: _build - + BUILD_DIR: _build jobs: gcc-meson-build: runs-on: ${{ matrix.os }} @@ -11,376 +9,278 @@ jobs: fail-fast: false matrix: os: [macos-latest, ubuntu-latest] - fc: [gfortran-11] - cc: [gcc-11] + version: [12] include: - - os: ubuntu-latest - fc: gfortran-9 - cc: gcc-9 - - os: ubuntu-latest - fc: gfortran-10 - cc: gcc-10 - + - os: ubuntu-latest + version: 10 + - os: ubuntu-latest + version: 11 + - os: macos-latest + version: 13 + - os: macos-latest + version: 14 steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v4 - with: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: python-version: 3.x - - - name: Install OpenBLAS (OSX) - if: ${{ contains(matrix.os, 'macos') }} - run: | + - name: Install OpenBLAS (macOS) + if: ${{ contains(matrix.os, 'macos') }} + run: | brew install openblas echo "PKG_CONFIG_PATH=/usr/local/opt/openblas/lib/pkgconfig" >> $GITHUB_ENV - - - name: Install meson - run: pip3 install meson==0.62.0 ninja cmake - - - name: Configure build - run: >- - meson setup ${{ env.BUILD_DIR }} - --buildtype=debug - --warnlevel=0 - -Db_coverage=true - ${{ env.MESON_ARGS }} - env: - FC: ${{ matrix.fc }} - CC: ${{ matrix.cc }} + echo "LDFLAGS=-L/opt/homebrew/opt/openblas/lib" >> $GITHUB_ENV + echo "CPPFLAGS=-I/opt/homebrew/opt/openblas/include" >> $GITHUB_ENV + - name: Install meson + run: pip install meson ninja cmake + - name: Configure build + run: >- + meson setup ${{ env.BUILD_DIR }} --buildtype=debug --warnlevel=0 -Db_coverage=true ${{ env.MESON_ARGS }} + env: + FC: gfortran-${{ matrix.version }} + CC: gcc-${{ matrix.version }} MESON_ARGS: ${{ contains(matrix.os, 'macos') && '-Dlapack=openblas' || '-Dlapack=netlib' }} - - - name: Build project - run: meson compile -C ${{ env.BUILD_DIR }} - - - name: Run unit tests - run: meson test -C ${{ env.BUILD_DIR }} --print-errorlogs --no-rebuild -t 120 --suite xtb - env: + - name: Build project + run: meson compile -C ${{ env.BUILD_DIR }} + - name: Run unit tests + run: meson test -C ${{ env.BUILD_DIR }} --print-errorlogs --no-rebuild -t 120 --suite xtb + env: OMP_NUM_THREADS: 2,1 - - - name: Upload coverage report - run: bash <(curl -s https://codecov.io/bash) - + - name: Upload coverage report + run: bash <(curl -s https://codecov.io/bash) gcc-cmake-build: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest] - fc: [gfortran-10] - cc: [gcc-10] - + fc: [gfortran-12] + cc: [gcc-12] steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v4 - with: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: python-version: 3.x - - - name: Install CMake - run: pip3 install ninja cmake - - - name: Configure build - run: cmake -B ${{ env.BUILD_DIR }} -G Ninja - env: + - name: Install CMake + run: pip install ninja cmake + - name: Configure build + run: cmake -B ${{ env.BUILD_DIR }} -G Ninja + env: FC: ${{ matrix.fc }} CC: ${{ matrix.cc }} - - - name: Build project - run: cmake --build ${{ env.BUILD_DIR }} - - - name: Run unit tests - run: ctest --parallel --output-on-failure -R 'xtb/*' - working-directory: ${{ env.BUILD_DIR }} - env: + - name: Build project + run: cmake --build ${{ env.BUILD_DIR }} + - name: Run unit tests + run: ctest --parallel --output-on-failure -R 'xtb/*' + working-directory: ${{ env.BUILD_DIR }} + env: OMP_NUM_THREADS: 2,1 - xtb-lightweight-meson-build: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest] - fc: [gfortran-11] - cc: [gcc-11] - + fc: [gfortran-12] + cc: [gcc-12] steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v4 - with: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: python-version: 3.x - - - name: Install meson - run: pip3 install meson==0.62.0 ninja cmake - - - name: Configure build - run: >- - meson setup ${{ env.BUILD_DIR }} - --buildtype=debug - --warnlevel=0 - ${{ env.MESON_ARGS }} - env: + - name: Install meson + run: pip3 install meson==0.62.0 ninja cmake + - name: Configure build + run: >- + meson setup ${{ env.BUILD_DIR }} --buildtype=debug --warnlevel=0 ${{ env.MESON_ARGS }} + env: FC: ${{ matrix.fc }} CC: ${{ matrix.cc }} MESON_ARGS: ${{ '-Dlapack=netlib -Dtblite=disabled -Dcpcmx=disabled' }} - - - name: Build project - run: meson compile -C ${{ env.BUILD_DIR }} - - - name: Run unit tests - run: meson test -C ${{ env.BUILD_DIR }} --print-errorlogs --no-rebuild -t 120 --suite xtb - env: + - name: Build project + run: meson compile -C ${{ env.BUILD_DIR }} + - name: Run unit tests + run: meson test -C ${{ env.BUILD_DIR }} --print-errorlogs --no-rebuild -t 120 --suite xtb + env: OMP_NUM_THREADS: 2,1 - xtb-lightweight-cmake-build: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest] - fc: [gfortran-10] - cc: [gcc-10] - + fc: [gfortran-12] + cc: [gcc-12] steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v4 - with: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: python-version: 3.x - - - name: Install CMake - run: pip3 install ninja cmake - - - name: Configure build - run: cmake -B ${{ env.BUILD_DIR }} -DWITH_CPCMX=false -DWITH_TBLITE=false -G Ninja - env: + - name: Install CMake + run: pip3 install ninja cmake + - name: Configure build + run: cmake -B ${{ env.BUILD_DIR }} -DWITH_CPCMX=false -DWITH_TBLITE=false -G Ninja + env: FC: ${{ matrix.fc }} CC: ${{ matrix.cc }} - - - name: Build project - run: cmake --build ${{ env.BUILD_DIR }} - - - name: Run unit tests - run: ctest --parallel --output-on-failure -R 'xtb/*' - working-directory: ${{ env.BUILD_DIR }} - env: + - name: Build project + run: cmake --build ${{ env.BUILD_DIR }} + - name: Run unit tests + run: ctest --parallel --output-on-failure -R 'xtb/*' + working-directory: ${{ env.BUILD_DIR }} + env: OMP_NUM_THREADS: 2,1 - # Test native MinGW Windows build mingw-meson-build: runs-on: windows-latest strategy: fail-fast: false matrix: - include: [ - { msystem: MINGW64, arch: x86_64 }, - # { msystem: MINGW32, arch: i686 } + include: [{msystem: MINGW64, arch: x86_64,} + # { msystem: MINGW32, arch: i686 } ] defaults: run: shell: msys2 {0} steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup MSYS2 toolchain - uses: msys2/setup-msys2@v2 - with: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup MSYS2 toolchain + uses: msys2/setup-msys2@v2 + with: msystem: ${{ matrix.msystem }} update: false install: >- - git - mingw-w64-${{ matrix.arch }}-gcc-fortran - mingw-w64-${{ matrix.arch }}-openblas - mingw-w64-${{ matrix.arch }}-lapack - mingw-w64-${{ matrix.arch }}-python - mingw-w64-${{ matrix.arch }}-python-pip - mingw-w64-${{ matrix.arch }}-meson - mingw-w64-${{ matrix.arch }}-ninja - - - name: Configure build - run: meson setup ${{ env.BUILD_DIR }} -Dlapack=netlib --warnlevel=0 - env: + git mingw-w64-${{ matrix.arch }}-gcc-fortran mingw-w64-${{ matrix.arch }}-openblas mingw-w64-${{ matrix.arch }}-lapack mingw-w64-${{ matrix.arch }}-python mingw-w64-${{ matrix.arch }}-python-pip mingw-w64-${{ matrix.arch }}-meson mingw-w64-${{ matrix.arch }}-ninja + - name: Configure build + run: meson setup ${{ env.BUILD_DIR }} -Dlapack=netlib --warnlevel=0 + env: FC: gfortran CC: gcc - - - name: Build project - run: meson compile -C ${{ env.BUILD_DIR }} - - - name: Run unit tests - run: meson test -C ${{ env.BUILD_DIR }} --print-errorlogs --no-rebuild -t 120 --suite xtb - env: + - name: Build project + run: meson compile -C ${{ env.BUILD_DIR }} + - name: Run unit tests + run: meson test -C ${{ env.BUILD_DIR }} --print-errorlogs --no-rebuild -t 120 --suite xtb + env: OMP_NUM_THREADS: 1 - intel-meson-build: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - os: [ubuntu-20.04] + os: [ubuntu-latest] fc: [ifort] cc: [icc] env: FC: ${{ matrix.fc }} CC: ${{ matrix.cc }} APT_PACKAGES: >- - intel-oneapi-compiler-fortran-2022.1.0 - intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic-2022.1.0 - intel-oneapi-mkl-2022.1.0 - intel-oneapi-mkl-devel-2022.1.0 - asciidoctor - + intel-oneapi-compiler-fortran-2022.1.0 intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic-2022.1.0 intel-oneapi-mkl-2022.1.0 intel-oneapi-mkl-devel-2022.1.0 asciidoctor steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup Python - uses: actions/setup-python@v1 - with: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: python-version: 3.x - - - run: pip3 install meson ninja --user - - - name: Add Intel repository - if: contains(matrix.os, 'ubuntu') - run: | + - run: pip3 install meson ninja --user + - name: Add Intel repository + if: contains(matrix.os, 'ubuntu') + run: | wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB rm GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list sudo apt-get update - - - name: Install Intel oneAPI compiler - if: contains(matrix.os, 'ubuntu') - run: | + - name: Install Intel oneAPI compiler + if: contains(matrix.os, 'ubuntu') + run: | sudo apt-get install ${APT_PACKAGES} source /opt/intel/oneapi/setvars.sh printenv >> $GITHUB_ENV - - - name: Configure meson build - run: >- - meson setup ${{ env.BUILD_DIR }} - --prefix=/ --libdir=lib - -Dfortran_link_args="-lifcoremt -static" - -Ddefault_library=static - -Dlapack=mkl - - - name: Build project - run: ninja -C ${{ env.BUILD_DIR }} - - - name: Run unit tests - run: >- - meson test -C ${{ env.BUILD_DIR }} - --print-errorlogs - --num-processes 1 - --no-rebuild - --suite xtb - -t 120 - env: + - name: Configure meson build + run: >- + meson setup ${{ env.BUILD_DIR }} --prefix=/ --libdir=lib -Dfortran_link_args="-lifcoremt -static" -Ddefault_library=static -Dlapack=mkl + - name: Build project + run: ninja -C ${{ env.BUILD_DIR }} + - name: Run unit tests + run: >- + meson test -C ${{ env.BUILD_DIR }} --print-errorlogs --num-processes 1 --no-rebuild --suite xtb -t 120 + env: OMP_NUM_THREADS: 2,1 - - - name: Install package - run: | + - name: Install package + run: | meson install -C ${{ env.BUILD_DIR }} --no-rebuild tar cJvf xtb-bleed.tar.xz xtb-bleed - env: + env: DESTDIR: ${{ env.PWD }}/xtb-bleed - - - name: Upload binary - if: github.event_name == 'push' - uses: actions/upload-artifact@v2 - with: + - name: Upload binary + if: github.event_name == 'push' + uses: actions/upload-artifact@v2 + with: name: xtb-bleed.tar.xz path: xtb-bleed.tar.xz - # Inspired from https://github.com/endless-sky/endless-sky continuous-delivery: if: github.event_name == 'push' runs-on: ubuntu-latest needs: - intel-meson-build - env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} RELEASE_TAG: bleed OUTPUT_INTEL: xtb-bleed.tar.xz - steps: - - uses: actions/checkout@v3 - - - name: Install github-release - run: | + - uses: actions/checkout@v4 + - name: Install github-release + run: | go install github.com/github-release/github-release@latest echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV echo "$(go env GOPATH)/bin" >> $GITHUB_PATH - - - name: Set environment variables - run: | + - name: Set environment variables + run: | echo "GITHUB_USER=$( echo ${{ github.repository }} | cut -d/ -f1 )" >> $GITHUB_ENV echo "GITHUB_REPO=$( echo ${{ github.repository }} | cut -d/ -f2 )" >> $GITHUB_ENV - - - name: Move/Create continuous tag - run: | + - name: Move/Create continuous tag + run: | git tag --force ${{ env.RELEASE_TAG }} ${{ github.sha }} git push --tags --force - - - name: Get Time - run: echo "TIME=$(date -u '+%Y/%m/%d, %H:%M')" >> $GITHUB_ENV - - - name: Check continuous release status - run: | + - name: Get Time + run: echo "TIME=$(date -u '+%Y/%m/%d, %H:%M')" >> $GITHUB_ENV + - name: Check continuous release status + run: | if ! github-release info -t ${{ env.RELEASE_TAG }} > /dev/null 2>&1; then echo "RELEASE_COMMAND=release" >> $GITHUB_ENV else echo "RELEASE_COMMAND=edit" >> $GITHUB_ENV fi - - - name: Setup continuous release - run: >- - github-release ${{ env.RELEASE_COMMAND }} - --tag ${{ env.RELEASE_TAG }} - --name "Bleeding edge version" - --description "$DESCRIPTION" - --pre-release - env: + - name: Setup continuous release + run: >- + github-release ${{ env.RELEASE_COMMAND }} --tag ${{ env.RELEASE_TAG }} --name "Bleeding edge version" --description "$DESCRIPTION" --pre-release + env: DESCRIPTION: | Created on ${{ env.TIME }} UTC by @${{ github.actor }} with commit ${{ github.sha }}. This is an automated distribution of the latest `xtb` version. This version is only minimally tested and may be unstable or even crash. Use with caution! https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - - - name: Download Artifacts - uses: actions/download-artifact@v2 - with: + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: path: ${{ github.workspace }} # This will download all files - - - name: Create SHA256 checksum - run: | + - name: Create SHA256 checksum + run: | cd ${{ env.OUTPUT_INTEL }} sha256sum ${{ env.OUTPUT_INTEL }} > sha256.txt - - - name: Add ${{ env.OUTPUT_INTEL }} to release tag - run: >- - github-release upload - --tag ${{ env.RELEASE_TAG }} - --replace - --name ${{ env.OUTPUT_INTEL }} - --file ${{ env.OUTPUT_INTEL }}/${{ env.OUTPUT_INTEL }} - - - name: Add SHA256 checksums to release tag - run: >- - github-release upload - --tag ${{ env.RELEASE_TAG }} - --replace - --name sha256.txt - --file ${{ env.OUTPUT_INTEL }}/sha256.txt - - - + - name: Add ${{ env.OUTPUT_INTEL }} to release tag + run: >- + github-release upload --tag ${{ env.RELEASE_TAG }} --replace --name ${{ env.OUTPUT_INTEL }} --file ${{ env.OUTPUT_INTEL }}/${{ env.OUTPUT_INTEL }} + - name: Add SHA256 checksums to release tag + run: >- + github-release upload --tag ${{ env.RELEASE_TAG }} --replace --name sha256.txt --file ${{ env.OUTPUT_INTEL }}/sha256.txt diff --git a/.github/workflows/stale_label.yml b/.github/workflows/stale_label.yml index 6b3aec717..43805870b 100644 --- a/.github/workflows/stale_label.yml +++ b/.github/workflows/stale_label.yml @@ -2,6 +2,8 @@ name: "Close Stale" # The workflow triggers on: + schedule: + - cron: '0 0 * * *' issues: types: [labeled] pull_request: diff --git a/CMakeLists.txt b/CMakeLists.txt index 51f77c0a1..a46052a00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ endif() # Setup the xtb Project project( "xtb" - VERSION "6.7.0" + VERSION "6.7.1" LANGUAGES "C" "Fortran" ) diff --git a/README.md b/README.md index 032f3256a..d8f7260c1 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ features reality: - S. Dohm ([@thch-dohm](https://github.com/thch-dohm)) - S. Ehlert ([@awvwgk](https://github.com/awvwgk)) - S. Ehrlich -- I. Gerasimov ([@FulgurIgor](https://github.com/fulgurigor)) +- I. Gerasimov ([@foxtran](https://github.com/foxtran)) - [S. Grimme](https://www.chemie.uni-bonn.de/pctc/mulliken-center/grimme/) ([@stefangrimme](https://github.com/stefangrimme)) - C. Hölzer ([@hoelzerC](https://github.com/hoelzerc)) - A. Katbashev ([@Albkat](https://github.com/albkat)) diff --git a/include/xtb.h b/include/xtb.h index 383c264e1..e66149080 100644 --- a/include/xtb.h +++ b/include/xtb.h @@ -19,10 +19,10 @@ #define XTB_API_ENTRY #define XTB_API_CALL -#define XTB_API_SUFFIX__VERSION_1_0_0 +#define XTB_API_SUFFIX__VERSION_2_0_0 /// Define proprocessor to allow to check for specific API features -#define XTB_API_VERSION 10000 +#define XTB_API_VERSION 20000 #define XTB_VERSION_6_3_0 1 #define XTB_VERSION_6_3_1 1 #define XTB_VERSION_6_3_2 1 @@ -69,7 +69,7 @@ typedef struct _xtb_TResults* xtb_TResults; /// Returns API version as 10000 * major + 100 * minor + 1 * patch extern XTB_API_ENTRY int XTB_API_CALL -xtb_getAPIVersion() XTB_API_SUFFIX__VERSION_1_0_0; +xtb_getAPIVersion() XTB_API_SUFFIX__VERSION_2_0_0; /* * Calculation environment @@ -77,40 +77,40 @@ xtb_getAPIVersion() XTB_API_SUFFIX__VERSION_1_0_0; /// Create new xtb calculation environment object extern XTB_API_ENTRY xtb_TEnvironment XTB_API_CALL -xtb_newEnvironment(void) XTB_API_SUFFIX__VERSION_1_0_0; +xtb_newEnvironment(void) XTB_API_SUFFIX__VERSION_2_0_0; /// Delete a xtb calculation environment object extern XTB_API_ENTRY void XTB_API_CALL -xtb_delEnvironment(xtb_TEnvironment* /* env */) XTB_API_SUFFIX__VERSION_1_0_0; +xtb_delEnvironment(xtb_TEnvironment* /* env */) XTB_API_SUFFIX__VERSION_2_0_0; /// Check current status of calculation environment extern XTB_API_ENTRY int XTB_API_CALL -xtb_checkEnvironment(xtb_TEnvironment /* env */) XTB_API_SUFFIX__VERSION_1_0_0; +xtb_checkEnvironment(xtb_TEnvironment /* env */) XTB_API_SUFFIX__VERSION_2_0_0; /// Show and empty error stack extern XTB_API_ENTRY void XTB_API_CALL xtb_showEnvironment(xtb_TEnvironment /* env */, - const char* /* message */) XTB_API_SUFFIX__VERSION_1_0_0; + const char* /* message */) XTB_API_SUFFIX__VERSION_2_0_0; /// Return and empty error stack extern XTB_API_ENTRY void XTB_API_CALL xtb_getError(xtb_TEnvironment /* env */, char* /* buffer */, - const int* /* buffersize */) XTB_API_SUFFIX__VERSION_1_0_0; + const int* /* buffersize */) XTB_API_SUFFIX__VERSION_2_0_0; /// Bind output from this environment extern XTB_API_ENTRY void XTB_API_CALL xtb_setOutput(xtb_TEnvironment /* env */, - const char* /* filename */) XTB_API_SUFFIX__VERSION_1_0_0; + const char* /* filename */) XTB_API_SUFFIX__VERSION_2_0_0; /// Release output unit from this environment extern XTB_API_ENTRY void XTB_API_CALL -xtb_releaseOutput(xtb_TEnvironment /* env */) XTB_API_SUFFIX__VERSION_1_0_0; +xtb_releaseOutput(xtb_TEnvironment /* env */) XTB_API_SUFFIX__VERSION_2_0_0; /// Set verbosity of calculation output extern XTB_API_ENTRY void XTB_API_CALL xtb_setVerbosity(xtb_TEnvironment /* env */, - int /* verbosity */) XTB_API_SUFFIX__VERSION_1_0_0; + int /* verbosity */) XTB_API_SUFFIX__VERSION_2_0_0; /* * Molecular structure data class @@ -125,18 +125,18 @@ xtb_newMolecule(xtb_TEnvironment /* env */, const double* /* charge in e */, const int* /* uhf */, const double* /* lattice [3][3] */, - const bool* /* periodic [3] */) XTB_API_SUFFIX__VERSION_1_0_0; + const bool* /* periodic [3] */) XTB_API_SUFFIX__VERSION_2_0_0; /// Delete molecular structure data extern XTB_API_ENTRY void XTB_API_CALL -xtb_delMolecule(xtb_TMolecule* /* mol */) XTB_API_SUFFIX__VERSION_1_0_0; +xtb_delMolecule(xtb_TMolecule* /* mol */) XTB_API_SUFFIX__VERSION_2_0_0; /// Update coordinates and lattice parameters (quantities in Bohr) extern XTB_API_ENTRY void XTB_API_CALL xtb_updateMolecule(xtb_TEnvironment /* env */, xtb_TMolecule /* mol */, const double* /* positions [natoms][3] */, - const double* /* lattice [3][3] */) XTB_API_SUFFIX__VERSION_1_0_0; + const double* /* lattice [3][3] */) XTB_API_SUFFIX__VERSION_2_0_0; /* * Singlepoint calculator @@ -144,39 +144,39 @@ xtb_updateMolecule(xtb_TEnvironment /* env */, /// Create new calculator object extern XTB_API_ENTRY xtb_TCalculator XTB_API_CALL -xtb_newCalculator(void) XTB_API_SUFFIX__VERSION_1_0_0; +xtb_newCalculator(void) XTB_API_SUFFIX__VERSION_2_0_0; /// Delete calculator object extern XTB_API_ENTRY void XTB_API_CALL -xtb_delCalculator(xtb_TCalculator* /* calc */) XTB_API_SUFFIX__VERSION_1_0_0; +xtb_delCalculator(xtb_TCalculator* /* calc */) XTB_API_SUFFIX__VERSION_2_0_0; /// Load GFN0-xTB calculator extern XTB_API_ENTRY void XTB_API_CALL xtb_loadGFN0xTB(xtb_TEnvironment /* env */, xtb_TMolecule /* mol */, xtb_TCalculator /* calc */, - char* /* filename */) XTB_API_SUFFIX__VERSION_1_0_0; + char* /* filename */) XTB_API_SUFFIX__VERSION_2_0_0; /// Load GFN1-xTB calculator extern XTB_API_ENTRY void XTB_API_CALL xtb_loadGFN1xTB(xtb_TEnvironment /* env */, xtb_TMolecule /* mol */, xtb_TCalculator /* calc */, - char* /* filename */) XTB_API_SUFFIX__VERSION_1_0_0; + char* /* filename */) XTB_API_SUFFIX__VERSION_2_0_0; /// Load GFN2-xTB calculator extern XTB_API_ENTRY void XTB_API_CALL xtb_loadGFN2xTB(xtb_TEnvironment /* env */, xtb_TMolecule /* mol */, xtb_TCalculator /* calc */, - char* /* filename */) XTB_API_SUFFIX__VERSION_1_0_0; + char* /* filename */) XTB_API_SUFFIX__VERSION_2_0_0; /// Load GFN-FF calculator extern XTB_API_ENTRY void XTB_API_CALL xtb_loadGFNFF(xtb_TEnvironment /* env */, xtb_TMolecule /* mol */, xtb_TCalculator /* calc */, - char* /* filename */) XTB_API_SUFFIX__VERSION_1_0_0; + char* /* filename */) XTB_API_SUFFIX__VERSION_2_0_0; /// Add a solvation model to calculator (requires loaded parametrisation) extern XTB_API_ENTRY void XTB_API_CALL @@ -185,12 +185,13 @@ xtb_setSolvent(xtb_TEnvironment /* env */, char* /* solvent */, int* /* state */, double* /* temp */, - int* /* grid */) XTB_API_SUFFIX__VERSION_1_0_0; + int* /* grid */, + char* /* solvent model */) XTB_API_SUFFIX__VERSION_2_0_0; /// Unset the solvation model extern XTB_API_ENTRY void XTB_API_CALL xtb_releaseSolvent(xtb_TEnvironment /* env */, - xtb_TCalculator /* calc */) XTB_API_SUFFIX__VERSION_1_0_0; + xtb_TCalculator /* calc */) XTB_API_SUFFIX__VERSION_2_0_0; /// Add a external charge potential to calculator (only supported in GFN1/2-xTB) extern XTB_API_ENTRY void XTB_API_CALL @@ -199,37 +200,56 @@ xtb_setExternalCharges(xtb_TEnvironment /* env */, int* /* n */, int* /* numbers [n] */, double* /* charges [n] */, - double* /* positions [n][3] */) XTB_API_SUFFIX__VERSION_1_0_0; + double* /* positions [n][3] */) XTB_API_SUFFIX__VERSION_2_0_0; /// Unset the external charge potential extern XTB_API_ENTRY void XTB_API_CALL xtb_releaseExternalCharges(xtb_TEnvironment /* env */, - xtb_TCalculator /* calc */) XTB_API_SUFFIX__VERSION_1_0_0; + xtb_TCalculator /* calc */) XTB_API_SUFFIX__VERSION_2_0_0; /// Set numerical accuracy of calculator in the range of 1000 to 0.0001 extern XTB_API_ENTRY void XTB_API_CALL xtb_setAccuracy(xtb_TEnvironment /* env */, xtb_TCalculator /* calc */, - double /* accuracy */) XTB_API_SUFFIX__VERSION_1_0_0; + double /* accuracy */) XTB_API_SUFFIX__VERSION_2_0_0; /// Set maximum number of iterations for self-consistent TB calculators extern XTB_API_ENTRY void XTB_API_CALL xtb_setMaxIter(xtb_TEnvironment /* env */, xtb_TCalculator /* calc */, - int /* iterations */) XTB_API_SUFFIX__VERSION_1_0_0; + int /* iterations */) XTB_API_SUFFIX__VERSION_2_0_0; /// Set electronic temperature for level filling in tight binding calculators in K extern XTB_API_ENTRY void XTB_API_CALL xtb_setElectronicTemp(xtb_TEnvironment /* env */, xtb_TCalculator /* calc */, - double /* temperature */) XTB_API_SUFFIX__VERSION_1_0_0; + double /* temperature */) XTB_API_SUFFIX__VERSION_2_0_0; + +//// Calculate CPCM-X solvation energy +extern XTB_API_ENTRY void XTB_API_CALL +xtb_cpcmx_calc(xtb_TEnvironment /* env */, + xtb_TMolecule /* mol */, + xtb_TCalculator /* calc */, + xtb_TResults /* res */) XTB_API_SUFFIX__VERSION_2_0_0; /// Perform singlepoint calculation extern XTB_API_ENTRY void XTB_API_CALL xtb_singlepoint(xtb_TEnvironment /* env */, xtb_TMolecule /* mol */, xtb_TCalculator /* calc */, - xtb_TResults /* res */) XTB_API_SUFFIX__VERSION_1_0_0; + xtb_TResults /* res */) XTB_API_SUFFIX__VERSION_2_0_0; + +/// Perform hessian calculation +extern XTB_API_ENTRY void XTB_API_CALL +xtb_hessian(xtb_TEnvironment /* env */, + xtb_TMolecule /* mol */, + xtb_TCalculator /* calc */, + xtb_TResults /* res */, + double* /* hessian */, + int* /* atom_index_list */, + int* /* step_size */, + double* /* dipole_gradient */, + double* /* polarizability_gradient */) XTB_API_SUFFIX__VERSION_2_0_0; /* * Calculation results @@ -237,81 +257,87 @@ xtb_singlepoint(xtb_TEnvironment /* env */, /// Create new singlepoint results object extern XTB_API_ENTRY xtb_TResults XTB_API_CALL -xtb_newResults(void) XTB_API_SUFFIX__VERSION_1_0_0; +xtb_newResults(void) XTB_API_SUFFIX__VERSION_2_0_0; /// Delete singlepoint results object extern XTB_API_ENTRY void XTB_API_CALL -xtb_delResults(xtb_TResults* /* res */) XTB_API_SUFFIX__VERSION_1_0_0; +xtb_delResults(xtb_TResults* /* res */) XTB_API_SUFFIX__VERSION_2_0_0; /// Create copy from a singlepoint results object extern XTB_API_ENTRY xtb_TResults XTB_API_CALL -xtb_copyResults(xtb_TResults /* res */) XTB_API_SUFFIX__VERSION_1_0_0; +xtb_copyResults(xtb_TResults /* res */) XTB_API_SUFFIX__VERSION_2_0_0; /// Query singlepoint results object for energy in Hartree extern XTB_API_ENTRY void XTB_API_CALL xtb_getEnergy(xtb_TEnvironment /* env */, xtb_TResults /* res */, - double* /* energy */) XTB_API_SUFFIX__VERSION_1_0_0; + double* /* energy */) XTB_API_SUFFIX__VERSION_2_0_0; + +/// Query singlepoint results object for solvation energy in Hartree +extern XTB_API_ENTRY void XTB_API_CALL +xtb_getSolvationEnergy(xtb_TEnvironment /* env */, + xtb_TResults /* res */, + double* /* energy */) XTB_API_SUFFIX__VERSION_2_0_0; /// Query singlepoint results object for gradient in Hartree / Bohr extern XTB_API_ENTRY void XTB_API_CALL xtb_getGradient(xtb_TEnvironment /* env */, xtb_TResults /* res */, - double* /* gradient [natoms][3] */) XTB_API_SUFFIX__VERSION_1_0_0; + double* /* gradient [natoms][3] */) XTB_API_SUFFIX__VERSION_2_0_0; /// Query singlepoint results object for pc gradient in Hartree / Bohr extern XTB_API_ENTRY void XTB_API_CALL xtb_getPCGradient(xtb_TEnvironment /* env */, xtb_TResults /* res */, - double* /* gradient [natoms][3] */) XTB_API_SUFFIX__VERSION_1_0_0; + double* /* gradient [natoms][3] */) XTB_API_SUFFIX__VERSION_2_0_0; /// Query singlepoint results object for virial in Hartree extern XTB_API_ENTRY void XTB_API_CALL xtb_getVirial(xtb_TEnvironment /* env */, xtb_TResults /* res */, - double* /* virial [3][3] */) XTB_API_SUFFIX__VERSION_1_0_0; + double* /* virial [3][3] */) XTB_API_SUFFIX__VERSION_2_0_0; /// Query singlepoint results object for dipole in e Bohr extern XTB_API_ENTRY void XTB_API_CALL xtb_getDipole(xtb_TEnvironment /* env */, xtb_TResults /* res */, - double* /* dipole [3] */) XTB_API_SUFFIX__VERSION_1_0_0; + double* /* dipole [3] */) XTB_API_SUFFIX__VERSION_2_0_0; /// Query singlepoint results object for partial charges in e extern XTB_API_ENTRY void XTB_API_CALL xtb_getCharges(xtb_TEnvironment /* env */, xtb_TResults /* res */, - double* /* charges [natoms] */) XTB_API_SUFFIX__VERSION_1_0_0; + double* /* charges [natoms] */) XTB_API_SUFFIX__VERSION_2_0_0; /// Query singlepoint results object for bond orders extern XTB_API_ENTRY void XTB_API_CALL xtb_getBondOrders(xtb_TEnvironment /* env */, xtb_TResults /* res */, - double* /* wbo [natoms][natoms] */) XTB_API_SUFFIX__VERSION_1_0_0; + double* /* wbo [natoms][natoms] */) XTB_API_SUFFIX__VERSION_2_0_0; /// Query singlepoint results object for the number of basis functions extern XTB_API_ENTRY void XTB_API_CALL xtb_getNao(xtb_TEnvironment /* env */, xtb_TResults /* res */, - int* /* nao */) XTB_API_SUFFIX__VERSION_1_0_0; + int* /* nao */) XTB_API_SUFFIX__VERSION_2_0_0; /// Query singlepoint results object for orbital energies in Hartree [nao] extern XTB_API_ENTRY void XTB_API_CALL xtb_getOrbitalEigenvalues(xtb_TEnvironment /* env */, xtb_TResults /* res */, - double* /* emo */) XTB_API_SUFFIX__VERSION_1_0_0; + double* /* emo */) XTB_API_SUFFIX__VERSION_2_0_0; /// Query singlepoint results object for occupation numbers [nao] extern XTB_API_ENTRY void XTB_API_CALL xtb_getOrbitalOccupations(xtb_TEnvironment /* env */, xtb_TResults /* res */, - double* /* focc */) XTB_API_SUFFIX__VERSION_1_0_0; + double* /* focc */) XTB_API_SUFFIX__VERSION_2_0_0; /// Query singlepoint results object for orbital coefficients [nao][nao] extern XTB_API_ENTRY void XTB_API_CALL xtb_getOrbitalCoefficients(xtb_TEnvironment /* env */, xtb_TResults /* res */, - double* /* c */) XTB_API_SUFFIX__VERSION_1_0_0; + double* /* c */) XTB_API_SUFFIX__VERSION_2_0_0; #ifdef __cplusplus } diff --git a/man/xtb.1.adoc b/man/xtb.1.adoc index 7d88206cb..4f417b48a 100644 --- a/man/xtb.1.adoc +++ b/man/xtb.1.adoc @@ -80,6 +80,9 @@ OPTIONS *--tblite* :: use tblite library as implementation for xTB + +--ceh* :: + calculate CEH (Charge-Extended Hückel model) charges and write them to ceh.charges file *--ptb* :: performs single-point calculation with the density tight-binding method PTB. @@ -121,7 +124,7 @@ OPTIONS 'ethylacetate', 'furane', 'hexandecane', 'hexane', 'methanol', 'nitromethane', 'octanol', 'woctanol', 'phenol', 'toluene', 'thf', 'water'. The solvent input is not case-sensitive. - The Gsolv reference state can be chosen as 'reference' or 'bar1M' (default). + The Gsolv reference state can be chosen as 'reference', 'bar1M', or 'gsolv' (default). *-g, --gbsa* 'SOLVENT' ['STATE']:: generalized born (GB) model with solvent accessable surface (SASA) model, @@ -129,7 +132,20 @@ OPTIONS 'CH2Cl2', 'CHCl3', 'CS2', 'DMF' (only GFN2-xTB), 'DMSO', 'ether', 'H2O', 'methanol', 'n-hexane' (only GFN2-xTB), 'THF' and 'toluene'. The solvent input is not case-sensitive. - The Gsolv reference state can be chosen as 'reference' or 'bar1M' (default). + The Gsolv reference state can be chosen as 'reference', 'bar1M', or 'gsolv' (default). + +*--cosmo* 'SOLVENT/EPSILON':: + domain decomposition conductor-like screening model (ddCOSMO) + available solvents are all solvents that are available for alpb. + Additionally, the dielectric constant can be set manually or an ideal conductor + can be chosen by setting epsilon to infinity. + +*--tmcosmo* 'SOLVENT/EPSILON':: + same as --cosmo, but uses TM convention for writing the .cosmo files. + +*--cpcmx* 'SOLVENT':: + extended conduction-like polarizable continuum solvation model (CPCM-X), + available solvents are all solvents included in the Minnesota Solvation Database. *--cma* :: shifts molecule to center of mass and transforms cartesian coordinates @@ -346,6 +362,9 @@ OUTPUT *charges*:: contains Mulliken partial charges calculated in SCC +*ceh.charges*:: + contains CEH (Charge-Extended Hückel) charges + *wbo*:: contains Wiberg bond order calculated in SCC, *--namespace* compatible. diff --git a/meson.build b/meson.build index 8c8e56cb5..35396f728 100644 --- a/meson.build +++ b/meson.build @@ -19,7 +19,7 @@ project( 'xtb', 'fortran', 'c', - version: '6.7.0', + version: '6.7.1', license: 'LGPL3-3.0-or-later', meson_version: '>=0.62.0', default_options: [ diff --git a/meson/meson.build b/meson/meson.build index df35dcdda..81b10e977 100644 --- a/meson/meson.build +++ b/meson/meson.build @@ -18,28 +18,33 @@ fc = meson.get_compiler('fortran') cc = meson.get_compiler('c') fc_id = fc.get_id() +cc_id = cc.get_id() -if fc.get_id() != cc.get_id() +if fc_id != cc_id warning('FC and CC are not from the same vendor') endif fopts = [] -if fc.get_id() == 'gcc' +if fc_id == 'gcc' fopts = [ '-fdefault-real-8', '-fdefault-double-8', '-ffree-line-length-none', '-fbacktrace', ] -elif fc.get_id() == 'intel' +elif fc_id == 'intel' or fc_id == 'intel-llvm' + # ifort and ifx largely share the same options if get_option('buildtype') == 'release' opt_level = [ '-Ofast', - '-ip', '-axAVX2', '-mtune=core-avx2', '-fma', ] + # Not available with ifx + if fc_id == 'intel' + opt_level += ['-ip'] + endif else opt_level = [ '-axAVX2', @@ -49,7 +54,7 @@ elif fc.get_id() == 'intel' '-r8', '-traceback', ] -elif fc.get_id() == 'intel-cl' +elif fc_id == 'intel-cl' if get_option('buildtype') == 'release' opt_level = [ '/O3', @@ -68,7 +73,7 @@ elif fc.get_id() == 'intel-cl' '/4R8', '/traceback', ] -elif fc.get_id() == 'pgi' or fc.get_id() == 'nvidia_hpc' +elif fc_id == 'pgi' or fc_id == 'nvidia_hpc' fopts = [ '-Mpreprocess', '-Mbackslash', @@ -102,14 +107,14 @@ add_project_arguments('-D_Float128=__float128', language: 'c') lapack_vendor = get_option('lapack') if lapack_vendor == 'auto' - if fc_id == 'intel' + if fc_id == 'intel' or fc_id == 'intel-llvm' lapack_vendor = 'mkl' endif endif if lapack_vendor == 'mkl' mkl_dep = [] - if fc_id == 'intel' + if fc_id == 'intel' or fc_id == 'intel-llvm' mkl_dep += cc.find_library('mkl_intel_lp64') if get_option('openmp') mkl_dep += cc.find_library('mkl_intel_thread') @@ -165,9 +170,9 @@ else endif if get_option('openmp') - omp_dep = dependency('openmp', required: fc.get_id() != 'intel' and fc.get_id() != 'nvidia_hpc') + omp_dep = dependency('openmp', required: fc_id != 'intel' and fc_id != 'intel-llvm' and fc_id != 'nvidia_hpc') if not omp_dep.found() - if fc.get_id() == 'intel' + if fc_id == 'intel' or fc_id == 'intel-llvm' message('Using -qopenmp to use OpenMP with Intel compilers') omp_dep = declare_dependency( compile_args: '-qopenmp', @@ -211,6 +216,7 @@ lib_deps += tblite_dep multicharge_dep = dependency( 'multicharge', fallback: ['multicharge', 'multicharge_dep'], + required: get_option('tblite') ) lib_deps += multicharge_dep @@ -218,6 +224,7 @@ lib_deps += multicharge_dep dftd4_dep = dependency( 'dftd4', fallback: ['dftd4', 'dftd4_dep'], + required: get_option('tblite') ) lib_deps += dftd4_dep diff --git a/meson_options.txt b/meson_options.txt index c057f5791..fd5377f3c 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -48,6 +48,22 @@ option( description: 'include CPCM-X library for solvation evaluation', ) +option( + 'dftd4', + type: 'feature', + value: 'auto', + yield: true, + description: 'include DFTD4 library for D4 dispersion', +) + +option( + 'multicharge', + type: 'feature', + value: 'auto', + yield: true, + description: 'include multicharge library for atomic partial charges', +) + option( 'openmp', type: 'boolean', diff --git a/src/api/calculator.f90 b/src/api/calculator.f90 index 1fe9c706a..bb80e8345 100644 --- a/src/api/calculator.f90 +++ b/src/api/calculator.f90 @@ -338,7 +338,7 @@ end subroutine loadGFN2xTB_api !> Add a solvation model to calculator (requires loaded parametrisation) -subroutine setSolvent_api(venv, vcalc, charptr, state, temperature, grid) & +subroutine setSolvent_api(venv, vcalc, charptr, state, temperature, grid, charptr2) & & bind(C, name="xtb_setSolvent") !DEC$ ATTRIBUTES DLLEXPORT :: setSolvent_api character(len=*), parameter :: source = 'xtb_api_setSolvent' @@ -346,11 +346,13 @@ subroutine setSolvent_api(venv, vcalc, charptr, state, temperature, grid) & type(VEnvironment), pointer :: env type(c_ptr), value :: vcalc type(VCalculator), pointer :: calc - character(kind=c_char), intent(in) :: charptr(*) + character(kind=c_char), intent(in) :: charptr(*) ! Solvent integer(c_int), intent(in), optional :: state real(c_double), intent(in), optional :: temperature integer(c_int), intent(in), optional :: grid + character(kind=c_char), intent(in), optional :: charptr2(*) ! Solvent model character(len=:), allocatable :: solvent + character(len=:), allocatable :: solv_model type(TSolvInput) :: input integer :: gsolvstate, nang real(wp) :: temp @@ -391,6 +393,12 @@ subroutine setSolvent_api(venv, vcalc, charptr, state, temperature, grid) & call c_f_character(charptr, solvent) + if (present(charptr2)) then + call c_f_character(charptr2, solv_model) + else + solv_model = 'gbsa' + end if + ! PGI 20.5 cannot use default constructor with deferred-length characters: ! input = TSolvInput(solvent=solvent, temperature=temp, state=gsolvstate, & ! & nang=nang) @@ -398,8 +406,32 @@ subroutine setSolvent_api(venv, vcalc, charptr, state, temperature, grid) & input%temperature = temp input%state = gsolvstate input%nang = nang + + ! Set solvent model input%alpb = .false. - input%kernel = gbKernel%still + input%cosmo = .false. + input%tmcosmo = .false. + input%kernel = gbKernel%p16 + if (solv_model == 'gbsa') then + input%kernel = gbKernel%still + elseif (solv_model == 'alpb') then + input%alpb = .true. + elseif (solv_model == 'cosmo') then + input%cosmo = .true. + elseif (solv_model == 'tmcosmo') then + input%tmcosmo = .true. + elseif (solv_model == 'cpcmx') then + ! CPCM-X does an initial SCF with COSMO and a special solvent + ! before running a second SCF with the actual solvent. + input%cosmo = .true. + input%solvent = 'infinity' + + input%cpxsolvent = solvent + else + call env%ptr%error("Unknown solvation model", source) + return + end if + call addSolvationModel(env%ptr, calc%ptr, input) call env%ptr%check(exitRun) diff --git a/src/api/interface.f90 b/src/api/interface.f90 index 70b1c1b7c..92f8cea6f 100644 --- a/src/api/interface.f90 +++ b/src/api/interface.f90 @@ -155,5 +155,302 @@ subroutine singlepoint_api(venv, vmol, vcalc, vres) & end subroutine singlepoint_api +subroutine cpcmx_calc_api(venv, vmol, vcalc, vres) & + & bind(C, name="xtb_cpcmx_calc") + !DEC$ ATTRIBUTES DLLEXPORT :: cpcmx_calc_api + use xtb_solv_cpx, only: TCpcmx + use xtb_type_calculator, only: TCalculator + + character(len=*), parameter :: source = 'xtb_api_cpcmx_calc' + type(c_ptr), value :: venv + type(VEnvironment), pointer :: env + type(c_ptr), value :: vmol + type(VMolecule), pointer :: mol + type(c_ptr), value :: vcalc + type(VCalculator), pointer :: calc + type(c_ptr), value :: vres + type(VResults), pointer :: res + type(scc_results) :: spRes + + type(TCpcmx) :: cpx + type(VCalculator) :: cpx_calc + real(c_double) :: energy_gas + + if (c_associated(venv)) then + call c_f_pointer(venv, env) + call checkGlobalEnv + + if (.not.c_associated(vmol)) then + call env%ptr%error("Molecular structure data is not allocated", source) + return + end if + call c_f_pointer(vmol, mol) + + if (.not.c_associated(vcalc)) then + call env%ptr%error("Singlepoint calculator is not allocated", source) + return + end if + call c_f_pointer(vcalc, calc) + + ! Fail early if CPCM-X solvation model is not set + if (allocated(calc%ptr%solvation)) then + if (.not. allocated(calc%ptr%solvation%cpxsolvent)) then + call env%ptr%error("CPCM-X solvent not set", source) + return + end if + else + call env%ptr%error("No solvation input given", source) + return + end if + + ! Fail early if not using xTB + select type(xtb => calc%ptr) + type is (TGFFCalculator) + call env%ptr%error("CPCM-X is not possible with a force field.", source) + return + end select + + if (.not.allocated(calc%ptr)) then + call env%ptr%error("No calculator loaded for single point", & + & source) + return + end if + + if (.not.c_associated(vres)) then + call env%ptr%error("Calculation results are not allocated", source) + return + end if + call c_f_pointer(vres, res) + + ! check cache, automatically invalidate missmatched data + if (allocated(res%chk)) then + select type(xtb => calc%ptr) + type is(TxTBCalculator) + if (res%chk%wfn%n /= mol%ptr%n .or. res%chk%wfn%n /= xtb%basis%n .or. & + & res%chk%wfn%nao /= xtb%basis%nao .or. & + & res%chk%wfn%nshell /= xtb%basis%nshell) then + deallocate(res%chk) + end if + end select + end if + + if (.not.allocated(res%chk)) then + allocate(res%chk) + ! in case of a new wavefunction cache we have to perform an initial guess + select type(xtb => calc%ptr) + type is(TxTBCalculator) + call newWavefunction(env%ptr, mol%ptr, xtb, res%chk) + end select + end if + + if (.not.allocated(res%energy)) then + allocate(res%energy) + end if + + if (.not.allocated(res%egap)) then + allocate(res%egap) + end if + + if (allocated(res%pcgradient)) then + deallocate(res%pcgradient) + end if + + if (allocated(res%gradient)) then + if (any(shape(res%gradient) /= [3, mol%ptr%n])) then + call env%ptr%warning("Shape missmatch in gradient, reallocating", source) + deallocate(res%gradient) + end if + end if + if (.not.allocated(res%gradient)) then + allocate(res%gradient(3, mol%ptr%n)) + end if + + if (allocated(res%sigma)) then + if (any(shape(res%sigma) /= [3, 3])) then + call env%ptr%warning("Shape missmatch in virial, reallocating", source) + deallocate(res%sigma) + end if + end if + if (.not.allocated(res%sigma)) then + allocate(res%sigma(3, 3)) + end if + + ! Initial COSMO singlepoint calculation + call calc%ptr%singlepoint(env%ptr, mol%ptr, res%chk, env%verbosity, .true., & + & res%energy, res%gradient, res%sigma, res%egap, spRes) + + ! CPCM-X calculation + call cpx%setup(env%ptr, calc%ptr%solvation%cpxsolvent) + cpx_calc = calc + deallocate(cpx_calc%ptr%solvation) + + energy_gas = res%energy + call generic_header(env%ptr%unit, "CPCM-X post-SCF solvation evaluation", 49, 10) + call cpx_calc%ptr%singlepoint(env%ptr, mol%ptr, res%chk, env%verbosity, .false., & + & energy_gas, res%gradient, res%sigma, res%egap, spRes) + + + call cpx%calc_solv(env%ptr, calc%ptr%solvation%cpxsolvent, energy_gas, & + & 0.4_wp, 298.15_wp, 500, 0.0001_wp, spRes%e_total) + call cpx%print(.true.) + + res%energy = spRes%e_total + res%solvation_energy = res%energy - energy_gas + res%dipole = spRes%dipole + + ! Zero out the gradient and sigma (not yet implemented for CPCM-X) + res%gradient = 0.0_wp + res%sigma = 0.0_wp + + endif + +end subroutine cpcmx_calc_api + + +subroutine hessian_api(venv, vmol, vcalc, vres, c_hess, & + & c_step, c_list, c_dipgrad, c_polgrad) & + & bind(C, name="xtb_hessian") + !DEC$ ATTRIBUTES DLLEXPORT :: hessian_api + character(len=*), parameter :: source = 'xtb_api_hessian' + type(c_ptr), value :: venv + type(VEnvironment), pointer :: env + type(c_ptr), value :: vmol + type(VMolecule), pointer :: mol + type(c_ptr), value :: vcalc + type(VCalculator), pointer :: calc + type(c_ptr), value :: vres + type(VResults), pointer :: res + + !> Array to add Hessian to + real(c_double), intent(inout) :: c_hess(*) + real(wp), allocatable :: hess(:, :) + !> List of atoms to displace + integer(c_int), intent(in), optional :: c_list(:) + integer, allocatable :: list(:) + !> Step size for numerical differentiation + real(c_double), intent(in), optional :: c_step + real(wp) :: step + !> Array to add dipole gradient to + real(c_double), intent(inout), optional :: c_dipgrad(*) + real(wp), allocatable :: dipgrad(:, :) + !> Array to add polarizability gradient to + real(c_double), intent(inout), optional :: c_polgrad(*) + real(wp), allocatable :: polgrad(:, :) + + integer :: natom, natsq, i, j + logical :: has_polgrad, has_dipgrad + + if (c_associated(venv)) then + call c_f_pointer(venv, env) + call checkGlobalEnv + + if (.not.c_associated(vmol)) then + call env%ptr%error("Molecular structure data is not allocated", source) + return + end if + call c_f_pointer(vmol, mol) + natom = mol%ptr%n + natsq = natom * natom + + if (.not.c_associated(vcalc)) then + call env%ptr%error("Singlepoint calculator is not allocated", source) + return + end if + call c_f_pointer(vcalc, calc) + + if (.not.allocated(calc%ptr)) then + call env%ptr%error("No calculator loaded for single point", & + & source) + return + end if + + if (.not.c_associated(vres)) then + call env%ptr%error("Calculation results are not allocated", source) + return + end if + call c_f_pointer(vres, res) + + ! check cache, automatically invalidate missmatched data + if (allocated(res%chk)) then + select type(xtb => calc%ptr) + type is(TxTBCalculator) + if (res%chk%wfn%n /= mol%ptr%n .or. res%chk%wfn%n /= xtb%basis%n .or. & + & res%chk%wfn%nao /= xtb%basis%nao .or. & + & res%chk%wfn%nshell /= xtb%basis%nshell) then + deallocate(res%chk) + end if + end select + end if + + if (.not.allocated(res%chk)) then + allocate(res%chk) + ! in case of a new wavefunction cache we have to perform an initial guess + select type(xtb => calc%ptr) + type is(TxTBCalculator) + call newWavefunction(env%ptr, mol%ptr, xtb, res%chk) + end select + end if + + hess = reshape(c_hess(:9*natsq), & + &(/3*natom, 3*natom/)) + ! Need to initialize, as the subroutine increments the values + hess = 0.0_wp + + if (.not.present(c_step)) then + step = 0.005_wp + else + step = c_step + end if + + if (.not.present(c_list)) then + list = [(i, i=1, natom)] + else + list = c_list + end if + + ! Dipole gradient is required by the hessian method, + ! so we have to allocate it + has_dipgrad = present(c_dipgrad) + if (.not. has_dipgrad) then + allocate(dipgrad(3, 3*natom)) + else + dipgrad = reshape(c_dipgrad(:9*natom), & + &(/3, 3*natom/)) + end if + + has_polgrad = present(c_polgrad) + if (has_polgrad) then + polgrad = reshape(c_polgrad(:18*natom), & + &(/6, 3*natom/)) + end if + + ! hessian calculation + if (has_polgrad) then + call calc%ptr%hessian(env%ptr, mol%ptr, res%chk, list, step, & + & hess, dipgrad, polgrad) + else + call calc%ptr%hessian(env%ptr, mol%ptr, res%chk, list, step, & + & hess, dipgrad) + end if + + ! Symmetrize the hessian + do i = 1, 3*natom + do j = i+1, 3*natom + hess(i, j) = 0.5_wp * (hess(i, j) + hess(j, i)) + hess(j, i) = hess(i, j) + end do + end do + + ! copy back the results + c_hess(:9*natsq) = reshape(hess, (/9*natsq/)) + if (has_dipgrad) then + c_dipgrad(:9*natom) = reshape(dipgrad, (/9*natom/)) + end if + if (has_polgrad) then + c_polgrad(:18*natom) = reshape(polgrad, (/18*natom/)) + end if + end if + +end subroutine hessian_api end module xtb_api_interface diff --git a/src/api/results.f90 b/src/api/results.f90 index 74c99bc50..2c904b918 100644 --- a/src/api/results.f90 +++ b/src/api/results.f90 @@ -42,6 +42,7 @@ module xtb_api_results real(wp), allocatable :: sigma(:, :) real(wp), allocatable :: dipole(:) real(wp), allocatable :: egap + real(wp), allocatable :: solvation_energy end type VResults @@ -135,6 +136,38 @@ subroutine getEnergy_api(venv, vres, dptr) & end subroutine getEnergy_api +!> Query singlepoint results object for solvation energy +subroutine getSolvationEnergy_api(venv, vres, dptr) & + & bind(C, name="xtb_getSolvationEnergy") + !DEC$ ATTRIBUTES DLLEXPORT :: getSolvationEnergy_api + character(len=*), parameter :: source = "xtb_api_getSolvationEnergy" + type(c_ptr), value :: venv + type(VEnvironment), pointer :: env + type(c_ptr), value :: vres + type(VResults), pointer :: res + real(c_double), intent(inout) :: dptr + + if (c_associated(venv)) then + call c_f_pointer(venv, env) + call checkGlobalEnv + + if (.not.c_associated(vres)) then + call env%ptr%error("Results object is not allocated", source) + return + end if + call c_f_pointer(vres, res) + + if (.not.allocated(res%solvation_energy)) then + call env%ptr%error("Solvation energy is not available in results", source) + return + end if + + dptr = res%solvation_energy + + end if + +end subroutine getSolvationEnergy_api + !> Query singlepoint results object for gradient subroutine getGradient_api(venv, vres, dptr) & diff --git a/src/api/version.f90 b/src/api/version.f90 index e8d5b1b4b..851fd70e2 100644 --- a/src/api/version.f90 +++ b/src/api/version.f90 @@ -23,7 +23,7 @@ module xtb_api_version public :: getAPIVersion_api - integer(c_int), parameter :: apiMajor = 1 + integer(c_int), parameter :: apiMajor = 2 integer(c_int), parameter :: apiMinor = 0 integer(c_int), parameter :: apiPatch = 0 diff --git a/src/axis_trafo.f90 b/src/axis_trafo.f90 index 32dd280ac..4d084e939 100644 --- a/src/axis_trafo.f90 +++ b/src/axis_trafo.f90 @@ -112,96 +112,128 @@ subroutine axis(numat,nat,xyz,aa,bb,cc) return end subroutine axis - subroutine axis2(numat,nat,xyz,aa,bb,cc,avmom,sumw) - use xtb_splitparam - implicit double precision (a-h,o-z) - dimension xyz(3,numat) - integer nat(numat) - PARAMETER (BOHR=0.52917726) - dimension t(6), rot(3), xyzmom(3), eig(3), evec(3,3) - dimension x(numat),y(numat),z(numat),coord(3,numat) - data t /6*0.d0/ - !************************************************************************ - !* const1 = 10**40/(n*a*a) - !* n = avergadro's number - !* a = cm in an angstrom - !* 10**40 is to allow units to be 10**(-40)gram-cm**2 - !* - !************************************************************************ - const1 = 1.66053d0 - !************************************************************************ - !* - !* const2 = conversion factor from angstrom-amu to cm**(-1) - !* - !* = (planck's constant*n*10**16)/(8*pi*pi*c) - !* = 6.62618*10**(-27)[erg-sec]*6.02205*10**23*10**16/ - !* (8*(3.1415926535)**2*2.997925*10**10[cm/sec]) - !* - !************************************************************************ - const2=16.8576522d0 - - sumw=1.d-20 - sumwx=0.d0 - sumwy=0.d0 - sumwz=0.d0 - coord(1:3,1:numat)=xyz(1:3,1:numat)*bohr +subroutine axis2(n,xyz,aa,bb,cc,avmom,sumw) + + use xtb_splitparam, only : atmass + use xtb_mctc_convert, only : autoaa + + implicit double precision (a-h,o-z) + + !> number of atoms + integer, intent(in) :: n + + !> cartesian coordinates + real(wp), intent(in) :: xyz(:,:) + + !> rotational constants + real(wp), intent(out) :: aa,bb,cc + + !> average moment of inertia + real(wp), intent(out) :: avmom + + !> sum of atomic masses + real(wp), intent(out) :: sumw + + !> const1 = 10**40/(n*a*a) + !> n = avergadro's number + !> a = cm in an angstrom + !> 10**40 is to allow units to be 10**(-40)gram-cm**2 + real(wp), parameter :: const1 = 1.66053_wp + + !> const2 = conversion factor from angstrom-amu to cm**(-1) + !> = (planck's constant*n*10**16)/(8*pi*pi*c) + !> = 6.62618*10**(-27)[erg-sec]*6.02205*10**23*10**16/ + !> (8*(3.1415926535)**2*2.997925*10**10[cm/sec]) + real(wp), parameter :: const2 = 16.8576522_wp + + !> temporary variables + real(wp) :: xsum,eps,ams + + !> weighted sum of coordinates + real(wp) :: sumwx,sumwy,sumwz + + !> loop variables + integer :: i + + !> temporary arrays + real(wp) :: t(6), rot(3), xyzmom(3), eig(3), evec(3,3) + real(wp) :: x(n),y(n),z(n) + + !> Cartesian coordinates in Bohr + real(wp) :: coord(3,n) + + t(:) = 0.0_wp + sumw = 0.0_wp + sumwx = 0.0_wp + sumwy = 0.0_wp + sumwz = 0.0_wp + + ! convert Bohr to Angstrom ! + coord(:,:) = xyz(:,:) * autoaa + + ! cma ! + do i=1,n + sumw=sumw+atmass(i) + sumwx=sumwx+atmass(i)*coord(1,i) + sumwy=sumwy+atmass(i)*coord(2,i) + sumwz=sumwz+atmass(i)*coord(3,i) + enddo + + sumwx=sumwx/sumw + sumwy=sumwy/sumw + sumwz=sumwz/sumw + + do i=1,n + x(i)=coord(1,i)-sumwx + y(i)=coord(2,i)-sumwy + z(i)=coord(3,i)-sumwz + enddo + + !************************************************************************ + !* matrix for moments of inertia is of form + !* + !* | y**2+z**2 | + !* | -y*x z**2+x**2 | -i =0 + !* | -z*x -z*y x**2+y**2 | + !* + !************************************************************************ + do i=1,6 + t(i)=dble(i)*1.0d-10 + enddo + + do i=1,n + t(1)=t(1)+atmass(i)*(y(i)**2+z(i)**2) + t(2)=t(2)-atmass(i)*x(i)*y(i) + t(3)=t(3)+atmass(i)*(z(i)**2+x(i)**2) + t(4)=t(4)-atmass(i)*z(i)*x(i) + t(5)=t(5)-atmass(i)*y(i)*z(i) + t(6)=t(6)+atmass(i)*(x(i)**2+y(i)**2) + enddo + + call rsp(t,3,3,eig,evec) + + do i=1,3 + + if(eig(i).lt.3.d-4) then + eig(i)=0.d0 + rot(i)=0.d0 + else + rot(i)=2.9979245d+4*const2/eig(i) + endif - do i=1,numat - sumw=sumw+atmass(i) - sumwx=sumwx+atmass(i)*coord(1,i) - sumwy=sumwy+atmass(i)*coord(2,i) - sumwz=sumwz+atmass(i)*coord(3,i) - enddo + xyzmom(i)=eig(i)*const1 - sumwx=sumwx/sumw - sumwy=sumwy/sumw - sumwz=sumwz/sumw - f=1.0d0/bohr - do i=1,numat - x(i)=coord(1,i)-sumwx - y(i)=coord(2,i)-sumwy - z(i)=coord(3,i)-sumwz - enddo + enddo - !************************************************************************ - !* matrix for moments of inertia is of form - !* - !* | y**2+z**2 | - !* | -y*x z**2+x**2 | -i =0 - !* | -z*x -z*y x**2+y**2 | - !* - !************************************************************************ - do i=1,6 - t(i)=dble(i)*1.0d-10 - enddo - do i=1,numat - t(1)=t(1)+atmass(i)*(y(i)**2+z(i)**2) - t(2)=t(2)-atmass(i)*x(i)*y(i) - t(3)=t(3)+atmass(i)*(z(i)**2+x(i)**2) - t(4)=t(4)-atmass(i)*z(i)*x(i) - t(5)=t(5)-atmass(i)*y(i)*z(i) - t(6)=t(6)+atmass(i)*(x(i)**2+y(i)**2) - enddo - call rsp(t,3,3,eig,evec) - do i=1,3 - if(eig(i).lt.3.d-4) then - eig(i)=0.d0 - rot(i)=0.d0 - else - rot(i)=2.9979245d+4*const2/eig(i) - endif - xyzmom(i)=eig(i)*const1 - enddo + aa=rot(3)/2.9979245d+4 + bb=rot(2)/2.9979245d+4 + cc=rot(1)/2.9979245d+4 - aa=rot(3)/2.9979245d+4 - bb=rot(2)/2.9979245d+4 - cc=rot(1)/2.9979245d+4 - avmom=1.d-47*(xyzmom(1)+xyzmom(2)+xyzmom(3))/3. + avmom=1.d-47*(xyzmom(1)+xyzmom(2)+xyzmom(3))/3. - return - end subroutine axis2 +end subroutine axis2 subroutine axisvec(numat,nat,xyz,aa,bb,cc,evec) use xtb_splitparam diff --git a/src/detrotra.f90 b/src/detrotra.f90 index 0b697ba30..7812d733a 100644 --- a/src/detrotra.f90 +++ b/src/detrotra.f90 @@ -77,62 +77,71 @@ subroutine detrotra4(linear,mol,h,eig) enddo end subroutine detrotra4 - - subroutine detrotra8(linear,n,xyz,h,eig) - use xtb_mctc_accuracy, only : wp - use xtb_type_molecule - implicit none - integer, intent(in) :: n - real(wp), intent(in) :: xyz(3,n) ! values from projected Lindh diag - real(wp), intent(in) :: h(3*n,3*n) ! values from projected Lindh diag - real(wp), intent(inout) :: eig(3*n) ! eigenvectors from projected Lindh diag - logical, intent(in) :: linear - - integer :: i,j,k,kk,ii,nn,n3,nend - integer,allocatable :: ind(:) - real(wp), allocatable :: tmp(:,:) - real(wp), allocatable :: e(:) - real(wp) :: a0,b0,c0 - - n3 = 3*n - - allocate(tmp(3,n),e(n3),ind(n3)) - - nn = 0 - do ii=1, n3 - if(eig(ii).gt.0.05) cycle ! only lowest checked - - kk=0 - do j=1,n - do k=1,3 - kk=kk+1 - tmp(k,j)=xyz(k,j)+h(kk,ii) ! distort along mode ii - enddo - enddo - - c0=0 ! compared all interatomic distances of original and distortet geom. - do i=2,n - do j=1,i-1 - a0 = sqrt((xyz(1,i)-xyz(1,j))**2+(xyz(2,i)-xyz(2,j))**2+(xyz(3,i)-xyz(3,j))**2) - b0 = sqrt((tmp(1,i)-tmp(1,j))**2+(tmp(2,i)-tmp(2,j))**2+(tmp(3,i)-tmp(3,j))**2) - c0 = c0+(a0-b0)**2 - enddo - enddo - nn = nn + 1 - e(nn)=sqrt(c0/n)*abs(eig(ii)) ! weight by Lindh eigenvalue - ind(nn)=nn - - enddo - - call qsort(e, 1, nn, ind) ! sort - - nend = 6 - if (linear) nend = 5 - - do i=1,nend - eig(ind(i)) = 0.0 ! identifier for rot/tra - enddo - - end subroutine detrotra8 + +!> determine rotational and translational modes +subroutine detrotra8(linear,n,xyz,h,eig) + + use xtb_mctc_accuracy, only : wp + use xtb_type_molecule + implicit none + + integer, intent(in) :: n + real(wp), intent(in) :: xyz(3,n) ! values from projected Lindh diag + real(wp), intent(in) :: h(3*n,3*n) ! values from projected Lindh diag + real(wp), intent(inout) :: eig(3*n) ! eigenvalues from projected Lindh diag + logical, intent(in) :: linear + + integer :: i,j,k,kk,ii,nn,n3,nend + integer,allocatable :: ind(:) + real(wp), allocatable :: tmpxyz(:,:) + real(wp), allocatable :: e(:) + real(wp) :: a0,b0,c0 + + n3 = 3*n + + allocate(tmpxyz(3,n),e(n3),ind(n3)) + + nn = 0 + do ii=1, n3 + + if(eig(ii).gt.0.05) cycle ! check only low-lying modes + + ! distort initial geometry along ii-th mode ! + kk=0 + do j=1,n + do k=1,3 + kk=kk+1 + tmpxyz(k,j)=xyz(k,j)+h(kk,ii) + enddo + enddo + + ! compare all interatomic distances of original and distortet geom. ! + c0=0 + do i=2,n + do j=1,i-1 + a0 = sqrt((xyz(1,i)-xyz(1,j))**2+(xyz(2,i)-xyz(2,j))**2+(xyz(3,i)-xyz(3,j))**2) + b0 = sqrt((tmpxyz(1,i)-tmpxyz(1,j))**2+(tmpxyz(2,i)-tmpxyz(2,j))**2+(tmpxyz(3,i)-tmpxyz(3,j))**2) + c0 = c0+(a0-b0)**2 ! sum of squared differences + enddo + enddo + + nn = nn + 1 + e(nn)=sqrt(c0/n)*abs(eig(ii)) ! weight by Lindh eigenvalue + ind(nn)=nn + + enddo + + ! sort in ascending order ! + call qsort(e,1,nn,ind) + + nend = 6 + if (linear) nend = 5 + + ! set lowest eigenvalues to zero ! + do i=1,nend + eig(ind(i)) = 0.0 + enddo + +end subroutine detrotra8 end module xtb_detrotra diff --git a/src/dipro.F90 b/src/dipro.F90 index 42a136364..ab64e0710 100644 --- a/src/dipro.F90 +++ b/src/dipro.F90 @@ -130,6 +130,10 @@ subroutine get_jab(env, tblite, mol, fragment, dipro) !=========================set up calculator=========================================== call get_calculator(xcalc, struc, tblite%method, error) + if (allocated(error)) then + call env%error(error%message, source) + return + end if call new_wavefunction(wfn, struc%nat, xcalc%bas%nsh, xcalc%bas%nao, & & 1, set%etemp * ktoau) wfn%nspin=1 @@ -258,6 +262,10 @@ subroutine get_jab(env, tblite, mol, fragment, dipro) write(*,'(A,I2)') "unpaired e- of fragment : ", mfrag(ifr)%uhf call get_calculator(fcalc(ifr), mfrag(ifr), tblite%method, error) + if (allocated(error)) then + call env%error(error%message, source) + return + end if !> mol%charge is updated automatically from wfn by tblite library call new_wavefunction(wfx(ifr), mfrag(ifr)%nat, fcalc(ifr)%bas%nsh, fcalc(ifr)%bas%nao, & & 1, set%etemp * ktoau) diff --git a/src/dipro/xtb.F90 b/src/dipro/xtb.F90 index 95aff7848..4db948a3e 100644 --- a/src/dipro/xtb.F90 +++ b/src/dipro/xtb.F90 @@ -50,11 +50,11 @@ subroutine get_calculator(xcalc, mol, method, error) call fatal_error(error, "Unknown method '"//method//"' requested") ! error stop case("gfn2") - call new_gfn2_calculator(xcalc, mol) + call new_gfn2_calculator(xcalc, mol, error) case("gfn1") - call new_gfn1_calculator(xcalc, mol) + call new_gfn1_calculator(xcalc, mol, error) case("ipea1") - call new_ipea1_calculator(xcalc, mol) + call new_ipea1_calculator(xcalc, mol, error) end select end subroutine get_calculator #endif diff --git a/src/docking/param.f90 b/src/docking/param.f90 index 5c872c705..8aa964f29 100644 --- a/src/docking/param.f90 +++ b/src/docking/param.f90 @@ -359,7 +359,7 @@ end subroutine diptot ! axis ! molw is the weigth, sum3 the CMA (all in a.u.) - subroutine axis(numat, nat, coord, sum3, sumw, eig, evec) + subroutine axis_docking(numat, nat, coord, sum3, sumw, eig, evec) integer, intent(in) ::numat, nat(numat) real(wp), intent(in) :: coord(3, *) @@ -368,7 +368,7 @@ subroutine axis(numat, nat, coord, sum3, sumw, eig, evec) real(wp) :: t(6) real(wp) :: x(numat), y(numat), z(numat) real(wp) :: sumwx, sumwy, sumwz - real(wp) :: atmass + real(wp) :: atmass_dock integer :: i real(wp) :: ams(107) data ams/1.00790d0, 4.00260d0, 6.94000d0, 9.01218d0,& @@ -396,11 +396,11 @@ subroutine axis(numat, nat, coord, sum3, sumw, eig, evec) sumwz = 0.d0 do i = 1, numat - atmass = ams(nat(i)) - sumw = sumw + atmass - sumwx = sumwx + atmass*coord(1, i) - sumwy = sumwy + atmass*coord(2, i) - sumwz = sumwz + atmass*coord(3, i) + atmass_dock = ams(nat(i)) + sumw = sumw + atmass_dock + sumwx = sumwx + atmass_dock*coord(1, i) + sumwy = sumwy + atmass_dock*coord(2, i) + sumwz = sumwz + atmass_dock*coord(3, i) end do sum3(1) = sumwx/sumw @@ -418,19 +418,19 @@ subroutine axis(numat, nat, coord, sum3, sumw, eig, evec) end do do i = 1, numat - atmass = ams(nat(i)) - t(1) = t(1) + atmass*(y(i)**2 + z(i)**2) - t(2) = t(2) - atmass*x(i)*y(i) - t(3) = t(3) + atmass*(z(i)**2 + x(i)**2) - t(4) = t(4) - atmass*z(i)*x(i) - t(5) = t(5) - atmass*y(i)*z(i) - t(6) = t(6) + atmass*(x(i)**2 + y(i)**2) + atmass_dock = ams(nat(i)) + t(1) = t(1) + atmass_dock*(y(i)**2 + z(i)**2) + t(2) = t(2) - atmass_dock*x(i)*y(i) + t(3) = t(3) + atmass_dock*(z(i)**2 + x(i)**2) + t(4) = t(4) - atmass_dock*z(i)*x(i) + t(5) = t(5) - atmass_dock*y(i)*z(i) + t(6) = t(6) + atmass_dock*(x(i)**2 + y(i)**2) end do call rsp(t, 3, 3, eig, evec) eig = eig/sumw - end subroutine axis + end subroutine axis_docking subroutine cmadock(n, numat, nat, coord, sum3) @@ -1225,6 +1225,7 @@ subroutine combine_mol(comb, molA, molB) call init(comb, at, xyz) comb%chrg = molA%chrg + molB%chrg comb%uhf = molA%uhf + molB%uhf + atmass=comb%atmass !Setting global atmass array required in axis module deallocate (at) deallocate (xyz) diff --git a/src/docking/search_nci.f90 b/src/docking/search_nci.f90 index e1d846e10..92b454f5b 100644 --- a/src/docking/search_nci.f90 +++ b/src/docking/search_nci.f90 @@ -48,13 +48,14 @@ module xtb_docking_search_nci & gff_print, gfnff_param_dealloc use xtb_constrain_param, only: read_userdata use xtb_fixparam - use xtb_disp_ncoord, only: ncoord_gfn, ncoord_erf + use xtb_disp_ncoord, only: ncoord_gfn, ncoord_erf, ncoord_d3 use xtb_scc_core, only: iniqshell use xtb_eeq, only: goedecker_chrgeq use xtb_basis, only: newBasisset use xtb_gfnff_neighbor, only: TNeigh use xtb_io_writer, only : writeMolecule use xtb_mctc_filetypes, only : generateFileName + use xtb_iniq, only: iniqcn implicit none private @@ -203,9 +204,9 @@ END SUBROUTINE Quicksort if (.not. fulle) write (env%unit, *) ! just output - call axis(n1, at1, xyz1, dum, pmass, dum2, dum3) + call axis_docking(n1, at1, xyz1, dum, pmass, dum2, dum3) r1 = sqrt(dum2(1) + dum2(2) + dum2(3)) - call axis(n2, at2, xyz2, dum, pmass, dum2, dum3) + call axis_docking(n2, at2, xyz2, dum, pmass, dum2, dum3) r2 = sqrt(dum2(1) + dum2(2) + dum2(3)) call rcma(n1, xyz1, at1, n2, xyz2, at2, r, rmin) write (env%unit, '('' Method for final opts. :'',1x,a )') optlvl @@ -500,7 +501,7 @@ END SUBROUTINE Quicksort ! xyztmp contains now each gridpoint belonging to fragment i ! same for attmp (anyway always probe_atom_type) ! determine size (=R) of gridpoint cluster belonging to fragment i - call axis(k, attmp, xyztmp, dum, pmass, dum2, dum3) + call axis_docking(k, attmp, xyztmp, dum, pmass, dum2, dum3) r = sqrt(dum2(1) + dum2(2) + dum2(3)) !> check if moleculeB is small enough to fit in gridpoint cluster of fragmen i @@ -1065,11 +1066,17 @@ subroutine restart_gff(env, mol, calc) call gfnff_param_dealloc(calc%topo) call newD3Model(calc%topo%dispm, mol%n, mol%at) call gfnff_set_param(mol%n, calc%gen, calc%param) - if (.not. allocated(calc%neigh%nb)) allocate (calc%neigh%nb(calc%neigh%numnb, mol%n, calc%neigh%numctr), source=0) - if (.not.allocated(calc%topo%qfrag)) & - & allocate( calc%topo%qfrag(mol%n), source = 0.0d0 ) - if (.not.allocated(calc%topo%fraglist)) & - & allocate( calc%topo%fraglist(mol%n), source = 0 ) + if (allocated(calc%neigh%nb)) deallocate(calc%neigh%nb) + allocate (calc%neigh%nb(calc%neigh%numnb, mol%n, calc%neigh%numctr), source=0) + if (allocated(calc%topo%qfrag)) deallocate(calc%topo%qfrag) + allocate( calc%topo%qfrag(mol%n), source = 0.0d0 ) + if (allocated(calc%topo%fraglist)) deallocate(calc%topo%fraglist) + allocate( calc%topo%fraglist(mol%n), source = 0 ) + if (allocated(calc%neigh%iTrUsed)) deallocate(calc%neigh%iTrUsed) + if (allocated(calc%neigh%bpair)) deallocate(calc%neigh%bpair) + if (allocated(calc%neigh%blist)) deallocate(calc%neigh%blist) + if (allocated(calc%neigh%vbond)) deallocate(calc%neigh%vbond) + if (allocated(calc%neigh%nr_hb)) deallocate(calc%neigh%nr_hb) calc%topo%qfrag(1) = set%ichrg calc%topo%qfrag(2:mol%n) = 0.0_wp call gfnff_ini(env, .false., ini, mol, calc%gen,& @@ -1116,15 +1123,30 @@ subroutine restart_xTB(env, mol, chk, calc, basisset) calc%maxiter = set%maxscciter call chk%wfn%allocate(mol%n, calc%basis%nshell, calc%basis%nao) + ! Make sure number of electrons is initialized an multiplicity is consistent + chk%wfn%nel = nint(sum(mol%z) - mol%chrg) + chk%wfn%nopen = mol%uhf + if (chk%wfn%nopen == 0 .and. mod(chk%wfn%nel, 2) /= 0) chk%wfn%nopen = 1 + !> EN charges and CN - call ncoord_gfn(mol%n, mol%at, mol%xyz, cn) + if (set%gfn_method < 2) then + call ncoord_d3(mol%n, mol%at, mol%xyz, cn) + else + call ncoord_gfn(mol%n, mol%at, mol%xyz, cn) + end if if (mol%npbc > 0) then chk%wfn%q = real(set%ichrg, wp)/real(mol%n, wp) else - call ncoord_erf(mol%n, mol%at, mol%xyz, cn) - call goedecker_chrgeq(mol%n,mol%at,mol%xyz,real(set%ichrg,wp),cn,dcn,chk%wfn%q,dq,er,g,& - & .false., .false., .false.) - chk%wfn%q = real(set%ichrg, wp)/real(mol%n, wp) + if (set%guess_charges == p_guess_gasteiger) then + call iniqcn(mol%n, mol%at, mol%z, mol%xyz, set%ichrg, 1.0_wp, chk%wfn%q, cn, set%gfn_method, .true.) + else if (set%guess_charges == p_guess_goedecker) then + call ncoord_erf(mol%n, mol%at, mol%xyz, cn) + call goedecker_chrgeq(mol%n, mol%at, mol%xyz, real(set%ichrg, wp), cn, dcn, chk%wfn%q, dq, er, g, & + .false., .false., .false.) + else + call ncoord_gfn(mol%n, mol%at, mol%xyz, cn) + chk%wfn%q = real(set%ichrg, wp) / real(mol%n, wp) + end if end if !> initialize shell charges from gasteiger charges call iniqshell(calc%xtbData,mol%n,mol%at,mol%z,calc%basis%nshell,chk%wfn%q,chk%wfn%qsh,set%gfn_method) diff --git a/src/esp.f b/src/esp.f index f18a4b67f..8caf7045f 100644 --- a/src/esp.f +++ b/src/esp.f @@ -124,12 +124,12 @@ subroutine espplot(n,nmo,nbf,at,xyz,z,occ,C,basis) call timing(t0,w0) point=0 call espints(n,nbf,xyz,intcut,point,pthr,P, - & mprim,npp,nnn,indp,efact,gama,ee,dd,espe(i),basis) + & mprim,npp,nnn,indp,efact,gama,ee,dd,espe(1),basis) call timing(t1,w1) write(*,'('' estimated wall time (s) '',f6.1)') np*(w1-w0)/nproc write(*,*)'computing ESP ...' -!$OMP PARALLEL PRIVATE(i,rx,ry,rz,r,point) +!$OMP PARALLEL PRIVATE(i,j,rx,ry,rz,r,point) !$OMP& SHARED(espe,pa,basis) !$OMP& DEFAULT(SHARED) !$OMP DO diff --git a/src/geoopt_driver.f90 b/src/geoopt_driver.f90 index 35405bd17..b05bb942f 100644 --- a/src/geoopt_driver.f90 +++ b/src/geoopt_driver.f90 @@ -157,7 +157,7 @@ subroutine geometry_optimization & ! get number of unique species; used in precond_lindh !call get_identity(mol%nid, mol%id, mol%at) ! create new anc filter - optcell = mol%npbc > 0 ! optimize cell parameters if present + optcell = mol%npbc > 0 .and. set%optcell call new_cartesian_filter(filter, mol, optcell) ! create new Limited-memory BFGS optimizer call new_lbfgs_optimizer(lbfgs_opt, env, opt_input, filter) diff --git a/src/gfnff/gfnff_eg.f90 b/src/gfnff/gfnff_eg.f90 index d7210e9c3..58b84ca1f 100644 --- a/src/gfnff/gfnff_eg.f90 +++ b/src/gfnff/gfnff_eg.f90 @@ -197,6 +197,7 @@ subroutine gfnff_eg(env,mol,pr,n,ichrg,at,xyz,sigma,g,etot,res_gff, & real(wp),allocatable :: xtmp(:) type(tb_timer) :: timer real(wp) :: dispthr, cnthr, repthr, hbthr1, hbthr2 + real(wp) :: dist(n,n) real(wp) :: ds(3,3) real(wp) :: convF !convergence factor alpha, aka ewald parameter logical, allocatable :: considered_ABH(:,:,:) @@ -225,9 +226,6 @@ subroutine gfnff_eg(env,mol,pr,n,ichrg,at,xyz,sigma,g,etot,res_gff, & ! get Distances between atoms for repulsion call neigh%getTransVec(env,mol,sqrt(repthr)) - if(allocated(neigh%distances)) deallocate(neigh%distances) - call getDistances(neigh%distances, mol, neigh) - g = 0 exb = 0 @@ -291,6 +289,18 @@ subroutine gfnff_eg(env,mol,pr,n,ichrg,at,xyz,sigma,g,etot,res_gff, & sqrab(ij + i) = 0.0d0 srab(ij + i) = 0.0d0 enddo + if (mol%npbc.ne.0) then + dist = 0.0_wp + !$omp parallel do collapse(2) default(none) shared(dist,mol) & + !$omp private(i,j) + do i=1, mol%n + do j=1, mol%n + dist(j,i) = NORM2(mol%xyz(:,j)-mol%xyz(:,i)) + enddo + enddo + !$omp end parallel do + endif + if (pr) call timer%measure(1) !----------! @@ -434,7 +444,7 @@ subroutine gfnff_eg(env,mol,pr,n,ichrg,at,xyz,sigma,g,etot,res_gff, & if (pr) call timer%measure(4) else if (pr) call timer%measure(4,'EEQ energy and q') - call goed_pbc_gfnff(env,mol,accuracy.gt.1,n,at,neigh%distances(:,:,1), & + call goed_pbc_gfnff(env,mol,accuracy.gt.1,n,at,dist, & & dfloat(ichrg),eeqtmp,cn,nlist%q,ees,solvation,param,topo, gTrans, & & rTrans, xtmp, convF) ! without dq/dr ees = ees*mcf_ees @@ -602,7 +612,7 @@ subroutine gfnff_eg(env,mol,pr,n,ichrg,at,xyz,sigma,g,etot,res_gff, & dx=xa-xyz(1,jat)-neigh%transVec(1,iTr) dy=ya-xyz(2,jat)-neigh%transVec(2,iTr) dz=za-xyz(3,jat)-neigh%transvec(3,iTr) - rab=neigh%distances(jat,iat,iTr) + rab=NORM2(xyz(:,iat)-(xyz(:,jat)+neigh%transVec(:,iTr))) r2=rab**2 ati=at(iat) atj=at(jat) @@ -734,8 +744,6 @@ subroutine gfnff_eg(env,mol,pr,n,ichrg,at,xyz,sigma,g,etot,res_gff, & call neigh%getTransVec(env,mol,sqrt(hbthr2)) if (pr) call timer%measure(10,'HB/XB (incl list setup)') if (update.or.require_update) then - if(allocated(neigh%distances)) deallocate(neigh%distances) - call getDistances(neigh%distances, mol, neigh) call gfnff_hbset(n,at,xyz,topo,neigh,nlist,hbthr1,hbthr2) end if @@ -781,12 +789,11 @@ subroutine gfnff_eg(env,mol,pr,n,ichrg,at,xyz,sigma,g,etot,res_gff, & nbk=0 iTr=0 ! nbk is the first neighbor of k ! atnb=0 - call neigh%jth_nb(nbk,1,k,iTr) + call neigh%jth_nb(n,xyz,nbk,1,k,iTr) ! get iTrC and cycle if out of cutoff (the cutoff used in last getTransVec call) iTrDum=neigh%fTrSum(iTr,iTrk) if(iTrDum.eq.-1.or.iTrDum.gt.neigh%nTrans) cycle ! get number neighbors of neighbor of k ! - if(nbk.le.0 .or. nbk.gt.n) write(*,*) 'nbk=',nbk if(nbk.ne.0) then nbnbk=sum(neigh%nb(neigh%numnb,nbk,:)) atnb=at(nbk) @@ -2283,7 +2290,7 @@ subroutine abhgfnff_eg2new(n,A,B,H,iTrA,iTrB,nbb,at,xyz,q,sqrab, & ! Neighbours of B do i=1,nbb inb=0; iTr=0 ! jth_nb output - call neigh%jth_nb(inb,i,B,iTr) ! inb is the i-th nb of B when inb is shifted to iTr + call neigh%jth_nb(n,xyz,inb,i,B,iTr) ! inb is the i-th nb of B when inb is shifted to iTr ! compute distances vecDum = neigh%transVec(:,iTr)+neigh%transVec(:,iTrB) dranb(1:3,i) = (xyz(1:3,A)+neigh%transVec(1:3,iTrA)) -(xyz(1:3,inb)+vecDum) @@ -2456,7 +2463,7 @@ subroutine abhgfnff_eg2new(n,A,B,H,iTrA,iTrB,nbb,at,xyz,q,sqrab, & gdr(1:3,H) = gdr(1:3,H) + gh(1:3) do i=1,nbb inb=0; iTr=0 ! jth_nb output - call neigh%jth_nb(inb,i,B,iTr) ! inb is the i-th nb of B when shifted to iTr + call neigh%jth_nb(n,xyz,inb,i,B,iTr) ! inb is the i-th nb of B when shifted to iTr gdr(1:3,inb) = gdr(1:3,inb) + gnb(1:3,i) end do @@ -2466,7 +2473,7 @@ subroutine abhgfnff_eg2new(n,A,B,H,iTrA,iTrB,nbb,at,xyz,q,sqrab, & sigma=sigma+mcf_ehb*spread(gh,1,3)*spread(xyz(:,H),2,3) do i=1,nbb inb=0; iTr=0 ! jth_nb output - call neigh%jth_nb(inb,i,B,iTr) ! inb is the i-th nb of B when shifted to iTr + call neigh%jth_nb(n,xyz,inb,i,B,iTr) ! inb is the i-th nb of B when shifted to iTr vecDum = neigh%transVec(:,iTr)+neigh%transVec(:,iTrB) sigma=sigma+mcf_ehb*spread(gnb(:,i),1,3)*spread(xyz(:,inb)+vecDum,2,3) enddo @@ -2543,7 +2550,7 @@ subroutine abhgfnff_eg2_rnr(n,A,B,H,iTrA,iTrB,at,xyz,q,sqrab,srab,energy,gdr,par ! Neighbours of B do i=1,nbb inb=0; iTr=0 ! jth_nb output - call neigh%jth_nb(inb,i,B,iTr) ! inb is the i-th nb of B when shifted to iTr + call neigh%jth_nb(n,xyz,inb,i,B,iTr) ! inb is the i-th nb of B when shifted to iTr ! compute distances vTrinb=neigh%transVec(:,iTr)+neigh%transVec(:,iTrB) dranb(1:3,i) = (xyz(1:3,A)+neigh%transVec(1:3,iTrA)) -(xyz(1:3,inb)+vTrinb) @@ -2753,7 +2760,7 @@ subroutine abhgfnff_eg2_rnr(n,A,B,H,iTrA,iTrB,at,xyz,q,sqrab,srab,energy,gdr,par gdr(1:3,H) = gdr(1:3,H) + gh(1:3) do i=1,nbb inb=0; iTr=0 ! jth_nb output - call neigh%jth_nb(inb,i,B,iTr) ! inb is the i-th nb of B when shifted to iTr + call neigh%jth_nb(n,xyz,inb,i,B,iTr) ! inb is the i-th nb of B when shifted to iTr gdr(1:3,inb) = gdr(1:3,inb) + gnb(1:3,i) - gnb_lp(1:3)/dble(nbb) end do @@ -2764,7 +2771,7 @@ subroutine abhgfnff_eg2_rnr(n,A,B,H,iTrA,iTrB,at,xyz,q,sqrab,srab,energy,gdr,par sigma=sigma+mcf_ehb*spread(gnb_lp,1,3)*spread(xyz(:,B)+neigh%transVec(1:3,iTrB),2,3) do i=1,nbb inb=0; iTr=0 ! jth_nb output - call neigh%jth_nb(inb,i,B,iTr) ! inb is the i-th nb of B when shifted to iTr + call neigh%jth_nb(n,xyz,inb,i,B,iTr) ! inb is the i-th nb of B when shifted to iTr vTrinb=neigh%transVec(:,iTr)+neigh%transVec(:,iTrB) sigma=sigma+mcf_ehb*spread(gnb(:,i),1,3)*spread(xyz(:,inb)+vTrinb,2,3) sigma=sigma-mcf_ehb*spread(gnb_lp(1:3)/dble(nbb),1,3)*spread(xyz(:,inb)+vTrinb,2,3) @@ -3267,8 +3274,8 @@ subroutine batmgfnff_eg(n,iat,jat,kat,iTrj,iTrk,at,xyz,q,sqrab,srab,energy,g,ds, real*8 r2ij,r2jk,r2ik,c9,mijk,imjk,ijmk,rijk3,ang,angr9,rav3 real*8 rij(3),rik(3),rjk(3),ri(3),rj(3),rk(3),drij,drik,drjk,dang,ff,fi,fj,fk,fqq parameter (fqq=3.0d0) - integer linij,linik,linjk,lina,i,j,iTrDum,dm1,dm2 - lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 + integer :: linij,linik,linjk,lina,i,j,iTrDum,dm1,dm2 + lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 fi=(1.d0-fqq*q(iat)) fi=min(max(fi,-4.0d0),4.0d0) @@ -3278,13 +3285,13 @@ subroutine batmgfnff_eg(n,iat,jat,kat,iTrj,iTrk,at,xyz,q,sqrab,srab,energy,g,ds, fk=min(max(fk,-4.0d0),4.0d0) ff=fi*fj*fk ! charge term c9=ff*param%zb3atm(at(iat))*param%zb3atm(at(jat))*param%zb3atm(at(kat)) ! strength of interaction - r2ij=neigh%distances(jat,iat,iTrj)**2 - r2ik=neigh%distances(kat,iat,iTrk)**2 + r2ij=NORM2(xyz(:,iat)-(xyz(:,jat)+neigh%transVec(:,iTrj)))**2 + r2ik=NORM2(xyz(:,iat)-(xyz(:,kat)+neigh%transVec(:,iTrk)))**2 iTrDum=neigh%fTrSum(neigh%iTrNeg(iTrj),iTrk) if(iTrDum.le.0.or.iTrDum.gt.neigh%numctr) then r2jk=NORM2((xyz(:,kat)+neigh%transVec(:,iTrk))-(xyz(:,jat)+neigh%transVec(:,iTrj)))**2 else - r2jk=neigh%distances(kat,jat,iTrDum)**2 !use adjusted iTr since jat is actually shifted + r2jk=NORM2(xyz(:,jat)-(xyz(:,kat)+neigh%transVec(:,iTrDum)))**2 endif mijk=-r2ij+r2jk+r2ik imjk= r2ij-r2jk+r2ik @@ -4039,9 +4046,9 @@ function get_cf(rTrans,gTrans,vol,avgAlp) result(cf) integer, parameter :: ewaldCutD(3) = 2 integer, parameter :: ewaldCutR(3) = 2 ! real space lattice vectors - real(wp), intent(in) :: rTrans( 3, product(2*ewaldCutD+1)) + real(wp), intent(in) :: rTrans(:, :) ! reciprocal space lattice vectors - real(wp), intent(in) :: gTrans(3, product(2*ewaldCutR+1)-1) + real(wp), intent(in) :: gTrans(:, :) ! unit cell volume real(wp), intent(in) :: vol ! average alphaEEQ value diff --git a/src/gfnff/gfnff_ini.f90 b/src/gfnff/gfnff_ini.f90 index f1b65be1f..a797a223b 100644 --- a/src/gfnff/gfnff_ini.f90 +++ b/src/gfnff/gfnff_ini.f90 @@ -206,19 +206,15 @@ integer function itabrow6(i) sqrab = 0 !Get all distances call neigh%getTransVec(env,mol,sqrt(hbthr2)) - if (.not. allocated(neigh%distances)) then - call getDistances(neigh%distances, mol, neigh) - endif ! Transfer calculated distances in central cell to rab and sqrab - ! want to change to neigh%distances do i=1, mol%n ati=mol%at(i) kk=i*(i-1)/2 do j=1, i-1 atj=mol%at(j) k=kk+j - rab(k) = neigh%distances(j,i,1) + rab(k) = NORM2(mol%xyz(:,i)-mol%xyz(:,j)) sqrab(k) = rab(k)**2 if(rab(k).lt.1.d-3) then write(env%unit,*) i,j,ati,atj,rab(k) @@ -404,7 +400,7 @@ integer function itabrow6(i) nn =sum(neigh%nb(neigh%numnb,i,:)) if(nn.eq.0) cycle ip =piadr2(i) - call neigh%jth_nb(ji,1,i,iTrtmp) ! ji is the first nb of i in cell iTr + call neigh%jth_nb(mol%n,mol%xyz,ji,1,i,iTrtmp) ! ji is the first nb of i in cell iTr nh =0 nm =0 do iTr=1, neigh%numctr @@ -858,7 +854,7 @@ integer function itabrow6(i) end do do i = 1,mol%n ! get first nb, iTr expected to be irrelevant since same in each cell - call neigh%jth_nb(nn,1,i,iTr) ! R - N/C/O - H ! terminal H + call neigh%jth_nb(mol%n,mol%xyz,nn,1,i,iTr) ! R - N/C/O - H ! terminal H if(nn.le.0) cycle ! cycle if there is no nb topo%hbaci(i)=param%xhaci(mol%at(i)) ! only first neighbor of interest if (amideH(mol%n,mol%at,topo%hyb,neigh%numnb,neigh%numctr,neigh%nb,piadr2,i,neigh)) & @@ -876,7 +872,7 @@ integer function itabrow6(i) if(mol%at(i).ne.1) cycle if(topo%hyb(i).eq.1) cycle ! exclude bridging hydrogens from HB correction ff=gen%hqabthr - call neigh%jth_nb(j,1,i,iTr) ! get j, first neighbor of H when j is shifted to iTr + call neigh%jth_nb(mol%n,mol%xyz,j,1,i,iTr) ! get j, first neighbor of H when j is shifted to iTr if(j.le.0) cycle if(mol%at(j).gt.10) ff=ff-0.20 ! H on heavy atoms may be negatively charged if(mol%at(j).eq.6.and.topo%hyb(j).eq.3) ff=ff+0.05 ! H on sp3 C must be really positive 0.05 @@ -1038,7 +1034,7 @@ integer function itabrow6(i) ja=piadr4(jj) if(ia.gt.0.and.ja.gt.0) then !dum=1.d-9*rab(lin(ii,jj)) ! distort so that Huckel for e.g. COT localizes to right bonds - dum=1.d-9*neigh%distances(jj,ii,iTr) ! distort so that Huckel for e.g. COT localizes to right bonds + dum=1.d-9*NORM2(mol%xyz(:,ii)-(mol%xyz(:,jj)+neigh%transVec(:,iTr))) ! distort so that Huckel for e.g. COT localizes to right bonds dum=sqrt(gen%hoffdiag(mol%at(ii))*gen%hoffdiag(mol%at(jj)))-dum ! better than arithmetic dum2=gen%hiter if(topo%hyb(ii).eq.1) dum2=dum2*gen%htriple ! triple bond is different @@ -2065,16 +2061,16 @@ integer function itabrow6(i) endif deallocate(locarr) ! sort atoms according to distance to central atom such that the same inversion angle def. always results - sdum3(1)=neigh%distances(jj,i,iTrj) - sdum3(2)=neigh%distances(kk,i,iTrk) - sdum3(3)=neigh%distances(ll,i,iTrl) + sdum3(1)=NORM2(mol%xyz(:,i)-(mol%xyz(:,jj)+neigh%transVec(:,iTrj))) + sdum3(2)=NORM2(mol%xyz(:,i)-(mol%xyz(:,kk)+neigh%transVec(:,iTrk))) + sdum3(3)=NORM2(mol%xyz(:,i)-(mol%xyz(:,ll)+neigh%transVec(:,iTrl))) ind3(1)=jj ind3(2)=kk ind3(3)=ll call ssort(3,sdum3,ind3) - sdum3(1)=neigh%distances(jj,i,iTrj) ! need old indices for sorting iTr's - sdum3(2)=neigh%distances(kk,i,iTrk) - sdum3(3)=neigh%distances(ll,i,iTrl) + sdum3(1)=NORM2(mol%xyz(:,i)-(mol%xyz(:,jj)+neigh%transVec(:,iTrj))) + sdum3(2)=NORM2(mol%xyz(:,i)-(mol%xyz(:,kk)+neigh%transVec(:,iTrk))) + sdum3(3)=NORM2(mol%xyz(:,i)-(mol%xyz(:,ll)+neigh%transVec(:,iTrl))) jj=ind3(1) ! assign sorted indices kk=ind3(2) ll=ind3(3) @@ -2163,7 +2159,7 @@ integer function itabrow6(i) if (mol%at(i).eq.6.and.sum(neigh%nb(neigh%numnb,i,:)).eq.2) then do j=1, 2 nbi=0 - call neigh%jth_nb(nbi,j,i,iTr) ! nbi is the jth nb of i in cell iTr + call neigh%jth_nb(mol%n,mol%xyz,nbi,j,i,iTr) ! nbi is the jth nb of i in cell iTr if (nbi.eq.0) cycle if (mol%at(nbi).eq.6.and.sum(neigh%nb(neigh%numnb,nbi,:)).eq.2) then nn = nn + 1 @@ -2222,7 +2218,7 @@ subroutine specialTorsList(nst, mol, topo, neigh, sTorsList) ! carbon with two neighbors bonded to other carbon* with two neighbors if (mol%at(i).eq.6.and.sum(neigh%nb(neigh%numnb,i,:)).eq.2) then do j=1, 2 - call neigh%jth_nb(nbi,j,i,iTr) ! nbi is the jth nb of i in cell iTr + call neigh%jth_nb(mol%n,mol%xyz,nbi,j,i,iTr) ! nbi is the jth nb of i in cell iTr if (nbi.eq.0.or.iTr.eq.0) cycle if (mol%at(nbi).eq.6.and.sum(neigh%nb(neigh%numnb,nbi,:)).eq.2) then ! *other carbon ! check carbon triple bond distance @@ -2231,14 +2227,14 @@ subroutine specialTorsList(nst, mol, topo, neigh, sTorsList) ! check C2 and C3 do k=1, 2 ! C2 is other nb of Ci nbk=0 - call neigh%jth_nb(nbk,k,i,iTr) ! nbk is the jth nb of i in cell iTr .ne.nbi + call neigh%jth_nb(mol%n,mol%xyz,nbk,k,i,iTr) ! nbk is the jth nb of i in cell iTr .ne.nbi if (nbk.ne.nbi.and.nbk.ne.0.and.mol%at(nbk).eq.6) then jj=nbk ! C2 index endif enddo do k=1, 2 ! C3 is other nb of Cnbi nbk=0 - call neigh%jth_nb(nbk,k,nbi,iTr) ! nbk is the jth nb of i in cell iTr .ne.nbi + call neigh%jth_nb(mol%n,mol%xyz,nbk,k,nbi,iTr) ! nbk is the jth nb of i in cell iTr .ne.nbi if (nbk.ne.i.and.nbk.ne.0.and.mol%at(nbk).eq.6) then kk=nbk ! C3 index endif @@ -2255,7 +2251,7 @@ subroutine specialTorsList(nst, mol, topo, neigh, sTorsList) ! on atom sorting in input file !!! The last one in file. do k=1, sum(neigh%nb(neigh%numnb,jj,:)) nbk=0 - call neigh%jth_nb(nbk,k,jj,iTr) ! nbk is the jth nb of i in cell iTr .ne.nbi + call neigh%jth_nb(mol%n,mol%xyz,nbk,k,jj,iTr) ! nbk is the jth nb of i in cell iTr .ne.nbi if (topo%hyb(k).eq.2.and.mol%at(k).eq.6.and.sum(neigh%nb(neigh%numnb,k,:)).eq.3.and. & & nbk.ne.i.and.nbk.ne.0) then ii=nbk @@ -2266,7 +2262,7 @@ subroutine specialTorsList(nst, mol, topo, neigh, sTorsList) ! on atom sorting in input file !!! The last one in file. do k=1, sum(neigh%nb(neigh%numnb,kk,:)) nbk=0 - call neigh%jth_nb(nbk,k,jj,iTr) ! nbk is the jth nb of i in cell iTr .ne.nbi + call neigh%jth_nb(mol%n,mol%xyz,nbk,k,jj,iTr) ! nbk is the jth nb of i in cell iTr .ne.nbi if (topo%hyb(k).eq.2.and.mol%at(k).eq.6.and.sum(neigh%nb(neigh%numnb,i,:)).eq.3.and. & & nbk.ne.nbi.and.nbk.ne.0) then ll=nbk diff --git a/src/gfnff/gfnff_ini2.f90 b/src/gfnff/gfnff_ini2.f90 index d335eabad..e0a70da3e 100644 --- a/src/gfnff/gfnff_ini2.f90 +++ b/src/gfnff/gfnff_ini2.f90 @@ -343,7 +343,7 @@ subroutine gfnff_neigh(env,makeneighbor,natoms,at,xyz,rab,fq,f_in,f2_in,lintr, & if(nb20i.gt.3.and.ati.gt.10.and.nbdiff.eq.0) hyb(i)=5 if(nb20i.eq.2) hyb(i)=3 if(nb20i.eq.2.and.nbmdiff.gt.0) then - call nn_nearest_noM(i,natoms,at,neigh,rab,j,param) ! CN of closest non-M atom + call nn_nearest_noM(i,natoms,at,mol%xyz,neigh,rab,j,param) ! CN of closest non-M atom if(j.eq.3) hyb(i)=2 ! M-O-X konj if(j.eq.4) hyb(i)=3 ! M-O-X non endif @@ -469,27 +469,32 @@ end subroutine getnb ! find the CN of the non metal atom that is closest to atom i !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc - subroutine nn_nearest_noM(ii,n,at,neigh,r,nn,param) + subroutine nn_nearest_noM(ii,n,at,xyz,neigh,r,nn,param) + use xtb_mctc_accuracy, only : wp implicit none type(TGFFData), intent(in) :: param type(TNeigh), intent(in) :: neigh integer, intent(in) :: ii,n,at(n) + real(wp), intent(in) :: xyz(3,n) integer, intent(inout) :: nn real*8, intent(in) :: r(n*(n+1)/2) integer jmin,j,jj,lin, numnb, iTr + real(wp) :: dist real*8 rmin numnb=neigh%numnb nn=0 rmin=1.d+42 jmin=0 + dist=0.0 do iTr=1, neigh%numctr do j=1,neigh%nb(numnb,ii,iTr) jj=neigh%nb(j,ii,iTr) if(param%metal(at(jj)).ne.0) cycle - if(neigh%distances(jj,ii,iTr).lt.rmin)then - rmin=neigh%distances(jj,ii,iTr) + dist = NORM2(xyz(:,ii)-(xyz(:,jj)+neigh%transVec(:,iTr))) + if(dist.lt.rmin)then + rmin=dist jmin=jj endif enddo @@ -786,29 +791,22 @@ subroutine gfnff_hbset(n,at,xyz,topo,neigh,nlist,hbthr1,hbthr2) ! get adjustet iTr -> for use of neigh% distances and bpair with two shifted atoms iTrDum=neigh%fTrSum(neigh%iTrNeg(iTri),iTrj) if(iTrDum.gt.neigh%nTrans.or.iTrDum.lt.-1.or.iTrDum.eq.0) cycle ! cycle nonsense - if(iTrDum.eq.-1) then - rab=NORM2((xyz(:,i)+neigh%transVec(:,iTri))-(xyz(:,j)+neigh%transVec(:,iTrj)))**2 - if(rab.gt.hbthr1) cycle - ijnonbond=.true. ! i and j are not in neighboring or same cell for iTrDum=-1 + rab=NORM2((xyz(:,i)+neigh%transVec(:,iTri))-(xyz(:,j)+neigh%transVec(:,iTrj)))**2 + if(rab.gt.hbthr1) cycle + ! check if ij bonded + if(iTrDum.le.neigh%numctr.and.iTrDum.gt.0) then + ijnonbond=neigh%bpair(j,i,iTrDum).ne.1 else - ! check ij distance - rab=neigh%distances(j,i,iTrDum)**2 ! %distances are generated up to hbthr2 - if(rab.gt.hbthr1) cycle - ! check if ij bonded - if(iTrDum.le.neigh%numctr) then - ijnonbond=neigh%bpair(j,i,iTrDum).ne.1 - else - ! i and j are not in neighboring cells - ijnonbond=.true. - endif + ! i and j are not in neighboring cells + ijnonbond=.true. endif ! loop over relevant H atoms do k=1,topo%nathbH free=.true. ! tripplet not assigned yet nh =topo%hbatHl(1,k) ! nh always in central cell ! distances for non-cov bonded case - rih=neigh%distances(i,nh,iTri)**2 - rjh=neigh%distances(j,nh,iTrj)**2 + rih=NORM2(xyz(:,nh)-(xyz(:,i)+neigh%transVec(:,iTri)))**2 + rjh=NORM2(xyz(:,nh)-(xyz(:,j)+neigh%transVec(:,iTrj)))**2 ! check if i is the bonded A if(iTri.le.neigh%numctr) then ! nh is not shifted so bpair works without adjustment if(neigh%bpair(i,nh,iTri).eq.1.and.ijnonbond) then @@ -902,16 +900,14 @@ subroutine bond_hbset(n,at,xyz,npbc,bond_hbn,bond_hbl,topo,neigh,hbthr1,hbthr2) do iTri=1,neigh%nTrans do iTrj=1,neigh%nTrans iTrDum=neigh%fTrSum(neigh%iTrNeg(iTri),iTrj) - if(iTrDum.eq.-1.or.iTrDum.gt.neigh%numctr) then - rab=NORM2((xyz(:,i)+neigh%transVec(:,iTri))-(xyz(:,j)+neigh%transVec(:,iTrj)))**2 - if(rab.gt.hbthr1) cycle - ijnonbond=.true. ! i and j are not in neighboring cells for this range of iTrDum - else - ! check ij distance - rab=neigh%distances(j,i,iTrDum)**2 ! %distances are generated up to hbthr2 - if(rab.gt.hbthr1) cycle - ! check if ij bonded + rab=NORM2((xyz(:,i)+neigh%transVec(:,iTri))-(xyz(:,j)+neigh%transVec(:,iTrj)))**2 + if(rab.gt.hbthr1) cycle + ! check if ij bonded + if(iTrDum.le.neigh%numctr.and.iTrDum.gt.0) then ijnonbond=neigh%bpair(j,i,iTrDum).ne.1 + else + ! i and j are not in neighboring cells + ijnonbond=.true. endif ! loop over relevant H atoms do k=1,topo%nathbH @@ -983,7 +979,7 @@ subroutine bond_hbset0(n,at,xyz,npbc,bond_hbn,topo,neigh,hbthr1,hbthr2) ijnonbond=.true. ! i and j are not in neighboring or same cell for iTrDum=-1 else ! check ij distance - rab=neigh%distances(j,i,iTrDum)**2 + rab=NORM2(xyz(:,i)-(xyz(:,j)+neigh%transVec(:,iTrDum)))**2 if(rab.gt.hbthr1) cycle ! check if ij bonded ijnonbond=neigh%bpair(j,i,iTrDum).ne.1 @@ -1295,15 +1291,15 @@ subroutine gfnff_hbset0(n,at,xyz,topo,nhb1,nhb2,nxb,neigh,nlist,hbthr1,hbthr2) if(rab.gt.hbthr1) cycle ijnonbond=.true. ! i and j are not in neighboring or same cell for iTrDum=-1 else - ! check ij distance - rab=neigh%distances(j,i,iTrDum)**2 ! %distances are generated up to hbthr2 + ! check + rab=NORM2(xyz(:,i)-(xyz(:,j)+neigh%transVec(:,iTrDum)))**2 if(rab.gt.hbthr1) cycle ! check if ij bonded if(iTrDum.le.neigh%numctr) then ijnonbond=neigh%bpair(j,i,iTrDum).ne.1 else ! i and j are not in neighboring cells - ijnonbond=.true. + ijnonbond=.true. endif endif ! loop over relevant H atoms @@ -1311,8 +1307,8 @@ subroutine gfnff_hbset0(n,at,xyz,topo,nhb1,nhb2,nxb,neigh,nlist,hbthr1,hbthr2) free=.true. nh =topo%hbatHl(1,k) ! nh always in central cell ! distances for non-cov bonded case - rih=neigh%distances(i,nh,iTri)**2 - rjh=neigh%distances(j,nh,iTrj)**2 + rih=NORM2(xyz(:,nh)-(xyz(:,i)+neigh%transVec(:,iTri)))**2 + rjh=NORM2(xyz(:,nh)-(xyz(:,j)+neigh%transVec(:,iTrj)))**2 ! check if i is the bonded A if(iTri.le.neigh%numctr) then ! nh is not shifted so bpair works without adjustment if(neigh%bpair(i,nh,iTri).eq.1.and.ijnonbond) then @@ -1341,7 +1337,7 @@ subroutine gfnff_hbset0(n,at,xyz,topo,nhb1,nhb2,nxb,neigh,nlist,hbthr1,hbthr2) i =topo%xbatABl(1,ix) j =topo%xbatABl(2,ix) iTrj=topo%xbatABl(4,ix) - rab=neigh%distances(j,i,iTrj)**2 ! %distances are generated up to hbthr2 + rab=NORM2(xyz(:,i)-(xyz(:,j)+neigh%transVec(:,iTrj)))**2 if(rab.gt.hbthr2)cycle nxb=nxb+1 !enddo diff --git a/src/gfnff/neighbor.f90 b/src/gfnff/neighbor.f90 index 81c3aa086..843d80cf0 100644 --- a/src/gfnff/neighbor.f90 +++ b/src/gfnff/neighbor.f90 @@ -9,7 +9,7 @@ module xtb_gfnff_neighbor implicit none private - public :: TNeigh, getDistances + public :: TNeigh !> Neighbor lists type :: TNeigh @@ -24,7 +24,7 @@ module xtb_gfnff_neighbor integer, allocatable :: bpair(:,:,:) integer, allocatable :: molbpair(:) ! distances of all atoms to all atoms in central 27 cells - real(wp), allocatable :: distances(:,:,:) + !real(wp), allocatable :: distances(:,:,:) !> Maximum number of neighbors per atom ! where nb(numnb,i,transVec) is the num of neigh atom i has in cell transVec integer :: numnb = 42 @@ -115,11 +115,21 @@ subroutine get_nb(self, mol, rab, rtmp, mchar, icase, f_in, f2_in, param) !integer, intent(inout) :: nbf(20,mol%n) type(TGFFData), intent(in) :: param !real(wp) :: latThresh, maxNBr - integer :: n - - n = mol%n + real(wp) :: dist(mol%n,mol%n,self%numctr) + integer :: i,j,iTr - call fillnb(self,n,mol%at,rtmp,self%distances,mchar,icase,f_in,f2_in,param) + dist=0.0_wp + !$omp parallel do collapse(3) default(none) shared(dist,mol,self) & + !$omp private(iTr,i,j) + do iTr=1, self%numctr + do i=1, mol%n + do j=1, mol%n + dist(j,i,iTr) = NORM2(mol%xyz(:,i)-(mol%xyz(:,j)+self%transVec(:,iTr))) + enddo + enddo + enddo + !$omp end parallel do + call fillnb(self,mol%n,mol%at,rtmp,dist,mchar,icase,f_in,f2_in,param) end subroutine get_nb @@ -390,26 +400,6 @@ function id2v(self,mol,id) result(vector) end function id2v - subroutine getDistances(distances, mol, neigh) - real(wp), allocatable, intent(out) :: distances(:,:,:) - class(TNeigh), intent(in) :: neigh - type(TMolecule), intent(in) :: mol - integer :: i,j, iTr, n - - n=mol%n - allocate(distances(n,n,neigh%nTrans), source=0.0_wp) - - do iTr=1, neigh%nTrans - do i=1, n - do j=1, n - distances(j,i,iTr) = vecNorm(mol%xyz(:,j)-mol%xyz(:,i)+neigh%transVec(:,iTr)) - enddo - enddo - enddo - - - end subroutine getDistances - ! is a modified "getnb" from gfnff_ini2.f90 subroutine fillnb(self,n,at,rad,dist,mchar,icase,f,f2,param) implicit none @@ -417,8 +407,8 @@ subroutine fillnb(self,n,at,rad,dist,mchar,icase,f,f2,param) class(TNeigh), intent(inout) :: self integer, intent(in) :: n,at(n) real(wp), intent(in) :: rad(n*(n+1)/2) - real(wp), intent(in) :: mchar(n),f,f2 real(wp), intent(in) :: dist(n,n,self%numctr) + real(wp), intent(in) :: mchar(n),f,f2 integer i,j,k,iTr,nn,icase,hc_crit,nnfi,nnfj,lin integer tag(n,n,self%numctr) real(wp) rco,fm @@ -548,8 +538,10 @@ subroutine nbLoc(self, n, nblist, indexi, locarr) ! gives index j of the jth neighbor of i and the corresp transVec index iTr - subroutine jth_nb(self, j, jth, i, iTr) + subroutine jth_nb(self, n, xyz, j, jth, i, iTr) class(TNeigh), intent(inout) :: self + integer, intent(in) :: n + real(wp), intent(in) :: xyz(3,n) integer, intent(inout) :: j, iTr integer, intent(in) :: jth, i integer :: k, l, iTrdum, sizenb, sizeindx, jdum @@ -567,7 +559,7 @@ subroutine jth_nb(self, j, jth, i, iTr) do k=1, self%nb(self%numnb,i,iTrdum) jdum = self%nb(k,i,iTrdum) l=l+1 - distnb(l) = self%distances(jdum,i,iTrdum) + distnb(l) = NORM2(xyz(:,i)-(xyz(:,jdum)+self%transVec(:,iTrDum))) enddo enddo diff --git a/src/iff/iff_prepare.f90 b/src/iff/iff_prepare.f90 index 15632a2f4..813be1b32 100644 --- a/src/iff/iff_prepare.f90 +++ b/src/iff/iff_prepare.f90 @@ -193,7 +193,7 @@ subroutine precomp(env, iff_data, mol, etot, mol_num) !> the SP call singlepoint & & (env, mol, chk, calc, egap, set%etemp, set%maxscciter, 2,& - & exist, lgrad, acc, etot, g, sigma, res) + & .false., lgrad, acc, etot, g, sigma, res) set%pr_lmo = .false. diff --git a/src/main/json.F90 b/src/main/json.F90 index 263006637..2b7a8da8e 100644 --- a/src/main/json.F90 +++ b/src/main/json.F90 @@ -439,13 +439,13 @@ subroutine write_json_gfnff_lists(n, etot, gnorm, topo, neigh, nlist, printTopo) write (iunit, '("]")') write (iunit, '(3x,"],")') end if - if (printTopo%blist) then ! blist(2,nbond) + if (printTopo%blist) then ! blist(3,nbond) write (iunit, '(3x,''"blist":'',"[")') do j = 1, neigh%nbond - 1 - write (iunit, '(3x,"[",*(i8,:,","))', advance='no') topo%blist(:, j) + write (iunit, '(3x,"[",*(i8,:,","))', advance='no') neigh%blist(:, j) write (iunit, '("],")') end do - write (iunit, '(3x,"[",*(i8,:,","),"]",/)', advance='no') topo%blist(:, neigh%nbond) + write (iunit, '(3x,"[",*(i8,:,","),"]",/)', advance='no') neigh%blist(:, neigh%nbond) write (iunit, '("]")') write (iunit, '(3x,"],")') end if diff --git a/src/main/property.F90 b/src/main/property.F90 index b4a42abe3..ab22c3717 100644 --- a/src/main/property.F90 +++ b/src/main/property.F90 @@ -1239,7 +1239,7 @@ subroutine print_thermo(iunit, nat, nvib_in, at, xyz, freq, etot, htot, gtot, ni nvib = 0 nimag = 0 - call axis2(nat, at, xyz, aa, bb, cc, avmom, wt) + call axis2(nat,xyz,aa,bb,cc,avmom,wt) nvib_theo = 3 * nat - 6 if (cc < 1.d-10) linear = .true. diff --git a/src/optimizer.f90 b/src/optimizer.f90 index 6c36d7ca5..e6fdc9a4d 100644 --- a/src/optimizer.f90 +++ b/src/optimizer.f90 @@ -22,9 +22,11 @@ module xtb_optimizer use xtb_type_environment, only : TEnvironment use xtb_extern_turbomole, only : TTMCalculator use xtb_bfgs + use xtb_hessian, only : numhess use xtb_david2 implicit none + !> time profiling logical,private,parameter :: profile = .true. type :: convergence_log @@ -42,6 +44,7 @@ module xtb_optimizer contains +!> construct optimizer settings from optimization level subroutine get_optthr(n,olev,ethr,gthr,maxcycle,acc) use xtb_setparam implicit none @@ -51,66 +54,74 @@ subroutine get_optthr(n,olev,ethr,gthr,maxcycle,acc) real(wp),intent(out) :: gthr integer, intent(out) :: maxcycle real(wp),intent(out) :: acc + select case(olev) -! very approximate = crude + ! very approximate = crude ! case(p_olev_crude) ethr = 5.d-4 gthr = 1.d-2 maxcycle=n acc=3.00d0 -! approximate = sloopy + + ! approximate = sloopy ! case(p_olev_sloppy) ethr = 1.d-4 gthr = 6.d-3 maxcycle=n acc=3.00d0 -! loose + + ! loose ! case(p_olev_loose) ethr = 5.d-5 gthr = 4.d-3 maxcycle=n*2 acc=2.00d0 -! for DCOSMO-RS opts with TM i.e. between loose and normal, keyword "lax" + + ! for DCOSMO-RS opts with TM i.e. between loose and normal ! case(p_olev_lax) ethr = 2.d-5 gthr = 2.5d-3 maxcycle=n*2 acc=2.00d0 -! normal + + ! normal ! case default ethr = 5.d-6 gthr = 1.d-3 maxcycle=n*3 acc=1.0d0 -! tight + + ! tight ! case(p_olev_tight) ethr = 1.d-6 gthr = 8.d-4 maxcycle=n*5 acc=0.20d0 -! very tight + + ! very tight ! case(p_olev_vtight) ethr = 1.d-7 gthr = 2.d-4 maxcycle=n*20 acc=0.05d0 -! extreme + + ! extreme ! case(p_olev_extreme) ethr = 5.d-8 gthr = 5.d-5 maxcycle=n*20 acc=0.01d0 end select + maxcycle=min(maxcycle,10000) maxcycle=max(maxcycle,200) end subroutine get_optthr -!---------------------------------------- -! Approximate Normal Coordinate Optimizer -!---------------------------------------- +!> Approximate Normal Coordinate rational function optimizer subroutine ancopt(env,ilog,mol,chk,calc, & & egap,et,maxiter,maxcycle_in,etot,g,sigma,tight,pr,fail) + use xtb_mctc_convert use xtb_mctc_la @@ -132,67 +143,150 @@ subroutine ancopt(env,ilog,mol,chk,calc, & use xtb_lsrmsd implicit none - + + !> traceback for error handling character(len=*), parameter :: source = "optimizer_ancopt" - !! source of errors in the main program unit + + !> calculation environment type(TEnvironment), intent(inout) :: env - !! calculation environment + + !> molecular structure data type(TMolecule), intent(inout) :: mol - !! molecular structure data + + !> optimization level integer, intent(in) :: tight - !! optimization level + + !> max number of SCC cycles integer, intent(in) :: maxiter - !! max SCC cycles + + !> max number of optimization cycles integer, intent(in) :: maxcycle_in - !! max GEOOPT cycles + + !> wrapper for changing info during SCC type(TRestart),intent(inout) :: chk - !! wrapper for changing info during SCC + + !> polymorphic calculator instance class(TCalculator), intent(inout) :: calc - !! calculator instance + + !> electronic energy real(wp) :: eel - !! electronic energy + + !> total energy real(wp),intent(inout) :: etot - !! total energy + + !> electronic temperature real(wp),intent(in) :: et - !! electronic temperature + + !> HOMO-LUMO gap real(wp),intent(inout) :: egap - !! HOMO-LUMO gap + + !> gradients real(wp),intent(inout) :: g(3,mol%n) - !! gradients + + !> strain derivatives real(wp),intent(inout) :: sigma(3,3) - !! strain derivatives + + !> printlevel logical, intent(in) :: pr - !! if printed + + !> optimization failure logical, intent(out) :: fail - !! if failed + +!-----------------! +! local variables ! +!-----------------! - !> local variables type(TMolecule) :: molopt type(scc_results) :: res type(tb_anc) :: anc type(tb_timer) :: timer - real(wp) :: step,amu2au,au2cm,dumi,dumj,damp,hlow,edum,s6,thr,aaa,bbb - real(wp) :: maxdispl,gthr,ethr,hmax,energy,acc,rij(3),t1,t0,w1,w0,ccc - integer :: n3,i,j,k,l,jjj,ic,jc,ia,ja,ii,jj,info,lwork,nat3,liwork - integer :: nvar,iter,nread,maxcycle,maxmicro,itry,maxopt,iupdat,iii + + !> maximum coordinate displacement + real(wp) :: maxdispl + + !> lowest value for force constant + real(wp) :: hlow + + !> highest value for force constant + real(wp) :: hmax + + !> dispersion scaling + real(wp) :: s6 + + !> total energy from initial single point callculation + real(wp) :: estart + + !> energy & gradient convergence thresholds + real(wp) :: ethr, gthr + + + !> number of modes followed + integer :: modef + + !> max number of opt cycles + integer :: maxopt + + !> max number of opt cycles before generation of new ANC + integer :: maxmicro + + !> algorithm for updating Hessian + integer :: iupdat ! 0 = BFGS, 1 = Powell + + !> current iteration + integer :: iter + + !> number of atomic coordinates + integer :: nat3 + + !> deegrees of freedom + integer :: nvar + + !> work array size + integer :: lwork, liwork + + !> step size for numerical Hessian + real(wp) :: step_hess + + real(wp) :: step,amu2au,au2cm,dumi,dumj,damp,edum,thr,aaa,bbb + real(wp) :: energy,acc,rij(3),t1,t0,w1,w0,ccc + + integer :: n3,i,j,k,l,jjj,ic,jc,ia,ja,ii,jj,info + integer :: nread,itry,iii integer :: id,ihess,error integer, intent(in) :: ilog integer, external :: lin - real(wp),allocatable :: h (:,:) + + !> Hessian matrix + real(wp),allocatable :: h (:,:), hess_tmp(:,:) + real(wp),allocatable :: b (:,:) + real(wp),allocatable :: pmode(:,:) + real(wp),allocatable :: grmsd(:,:) + + !> force constants real(wp),allocatable :: fc(:) + + !> eigenvalues real(wp),allocatable :: eig(:) + real(wp),allocatable :: aux(:) real(wp),allocatable :: hess(:) integer, allocatable :: iwork(:) integer, allocatable :: totsym(:) - real(wp),allocatable :: pmode(:,:) - real(wp),allocatable :: grmsd(:,:) type(convergence_log), allocatable :: avconv + real(wp) :: U(3,3), x_center(3), y_center(3), rmsdval - integer :: modef - logical :: restart,ex,converged,linear - real(wp) :: estart,esave + real(wp) :: esave + logical :: restart,ex,converged + + !> if linear molecule + logical :: linear + + !> dipole + real(wp),allocatable :: dipgrad(:,:) + integer, allocatable :: list(:) + + !> formatting strings for output character(len=*),parameter :: scifmt = & '(10x,":",3x,a,e22.7,1x,a,1x,":")' character(len=*),parameter :: dblfmt = & @@ -201,43 +295,51 @@ subroutine ancopt(env,ilog,mol,chk,calc, & '(10x,":",3x,a,i18, 10x,":")' character(len=*),parameter :: chrfmt = & '(10x,":",3x,a,a18, 10x,":")' + + !> error string + character(len=128) :: errStr - ! Print ANCopt header ! + !> debug mode + logical, parameter :: debug(2) = [.false.,.false.] + character(len=9):: hessfmt + + ! print ANCopt header ! call ancopt_header(env%unit,set%veryverbose) - if(mol%n.eq.1) return - !! do not optimize for 1 molecule + if(mol%n.eq.1) return ! skip optimization for 1 atom + + ! performance profiling timer ! if (profile) call timer%new(8,.false.) if (profile) call timer%measure(1,'optimizer setup') - -! defaults - fail =.false. - modef=0 - hmax = 5.0_wp - maxdispl=set%optset%maxdispl_opt - hlow = set%optset%hlow_opt!0.01 in ancopt, 0.002 too small - s6 = set%mhset%s6 !slightly better than 30 for various proteins -! initial number of steps before new ANC are made by model Hessian -! increased during opt. - maxmicro=set%optset%micro_opt + + ! defaults ! + iter = 0 + fail = .false. + modef = 0 + iupdat= 0 + hmax = 5.0_wp + nat3 = 3 * mol%n + maxdispl = set%optset%maxdispl_opt ! def: 1.0 + hlow = set%optset%hlow_opt ! def: 0.01 + s6 = set%mhset%s6 ! def: 20.0 + maxmicro=set%optset%micro_opt ! def: 20 estart = etot - - iupdat=0 !0=BFGS, 1=Powell - + call get_optthr(mol%n,tight,ethr,gthr,maxopt,acc) + + ! if provided by user ! + if(maxcycle_in.gt.0)then + maxopt=maxcycle_in + endif + if(maxopt.lt.maxmicro) maxmicro=maxopt + + ! use Powell update if TS optimization ! if(set%tsopt)then hlow=max(hlow,0.250d0) iupdat=1 endif - - call get_optthr(mol%n,tight,ethr,gthr,maxcycle,acc) - - if(maxcycle_in.le.0)then - maxopt=maxcycle - else - maxopt=maxcycle_in - endif - if(maxopt.lt.maxmicro) maxmicro=maxopt - if (set%optset%average_conv) then + + ! energy and gradient averaging ! + if (set%optset%average_conv) then ! default: .false. select type(calc) class is(TTMCalculator) avconv = load_turbomole_log(maxopt) @@ -250,22 +352,23 @@ subroutine ancopt(env,ilog,mol,chk,calc, & end select end if - call axis2(mol%n,mol%at,mol%xyz,aaa,bbb,ccc,dumi,dumj) - - !call open_file(ilog,'xtbopt.log','w') - iter = 0 - nat3 = 3 * mol%n - nvar = nat3 - 6 - linear = .false. - if(ccc.lt.1.d-10) then + ! determine if linear molecule via rotational constants ! + call axis2(mol%n,mol%xyz,aaa,bbb,ccc,dumi,dumj) + if (ccc.lt.1.d-10) then linear = .true. nvar = nat3 - 5 + else + linear = .false. + nvar = nat3 - 6 endif - if(fixset%n.gt.0) then ! exact fixing - nvar=nat3-3*fixset%n-3 + + ! exact fixing case ! + if(fixset%n.gt.0) then + nvar = nat3 - 3*fixset%n - 3 if(nvar.le.0) nvar=1 endif + ! adjust if restrated ! call open_binary(id,'.xtbtmpmode','r') if(id.ne.-1)then read (id) modef @@ -277,43 +380,52 @@ subroutine ancopt(env,ilog,mol,chk,calc, & allocate(pmode(nat3,1)) ! dummy allocated endif + ! print ANCopt settings ! if(pr)then write(env%unit,'(/,10x,51("."))') write(env%unit,'(10x,":",22x,a,22x,":")') "SETUP" write(env%unit,'(10x,":",49("."),":")') - write(env%unit,chrfmt) "optimization level",int2optlevel(tight) - write(env%unit,intfmt) "max. optcycles ",maxopt - write(env%unit,intfmt) "ANC micro-cycles ",maxmicro - write(env%unit,intfmt) "degrees of freedom",nvar + write(env%unit,chrfmt) "optimization level", int2optlevel(tight) + write(env%unit,intfmt) "max. optcycles ", maxopt + write(env%unit,intfmt) "ANC micro-cycles ", maxmicro + write(env%unit,intfmt) "degrees of freedom", nvar + if (modef>0) then - write(env%unit,intfmt) "# mode follow ",modef + write(env%unit,intfmt) "# mode follow ", modef endif + write(env%unit,'(10x,":",49("."),":")') + if (set%optset%exact_rf) then - write(env%unit,chrfmt) "RF solver ","spevx" + write(env%unit,chrfmt) "RF solver ", "spevx" else - write(env%unit,chrfmt) "RF solver ","davidson" + write(env%unit,chrfmt) "RF solver ", "davidson" endif - write(env%unit,chrfmt) "write xtbopt.log ",bool2string(ilog.ne.-1) + + write(env%unit,chrfmt) "write xtbopt.log ", bool2string(ilog.ne.-1) + if (linear) then - write(env%unit,chrfmt) "linear (good luck)",bool2string(linear) + write(env%unit,chrfmt) "linear (good luck)", bool2string(linear) else - write(env%unit,chrfmt) "linear? ",bool2string(linear) + write(env%unit,chrfmt) "linear? ", bool2string(linear) endif - write(env%unit,scifmt) "energy convergence",ethr, "Eh " - write(env%unit,scifmt) "grad. convergence ",gthr, "Eh/α" - write(env%unit,dblfmt) "maxmium RF displ. ",maxdispl," " - write(env%unit,scifmt) "Hlow (freq-cutoff)",hlow, " " - write(env%unit,dblfmt) "Hmax (freq-cutoff)",hmax, " " - write(env%unit,dblfmt) "S6 in model hess. ",s6, " " + + write(env%unit,scifmt) "energy convergence", ethr, "Eh " + write(env%unit,scifmt) "grad. convergence ", gthr, "Eh/α" + write(env%unit,dblfmt) "maxmium RF displ. ", maxdispl," " + write(env%unit,scifmt) "Hlow (freq-cutoff)", hlow, " " + write(env%unit,dblfmt) "Hmax (freq-cutoff)", hmax, " " + write(env%unit,dblfmt) "S6 in model hess. ", s6, " " write(env%unit,'(10x,51("."))') endif + ! work arrays ! lwork = 1 + 6*nat3 + 2*nat3**2 liwork = 8 * nat3 allocate(h(nat3,nat3),fc(nat3*(nat3+1)/2),eig(nat3)) + ! read in Hessian from file ! if (set%mhset%model == p_modh_read) then call open_file(ihess, 'hessian', 'r') if (ihess == -1) then @@ -332,39 +444,71 @@ subroutine ancopt(env,ilog,mol,chk,calc, & ex = .false. endif - call anc%allocate(mol%n,nvar,hlow,hmax) - - molopt = mol - - if (profile) call timer%measure(1) + call anc%allocate(mol%n,nvar,hlow,hmax) ! allocate ANC + molopt = mol ! copy molecular information + if (profile) call timer%measure(1) ! start opt timer ! ====================================================================== ANC_microiter: do ! ====================================================================== - if (profile) call timer%measure(2,'model hessian') +!----------------------------------------------------------------! +!--------------------- Hessian generation -----------------------! +!----------------------------------------------------------------! + + if (profile) call timer%measure(2,'model hessian') ! start timer for Hessian + + ! initial guess for Hessian ! if (.not.ex)then ! normal case - if(pr)write(env%unit,'(/,''generating ANC from model Hessian ...'')') - call modhes(env, calc, set%mhset, molopt%n, molopt%xyz, molopt%at, fc, pr) ! WBO (array wb) not used in present version - call env%check(fail) - if (fail) then - call env%error("Calculation of model hessian failed", source) - return - end if - !call qpothess(molopt%n,fc,molopt%xyz) - thr=1.d-11 - else - if(pr)write(env%unit,'(/,''generating ANC from read Hessian ...'')') - k=0 - do i=1,nat3 - do j=1,i - k=k+1 - fc(k)=h(j,i) - enddo - enddo - thr=1.d-10 + + if (pr) & + & write(env%unit,'(/,''generating ANC from exact Hessian ...'')') + + call modhes(env, calc, set%mhset, molopt%n, molopt%xyz, molopt%at, fc, pr) ! def: Lindh model (1995) + call env%check(fail) + if (fail) then + call env%error("Calculation of model hessian failed", source) + return + end if + + ! blow up Hessian ! + k=0 + do i=1,nat3 + do j=1,i + k=k+1 + h(i,j)=fc(k) + h(j,i)=fc(k) + enddo + enddo + + thr=1.d-11 + + ! read in Hessian from file ! + else + + if(pr) & + & write(env%unit,'(/,''generating ANC from read Hessian ...'')') + + ! pack Hessian ! + k=0 + do i=1,nat3 + do j=1,i + k=k+1 + fc(k)=h(j,i) + enddo + enddo + + thr=1.d-10 + + endif + + if (debug(2) .and. nat3 <= 30) then !######## DEBUG ######## + write(env%unit,'(/,''Hessian matrix'')') + write(hessfmt,'(a,i0,a)') '(', nat3, 'F10.6)' + write(env%unit,hessfmt) (h(:,i), i=1,nat3) endif + ! project out translational and rotational modes ! if(modef.eq.0)then if(fixset%n.gt.0)then call trproj(molopt%n,nat3,molopt%xyz,fc,.false., -1 ,pmode,1) ! exact fixing @@ -375,42 +519,41 @@ subroutine ancopt(env,ilog,mol,chk,calc, & else call trproj(molopt%n,nat3,molopt%xyz,fc,.false.,modef,pmode,modef) ! NMF endif - if (profile) call timer%measure(2) - - if (profile) call timer%measure(3,'ANC generation') - ! this is completely useless, we blow up the Hessian, just to pack it again... - k=0 - do i=1,nat3 - do j=1,i - k=k+1 - h(i,j)=fc(k) - h(j,i)=fc(k) - enddo - enddo + + if (profile) call timer%measure(2) ! stop timer for model Hessian -! initialize hessian for opt. - call anc%new(env%unit,molopt%xyz,h,pr,linear) +!----------------------------------------------------------------! +!---------------------- ANC generation --------------------------! +!----------------------------------------------------------------! - if (profile) call timer%measure(3) + if (profile) call timer%measure(3,'ANC generation') ! start timer for ANC generation - esave = etot + ! diagonalize Hessian and sort eigenvalues ! + call anc%new(env%unit,molopt%xyz,h,pr,linear) + if (profile) call timer%measure(3) ! stop timer for ANC generation + esave = etot ! save energy -! now everything is prepared for the optimization +!----------------------------------------------------------------! +!---------------------- Optimization ----------------------------! +!----------------------------------------------------------------! call relax(env,iter,molopt,anc,restart,maxmicro,maxdispl,ethr,gthr, & & iii,chk,calc,egap,acc,et,maxiter,iupdat,etot,g,sigma,ilog,pr,fail, & & converged,timer,set%optset%exact_rf,avconv) + ! check for errors ! call env%check(fail) if (fail) then - call env%error("Could not relax structure", source) + call env%error("Could not relax/optimize structure", source) return endif + ! dynamically adjust number of micro iterations ! maxmicro=min(int(maxmicro*1.1),2*set%optset%micro_opt) + ! assess the optimization by RMSD change ! call rmsd(molopt%n,anc%xyz,molopt%xyz,1,U,x_center,y_center,rmsdval,.false.,grmsd) - ! this comes close to a goto, but it's not a goto ... it's even worse + ! this comes close to a goto, but it's not a goto ... it's even worse ! if (restart.and.iter.lt.maxopt) then if (pr) then write(env%unit,'(" * RMSD in coord.:",f14.7,1x,"α")',advance='no') rmsdval @@ -423,6 +566,7 @@ subroutine ancopt(env,ilog,mol,chk,calc, & enddo ANC_microiter ! ====================================================================== + ! convergence report ! if (converged) then if(pr) then call rmsd(mol%n,mol%xyz,molopt%xyz,1,U,x_center,y_center,rmsdval,.false.,grmsd) @@ -440,20 +584,19 @@ subroutine ancopt(env,ilog,mol,chk,calc, & write(env%unit,'(72("-"))') endif else -! not converging in the given cycles is a FAILURE, we should make this clearer -! This is still no ERROR, since we want the geometry written afterwards + ! not converging in the given cycles is a FAILURE, we should make this clearer ! + ! This is still no ERROR, since we want the geometry written afterwards ! if(pr) then write(env%unit,'(/,3x,"***",1x,a,1x,i0,1x,a,1x,"***",/)') & "FAILED TO CONVERGE GEOMETRY OPTIMIZATION IN",iter,"ITERATIONS" endif endif - mol = molopt + mol = molopt ! copy optimized geometry back to molecule - !call close_file(ilog) - - if (pr.and.profile) call timer%write(env%unit,'ANCopt') + if (pr.and.profile) call timer%write(env%unit,'ANCopt') ! write timer report + ! cleanup ! if (profile) call timer%deallocate if (allocated(pmode)) deallocate(pmode) if (allocated(h)) deallocate(h) @@ -485,36 +628,75 @@ subroutine relax(env,iter,mol,anc,restart,maxcycle,maxdispl,ethr,gthr, & implicit none - !> Source of errors in the main program unit + !> source of errors in the main program unit character(len=*), parameter :: source = "optimizer_relax" - !> Calculation environment + !> calculation environment type(TEnvironment), intent(inout) :: env + !> molecular structure data type(TMolecule), intent(inout) :: mol + + !> timer instance type(tb_timer), intent(inout) :: timer + + !> ANC instance type(tb_anc), intent(inout) :: anc + + !> WFN type(TRestart),intent(inout) :: chk + + !> polymorphic calculator instance class(TCalculator), intent(inout) :: calc + + !> number of micro iterations integer, intent(in) :: maxiter + + !> Hessian update algorithm integer, intent(in) :: iupdat + + !> iunit for log file integer, intent(in) :: ilog + + !> temperature real(wp),intent(in) :: et + + !> total energy real(wp),intent(inout) :: etot + + !> SCC accuracy real(wp),intent(in) :: acc_in + + !> gradients real(wp),intent(inout) :: g(3,mol%n) + + !> strain derivatives real(wp),intent(inout) :: sigma(3,3) + + !> HOMO-LUMO gap real(wp),intent(inout) :: egap + + !> conv check logical, intent(out) :: converged + + !> solver type logical, intent(in) :: exact + + !> averaging type(convergence_log), intent(inout), optional :: avconv + !> SCC results storage type(scc_results) :: res + + !> dimensions for RFO integer :: nvar1,npvar,npvar1 + + !> local booleans to control optimization logical :: restart, first, pr, fail logical :: econverged logical :: gconverged logical :: lowered + integer :: maxcycle, iter, prlevel integer :: i, j, ii, jj, k, lwork, info, m, idum, imax(3) real(wp) :: energy,ethr,gthr,dsnrm,maxdispl,t0,w0,t1,w1 @@ -522,56 +704,81 @@ subroutine relax(env,iter,mol,anc,restart,maxcycle,maxdispl,ethr,gthr, & real(wp) :: depred,echng,dummy,maxd,alp,gchng,smallreal,gnold real(wp),allocatable :: gold(:) real(wp),allocatable :: displ(:), gint(:) + + !> RFO eigenvalues real(sp),allocatable :: eaug(:) + + !> RFO eigenvectors real(sp),allocatable :: Uaug(:,:) + + !> Augmented Hessian real(sp),allocatable :: Aaug(:) + real(sp) :: r4dum,sdot parameter (r4dum=1.e-8) parameter (smallreal=1.d-14) - allocate( gold(anc%nvar), displ(anc%nvar), gint(anc%nvar), source = 0.0_wp ) +!----------------------------------------------------------------! +!--------------------- Initialization ---------------------------! +!----------------------------------------------------------------! + - prlevel=0 - if(pr)prlevel=1 - gnorm =0.0_wp - depred =0.0_wp - echng =0.0_wp - maxd =maxdispl - first =.true. - acc =acc_in + ! set printlevel ! + if (pr) then + prlevel = 1 + else + prlevel=0 + endif + + ! initialize variables ! + gnorm = 0.0_wp + depred = 0.0_wp + echng = 0.0_wp + alp = 1.0_wp + maxd = maxdispl + acc = acc_in energy = etot e_in = etot - alp =1.0_wp + first = .true. converged = .false. nvar1 = anc%nvar+1 ! dimension of RF calculation npvar = anc%nvar*(nvar1)/2 ! packed size of Hessian (note the abuse of nvar1!) npvar1 = nvar1*(nvar1+1)/2 ! packed size of augmented Hessian - allocate(Uaug(nvar1,1),eaug(nvar1),Aaug(npvar1)) + + allocate( gold(anc%nvar), displ(anc%nvar), gint(anc%nvar), source = 0.0_wp ) + allocate( Uaug(nvar1,1),eaug(nvar1),Aaug(npvar1) ) !! ======================================================================== main_loop: do ii=1,maxcycle !! ======================================================================== - iter=iter+1 + + iter=iter+1 ! iteration counter if(pr) & - write(env%unit,'(/,72("."),/,30(".")," CYCLE",i5,1x,30("."),/,72("."))')iter + write(env%unit,'(/,72("."),/,30(".")," CYCLE",i5,1x,30("."),/,72("."))')iter + ! save values from previous iteration ! gold = gint gnold= gnorm eold = energy -! calc predicted energy change based on E = E0 + delta * G + delta^2 * H + + ! dE via 2-nd order Taylor expansion ! + ! E = E0 + delta * G + delta^2 * H ! if (ii > 1) & - call prdechng(anc%nvar,gold,displ,anc%hess,depred) -! get gradient + call prdechng(anc%nvar,gold,displ,anc%hess,depred) + + ! displace cartesian coordinates ! if (profile) call timer%measure(4,'coordinate transformation') call anc%get_cartesian(mol%xyz) if (profile) call timer%measure(4) + + ! single point + analytical gradients ! if (profile) call timer%measure(5,'single point calculation') g = 0.0_wp call calc%singlepoint(env,mol,chk,prlevel,iter.eq.1,energy,g,sigma,egap,res) if (profile) call timer%measure(5) - - ! something went wrong in SCC or diag + + ! something went wrong in SCC or diag ! call env%check(fail) if (fail) then call env%error('SCF not converged, aborting...', source) @@ -582,24 +789,28 @@ subroutine relax(env,iter,mol,anc,restart,maxcycle,maxdispl,ethr,gthr, & fail=.true. return endif - if (profile) call timer%measure(6,'optimization log') + ! write geometry to log file ! + if (profile) call timer%measure(6,'optimization log') call writeMolecule(mol, ilog, format=fileType%xyz, energy=res%e_total, & & gnorm=res%gnorm) - !! to write log file if (profile) call timer%measure(6) -! transform xyz to internal gradient + + + ! transform xyz (g) to internal gradient (gint) ! if (profile) call timer%measure(4) call dgemv('t',anc%n3,anc%nvar,1.0_wp,anc%B,anc%n3,g,1,0.0_wp,gint,1) if (profile) call timer%measure(4) - gnorm = norm2(gint) - if(gnorm.gt.500.) then + ! check Euclidean norm of the normal gradient ! + gnorm = norm2(gint) + if(gnorm.gt.500.) then call env%error('|grad| > 500, something is totally wrong!', source) fail=.true. return endif + ! average energy and gradient ! if (present(avconv)) then call avconv%set_eg_log(energy, gnorm) energy = avconv%get_averaged_energy() @@ -612,7 +823,7 @@ subroutine relax(env,iter,mol,anc,restart,maxcycle,maxdispl,ethr,gthr, & end if end if -! adapt SCC acuracy + ! adjust SCC accuracy dynamically ! if(gnorm .lt.0.004)then acc=acc_in elseif(gnorm.lt.0.02)then @@ -621,33 +832,36 @@ subroutine relax(env,iter,mol,anc,restart,maxcycle,maxdispl,ethr,gthr, & acc=6.0d0*acc_in endif - first =.false. + first =.false. ! distinguish between first and subsequent iterations + ! calculate the change in energy and gradient norm ! gchng = gnorm -gnold echng = energy-eold - ! check for convergence + ! check for convergence ! econverged = abs(echng).lt.ethr gconverged = gnorm.lt.gthr lowered = echng.lt.0.0_wp + ! print energy and gradient norm of a current cycle ! if(pr) then - !write(env%unit,'(" E :",F16.8,2x,"G :",F10.6,4x,"pred/act E change:",2D11.3)')& - !energy,gnorm,depred,echng write(env%unit,'(" * total energy :",f14.7,1x,"Eh")',advance='no') energy write(env%unit,'(5x,"change ",e18.7,1x,"Eh")') echng write(env%unit,'(3x,"gradient norm :",f14.7,1x,"Eh/α")',advance='no') gnorm write(env%unit,'(3x,"predicted",e18.7)',advance='no') depred write(env%unit,'(1x,"("f7.2"%)")') (depred-echng)/echng*100 endif + + ! check 0 energy case ! if ( energy .eq. 0 ) then call env%error('external program error', source) return end if - if(ii.eq.1) estart=energy + if(ii.eq.1) estart=energy ! save energy of first iteration - if(gnorm.lt.0.002)then ! 0.002 + ! adjust step size dynamically ! + if(gnorm.lt.0.002)then alp = 1.5d0 ! 1.5 elseif(gnorm.lt.0.0006)then alp = 2.0d0 ! 2 @@ -663,11 +877,10 @@ subroutine relax(env,iter,mol,anc,restart,maxcycle,maxdispl,ethr,gthr, & if (profile) call timer%measure(7,'hessian update') if(ii.gt.1)then -! hessian update if(iupdat.eq.0)then - call bfgs (anc%nvar,gnorm,gint,gold,displ,anc%hess) + call bfgs (anc%nvar,gnorm,gint,gold,displ,anc%hess) else - call powell(anc%nvar,gnorm,gint,gold,displ,anc%hess) + call powell(anc%nvar,gnorm,gint,gold,displ,anc%hess) endif endif if (profile) call timer%measure(7) @@ -682,14 +895,15 @@ subroutine relax(env,iter,mol,anc,restart,maxcycle,maxdispl,ethr,gthr, & ! ⎛ H g ⎞ ⎛ dx ⎞ ⎛ dx ⎞ ! ⎝ g 0 ⎠ ⎝ 1 ⎠ = λ ⎝ 1 ⎠ ! first augment hessian by gradient, we keep everything nicely packed, no blowup - Aaug(1:npvar) = anc%hess - Aaug(npvar+1:npvar1-1) = gint - Aaug(npvar1) = 0.0_sp -! chose your favourite solver + Aaug(1:npvar) = anc%hess ! pack hessian + Aaug(npvar+1:npvar1-1) = gint ! augment with gradient + Aaug(npvar1) = 0.0_sp ! add zero + + ! chose your favourite solver ! if (exact .or. nvar1.lt.50) then call solver_sspevx(nvar1,r4dum,Aaug,Uaug,eaug,fail) else - ! steepest decent guess for displacement + ! steepest decent guess for displacement ! if (ii.eq.1) then Uaug(:,1)=[-real(gint(1:anc%nvar),sp),1.0_sp] dsnrm = sqrt(sdot(nvar1,Uaug,1,Uaug,1)) @@ -699,65 +913,74 @@ subroutine relax(env,iter,mol,anc,restart,maxcycle,maxdispl,ethr,gthr, & if (fail) & ! retry with better solver call solver_sspevx(nvar1,r4dum,Aaug,Uaug,eaug,fail) endif -! divide by last element to get the displacement vector + + ! error handling after RF calculation ! if (fail .or. abs(Uaug(nvar1,1)).lt.1.e-10) then call env%error("internal rational function error", source) return end if + + ! divide by last element to get the displacement vector ! displ(1:anc%nvar) = Uaug(1:anc%nvar,1)/Uaug(nvar1,1) -! check if step is too large, just cut off everything thats to large + + ! check if step is too large, cut off everything that is too large ! do j=1,anc%nvar if(abs(displ(j)).gt.maxd) then if(displ(j) < 0) displ(j)=-maxd if(displ(j) > 0) displ(j)= maxd endif enddo -! now some output - dsnrm=sqrt(ddot(anc%nvar,displ,1,displ,1)) + + ! now some output ! + dsnrm=sqrt(ddot(anc%nvar,displ,1,displ,1)) ! displacement norm if(pr)then - ! this array is currently not used and will be overwritten in next step + + ! find the largest displacement ! gold = abs(displ) imax(1) = maxloc(gold,1); gold(imax(1)) = 0.0_wp imax(2) = maxloc(gold,1); gold(imax(2)) = 0.0_wp imax(3) = maxloc(gold,1) + write(env%unit,'(3x,"displ. norm :",f14.7,1x,"α")',advance='no') & dsnrm*alp - write(env%unit,'(6x,"lambda ",e18.7)') eaug(1) + write(env%unit,'(6x,"lambda ",e18.7)') eaug(1) ! eigenvalue of the RF write(env%unit,'(3x,"maximum displ.:",f14.7,1x,"α")',advance='no') & abs(displ(imax(1)))*alp write(env%unit,'(6x,"in ANC''s ",3("#",i0,", "),"...")') imax - !call prdispl(anc%nvar,displ) endif + if (profile) call timer%measure(8) -! ------------------------------------------------------------------------ -! 2nd: exit and redo hessian (internal restart) + ! 2nd: exit and redo hessian (internal restart) ! if(ii.gt.2.and.dsnrm.gt.2.0) then if (pr) write(*,*) 'exit because of too large step' exit main_loop endif -! new coordinates + ! new coordinates ! anc%coord = anc%coord + displ * alp -! conv ? + ! conv check ! if(abs(echng).lt.ethr.and.gnorm.lt.gthr.and.echng.lt.1.0e-10_wp) then restart=.false. converged = .true. etot=energy return endif - !! ======================================================================== enddo main_loop !! ======================================================================== - if (allocated(Uaug)) deallocate(Uaug) - if (allocated(eaug)) deallocate(eaug) - if (allocated(Aaug)) deallocate(Aaug) + + ! cleanup ! + if (allocated(Uaug)) deallocate(Uaug) + if (allocated(eaug)) deallocate(eaug) + if (allocated(Aaug)) deallocate(Aaug) + ! post micro cycle processing ! restart=.true. etot=energy call anc%get_cartesian(mol%xyz) + end subroutine relax pure subroutine solver_ssyevx(n,thr,A,U,e,fail) @@ -872,6 +1095,7 @@ subroutine sort(nat3,nvar,hess,b) end subroutine sort +!> calculate predicted energy change subroutine prdechng(nat3,grad,displ,hess,depred) !--------------------------------------------------------------------- ! Purpose: @@ -908,11 +1132,11 @@ subroutine prdechng(nat3,grad,displ,hess,depred) !--------------------------------------------------------------------- allocate( hdx(nat3), source = 0.0_wp ) - call blas_spmv('u',nat3,0.5d0,hess,displ,1,0.0d0,hdx,1) + call blas_spmv('u',nat3,0.5d0,hess,displ,1,0.0d0,hdx,1) ! hdx = 0.5*H*displ - gtmp = ddot(nat3,displ,1,grad,1) + gtmp = ddot(nat3,displ,1,grad,1) ! gtmp = grad*displ - htmp = ddot(nat3,displ,1,hdx,1) + htmp = ddot(nat3,displ,1,hdx,1) ! htmp = hdx*displ depred = htmp + gtmp @@ -991,6 +1215,7 @@ subroutine prdispl(nvar,displ) end subroutine prdispl +!> generate model Hessian subroutine modhes(env, calc, modh, natoms, xyz, chg, Hess, pr) use xtb_type_setvar use xtb_modelhessian @@ -1016,21 +1241,22 @@ subroutine modhes(env, calc, modh, natoms, xyz, chg, Hess, pr) type(modhess_setvar),intent(in) :: modh logical, intent(in) :: pr -! Other variables + !> other variables integer :: i integer :: nhess integer, intent(in) :: natoms real(wp),intent(in) :: xyz(3,natoms) - real(wp),intent(out) :: hess((natoms*3)*((natoms*3)+1)/2) + + !> model hessian + real(wp),intent(out) :: Hess((natoms*3)*((natoms*3)+1)/2) integer, intent(in) :: chg(natoms) -! initialize - nhess=3*natoms - Hess=0.d0 + ! initialize ! + Hess=0.0_wp select type(calc) - class default - select case(modh%model) + class default ! all calculator cases except GFN-FF + select case(modh%model) case default call env%error("internal error in model hessian!", source) return @@ -1047,7 +1273,7 @@ subroutine modhes(env, calc, modh, natoms, xyz, chg, Hess, pr) if (pr) write(env%unit,'(a)') "Using Swart-Hessian" call mh_swart(xyz, natoms, Hess, chg, modh) end select - type is(TGFFCalculator) + type is(TGFFCalculator) ! GFN-FF case select case(modh%model) case default call env%error("internal error in model hessian!", source) diff --git a/src/prog/dock.f90 b/src/prog/dock.f90 index a82c3dbc8..f68976267 100644 --- a/src/prog/dock.f90 +++ b/src/prog/dock.f90 @@ -45,7 +45,7 @@ module xtb_prog_dock use xtb_iff_iffprepare, only: precomp use xtb_iff_iffenergy, only : iff_e use xtb_docking_search_nci, only: docking_search - use xtb_sphereparam, only: sphere, rabc, boxr, init_walls, wpot, maxwalls + use xtb_sphereparam, only: init_walls, maxwalls use xtb_constrain_param, only: read_userdata use xtb_fixparam, only: init_fix use xtb_scanparam, only: init_constr, init_scan, maxconstr, maxscan @@ -232,7 +232,6 @@ subroutine xtbDock(env, argParser) & iff_data%qcm2, iff_data%n, iff_data%at, iff_data%xyz, iff_data%q, icoord, icoord0,& & .false.) - !> CONSTRAINTS & SCANS call init_fix(iff_data%n) call init_split(iff_data%n) diff --git a/src/prog/main.F90 b/src/prog/main.F90 index 96465feb3..746278bea 100644 --- a/src/prog/main.F90 +++ b/src/prog/main.F90 @@ -93,7 +93,8 @@ module xtb_prog_main use xtb_iff_data, only: TIFFData use xtb_oniom, only: oniom_input, TOniomCalculator, calculateCharge use xtb_vertical, only: vfukui - use xtb_tblite_calculator, only: TTBLiteCalculator, TTBLiteInput, newTBLiteWavefunction + use xtb_tblite_calculator, only: TTBLiteCalculator, TTBLiteInput, & + & newTBLiteWavefunction, get_ceh use xtb_ptb_calculator, only: TPTBCalculator use xtb_solv_cpx, only: TCpcmx use xtb_dipro, only: get_jab, jab_input @@ -165,7 +166,6 @@ subroutine xtbMain(env, argParser) real(wp), allocatable :: q(:) real(wp), allocatable :: ql(:) real(wp), allocatable :: qr(:) - !! ------------------------------------------------------------------------ integer, external :: ncore @@ -224,6 +224,14 @@ subroutine xtbMain(env, argParser) call parseArguments(env, argParser, xcontrol, fnv, lgrad, & & restart, gsolvstate, strict, copycontrol, coffee, printTopo, oniom, dipro, tblite) + + ! TEMPORARY: no solvation available for PTB and tblite ! + if (set%mode_extrun == p_ext_tblite .or. set%mode_extrun == p_ext_ptb) then + if (allocated(set%solvInput%solvent)) then + call env%error("Solvation is not implemented for PTB/tblite", source) + endif + end if + !> Spin-polarization is only available in the tblite library if (set%mode_extrun /= p_ext_tblite .and. tblite%spin_polarized) then call env%error("Spin-polarization is only available with the tblite library! Try --tblite", source) @@ -275,8 +283,11 @@ subroutine xtbMain(env, argParser) & (set%runtyp == p_run_omd) .or. (set%runtyp == p_run_screen) .or. & & (set%runtyp == p_run_metaopt)) - if (allocated(set%solvInput%cpxsolvent) .and. anyopt) call env%terminate("CPCM-X not implemented for geometry optimization. & - &Please use another solvation model for optimization instead.") + if (allocated(set%solvInput%cpxsolvent).and.anyopt) then + call env%terminate("CPCM-X not implemented for geometry optimization. & + & Please use another solvation model for optimization instead.") + endif + if ((set%mode_extrun == p_ext_ptb) .and. anyopt) call env%terminate("PTB not implemented for geometry optimization. & &Please use another method for optimization instead.") @@ -617,6 +628,10 @@ subroutine xtbMain(env, argParser) call newTBLiteWavefunction(env, mol, calc, chk) end select + ! get CEH charges ! + if (tblite%ceh) & + call get_ceh(env,mol,tblite) + ! ------------------------------------------------------------------------ !> printout a header for the exttyp call calc%writeInfo(env%unit, mol) @@ -1453,6 +1468,15 @@ subroutine parseArguments(env, args, inputFile, paramFile, lgrad, & else call env%error("Molecular charge is not provided", source) end if + + case('--ceh') + if (get_xtb_feature('tblite')) then + tblite%ceh = .true. + else + call env%error("CEH charges are only available through tblite library", source) + return + end if + case ('-u', '--uhf') call args%nextArg(sec) @@ -1896,6 +1920,10 @@ subroutine parseArguments(env, args, inputFile, paramFile, lgrad, & else call env%error("The wrtopo keyword is missing an argument.", source) end if + + case ('--nocellopt') + set%optcell = .false. + end select call args%nextFlag(flag) end do diff --git a/src/ptb/calculator.F90 b/src/ptb/calculator.F90 index c6538ebcb..1c3bd9a0e 100644 --- a/src/ptb/calculator.F90 +++ b/src/ptb/calculator.F90 @@ -36,6 +36,8 @@ module xtb_ptb_calculator use mctc_io_convert, only: autoev #if WITH_TBLITE + use xtb_tblite_mapping, only : convert_tblite_to_wfn, convert_tblite_to_results + use multicharge_model, only: new_mchrg_model, mchrg_model_type use tblite_basis_type, only: basis_type @@ -290,29 +292,8 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, & return end if end if - - call chk%wfn%allocate(mol%n, self%bas%nsh, self%bas%nao) - chk%wfn%n = mctcmol%nat - chk%wfn%nel = nint(chk%tblite%nocc) - chk%wfn%nopen = mctcmol%uhf - chk%wfn%nshell = self%bas%nsh - chk%wfn%nao = self%bas%nao - chk%wfn%P = chk%tblite%density(:, :, 1) - chk%wfn%q = chk%tblite%qat(:, 1) - chk%wfn%qsh = chk%tblite%qsh(:, 1) - chk%wfn%focca = chk%tblite%focc(:, 1) - chk%wfn%foccb = 0.0_wp - chk%wfn%focc(:) = chk%tblite%focc(:, 1) - chk%wfn%emo = chk%tblite%emo(:, 1) * autoev - chk%wfn%C = chk%tblite%coeff(:, :, 1) - chk%wfn%ihomo = chk%tblite%homo(1) - chk%wfn%ihomoa = chk%tblite%homo(1) - chk%wfn%ihomob = chk%tblite%homo(2) - chk%wfn%wbo = wbo(:, :, 1) - chk%wfn%dipm = chk%tblite%dpat(:, :, 1) - chk%wfn%qp = chk%tblite%qpat(:, :, 1) - - results%hl_gap = (chk%tblite%emo(chk%tblite%homo(1) + 1, 1) - chk%tblite%emo(chk%tblite%homo(1), 1)) * autoev + call convert_tblite_to_wfn(env, self%bas, mol, chk, wbo=wbo) + call convert_tblite_to_results(results,mol,chk,energy,.true.) hlgap = results%hl_gap !> polarizability by simple perturbative treatment diff --git a/src/qsort.f90 b/src/qsort.f90 index f6ddccced..5d14a2f0f 100644 --- a/src/qsort.f90 +++ b/src/qsort.f90 @@ -15,32 +15,50 @@ ! You should have received a copy of the GNU Lesser General Public License ! along with xtb. If not, see . +!> QuickSort algorithm recursive subroutine qsort(a, first, last, ind) - use xtb_mctc_accuracy, only : wp - implicit none - real(wp) :: a(*), x, t - integer :: ind(*) - integer :: first, last - integer :: i, j, ii + use xtb_mctc_accuracy, only : wp + implicit none + + !> input array + real(wp) :: a(*) + + !> range to sort + integer :: first, last - x = a( (first+last) / 2 ) - i = first - j = last - do - do while (a(i) < x) + !> index array + integer :: ind(*) + + !> pivot postion + real(wp) :: x + + !> temporary variables + integer :: i, j, ii + real(wp) :: t + + x = a( (first+last) / 2 ) ! choose a middle element as pivot + i = first + j = last + + ! parallel swapping of elements ! + do + do while (a(i) < x) i=i+1 - end do - do while (x < a(j)) + end do + do while (x < a(j)) j=j-1 - end do - if (i >= j) exit - t = a(i); a(i) = a(j); a(j) = t - ii=ind(i); ind(i) = ind(j); ind(j) = ii - i=i+1 - j=j-1 - end do - if (first < i-1) call qsort(a, first, i-1, ind) - if (j+1 < last) call qsort(a, j+1, last, ind) + end do + if (i >= j) exit + t = a(i); a(i) = a(j); a(j) = t + ii=ind(i); ind(i) = ind(j); ind(j) = ii + i=i+1 + j=j-1 + end do + + ! recursive calls ! + if (first < i-1) call qsort(a, first, i-1, ind) + if (j+1 < last) call qsort(a, j+1, last, ind) + end subroutine qsort recursive subroutine qqsort(a, first, last) diff --git a/src/scf_module.F90 b/src/scf_module.F90 index 7a6ebfb37..a897ecb30 100644 --- a/src/scf_module.F90 +++ b/src/scf_module.F90 @@ -851,17 +851,18 @@ subroutine scf(env, mol, wfn, basis, pcem, xtbData, solvation, & & allocated(solvation), basis, res) endif - if (allocated(solvation)) then - select type(solvation) - type is (TCosmo) - call open_file(ich, "xtb.cosmo", 'w') - call solvation%writeCosmoFile(ich, mol%at, mol%sym, mol%xyz, & - & wfn%q, eel + ep + exb + merge(embd, ed + embd, allocated(scD4))) - call close_file(ich) - end select - end if - endif printing + + ! Need to write xtb.cosmo for CPCM-X, so separate this from the printing block + if (allocated(solvation)) then + select type(solvation) + type is (TCosmo) + call open_file(ich, "xtb.cosmo", 'w') + call solvation%writeCosmoFile(ich, mol%at, mol%sym, mol%xyz, & + & wfn%q, eel + ep + exb + merge(embd, ed + embd, allocated(scD4))) + call close_file(ich) + end select + end if !--------------------------! ! Wiberg-Mayer bond orders ! diff --git a/src/setparam.f90 b/src/setparam.f90 index 06d33fb1c..8c1a1ec92 100644 --- a/src/setparam.f90 +++ b/src/setparam.f90 @@ -216,6 +216,7 @@ module xtb_setparam logical :: newdisp = .true. logical :: solve_scc = .true. logical :: periodic = .false. + logical :: optcell = .true. ! Geometry input type integer :: geometry_inputfile = p_geo_coord @@ -245,17 +246,16 @@ module xtb_setparam character(len=:), allocatable :: opt_outfile character(len=:), allocatable :: opt_logfile integer, allocatable :: opt_engine + + !> ANCopt settings type(ancopt_setvar) :: optset = ancopt_setvar (& optlev = p_olev_normal, & -! number of opt. cycles before new ANC are made - micro_opt = 20, & -! total number of opt. cycles, 0 means automatically determined + micro_opt = 20, & ! increased during opt. maxoptcycle = 0, & ! det. in ancopt routine if not read in -! maximum coordinate displacement in ancopt maxdispl_opt = 1.000_wp, & -! lowest force constant in ANC generation (should be > 0.005) - hlow_opt = 0.010_wp, & + hlow_opt = 0.010_wp, & ! 0.002 is too small average_conv = .false.) + type(modhess_setvar) :: mhset = modhess_setvar (& model = p_modh_old, & ! force constants for stretch, bend and torsion diff --git a/src/tblite/CMakeLists.txt b/src/tblite/CMakeLists.txt index 7353809b6..8b2db7176 100644 --- a/src/tblite/CMakeLists.txt +++ b/src/tblite/CMakeLists.txt @@ -18,6 +18,7 @@ set(dir "${CMAKE_CURRENT_SOURCE_DIR}") list(APPEND srcs "${dir}/calculator.F90" "${dir}/restart.F90" + "${dir}/mapping.F90" ) set(srcs ${srcs} PARENT_SCOPE) diff --git a/src/tblite/calculator.F90 b/src/tblite/calculator.F90 index ff45b96a3..f05087414 100644 --- a/src/tblite/calculator.F90 +++ b/src/tblite/calculator.F90 @@ -26,6 +26,7 @@ module xtb_tblite_calculator use mctc_io, only : structure_type, read_structure, filetype #if WITH_TBLITE use tblite_basis_type, only : basis_type + use tblite_ceh_ceh, only : new_ceh_calculator use tblite_container, only : container_type use tblite_context, only : context_type, context_terminal, escape use tblite_external_field, only : electric_field @@ -39,8 +40,10 @@ module xtb_tblite_calculator use tblite_xtb_gfn1, only : new_gfn1_calculator, export_gfn1_param use tblite_xtb_ipea1, only : new_ipea1_calculator, export_ipea1_param use tblite_xtb_singlepoint, only : xtb_singlepoint - use tblite_data_spin, only : get_spin_constant + use tblite_data_spin, only : get_spin_constant + use xtb_tblite_mapping, only : convert_tblite_to_wfn #endif + use xtb_tblite_mapping, only : convert_tblite_to_results use xtb_mctc_accuracy, only : wp use xtb_type_calculator, only : TCalculator use xtb_type_data @@ -57,6 +60,7 @@ module xtb_tblite_calculator private public :: TTBLiteCalculator, TTBLiteInput, newTBLiteCalculator, newTBLiteWavefunction + public :: get_ceh !> Input for tblite library type :: TTBLiteInput @@ -72,6 +76,8 @@ module xtb_tblite_calculator character(len=:), allocatable :: method !> Colorful output logical :: color = .false. + !> CEH charges + logical :: ceh = .false. end type TTBLiteInput !> Calculator interface for xTB based methods @@ -104,7 +110,7 @@ module xtb_tblite_calculator contains -!> Create a new instance of an tblite based xTB calculator +!> Create a new instance of tblite based xTB calculator subroutine newTBLiteCalculator(env, mol, calc, input) !> Source of the generated errors character(len=*), parameter :: source = 'tblite_calculator_newTBLiteCalculator' @@ -144,11 +150,16 @@ subroutine newTBLiteCalculator(env, mol, calc, input) case default call fatal_error(error, "Unknown method '"//method//"' requested") case("gfn2") - call new_gfn2_calculator(calc%tblite, struc) + call new_gfn2_calculator(calc%tblite, struc, error) case("gfn1") - call new_gfn1_calculator(calc%tblite, struc) + call new_gfn1_calculator(calc%tblite, struc, error) case("ipea1") - call new_ipea1_calculator(calc%tblite, struc) + call new_ipea1_calculator(calc%tblite, struc, error) + case("ceh") + calc%guess = method + calc%nspin = 1 + calc%etemp = 4000.0_wp * kt + call new_ceh_calculator(calc%tblite, struc, error) end select end if if (allocated(error)) then @@ -208,7 +219,7 @@ subroutine newTBLiteWavefunction(env, mol, calc, chk) !> Molecular structure data type(TMolecule), intent(in) :: mol !> Instance of the new calculator - type(TTBLiteCalculator), intent(in) :: calc + type(TTBLiteCalculator), intent(inout) :: calc !> Wavefunction data type(TRestart), intent(inout) :: chk @@ -229,6 +240,23 @@ subroutine newTBLiteWavefunction(env, mol, calc, chk) call sad_guess(struc, calc%tblite, wfn) case("eeq") call eeq_guess(struc, calc%tblite, wfn) + case("ceh") + block + use tblite_context, only : context_type, context_terminal + use tblite_context_terminal, only : escape + use tblite_ceh_singlepoint, only : ceh_singlepoint + use tblite_lapack_solver, only : lapack_solver + use tblite_lapack_solver, only : lapack_algorithm + type(context_type) :: ctx + + ctx%solver = lapack_solver(lapack_algorithm%gvd) + ctx%terminal = context_terminal(calc%color) + + write (env%unit, '(1x,a)') escape(ctx%terminal%cyan) // "Calculation of CEH charges" // & + & escape(ctx%terminal%reset) + + call ceh_singlepoint(ctx, calc%tblite, struc, wfn, calc%accuracy, 1) + end block end select end associate if (allocated(error)) then @@ -293,17 +321,13 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, & return end if - results%e_total = energy - results%converged = .true. - results%dipole = sum(chk%tblite%dpat(:, :, 1), 2) + matmul(struc%xyz, chk%tblite%qat(: ,1)) - results%gnorm = norm2(gradient) + ! convert tblite results into xtb data ! + call convert_tblite_to_wfn(env, self%tblite%bas, mol, chk) + call convert_tblite_to_results(results,mol,chk,energy,.true.,gradient=gradient) + hlgap = results%hl_gap -! if (printlevel > 2) then -! call ascii_levels(ctx%unit, printlevel, chk%tblite%homo, chk%tblite%emo, & -! & chk%tblite%focc, 7) -! end if #else - call feature_not_implemented(env) + call feature_not_implemented(env) #endif end subroutine singlepoint @@ -362,6 +386,51 @@ subroutine get_spin_constants(wll, mol, bas) end subroutine get_spin_constants #endif +!> get CEH charges via tblite +subroutine get_ceh(env,mol,tblite) + + use xtb_propertyoutput, only : print_charges + + !> computational environment + type(TEnvironment), intent(inout) :: env + + !> molecular structure data + type(TMolecule), intent(in) :: mol + + !> tblite input + type(TTBLiteInput), intent(in) :: tblite + + !> initialize temporary calculator for CEH + type(TTBLiteCalculator) :: calc_ceh + + !> initialize temporary input for CEH + type(TTBLiteInput) :: tblite_ceh + + !> initialize temporary wfn for CEH + type(TRestart) :: chk_ceh + + integer :: ich + + tblite_ceh = tblite ! copy the tblite input + tblite_ceh%method = "ceh" +#if WITH_TBLITE + write(env%unit, '(a)') repeat('-', 36) + + call newTBLiteCalculator(env, mol, calc_ceh, tblite_ceh) + call newTBLiteWavefunction(env, mol, calc_ceh, chk_ceh) + + ! create ceh.charges file ! + call open_file(ich, 'ceh.charges', 'w') + call print_charges(ich, mol%n, chk_ceh%tblite%qat(:,1)) + call close_file(ich) + + write(env%unit, '(1x, a, /, a, /)') "CEH charges written to ceh.charges", repeat('-', 36) +#else + call feature_not_implemented(env) +#endif + +end subroutine get_ceh + #if ! WITH_TBLITE subroutine feature_not_implemented(env) !> Computational environment diff --git a/src/tblite/mapping.F90 b/src/tblite/mapping.F90 new file mode 100644 index 000000000..9431dd2cf --- /dev/null +++ b/src/tblite/mapping.F90 @@ -0,0 +1,161 @@ +#ifndef WITH_TBLITE +#define WITH_TBLITE 0 +#endif + +module xtb_tblite_mapping + + use xtb_type_environment, only: TEnvironment + use xtb_type_restart, only: TRestart + use xtb_type_data, only: scc_results + use xtb_type_molecule, only: TMolecule + use xtb_mctc_accuracy, only: wp + use mctc_io_convert, only: autoev + use xtb_type_wavefunction, only: TWavefunction + +#if WITH_TBLITE + use tblite_basis_type, only: basis_type +#endif + implicit none + private + public :: convert_tblite_to_results + +#if WITH_TBLITE + public :: convert_tblite_to_wfn + interface assignment(=) + module procedure :: from_tblite_wfn + module procedure :: from_tblite_basis + module procedure :: from_struc + end interface assignment(=) +#endif +contains + +#if WITH_TBLITE +!> convert tblite wavefunction to xtb wavefunction +subroutine convert_tblite_to_wfn(env, bas, mol, chk, wbo) + + !> computational environment + type(TEnvironment), intent(inout) :: env + + !> basis set + type(basis_type), intent(in) :: bas + + !> molecular structure + type(TMolecule), intent(in) :: mol + + !> restart data + type(TRestart), intent(inout) :: chk + + !> wiberg bond orders + real(wp), optional, intent(in) :: wbo(:,:,:) + + call chk%wfn%allocate(mol%n, bas%nsh, bas%nao) + + ! assignment interfaces ! + chk%wfn = chk%tblite + chk%wfn = bas + chk%wfn = mol + + if (present(wbo)) chk%wfn%wbo = wbo(:,:,1) ! only + +end subroutine convert_tblite_to_wfn +#endif + +!> convert tblite results to xtb results +subroutine convert_tblite_to_results(results, mol, chk, energy, converged, gradient) + + !> scc results + type(scc_results), intent(inout) :: results + + !> molecular structure + type(TMolecule), intent(in) :: mol + + !> restart data + type(TRestart), intent(in) :: chk + + !> SCC energy + real(wp), intent(in) :: energy + + !> convergence flag + logical, intent(in) :: converged + + !> (analytical) gradients + real(wp), optional, intent(in) :: gradient(:,:) + + + results%e_total = energy + results%converged = converged + +#if WITH_TBLITE + + ! do not overwrite dipole moments, if calculated (PTB case) ! + if (all(results%dipole == 0.0_wp)) then + results%dipole = sum(chk%tblite%dpat(:, :, 1), 2) + matmul(mol%xyz, chk%tblite%qat(: ,1)) + endif + results%hl_gap = (chk%tblite%emo(chk%tblite%homo(1) + 1, 1) - chk%tblite%emo(chk%tblite%homo(1), 1)) * autoev + +#endif + + if (present(gradient)) results%gnorm = norm2(gradient) + +end subroutine convert_tblite_to_results + + +#if WITH_TBLITE + +subroutine from_tblite_wfn(wfn, tblite) + + use tblite_wavefunction, only : wavefunction_type + + type(TWavefunction), intent(inout) :: wfn + type(wavefunction_type), intent(in) :: tblite + + wfn%dipm = tblite%dpat(:, :, 1) + wfn%nel = nint(tblite%nocc) + wfn%P = tblite%density(:, :, 1) + wfn%q = tblite%qat(:, 1) + wfn%qsh = tblite%qsh(:, 1) + wfn%focca = tblite%focc(:, 1) + wfn%foccb = 0.0_wp + wfn%focc(:) = tblite%focc(:, 1) + wfn%emo = tblite%emo(:, 1) * autoev + wfn%C = tblite%coeff(:, :, 1) + wfn%ihomo = tblite%homo(1) + wfn%ihomoa = tblite%homo(1) + wfn%ihomob = tblite%homo(2) + wfn%qp = tblite%qpat(:, :, 1) + +end subroutine from_tblite_wfn + +subroutine from_tblite_basis(wfn, bas) + + use tblite_basis_type, only: basis_type + + type(TWavefunction), intent(inout) :: wfn + type(basis_type), intent(in) :: bas + + wfn%nshell = bas%nsh + wfn%nao = bas%nao + +end subroutine from_tblite_basis + +subroutine from_struc(wfn, mol) + + type(TWavefunction), intent(inout) :: wfn + type(TMolecule), intent(in) :: mol + + wfn%n = mol%n + wfn%nopen = mol%uhf + +end subroutine from_struc +#endif + +#if ! WITH_TBLITE +subroutine feature_not_implemented(env) + !> Computational environment + type(TEnvironment), intent(inout) :: env + + call env%error("Compiled without support for tblite library") +end subroutine feature_not_implemented +#endif + +end module xtb_tblite_mapping \ No newline at end of file diff --git a/src/tblite/meson.build b/src/tblite/meson.build index d9aeabe4c..56529ca06 100644 --- a/src/tblite/meson.build +++ b/src/tblite/meson.build @@ -16,5 +16,6 @@ srcs += files( 'calculator.F90', 'restart.F90', + 'mapping.F90', ) diff --git a/src/thermo.f90 b/src/thermo.f90 index 34aa069fb..75735b49e 100644 --- a/src/thermo.f90 +++ b/src/thermo.f90 @@ -31,7 +31,7 @@ subroutine getsymmetry (pr, iunit, n, iat, xyz, symthr, maxatdesy, sfsym) real(wp) symthr Character(len=*) sfsym logical pr - Character(len=4) atmp + Character(len=6) atmp integer,allocatable :: ictdum(:,:) Real(wp) :: paramar (11) !parameter array for get_schoenflies_ diff --git a/src/type/anc.f90 b/src/type/anc.f90 index e50652a85..836d70d80 100644 --- a/src/type/anc.f90 +++ b/src/type/anc.f90 @@ -25,22 +25,39 @@ module xtb_type_anc private type tb_anc - integer :: n !< number of atoms - integer :: n3 !< dimension of hessian - integer :: nvar !< actual dimension + integer :: n ! number of atoms + integer :: n3 ! dimension of hessian + integer :: nvar ! actual dimension + + !> lower bound for eigenvalues real(wp) :: hlow + + !> upper bound for eigenvalues real(wp) :: hmax + + !> hessian matrix real(wp),allocatable :: hess(:) + + !> transformation matrix real(wp),allocatable :: B(:,:) + + !> eigenvalues of hessian real(wp),allocatable :: eigv(:) + + !> internal coordinates (approximate normal coordinates) real(wp),allocatable :: coord(:) + + !> cartesian coordinates real(wp),allocatable :: xyz(:,:) contains procedure :: allocate => allocate_anc procedure :: deallocate => deallocate_anc - procedure :: write => write_anc + procedure :: write_anc + procedure :: write_anc_2 + generic :: write => write_anc, write_anc_2 procedure :: new => generate_anc_blowup procedure :: get_cartesian + procedure :: get_normal end type tb_anc contains @@ -81,16 +98,15 @@ subroutine deallocate_anc(self) end subroutine deallocate_anc !> @brief print information about current approximate normal coordinates to unit -subroutine write_anc(self,iunit,comment) +subroutine write_anc(self,iunit) + implicit none class(tb_anc), intent(in) :: self !< approximate normal coordinates integer, intent(in) :: iunit !< file handle - character(len=*),intent(in) :: comment !< name of the variable character(len=*),parameter :: dfmt = '(1x,a,1x,"=",1x,g0)' write(iunit,'(72(">"))') write(iunit,'(1x,"*",1x,a)') "Writing 'tb_anc' class" - write(iunit,'( "->",1x,a)') comment write(iunit,'(72("-"))') write(iunit,'(1x,"*",1x,a)') "status of the fields" write(iunit,dfmt) "integer :: n ",self%n @@ -125,19 +141,69 @@ subroutine write_anc(self,iunit,comment) write(iunit,dfmt) "size(2) :: xyz(:,*) ",size(self%xyz,2) endif write(iunit,'(72("<"))') + end subroutine write_anc +!> print information about current approximate normal coordinates to unit +subroutine write_anc_2(self,iunit,nvar) + + use xtb_mctc_accuracy, only : wp + + implicit none + + !> optimization state holder + class(tb_anc), intent(in) :: self + + !> output unit + integer, intent(in) :: iunit + + !> number of variables to print + integer, intent(in) :: nvar + + integer :: i,j + + write(iunit,*) 'Transformation matrix B' + do i = 1, self%n3 + do j = 1, nvar + write(iunit,'(f8.3,1x)',advance='no') self%B(i,j) + enddo + write(iunit,*) + enddo + + ! print internal coordinates ! + write(iunit,*) 'Internal coordinates' + do i = 1, self%nvar + write(iunit,'(f8.3,1x)',advance='no') self%coord(i) + enddo + write(iunit,*) + +end subroutine write_anc_2 + +!> initialize subroutine generate_anc_blowup(self,iunit,xyz,hess,pr,linear) + use xtb_mctc_accuracy, only : wp use xtb_mctc_la use xtb_detrotra, only : detrotra8 implicit none - class(tb_anc),intent(inout) :: self - integer, intent(in) :: iunit - real(wp), intent(in) :: xyz(3,self%n) - real(wp), intent(inout) :: hess(self%n3,self%n3) - logical, intent(in) :: pr - logical, intent(in) :: linear + + !> ANC object + class(tb_anc),intent(inout) :: self ! anc + + !> output unit + integer, intent(in) :: iunit ! env%unit + + !> cartesian coordinates + real(wp), intent(in) :: xyz(3,self%n) ! molopt%xyz + + !> Hessian matrix + real(wp), intent(inout) :: hess(self%n3,self%n3) ! h + + !> printlevel + logical, intent(in) :: pr ! pr + + !> if linear structure + logical, intent(in) :: linear ! linear real(wp),parameter :: thr1 = 1.0e-10_wp real(wp),parameter :: thr2 = 1.0e-11_wp @@ -145,39 +211,46 @@ subroutine generate_anc_blowup(self,iunit,xyz,hess,pr,linear) integer :: i,itry integer :: nvar integer :: info + + !> LAPACK, length of auxilary fp workspace integer :: lwork + + !> LAPACK, length of auxilary integer workspace integer :: liwork - logical :: fail + + !> LAPACK, auxilary workspace for integer operations integer, allocatable :: iwork(:) + real(wp) :: elow,damp,thr - real(wp),allocatable :: aux(:) + + !> LAPACK, auxilary workspace for floating point operations + real(wp),allocatable :: aux(:) ! = work + logical :: fail + + ! Intialize ! self%xyz = xyz - thr = thr2 lwork = 1 + 6*self%n3 + 2*self%n3**2 liwork = 8 * self%n3 + allocate(iwork(liwork), source = 0) + allocate(aux(lwork), source = 0.0_wp) - allocate(iwork(liwork), source = 0 ) - allocate(aux(lwork), source = 0.0_wp ) - + ! Diagonalize Hessian ! call lapack_syevd('V','U',self%n3,hess,self%n3,self%eigv, & & aux,lwork,iwork,liwork,info) + ! determine, sort, and nullify rot/trans modes ! call detrotra8(linear,self%n,self%xyz,hess,self%eigv) - !elow = 1.0e+99_wp - elow = minval(self%eigv,mask=(abs(self%eigv) > thr1)) -! do i = 1, self%n3 -! if (abs(self%eigv(i)) > thr1 ) elow = min(elow,self%eigv(i)) -! enddo + ! find lowest eigenvalue (ignore nullified ones) ! + elow = minval(self%eigv,mask=(abs(self%eigv) > thr1)) + ! shift eigenvalues to hlow ! damp = max(self%hlow - elow,0.0_wp) where(abs(self%eigv) > thr2) self%eigv = self%eigv + damp -! do i = 1, self%n3 -! if (abs(self%eigv(i)) > thr2 ) self%eigv(i) = self%eigv(i) + damp -! enddo + ! print eigenvalue spectrum ! if(pr)then write(iunit,*) 'Shifting diagonal of input Hessian by ', damp write(iunit,*) 'Lowest eigenvalues of input Hessian' @@ -188,11 +261,13 @@ subroutine generate_anc_blowup(self,iunit,xyz,hess,pr,linear) endif fail = .true. - get_anc: do itry = 1, maxtry + get_anc: do itry = 1, maxtry ! 4 times + self%B = 0.0_wp self%hess = 0.0_wp nvar = 0 - ! take largest (positive) first + + ! take largest (positive) first ! do i = self%n3, 1, -1 if (abs(self%eigv(i)) > thr .and. nvar < self%nvar) then nvar = nvar+1 @@ -202,6 +277,7 @@ subroutine generate_anc_blowup(self,iunit,xyz,hess,pr,linear) endif enddo + ! reduce thr if not enough modes found ! if (nvar.ne.self%nvar) then thr = thr * 0.1_wp cycle get_anc @@ -212,14 +288,15 @@ subroutine generate_anc_blowup(self,iunit,xyz,hess,pr,linear) enddo get_anc - if (fail) then - write(*,*) 'nvar, selv%nvar',nvar,self%nvar - call raise('E',"ANC generation failed!") - end if + ! nvar .ne. self%nvar ! + if (fail) & + & call raise('E',"ANC generation failed, not enough modes!") + ! sort eigenvalues and eigenvectors in ascending order ! call sort(self%n3,self%nvar,self%hess,self%B) self%coord = 0.0_wp + end subroutine generate_anc_blowup subroutine generate_anc_packed(self,xyz,hess,pr) @@ -285,7 +362,7 @@ subroutine generate_anc_packed(self,xyz,hess,pr) self%B = 0.0_wp self%hess = 0.0_wp nvar = 0 - ! take largest (positive) first + ! take largest (positive) first ! do i = self%n3, 1, -1 if (abs(self%eigv(i)) > thr .and. nvar < self%nvar) then nvar = nvar+1 @@ -311,39 +388,52 @@ subroutine generate_anc_packed(self,xyz,hess,pr) call sort(self%n3,self%nvar,self%hess,self%B) self%coord = 0.0_wp + end subroutine generate_anc_packed +!> sort eigenvalues and eigenvectors pure subroutine sort(nat3,nvar,hess,b) + implicit none - integer :: ii,k,j,m,i - integer, intent(in) :: nat3,nvar + integer, intent(in) :: nat3, nvar real(wp),intent(inout) :: hess(nvar*(nvar+1)/2) real(wp),intent(inout) :: b(nat3,nat3) + real(wp) :: pp,sc1 real(wp),allocatable :: edum(:) + integer :: ii,k,j,m,i + allocate( edum(nvar), source = 0.0_wp ) + ! copy diagonal elements ! do k=1,nvar edum(k)=hess(k+k*(k-1)/2) enddo -! sort + + ! sort eigenvalues and eigenvectors ! do ii = 2, nvar + i = ii - 1 k = i pp= edum(i) + do j = ii, nvar if (edum(j) .gt. pp) cycle k = j pp= edum(j) enddo + if (k .eq. i) cycle + edum(k) = edum(i) edum(i) = pp + do m=1,nat3 sc1=b(m,i) b(m,i)=b(m,k) b(m,k)=sc1 enddo + enddo do k=1,nvar @@ -352,18 +442,63 @@ pure subroutine sort(nat3,nvar,hess,b) end subroutine sort +!> transform and add displacement vector to Cartesian coordinates subroutine get_cartesian(self,xyz) + + use xtb_mctc_io, only : stdout use xtb_mctc_accuracy, only : wp + implicit none - class(tb_anc),intent(in) :: self - integer :: m,i,j,k - real(wp),intent(out) :: xyz (3,self%n) - real(wp) :: dum -! generate cartesian displacement vector + !> optimization state holder + class(tb_anc),intent(inout) :: self + + !> cartesian coordinates to be transformed + real(wp),intent(out) :: xyz(3,self%n) + + !> temporary storage + real(wp), allocatable :: displ_cartesian(:) + integer :: i + + !> debug mode + logical, parameter :: debug = .false. + + allocate(displ_cartesian(3*self%n), source = 0.0_wp) xyz = self%xyz - call dgemv('n',self%n3,self%nvar,1.0_wp,self%B,self%n3,self%coord,1,1.0_wp,xyz,1) + + if (debug) & !####### DEBUG ####### + call self%write(stdout,self%nvar) + + call dgemv('n',self%n3,self%nvar,1.0_wp,self%B,self%n3,self%coord,1,0.0_wp,displ_cartesian,1) ! B * coord + xyz = xyz + reshape(displ_cartesian,(/3,self%n/)) ! xyz + displ_cartesian end subroutine get_cartesian -end module xtb_type_anc +!> transform gradients from Cartesian to normal coordinates +subroutine get_normal(self,g_cartesian, g_normal) + + use xtb_mctc_io, only : stdout + use xtb_mctc_accuracy, only : wp + + implicit none + + !> optimization state holder + class(tb_anc),intent(inout) :: self + + !> cartesian coordinates to be transformed + real(wp),intent(in) :: g_cartesian(3,self%n) + + !> cartesian coordinates to be transformed + real(wp),intent(out) :: g_normal(:) + + !> temporary storage + real(wp), allocatable :: array_form(:) + + allocate(array_form(3*self%n), source = 0.0_wp) + array_form = reshape(g_cartesian,(/3*self%n/)) + + call dgemv('t',self%n3,self%nvar,1.0_wp,self%B,self%n3,array_form,1,0.0_wp,g_normal,1) + +end subroutine get_normal + +end module xtb_type_anc \ No newline at end of file diff --git a/src/type/data.f90 b/src/type/data.f90 index 2da7963d2..59bd6a196 100644 --- a/src/type/data.f90 +++ b/src/type/data.f90 @@ -88,6 +88,8 @@ module xtb_type_data real(wp) :: e_batm = 0.0_wp real(wp) :: e_ext = 0.0_wp type(TIFFResults), allocatable :: iff_results + contains + procedure :: print => print_scc_results end type scc_results type freq_results @@ -172,4 +174,30 @@ subroutine deallocate_freq_results(self) if (allocated( self%pg )) deallocate( self%pg ) end subroutine deallocate_freq_results +!> print SCC results (for debug) +subroutine print_scc_results(self, unit) + use iso_fortran_env, only : output_unit + class(scc_results) :: self + integer, optional :: unit + + integer :: out ! output unit holder + character(len=*), parameter :: dfmt = '(3x,a,2x,f12.6)' ! format for double precision + integer :: i + + if (present(unit)) then + out = unit + else + out = output_unit + endif + + write(out, '(3x,a,/,2x,11("="))') 'SCC Results' + + write(out, dfmt) 'e_total :', self%e_total + write(out, dfmt) 'hl_gap :', self%hl_gap + do i=1,3 + write(out, dfmt) 'dipole :', self%dipole(i) + enddo + +end subroutine print_scc_results + end module xtb_type_data diff --git a/src/type/setvar.f90 b/src/type/setvar.f90 index 4b8501847..385192cef 100644 --- a/src/type/setvar.f90 +++ b/src/type/setvar.f90 @@ -70,39 +70,51 @@ module xtb_type_setvar real(wp) :: broydamp = 0.40_wp end type scc_setvar -!! ------------------------------------------------------------------------ -! approximate normal coordinate rational function optimizer -!! ------------------------------------------------------------------------ + !> approximate normal coordinate rational function optimizer type :: ancopt_setvar -! default optimization level -! crude = -3, sloppy = -2, loose = -1, normal = 0, -! tight = 1, verytight = 2, extreme = 3 + + !> default optimization level + !> crude = -3, sloppy = -2, loose = -1, normal = 0, + !> tight = 1, verytight = 2, extreme = 3 integer :: optlev = 0 -! number of opt. cycles before new ANC are made + + !> number of opt. cycles before new ANC are made by model Hessian integer :: micro_opt = 0 -! total number of opt. cycles, 0 means automatically determined - integer :: maxoptcycle = 0 ! det. in ancopt routine if not read in -! maximum coordinate displacement in ancopt + + !> total number of opt. cycles, 0 means automatically determined + integer :: maxoptcycle = 0 + + !> maximum coordinate displacement in ancopt real(wp) :: maxdispl_opt = 0.0_wp -! lowest force constant in ANC generation (should be > 0.005) + + !> lowest force constant in ANC generation (should be > 0.005) real(wp) :: hlow_opt = 0.0_wp - logical :: exact_rf = .false. + + logical :: exact_rf = .false. + + !> average energy and gradient before checking for convergence + !> to accelerate numerically noisy potential energy surfaces logical :: average_conv = .false. + end type ancopt_setvar type modhess_setvar integer :: model = 0 -! force constants for stretch, bend and torsion + + !> cutoff for constructing internal coordinates + real(wp) :: rcut = 0.0_wp + + !> dispersion scaling in ANC generation + real(wp) :: s6 = 0.0_wp + + !> force constants for stretch, bend and torsion real(wp) :: kr = 0.0_wp real(wp) :: kf = 0.0_wp real(wp) :: kt = 0.0_wp real(wp) :: ko = 0.0_wp real(wp) :: kd = 0.0_wp real(wp) :: kq = 0.0_wp -! cutoff for constructing internal coordinates - real(wp) :: rcut = 0.0_wp -! dispersion scaling in ANC generation - real(wp) :: s6 = 0.0_wp + end type modhess_setvar !! ------------------------------------------------------------------------ diff --git a/src/type/wavefunction.f90 b/src/type/wavefunction.f90 index 71712d450..6b6788247 100644 --- a/src/type/wavefunction.f90 +++ b/src/type/wavefunction.f90 @@ -24,45 +24,65 @@ module xtb_type_wavefunction private type :: TWavefunction + + !> number of atoms integer :: n = 0 - !! Number of atoms + + !> number of electrons integer :: nel = 0 - !! Number of elctrons + + !> number of unpaired electrons integer :: nopen = 0 - !! Number of unpaired electrons + + !> number of atomic orbitals integer :: nao = 0 - !! Number of atomic orbitals + + !> number of shells integer :: nshell = 0 - !! Number of shells + + !> density matrix real(wp),allocatable :: P(:,:) - !! Density matrix + + !> partial charges real(wp),allocatable :: q(:) - !! Partial charges + + !> shell charges real(wp),allocatable :: qsh(:) - !! Shell charges + + !> dipole moments real(wp),allocatable :: dipm(:,:) - !! Dipole moments + + !> quadrupole moments real(wp),allocatable :: qp(:,:) - !! Quadrupole moments + + !> wiberg bond orders real(wp),allocatable :: wbo(:,:) - !! Wiberg bond orders + + !> HOMO position integer :: ihomo = 0,ihomoa = 0,ihomob = 0 - !! HOMO position + + !> fermi real(wp) :: efa = 0.0_wp, efb = 0.0_wp + + !> fractional occupation real(wp),allocatable :: focc(:) - !! Fractional occupation + + !> alpha space real(wp),allocatable :: focca(:) - !! For alpha space + + !> beta space real(wp),allocatable :: foccb(:) - !! For beta space + + !> orbital energies real(wp),allocatable :: emo(:) - !! Orbital energies + + !> molecular orbitals real(wp),allocatable :: C(:,:) - !! Molecular orbitals contains procedure :: allocate => allocate_wavefunction procedure :: deallocate => deallocate_wavefunction + procedure :: print => print_wavefunction end type TWavefunction contains @@ -105,4 +125,88 @@ subroutine deallocate_wavefunction(self) if(allocated(self%C)) deallocate(self%C) end subroutine deallocate_wavefunction +!> print content of wavefunction (for debug) +subroutine print_wavefunction(self, level, unit) + use iso_fortran_env, only : output_unit + class(TWavefunction),intent(in) :: self + integer,intent(in) :: level + integer,intent(in),optional :: unit + + character(len=*), parameter :: fmt0 = '(3x,a,3x,i0)' + character(len=30):: fmt1_n + character(len=30):: fmt1_nao + character(len=30):: fmt1_nshell + integer :: out, i, ndim + + if (self%nao>20) then + ndim=20 + else + ndim=self%nao + end if + + write(fmt1_n,'(a,i0,a)') '(3x,a,3x,',self%n,'(f6.2,1x))' + write(fmt1_nao,'(a,i0,a)') '(3x,a,3x,',ndim,'(f6.2,1x))' + write(fmt1_nshell,'(a,i0,a)') '(3x,a,3x,',self%nshell,'(f6.2,1x))' + + if (present(unit)) then + out = unit + else + out = output_unit + end if + + + if (level >= 0 .and. level <= 2) then + write(out, '(3x,a,/,2x,12("="))') 'Wavefunction' + + ! scalar values ! + write(out,fmt0) 'n :', self%n + write(out,fmt0) 'nel :', self%nel + write(out,fmt0) 'nopen :', self%nopen + write(out,fmt0) 'nao :', self%nao + write(out,fmt0) 'nshell :', self%nshell + write(out,fmt0) 'ihomo :', self%ihomo + write(out,fmt0) 'ihomoa :', self%ihomoa + write(out,fmt0) 'ihomob :', self%ihomob + + ! vector values ! + if (level>0) then + write(out,fmt1_n) 'q :', self%q + write(out,fmt1_nshell) 'qsh :', self%qsh + write(out,fmt1_nao) 'focc :', self%focc(:ndim) + write(out,fmt1_nao) 'emo :', self%emo(:ndim) + + ! matrix values ! + if (level>1) then + + write(out,'(/)') + + do i=1,3 + write(out,fmt1_n) 'dipm :', self%dipm(i,:) + end do + + write(out,'(/)') + + do i=1,6 + write(out,fmt1_n) 'qp :', self%qp(i,:) + end do + + write(out,'(/)') + + do i=1,ndim + write(out,fmt1_nao) 'C :', self%C(:ndim,i) + end do + + write(out,'(/)') + + do i=1,ndim + write(out,fmt1_nao) 'P :', self%P(:ndim,i) + end do + + write(out,'(/)') + + endif + endif + endif +end subroutine print_wavefunction + end module xtb_type_wavefunction diff --git a/src/vertical.f90 b/src/vertical.f90 index 3d1157686..c633f9db2 100644 --- a/src/vertical.f90 +++ b/src/vertical.f90 @@ -47,8 +47,9 @@ subroutine vfukui(env, mol, chk, calc, fukui) type(TMolecule), intent(inout) :: mol !! molecular information type(TRestart), intent(inout) :: chk - type(TRestart) :: wf_p, wf_m + type(TRestart) :: wf_an, wf_cat + ! fukui functions f(+), f(-), f(0) real(wp), intent(out) :: fukui(3,mol%n) type(scc_results) :: res @@ -60,19 +61,45 @@ subroutine vfukui(env, mol, chk, calc, fukui) write(env%unit,'(a)') write(env%unit,'("Fukui index Calculation")') - wf_p%wfn = chk%wfn - wf_m%wfn = chk%wfn - mol%chrg = mol%chrg - 1 - if (mod(wf_p%wfn%nel,2).ne.0) wf_p%wfn%nopen = 1 - call calc%singlepoint(env, mol, wf_p, 1, exist, etot2, g, sigma, egap, res) - fukui(1,:) = wf_p%wfn%q-chk%wfn%q + ! copy wavefunction + wf_an%wfn = chk%wfn + wf_cat%wfn = chk%wfn + + ! reduce the charge -> anion + mol%chrg = mol%chrg - 1 + if (mod(wf_an%wfn%nel,2).ne.0) wf_an%wfn%nopen = 1 + + ! Perform single point calculation for anion + write(env%unit,'(a)') + write(env%unit,'("Run single point for reduced species")') + call calc%singlepoint(env, mol, wf_an, 1, exist, etot2, g, sigma, egap, res) + + ! increase the charge -> cation mol%chrg = mol%chrg + 2 - if (mod(wf_m%wfn%nel,2).ne.0) wf_m%wfn%nopen = 1 - call calc%singlepoint(env, mol, wf_m, 1, exist, etot2, g, sigma, egap, res) - fukui(2,:) = chk%wfn%q-wf_m%wfn%q - fukui(3,:) = 0.5d0*(wf_p%wfn%q-wf_m%wfn%q) + if (mod(wf_cat%wfn%nel,2).ne.0) wf_cat%wfn%nopen = 1 + ! Perform single point calculation for cation + write(env%unit,'(a)') + write(env%unit,'("Run single point for oxidized species")') + call calc%singlepoint(env, mol, wf_cat, 1, exist, etot2, g, sigma, egap, res) + + ! Calculate the fukui functions where N is the number of electrons + ! see J. Am. Chem. Soc. 1986, 108, 19, 5708–5711 for equations + ! keep in mind that their q are populations (p), + ! which are related to our q by q = Z-p + + ! f(+) = q_N - q_(N+1) / neutral - anion + fukui(1,:) = chk%wfn%q - wf_an%wfn%q + + ! f(-) = q_(N-1) - q_N / cation - neutral + fukui(2,:) = wf_cat%wfn%q-chk%wfn%q + + ! f(0) = 0.5 * [q_(N-1) - q_(N+1)] / cation - anion + fukui(3,:) = 0.5d0*(wf_cat%wfn%q-wf_an%wfn%q) + + ! Print out fukui functions write(env%unit,'(a)') + write(env%unit,'("Fukui functions:")') write(env%unit, '(1x," # f(+) f(-) f(0)")') do i=1,mol%n write(env%unit,'(i6,a4,2f9.3,2f9.3,2f9.3)') i, mol%sym(i), fukui(1,i), fukui(2,i), fukui(3,i) diff --git a/src/xhelp.f90 b/src/xhelp.f90 index e752a57f1..98fdd44d0 100644 --- a/src/xhelp.f90 +++ b/src/xhelp.f90 @@ -110,6 +110,9 @@ subroutine help(iunit) "-c, --chrg INT",& " specify molecular charge as INT, overrides .CHRG file and xcontrol option",& "",& + "--ceh",& + " calculate CEH (Charge-Extended Hückel model) charges and write them to ceh.charges file",& + "",& "-u, --uhf INT",& " specify number of unpaired electrons as INT, overrides .UHF file and xcontrol option",& "",& @@ -120,7 +123,7 @@ subroutine help(iunit) " specify parametrisation of GFN-FF",& "",& "--tblite,",& - " use tblite library as implementation for xTB",& + " use tblite library as implementation for xTB, please note that solvation is not yet implemented within tblite",& "",& "--ptb,",& " performs single-point calculation with the density tight-binding method PTB.", & @@ -162,7 +165,7 @@ subroutine help(iunit) " hexandecane, hexane, methanol, nitromethane, octanol, woctanol, phenol, toluene,",& " thf, water.",& " The solvent input is not case-sensitive. The Gsolv",& - " reference state can be chosen as reference or bar1M (default).",& + " reference state can be chosen as reference, bar1M, or gsolv (default).",& "",& "-g, --gbsa SOLVENT [STATE]",& " generalized born (GB) model with solvent accessable surface (SASA) model,",& @@ -170,7 +173,7 @@ subroutine help(iunit) " CHCl3, CS2, DMF (only GFN2-xTB), DMSO, ether, H2O, methanol,",& " n-hexane (only GFN2-xTB), THF and toluene.",& " The solvent input is not case-sensitive.", & - " The Gsolv reference state can be chosen as reference or bar1M (default).",& + " The Gsolv reference state can be chosen as reference, bar1M, or gsolv (default).",& "",& "--cosmo SOLVENT/EPSILON",& " domain decomposition conductor-like screening model (ddCOSMO),",& diff --git a/subprojects/dftd4.wrap b/subprojects/dftd4.wrap index 46dc07ad9..e3e93f459 100644 --- a/subprojects/dftd4.wrap +++ b/subprojects/dftd4.wrap @@ -1,4 +1,4 @@ [wrap-git] directory = dftd4 url = https://github.com/dftd4/dftd4 -revision = v3.5.0 +revision = v3.6.0 diff --git a/subprojects/mstore.wrap b/subprojects/mstore.wrap index acf5df9de..0dfe716c0 100644 --- a/subprojects/mstore.wrap +++ b/subprojects/mstore.wrap @@ -1,4 +1,4 @@ [wrap-git] directory = mstore url = https://github.com/grimme-lab/mstore -revision = v0.2.0 +revision = v0.3.0 diff --git a/test/api/c_api_example.c b/test/api/c_api_example.c index a4c04ee49..4bea81b48 100644 --- a/test/api/c_api_example.c +++ b/test/api/c_api_example.c @@ -22,15 +22,16 @@ static inline bool check_double(double actual, double expected, double tol, if (fabs(expected - actual) < tol) { return true; } - fprintf(stderr, "FAIL: %s: expected %g, got %g\n", msg, expected, actual); + fprintf(stderr, "FAIL: %s: expected %.10f, got %.10f\n", msg, expected, actual); return false; } int testFirst() { - // first molecule + // first molecule, various solvent models double* q; char* buffer; double* wbo; + double* hess; int buffersize = 512; int tester = 0; @@ -51,11 +52,17 @@ int testFirst() { xtb_TCalculator calc = NULL; xtb_TResults res = NULL; double energy; + double solv_energy; double dipole[3]; q = (double*) malloc(natoms * sizeof(double)); wbo = (double*) malloc(natsq * sizeof(double)); buffer = (char*) malloc(buffersize *sizeof(char)); + hess = (double*) malloc(9*natsq * sizeof(double)); char solvent[] = "h2o"; + char gbsa[] = "gbsa"; + char alpb[] = "alpb"; + char cosmo[] = "cosmo"; + char cpcmx[] = "cpcmx"; if (!check(XTB_API_VERSION, xtb_getAPIVersion(), "API version does not match")) goto error; @@ -104,7 +111,8 @@ int testFirst() { if (!check(wbo[9], 2.89823984265213, 1.0e-8, "Bond order does not match")) goto error; - xtb_setSolvent(env, calc, solvent, NULL, NULL, NULL); + // GBSA + xtb_setSolvent(env, calc, solvent, NULL, NULL, NULL, gbsa); if (xtb_checkEnvironment(env)) goto error; @@ -119,15 +127,140 @@ int testFirst() { if (xtb_checkEnvironment(env)) goto error; - if (!check(energy, -8.38393864716134, 1.0e-9, "Energy does not match")) + if (!check(energy, -8.38393864716134, 1.0e-9, "GBSA Energy does not match")) goto error; - if (!check(q[5], 0.06090868805034, 1.0e-8, "Charge does not match")) + if (!check(q[5], 0.06090868805034, 1.0e-8, "GBSA Charge does not match")) goto error; - if (!check(dipole[2], -0.35455233974705, 1.0e-6, "Dipole does not match")) + if (!check(dipole[2], -0.35455233974705, 1.0e-6, "GBSA Dipole does not match")) goto error; - if (!check(wbo[9], +2.89453979224265, 1.0e-8, "Bond order does not match")) + if (!check(wbo[9], +2.89453979224265, 1.0e-8, "GBSA Bond order does not match")) goto error; + // ALPB + xtb_releaseSolvent(env, calc); + xtb_setSolvent(env, calc, solvent, NULL, NULL, NULL, alpb); + if (xtb_checkEnvironment(env)) + goto error; + + xtb_singlepoint(env, mol, calc, res); + if (xtb_checkEnvironment(env)) + goto error; + + xtb_getEnergy(env, res, &energy); + xtb_getCharges(env, res, q); + xtb_getDipole(env, res, dipole); + xtb_getBondOrders(env, res, wbo); + if (xtb_checkEnvironment(env)) + goto error; + + if (!check(energy, -8.384076843892, 1.0e-9, "ALPB Energy does not match")) + goto error; + if (!check(q[5], 0.0644849340, 1.0e-8, "ALPB Charge does not match")) + goto error; + if (!check(dipole[2], -0.3641866008, 1.0e-6, "ALPB Dipole does not match")) + goto error; + if (!check(wbo[9], 2.8932146955, 1.0e-8, "ALPB Bond order does not match")) + goto error; + + // COSMO + //Sensitive to guess, so reset the results + xtb_delete(res); + res = xtb_newResults(); + if (xtb_checkEnvironment(env)) + goto error; + + xtb_loadGFN2xTB(env, mol, calc, NULL); + xtb_setAccuracy(env, calc, 1.0); + xtb_setElectronicTemp(env, calc, 300.0); + xtb_setMaxIter(env, calc, 30); + if (xtb_checkEnvironment(env)) + goto error; + + xtb_releaseSolvent(env, calc); + xtb_setSolvent(env, calc, solvent, NULL, NULL, NULL, cosmo); + if (xtb_checkEnvironment(env)) + goto error; + + xtb_singlepoint(env, mol, calc, res); + if (xtb_checkEnvironment(env)) + goto error; + + xtb_getEnergy(env, res, &energy); + xtb_getCharges(env, res, q); + xtb_getDipole(env, res, dipole); + xtb_getBondOrders(env, res, wbo); + if (xtb_checkEnvironment(env)) + goto error; + + if (!check(energy, -8.385752224008, 1.0e-9, "COSMO Energy does not match")) + goto error; + if (!check(q[5], 0.0597931738, 1.0e-8, "COSMO Charge does not match")) + goto error; + if (!check(dipole[2], -0.3709356947, 1.0e-6, "COSMO Dipole does not match")) + goto error; + if (!check(wbo[9], 2.8940365143, 1.0e-8, "COSMO Bond order does not match")) + goto error; + + + // CPCMX +#if WITH_CPCMX + //Sensitive to guess, so reset the results + xtb_delete(res); + res = xtb_newResults(); + if (xtb_checkEnvironment(env)) + goto error; + + xtb_releaseSolvent(env, calc); + xtb_setSolvent(env, calc, solvent, NULL, NULL, NULL, cpcmx); + if (xtb_checkEnvironment(env)) + goto error; + + xtb_cpcmx_calc(env, mol, calc, res); + if (xtb_checkEnvironment(env)) + goto error; + + xtb_getEnergy(env, res, &energy); + xtb_getSolvationEnergy(env, res, &solv_energy); + xtb_getCharges(env, res, q); + xtb_getDipole(env, res, dipole); + xtb_getBondOrders(env, res, wbo); + if (xtb_checkEnvironment(env)) + goto error; + + if (!check(energy, -8.383520040765, 1.0e-9, "CPCM-X Energy does not match")) + goto error; + if (!check(solv_energy, -0.0010406558065, 1.0e-8, "CPCM-X Solvation Energy does not match")) + goto error; + if (!check(q[5], 0.0518386448, 1.0e-8, "CPCM-X Charge does not match")) + goto error; + if (!check(dipole[2], -0.2983150104, 1.0e-6, "CPCM-X Dipole does not match")) + goto error; + if (!check(wbo[9], 2.8982388543, 1.0e-8, "CPCM-X Bond order does not match")) + goto error; + +#endif + // Compute Hessian + //Sensitive to guess, so reset the results + xtb_delete(res); + res = xtb_newResults(); + if (xtb_checkEnvironment(env)) + goto error; + + xtb_releaseSolvent(env, calc); + xtb_hessian(env, mol, calc, res, hess, NULL, NULL, NULL, NULL); + if (xtb_checkEnvironment(env)) + goto error; + + if (!check(hess[0], 0.4790088649, 1.0e-9, "Hessian[0,0] does not match")) + goto error; + if (!check(hess[3], -0.0463290233, 1.0e-9, "Hessian[0,3] does not match")) + goto error; + if (!check(hess[3], hess[63], 1.0e-9, "Hessian[0,3] != Hessian[3,0]")) + goto error; + if (!check(hess[(9*natsq)-1], 0.3636571159, 1.0e-9, "Hessian[21,21] does not match")) + goto error; + + xtb_delete(res); xtb_delete(calc); xtb_delete(mol); @@ -136,6 +269,7 @@ int testFirst() { free(q); free(wbo); free(buffer); + free(hess); tester = !res; if (!check(tester, 1, "Results not deleted")) diff --git a/test/api/meson.build b/test/api/meson.build index c13064796..3ef3c6e82 100644 --- a/test/api/meson.build +++ b/test/api/meson.build @@ -19,7 +19,10 @@ test( executable( 'xtb_c_test', sources: files('c_api_example.c'), - dependencies: xtb_dep_static + dependencies: xtb_dep_static, + c_args: [ + '-DWITH_CPCMX=@0@'.format(cpx_dep.found() ? 1 : 0), + ], ), env: xtbenv, ) diff --git a/test/unit/meson.build b/test/unit/meson.build index b2cd97758..32d23ebfd 100644 --- a/test/unit/meson.build +++ b/test/unit/meson.build @@ -74,6 +74,10 @@ tester = executable( 'tester', sources: test_srcs, dependencies: [xtb_dep_static, testdrive_dep], + fortran_args: [ + '-DWITH_TBLITE=@0@'.format(tblite_dep.found() ? 1 : 0), + '-DWITH_CPCMX=@0@'.format(cpx_dep.found() ? 1 : 0), + ], link_language: 'fortran', ) diff --git a/test/unit/test_docking.f90 b/test/unit/test_docking.f90 index 3802d0116..a92a5b3b5 100644 --- a/test/unit/test_docking.f90 +++ b/test/unit/test_docking.f90 @@ -29,14 +29,16 @@ subroutine collect_docking(testsuite) type(unittest_type), allocatable, intent(out) :: testsuite(:) testsuite = [ & - new_unittest("eth_wat", test_dock_eth_wat)]!, & -! new_unittest("ellips", test_iff_ellips), & -! ] + new_unittest("dock_gfn2_eth_wat", test_dock_eth_wat_gfn2), & + new_unittest("dock_gfn2_wat_wat_wall", test_dock_wat_wat_gfn2_wall), & + new_unittest("dock_gfn2_wat_wat_attpot", test_dock_wat_wat_gfn2_attpot), & + new_unittest("dock_gfnff_wat_wat", test_dock_wat_wat_gfnff) & + ] end subroutine collect_docking -subroutine test_dock_eth_wat(error) +subroutine test_dock_eth_wat_gfn2(error) use xtb_type_environment, only: TEnvironment, init use xtb_mctc_accuracy, only: wp use xtb_type_environment, only: TEnvironment @@ -112,8 +114,9 @@ subroutine test_dock_eth_wat(error) set%pr_local = .false. call precomp(env, iff_data, molA, molA_e, 1) - call check_(error, molA_e,-11.3943358674_wp, thr=thr) + call check_(error, molA_e,-11.39433586739173_wp, thr=thr) call precomp(env, iff_data, molB, molB_e, 2) + call check_(error, molB_e,-5.070201841808753_wp, thr=thr) call env%checkpoint("LMO computation failed") @@ -150,27 +153,492 @@ subroutine test_dock_eth_wat(error) & iff_data%den1, iff_data%den2, iff_data%gab1, iff_data%gab2, & & set%verbose, 0, e, icoord) - call check_(error, e,0.07745330953243718_wp, thr=thr) + call check_(error, e,.7745330953199690E-01_wp, thr=thr) call env%checkpoint("xtb-IFF sp computation failed") + optlvl="gfn2" call set_optlvl(env) !Sets the optimization level for search in global parameters -! call docking_search(env, molA, molB, n, n1, n2, at1, at2, neigh, xyz1,& -! & xyz2, q1, q2, c6ab, z1, z2,& -! &nlmo1, nlmo2, lmo1, lmo2, rlmo1, rlmo2,& -! &qdr1, qdr2, cn1, cn2, alp1, alp2, alpab, qct1, qct2,& -! &den1, den2, gab1, gab2, molA_e, molB_e,& -! &cprob, e, icoord, comb) -! call env%checkpoint("Docking algorithm failed") + !Settings for fast + maxparent = 30 + maxgen = 3 + mxcma = 250 + stepr = 4.0 + stepa = 60 + n_opt = 2 -! call check_(error, calc%topo%nbond,6) -! -! call check_(error, res_gff%e_total,-0.76480130317838_wp, thr=thr) + call docking_search(env, molA, molB, iff_data%n, iff_data%n1, iff_data%n2,& + & iff_data%at1, iff_data%at2, iff_data%neigh, iff_data%xyz1,& + & iff_data%xyz2, iff_data%q1, iff_data%q2, iff_data%c6ab,& + & iff_data%z1, iff_data%z2,& + & iff_data%nlmo1, iff_data%nlmo2, iff_data%lmo1,& + & iff_data%lmo2, iff_data%rlmo1, iff_data%rlmo2,& + & iff_data%qdr1, iff_data%qdr2, iff_data%cn1, iff_data%cn2, iff_data%alp1,& + & iff_data%alp2, iff_data%alpab, iff_data%qct1, iff_data%qct2,& + & iff_data%den1, iff_data%den2, iff_data%gab1, iff_data%gab2, molA_e, molB_e,& + & iff_data%cprob, e, icoord, comb) + + call env%checkpoint("Docking algorithm failed") + + call molA%deallocate + call molB%deallocate + +end subroutine test_dock_eth_wat_gfn2 + + +subroutine test_dock_wat_wat_gfn2_wall(error) + use xtb_type_environment, only: TEnvironment, init + use xtb_mctc_accuracy, only: wp + use xtb_type_environment, only: TEnvironment + use xtb_type_molecule + use xtb_setparam, only: initrand + use xtb_mctc_systools + use xtb_setmod + use xtb_docking_set_module + use xtb_docking_param + use xtb_iff_iffini, only: init_iff + use xtb_iff_iffprepare, only: precomp + use xtb_iff_iffenergy + use xtb_docking_search_nci, only: docking_search + use xtb_mctc_systools + use xtb_iff_data, only: TIFFData + use xtb_sphereparam, only: init_walls, maxwalls, set_sphere_radius,& + & spherepot_type, p_type_polynomial, clear_walls + + type(error_type), allocatable, intent(out) :: error + !> All important variables stored here + type(TIFFData) :: iff_data + real(wp),parameter :: thr = 1.0e-6_wp + real(wp) :: icoord0(6),icoord(6) + integer :: n1 + integer :: at1(3) + real(wp) :: xyz1(3,3) + integer :: n2 + integer :: at2(3) + real(wp) :: xyz2(3,3) + integer,parameter :: n = 6 + integer :: at(n) + real(wp) :: xyz(3,n) + real(wp) :: molA_e, molB_e + + logical, parameter :: restart = .false. + + type(TMolecule) :: molA,molB,comb + real(wp) :: r(3),e + integer :: i, j, k + type(TEnvironment) :: env + character(len=:), allocatable :: fnam + + logical :: exist + + n2 = 3 + at2 = [8,1,1] + xyz2 = reshape(& + &[-14.55824225787638_wp, 0.85763330814882_wp, 0.00000000000000_wp, & + & -12.72520790897730_wp, 0.85763330814882_wp, 0.00000000000000_wp, & + & -15.16924740842229_wp,-0.86379381534203_wp,-0.15285994688912_wp],& + & shape(xyz2)) + + n1=n2 + at1=at2 + xyz1=xyz2 + + qcg=.true. + call set_gbsa(env, 'solvent', "h2o") + call init(env) + + !Molecular stuff: + call init(molA, at1, xyz1) + call init(molB, at2, xyz2) + call iff_data%allocateIFFData(molA%n, molB%n) + + call initrand + + call set_iff_param + fnam = 'xtblmoinfo' + set%pr_local = .false. + + call precomp(env, iff_data, molA, molA_e, 1) +! call check_(error, molA_e,-5.084810260314862_wp, thr=thr) + call precomp(env, iff_data, molB, molB_e, 2) + call check_(error, molB_e,-5.08481026031486_wp, thr=thr) + + call env%checkpoint("LMO computation failed") + + call cmadock(molA%n, molA%n, molA%at, molA%xyz, r) + do i = 1, 3 + molA%xyz(i, 1:molA%n) = molA%xyz(i, 1:molA%n) - r(i) + end do + call cmadock(molB%n, molB%n, molB%at, molB%xyz, r) + do i = 1, 3 + molB%xyz(i, 1:molB%n) = molB%xyz(i, 1:molB%n) - r(i) + end do + + call init_iff(env, iff_data%n1, iff_data%n2, iff_data%at1, iff_data%at2,& + & iff_data%neigh, iff_data%xyz1, iff_data%xyz2, iff_data%q1, & + & iff_data%q2, iff_data%c6ab, iff_data%z1, iff_data%z2,& + & iff_data%cprob, iff_data%nlmo1, iff_data%nlmo2, iff_data%lmo1, iff_data%lmo2,& + & iff_data%qdr1, iff_data%qdr2, iff_data%rlmo1, iff_data%rlmo2,& + & iff_data%cn1, iff_data%cn2, iff_data%alp1, iff_data%alp2, iff_data%alpab,& + & iff_data%den1, iff_data%den2, iff_data%gab1, iff_data%gab2, iff_data%qcm1,& + & iff_data%qcm2, iff_data%n, iff_data%at, iff_data%xyz, iff_data%q, icoord, icoord0,& + & .false.) + + call check_(error, icoord(1) ,0.0000_wp, thr=1.0e-3_wp) + + !Wall potential stuff: + maxwalls=3 + call init_walls + spherepot_type = p_type_polynomial + call set_sphere_radius([6.7,4.7,3.8],[0.0,0.0,0.0],3,[1,2,3]) !"solute" + call set_sphere_radius([6.9,5.7,5.2],[0.0,0.0,0.0]) !"all" + + call env%checkpoint("Initializing xtb-IFF failed.") + + call iff_e(env, iff_data%n, iff_data%n1, iff_data%n2, iff_data%at1, iff_data%at2,& + & iff_data%neigh, iff_data%xyz1, iff_data%xyz2, iff_data%q1, iff_data%q2,& + & iff_data%c6ab, iff_data%z1, iff_data%z2,& + & iff_data%nlmo1, iff_data%nlmo2, iff_data%lmo1, iff_data%lmo2, & + & iff_data%rlmo1, iff_data%rlmo2,& + & iff_data%qdr1, iff_data%qdr2, iff_data%cn1, iff_data%cn2, iff_data%alp1, & + & iff_data%alp2, iff_data%alpab, iff_data%qct1, iff_data%qct2, & + & iff_data%den1, iff_data%den2, iff_data%gab1, iff_data%gab2, & + & set%verbose, 0, e, icoord) + + call env%checkpoint("xtb-IFF sp computation failed") + + optlvl="gfn2" + call set_optlvl(env) !Sets the optimization level for search in global parameters + + !Settings for fast + maxparent = 30 + maxgen = 3 + mxcma = 250 + stepr = 4.0 + stepa = 60 + n_opt = 2 + + call docking_search(env, molA, molB, iff_data%n, iff_data%n1, iff_data%n2,& + & iff_data%at1, iff_data%at2, iff_data%neigh, iff_data%xyz1,& + & iff_data%xyz2, iff_data%q1, iff_data%q2, iff_data%c6ab,& + & iff_data%z1, iff_data%z2,& + & iff_data%nlmo1, iff_data%nlmo2, iff_data%lmo1,& + & iff_data%lmo2, iff_data%rlmo1, iff_data%rlmo2,& + & iff_data%qdr1, iff_data%qdr2, iff_data%cn1, iff_data%cn2, iff_data%alp1,& + & iff_data%alp2, iff_data%alpab, iff_data%qct1, iff_data%qct2,& + & iff_data%den1, iff_data%den2, iff_data%gab1, iff_data%gab2, molA_e, molB_e,& + & iff_data%cprob, e, icoord, comb) + call env%checkpoint("Docking algorithm failed") + + call molA%deallocate + call molB%deallocate + call clear_walls + maxwalls=0 + +end subroutine test_dock_wat_wat_gfn2_wall + +subroutine test_dock_wat_wat_gfn2_attpot(error) + use xtb_type_environment, only: TEnvironment, init + use xtb_mctc_accuracy, only: wp + use xtb_type_environment, only: TEnvironment + use xtb_type_molecule + use xtb_setparam, only: initrand + use xtb_mctc_systools + use xtb_setmod + use xtb_docking_set_module + use xtb_docking_param + use xtb_iff_iffini, only: init_iff + use xtb_iff_iffprepare, only: precomp + use xtb_iff_iffenergy + use xtb_docking_search_nci, only: docking_search + use xtb_mctc_systools + use xtb_iff_data, only: TIFFData + use xtb_sphereparam, only: init_walls, maxwalls, set_sphere_radius,& + & spherepot_type, p_type_polynomial, clear_walls + + type(error_type), allocatable, intent(out) :: error + !> All important variables stored here + type(TIFFData) :: iff_data + real(wp),parameter :: thr = 1.0e-6_wp + real(wp) :: icoord0(6),icoord(6) + integer :: n1 + integer :: at1(3) + real(wp) :: xyz1(3,3) + integer :: n2 + integer :: at2(3) + real(wp) :: xyz2(3,3) + integer,parameter :: n = 6 + integer :: at(n) + real(wp) :: xyz(3,n) + real(wp) :: molA_e, molB_e + + logical, parameter :: restart = .false. + + type(TMolecule) :: molA,molB,comb + real(wp) :: r(3),e + integer :: i, j, k + type(TEnvironment) :: env + character(len=:), allocatable :: fnam + + logical :: exist + + n2 = 3 + at2 = [8,1,1] + xyz2 = reshape(& + &[-14.55824225787638_wp, 0.85763330814882_wp, 0.00000000000000_wp, & + & -12.72520790897730_wp, 0.85763330814882_wp, 0.00000000000000_wp, & + & -15.16924740842229_wp,-0.86379381534203_wp,-0.15285994688912_wp],& + & shape(xyz2)) + + n1=n2 + at1=at2 + xyz1=xyz2 + + qcg=.true. + call set_gbsa(env, 'solvent', "h2o") + call init(env) + + !Molecular stuff: + call init(molA, at1, xyz1) + call init(molB, at2, xyz2) + call iff_data%allocateIFFData(molA%n, molB%n) + + call initrand + + call set_iff_param + fnam = 'xtblmoinfo' + set%pr_local = .false. + + call precomp(env, iff_data, molA, molA_e, 1) +! call check_(error, molA_e,-5.084810260314862_wp, thr=thr) + call precomp(env, iff_data, molB, molB_e, 2) + call check_(error, molB_e,-5.08481026031486_wp, thr=thr) + + call env%checkpoint("LMO computation failed") + + call cmadock(molA%n, molA%n, molA%at, molA%xyz, r) + do i = 1, 3 + molA%xyz(i, 1:molA%n) = molA%xyz(i, 1:molA%n) - r(i) + end do + call cmadock(molB%n, molB%n, molB%at, molB%xyz, r) + do i = 1, 3 + molB%xyz(i, 1:molB%n) = molB%xyz(i, 1:molB%n) - r(i) + end do + + call init_iff(env, iff_data%n1, iff_data%n2, iff_data%at1, iff_data%at2,& + & iff_data%neigh, iff_data%xyz1, iff_data%xyz2, iff_data%q1, & + & iff_data%q2, iff_data%c6ab, iff_data%z1, iff_data%z2,& + & iff_data%cprob, iff_data%nlmo1, iff_data%nlmo2, iff_data%lmo1, iff_data%lmo2,& + & iff_data%qdr1, iff_data%qdr2, iff_data%rlmo1, iff_data%rlmo2,& + & iff_data%cn1, iff_data%cn2, iff_data%alp1, iff_data%alp2, iff_data%alpab,& + & iff_data%den1, iff_data%den2, iff_data%gab1, iff_data%gab2, iff_data%qcm1,& + & iff_data%qcm2, iff_data%n, iff_data%at, iff_data%xyz, iff_data%q, icoord, icoord0,& + & .false.) + + call check_(error, icoord(1) ,0.0000_wp, thr=1.0e-3_wp) + + directed_type = p_atom_qcg + allocate(directedset%expo(2), source=0.0_wp) + allocate(directedset%val(1), source=0.0_wp) + directedset%val(1)=0.011928 + directedset%expo(1)=0.01 + directedset%expo(2)=2.000 + directedset%n=3 + directedset%atoms=[1,2,3] + + call env%checkpoint("Initializing xtb-IFF failed.") + + call iff_e(env, iff_data%n, iff_data%n1, iff_data%n2, iff_data%at1, iff_data%at2,& + & iff_data%neigh, iff_data%xyz1, iff_data%xyz2, iff_data%q1, iff_data%q2,& + & iff_data%c6ab, iff_data%z1, iff_data%z2,& + & iff_data%nlmo1, iff_data%nlmo2, iff_data%lmo1, iff_data%lmo2, & + & iff_data%rlmo1, iff_data%rlmo2,& + & iff_data%qdr1, iff_data%qdr2, iff_data%cn1, iff_data%cn2, iff_data%alp1, & + & iff_data%alp2, iff_data%alpab, iff_data%qct1, iff_data%qct2, & + & iff_data%den1, iff_data%den2, iff_data%gab1, iff_data%gab2, & + & set%verbose, 0, e, icoord) + + call env%checkpoint("xtb-IFF sp computation failed") + + optlvl="gfn2" + call set_optlvl(env) !Sets the optimization level for search in global parameters + + !Settings for fast + maxparent = 30 + maxgen = 3 + mxcma = 250 + stepr = 4.0 + stepa = 60 + n_opt = 2 + + call docking_search(env, molA, molB, iff_data%n, iff_data%n1, iff_data%n2,& + & iff_data%at1, iff_data%at2, iff_data%neigh, iff_data%xyz1,& + & iff_data%xyz2, iff_data%q1, iff_data%q2, iff_data%c6ab,& + & iff_data%z1, iff_data%z2,& + & iff_data%nlmo1, iff_data%nlmo2, iff_data%lmo1,& + & iff_data%lmo2, iff_data%rlmo1, iff_data%rlmo2,& + & iff_data%qdr1, iff_data%qdr2, iff_data%cn1, iff_data%cn2, iff_data%alp1,& + & iff_data%alp2, iff_data%alpab, iff_data%qct1, iff_data%qct2,& + & iff_data%den1, iff_data%den2, iff_data%gab1, iff_data%gab2, molA_e, molB_e,& + & iff_data%cprob, e, icoord, comb) + call env%checkpoint("Docking algorithm failed") + + call molA%deallocate + call molB%deallocate + call directedset%deallocate + +end subroutine test_dock_wat_wat_gfn2_attpot + + +subroutine test_dock_wat_wat_gfnff(error) + use xtb_type_environment, only: TEnvironment, init + use xtb_mctc_accuracy, only: wp + use xtb_type_environment, only: TEnvironment + use xtb_type_molecule + use xtb_setparam, only: initrand + use xtb_mctc_systools + use xtb_setmod + use xtb_docking_set_module + use xtb_docking_param + use xtb_iff_iffini, only: init_iff + use xtb_iff_iffprepare, only: precomp + use xtb_iff_iffenergy + use xtb_docking_search_nci, only: docking_search + use xtb_mctc_systools + use xtb_iff_data, only: TIFFData + use xtb_mctc_global, only : persistentEnv + + type(error_type), allocatable, intent(out) :: error + !> All important variables stored here + type(TIFFData) :: iff_data + real(wp),parameter :: thr = 1.0e-6_wp + real(wp) :: icoord0(6),icoord(6) + integer :: n1 + integer :: at1(3) + real(wp) :: xyz1(3,3) + integer :: n2 + integer :: at2(3) + real(wp) :: xyz2(3,3) + integer,parameter :: n = 6 + integer :: at(n) + real(wp) :: xyz(3,n) + real(wp) :: molA_e, molB_e + + logical, parameter :: restart = .false. + + type(TMolecule) :: molA,molB,comb + real(wp) :: r(3),e + integer :: i, j, k + type(TEnvironment) :: env + character(len=:), allocatable :: fnam + + logical :: exist + + n2 = 3 + at2 = [8,1,1] + xyz2 = reshape(& + &[-14.55824225787638_wp, 0.85763330814882_wp, 0.00000000000000_wp, & + & -12.72520790897730_wp, 0.85763330814882_wp, 0.00000000000000_wp, & + & -15.16924740842229_wp,-0.86379381534203_wp,-0.15285994688912_wp],& + & shape(xyz2)) + + n1=n2 + at1=at2 + xyz1=xyz2 + + call set_gbsa(env, 'solvent', "h2o") + !GFN-FF + call set_exttyp('ff') + +! deallocate(persistentEnv%whoami) +! deallocate(persistentEnv%home) +! deallocate(persistentEnv%path) +! deallocate(persistentEnv%xtbpath) +! deallocate(persistentEnv%xtbhome) +! deallocate(persistentEnv%io%log) +! persistentEnv%io%count=0 + + + call init(env) + call init(molA, at1, xyz1) + call init(molB, at2, xyz2) + call iff_data%allocateIFFData(molA%n, molB%n) + + call initrand + + call set_iff_param + fnam = 'xtblmoinfo' + set%pr_local = .false. + + call precomp(env, iff_data, molA, molA_e, 1) +! call check_(error, molA_e,-5.084810260314862_wp, thr=thr) + call precomp(env, iff_data, molB, molB_e, 2) + call check_(error, molB_e,-5.08481026031486_wp, thr=thr) + + call env%checkpoint("LMO computation failed") + + call cmadock(molA%n, molA%n, molA%at, molA%xyz, r) + do i = 1, 3 + molA%xyz(i, 1:molA%n) = molA%xyz(i, 1:molA%n) - r(i) + end do + call cmadock(molB%n, molB%n, molB%at, molB%xyz, r) + do i = 1, 3 + molB%xyz(i, 1:molB%n) = molB%xyz(i, 1:molB%n) - r(i) + end do + + call init_iff(env, iff_data%n1, iff_data%n2, iff_data%at1, iff_data%at2,& + & iff_data%neigh, iff_data%xyz1, iff_data%xyz2, iff_data%q1, & + & iff_data%q2, iff_data%c6ab, iff_data%z1, iff_data%z2,& + & iff_data%cprob, iff_data%nlmo1, iff_data%nlmo2, iff_data%lmo1, iff_data%lmo2,& + & iff_data%qdr1, iff_data%qdr2, iff_data%rlmo1, iff_data%rlmo2,& + & iff_data%cn1, iff_data%cn2, iff_data%alp1, iff_data%alp2, iff_data%alpab,& + & iff_data%den1, iff_data%den2, iff_data%gab1, iff_data%gab2, iff_data%qcm1,& + & iff_data%qcm2, iff_data%n, iff_data%at, iff_data%xyz, iff_data%q, icoord, icoord0,& + & .false.) + + call check_(error, icoord(1) ,0.0000_wp, thr=1.0e-3_wp) + + call env%checkpoint("Initializing xtb-IFF failed.") + + call iff_e(env, iff_data%n, iff_data%n1, iff_data%n2, iff_data%at1, iff_data%at2,& + & iff_data%neigh, iff_data%xyz1, iff_data%xyz2, iff_data%q1, iff_data%q2,& + & iff_data%c6ab, iff_data%z1, iff_data%z2,& + & iff_data%nlmo1, iff_data%nlmo2, iff_data%lmo1, iff_data%lmo2, & + & iff_data%rlmo1, iff_data%rlmo2,& + & iff_data%qdr1, iff_data%qdr2, iff_data%cn1, iff_data%cn2, iff_data%alp1, & + & iff_data%alp2, iff_data%alpab, iff_data%qct1, iff_data%qct2, & + & iff_data%den1, iff_data%den2, iff_data%gab1, iff_data%gab2, & + & set%verbose, 0, e, icoord) + + call env%checkpoint("xtb-IFF sp computation failed") + + optlvl = "gfnff" + call set_optlvl(env) !Sets the optimization level for search in global parameters + + !Settings for fast + maxparent = 30 + maxgen = 3 + mxcma = 250 + stepr = 4.0 + stepa = 60 + n_opt = 2 + + call docking_search(env, molA, molB, iff_data%n, iff_data%n1, iff_data%n2,& + & iff_data%at1, iff_data%at2, iff_data%neigh, iff_data%xyz1,& + & iff_data%xyz2, iff_data%q1, iff_data%q2, iff_data%c6ab,& + & iff_data%z1, iff_data%z2,& + & iff_data%nlmo1, iff_data%nlmo2, iff_data%lmo1,& + & iff_data%lmo2, iff_data%rlmo1, iff_data%rlmo2,& + & iff_data%qdr1, iff_data%qdr2, iff_data%cn1, iff_data%cn2, iff_data%alp1,& + & iff_data%alp2, iff_data%alpab, iff_data%qct1, iff_data%qct2,& + & iff_data%den1, iff_data%den2, iff_data%gab1, iff_data%gab2, molA_e, molB_e,& + & iff_data%cprob, e, icoord, comb) + call env%checkpoint("Docking algorithm failed") call molA%deallocate call molB%deallocate -end subroutine test_dock_eth_wat +end subroutine test_dock_wat_wat_gfnff end module test_docking diff --git a/test/unit/test_ptb.F90 b/test/unit/test_ptb.F90 index 16c14cbe4..5e585f90d 100644 --- a/test/unit/test_ptb.F90 +++ b/test/unit/test_ptb.F90 @@ -186,12 +186,37 @@ subroutine test_ptb_overlap(error) !> (Scaled) overlap matrix character(len=:), allocatable :: message real(wp), parameter :: overlap_exp(6) = [ & - & 0.93209460_wp, & ! 1,2 - & 0.35489609_wp, & ! 1,3 - & 0.65682608_wp, & ! 2,3 - & 0.05627743_wp, & ! 1,15 - & -0.14217162_wp, & ! 1,24; diffferent because of tblite ordering - & 0.41844087_wp] ! 14,23; diffferent because of tblite ordering + & 0.93209460_wp, & ! s(Mg)-s(Mg) + & 0.35489609_wp, & ! s(Mg)-s(Mg) + & 0.65682608_wp, & ! s(Mg)-s(Mg) + & 0.05627743_wp, & ! s(Mg)-s(H) + & -0.14217162_wp, & ! s(Mg)-pz(H) + & 0.41844087_wp] ! dyz(Mg)-py(H) + ! 1: s(Mg) + ! 2: s(Mg) + ! 3: s(Mg) + ! 4: py(Mg) + ! 5: pz(Mg) + ! 6: px(Mg) + ! 7: py(Mg) + ! 8: pz(Mg) + ! 9: px(Mg) + ! 10: dxy(Mg) + ! 11: dyz(Mg) + ! 12: dz2(Mg) + ! 13: dxz(Mg) + ! 14: dx2-y2(Mg) + ! 15: s(H) + ! 16: s(H) + ! 17: py(H) + ! 18: pz(H) + ! 19: px(H) + ! 20: s(H) + ! 21: s(H) + ! 22: py(H) + ! 23: pz(H) + ! 24: px(H) + real(wp), allocatable :: lattr(:, :) real(wp) :: cutoff @@ -215,7 +240,7 @@ subroutine test_ptb_overlap(error) call check_(error, ints%overlap(2, 3), overlap_exp(3), thr=thr) call check_(error, ints%overlap(1, 15), overlap_exp(4), thr=thr) call check_(error, ints%overlap(1, 23), overlap_exp(5), thr=thr) - call check_(error, ints%overlap(12, 22), overlap_exp(6), thr=thr) + call check_(error, ints%overlap(11, 22), overlap_exp(6), thr=thr) end subroutine test_ptb_overlap @@ -249,12 +274,37 @@ subroutine test_ptb_overlap_h0(error) type(error_type), allocatable, intent(out) :: error character(len=:), allocatable :: message real(wp), parameter :: overlap_exp(6) = [ & - & 0.95689468_wp, & ! 1,2 - & 0.39195790_wp, & ! 1,3 - & 0.62961212_wp, & ! 2,3 - & 0.03782850_wp, & ! 1,15 - &-0.13826216_wp, & ! 1,24; diffferent because of tblite ordering - & 0.43334922_wp] ! 14,23; diffferent because of tblite ordering + & 0.95689468_wp, & ! s(Mg)-s(Mg) + & 0.39195790_wp, & ! s(Mg)-s(Mg) + & 0.62961212_wp, & ! s(Mg)-s(Mg) + & 0.03782850_wp, & ! s(Mg)-s(H) + &-0.13826216_wp, & ! s(Mg)-pz(H) + & 0.43334922_wp] ! dyz(Mg)-py(H) + ! 1: s(Mg) + ! 2: s(Mg) + ! 3: s(Mg) + ! 4: py(Mg) + ! 5: pz(Mg) + ! 6: px(Mg) + ! 7: py(Mg) + ! 8: pz(Mg) + ! 9: px(Mg) + ! 10: dxy(Mg) + ! 11: dyz(Mg) + ! 12: dz2(Mg) + ! 13: dxz(Mg) + ! 14: dx2-y2(Mg) + ! 15: s(H) + ! 16: s(H) + ! 17: py(H) + ! 18: pz(H) + ! 19: px(H) + ! 20: s(H) + ! 21: s(H) + ! 22: py(H) + ! 23: pz(H) + ! 24: px(H) + real(wp), allocatable :: lattr(:, :) real(wp) :: cutoff @@ -286,7 +336,7 @@ subroutine test_ptb_overlap_h0(error) & message=message) call check_(error, auxints%overlap_h0_1(1, 23), overlap_exp(5), thr=thr, & & message=message) - call check_(error, auxints%overlap_h0_1(12, 22), overlap_exp(6), thr=thr, & + call check_(error, auxints%overlap_h0_1(11, 22), overlap_exp(6), thr=thr, & & message=message) end subroutine test_ptb_overlap_h0 @@ -319,12 +369,37 @@ subroutine test_ptb_overlap_SX(error) real(wp), allocatable :: overlap_sx(:, :), overlap_oneminusx(:, :) character(len=:), allocatable :: message real(wp), parameter :: overlap_oneminusx_exp(6) = [ & - & 0.70788_wp, & ! 1,2 - & 0.16203_wp, & ! 1,3 - & 0.41532_wp, & ! 2,3 - & 0.01449_wp, & ! 1,15 - &-0.07203_wp, & ! 1,24; diffferent because of tblite ordering - & 0.28751_wp] ! 14,23; diffferent because of tblite ordering + & 0.70788_wp, & ! s(Mg)-s(Mg) + & 0.16203_wp, & ! s(Mg)-s(Mg) + & 0.41532_wp, & ! s(Mg)-s(Mg) + & 0.01449_wp, & ! s(Mg)-s(H) + &-0.07203_wp, & ! s(Mg)-pz(H) + & 0.28751_wp] ! dyz(Mg)-py(H) + ! 1: s(Mg) + ! 2: s(Mg) + ! 3: s(Mg) + ! 4: py(Mg) + ! 5: pz(Mg) + ! 6: px(Mg) + ! 7: py(Mg) + ! 8: pz(Mg) + ! 9: px(Mg) + ! 10: dxy(Mg) + ! 11: dyz(Mg) + ! 12: dz2(Mg) + ! 13: dxz(Mg) + ! 14: dx2-y2(Mg) + ! 15: s(H) + ! 16: s(H) + ! 17: py(H) + ! 18: pz(H) + ! 19: px(H) + ! 20: s(H) + ! 21: s(H) + ! 22: py(H) + ! 23: pz(H) + ! 24: px(H) + real(wp), allocatable :: lattr(:, :) real(wp) :: cutoff @@ -356,7 +431,7 @@ subroutine test_ptb_overlap_SX(error) & message=message) call check_(error, overlap_oneminusx(1, 23), overlap_oneminusx_exp(5), thr=thr2, & & message=message) - call check_(error, overlap_oneminusx(12, 22), overlap_oneminusx_exp(6), thr=thr2, & + call check_(error, overlap_oneminusx(11, 22), overlap_oneminusx_exp(6), thr=thr2, & & message=message) end subroutine test_ptb_overlap_SX @@ -392,10 +467,37 @@ subroutine test_ptb_V_ECP(error) type(error_type), allocatable, intent(out) :: error character(len=:), allocatable :: message real(wp), parameter :: vecp_ref(4) = [ & - & 0.077719_wp, & ! 1,1 ; diffferent because of tblite ordering - & -0.059122_wp, & ! 1,3 ; diffferent because of tblite ordering - & 0.052775_wp, & ! 3,5 ; diffferent because of tblite ordering - & 0.117176_wp] ! 9,9 ; diffferent because of tblite ordering + & 0.077719_wp, & ! s(B)-s(B) + & -0.059122_wp, & ! s(B)-px(B) + & 0.052775_wp, & ! px(B)-px(B) + & 0.117176_wp] ! dx2-y2(B)-dx2-y2(B) + ! 1: s(B) + ! 2: s(B) + ! 3: py(B) + ! 4: pz(B) + ! 5: px(B) + ! 6: py(B) + ! 7: pz(B) + ! 8: px(B) + ! 9: dxy(B) + ! 10: dyz(B) + ! 11: dz2(B) + ! 12: dxz(B) + ! 13: dx2-y2(B) + ! 14: s(Cl) + ! 15: s(Cl) + ! 16: py(Cl) + ! 17: pz(Cl) + ! 18: px(Cl) + ! 19: py(Cl) + ! 20: pz(Cl) + ! 21: px(Cl) + ! 22: dxy(Cl) + ! 23: dyz(Cl) + ! 24: dz2(Cl) + ! 25: dxz(Cl) + ! 26: dx2-y2(Cl) + real(wp), parameter :: xyz(3, 2) = reshape([ & & 2.0_wp, 0.0_wp, 0.0_wp, & & 0.0_wp, 0.0_wp, 0.0_wp], [3, 2]) @@ -434,7 +536,7 @@ subroutine test_ptb_V_ECP(error) & message=message) call check_(error, vecp(5, 8), vecp_ref(3), thr=thr2, & & message=message) - call check_(error, vecp(12, 12), vecp_ref(4), thr=thr2, & + call check_(error, vecp(13, 13), vecp_ref(4), thr=thr2, & & message=message) end subroutine test_ptb_V_ECP @@ -629,12 +731,39 @@ subroutine test_ptb_hamiltonian_h0(error) real(wp), allocatable :: vecp(:, :) real(wp), parameter :: h0_ref(6) = [ & - & -1.59330281_wp, & ! 1,1 - & -2.24996207_wp, & ! 1,2 - & 0.34974782_wp, & ! 1,23 ; diffferent because of tblite ordering - & 0.0_wp, & ! 7,11 ; different because of tblite ordering - & -1.17757007_wp, & ! 3,6 ; different because of tblite ordering - & 0.48301561_wp] ! 11,24 ; diffferent because of tblite ordering + & -1.59330281_wp, & ! s(B)-s(B) + & -2.24996207_wp, & ! s(B)-s(B) + & 0.34974782_wp, & ! s(B)-py(Cl) + & 0.0_wp, & ! dx2-y2(B)-py(B) + & -1.17757007_wp, & ! px(B)-px(B) + & 0.48301561_wp] ! dxy(B)-dxy(Cl) + ! 1: s(B) + ! 2: s(B) + ! 3: py(B) + ! 4: pz(B) + ! 5: px(B) + ! 6: py(B) + ! 7: pz(B) + ! 8: px(B) + ! 9: dxy(B) + ! 10: dyz(B) + ! 11: dz2(B) + ! 12: dxz(B) + ! 13: dx2-y2(B) + ! 14: s(Cl) + ! 15: s(Cl) + ! 16: py(Cl) + ! 17: pz(Cl) + ! 18: px(Cl) + ! 19: py(Cl) + ! 20: pz(Cl) + ! 21: px(Cl) + ! 22: dxy(Cl) + ! 23: dyz(Cl) + ! 24: dz2(Cl) + ! 25: dxz(Cl) + ! 26: dx2-y2(Cl) + real(wp), parameter :: levels(10) = [ & & -0.796651404_wp, & & -0.269771638_wp, & @@ -665,15 +794,16 @@ subroutine test_ptb_hamiltonian_h0(error) & alpha_scal=id_to_atom(mol, ptbData%hamiltonian%kalphah0l)) allocate (vecp(bas%nao, bas%nao), source=0.0_wp) + ints%hamiltonian = 0.0_wp call get_hamiltonian(mol, list, bas, ptbData%hamiltonian, ptbData%hamiltonian%kla, auxints%overlap_h0_1, & & levels, ints%hamiltonian, ptbGlobals%kpol, ptbGlobals%kitr, ptbGlobals%kitocod) message = "H0 matrix element not matching to expected value." call check_(error, ints%hamiltonian(1, 1), h0_ref(1), thr=thr) call check_(error, ints%hamiltonian(1, 2), h0_ref(2), thr=thr) - call check_(error, ints%hamiltonian(1, 22), h0_ref(3), thr=thr) + call check_(error, ints%hamiltonian(1, 24), h0_ref(3), thr=thr) call check_(error, ints%hamiltonian(13, 6), h0_ref(4), thr=thr) call check_(error, ints%hamiltonian(8, 5), h0_ref(5), thr=thr) - call check_(error, ints%hamiltonian(13, 26), h0_ref(6), thr=thr) + call check_(error, ints%hamiltonian(9, 22), h0_ref(6), thr=thr) end subroutine test_ptb_hamiltonian_h0 subroutine test_ptb_V_XC(error) @@ -708,10 +838,37 @@ subroutine test_ptb_V_XC(error) type(error_type), allocatable, intent(out) :: error character(len=:), allocatable :: message real(wp), parameter :: Vxc_ref(4) = [ & - & -0.92793357_wp, & ! 1,1 - & -0.85981333_wp, & ! 1,2 - & 0.06632750_wp, & ! 1,23 ; diffferent because of tblite ordering - & 0.00151880_wp] ! 11,24 ; diffferent because of tblite ordering + & -0.92793357_wp, & ! s(B)-s(B) + & -0.85981333_wp, & ! s(B)-s(B) + & 0.06632750_wp, & ! s(B)-dz2(Cl) + & 0.00151880_wp] ! dxy(B)-dxy(Cl) + ! 1: s(B) + ! 2: s(B) + ! 3: py(B) + ! 4: pz(B) + ! 5: px(B) + ! 6: py(B) + ! 7: pz(B) + ! 8: px(B) + ! 9: dxy(B) + ! 10: dyz(B) + ! 11: dz2(B) + ! 12: dxz(B) + ! 13: dx2-y2(B) + ! 14: s(Cl) + ! 15: s(Cl) + ! 16: py(Cl) + ! 17: pz(Cl) + ! 18: px(Cl) + ! 19: py(Cl) + ! 20: pz(Cl) + ! 21: px(Cl) + ! 22: dxy(Cl) + ! 23: dyz(Cl) + ! 24: dz2(Cl) + ! 25: dxz(Cl) + ! 26: dx2-y2(Cl) + real(wp), parameter :: xyz(3, 2) = reshape([ & & 2.0_wp, 0.0_wp, 0.0_wp, & & 0.0_wp, 0.0_wp, 0.0_wp], [3, 2]) @@ -769,9 +926,9 @@ subroutine test_ptb_V_XC(error) & message=message) call check_(error, Vxc(1, 2), Vxc_ref(2), thr=thr, & & message=message) - call check_(error, Vxc(1, 22), Vxc_ref(3), thr=thr, & + call check_(error, Vxc(1, 24), Vxc_ref(3), thr=thr, & & message=message) - call check_(error, Vxc(13, 26), Vxc_ref(4), thr=thr, & + call check_(error, Vxc(9, 22), Vxc_ref(4), thr=thr, & & message=message) end subroutine test_ptb_V_XC @@ -957,10 +1114,35 @@ subroutine test_ptb_coulomb_potential(error) !> Conversion factor from temperature to energy real(wp), parameter :: kt = 3.166808578545117e-06_wp real(wp), parameter :: coulomb_pot_ref(4) = [ & - & -0.05693153_wp, & ! 1,1 - & -0.33917531_wp, & ! 1,2 - & -0.00539212_wp, & ! 1,21 ; diffferent because of tblite ordering - & 0.01305793_wp] ! 6,24 ; diffferent because of tblite ordering + & -0.05693153_wp, & ! s(Mg)-s(Mg) + & -0.33917531_wp, & ! s(Mg)-s(Mg) + & -0.00539212_wp, & ! s(Mg)-s(H) + & 0.01305793_wp] ! pz(Mg)-pz(H) + ! 1: s(Mg) + ! 2: s(Mg) + ! 3: s(Mg) + ! 4: py(Mg) + ! 5: pz(Mg) + ! 6: px(Mg) + ! 7: py(Mg) + ! 8: pz(Mg) + ! 9: px(Mg) + ! 10: dxy(Mg) + ! 11: dyz(Mg) + ! 12: dz2(Mg) + ! 13: dxz(Mg) + ! 14: dx2-y2(Mg) + ! 15: s(H) + ! 16: s(H) + ! 17: py(H) + ! 18: pz(H) + ! 19: px(H) + ! 20: s(H) + ! 21: s(H) + ! 22: py(H) + ! 23: pz(H) + ! 24: px(H) + real(wp), allocatable :: lattr(:, :) real(wp) :: cutoff @@ -1044,10 +1226,36 @@ subroutine test_ptb_plus_U_potential(error) integer, parameter :: nat = 2 integer, parameter :: at(nat) = [5, 17] real(wp), parameter :: plusU_pot_ref(4) = [ & - & -0.0023185_wp, & ! 1,1 - & -0.0018289_wp, & ! 1,2 - & -0.5266562_wp, & ! 1,21 ; diffferent because of tblite ordering - & -1.6745659_wp] ! 6,24 ; diffferent because of tblite ordering + & -0.0023185_wp, & ! s(B)-s(B) + & -0.0018289_wp, & ! s(B)-s(B) + & -0.5266562_wp, & ! s(B)-pz(Cl) + & -1.6745659_wp] ! px(B)-dxy(Cl) + ! 1: s(B) + ! 2: s(B) + ! 3: py(B) + ! 4: pz(B) + ! 5: px(B) + ! 6: py(B) + ! 7: pz(B) + ! 8: px(B) + ! 9: dxy(B) + ! 10: dyz(B) + ! 11: dz2(B) + ! 12: dxz(B) + ! 13: dx2-y2(B) + ! 14: s(Cl) + ! 15: s(Cl) + ! 16: py(Cl) + ! 17: pz(Cl) + ! 18: px(Cl) + ! 19: py(Cl) + ! 20: pz(Cl) + ! 21: px(Cl) + ! 22: dxy(Cl) + ! 23: dyz(Cl) + ! 24: dz2(Cl) + ! 25: dxz(Cl) + ! 26: dx2-y2(Cl) call new(mol, at, xyz) allocate (ptbData) @@ -1067,7 +1275,7 @@ subroutine test_ptb_plus_U_potential(error) call check_(error, wfn%coeff(1, 1, 1), plusU_pot_ref(1), thr=thr) call check_(error, wfn%coeff(1, 2, 1), plusU_pot_ref(2), thr=thr) call check_(error, wfn%coeff(1, 20, 1), plusU_pot_ref(3), thr=thr) - call check_(error, wfn%coeff(8, 26, 1), plusU_pot_ref(4), thr=thr) + call check_(error, wfn%coeff(8, 22, 1), plusU_pot_ref(4), thr=thr) end subroutine test_ptb_plus_U_potential diff --git a/test/unit/test_thermo.f90 b/test/unit/test_thermo.f90 index f1b676f5f..8da8499af 100644 --- a/test/unit/test_thermo.f90 +++ b/test/unit/test_thermo.f90 @@ -94,7 +94,7 @@ subroutine test_axis(error) call check(error, rot1(2), .226266337664493_wp, thr=thr2) call check(error, rot1(3), 7.01216792608729_wp, thr=thr2) - call axis2(mol%n, mol%at, mol%xyz, rot2(1), rot2(2), rot2(3), avmom2, mass2) + call axis2(mol%n, mol%xyz, rot2(1), rot2(2), rot2(3), avmom2, mass2) call check(error, rot2(1), .226251131473004_wp, thr=thr2) call check(error, rot2(2), .226266337664493_wp, thr=thr2) @@ -128,7 +128,7 @@ subroutine test_axis(error) call check(error, rot1(2), .19263614502269_wp, thr=thr2) call check(error, rot1(3), 4.7581644454539_wp, thr=thr2) - call axis2(mol%n, mol%at, mol%xyz, rot2(1), rot2(2), rot2(3), avmom2, mass2) + call axis2(mol%n, mol%xyz, rot2(1), rot2(2), rot2(3), avmom2, mass2) call check(error, rot2(1), .19017218374861_wp, thr=thr2) call check(error, rot2(2), .19263614502269_wp, thr=thr2) diff --git a/test/unit/test_vertical.f90 b/test/unit/test_vertical.f90 index d90321fbd..d724de9ec 100644 --- a/test/unit/test_vertical.f90 +++ b/test/unit/test_vertical.f90 @@ -59,10 +59,10 @@ subroutine test_gfn1_fukui(error) & -5.79274623699377_wp, 0.35153057534898_wp, -1.18447939588312_wp], & & shape(xyz)) real(wp), parameter :: fukui_ref(3, nat) = reshape([ & - & -0.471_wp, -0.150_wp, -0.310_wp, & - & -0.176_wp, -0.283_wp, -0.230_wp, & - & -0.176_wp, -0.283_wp, -0.230_wp, & - & -0.176_wp, -0.283_wp, -0.230_wp], & + & 0.471_wp, 0.150_wp, 0.310_wp, & + & 0.176_wp, 0.283_wp, 0.230_wp, & + & 0.176_wp, 0.283_wp, 0.230_wp, & + & 0.176_wp, 0.283_wp, 0.230_wp], & & shape(fukui_ref)) !real(wp), parameter :: step = 1.0e-6_wp @@ -110,10 +110,10 @@ subroutine test_gfn2_fukui(error) & -5.79274623699377_wp, 0.35153057534898_wp, -1.18447939588312_wp], & & shape(xyz)) real(wp), parameter :: fukui_ref(3, nat) = reshape([ & - & -0.300_wp, 0.005_wp, -0.148_wp, & - & -0.233_wp, -0.335_wp, -0.284_wp, & - & -0.233_wp, -0.335_wp, -0.284_wp, & - & -0.233_wp, -0.335_wp, -0.284_wp], & + & 0.300_wp, -0.005_wp, 0.148_wp, & + & 0.233_wp, 0.335_wp, 0.284_wp, & + & 0.233_wp, 0.335_wp, 0.284_wp, & + & 0.233_wp, 0.335_wp, 0.284_wp], & & shape(fukui_ref)) type(TMolecule) :: mol diff --git a/yamlfmt.yml b/yamlfmt.yml new file mode 100644 index 000000000..f95c104ba --- /dev/null +++ b/yamlfmt.yml @@ -0,0 +1,3 @@ +formatter: + type: basic + indent: 3