LCOV - code coverage report
Current view: top level - pairinteraction - GreenTensor.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 77 138 55.8 %
Date: 2024-04-29 00:41:50 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2019 Sebastian Weber, Henri Menke, Johannes Block. All rights reserved.
       3             :  *
       4             :  * This file is part of the pairinteraction library.
       5             :  *
       6             :  * The pairinteraction library is free software: you can redistribute it and/or modify
       7             :  * it under the terms of the GNU Lesser General Public License as published by
       8             :  * the Free Software Foundation, either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * The pairinteraction library is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public License
      17             :  * along with the pairinteraction library. If not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #include "GreenTensor.hpp"
      21             : 
      22             : #include "EigenCompat.hpp"
      23             : #include <Eigen/Core>
      24             : #include <unsupported/Eigen/CXX11/Tensor>
      25             : 
      26             : #include <limits>
      27             : 
      28             : using TensorType = GreenTensor::TensorType;
      29             : 
      30          42 : GreenTensor::GreenTensor(double x, double y, double z)
      31          42 :     : x(x), y(y), z(z), zA(std::numeric_limits<double>::max()),
      32          42 :       zB(std::numeric_limits<double>::max()), dd_tensor_calculated(false),
      33          42 :       dq_tensor_calculated(false), qd_tensor_calculated(false) {}
      34             : 
      35          37 : void GreenTensor::addSurface(double d) {
      36          37 :     if (y != 0) {
      37           0 :         throw std::runtime_error("The atoms must be in the xz-plane if a surface is present");
      38             :     }
      39             : 
      40          37 :     double angle = std::atan(x / z);
      41             : 
      42          37 :     zA = d - z * std::sin(angle) / 2.;
      43          37 :     zB = d + z * std::sin(angle) / 2.;
      44             : 
      45          37 :     if (zA < 0 || zB < 0) {
      46           0 :         throw std::runtime_error(
      47           0 :             "zA or zB < 0. One of the atoms is inside the plate. Plate is half-space z < 0.");
      48             :     }
      49             : 
      50          37 :     dd_tensor_calculated = false;
      51          37 :     dq_tensor_calculated = false;
      52          37 :     qd_tensor_calculated = false;
      53          37 : }
      54             : 
      55          42 : const Eigen::Matrix3<double> &GreenTensor::getDDTensor() {
      56          42 :     if (!dd_tensor_calculated) {
      57          42 :         dd_tensor = getDDTensorVacuum(x, y, z);
      58          42 :         if (zA != std::numeric_limits<double>::max()) {
      59          37 :             dd_tensor += getDDTensorPlate(x, zA, zB);
      60             :         }
      61          42 :         dd_tensor_calculated = true;
      62             :     }
      63             : 
      64          42 :     return dd_tensor;
      65             : }
      66             : 
      67           1 : const TensorType &GreenTensor::getDQTensor() {
      68           1 :     if (!dq_tensor_calculated) {
      69           1 :         dq_tensor = getDQTensorVacuum(x, y, z);
      70           1 :         if (zA != std::numeric_limits<double>::max()) {
      71           0 :             dq_tensor += getDQTensorPlate(x, zA, zB);
      72             :         }
      73           1 :         dq_tensor_calculated = true;
      74             :     }
      75           1 :     return dq_tensor;
      76             : }
      77             : 
      78           1 : const TensorType &GreenTensor::getQDTensor() {
      79           1 :     if (!qd_tensor_calculated) {
      80           1 :         qd_tensor = getQDTensorVacuum(x, y, z);
      81           1 :         if (zA != std::numeric_limits<double>::max()) {
      82           0 :             qd_tensor += getQDTensorPlate(x, zA, zB);
      83             :         }
      84           1 :         qd_tensor_calculated = true;
      85             :     }
      86           1 :     return qd_tensor;
      87             : }
      88             : 
      89          42 : Eigen::Matrix3<double> GreenTensor::getDDTensorVacuum(double x, double y, double z) const {
      90             :     // Build distance vector
      91          42 :     Eigen::Matrix<double, 3, 1> distance;
      92          42 :     distance << x, y, z;
      93             : 
      94             :     // Construct Green tensor
      95             :     Eigen::Matrix3<double> vacuum_tensor =
      96          42 :         -Eigen::MatrixXd::Identity(3, 3) / std::pow(distance.norm(), 3.) +
      97          84 :         3. * distance * distance.transpose() / std::pow(distance.norm(), 5.);
      98             : 
      99          84 :     return vacuum_tensor;
     100             : }
     101             : 
     102          37 : Eigen::Matrix3<double> GreenTensor::getDDTensorPlate(double x, double zA, double zB) const {
     103             :     // Calculate distances to mirror dipole
     104          37 :     double zp = zA + zB;
     105          37 :     double rp = std::sqrt(x * x + zp * zp);
     106             : 
     107             :     // Construct Green tensor
     108          37 :     Eigen::Matrix3<double> plate_tensor_second_matrix;
     109          37 :     plate_tensor_second_matrix << x * x, 0., -x * zp, 0., 0., 0., x * zp, 0., x * x;
     110             : 
     111             :     Eigen::Matrix3<double> plate_tensor =
     112          37 :         Eigen::Vector3<double>({1., 1., 2.}).asDiagonal().toDenseMatrix() / std::pow(rp, 3.) -
     113          74 :         3. * plate_tensor_second_matrix / std::pow(rp, 5);
     114             : 
     115          74 :     return plate_tensor;
     116             : }
     117             : 
     118           1 : TensorType GreenTensor::getDQTensorVacuum(double x, double y, double z) const {
     119           1 :     TensorType vacuum_tensor;
     120           1 :     vacuum_tensor.setZero();
     121             : 
     122           1 :     Eigen::Matrix3<double> Eye = Eigen::Matrix3<double>::Identity(3, 3);
     123           1 :     Eigen::Matrix<double, 3, 1> distance;
     124           1 :     distance << x, y, z;
     125           1 :     double dist = std::sqrt(x * x + y * y + z * z);
     126             : 
     127           4 :     for (int i = 0; i < 3; i++) {
     128          12 :         for (int j = 0; j < 3; j++) {
     129          36 :             for (int k = 0; k < 3; k++) {
     130          27 :                 vacuum_tensor(i, j, k) += -3 / std::pow(dist, 5.) *
     131          27 :                         (Eye(i, j) * distance(k) + distance(i) * Eye(j, k) +
     132          27 :                          distance(j) * Eye(i, k)) +
     133          27 :                     15. / std::pow(dist, 7.) * distance(i) * distance(j) * distance(k);
     134             :             }
     135             :         }
     136             :     }
     137             : 
     138           2 :     return vacuum_tensor;
     139             : }
     140             : 
     141           1 : TensorType GreenTensor::getQDTensorVacuum(double x, double y, double z) const {
     142           1 :     TensorType vacuum_tensor;
     143           1 :     vacuum_tensor.setZero();
     144             : 
     145           1 :     Eigen::Matrix3<double> Eye = Eigen::Matrix3<double>::Identity(3, 3);
     146           1 :     Eigen::Matrix<double, 3, 1> distance;
     147           1 :     distance << x, y, z;
     148           1 :     double dist = std::sqrt(x * x + y * y + z * z);
     149             : 
     150           4 :     for (int i = 0; i < 3; i++) {
     151          12 :         for (int j = 0; j < 3; j++) {
     152          36 :             for (int k = 0; k < 3; k++) {
     153             : 
     154          27 :                 vacuum_tensor(i, j, k) += 3 / std::pow(dist, 5.) *
     155          27 :                         (distance(i) * Eye(j, k) + Eye(i, j) * distance(k) +
     156          27 :                          Eye(i, k) * distance(j)) -
     157          27 :                     15. / std::pow(dist, 7.) * distance(i) * distance(j) * distance(k);
     158             :             }
     159             :         }
     160             :     }
     161             : 
     162           2 :     return vacuum_tensor;
     163             : }
     164             : 
     165           0 : TensorType GreenTensor::getDQTensorPlate(double x, double zA, double zB) const {
     166           0 :     TensorType plate_tensor;
     167           0 :     plate_tensor.setZero();
     168             : 
     169           0 :     double zp = zA + zB;
     170           0 :     Eigen::Matrix<double, 3, 1> distanceplus;
     171           0 :     distanceplus << -x, 0., zp;
     172           0 :     double rp = distanceplus.norm();
     173             : 
     174             :     Eigen::Matrix3<double> plate_tensor_first_matrix =
     175           0 :         Eigen::Vector3<double>({1., 1., 2.}).asDiagonal().toDenseMatrix();
     176           0 :     Eigen::Matrix3<double> plate_tensor_second_matrix;
     177           0 :     plate_tensor_second_matrix << x * x, 0., -x * zp, 0., 0., 0., x * zp, 0., x * x;
     178             : 
     179           0 :     TensorType plate_tensor_second_gradient;
     180           0 :     plate_tensor_second_gradient.setZero();
     181           0 :     plate_tensor_second_gradient(0, 0, 0) = -2. * x;
     182           0 :     plate_tensor_second_gradient(2, 2, 0) = -2. * x;
     183           0 :     plate_tensor_second_gradient(0, 2, 0) = zp;
     184           0 :     plate_tensor_second_gradient(2, 0, 0) = -zp;
     185           0 :     plate_tensor_second_gradient(0, 2, 2) = -x;
     186           0 :     plate_tensor_second_gradient(2, 0, 2) = x;
     187             : 
     188           0 :     for (int i = 0; i < 3; i++) {
     189           0 :         for (int j = 0; j < 3; j++) {
     190           0 :             for (int k = 0; k < 3; k++) {
     191           0 :                 plate_tensor(i, j, k) +=
     192           0 :                     -3. * plate_tensor_first_matrix(i, j) * distanceplus(k) / std::pow(rp, 5.);
     193           0 :                 plate_tensor(i, j, k) +=
     194           0 :                     15. * plate_tensor_second_matrix(i, j) * distanceplus(k) / std::pow(rp, 7.);
     195           0 :                 plate_tensor(i, j, k) +=
     196           0 :                     -3. * plate_tensor_second_gradient(i, j, k) / std::pow(rp, 5.);
     197             :             }
     198             :         }
     199             :     }
     200             : 
     201           0 :     return plate_tensor;
     202             : }
     203             : 
     204           0 : TensorType GreenTensor::getQDTensorPlate(double x, double zA, double zB) const {
     205           0 :     TensorType plate_tensor;
     206           0 :     plate_tensor.setZero();
     207             : 
     208           0 :     double zp = zA + zB;
     209           0 :     Eigen::Matrix<double, 3, 1> distanceplus;
     210           0 :     distanceplus << x, 0., zp;
     211           0 :     double rp = distanceplus.norm();
     212             : 
     213             :     Eigen::Matrix3<double> plate_tensor_first_matrix =
     214           0 :         Eigen::Vector3<double>({1., 1., 2.}).asDiagonal().toDenseMatrix();
     215           0 :     Eigen::Matrix3<double> plate_tensor_second_matrix;
     216           0 :     plate_tensor_second_matrix << x * x, 0., -x * zp, 0., 0., 0., x * zp, 0., x * x;
     217             : 
     218           0 :     TensorType gradient_plate_tensor_second;
     219           0 :     gradient_plate_tensor_second.setZero();
     220           0 :     gradient_plate_tensor_second(0, 0, 0) = 2. * x;
     221           0 :     gradient_plate_tensor_second(0, 2, 2) = 2. * x;
     222           0 :     gradient_plate_tensor_second(0, 0, 2) = -zp;
     223           0 :     gradient_plate_tensor_second(0, 2, 0) = zp;
     224           0 :     gradient_plate_tensor_second(2, 0, 2) = -x;
     225           0 :     gradient_plate_tensor_second(2, 2, 0) = x;
     226             : 
     227           0 :     for (int i = 0; i < 3; i++) {
     228           0 :         for (int j = 0; j < 3; j++) {
     229           0 :             for (int k = 0; k < 3; k++) {
     230           0 :                 plate_tensor(i, j, k) +=
     231           0 :                     -3. * distanceplus(i) * plate_tensor_first_matrix(j, k) / std::pow(rp, 5.);
     232           0 :                 plate_tensor(i, j, k) +=
     233           0 :                     15. * distanceplus(i) * plate_tensor_second_matrix(j, k) / std::pow(rp, 7.);
     234           0 :                 plate_tensor(i, j, k) +=
     235           0 :                     -3. * gradient_plate_tensor_second(i, j, k) / std::pow(rp, 5.);
     236             :             }
     237             :         }
     238             :     }
     239             : 
     240           0 :     return plate_tensor;
     241             : }

Generated by: LCOV version 1.14