diff --git a/doc/users/user_ref.rst b/doc/users/user_ref.rst index dafff9294..eab00a744 100644 --- a/doc/users/user_ref.rst +++ b/doc/users/user_ref.rst @@ -458,6 +458,33 @@ User input reference **Default** ``user['GeometryOptimizer']['run']`` + :Forces: Define parameters for the computation of forces. + + :red:`Keywords` + :method: Method for computing forces. ``surface_integrals`` (more accurate) uses surface integrals over the quantum mechanical stress tensor, while ``hellmann_feynman`` uses the Hellmann-Feynman theorem. + + **Type** ``str`` + + **Default** ``surface_integrals`` + + **Predicates** + - ``value.lower() in ['surface_integrals', 'hellmann_feynman']`` + + :surface_integral_precision: Precision of the surface integrals used in the computation of forces. Determines the number of Lebedev grid points used in the surface integration. + + **Type** ``str`` + + **Default** ``medium`` + + **Predicates** + - ``value.lower() in ['low', 'medium', 'high']`` + + :radius_factor: Sets the radius of the surface used in the computation of forces. The radius is given by this factor times the distance to the neariest neighbour. Must be between 0.1 and 0.9. This should rarely need to be changed. Different values can change the accuracy of the forces. + + **Type** ``float`` + + **Default** ``0.5`` + :ExternalFields: Define external electromagnetic fields. :red:`Keywords` @@ -12227,4 +12254,4 @@ User input reference **Type** ``float`` **Default** ``0.00011186082063`` - \ No newline at end of file + diff --git a/python/mrchem/helpers.py b/python/mrchem/helpers.py index de7731dc8..90e767436 100644 --- a/python/mrchem/helpers.py +++ b/python/mrchem/helpers.py @@ -287,7 +287,7 @@ def write_scf_solver(user_dict, wf_dict): def write_scf_properties(user_dict, origin): prop_dict = {} if user_dict["Properties"]["dipole_moment"]: - prop_dict["dipole_moment"] = {} + prop_dict["dipole_moment"] = {} prop_dict["dipole_moment"]["dip-1"] = { "operator": "h_e_dip", "precision": user_dict["world_prec"], @@ -306,6 +306,9 @@ def write_scf_properties(user_dict, origin): "operator": "h_nuc_grad", "precision": user_dict["world_prec"], "smoothing": user_dict["Precisions"]["nuclear_prec"], + "method": user_dict["Forces"]["method"], + "surface_integral_precision": user_dict["Forces"]["surface_integral_precision"], + "radius_factor": user_dict["Forces"]["radius_factor"], } if user_dict["Properties"]["hirshfeld_charges"]: prop_dict["hirshfeld_charges"] = {} diff --git a/python/mrchem/input_parser/api.py b/python/mrchem/input_parser/api.py index d16a573ac..3388ca232 100644 --- a/python/mrchem/input_parser/api.py +++ b/python/mrchem/input_parser/api.py @@ -370,6 +370,24 @@ def stencil() -> JSONDict: 'name': 'geometric_derivative', 'type': 'bool'}], 'name': 'Properties'}, + { 'keywords': [ { 'default': 'surface_integrals', + 'name': 'method', + 'predicates': [ 'value.lower() ' + 'in ' + "['surface_integrals', " + "'hellmann_feynman']"], + 'type': 'str'}, + { 'default': 'medium', + 'name': 'surface_integral_precision', + 'predicates': [ 'value.lower() ' + "in ['low', " + "'medium', " + "'high']"], + 'type': 'str'}, + { 'default': 0.5, + 'name': 'radius_factor', + 'type': 'float'}], + 'name': 'Forces'}, { 'keywords': [ { 'default': [], 'name': 'electric_field', 'predicates': [ 'len(value) == 0 ' diff --git a/python/mrchem/input_parser/docs/user_ref.rst b/python/mrchem/input_parser/docs/user_ref.rst index dafff9294..0f6ed3435 100644 --- a/python/mrchem/input_parser/docs/user_ref.rst +++ b/python/mrchem/input_parser/docs/user_ref.rst @@ -458,6 +458,33 @@ User input reference **Default** ``user['GeometryOptimizer']['run']`` + :Forces: Define parameters for the computation of forces. + + :red:`Keywords` + :method: Method for computing forces. ``surface_integrals`` (more accurate) uses surface integrals over the quantum mechanical stress tensor, while ``hellmann_feynman`` uses the Hellmann-Feynman theorem. + + **Type** ``str`` + + **Default** ``surface_integrals`` + + **Predicates** + - ``value.lower() in ['surface_integrals', 'hellmann_feynman']`` + + :surface_integral_precision: Precision of the surface integrals used in the computation of forces. Determines the number of Lebedev grid points used in the surface integration. + + **Type** ``str`` + + **Default** ``medium`` + + **Predicates** + - ``value.lower() in ['low', 'medium', 'high']`` + + :radius_factor: Sets the radius of the surface used in the computation of forces. The radius is given by this factor times the distance to the neariest neighbour. Must be between 0.1 and 0.9. This should rarely need to be changed. Different values can change the accuracy of the forces. + + **Type** ``float`` + + **Default** ``0.6`` + :ExternalFields: Define external electromagnetic fields. :red:`Keywords` diff --git a/python/template.yml b/python/template.yml index 86735123c..b382b8575 100644 --- a/python/template.yml +++ b/python/template.yml @@ -416,6 +416,34 @@ sections: default: false docstring: | Compute Hirshfeld charges. + - name: Forces + docstring: | + Define parameters for the computation of forces. + keywords: + - name: method + type: str + default: surface_integrals + predicates: + - value.lower() in ['surface_integrals', 'hellmann_feynman'] + docstring: | + Method for computing forces. ``surface_integrals`` (more accurate) uses surface + integrals over the quantum mechanical stress tensor, while ``hellmann_feynman`` uses the Hellmann-Feynman + theorem. + - name: surface_integral_precision + type: str + default: medium + predicates: + - value.lower() in ['low', 'medium', 'high'] + docstring: | + Precision of the surface integrals used in the computation of forces. Determines the number of Lebedev grid points used in the + surface integration. + - name: radius_factor + type: float + default: 0.5 + docstring: | + Sets the radius of the surface used in the computation of forces. + The radius is given by this factor times the distance to the neariest neighbour. Must be between 0.1 and 0.9. + This should rarely need to be changed. Different values can change the accuracy of the forces. - name: ExternalFields docstring: | Define external electromagnetic fields. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 696092ddc..aec3eae2b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,15 +36,13 @@ add_subdirectory(properties) add_subdirectory(qmfunctions) add_subdirectory(qmoperators) add_subdirectory(scf_solver) +add_subdirectory(surface_forces) add_subdirectory(tensor) add_subdirectory(utils) -target_compile_definitions(mrchem PRIVATE +target_compile_definitions(mrchem PRIVATE HIRSHFELD_SOURCE_DIR="${HIRSHFELD_SOURCE_DIR}" HIRSHFELD_INSTALL_DIR="${HIRSHFELD_INSTALL_DIR}" -) - -target_compile_definitions(mrchem PRIVATE AZORA_POTENTIALS_SOURCE_DIR="${AZORA_POTENTIALS_SOURCE_DIR}" AZORA_POTENTIALS_INSTALL_DIR="${AZORA_POTENTIALS_INSTALL_DIR}" ) diff --git a/src/driver.cpp b/src/driver.cpp index a87e04e7b..49e4629af 100644 --- a/src/driver.cpp +++ b/src/driver.cpp @@ -83,7 +83,7 @@ #include "environment/LPBESolver.h" #include "environment/PBESolver.h" #include "environment/Permittivity.h" - +#include "surface_forces/SurfaceForce.h" #include "properties/hirshfeld/HirshfeldPartition.h" #include "mrdft/Factory.h" @@ -117,7 +117,7 @@ namespace scf { bool guess_orbitals(const json &input, Molecule &mol); bool guess_energy(const json &input, Molecule &mol, FockBuilder &F); void write_orbitals(const json &input, Molecule &mol); -void calc_properties(const json &input, Molecule &mol); +void calc_properties(const json &input, Molecule &mol, const json &json_fock); void plot_quantities(const json &input, Molecule &mol); } // namespace scf @@ -318,7 +318,7 @@ json driver::scf::run(const json &json_scf, Molecule &mol) { if (json_out["success"]) { if (json_scf.contains("write_orbitals")) scf::write_orbitals(json_scf["write_orbitals"], mol); - if (json_scf.contains("properties")) scf::calc_properties(json_scf["properties"], mol); + if (json_scf.contains("properties")) scf::calc_properties(json_scf["properties"], mol, json_fock); if (json_scf.contains("plots")) scf::plot_quantities(json_scf["plots"], mol); } @@ -471,7 +471,7 @@ void driver::scf::write_orbitals(const json &json_orbs, Molecule &mol) { * input section, and will compute all properties which are present in this input. * This includes the diamagnetic contributions to the magnetic response properties. */ -void driver::scf::calc_properties(const json &json_prop, Molecule &mol) { +void driver::scf::calc_properties(const json &json_prop, Molecule &mol, const json &json_fock) { Timer t_tot, t_lap; auto plevel = Printer::getPrintLevel(); if (plevel == 1) mrcpp::print::header(1, "Computing ground state properties"); @@ -519,12 +519,29 @@ void driver::scf::calc_properties(const json &json_prop, Molecule &mol) { if (json_prop.contains("geometric_derivative")) { t_lap.start(); mrcpp::print::header(2, "Computing geometric derivative"); - for (const auto &item : json_prop["geometric_derivative"].items()) { - const auto &id = item.key(); - const double &prec = item.value()["precision"]; - const double &smoothing = item.value()["smoothing"]; - GeometricDerivative &G = mol.getGeometricDerivative(id); - auto &nuc = G.getNuclear(); + GeometricDerivative &G = mol.getGeometricDerivative("geom-1"); + auto &nuc = G.getNuclear(); + + // calculate nuclear gradient + for (auto k = 0; k < mol.getNNuclei(); ++k) { + const auto nuc_k = nuclei[k]; + auto Z_k = nuc_k.getCharge(); + auto R_k = nuc_k.getCoord(); + nuc.row(k) = Eigen::RowVector3d::Zero(); + for (auto l = 0; l < mol.getNNuclei(); ++l) { + if (l == k) continue; + const auto nuc_l = nuclei[l]; + auto Z_l = nuc_l.getCharge(); + auto R_l = nuc_l.getCoord(); + std::array R_kl = {R_k[0] - R_l[0], R_k[1] - R_l[1], R_k[2] - R_l[2]}; + auto R_kl_3_2 = std::pow(math_utils::calc_distance(R_k, R_l), 3.0); + nuc.row(k) -= Eigen::Map(R_kl.data()) * (Z_k * Z_l / R_kl_3_2); + } + } + // calculate electronic gradient using the Hellmann-Feynman theorem + if (json_prop["geometric_derivative"]["geom-1"]["method"] == "hellmann_feynman") { + const double &prec = json_prop["geometric_derivative"]["geom-1"]["precision"]; + const double &smoothing = json_prop["geometric_derivative"]["geom-1"]["smoothing"]; auto &el = G.getElectronic(); for (auto k = 0; k < mol.getNNuclei(); ++k) { @@ -534,19 +551,24 @@ void driver::scf::calc_properties(const json &json_prop, Molecule &mol) { double c = detail::nuclear_gradient_smoothing(smoothing, Z_k, mol.getNNuclei()); NuclearGradientOperator h(Z_k, R_k, prec, c); h.setup(prec); - nuc.row(k) = Eigen::RowVector3d::Zero(); - for (auto l = 0; l < mol.getNNuclei(); ++l) { - if (l == k) continue; - const auto nuc_l = nuclei[l]; - auto Z_l = nuc_l.getCharge(); - auto R_l = nuc_l.getCoord(); - std::array R_kl = {R_k[0] - R_l[0], R_k[1] - R_l[1], R_k[2] - R_l[2]}; - auto R_kl_3_2 = std::pow(math_utils::calc_distance(R_k, R_l), 3.0); - nuc.row(k) -= Eigen::Map(R_kl.data()) * (Z_k * Z_l / R_kl_3_2); - } el.row(k) = h.trace(Phi).real(); h.clear(); } + // calculate electronic gradient using the surface integrals method + } else if (json_prop["geometric_derivative"]["geom-1"]["method"] == "surface_integrals") { + double prec = json_prop["geometric_derivative"]["geom-1"]["precision"]; + std::string leb_prec = json_prop["geometric_derivative"]["geom-1"]["surface_integral_precision"]; + double radius_factor = json_prop["geometric_derivative"]["geom-1"]["radius_factor"]; + Eigen::MatrixXd surfaceForces = surface_force::surface_forces(mol, Phi, prec, json_fock, leb_prec, radius_factor); + GeometricDerivative &G = mol.getGeometricDerivative("geom-1"); + auto &nuc = G.getNuclear(); + auto &el = G.getElectronic(); + // set electronic gradient + for (int k = 0; k < mol.getNNuclei(); k++) { + el.row(k) = surfaceForces.row(k) - nuc.row(k); + } + } else { + MSG_ABORT("Invalid method for geometric derivative"); } mrcpp::print::footer(2, t_lap, 2); if (plevel == 1) mrcpp::print::time(1, "Geometric derivative", t_lap); @@ -783,7 +805,7 @@ json driver::rsp::run(const json &json_rsp, Molecule &mol) { F_0.setup(unpert_prec); if (plevel == 1) mrcpp::print::footer(1, t_unpert, 2); - if (json_rsp.contains("properties")) scf::calc_properties(json_rsp["properties"], mol); + if (json_rsp.contains("properties")) scf::calc_properties(json_rsp["properties"], mol, unpert_fock); /////////////////////////////////////////////////////////// ////////////// Preparing Perturbed System ///////////// diff --git a/src/mrdft/Functional.h b/src/mrdft/Functional.h index b9ee9e0cd..c23374f4d 100644 --- a/src/mrdft/Functional.h +++ b/src/mrdft/Functional.h @@ -62,6 +62,8 @@ class Functional { } double XCenergy = 0.0; + Eigen::MatrixXd evaluate(Eigen::MatrixXd &inp) const; + Eigen::MatrixXd evaluate_transposed(Eigen::MatrixXd &inp) const; friend class MRDFT; protected: @@ -78,8 +80,6 @@ class Functional { virtual int getCtrInputLength() const = 0; virtual int getCtrOutputLength() const = 0; - Eigen::MatrixXd evaluate(Eigen::MatrixXd &inp) const; - Eigen::MatrixXd evaluate_transposed(Eigen::MatrixXd &inp) const; Eigen::MatrixXd contract(Eigen::MatrixXd &xc_data, Eigen::MatrixXd &d_data) const; Eigen::MatrixXd contract_transposed(Eigen::MatrixXd &xc_data, Eigen::MatrixXd &d_data) const; diff --git a/src/properties/GeometricDerivative.h b/src/properties/GeometricDerivative.h index c1589a48c..79fab7210 100644 --- a/src/properties/GeometricDerivative.h +++ b/src/properties/GeometricDerivative.h @@ -56,6 +56,8 @@ class GeometricDerivative final { mrcpp::print::separator(0, '-'); print_utils::matrix(0, "Electronic", getElectronic()); print_utils::scalar(0, "Norm", getElectronic().norm(), "(au)"); + mrcpp::print::separator(0, '-'); + print_utils::scalar(0, "Est. var. of force error", variance(), "(au)", 4, true); mrcpp::print::separator(0, '=', 2); } @@ -68,6 +70,18 @@ class GeometricDerivative final { {"electronic_norm", getElectronic().norm()}}; } + /** + * @brief Compute the variance of the total force using the formula + * sigma = sqrt(1/(3N) * sum_i sum_j (F_{ij})^2) presented in + * Gubler et al.: Journal of Computational Physics: X Volume 17, November 2023, 100131 + */ + double variance() const { + DoubleMatrix forces = getTensor(); + Eigen::Vector3d total_force = forces.colwise().sum(); + double force_variance = total_force.norm() * std::sqrt( 1.0 / (3.0 * forces.rows()) ); + return force_variance; + } + protected: DoubleMatrix nuclear; DoubleMatrix electronic; diff --git a/src/qmoperators/one_electron/HessianOperator.h b/src/qmoperators/one_electron/HessianOperator.h new file mode 100644 index 000000000..2fc049d84 --- /dev/null +++ b/src/qmoperators/one_electron/HessianOperator.h @@ -0,0 +1,44 @@ +#pragma once + +#include "tensor/RankOneOperator.h" + +#include "qmoperators/QMDerivative.h" +#include "qmoperators/one_electron/NablaOperator.h" + +namespace mrchem { + +/** @class HessianOperator + * + * @brief Hessian operator + * + * This Hessian operator stores the second derivatives of Orbitals in an OrbitalVector. The ordering of the indices is + * [xx, yy, zz, yz, xz, xy]. + */ +class HessianOperator final : public RankOneOperator<6> { +public: + HessianOperator(std::shared_ptr> D1, std::shared_ptr> D2, double prec) { + bool imag = false; + NablaOperator N1 = NablaOperator(D1, imag); + NablaOperator N2 = NablaOperator(D2, imag); + N1.setup(prec); + N2.setup(prec); + + // Invoke operator= to assign *this operator + RankOneOperator<6> &d = (*this); + d[0] = N2[0]; + d[1] = N2[1]; + d[2] = N2[2]; + d[3] = N1[1] * N1[2]; + d[4] = N1[0] * N1[2]; + d[5] = N1[0] * N1[1]; + + d[0].name() = "del[x]del[x]"; + d[1].name() = "del[y]del[y]"; + d[2].name() = "del[z]del[z]"; + d[3].name() = "del[y]del[z]"; + d[4].name() = "del[x]del[z]"; + d[5].name() = "del[x]del[y]"; + } +}; + +} \ No newline at end of file diff --git a/src/qmoperators/two_electron/XCOperator.h b/src/qmoperators/two_electron/XCOperator.h index d2d2d8fff..9dff3ed0e 100644 --- a/src/qmoperators/two_electron/XCOperator.h +++ b/src/qmoperators/two_electron/XCOperator.h @@ -70,8 +70,10 @@ class XCOperator final : public RankZeroOperator { } void clearSpin() { this->potential->setReal(nullptr); } + std::shared_ptr getPotential() { return potential; } + private: std::shared_ptr potential{nullptr}; }; -} // namespace mrchem +} // namespace mrchem \ No newline at end of file diff --git a/src/qmoperators/two_electron/XCPotential.cpp b/src/qmoperators/two_electron/XCPotential.cpp index 763a87db2..6c79d6d59 100644 --- a/src/qmoperators/two_electron/XCPotential.cpp +++ b/src/qmoperators/two_electron/XCPotential.cpp @@ -85,7 +85,6 @@ void XCPotential::setup(double prec) { this->potentials.push_back(std::make_tuple(1.0, v_global)); } - mrcpp::clear(xc_out, true); if (plevel == 2) { int totNodes = 0; @@ -98,6 +97,7 @@ void XCPotential::setup(double prec) { auto t = timer.elapsed(); mrcpp::print::tree(2, "XC operator", totNodes, totSize, t); } + mrcpp::clear(xc_out, true); mrcpp::print::footer(3, timer, 2); } @@ -188,4 +188,4 @@ QMOperatorVector XCPotential::apply(QMOperator_p &O) { NOT_IMPLEMENTED_ABORT; } -} // namespace mrchem +} // namespace mrchem \ No newline at end of file diff --git a/src/qmoperators/two_electron/XCPotential.h b/src/qmoperators/two_electron/XCPotential.h index 307477690..f0ed0e3ac 100644 --- a/src/qmoperators/two_electron/XCPotential.h +++ b/src/qmoperators/two_electron/XCPotential.h @@ -63,6 +63,13 @@ class XCPotential : public QMPotential { , mrdft(std::move(F)) {} ~XCPotential() override = default; + /** + * @brief Get the XC potential. For unrestricted calculations, the potential is a vector of two functions. + */ + std::shared_ptr> getPotentialVector() { + return std::make_shared>(potentials); + } + friend class XCOperator; protected: @@ -87,4 +94,4 @@ class XCPotential : public QMPotential { QMOperatorVector apply(std::shared_ptr &O) override; }; -} // namespace mrchem +} // namespace mrchem \ No newline at end of file diff --git a/src/surface_forces/CMakeLists.txt b/src/surface_forces/CMakeLists.txt new file mode 100644 index 000000000..70f9d054b --- /dev/null +++ b/src/surface_forces/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(mrchem PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/SurfaceForce.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lebedev.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/LebedevData.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/detail/lebedev_utils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/xcStress.cpp + ) diff --git a/src/surface_forces/LebedevData.cpp b/src/surface_forces/LebedevData.cpp new file mode 100644 index 000000000..b6b2a9949 --- /dev/null +++ b/src/surface_forces/LebedevData.cpp @@ -0,0 +1,129 @@ +#include "LebedevData.h" + +#include +#include +#include + +#include + +#include "detail/Lebedev_003_0006.hpp" +#include "detail/Lebedev_005_0014.hpp" +#include "detail/Lebedev_007_0026.hpp" +#include "detail/Lebedev_009_0038.hpp" +#include "detail/Lebedev_011_0050.hpp" +#include "detail/Lebedev_013_0074.hpp" +#include "detail/Lebedev_015_0086.hpp" +#include "detail/Lebedev_017_0110.hpp" +#include "detail/Lebedev_019_0146.hpp" +#include "detail/Lebedev_021_0170.hpp" +#include "detail/Lebedev_023_0194.hpp" +#include "detail/Lebedev_025_0230.hpp" +#include "detail/Lebedev_027_0266.hpp" +#include "detail/Lebedev_029_0302.hpp" +#include "detail/Lebedev_031_0350.hpp" +#include "detail/Lebedev_035_0434.hpp" +#include "detail/Lebedev_041_0590.hpp" +#include "detail/Lebedev_047_0770.hpp" +#include "detail/Lebedev_053_0974.hpp" +#include "detail/Lebedev_059_1202.hpp" +#include "detail/Lebedev_065_1454.hpp" +#include "detail/Lebedev_071_1730.hpp" +#include "detail/Lebedev_077_2030.hpp" +#include "detail/Lebedev_083_2354.hpp" +#include "detail/Lebedev_089_2702.hpp" +#include "detail/Lebedev_095_3074.hpp" +#include "detail/Lebedev_101_3470.hpp" +#include "detail/Lebedev_107_3890.hpp" +#include "detail/Lebedev_113_4334.hpp" +#include "detail/Lebedev_119_4802.hpp" +#include "detail/Lebedev_125_5294.hpp" +#include "detail/Lebedev_131_5810.hpp" + +auto +lebedev(size_t N) -> std::tuple +{ + std::array available = { + 6, 14, 26, 38, 50, 74, 86, 110, 146, 170, 194, 230, 266, 302, 350, 434, + 590, 770, 974, 1202, 1454, 1730, 2030, 2354, 2702, 3074, 3470, 3890, 4334, 4802, 5294, 5810 + }; + + const auto lb = std::lower_bound(available.cbegin(), available.cend(), N); + auto closest = (lb == available.cend()) ? available.back() : *lb; + + if (lb != available.cbegin()) { + auto prec = lb - 1; + if (std::abs(closest - N) > std::abs(*prec - N)) + closest = *prec; + } + + switch (closest) { + case 6: + return detail::Lebedev_003_0006::quadrature(); + case 14: + return detail::Lebedev_005_0014::quadrature(); + case 26: + return detail::Lebedev_007_0026::quadrature(); + case 38: + return detail::Lebedev_009_0038::quadrature(); + case 50: + return detail::Lebedev_011_0050::quadrature(); + case 74: + return detail::Lebedev_013_0074::quadrature(); + case 86: + return detail::Lebedev_015_0086::quadrature(); + case 110: + return detail::Lebedev_017_0110::quadrature(); + case 146: + return detail::Lebedev_019_0146::quadrature(); + case 170: + return detail::Lebedev_021_0170::quadrature(); + case 194: + return detail::Lebedev_023_0194::quadrature(); + case 230: + return detail::Lebedev_025_0230::quadrature(); + case 266: + return detail::Lebedev_027_0266::quadrature(); + case 302: + return detail::Lebedev_029_0302::quadrature(); + case 350: + return detail::Lebedev_031_0350::quadrature(); + case 434: + return detail::Lebedev_035_0434::quadrature(); + case 590: + return detail::Lebedev_041_0590::quadrature(); + case 770: + return detail::Lebedev_047_0770::quadrature(); + case 974: + return detail::Lebedev_053_0974::quadrature(); + case 1202: + return detail::Lebedev_059_1202::quadrature(); + case 1454: + return detail::Lebedev_065_1454::quadrature(); + case 1730: + return detail::Lebedev_071_1730::quadrature(); + case 2030: + return detail::Lebedev_077_2030::quadrature(); + case 2354: + return detail::Lebedev_083_2354::quadrature(); + case 2702: + return detail::Lebedev_089_2702::quadrature(); + case 3074: + return detail::Lebedev_095_3074::quadrature(); + case 3470: + return detail::Lebedev_101_3470::quadrature(); + case 3890: + return detail::Lebedev_107_3890::quadrature(); + case 4334: + return detail::Lebedev_113_4334::quadrature(); + case 4802: + return detail::Lebedev_119_4802::quadrature(); + case 5294: + return detail::Lebedev_125_5294::quadrature(); + case 5810: + return detail::Lebedev_131_5810::quadrature(); + + default: + // FIXME error handling + std::abort(); + } +} \ No newline at end of file diff --git a/src/surface_forces/LebedevData.h b/src/surface_forces/LebedevData.h new file mode 100644 index 000000000..eccc5e04e --- /dev/null +++ b/src/surface_forces/LebedevData.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#include + +/** Lebedev-Laikov partition with at most \f$N\f$ points. + * + * @param[in] N + * @return the weights and points. + */ +auto +lebedev(size_t N) -> std::tuple; \ No newline at end of file diff --git a/src/surface_forces/SurfaceForce.cpp b/src/surface_forces/SurfaceForce.cpp new file mode 100644 index 000000000..b3b9d8cbe --- /dev/null +++ b/src/surface_forces/SurfaceForce.cpp @@ -0,0 +1,401 @@ +#include "surface_forces/SurfaceForce.h" + +#include +#include +#include + +#include "qmfunctions/Density.h" +#include "qmfunctions/Orbital.h" +#include "qmfunctions/density_utils.h" +#include "qmfunctions/orbital_utils.h" + +#include "qmoperators/one_electron/NablaOperator.h" +#include +#include "qmoperators/one_electron/NuclearGradientOperator.h" + +#include "chemistry/Molecule.h" +#include "chemistry/Nucleus.h" +#include "chemistry/PhysicalConstants.h" +#include +#include + +#include "mrdft/Factory.h" +#include "mrdft/MRDFT.h" +#include "mrdft/xc_utils.h" +#include "qmoperators/two_electron/XCOperator.h" +#include "mrdft/Functional.h" + +#include "qmoperators/one_electron/HessianOperator.h" +#include "tensor/RankOneOperator.h" + +#include "surface_forces/lebedev.h" +#include "surface_forces/xcStress.h" +#include +#include +#include + +#include + +extern mrcpp::MultiResolutionAnalysis<3> *mrchem::MRA; + +using namespace Eigen; +using namespace mrchem; +using nlohmann::json; + +namespace surface_force { + +/** + * Calculates the electric field due to the nuclei. + * @param nucPos The positions of the nuclei. Shape (nNuc, 3). + * @param nucCharge The charges of the nuclei. Shape (nNuc,). + * @param nucSmoothing The smoothing parameter for the nuclei. Shape (nNuc,). + * @param gridPos The positions of the grid points where the field should be evaluated. Shape (nGrid, 3). +*/ +MatrixXd nuclearEfield(const MatrixXd &nucPos, const VectorXd &nucCharge, const VectorXd &nucSmoothing, const MatrixXd gridPos) { + int nGrid = gridPos.rows(); + int nNuc = nucPos.rows(); + MatrixXd Efield = MatrixXd::Zero(nGrid, 3); + Vector3d r_vect; + double r; + double r2, r3; + double temp; + double c, q; + double c2, c3; + double c3_times_sqrt_pi_times_three; + double sqrt_pi = std::sqrt(M_PI); + for (int i = 0; i < nNuc; ++i) { + c = nucSmoothing(i); + q = nucCharge(i); + c2 = c * c; + c3 = c2 * c; + c3_times_sqrt_pi_times_three = 3. * std::sqrt(M_PI) * c3; + for (int j = 0; j < nGrid; j++) + { + r_vect = nucPos.row(i) - gridPos.row(j); + r = r_vect.norm(); + r2 = r * r; + r3 = r2 * r; + Efield.row(j) += q * r_vect / r3; + // This would compute the electric field for the finite point like nucleus. It does not improve accuracy since the integration speres + // are large enough to not be affected by the finite point like nucleus. It is kept here for reference. + // Efield.row(j) += q * r_vect / r * (std::erf(r / c) / r2 - 2 * std::exp(-r2/c2)/(sqrt_pi * c * r) + 2.0 * r * std::exp(-r2 / c2) / c3_times_sqrt_pi_times_three + // + 128.0 * r * std::exp(-4.0 * r2 / c2) / c3_times_sqrt_pi_times_three); + } + } + return Efield; +} + +/** + * @brief Calculates the coulomb potential due to the given density. +*/ +mrcpp::ComplexFunction calcPotential(Density &rho, mrcpp::PoissonOperator &poisson, double prec) { + mrcpp::ComplexFunction V(false); + V.alloc(mrchem::NUMBER::Real); + mrcpp::apply(prec, V.real(), poisson, rho.real()); + return V; +} + +/** + * @brief Calculates the electric field due to the electrons. + * @param negEfield The negative gradient of the electric field. Shape (3,). + * @param gridPos The positions of the grid points where the field should be evaluated. Shape (nGrid, 3). +*/ +MatrixXd electronicEfield(mrchem::OrbitalVector &negEfield, const MatrixXd &gridPos) { + int nGrid = gridPos.rows(); + MatrixXd Efield = MatrixXd::Zero(nGrid, 3); + for (int i = 0; i < nGrid; i++) + { + std::array pos = {gridPos(i, 0), gridPos(i, 1), gridPos(i, 2)}; + Efield(i, 0) = -negEfield[0].real().evalf(pos); + Efield(i, 1) = -negEfield[1].real().evalf(pos); + Efield(i, 2) = -negEfield[2].real().evalf(pos); + } + return Efield; +} + +/** + * Calculates the Maxwell stress tensor for the given molecule. + * @param mol The molecule for which to calculate the stress tensor. + * @param negEfield Negative electric field (gradient of potential) + * @param gridPos The positions of the grid points where the field should be evaluated. Shape (nGrid, 3). + * @param prec The precision value used in the calculation. +*/ +std::vector maxwellStress(const Molecule &mol, mrchem::OrbitalVector &negEfield, const MatrixXd &gridPos, double prec){ + int nGrid = gridPos.rows(); + int nNuc = mol.getNNuclei(); + + Eigen::MatrixXd nucPos(nNuc, 3); + Eigen::VectorXd nucCharge(nNuc); + Eigen::VectorXd nucSmoothing(nNuc); + for (int i = 0; i < nNuc; i++) + { + std::array coord = mol.getNuclei()[i].getCoord(); + nucPos(i, 0) = coord[0]; + nucPos(i, 1) = coord[1]; + nucPos(i, 2) = coord[2]; + nucCharge(i) = mol.getNuclei()[i].getCharge(); + double tmp = 0.00435 * prec / std::pow(nucCharge(i), 5.0); + nucSmoothing(i) = std::cbrt(tmp); + } + + MatrixXd Efield = electronicEfield(negEfield, gridPos) + nuclearEfield(nucPos, nucCharge, nucSmoothing, gridPos); + + std::vector stress(nGrid); + for (int i = 0; i < nGrid; i++) { + for (int i1 = 0; i1 < 3; i1++) { + for (int i2 = 0; i2 < 3; i2++) { + stress[i](i1, i2) = Efield(i, i1) * Efield(i, i2); + } + } + for (int i1 = 0; i1 < 3; i1++){ + stress[i](i1, i1) = stress[i](i1, i1) - 0.5 * (Efield(i, 0) * Efield(i, 0) + Efield(i, 1) * Efield(i, 1) + Efield(i, 2) * Efield(i, 2)); + } + for (int i1 = 0; i1 < 3; i1++){ + for (int i2 = 0; i2 < 3; i2++){ + stress[i](i1, i2) *= 1.0 / (4 * M_PI); + } + } + } + return stress; +} + +/** + * @brief Calculates the kinetic stress tensor for the given molecule. See the function description for the formula. +*/ +std::vector kineticStress(const Molecule &mol, OrbitalVector &Phi, std::vector> &nablaPhi + , std::vector &hessRho, double prec, const MatrixXd &gridPos){ + + // original formula for kinetic stress: + // sigma_ij = 0.5 \sum_k phi_k del_i del_j phi_k - (del_i phi_k) (del_j phi_k) + // using the product rule for the first term: + // sigma_ij = 0.5 * del_i del_j rho - 2 * \sum_k (del_i phi_k) (del_j phi_k) + // That way, only second derivatives of density is needed which speeds things up. quite a lot. + + int nGrid = gridPos.rows(); + int nOrbs = Phi.size(); + + double StressArray[nGrid][3][3]; + + double orbVal; + std::vector stress(nGrid); + + Eigen::MatrixXd voigtStress = Eigen::MatrixXd::Zero(nGrid, 6); + + std::array pos; + double n1, n2, n3; + int occ; + for (int iOrb = 0; iOrb < Phi.size(); iOrb++) { + occ = Phi[iOrb].occ(); + + for (int i = 0; i < nGrid; i++) { + if (mrcpp::mpi::my_orb(iOrb)) { + pos[0] = gridPos(i, 0); + pos[1] = gridPos(i, 1); + pos[2] = gridPos(i, 2); + n1 = nablaPhi[iOrb][0].real().evalf(pos); + n2 = nablaPhi[iOrb][1].real().evalf(pos); + n3 = nablaPhi[iOrb][2].real().evalf(pos); + voigtStress(i, 0) -= occ * n1 * n1; + voigtStress(i, 1) -= occ * n2 * n2; + voigtStress(i, 2) -= occ * n3 * n3; + voigtStress(i, 5) -= occ * n1 * n2; + voigtStress(i, 4) -= occ * n1 * n3; + voigtStress(i, 3) -= occ * n2 * n3; + } + + } + } + mrcpp::mpi::allreduce_matrix(voigtStress, mrcpp::mpi::comm_wrk); + for (int i = 0; i < nGrid; i++) { + pos[0] = gridPos(i, 0); + pos[1] = gridPos(i, 1); + pos[2] = gridPos(i, 2); + voigtStress(i, 0) += 0.25 * hessRho[0].real().evalf(pos); + voigtStress(i, 1) += 0.25 * hessRho[1].real().evalf(pos); + voigtStress(i, 2) += 0.25 * hessRho[2].real().evalf(pos); + voigtStress(i, 3) += 0.25 * hessRho[3].real().evalf(pos); + voigtStress(i, 4) += 0.25 * hessRho[4].real().evalf(pos); + voigtStress(i, 5) += 0.25 * hessRho[5].real().evalf(pos); + } + + for (int i = 0; i < nGrid; i++) { + stress[i] << voigtStress(i, 0), voigtStress(i, 5), voigtStress(i, 4), + voigtStress(i, 5), voigtStress(i, 1), voigtStress(i, 3), + voigtStress(i, 4), voigtStress(i, 3), voigtStress(i, 2); + } + return stress; +} + +/** + * Calculates the distance to the nearest neighbor for each point in the given position matrix. + * + * @param pos The matrix containing the positions of the points. Shape (nPoints, 3). + * @return A vector containing the distances to the nearest neighbor for each point. + */ +VectorXd distanceToNearestNeighbour(MatrixXd pos){ + int n = pos.rows(); + VectorXd dist(n); + double temp; + if (n == 1){ + dist(0) = 1.0; + } else { + for (int i = 0; i < n; i++){ + dist(i) = (pos.row(i) - pos.row((i + 1) % n)).norm(); + for (int j = 0; j < n; j++){ + if (i != j){ + temp = (pos.row(i) - pos.row(j)).norm(); + if (temp < dist(i)){ + dist(i) = temp; + } + } + } + } + } + return dist; +} + +/** + * Calculates the forces using surface integrals for a given molecule and orbital vector. + * + * @param mol The molecule for which to calculate the forces. + * @param Phi The orbital vector obtained from the SCF calculation. + * @param prec The precision value used in the calculation. + * @param json_fock The JSON object containing the Fock matrix settings. + * @return The matrix of forces, shape (nAtoms, 3). + */ +Eigen::MatrixXd surface_forces(mrchem::Molecule &mol, mrchem::OrbitalVector &Phi, double prec, const json &json_fock + , std::string leb_prec, double radius_factor) { + + if (radius_factor > 0.95 && radius_factor < 0.05){ + MSG_ABORT("Invalid value of radius_factor") + } + + // setup density + mrchem::Density rho(false); + mrchem::density::compute(prec, rho, Phi, DensityType::Total); + + std::shared_ptr phi_p = std::make_shared(Phi); + + // setup operators and potentials + auto poisson_op = mrcpp::PoissonOperator(*mrchem::MRA, prec); + int derivOrder = 1; + auto mrcd = std::make_shared>(*mrchem::MRA, derivOrder); + mrchem::NablaOperator nabla(mrcd); + nabla.setup(prec); + double abs_prec = prec / mrchem::orbital::get_electron_number(Phi); + mrcpp::ComplexFunction pot = calcPotential(rho, poisson_op, abs_prec); + mrchem::OrbitalVector negEfield = nabla(pot); + + // set up operators for kinetic stress: + int derivOrder1 = 1; + auto D1 = std::make_shared>(*mrchem::MRA, derivOrder1); + int derivOrder2 = 2; + auto D2 = std::make_shared>(*mrchem::MRA, derivOrder2); + mrchem::HessianOperator hess(D1, D2, prec); + hess.setup(prec); + + std::vector> nablaPhi(Phi.size()); + std::vector hessRho = hess(rho); + for (int i = 0; i < Phi.size(); i++) { + if (mrcpp::mpi::my_orb(i)) { + nablaPhi[i] = nabla(Phi[i]); + } + } + // setup xc stuff: + int order = 0; + bool shared_memory = json_fock["xc_operator"]["shared_memory"]; + auto json_xcfunc = json_fock["xc_operator"]["xc_functional"]; + bool xc_spin = json_xcfunc["spin"]; + auto xc_cutoff = json_xcfunc["cutoff"]; + auto xc_funcs = json_xcfunc["functionals"]; + auto xc_order = order + 1; + auto funcVectorShared = std::make_shared(Phi); + + mrdft::Factory xc_factory(*MRA); + xc_factory.setSpin(xc_spin); + xc_factory.setOrder(xc_order); + xc_factory.setDensityCutoff(xc_cutoff); + for (const auto &f : xc_funcs) { + auto name = f["name"]; + auto coef = f["coef"]; + xc_factory.setFunctional(name, coef); + } + std::unique_ptr mrdft_p = xc_factory.build(); + + mrdft::Factory xc_factory2(*MRA); + xc_factory2.setSpin(xc_spin); + xc_factory2.setOrder(xc_order); + xc_factory2.setDensityCutoff(xc_cutoff); + for (const auto &f : xc_funcs) { + auto name = f["name"]; + auto coef = f["coef"]; + xc_factory2.setFunctional(name, coef); + } + std::unique_ptr mrdft_p_for_operator = xc_factory2.build(); + + std::shared_ptr xc_op = std::make_shared(mrdft_p_for_operator, phi_p, false); + xc_op->setup(prec); + + std::shared_ptr> xc_pot_vector = xc_op->getPotential()->getPotentialVector(); + + int numAtoms = mol.getNNuclei(); + + std::array coord; + + Eigen::MatrixXd posmatrix = Eigen::MatrixXd::Zero(numAtoms, 3); + for (int i = 0; i < numAtoms; i++) { + coord = mol.getNuclei()[i].getCoord(); + posmatrix(i, 0) = coord[0]; + posmatrix(i, 1) = coord[1]; + posmatrix(i, 2) = coord[2]; + } + VectorXd dist = distanceToNearestNeighbour(posmatrix); + + int nLebPoints = 0; + int nTinyPoints = 1; + if (leb_prec == "low") { + nLebPoints = 194; + } + else if (leb_prec == "medium"){ + nLebPoints = 434; + } + else if (leb_prec == "high") { + nLebPoints = 770; + } + else { + MSG_ABORT("Invalid lebedev precision"); + } + + double radius; + Vector3d center; + Eigen::MatrixXd forces = Eigen::MatrixXd::Zero(numAtoms, 3); + + for (int iAtom = 0; iAtom < numAtoms; iAtom++) { + radius = dist(iAtom) * radius_factor; + coord = mol.getNuclei()[iAtom].getCoord(); + center << coord[0], coord[1], coord[2]; + + LebedevIntegrator integrator(nLebPoints, radius, center); + MatrixXd gridPos = integrator.getPoints(); + VectorXd weights = integrator.getWeights(); + MatrixXd normals = integrator.getNormals(); + std::vector xcStress = getXCStress(mrdft_p, *xc_pot_vector, std::make_shared(Phi), + std::make_shared(nabla), gridPos, xc_spin, prec); + + + std::vector kstress = kineticStress(mol, Phi, nablaPhi, hessRho, prec, gridPos); + std::vector mstress = maxwellStress(mol, negEfield, gridPos, prec); + std::vector stress(integrator.n); + for (int i = 0; i < integrator.n; i++){ + stress[i] = xcStress[i] + kstress[i] + mstress[i]; + forces.row(iAtom) -= stress[i] * normals.row(i).transpose() * weights(i); + } + } + + hess.clear(); + nabla.clear(); + xc_op->clear(); + return forces; +} + +} // namespace surface_force diff --git a/src/surface_forces/SurfaceForce.h b/src/surface_forces/SurfaceForce.h new file mode 100644 index 000000000..00c570c1d --- /dev/null +++ b/src/surface_forces/SurfaceForce.h @@ -0,0 +1,20 @@ +#ifndef SURFACEFORCE_H +#define SURFACEFORCE_H + +#include +#include "qmfunctions/Orbital.h" +#include "chemistry/Molecule.h" +#include +#include +#include + +namespace surface_force { + +// Function declaration +Eigen::MatrixXd surface_forces(mrchem::Molecule &mol, mrchem::OrbitalVector &Phi, double prec + , const json &json_fock, std::string leb_prec, double radius_factor); + +} // namespace surface_force + +#endif // SURFACEFORCE_H + diff --git a/src/surface_forces/detail/Lebedev_003_0006.hpp b/src/surface_forces/detail/Lebedev_003_0006.hpp new file mode 100644 index 000000000..96742320b --- /dev/null +++ b/src/surface_forces/detail/Lebedev_003_0006.hpp @@ -0,0 +1,39 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_003_0006 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.16666666666666666; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(6); + Points xs = Points::Zero(3, 6); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_005_0014.hpp b/src/surface_forces/detail/Lebedev_005_0014.hpp new file mode 100644 index 000000000..0b2239732 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_005_0014.hpp @@ -0,0 +1,50 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_005_0014 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.06666666666666667; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.075; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(14); + Points xs = Points::Zero(3, 14); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_007_0026.hpp b/src/surface_forces/detail/Lebedev_007_0026.hpp new file mode 100644 index 000000000..8d65b21a8 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_007_0026.hpp @@ -0,0 +1,61 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_007_0026 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.04761904761904772; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.03809523809523815; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.03214285714285716; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(26); + Points xs = Points::Zero(3, 26); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_009_0038.hpp b/src/surface_forces/detail/Lebedev_009_0038.hpp new file mode 100644 index 000000000..7dd81378d --- /dev/null +++ b/src/surface_forces/detail/Lebedev_009_0038.hpp @@ -0,0 +1,67 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_009_0038 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.009523809523809493; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.03214285714285712; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 1> pq0 = { { { { 0.02857142857142858, 0.1520433619923482 } } } }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(38); + Points xs = Points::Zero(3, 38); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_011_0050.hpp b/src/surface_forces/detail/Lebedev_011_0050.hpp new file mode 100644 index 000000000..9633c46a8 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_011_0050.hpp @@ -0,0 +1,78 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_011_0050 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.01269841269841246; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.02257495590828945; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.02109375000000007; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 1> llm = { { { { 0.02017333553791894, 0.1402188990037718 } } } }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(50); + Points xs = Points::Zero(3, 50); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_013_0074.hpp b/src/surface_forces/detail/Lebedev_013_0074.hpp new file mode 100644 index 000000000..370b204bc --- /dev/null +++ b/src/surface_forces/detail/Lebedev_013_0074.hpp @@ -0,0 +1,96 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_013_0074 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.0005130671797338573; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.01660406956574207; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = -0.02958603896103878; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 1> pq0 = { { { { 0.01652217099371571, 0.1039425436019301 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 1> llm = { { { { 0.02657620708215941, 0.2377452061506383 } } } }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(74); + Points xs = Points::Zero(3, 74); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_015_0086.hpp b/src/surface_forces/detail/Lebedev_015_0086.hpp new file mode 100644 index 000000000..8c91bdf43 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_015_0086.hpp @@ -0,0 +1,86 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_015_0086 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.01154401154401154; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.01194390908585627; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 1> pq0 = { { { { 0.01181230374690448, 0.122097420896829 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 2> llm = { { { { 0.01111055571060341, 0.175074219393757 } }, + { { 0.01187650129453714, 0.4394547818483105 } } } }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(86); + Points xs = Points::Zero(3, 86); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = + xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_017_0110.hpp b/src/surface_forces/detail/Lebedev_017_0110.hpp new file mode 100644 index 000000000..b938e7e92 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_017_0110.hpp @@ -0,0 +1,87 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_017_0110 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.003828270494937165; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.009793737512487516; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 1> pq0 = { { { { 0.009694996361663016, 0.1587718599599673 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 3> llm = { { { { 0.00821173728319111, 0.08431378642264122 } }, + { { 0.00994281489117811, 0.4307128024241376 } }, + { { 0.009595471336070959, 0.1890411561417223 } } } }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(110); + Points xs = Points::Zero(3, 110); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = + xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_019_0146.hpp b/src/surface_forces/detail/Lebedev_019_0146.hpp new file mode 100644 index 000000000..f71d3202a --- /dev/null +++ b/src/surface_forces/detail/Lebedev_019_0146.hpp @@ -0,0 +1,100 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_019_0146 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.0005996313688621423; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.007372999718620753; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.00721051536014448; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 3> llm = { { { { 0.007116355493117556, 0.4059125877037633 } }, + { { 0.006753829486314482, 0.2010413026271249 } }, + { { 0.007574394159054035, 0.07148472221258875 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 1> rsw = { + { { { 0.006991087353303258, 0.1560143459914701, 0.09637179505136553 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(146); + Points xs = Points::Zero(3, 146); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_021_0170.hpp b/src/surface_forces/detail/Lebedev_021_0170.hpp new file mode 100644 index 000000000..ce6d85270 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_021_0170.hpp @@ -0,0 +1,120 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_021_0170 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.005544842902037351; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.00607133277067074; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.006383674773515079; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 1> pq0 = { { { { 0.005477143385137349, 0.08418189984183713 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 3> llm = { { { { 0.00518338758774779, 0.1174968529773118 } }, + { { 0.006317929009813731, 0.4027484749288706 } }, + { { 0.006201670006589078, 0.2091465148367879 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 1> rsw = { + { { { 0.00596838398768115, 0.1739152488294495, 0.08980998574526211 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(170); + Points xs = Points::Zero(3, 170); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_023_0194.hpp b/src/surface_forces/detail/Lebedev_023_0194.hpp new file mode 100644 index 000000000..f937ba4e2 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_023_0194.hpp @@ -0,0 +1,121 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_023_0194 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.001782340447244553; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.0057169059499771; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.005573383178848731; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 1> pq0 = { { { { 0.005051846064614807, 0.1123823329341791 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 4> llm = { { { { 0.005608704082588003, 0.3982647562227038 } }, + { { 0.005158237711805389, 0.1341420769255836 } }, + { { 0.005518771467273624, 0.2164909639525588 } }, + { { 0.004106777028169397, 0.0588249100009834 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 1> rsw = { + { { { 0.005530248916233095, 0.1848673899291661, 0.09361050601652832 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(194); + Points xs = Points::Zero(3, 194); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_025_0230.hpp b/src/surface_forces/detail/Lebedev_025_0230.hpp new file mode 100644 index 000000000..857777ee9 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_025_0230.hpp @@ -0,0 +1,112 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_025_0230 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = -0.05522639919727151; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.004450274607445213; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 2> pq0 = { { { { 0.004231083095357338, 0.1978800670300886 } }, + { { 0.005198069864064393, 0.1153787776721498 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 5> llm = { { { { 0.004496841067921402, 0.2191116154710022 } }, + { { 0.00504915345047875, 0.1160099697625648 } }, + { { 0.003976408018051886, 0.4493979784611453 } }, + { { 0.004401400650381014, 0.3815865619710557 } }, + { { 0.01724544350544358, 0.01818973371786956 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 1> rsw = { + { { { 0.004695720972568876, 0.1804103147536413, 0.139090532881485 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(230); + Points xs = Points::Zero(3, 230); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = + xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws( + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + auto xs_ = xs( + Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_027_0266.hpp b/src/surface_forces/detail/Lebedev_027_0266.hpp new file mode 100644 index 000000000..0649f4a7d --- /dev/null +++ b/src/surface_forces/detail/Lebedev_027_0266.hpp @@ -0,0 +1,123 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_027_0266 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = -0.001313769127326983; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = -0.002522728704859417; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.004186853881700566; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 1> pq0 = { { { { 0.004229582700647239, 0.1762081911747833 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 5> llm = { { { { 0.005315167977810922, 0.4698507590609774 } }, + { { 0.004047142377086223, 0.04573691253800456 } }, + { { 0.004112482394406988, 0.2282797998614352 } }, + { { 0.003595584899758778, 0.1534056193468028 } }, + { { 0.00425613135142816, 0.3857345813114577 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 2> rsw = { + { { { 0.004080914225780509, 0.1115427837683389, 0.1090391264984581 } }, + { { 0.004071467593830959, 0.1943382312726988, 0.132298236105979 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(266); + Points xs = Points::Zero(3, 266); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_029_0302.hpp b/src/surface_forces/detail/Lebedev_029_0302.hpp new file mode 100644 index 000000000..3cecd85a2 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_029_0302.hpp @@ -0,0 +1,114 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_029_0302 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.0008545911725125194; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.003599119285025563; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 2> pq0 = { { { { 0.002982344963171799, 0.08517895589394739 } }, + { { 0.003600820932216471, 0.1937917611754077 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 6> llm = { { { { 0.003449788424305891, 0.1656335697510352 } }, + { { 0.003604822601419879, 0.379003267312355 } }, + { { 0.00357672966174337, 0.2331871506325207 } }, + { { 0.002352101413689175, 0.04343224261369796 } }, + { { 0.003108953122413699, 0.1016374264737829 } }, + { { 0.003650045807677262, 0.4587466647164051 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 2> rsw = { + { { { 0.003571540554273389, 0.2047941668195036, 0.1374113409842759 } }, + { { 0.003392312205006175, 0.1417721795944134, 0.09243609737808951 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(302); + Points xs = Points::Zero(3, 302); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = + xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws( + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + auto xs_ = xs( + Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_031_0350.hpp b/src/surface_forces/detail/Lebedev_031_0350.hpp new file mode 100644 index 000000000..805b11f2c --- /dev/null +++ b/src/surface_forces/detail/Lebedev_031_0350.hpp @@ -0,0 +1,115 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_031_0350 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.003006796749453936; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.00305062774565076; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 2> pq0 = { { { { 0.003007949555218536, 0.06191727944646849 } }, + { { 0.002881964603055306, 0.1240930463255775 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 6> llm = { { { { 0.001621104600288989, 0.4922377847263371 } }, + { { 0.003005701484901751, 0.2371836111970294 } }, + { { 0.002990992529653774, 0.08788169148411765 } }, + { { 0.0029821706441076, 0.4363925918740951 } }, + { { 0.002721564237310999, 0.1704622980156029 } }, + { { 0.00303351379581114, 0.3710217638645251 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 3> rsw = { + { { { 0.002958357626535696, 0.2082808066943686, 0.1580611367940407 } }, + { { 0.003036020026407086, 0.1894331933396794, 0.05526289716428369 } }, + { { 0.002832187403926303, 0.1380140915227121, 0.1437471695874424 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(350); + Points xs = Points::Zero(3, 350); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = + xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws( + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + auto xs_ = xs( + Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_035_0434.hpp b/src/surface_forces/detail/Lebedev_035_0434.hpp new file mode 100644 index 000000000..a7a70d8da --- /dev/null +++ b/src/surface_forces/detail/Lebedev_035_0434.hpp @@ -0,0 +1,128 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_035_0434 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.0005265897968228898; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.002548219972002607; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.002512317418927299; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 2> pq0 = { { { { 0.002417442375638987, 0.1563228953888757 } }, + { { 0.001910951282179527, 0.06743512918521113 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 7> llm = { { { { 0.002530403801186355, 0.4317916211421352 } }, + { { 0.002014279020918488, 0.08075932475954789 } }, + { { 0.002501725168402938, 0.2445925526145315 } }, + { { 0.002513267174597568, 0.3663265069319693 } }, + { { 0.002302694782227404, 0.1326057309579972 } }, + { { 0.00146249562159454, 0.0341337299597072 } }, + { { 0.002445373437312978, 0.1874342228194836 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 4> rsw = { + { { { 0.002416930044324782, 0.1647978238635747, 0.1362863107481372 } }, + { { 0.002512236854563495, 0.2048710360686823, 0.05695446177756676 } }, + { { 0.002496644054553092, 0.2193835459268291, 0.1623274676288571 } }, + { { 0.002236607760437855, 0.1134255321813034, 0.09180065418907327 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(434); + Points xs = Points::Zero(3, 434); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_041_0590.hpp b/src/surface_forces/detail/Lebedev_041_0590.hpp new file mode 100644 index 000000000..c80d600c6 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_041_0590.hpp @@ -0,0 +1,124 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_041_0590 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.0003095121295305836; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.001852379698597478; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 3> pq0 = { { { { 0.001857161196774076, 0.2095077328439292 } }, + { { 0.001705153996395864, 0.1297668400660099 } }, + { { 0.001300321685886048, 0.05517743482053686 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 9> llm = { + { { { 0.001871790639277746, 0.4706131545204132 } }, + { { 0.00185881258543832, 0.4128585706917278 } }, + { { 0.001852028828296213, 0.3573229684376594 } }, + { { 0.001846715956151241, 0.2528405584420118 } }, + { { 0.001818471778162771, 0.2033229747758977 } }, + { { 0.001749564657281158, 0.1554666203257969 } }, + { { 0.001617210647254415, 0.109497676338565 } }, + { { 0.001384737234851695, 0.06615493890521376 } }, + { { 0.0009764331165051027, 0.02747138341414011 } } } + }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 6> rsw = { + { { { 0.001842866472905286, 0.2303850210691616, 0.1782913553398007 } }, + { { 0.001802658934377453, 0.1825270299224028, 0.1614172350949324 } }, + { { 0.001849830560443662, 0.2150558240678685, 0.0938170165851402 } }, + { { 0.001713904507106709, 0.1366839727348951, 0.1356325143675007 } }, + { { 0.001555213603396811, 0.09357248336623084, 0.09147934984857106 } }, + { { 0.001802239128008522, 0.1708498650344756, 0.0563137356299042 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(590); + Points xs = Points::Zero(3, 590); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = + xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws( + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + auto xs_ = xs( + Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_047_0770.hpp b/src/surface_forces/detail/Lebedev_047_0770.hpp new file mode 100644 index 000000000..4b1f0e9ed --- /dev/null +++ b/src/surface_forces/detail/Lebedev_047_0770.hpp @@ -0,0 +1,137 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_047_0770 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.0002192942088182175; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.001436433617319091; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.001421940344335874; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 3> pq0 = { { { { 0.0009254401499865399, 0.04621738571378741 } }, + { { 0.001250239995053508, 0.1100975833825021 } }, + { { 0.001394365843329228, 0.1791538510007847 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 10> llm = { { { { 0.0006798123511050234, 0.02292026702769342 } }, + { { 0.0009913184235294894, 0.0555702172024949 } }, + { { 0.001180207833238949, 0.09254023339464029 } }, + { { 0.001296599602080922, 0.1319393297241756 } }, + { { 0.001365871427428312, 0.1730026707517375 } }, + { { 0.001402988604775323, 0.2154115731074323 } }, + { { 0.001418645563595606, 0.2590829375936784 } }, + { { 0.001421376741851662, 0.3505993811839581 } }, + { { 0.001423996475490966, 0.3988264338132601 } }, + { { 0.001431554042178568, 0.4488003348564934 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 9> rsw = { + { { { 0.00112708909467175, 0.07896604124950307, 0.09126444167498717 } }, + { { 0.001345753760910667, 0.1553094137600919, 0.1608217314832364 } }, + { { 0.001424957283316787, 0.215550404070437, 0.0408824237566492 } }, + { { 0.001261523341237749, 0.115923272601319, 0.1352197040723114 } }, + { { 0.001392547106052695, 0.1836874558196702, 0.09300622918241049 } }, + { { 0.001418761677877655, 0.2238040826792707, 0.119230464563211 } }, + { { 0.001338366684479552, 0.1455361124992715, 0.05591508238246502 } }, + { { 0.00139370086267613, 0.1964019716288602, 0.1775706977927038 } }, + { { 0.00141591475746693, 0.2389135816551385, 0.1893661429124828 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(770); + Points xs = Points::Zero(3, 770); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_053_0974.hpp b/src/surface_forces/detail/Lebedev_053_0974.hpp new file mode 100644 index 000000000..dd9abdbc8 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_053_0974.hpp @@ -0,0 +1,132 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_053_0974 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.000143829419053; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.001125772288287; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 4> pq0 = { { { { 0.000682336792711, 0.03946600009801534 } }, + { { 0.000945415816045, 0.09501245088959068 } }, + { { 0.001074429975386, 0.15566509596376388 } }, + { { 0.001129300086569, 0.2183643706356081 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 12> llm = { { { { 0.000494802934195, 0.019337017127159052 } }, + { { 0.000735799010913, 0.04750701000375154 } }, + { { 0.00088891327713, 0.07960603068581106 } }, + { { 0.000988834783892, 0.1139520045627366 } }, + { { 0.001053299681709, 0.1498166059474992 } }, + { { 0.001092778807015, 0.18685324600959904 } }, + { { 0.001114389394063, 0.22491326381309878 } }, + { { 0.001123724788052, 0.26397058054454303 } }, + { { 0.001125239325244, 0.34538559044616385 } }, + { { 0.001126153271816, 0.38800992457940353 } }, + { { 0.001130286931124, 0.4320172490827723 } }, + { { 0.001134986534364, 0.4771817066440508 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 12> rsw = { + { { { 0.00084368845009, 0.0678427744589942, 0.0911399534108118 } }, + { { 0.001075255720449, 0.15950256677371893, 0.09245458231700068 } }, + { { 0.001108577236864, 0.20750107737350024, 0.18879250210965065 } }, + { { 0.000956647532378, 0.10003743318687472, 0.13495092827433242 } }, + { { 0.001080663250717, 0.17037391906706956, 0.17706122532834084 } }, + { { 0.001126797131196, 0.22169791057730812, 0.07103466827059002 } }, + { { 0.001022568715358, 0.12604674065566943, 0.0556505520034843 } }, + { { 0.001108960267713, 0.1877588469112349, 0.04049681224647043 } }, + { { 0.001122790653436, 0.2311961883820272, 0.13768263611849016 } }, + { { 0.001032401847117, 0.13444579383088165, 0.16042026040349594 } }, + { { 0.001107249382284, 0.19466826141718838, 0.118434013056699 } }, + { { 0.00112178004852, 0.24570106099668815, 0.19748919518870767 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(974); + Points xs = Points::Zero(3, 974); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = + xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws( + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + auto xs_ = xs( + Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_059_1202.hpp b/src/surface_forces/detail/Lebedev_059_1202.hpp new file mode 100644 index 000000000..68fa7df74 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_059_1202.hpp @@ -0,0 +1,148 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_059_1202 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 0.000110518923327; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.000920523273809; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.000913315978644; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 4> pq0 = { { { { 0.000517697731297, 0.03420075260565257 } }, + { { 0.00073311436821, 0.08313162364341634 } }, + { { 0.000846323283638, 0.13701491459108198 } }, + { { 0.000903112269425, 0.19307102433703996 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 13> llm = { { { { 0.000369042189802, 0.016720424160189817 } }, + { { 0.000560399092868, 0.04126017303586406 } }, + { { 0.000686529762928, 0.0694729706214065 } }, + { { 0.000772033855115, 0.09980353185791829 } }, + { { 0.000830154595889, 0.13155235170779025 } }, + { { 0.000868669255018, 0.16436581638357306 } }, + { { 0.000892707628585, 0.1980657851787268 } }, + { { 0.000906082023857, 0.23257851288553447 } }, + { { 0.000911977725494, 0.26790167541606985 } }, + { { 0.00091287201386, 0.3412238232237018 } }, + { { 0.000913071493569, 0.3794156291080754 } }, + { { 0.000915287378455, 0.4187196099185521 } }, + { { 0.000918743627432, 0.45903955700964827 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 16> rsw = { + { { { 0.000648577845316, 0.059125048710861904, 0.09104538585311528 } }, + { { 0.000743503091098, 0.08753554058354115, 0.13476625655108154 } }, + { { 0.000799852789184, 0.11063719205345883, 0.05547084389337896 } }, + { { 0.000810173149747, 0.117990254123381, 0.16014183229915946 } }, + { { 0.000848338957459, 0.14034322517430972, 0.09207018989157909 } }, + { { 0.000855629925731, 0.1498356879851596, 0.17669748867405466 } }, + { { 0.000880320867974, 0.1656336092513369, 0.040224891242256824 } }, + { { 0.000881104818243, 0.1715841534183696, 0.11785881091491886 } }, + { { 0.000885028234127, 0.18274525247006784, 0.18836275020540447 } }, + { { 0.000902134229904, 0.19589548091013856, 0.07047600592771162 } }, + { { 0.000901009167711, 0.20401067271108056, 0.1369616236187671 } }, + { { 0.000902269293843, 0.2165602520928162, 0.19702704234601376 } }, + { { 0.000915801617469, 0.22216394131587347, 0.03187470178277977 } }, + { { 0.000913157800319, 0.22746279397069277, 0.09394027570063196 } }, + { { 0.000910781357948, 0.23744932011918268, 0.15164004637018952 } }, + { { 0.000910576025897, 0.25122346068669016, 0.20369796009147373 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(1202); + Points xs = Points::Zero(3, 1202); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_065_1454.hpp b/src/surface_forces/detail/Lebedev_065_1454.hpp new file mode 100644 index 000000000..e47189b68 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_065_1454.hpp @@ -0,0 +1,144 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_065_1454 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 7.7771607433e-05; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.0007557646413; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 5> pq0 = { { { { 0.000402168044787, 0.03002483397375312 } }, + { { 0.000580487179395, 0.07356619587204107 } }, + { { 0.000679215195595, 0.1218942218184075 } }, + { { 0.000733674121129, 0.17244770702224507 } }, + { { 0.000758186630099, 0.22404572432210743 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 15> llm = { { { { 0.000284163380609, 0.014541973303948906 } }, + { { 0.000437441912705, 0.036256356902763215 } }, + { { 0.000541717474087, 0.06134347429283711 } }, + { { 0.000614800089136, 0.08841663566770758 } }, + { { 0.00066643944858, 0.11682578562312121 } }, + { { 0.000702503935692, 0.14622485492090825 } }, + { { 0.000726851178925, 0.176424040909554 } }, + { { 0.000742263753421, 0.20732548358335812 } }, + { { 0.000750954503584, 0.23889218046843466 } }, + { { 0.000754853505772, 0.27113178450101194 } }, + { { 0.000755408896977, 0.3378245651771407 } }, + { { 0.000755314717444, 0.3724214055050285 } }, + { { 0.000756476765329, 0.4079277989979188 } }, + { { 0.000758799180852, 0.4443064433703368 } }, + { { 0.000760826183203, 0.48135058138208653 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 20> rsw = { + { { { 0.00075382578598, 0.2558003577809087, 0.20859614189791004 } }, + { { 0.000748351724705, 0.22408472579890718, 0.2033204671768711 } }, + { { 0.000737176366111, 0.19306103334458685, 0.19666471662424795 } }, + { { 0.000718344889576, 0.16275432818948848, 0.18804149522722452 } }, + { { 0.000689581552982, 0.13324870864184388, 0.17643341386541955 } }, + { { 0.000648010580179, 0.10471633615407486, 0.15994385152980334 } }, + { { 0.000589755889659, 0.07747808165091459, 0.1346384497079675 } }, + { { 0.000509570884925, 0.05214524403629088, 0.09098925491262612 } }, + { { 0.000753690642891, 0.24277387514946042, 0.16254595611164124 } }, + { { 0.000747250596558, 0.21198920799674287, 0.15100683461207687 } }, + { { 0.000734301713228, 0.18199417202541565, 0.1364152050357355 } }, + { { 0.000713087158218, 0.1528797709057363, 0.1174379770106918 } }, + { { 0.000681702203211, 0.12483119354960753, 0.09179496313058289 } }, + { { 0.00063809411456, 0.09818737315696387, 0.055343676032884016 } }, + { { 0.000755038137792, 0.23269927807800983, 0.11182321068294632 } }, + { { 0.000747864664014, 0.203313866757253, 0.09333015692137783 } }, + { { 0.00073359187206, 0.17490196727498353, 0.07006345916885712 } }, + { { 0.000711012052766, 0.1476521039744757, 0.04002895490431486 } }, + { { 0.000757136397869, 0.22626624665276363, 0.057100620618486995 } }, + { { 0.000748990832908, 0.19874998248857403, 0.03161917277066387 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(1454); + Points xs = Points::Zero(3, 1454); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = + xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws( + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + auto xs_ = xs( + Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_071_1730.hpp b/src/surface_forces/detail/Lebedev_071_1730.hpp new file mode 100644 index 000000000..059c47b82 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_071_1730.hpp @@ -0,0 +1,161 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + +namespace detail { +class Lebedev_071_1730 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 6.3090494374e-05; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.000639828770557; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.000635718507353; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 5> pq0 = { { { { 0.000318691344995, 0.02662567388107946 } }, + { { 0.000467802855859, 0.06572409006333814 } }, + { { 0.00055388296976, 0.1094192803396822 } }, + { { 0.000604447590719, 0.15535139330769052 } }, + { { 0.000631357510351, 0.20242837200985242 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 16> llm = { { { { 0.000222120716219, 0.0128821951216131 } }, + { { 0.000347578402229, 0.032207731604644504 } }, + { { 0.000435074244359, 0.054701957361929614 } }, + { { 0.000497856913652, 0.07907872541215494 } }, + { { 0.0005435036222, 0.10472423247884396 } }, + { { 0.000576591338822, 0.1313033365858972 } }, + { { 0.000600120035923, 0.15862323583036297 } }, + { { 0.000616217817272, 0.1865740566052706 } }, + { { 0.000626521815244, 0.21509963472632135 } }, + { { 0.000632398716097, 0.2441820363305423 } }, + { { 0.000635076785154, 0.27383276117335115 } }, + { { 0.00063543627753, 0.33499578715110123 } }, + { { 0.000635230246271, 0.3666178126756868 } }, + { { 0.000635811788142, 0.39899550033190523 } }, + { { 0.000637310159031, 0.43211887236649743 } }, + { { 0.000639042896137, 0.46587318374717057 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 25> rsw = { + { { { 0.000407862643186, 0.04644429609109567, 0.09094145309269727 } }, + { { 0.000475993305781, 0.06923315329746019, 0.1345446587879024 } }, + { { 0.000526815118641, 0.09380751997100091, 0.1597986971590518 } }, + { { 0.000564304856051, 0.11959776925851553, 0.17623731960187097 } }, + { { 0.000591450107661, 0.1462944266839557, 0.18779859315577804 } }, + { { 0.000610456125787, 0.17372158857969944, 0.19638310871162132 } }, + { { 0.000623025286071, 0.20178171635925438, 0.20301334075208635 } }, + { { 0.000630561876176, 0.23042860761585268, 0.20828355715615282 } }, + { { 0.00063430927676, 0.25965307523608, 0.21255830404253653 } }, + { { 0.000517626894574, 0.08794707624386362, 0.05525153980013495 } }, + { { 0.000556484031331, 0.11204509589546444, 0.09159274175854999 } }, + { { 0.000585642667104, 0.13744522362543432, 0.11712413186869162 } }, + { { 0.000606638692578, 0.1638235897217632, 0.13599893913777458 } }, + { { 0.000620882496223, 0.19099329347026625, 0.1505076183425183 } }, + { { 0.000629631429782, 0.21885026631240181, 0.16199557887487917 } }, + { { 0.000634042375679, 0.24734548378169824, 0.17129282153427458 } }, + { { 0.000582962767711, 0.1327847126725995, 0.03988414867701234 } }, + { { 0.000604869337608, 0.1575226934924021, 0.06975403592073667 } }, + { { 0.000620236231773, 0.18331731309264804, 0.09286112723766339 } }, + { { 0.00062990053284, 0.20997811889533646, 0.11122182993593546 } }, + { { 0.000634772239061, 0.2373961100597402, 0.12612209724859638 } }, + { { 0.000620377898124, 0.17930414564418112, 0.03142567934766161 } }, + { { 0.000630841467124, 0.20435855567306369, 0.05670247592940609 } }, + { { 0.000636270646696, 0.23033583124044069, 0.07740125753569922 } }, + { { 0.000637541417033, 0.22665311278358263, 0.02611611008118614 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(1730); + Points xs = Points::Zero(3, 1730); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail diff --git a/src/surface_forces/detail/Lebedev_077_2030.hpp b/src/surface_forces/detail/Lebedev_077_2030.hpp new file mode 100644 index 000000000..0d454a5f3 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_077_2030.hpp @@ -0,0 +1,160 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + + +namespace detail { +class Lebedev_077_2030 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 4.6560318992e-05; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.00054215491953; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 6> pq0 = { { { { 0.000256800249773, 0.02382873604048719 } }, + { { 0.000382721170029, 0.05919454144498195 } }, + { { 0.000457949156192, 0.09897501240267485 } }, + { { 0.000504200396908, 0.14097739113409083 } }, + { { 0.000531270888998, 0.18418303972165878 } }, + { { 0.000543840179075, 0.22799849848688084 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 18> llm = { { { { 0.000177852213335, 0.011440240333553339 } }, + { { 0.000281132540568, 0.02884654222301814 } }, + { { 0.000354889631263, 0.04918482752065367 } }, + { { 0.000409031089717, 0.07129976191437562 } }, + { { 0.000449328613417, 0.09462257239966308 } }, + { { 0.000479372844796, 0.11883307451319587 } }, + { { 0.000501541531916, 0.14374040519867876 } }, + { { 0.000517512737268, 0.16922931750291914 } }, + { { 0.000528552226208, 0.19523304655136767 } }, + { { 0.000535683270371, 0.2217185876480012 } }, + { { 0.000539791473618, 0.24867829648769377 } }, + { { 0.00054168994416, 0.2761247273453157 } }, + { { 0.000541930847689, 0.33260491862951663 } }, + { { 0.000541693690203, 0.361724274183216 } }, + { { 0.00054195443387, 0.39148038327329115 } }, + { { 0.000542898365663, 0.42187592637813365 } }, + { { 0.00054422865001, 0.452847070422067 } }, + { { 0.000545225034506, 0.48423160979755336 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 30> rsw = { + { { { 0.00033160418732, 0.041717375566021495, 0.0909121294226695 } }, + { { 0.000389911356715, 0.0623698186564717, 0.1344754439526608 } }, + { { 0.00043433433272, 0.08470338444769895, 0.1596897782776591 } }, + { { 0.000467941526232, 0.1081870685924007, 0.1760888376667163 } }, + { { 0.000493084798163, 0.1325248525263869, 0.1876123327182394 } }, + { { 0.000511503186754, 0.1575419782291847, 0.19616323676607925 } }, + { { 0.000524521714846, 0.18313463768637675, 0.2027669357714648 } }, + { { 0.00053320414999, 0.20924485380242722, 0.20802142331344914 } }, + { { 0.000538458312602, 0.23584693931713388, 0.21229618706426556 } }, + { { 0.00054110672108, 0.2629397299261896, 0.21582896181460065 } }, + { { 0.000425979739147, 0.07939622760508908, 0.055182374747974626 } }, + { { 0.000460493136846, 0.10134657952582082, 0.09144055632471736 } }, + { { 0.000487181487826, 0.1245144128130184, 0.1168857298537963 } }, + { { 0.000507224291007, 0.1485925561541061, 0.13567815467589486 } }, + { { 0.000521706984524, 0.1733972541505497, 0.15011458258626764 } }, + { { 0.000531578596628, 0.1988190002039459, 0.16154737711489003 } }, + { { 0.000537683370876, 0.22479687342928137, 0.17081525014445756 } }, + { { 0.000540803209207, 0.2513043794619103, 0.17845916790513258 } }, + { { 0.00048427449179, 0.12031244726303181, 0.03977490130136878 } }, + { { 0.000504892607619, 0.14292449218331743, 0.06951809343561059 } }, + { { 0.000520260798048, 0.16651144408744856, 0.09249764235304189 } }, + { { 0.000530993238833, 0.19088638537196473, 0.11074376794678162 } }, + { { 0.00053774197709, 0.2159349509430741, 0.12555631421581928 } }, + { { 0.000541169633168, 0.2415923854202134, 0.1377912289972581 } }, + { { 0.000519799629328, 0.1629280674120531, 0.031277144226667615 } }, + { { 0.000531112083662, 0.18589222528429114, 0.056391299211738244 } }, + { { 0.000538430931996, 0.20969245446347537, 0.07693651699435375 } }, + { { 0.000542185950405, 0.23421699784124456, 0.09400845965175704 } }, + { { 0.000539094835505, 0.20645400832343744, 0.02593526986849543 } }, + { { 0.000543331270503, 0.22958259580795992, 0.04771629680091758 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(2030); + Points xs = Points::Zero(3, 2030); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = + xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws( + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + auto xs_ = xs( + Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail + diff --git a/src/surface_forces/detail/Lebedev_083_2354.hpp b/src/surface_forces/detail/Lebedev_083_2354.hpp new file mode 100644 index 000000000..6aa51a97f --- /dev/null +++ b/src/surface_forces/detail/Lebedev_083_2354.hpp @@ -0,0 +1,178 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + + +namespace detail { +class Lebedev_083_2354 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 3.9226162707e-05; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.000470383175085; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.000467820280128; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 6> pq0 = { { { { 0.000209994228107, 0.02148323008071945 } }, + { { 0.000317226915071, 0.053688384512778804 } }, + { { 0.000383205135855, 0.09012092708102555 } }, + { { 0.000425219381815, 0.12874501337985692 } }, + { { 0.000451380796375, 0.16860448658816918 } }, + { { 0.000465779746911, 0.209148252869559 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 19> llm = { { { { 0.000143783222898, 0.0103105356590626 } }, + { { 0.000230357249358, 0.02604407895727144 } }, + { { 0.000293311075245, 0.04454481490925946 } }, + { { 0.000340290599836, 0.06473491178346792 } }, + { { 0.000375913846687, 0.08607922577105943 } }, + { { 0.00040306384479, 0.10827224463759817 } }, + { { 0.000423659143224, 0.13112750294976167 } }, + { { 0.000439052265695, 0.15452812760064788 } }, + { { 0.000450252346663, 0.17840164434395828 } }, + { { 0.000458057772778, 0.20270607993191486 } }, + { { 0.000463139161662, 0.22742189873716076 } }, + { { 0.00046609289537, 0.2525471144673109 } }, + { { 0.000467475180794, 0.278094061578268 } }, + { { 0.000467641490393, 0.33055750758729435 } }, + { { 0.000467408649235, 0.35754201306062255 } }, + { { 0.000467492853948, 0.38506984706068115 } }, + { { 0.000468074897969, 0.413149299426279 } }, + { { 0.000469044980639, 0.4417452451509824 } }, + { { 0.000469987707586, 0.4707553754870439 } } } }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 36> rsw = { + { { { 0.000273336280052, 0.037743625637352785, 0.09088472512920288 } }, + { { 0.000323548536846, 0.05658124612192914, 0.13442239982419044 } }, + { { 0.000362490872601, 0.07700624085599411, 0.15960668222432448 } }, + { { 0.000392554007071, 0.09852377819321616, 0.17597464333125812 } }, + { { 0.000415612978112, 0.12085224031518965, 0.18746763179651368 } }, + { { 0.000433064498462, 0.14382072327200804, 0.19599015346591778 } }, + { { 0.000445967772592, 0.16732318186207223, 0.20256938328271545 } }, + { { 0.000455159300446, 0.19129519268422873, 0.2078055112217531 } }, + { { 0.000461334146275, 0.21570120393595657, 0.2120708126146701 } }, + { { 0.000465101961827, 0.24052715022858334, 0.2156066524708237 } }, + { { 0.00046702495361, 0.26577591697740255, 0.2185744280602722 } }, + { { 0.000354955557644, 0.07216504764039339, 0.055130070446995944 } }, + { { 0.000385610824525, 0.09228070552880042, 0.0913242194519082 } }, + { { 0.000409862284576, 0.11354199196436619, 0.11670182943449679 } }, + { { 0.000428632860427, 0.1356585148603882, 0.13542796525954431 } }, + { { 0.000442780219899, 0.15845204047317685, 0.14980340556108718 } }, + { { 0.000453047351149, 0.18181171606183896, 0.16118476007373866 } }, + { { 0.00046008054757, 0.20567040966642677, 0.1704157879330728 } }, + { { 0.000464459905996, 0.2299914766537107, 0.17804384755163255 } }, + { { 0.000466727445571, 0.2547609952738979, 0.1844353087637181 } }, + { { 0.000406936051802, 0.10971921112740224, 0.03969101287175254 } }, + { { 0.000426044281992, 0.1305095211763083, 0.06933542701583828 } }, + { { 0.000440867850803, 0.15220870821515906, 0.0922129333437181 } }, + { { 0.000451874811555, 0.17463595623685488, 0.1103629057453786 } }, + { { 0.000459556487538, 0.19767599129304933, 0.12509380222310257 } }, + { { 0.000464398877432, 0.22125786065218556, 0.13727104621488875 } }, + { { 0.000466882749165, 0.2453423661150161, 0.14748176427821896 } }, + { { 0.000440054182374, 0.1489712500225431, 0.031161557211991396 } }, + { { 0.000451451289019, 0.1701392349394957, 0.05614611735613247 } }, + { { 0.000459619862735, 0.1920763306362031, 0.07656320836273045 } }, + { { 0.00046486590168, 0.21466903585235447, 0.0935232678749094 } }, + { { 0.000467550201716, 0.237846060277366, 0.10780208571690666 } }, + { { 0.000459849447646, 0.18918326318817155, 0.025791431603201697 } }, + { { 0.000465491695515, 0.21055131325424792, 0.04742096375190213 } }, + { { 0.000468470977951, 0.23260332842524298, 0.06577176881442136 } }, + { { 0.000469144553911, 0.2298980098880378, 0.022118446350596878 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(2354); + Points xs = Points::Zero(3, 2354); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail + diff --git a/src/surface_forces/detail/Lebedev_089_2702.hpp b/src/surface_forces/detail/Lebedev_089_2702.hpp new file mode 100644 index 000000000..eb7d19b17 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_089_2702.hpp @@ -0,0 +1,168 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + + +namespace detail { +class Lebedev_089_2702 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 2.9986751499e-05; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.00040778605295; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 7> pq0 = { { { { 0.000173898681175, 0.019504083272014666 } }, + { { 0.000265961604528, 0.048992350041236 } }, + { { 0.000324059600817, 0.0825332235620925 } }, + { { 0.000362119596443, 0.11822519839431116 } }, + { { 0.000386883833076, 0.15516757030789682 } }, + { { 0.000401891153269, 0.19284298215381002 } }, + { { 0.000408992943298, 0.23090699168193182 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 21> llm = { + { { { 0.000118534919252, 0.009299621174798444 } }, { { 0.000191340864343, 0.023659215108291817 } }, + { { 0.000245288657721, 0.040594837447854165 } }, { { 0.000286240818329, 0.05913124047454959 } }, + { { 0.000317803225826, 0.07877165755876729 } }, { { 0.000342294566763, 0.09922627578196008 } }, + { { 0.000361279052024, 0.1203145040693523 } }, { { 0.000375863822982, 0.14192006474436658 } }, + { { 0.000386871179886, 0.16396770467049449 } }, { { 0.000394942993319, 0.18641014672799455 } }, + { { 0.000400606810754, 0.20922039460299993 } }, { { 0.000404319214967, 0.23238702174833858 } }, + { { 0.000406494749581, 0.255911158481507 } }, { { 0.000407524561981, 0.27980436335312925 } }, + { { 0.000407642354089, 0.3287844859640549 } }, { { 0.000407428086225, 0.3539262986287412 } }, + { { 0.000407416375601, 0.37953686493412986 } }, { { 0.000407764779507, 0.4056266456277628 } }, + { { 0.000408451755278, 0.4321769981995628 } }, { { 0.000409246845922, 0.4591229832325327 } }, + { { 0.000409787268724, 0.4863416665034887 } } } + }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 42> rsw = { + { { { 0.000227990752771, 0.03436681470127729, 0.09086849544871468 } }, + { { 0.000271520549058, 0.051644421330199426, 0.13438217012923867 } }, + { { 0.00030579178967, 0.07042550801173678, 0.15954236093630902 } }, + { { 0.000332691305245, 0.09024803669564561, 0.17588550976799394 } }, + { { 0.000353733471189, 0.11084459756408502, 0.18735370470068727 } }, + { { 0.000370056750078, 0.13204947781981466, 0.19585248971516858 } }, + { { 0.000382524537259, 0.1537567152755291, 0.2024101946225456 } }, + { { 0.000391812517152, 0.1758985905010745, 0.20762836888005923 } }, + { { 0.000398472041994, 0.1984336588948514, 0.21188095922911135 } }, + { { 0.000402974600334, 0.22133971967495242, 0.21541144144517566 } }, + { { 0.000405742863216, 0.24460950296105605, 0.21838392518490038 } }, + { { 0.000407171927411, 0.2682478541828218, 0.22091169113093448 } }, + { { 0.000299023695066, 0.06598188689594922, 0.055089534111938475 } }, + { { 0.000326295173421, 0.08451357920461729, 0.09123376892849176 } }, + { { 0.000348263460824, 0.10412844646981298, 0.11655782680613067 } }, + { { 0.00036565966817, 0.12455231517854437, 0.13523033141502266 } }, + { { 0.000379174046779, 0.14561357152343674, 0.14955486971484258 } }, + { { 0.000389403445016, 0.16720229214098942, 0.16089079428781922 } }, + { { 0.000396860024551, 0.18924841946053073, 0.17008496585779787 } }, + { { 0.000401993135142, 0.2117094049587665, 0.17768852416441078 } }, + { { 0.000405210880128, 0.2345628880915592, 0.1840726291968587 } }, + { { 0.000406897861394, 0.2578021611634835, 0.1894935735877868 } }, + { { 0.000345427535132, 0.10062502552805537, 0.0396255830809811 } }, + { { 0.000362996353701, 0.11983775907421261, 0.06919193291928188 } }, + { { 0.000377018723389, 0.13990431349250007, 0.09198727485723154 } }, + { { 0.000387860861369, 0.16065107710970586, 0.11005739257320142 } }, + { { 0.000395906527022, 0.18196424996532481, 0.12471640471346784 } }, + { { 0.000401528697546, 0.20377022223408525, 0.1368356052613229 } }, + { { 0.000405086678561, 0.22602383303298287, 0.1470089338642573 } }, + { { 0.000406932018505, 0.24870114433171436, 0.1556502756669482 } }, + { { 0.000376012096406, 0.13695207931460154, 0.03107036643743837 } }, + { { 0.000387096956442, 0.15656068154418076, 0.05595093547248068 } }, + { { 0.000395528779053, 0.17688469742993385, 0.07626210978060294 } }, + { { 0.00040153619113, 0.19781170620276076, 0.09312413288736685 } }, + { { 0.000405383698672, 0.2192674038421525, 0.10732270843070195 } }, + { { 0.00040735786733, 0.2412055444632103, 0.11941677099067832 } }, + { { 0.000395462837923, 0.17426866411547765, 0.025676175296736718 } }, + { { 0.000401764550885, 0.19410348608945335, 0.04718083967949124 } }, + { { 0.000405903034865, 0.21456648708853332, 0.06541131103330632 } }, + { { 0.000408056580948, 0.23558660319741667, 0.08102731647185069 } }, + { { 0.000406301875366, 0.2121495916641633, 0.02198403859038884 } }, + { { 0.00040871912928, 0.23209355666287107, 0.04097218051583061 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(2702); + Points xs = Points::Zero(3, 2702); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = + xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws( + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + auto xs_ = xs( + Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail + diff --git a/src/surface_forces/detail/Lebedev_095_3074.hpp b/src/surface_forces/detail/Lebedev_095_3074.hpp new file mode 100644 index 000000000..1b6442b4e --- /dev/null +++ b/src/surface_forces/detail/Lebedev_095_3074.hpp @@ -0,0 +1,186 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + + +namespace detail { +class Lebedev_095_3074 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 2.5990959538e-05; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.000360313408969; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.000358606797441; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 7> pq0 = { { { { 0.000145644709674, 0.01780632613066149 } }, + { { 0.000225237018828, 0.044947649826731696 } }, + { { 0.000276613544347, 0.07596872960251945 } }, + { { 0.00031107294915, 0.10909458634282024 } }, + { { 0.00033425067123, 0.14347412010759739 } }, + { { 0.000349198183403, 0.17861837137640935 } }, + { { 0.000357600360435, 0.2142066684242369 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 22> llm = { + { { { 9.8315284744e-05, 0.008491478491336383 } }, { { 0.000160502310795, 0.0216252009289231 } }, + { { 0.000207220013146, 0.03719980947578939 } }, { { 0.000243129761881, 0.05430034267672929 } }, + { { 0.00027118190645, 0.07245921913487467 } }, { { 0.000293276203832, 0.09140116470751057 } }, + { { 0.00031070325142, 0.1109520797855045 } }, { { 0.000324380805892, 0.13099759338729772 } }, + { { 0.000334989909137, 0.15146147974388993 } }, { { 0.000343058068851, 0.1722934370888343 } }, + { { 0.000349012410929, 0.19346178184185475 } }, { { 0.000353214894856, 0.2149489150562011 } }, + { { 0.000355986266906, 0.23674841919071238 } }, { { 0.000357622431755, 0.2588631079592939 } }, + { { 0.000358405053309, 0.28130355966846415 } }, { { 0.000358490358137, 0.32723414474220325 } }, + { { 0.000358299187904, 0.35076920668375916 } }, { { 0.000358237118796, 0.37471263299687224 } }, + { { 0.000358435363112, 0.3990753718567368 } }, { { 0.000358912016652, 0.42384837461845704 } }, + { { 0.000359544570453, 0.44899023881292777 } }, { { 0.000360094355711, 0.4744167749955591 } } } + }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 49> rsw = { + { { { 0.000192192130579, 0.031465662351515905, 0.09085164306768208 } }, + { { 0.00023014582165, 0.047391274897813765, 0.13435012987204045 } }, + { { 0.000260424854952, 0.06474365273393522, 0.15949159054664724 } }, + { { 0.000284527542587, 0.08309105162827109, 0.17581481825424403 } }, + { { 0.000303687089797, 0.10217994835018449, 0.18726279838436768 } }, + { { 0.00031884148323, 0.12185054471509318, 0.19574180715936648 } }, + { { 0.000330704641472, 0.14199834411329149, 0.2022809630751209 } }, + { { 0.000339833096903, 0.16255425833037224, 0.20748271274310928 } }, + { { 0.000346675789971, 0.1834734047562495, 0.2117220650020316 } }, + { { 0.000351609592323, 0.20472843521609305, 0.21524379429238114 } }, + { { 0.000354964518405, 0.22630540159341608, 0.21821363386661324 } }, + { { 0.000357041596944, 0.2482010920943633, 0.22074692285287065 } }, + { { 0.00035812517985, 0.27042119121176594, 0.22292542923153252 } }, + { { 0.000254349132991, 0.06064339323452652, 0.055057764324450115 } }, + { { 0.000278671105133, 0.07779507453052478, 0.09116229894048221 } }, + { { 0.000298555236108, 0.0959746938704924, 0.11644339534113997 } }, + { { 0.000314586792915, 0.11492342603434177, 0.13507225317618396 } }, + { { 0.000327329066207, 0.13447671452436294, 0.14935442403997615 } }, + { { 0.000337270551194, 0.1545268389697898, 0.16065112739682047 } }, + { { 0.000344827443785, 0.17500276656351987, 0.16981124601058925 } }, + { { 0.000350359278305, 0.19585862595374656, 0.17738828884663443 } }, + { { 0.000354185479266, 0.21706680119919253, 0.18375632088577024 } }, + { { 0.000356599551791, 0.23861363429976987, 0.1891752884830942 } }, + { { 0.00035788020783, 0.2604966284261268, 0.1938295025157241 } }, + { { 0.000295864459286, 0.09274427704983511, 0.0395737232927744 } }, + { { 0.000311954812912, 0.11057845952784265, 0.06907763088162186 } }, + { { 0.000325074522501, 0.12921937707613373, 0.09180631818787073 } }, + { { 0.000335515341594, 0.14850101251605247, 0.10981020998375317 } }, + { { 0.000343584756855, 0.16831231500083096, 0.12440734609770791 } }, + { { 0.000349578683162, 0.188579058802564, 0.13647287735999802 } }, + { { 0.000353776780553, 0.20925288683827323, 0.14660501010704388 } }, + { { 0.000356445981542, 0.23030450756758208, 0.1552227164749716 } }, + { { 0.000357846406123, 0.2517193463622896, 0.16262497682493987 } }, + { { 0.000323974876284, 0.12650692621088908, 0.030997494536175008 } }, + { { 0.000334549178417, 0.14474962575433292, 0.05579389682143906 } }, + { { 0.00034291261773, 0.16366334732767546, 0.0760175394141712 } }, + { { 0.00034924203431, 0.1831382423052164, 0.09279551520127183 } }, + { { 0.000353739905024, 0.20309929262528792, 0.1069200932593852 } }, + { { 0.000356620915266, 0.22349687087566739, 0.1189572114735275 } }, + { { 0.000358108432192, 0.24430059419858002, 0.12931678922977702 } }, + { { 0.000342652211759, 0.1612750766348191, 0.025582990466131734 } }, + { { 0.000349184877012, 0.17976340654842216, 0.04698470477753579 } }, + { { 0.000353931823523, 0.19883523525711896, 0.06511234997254838 } }, + { { 0.000357023143846, 0.21841811256686908, 0.08063545461473559 } }, + { { 0.000358620733505, 0.23846345426669463, 0.09405097152337796 } }, + { { 0.000354119620516, 0.19664915215120718, 0.02187331846961495 } }, + { { 0.000357429691157, 0.21527283022919985, 0.0407454681687205 } }, + { { 0.000359199327982, 0.23442242541551717, 0.05716016707015379 } }, + { { 0.000359585503466, 0.23235214507614843, 0.019181495137045916 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(3074); + Points xs = Points::Zero(3, 3074); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail + diff --git a/src/surface_forces/detail/Lebedev_101_3470.hpp b/src/surface_forces/detail/Lebedev_101_3470.hpp new file mode 100644 index 000000000..7bef9797e --- /dev/null +++ b/src/surface_forces/detail/Lebedev_101_3470.hpp @@ -0,0 +1,184 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + + +namespace detail { +class Lebedev_101_3470 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 2.0403827308e-05; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.000317814970389; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 8> pq0 = { { { { 0.000123177961174, 0.016344556304521085 } }, + { { 0.000192466137384, 0.04143335771795334 } }, + { { 0.00023808818674, 0.07024202312571583 } }, + { { 0.000269310066304, 0.10110526879039469 } }, + { { 0.000290867338283, 0.1332173558287646 } }, + { { 0.000305391461938, 0.16611408528089006 } }, + { { 0.000314391668415, 0.19949362467056284 } }, + { { 0.000318704224406, 0.23313659571307074 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 24> llm = { + { { { 8.2881151281e-05, 0.007749881947614417 } }, { { 0.000136088319252, 0.01985979432565779 } }, + { { 0.000176685445454, 0.03425415017932637 } }, { { 0.000208315316123, 0.05009920744950451 } }, + { { 0.000233327954466, 0.06695936394100163 } }, { { 0.000253280953993, 0.08457387144861545 } }, + { { 0.000269247218421, 0.10277546875267733 } }, { { 0.000281994994681, 0.12145249207179949 } }, + { { 0.000292095359397, 0.14052889127712842 } }, { { 0.000299988978295, 0.15995280065216833 } }, + { { 0.00030602921205, 0.1796896304794532 } }, { { 0.000310510916752, 0.19971772633860269 } }, + { { 0.000313690238755, 0.22002556156551312 } }, { { 0.000315798465245, 0.24060986646702168 } }, + { { 0.000317051651843, 0.26147431218432343 } }, { { 0.000317656842563, 0.28262846221673504 } }, + { { 0.000317719841121, 0.32586699357539184 } }, { { 0.000317551949239, 0.3479885990052334 } }, + { { 0.000317465495263, 0.37046903559938327 } }, { { 0.000317567641547, 0.39331892936675267 } }, + { { 0.000317892341784, 0.4165348535670623 } }, { { 0.000318378828753, 0.4400904100279172 } }, + { { 0.000318875515192, 0.4639277106906239 } }, { { 0.000319191688931, 0.4879536792385888 } } } + }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 56> rsw = { + { { { 0.000163521953587, 0.02895240483472415, 0.09084195687644707 } }, + { { 0.00019681099177, 0.04369558678151344, 0.13432493392428288 } }, + { { 0.000223675434225, 0.05979582876450281, 0.15945098252294698 } }, + { { 0.000245318668702, 0.0768486985208707, 0.1757580397498497 } }, + { { 0.000262755179158, 0.09461381877597969, 0.18718942306243078 } }, + { { 0.000276765486015, 0.11293757086948318, 0.19565192809740675 } }, + { { 0.000287946702777, 0.1317177415550717, 0.20217522837546045 } }, + { { 0.000296763991892, 0.15088508287849187, 0.20736238698169687 } }, + { { 0.000303590068466, 0.17039283361245564, 0.2115891231725775 } }, + { { 0.00030873382373, 0.1902104102216678, 0.21510105422035866 } }, + { { 0.000312460883886, 0.2103194512451932, 0.21806493737281718 } }, + { { 0.000315008429423, 0.23071125619635593, 0.22059737811839863 } }, + { { 0.00031659583986, 0.2513850612816363, 0.2227817287466194 } }, + { { 0.000317432044096, 0.27234678349164093, 0.22467843869304452 } }, + { { 0.000218218890981, 0.05599486317166561, 0.05503227538999848 } }, + { { 0.000239972793392, 0.07193464175708549, 0.09110500957893775 } }, + { { 0.000257979613351, 0.08885280803282207, 0.11635132746450935 } }, + { { 0.000272711405262, 0.10650493423082077, 0.13494440518144474 } }, + { { 0.000284632765628, 0.12473359798461711, 0.14919124865826203 } }, + { { 0.000294149110205, 0.14343399483159447, 0.16045439583854126 } }, + { { 0.000301604949214, 0.1625353035180764, 0.16958411014215521 } }, + { { 0.000307294972618, 0.18198993800012658, 0.1771354656149772 } }, + { { 0.000311476814289, 0.2017670436828468, 0.18348438591351865 } }, + { { 0.000314382367367, 0.22184841321857326, 0.18889309003713706 } }, + { { 0.000316226976466, 0.24222583392231792, 0.1935487183660536 } }, + { { 0.000317216466376, 0.262899280163646, 0.19758700828153689 } }, + { { 0.000255457539897, 0.08585864873460385, 0.03953209605484016 } }, + { { 0.000270170406914, 0.10247860536605306, 0.06898549045868849 } }, + { { 0.000282369341347, 0.11986423146649551, 0.09165965685856722 } }, + { { 0.000292289846321, 0.13785710478175447, 0.10960847846368107 } }, + { { 0.000300182906216, 0.15634959107904098, 0.12415281154317126 } }, + { { 0.000306289086454, 0.17526804844229302, 0.13617046576998615 } }, + { { 0.000310832827926, 0.194562608754736, 0.1462624680310711 } }, + { { 0.00031402431462, 0.21420077832515072, 0.15485102812076776 } }, + { { 0.000316063803098, 0.23416332254082484, 0.16223902758452816 } }, + { { 0.000317146288221, 0.25444153772600936, 0.1686471915943984 } }, + { { 0.000281238841603, 0.11735653737831038, 0.030938590172687394 } }, + { { 0.000291213750029, 0.13439343726746683, 0.055666271865395384 } }, + { { 0.00029932412565, 0.15206375390225602, 0.07581732660441519 } }, + { { 0.000305710173898, 0.17026098633638423, 0.09252381873240215 } }, + { { 0.000310531932625, 0.18891072480321247, 0.10658258550064224 } }, + { { 0.000313956551443, 0.20796181155773216, 0.11856421720479345 } }, + { { 0.000316154300681, 0.22738053976144706, 0.1288837991223337 } }, + { { 0.000317298596061, 0.24714678625564723, 0.13784718367975352 } }, + { { 0.00029894003369, 0.14986647996439656, 0.02550696778125542 } }, + { { 0.000305455588395, 0.16716346521387787, 0.04682346651442345 } }, + { { 0.000310476496081, 0.18500713945116673, 0.06486389837721507 } }, + { { 0.000314101582598, 0.20332524290354823, 0.08030462915259472 } }, + { { 0.000316452062116, 0.22206729905893724, 0.09364959837002847 } }, + { { 0.000317665230591, 0.24119971687448638, 0.10527704392520035 } }, + { { 0.000310509716102, 0.18301036563682505, 0.02178173880939733 } }, + { { 0.000314301411789, 0.20046242422286578, 0.04055566473710004 } }, + { { 0.000316817286629, 0.2184026925264357, 0.05687451971222168 } }, + { { 0.000318140186557, 0.23678341481600007, 0.07116400470382565 } }, + { { 0.000317066365916, 0.21653004466353704, 0.019077823421055667 } }, + { { 0.000318544794463, 0.23405840187253335, 0.03589394868915266 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(3470); + Points xs = Points::Zero(3, 3470); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = + xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws( + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + auto xs_ = xs( + Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail + diff --git a/src/surface_forces/detail/Lebedev_107_3890.hpp b/src/surface_forces/detail/Lebedev_107_3890.hpp new file mode 100644 index 000000000..04ee4a721 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_107_3890.hpp @@ -0,0 +1,204 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + + +namespace detail { +class Lebedev_107_3890 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 1.8073952522e-05; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.000284800878224; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.000283606583753; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 8> pq0 = { { { { 0.000105119340697, 0.015068765785941985 } }, + { { 0.00016578718388, 0.03835680822920328 } }, + { { 0.000206464811371, 0.06520909095162035 } }, + { { 0.000234794274582, 0.09406401498682768 } }, + { { 0.00025477753266, 0.12415729394387427 } }, + { { 0.000268687668485, 0.15504683778658174 } }, + { { 0.000277866575552, 0.18644642293553204 } }, + { { 0.000283099661678, 0.21815146497067894 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 25> llm = { + { { { 7.0131492667e-05, 0.0071485561308244445 } }, { { 0.000116279802196, 0.018327932440800655 } }, + { { 0.000151872858397, 0.03167988232944343 } }, { { 0.000179879610822, 0.046417885731530835 } }, + { { 0.000202259338597, 0.06213106301582435 } }, { { 0.000220309310558, 0.07857193698102315 } }, + { { 0.00023492942343, 0.09558007711401575 } }, { { 0.000246768205875, 0.11304697548857842 } }, + { { 0.000256309268357, 0.13089748552923006 } }, { { 0.000263925389676, 0.14907913221786356 } }, + { { 0.000269913747927, 0.1675555923435256 } }, { { 0.000274519642017, 0.1863025548503725 } }, + { { 0.00027795291974, 0.20530501433081755 } }, { { 0.000280399608668, 0.22455545786553988 } }, + { { 0.000282030235672, 0.24405261231057868 } }, { { 0.000283005674749, 0.2638005234793376 } }, + { { 0.000283480895078, 0.28380778325245215 } }, { { 0.000283528233908, 0.3246523693301685 } }, + { { 0.000283381926707, 0.3455208724864761 } }, { { 0.000283285833691, 0.3667071021506386 } }, + { { 0.000283326823545, 0.3882209984773418 } }, { { 0.000283543267703, 0.4100624231974284 } }, + { { 0.000283909172274, 0.4322146629721852 } }, { { 0.000284330817888, 0.45463772672101627 } }, + { { 0.000284670355053, 0.47726402550022157 } } } + }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 64> rsw = { + { { { 0.000140306334017, 0.026756904116324767, 0.09083080758751778 } }, + { { 0.000169650412594, 0.040459352526304795, 0.13430432175017948 } }, + { { 0.000193578724275, 0.0554544547393813, 0.15941814239107843 } }, + { { 0.000213061451052, 0.07136296772926985, 0.1757119504803404 } }, + { { 0.000228938126593, 0.08795701444283947, 0.18712958944497504 } }, + { { 0.000241863029282, 0.10508921824591066, 0.19557825010237478 } }, + { { 0.000252340049563, 0.1226601236364336, 0.2020880151062703 } }, + { { 0.000260762397345, 0.14060108941846416, 0.20726238792918977 } }, + { { 0.000267444103269, 0.15886448968189493, 0.21147757945380982 } }, + { { 0.000272643236034, 0.1774177586022931, 0.21497977487366274 } }, + { { 0.000276578768592, 0.19623961744590462, 0.21793640505617762 } }, + { { 0.000279442869064, 0.21531760918682935, 0.22046489014207246 } }, + { { 0.000281409900206, 0.23464644121628148, 0.22264958119749648 } }, + { { 0.000282642953158, 0.2542268234215635, 0.22455216289232777 } }, + { { 0.000283298354255, 0.27406457883308355, 0.22621825664742723 } }, + { { 0.000188669556528, 0.051916664429042976, 0.05501179674321844 } }, + { { 0.000208186788275, 0.06678453710310651, 0.09105863130162835 } }, + { { 0.00022451486806, 0.08258593949522913, 0.11627645997800351 } }, + { { 0.000238037049151, 0.09908984525335837, 0.13483995090273831 } }, + { { 0.000249139804185, 0.1161458293078442, 0.14905719519611704 } }, + { { 0.000258163240588, 0.13365237154416265, 0.16029169857277037 } }, + { { 0.000265396550623, 0.15153958867365605, 0.16939470240128604 } }, + { { 0.000271085721675, 0.16975920517058327, 0.17692235335047635 } }, + { { 0.00027544340939, 0.18827843341350048, 0.18325181388522935 } }, + { { 0.000278657993252, 0.20707609536882474, 0.18864678068216575 } }, + { { 0.000280901108068, 0.2261400884151262, 0.19329619330299586 } }, + { { 0.000282333618456, 0.24546567532275862, 0.19733800814753286 } }, + { { 0.000283110117581, 0.26505426730152926, 0.20087427916745015 } }, + { { 0.000222167997035, 0.07979832354317783, 0.03949830261034868 } }, + { { 0.000235618573427, 0.09534128386361833, 0.06891040748433563 } }, + { { 0.000246922834481, 0.11161355018149274, 0.09153959162188663 } }, + { { 0.000256272634864, 0.12846408561275952, 0.10944239212094836 } }, + { { 0.000263875672675, 0.14578898429768233, 0.1239417629556266 } }, + { { 0.000269931115739, 0.16351589660362983, 0.13591741664833346 } }, + { { 0.00027462332684, 0.18159449395396565, 0.14597232165717597 } }, + { { 0.000278122567445, 0.1999904525586456, 0.15453084191052663 } }, + { { 0.000280588125405, 0.21868155531206285, 0.16189838002884194 } }, + { { 0.0002821719877, 0.23765510193417355, 0.1682987082021755 } }, + { { 0.000283022250233, 0.2569061311939487, 0.17389796113043032 } }, + { { 0.000245799595674, 0.1092829755281925, 0.030890470010366697 } }, + { { 0.00025514744075, 0.1252480716651396, 0.05556154047414795 } }, + { { 0.00026290653352, 0.14181409405591308, 0.07565207742708566 } }, + { { 0.000269190044993, 0.158878254201745, 0.09229787387370694 } }, + { { 0.000274127548575, 0.176367516257361, 0.10629906830213084 } }, + { { 0.000277853097012, 0.19423032464841863, 0.11822947861698856 } }, + { { 0.000280501056765, 0.21243113584373424, 0.12850763688584335 } }, + { { 0.000282205583403, 0.23094675049785268, 0.13744332669490386 } }, + { { 0.000283101690124, 0.24976380712614185, 0.14526847762670542 } }, + { { 0.000262447490113, 0.1397796059394766, 0.025444384185962215 } }, + { { 0.000268803416304, 0.15601550753152524, 0.04668994757217974 } }, + { { 0.000273893275129, 0.1727670547176668, 0.06465649877587272 } }, + { { 0.000277794479124, 0.18996309214808085, 0.08002536313162395 } }, + { { 0.000280601166166, 0.207552545893295, 0.09330534541074705 } }, + { { 0.00028241814566, 0.22549977830117915, 0.10487981947084465 } }, + { { 0.000283358521658, 0.24378135493302303, 0.11503990482943398 } }, + { { 0.000273816523696, 0.17092869125735938, 0.021705553310466683 } }, + { { 0.00027783652082, 0.18733470379039832, 0.04039638517653392 } }, + { { 0.000280785294042, 0.2041978490694884, 0.05663177954362433 } }, + { { 0.000282724594967, 0.22146931332121098, 0.07084407918181872 } }, + { { 0.000283734234483, 0.23911473396185762, 0.08336827537707991 } }, + { { 0.000280923390761, 0.20248705041668288, 0.01899015580987787 } }, + { { 0.000282993080974, 0.2189891780845841, 0.035714898791472535 } }, + { { 0.000284109787411, 0.2359076675622355, 0.05053191336752723 } }, + { { 0.000284345520601, 0.23427285444479826, 0.016932714566415905 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(3890); + Points xs = Points::Zero(3, 3890); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail + diff --git a/src/surface_forces/detail/Lebedev_113_4334.hpp b/src/surface_forces/detail/Lebedev_113_4334.hpp new file mode 100644 index 000000000..85077431a --- /dev/null +++ b/src/surface_forces/detail/Lebedev_113_4334.hpp @@ -0,0 +1,203 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + + +namespace detail { +class Lebedev_113_4334 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 1.4490630225e-05; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.000254637732983; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 9> pq0 = { { { { 9.0413396951e-05, 0.01395351910027634 } }, + { { 0.000143842633008, 0.03564475435943178 } }, + { { 0.000180252308982, 0.06075650766272976 } }, + { { 0.000206005229057, 0.08781815498619268 } }, + { { 0.000224500224897, 0.1161037280905153 } }, + { { 0.000237705984773, 0.1451911777915669 } }, + { { 0.000246811895588, 0.1748076813565832 } }, + { { 0.000252541087297, 0.20476035016396732 } }, + { { 0.000255310140993, 0.23490008480656582 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 27> llm = { + { { { 6.0184329611e-05, 0.006585816231197478 } }, { { 0.000100228658326, 0.016978295465352695 } }, + { { 0.000131522293103, 0.02941331824582966 } }, { { 0.000156421374688, 0.043169783569429236 } }, + { { 0.000176511884151, 0.0578634928222984 } }, { { 0.000192873709931, 0.0732598925247085 } }, + { { 0.000206265853426, 0.08920530725497784 } }, { { 0.000217239544595, 0.10559463062493106 } }, + { { 0.000226207618888, 0.12235408447801092 } }, { { 0.000233488569946, 0.13943121879271939 } }, + { { 0.000239335527318, 0.15678876578702314 } }, { { 0.000243955920047, 0.1744007029170554 } }, + { { 0.000247525186606, 0.19224965345551862 } }, { { 0.000250196555816, 0.21032512985560742 } }, + { { 0.000252108140793, 0.22862231991444856 } }, { { 0.000253388100239, 0.24714121928482902 } }, + { { 0.000254158290085, 0.2658859667561476 } }, { { 0.000254536573753, 0.2848642596496941 } }, + { { 0.000254572699307, 0.32356609144151754 } }, { { 0.000254445619747, 0.34331599608608754 } }, + { { 0.000254348159688, 0.3633491580535364 } }, { { 0.000254350645143, 0.3836746960299212 } }, + { { 0.000254490567549, 0.40429436689368065 } }, { { 0.000254761140734, 0.42519777898583205 } }, + { { 0.000255106037545, 0.4463571967002744 } }, { { 0.000255429193382, 0.46772345842817015 } }, + { { 0.000255625571069, 0.48922536088416635 } } } + }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 72> rsw = { + { { { 0.000121287973367, 0.024826589435509375, 0.0908248642928678 } }, + { { 0.000147287288127, 0.037606188116090074, 0.1342878583229538 } }, + { { 0.000168684660101, 0.0516193731380104, 0.15939135798995077 } }, + { { 0.000186269841466, 0.06650966630500786, 0.17567417436057192 } }, + { { 0.000200743095699, 0.08206086361827945, 0.1870803281699501 } }, + { { 0.000212656812539, 0.0981317134254003, 0.19551731006557105 } }, + { { 0.000222439460337, 0.11462577117871149, 0.20201550707789287 } }, + { { 0.000230426452267, 0.13147548980645138, 0.2071787435809739 } }, + { { 0.000236885428842, 0.14863304930313578, 0.21138358163535922 } }, + { { 0.000242035208946, 0.16606474079324737, 0.2148766028862085 } }, + { { 0.000246059711308, 0.1837473764690447, 0.21782569788152228 } }, + { { 0.000249118191226, 0.20166592160345528, 0.22034883112475293 } }, + { { 0.000251352819421, 0.21981189295629958, 0.2225310084267689 } }, + { { 0.000252894309669, 0.23818224552443168, 0.22443471048535044 } }, + { { 0.000253866036849, 0.25677856177883723, 0.22610653295319816 } }, + { { 0.00025438686483, 0.27560640179835677, 0.22758153244769486 } }, + { { 0.000164259553783, 0.04831461121000753, 0.05499504063762987 } }, + { { 0.000181824665985, 0.06222842684158024, 0.09102068134770995 } }, + { { 0.000196656564949, 0.07703482709451791, 0.11621496759054711 } }, + { { 0.000209067790566, 0.09251523213636802, 0.13475379353131628 } }, + { { 0.000219382040951, 0.10852596759005421, 0.1489461063744023 } }, + { { 0.000227887082766, 0.1249689648253517, 0.1601561392514306 } }, + { { 0.000234828319228, 0.14177572300314545, 0.1692358469424084 } }, + { { 0.000240413975558, 0.15889794103947424, 0.17674213745131875 } }, + { { 0.000244822740776, 0.17630176075307522, 0.18305302984992092 } }, + { { 0.000248211045559, 0.19396408868298623, 0.18843321874381722 } }, + { { 0.000250719239777, 0.21187017371002143, 0.19307283341108633 } }, + { { 0.000252476596853, 0.23001196873927823, 0.19711127029607975 } }, + { { 0.000253605238854, 0.24838698574725807, 0.20065234310909458 } }, + { { 0.000254223058803, 0.26699744672128584, 0.20377418448763945 } }, + { { 0.000194481701305, 0.07442936765504839, 0.039470594067149686 } }, + { { 0.000206786236275, 0.08901110116005964, 0.0688486136011633 } }, + { { 0.000217244073465, 0.10428954517870051, 0.09144037638194737 } }, + { { 0.000226012599172, 0.12012073149104222, 0.10930450155735087 } }, + { { 0.000233265500869, 0.1364045907260432, 0.12376554372835964 } }, + { { 0.000239169968153, 0.15307047844898988, 0.13570462132681513 } }, + { { 0.000243880152827, 0.17006826863661167, 0.14572608901094675 } }, + { { 0.000247537050426, 0.18736269844263126, 0.15425580022289115 } }, + { { 0.000250270723564, 0.20492967773521928, 0.16160085306526273 } }, + { { 0.000252203170105, 0.22275382270295324, 0.16798702094555565 } }, + { { 0.000253451126998, 0.2408267667834625, 0.17358285311213922 } }, + { { 0.000254128491496, 0.2591459616458878, 0.17851556927875667 } }, + { { 0.000216150925069, 0.10211385382509494, 0.030850773488741746 } }, + { { 0.000224877851344, 0.11712040979083312, 0.05547481380152686 } }, + { { 0.00023223888034, 0.1326993646352754, 0.07551459268545714 } }, + { { 0.0002383265471, 0.14875177504139472, 0.0921087716174105 } }, + { { 0.000243247667502, 0.16520641479475065, 0.10605995278531749 } }, + { { 0.000247112222375, 0.18201203094918025, 0.11794427840769996 } }, + { { 0.000250029175249, 0.1991321936189417, 0.128182675304197 } }, + { { 0.000252105594276, 0.2165418190268875, 0.13708757148351533 } }, + { { 0.000253447278558, 0.2342247843627668, 0.14489396078472272 } }, + { { 0.000254159971308, 0.25217225663713383, 0.15178037729635585 } }, + { { 0.000231738097586, 0.1308054997681273, 0.025392421503900364 } }, + { { 0.000237855073372, 0.14609070788493705, 0.04657856450417362 } }, + { { 0.000242888445674, 0.16186487468085262, 0.06448240565753134 } }, + { { 0.000246900265576, 0.17805847354917337, 0.07978898607750695 } }, + { { 0.000249965757427, 0.19462062582320694, 0.09301063055413772 } }, + { { 0.000252167616849, 0.21151470568331482, 0.10453429327190089 } }, + { { 0.000253593566265, 0.2287152612822803, 0.11465498130210473 } }, + { { 0.000254335674336, 0.24620583798071274, 0.12359931585974145 } }, + { { 0.00024273532852, 0.16016126954688778, 0.02164176799462574 } }, + { { 0.000246825803974, 0.1756281367713069, 0.040262151621323544 } }, + { { 0.000250006095644, 0.1915259595649753, 0.0564253370646936 } }, + { { 0.000252323836542, 0.20780580420347788, 0.07056847433588244 } }, + { { 0.000253839926025, 0.2244320402039764, 0.08303151320792289 } }, + { { 0.000254625592727, 0.24137974530984346, 0.09407979930524346 } }, + { { 0.000250058336005, 0.18995037336148488, 0.0189158592586531 } }, + { { 0.000252477763826, 0.20552859578566893, 0.03556160535882843 } }, + { { 0.000254095119386, 0.22149662453058616, 0.0503009173850905 } }, + { { 0.000254952408503, 0.23782091848765186, 0.06342356231621332 } }, + { { 0.000254256950701, 0.2200030512470934, 0.016850394351916542 } }, + { { 0.000255211412758, 0.2356367624036941, 0.03193333194586681 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(4334); + Points xs = Points::Zero(3, 4334); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = + xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws( + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + auto xs_ = xs( + Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail + diff --git a/src/surface_forces/detail/Lebedev_119_4802.hpp b/src/surface_forces/detail/Lebedev_119_4802.hpp new file mode 100644 index 000000000..999d206f3 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_119_4802.hpp @@ -0,0 +1,223 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + + +namespace detail { +class Lebedev_119_4802 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 9.6875218794e-05; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.000230789789537; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.00022973108525; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 9> pq0 = { { { { 9.3122746967e-05, 0.0146332680932937 } }, + { { 0.000119991938588, 0.033462389092328126 } }, + { { 0.000159803913888, 0.056754040342175384 } }, + { { 0.000182225376357, 0.08237413424373077 } }, + { { 0.000198857959366, 0.10901192711829599 } }, + { { 0.000211262010253, 0.1364226239795359 } }, + { { 0.00022015948877, 0.1643886421891819 } }, + { { 0.00022616225909, 0.19273033095644077 } }, + { { 0.000229645845344, 0.22130770601583696 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 28> llm = { + { { { 7.386265944e-05, 0.010516385924747362 } }, { { 8.2579776985e-05, 0.01960772775995671 } }, + { { 9.7060447621e-05, 0.029026799358814248 } }, { { 0.000130239384712, 0.04064232608924972 } }, + { { 0.00015419570046, 0.05413125885790828 } }, { { 0.000170445977009, 0.0685804508011497 } }, + { { 0.000182737489094, 0.08360626770987507 } }, { { 0.000192636081744, 0.09905386070706378 } }, + { { 0.000200801023949, 0.11484429655220994 } }, { { 0.000207563598321, 0.1309296441999107 } }, + { { 0.000213130663869, 0.14727734560668404 } }, { { 0.000217656232994, 0.16386387750530554 } }, + { { 0.000221268226299, 0.18067214609683985 } }, { { 0.000224079951567, 0.19769037475978798 } }, + { { 0.000226195981619, 0.21491150246675975 } }, { { 0.000227715636881, 0.23233272360089904 } }, + { { 0.000228735177213, 0.24995505609031266 } }, { { 0.000229349081408, 0.26778290225548135 } }, + { { 0.000229650531238, 0.2858235728148527 } }, { { 0.000229679383232, 0.32258362430889304 } }, + { { 0.000229578544384, 0.34132612734755713 } }, { { 0.000229501793153, 0.36032518829756327 } }, + { { 0.000229505963818, 0.3795887501505544 } }, { { 0.000229623234324, 0.39911888341587753 } }, + { { 0.000229853017874, 0.41890825413607846 } }, { { 0.000230157979028, 0.43893634985964675 } }, + { { 0.0002304690405, 0.45916635731392214 } }, { { 0.000230702799591, 0.479544033952301 } } } + }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 81> rsw = { + { { { 0.000100600699027, 0.024410278130508934, 0.09175097440381855 } }, + { { 0.000122767668964, 0.035382715864839764, 0.13580210539409612 } }, + { { 0.000146786428027, 0.04824937260174046, 0.1595329984958098 } }, + { { 0.00016441789121, 0.06222127451120022, 0.175570973816619 } }, + { { 0.000177766489072, 0.07687723706632836, 0.18699808292305223 } }, + { { 0.000188482566452, 0.09202660230625842, 0.1954681847329587 } }, + { { 0.000197326924645, 0.10756867024480242, 0.20197548955720607 } }, + { { 0.000204676777586, 0.12344093669929387, 0.2071332287067197 } }, + { { 0.000210760012592, 0.1396011381789425, 0.21132699380742836 } }, + { { 0.000215741636227, 0.15601912401447615, 0.21480749208731725 } }, + { { 0.000219755781692, 0.1726728923897927, 0.21774450760799194 } }, + { { 0.000222919261184, 0.18954672467673767, 0.2202572812532938 } }, + { { 0.000225338511021, 0.20663024212585462, 0.2224319000221757 } }, + { { 0.000227113710755, 0.22391779598328637, 0.22433175890594728 } }, + { { 0.000228341409292, 0.2414079623318483, 0.2260042041096887 } }, + { { 0.000229116167313, 0.2591030657931698, 0.22748493626130054 } }, + { { 0.000229531390858, 0.2770086955430346, 0.22880101820767618 } }, + { { 0.000143820472136, 0.04501651621402635, 0.055276282182960136 } }, + { { 0.00016077380255, 0.05816875882975513, 0.09089178652706655 } }, + { { 0.000174148385353, 0.07215649008228939, 0.1160658476889212 } }, + { { 0.000185191846752, 0.08675285245557454, 0.13466287782191522 } }, + { { 0.000194462863807, 0.10183705003414102, 0.14888184667192184 } }, + { { 0.000202249544628, 0.11732491972964101, 0.1600864160943806 } }, + { { 0.000208746238244, 0.13315529432199105, 0.1691458307135706 } }, + { { 0.000214107475482, 0.1492840020002418, 0.1766270877279356 } }, + { { 0.000218464091375, 0.16567897781060953, 0.18291259640483867 } }, + { { 0.000221930916522, 0.1823169741616184, 0.18826959652404424 } }, + { { 0.000224612311834, 0.19918168092900812, 0.19289039405464387 } }, + { { 0.000226606276692, 0.21626262386917275, 0.1969163586572439 } }, + { { 0.000228007295223, 0.23355439892994348, 0.20045299271403422 } }, + { { 0.00022890820252, 0.2510560436291886, 0.20357985431538875 } }, + { { 0.000229401269512, 0.2687704628528671, 0.20635731909135352 } }, + { { 0.000172243448874, 0.06972095562696587, 0.03937828898750104 } }, + { { 0.000183023742146, 0.0834802867612743, 0.0687652149920336 } }, + { { 0.000192385535, 0.09786867271227233, 0.09138006252435742 } }, + { { 0.000200406786194, 0.11277518194583593, 0.10923879941714051 } }, + { { 0.000207181729735, 0.12811231242293247, 0.12367272022505514 } }, + { { 0.00021282508341, 0.14381388857638544, 0.13557553914812265 } }, + { { 0.000217451371944, 0.15983162224390302, 0.14555844267897486 } }, + { { 0.000221166183915, 0.17613046963974818, 0.15405091609008043 } }, + { { 0.000224066525781, 0.1926851521571052, 0.16136311154174407 } }, + { { 0.000226243951663, 0.2094780676834112, 0.16772384900060022 } }, + { { 0.000227787455723, 0.2264980152542648, 0.17330450249100102 } }, + { { 0.000228785431445, 0.24373928716683302, 0.17823474250845384 } }, + { { 0.000229326849962, 0.26120092361521785, 0.18261331449142987 } }, + { { 0.000191262820153, 0.09583855500358501, 0.03082648621752783 } }, + { { 0.000199249967224, 0.10996392769038052, 0.055437285128824246 } }, + { { 0.000206127553345, 0.12463585758948627, 0.07544793350614502 } }, + { { 0.000211931821597, 0.13976275969351334, 0.09199979513457514 } }, + { { 0.000216741658188, 0.15527533859903808, 0.10590256029388166 } }, + { { 0.000220643073052, 0.17112279130974364, 0.11773708480210619 } }, + { { 0.00022371869387, 0.18726799085545387, 0.12792807449444732 } }, + { { 0.000226048007503, 0.2036840049482704, 0.13679195959290727 } }, + { { 0.000227709888456, 0.22035202512766836, 0.14456781959171353 } }, + { { 0.000228784571511, 0.23726007126828003, 0.15143795264924456 } }, + { { 0.000229354726824, 0.25440202881169705, 0.15754212552618363 } }, + { { 0.000205607383985, 0.12285883675780981, 0.025368727813601492 } }, + { { 0.000211423586583, 0.1372666260886485, 0.04651691804056091 } }, + { { 0.000216317562977, 0.15214524225422435, 0.06437073412769535 } }, + { { 0.000220339215811, 0.1674261668872002, 0.07962053127339411 } }, + { { 0.000223547317685, 0.18305841978191756, 0.09278334975812079 } }, + { { 0.00022600241415, 0.199004129933758, 0.10425098426147628 } }, + { { 0.000227767592933, 0.215235481179111, 0.11432372391005954 } }, + { { 0.000228910211228, 0.2317329159397003, 0.12323345302858435 } }, + { { 0.000229502795463, 0.24848396150511579, 0.13115990614661632 } }, + { { 0.000216128158988, 0.15054956776138143, 0.021601407141936407 } }, + { { 0.00022019804774, 0.16515510453413385, 0.04016757966644758 } }, + { { 0.000223495206659, 0.18017406638553224, 0.056267816815705245 } }, + { { 0.000226054009852, 0.19555697106582798, 0.07034473170523621 } }, + { { 0.00022791579819, 0.21126635077307532, 0.0827443735520565 } }, + { { 0.000229129691857, 0.22727433676348735, 0.09373867305497706 } }, + { { 0.000229753375254, 0.24356125198500728, 0.10354168759119256 } }, + { { 0.000223492735647, 0.17870662368990595, 0.018859462807990477 } }, + { { 0.000226128801299, 0.1934430242451004, 0.03543791473633499 } }, + { { 0.000228081816092, 0.20855095383964517, 0.050105227346792444 } }, + { { 0.000229377329518, 0.22399430105042561, 0.06315837295756885 } }, + { { 0.000230052876734, 0.2397459789338036, 0.07483570742956569 } }, + { { 0.000228189385507, 0.20717093634853642, 0.01678089014665939 } }, + { { 0.000229572044484, 0.2219848201259305, 0.031787958381561086 } }, + { { 0.000230322764903, 0.23713798916789933, 0.045271244754101284 } }, + { { 0.000230483191323, 0.23581330991926575, 0.015154107595876577 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(4802); + Points xs = Points::Zero(3, 4802); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail + diff --git a/src/surface_forces/detail/Lebedev_125_5294.hpp b/src/surface_forces/detail/Lebedev_125_5294.hpp new file mode 100644 index 000000000..0a431dda7 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_125_5294.hpp @@ -0,0 +1,223 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + + +namespace detail { +class Lebedev_125_5294 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 9.0805107643e-05; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.000208482436199; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 10> pq0 = { { { { 7.5917081174e-05, 0.0122272800733374 } }, + { { 0.000108338396817, 0.031358021314585115 } }, + { { 0.000140301939529, 0.05327159232476883 } }, + { { 0.000161597017929, 0.07733443578088112 } }, + { { 0.00017711441875, 0.10251681487866783 } }, + { { 0.000188776002299, 0.12847228711290487 } }, + { { 0.000197347467077, 0.15498299192569068 } }, + { { 0.000203378766123, 0.18187924973307468 } }, + { { 0.000207234362652, 0.20903016391066756 } }, + { { 0.000209117783423, 0.2363274194008368 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 30> llm = { + { { { 5.0111056572e-05, 0.010370154728179072 } }, { { 5.9425204097e-05, 0.016921349905386622 } }, + { { 9.5643948261e-05, 0.026237512831250583 } }, { { 0.000118553065713, 0.0379169709701096 } }, + { { 0.000136451011423, 0.0507644298779388 } }, { { 0.000150582882561, 0.06436585073662636 } }, + { { 0.000161929874987, 0.0785087060996483 } }, { { 0.000171245050427, 0.09307034997457828 } }, + { { 0.000178989109816, 0.10797423771743253 } }, { { 0.000185447495563, 0.12316928382347049 } }, + { { 0.000190814863667, 0.13861967848048073 } }, { { 0.000195237740528, 0.15429949627873993 } }, + { { 0.000198834925428, 0.17018980238335438 } }, { { 0.000201707980716, 0.18627708646592972 } }, + { { 0.000203947308271, 0.20255235349932824 } }, { { 0.000205636027929, 0.21901051941436284 } }, + { { 0.000206852582307, 0.23564994889491964 } }, { { 0.000207672487753, 0.25247206217045837 } }, + { { 0.000208169427824, 0.2694809690338038 } }, { { 0.000208415763122, 0.2866830912891763 } }, + { { 0.000208438153113, 0.32170146690868673 } }, { { 0.000208347627713, 0.33953743424370153 } }, + { { 0.000208268619446, 0.35760412753497606 } }, { { 0.000208247568611, 0.3759088478631594 } }, + { { 0.000208313986029, 0.3944545521917069 } }, { { 0.000208474556183, 0.41323716441219555 } }, + { { 0.000208709131338, 0.4322425704684371 } }, { { 0.00020897184133, 0.45144385720653785 } }, + { { 0.000209200330348, 0.4707997141844027 } }, { { 0.000209333614826, 0.49025509912850934 } } } + }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 90> rsw = { + { { { 9.3166844847e-05, 0.022081809907520338, 0.09012636296744164 } }, + { { 0.000111619368868, 0.03303389945888849, 0.1346442931603896 } }, + { { 0.000129862355156, 0.04525210350388219, 0.15950767583470055 } }, + { { 0.000145023683246, 0.05838935640593082, 0.17561712910914978 } }, + { { 0.000157271995815, 0.07217284560667382, 0.18699113302697762 } }, + { { 0.000167323478587, 0.08644508443751665, 0.19542637654942827 } }, + { { 0.000175686011873, 0.10110878625952792, 0.20191730688850307 } }, + { { 0.000182677629044, 0.11609905098916502, 0.20706589456111046 } }, + { { 0.000188511634799, 0.13137056480756018, 0.2112527875091941 } }, + { { 0.000193345786017, 0.14689075034997995, 0.21472744934880078 } }, + { { 0.00019730606719, 0.1626358121853319, 0.21765940322029603 } }, + { { 0.000200498709962, 0.17858847420281362, 0.22016781632878143 } }, + { { 0.000203017090928, 0.19473667446532816, 0.22233885028263625 } }, + { { 0.000204946146012, 0.21107275091530697, 0.2242361770430969 } }, + { { 0.00020636535652, 0.22759286517745056, 0.2259076302806007 } }, + { { 0.000207350792738, 0.24429654404542667, 0.22738958536386672 } }, + { { 0.000207976459326, 0.261186278622972, 0.22870993735006442 } }, + { { 0.000208315053497, 0.2782671390048192, 0.22989017282376814 } }, + { { 0.000126271512159, 0.04231068152075113, 0.05515512256026261 } }, + { { 0.000141438612855, 0.054589376614723295, 0.09099187634526304 } }, + { { 0.000153874040131, 0.06772486308074946, 0.11609130309265848 } }, + { { 0.000164243494233, 0.08147435576486389, 0.13461361004959066 } }, + { { 0.000172979060924, 0.0957066664273712, 0.14879266648213288 } }, + { { 0.000180350519026, 0.11033448477821067, 0.15997544458093477 } }, + { { 0.000186547535008, 0.12529527766860735, 0.1690189965911007 } }, + { { 0.000191718266968, 0.1405436318767864, 0.17648652695422162 } }, + { { 0.000195985170903, 0.15604637053459755, 0.18275983943393823 } }, + { { 0.000199452954812, 0.17177922087650654, 0.18810610095779381 } }, + { { 0.000202213891115, 0.18772469250478985, 0.1927176681190042 } }, + { { 0.000204351802421, 0.20387075949209946, 0.1967362540529479 } }, + { { 0.000205945031302, 0.22020999421672954, 0.20026810539286616 } }, + { { 0.000207068571532, 0.23673893643468683, 0.20339392272465742 } }, + { { 0.000207795531069, 0.25345758522487716, 0.20617557433232722 } }, + { { 0.000208198038782, 0.27036895055700305, 0.20866075859467562 } }, + { { 0.000152131861038, 0.06541943412961183, 0.03941028025430509 } }, + { { 0.000162277272019, 0.07838366927862381, 0.06873763434828653 } }, + { { 0.000171049813942, 0.09196777689757975, 0.09129901797134436 } }, + { { 0.000178591114945, 0.10605258338214514, 0.10912251981954836 } }, + { { 0.000185012531369, 0.12055153978932494, 0.12352966531571986 } }, + { { 0.000190422970393, 0.13540001689357692, 0.13540849558689305 } }, + { { 0.000194925995612, 0.15055025789706813, 0.14536923887551031 } }, + { { 0.000198616154536, 0.16596714863702092, 0.15384162902729173 } }, + { { 0.000201579058564, 0.1816249736445483, 0.16113600597060737 } }, + { { 0.000203893419871, 0.19750524472951309, 0.1674815028240045 } }, + { { 0.000205633406054, 0.2135953106040044, 0.173050272174846 } }, + { { 0.000206870595946, 0.22988742026669648, 0.17797335159579097 } }, + { { 0.000207675390611, 0.24637802734319578, 0.18235142093220438 } }, + { { 0.000208117939173, 0.26306722160214996, 0.18626230107937097 } }, + { { 0.000170034521623, 0.09005428627545445, 0.03079257975297781 } }, + { { 0.000177490677999, 0.10341040526963217, 0.05536128560142009 } }, + { { 0.0001839659377, 0.11728781768718408, 0.07533401069515712 } }, + { { 0.000189498746298, 0.13159904129352548, 0.09185031676141037 } }, + { { 0.000194154880945, 0.14627768423517856, 0.10571891183405266 } }, + { { 0.000198007842725, 0.1612742281004715, 0.11752130645637797 } }, + { { 0.000201129628474, 0.1765519752868946, 0.12768288123464533 } }, + { { 0.000203588845697, 0.19208387677995004, 0.13652050869977778 } }, + { { 0.000205451632535, 0.20785039759940338, 0.14427398585052412 } }, + { { 0.000206783103309, 0.22383813400871805, 0.15112698907187344 } }, + { { 0.000207648532028, 0.24003885901039174, 0.15722142565632113 } }, + { { 0.000208114143953, 0.2564487909395465, 0.1626675425458804 } }, + { { 0.000183438301547, 0.1156225443668364, 0.02532508100578916 } }, + { { 0.000188954059178, 0.12926166315631585, 0.04642844996120459 } }, + { { 0.00019366770236, 0.14334861692059786, 0.06423722763290415 } }, + { { 0.000197617649507, 0.15781772849584919, 0.07944269305847527 } }, + { { 0.000200853600456, 0.1726193921644713, 0.09256320466879381 } }, + { { 0.000203428035171, 0.18771635191499633, 0.10399154701924673 } }, + { { 0.000205394446603, 0.2030808272249597, 0.11402887166058162 } }, + { { 0.000206807764288, 0.21869258580978418, 0.12290839869853407 } }, + { { 0.000207725094966, 0.23453767669697423, 0.13081203498008256 } }, + { { 0.000208206244071, 0.2506075221905784, 0.13788228024837046 } }, + { { 0.000193437448655, 0.14185759926245525, 0.021552567328192232 } }, + { { 0.000197410701048, 0.15569779942126724, 0.04006705163172344 } }, + { { 0.000200712929039, 0.16993013808033486, 0.056114816577325075 } }, + { { 0.000203373694747, 0.18450644512314449, 0.07014039441664384 } }, + { { 0.00020542871259, 0.19938994854477599, 0.08249135877802373 } }, + { { 0.000206918493682, 0.21455286714031777, 0.09344118901431282 } }, + { { 0.000207888368981, 0.22997480076438112, 0.10320613363919821 } }, + { { 0.000208388636612, 0.24564164823387824, 0.11195762822953943 } }, + { { 0.000200659327547, 0.1685636990437287, 0.018804643571100836 } }, + { { 0.000203372842614, 0.1825412253459679, 0.035325186761107394 } }, + { { 0.000205500878138, 0.19686989497063076, 0.04993404617015873 } }, + { { 0.000207065178352, 0.21151428543922507, 0.06293041358870975 } }, + { { 0.000208095333509, 0.22644733164035438, 0.07455506125389763 } }, + { { 0.000208628499899, 0.2416490625189963, 0.08500183761206065 } }, + { { 0.000205554938764, 0.19559080497154124, 0.016720321133884327 } }, + { { 0.000207187185027, 0.2096558300595442, 0.03166412502721149 } }, + { { 0.000208285660043, 0.2240409129536197, 0.04508436639190506 } }, + { { 0.000208870585882, 0.2387203398103678, 0.057188455484861234 } }, + { { 0.000208399586754, 0.22282021351432665, 0.01508849379552935 } }, + { { 0.000209050971289, 0.23692998731338194, 0.028756638475066133 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(5294); + Points xs = Points::Zero(3, 5294); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = + xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws( + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + auto xs_ = xs( + Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail + diff --git a/src/surface_forces/detail/Lebedev_131_5810.hpp b/src/surface_forces/detail/Lebedev_131_5810.hpp new file mode 100644 index 000000000..b01e29cd4 --- /dev/null +++ b/src/surface_forces/detail/Lebedev_131_5810.hpp @@ -0,0 +1,245 @@ + +#pragma once + +#include +#include + +#include + +#include "lebedev_utils.hpp" +#include "meta_utils.hpp" + + +namespace detail { +class Lebedev_131_5810 final +{ +private: + /** Number of points in A1 block */ + static constexpr auto N_a1 = 6; + /** Quadrature weight in A1 block */ + static constexpr auto a1 = 9.735347946e-06; + + /** Number of points in A2 block */ + static constexpr auto N_a2 = 12; + /** Quadrature weight in A2 block */ + static constexpr auto a2 = 0.00019075812418; + + /** Number of points in A3 block */ + static constexpr auto N_a3 = 8; + /** Quadrature weight in A3 block */ + static constexpr auto a3 = 0.000190105954674; + + /** Number of points in each PQ0 block */ + static constexpr auto N_pq0 = 24; + /** Quadrature weight(s) and point(s) in PQ0 block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as \f$(p, q, + * 0) = (\sin(x * \pi), \cos(x * \pi), 0)\f$ + */ + static constexpr std::array, 10> pq0 = { { { { 5.9929978442e-05, 0.011310243989387595 } }, + { { 9.7490593825e-05, 0.029169910339518858 } }, + { { 0.00012416808046, 0.05005972795112629 } }, + { { 0.00014376261543, 0.07274361051753524 } }, + { { 0.000158420005479, 0.09659443028863011 } }, + { { 0.000169443655098, 0.12124153534283726 } }, + { { 0.000177661701402, 0.14644433896058337 } }, + { { 0.000183613243444, 0.17203495880339476 } }, + { { 0.000187649472708, 0.1978883433832886 } }, + { { 0.000189990653534, 0.22390500638984218 } } } }; + + /** Number of points in each LLM block */ + static constexpr auto N_llm = 24; + /** Quadrature weight(s) and point(s) in LLM block. + * + * Each element is a {weight, x} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(l, l, m) = (\frac{\sin(x * \pi)}{\sqrt{2}}, \frac{\sin(x * \pi)}{\sqrt{2}}, \cos(x * \pi))\f$ + */ + static constexpr std::array, 31> llm = { + { { { 3.9264245389e-05, 0.0053227455371747615 } }, { { 6.6679054673e-05, 0.013788807661542444 } }, + { { 8.868891315e-05, 0.024015279208793712 } }, { { 0.000106630600096, 0.03540209759265456 } }, + { { 0.000121450674334, 0.04762588477081858 } }, { { 0.000133805468164, 0.060485467745096444 } }, + { { 0.000144167702363, 0.0738459942735925 } }, { { 0.000152888020083, 0.08761288322788305 } }, + { { 0.000160233062377, 0.10171780783142727 } }, { { 0.000166410265345, 0.11611045233455725 } }, + { { 0.000171584585401, 0.13075336178024718 } }, { { 0.000175890100013, 0.14561857977102433 } }, + { { 0.000179438248526, 0.16068538000014998 } }, { { 0.000182323810676, 0.17593869686001495 } }, + { { 0.000184629325296, 0.19136801834299505 } }, { { 0.000186428407932, 0.20696659225171787 } }, + { { 0.000187788269463, 0.2227308473172956 } }, { { 0.000188771632185, 0.2386599602799077 } }, + { { 0.000189438163818, 0.2547555165248323 } }, { { 0.000189845489953, 0.2710212197275513 } }, + { { 0.000190049792958, 0.28746260727206774 } }, { { 0.000190067150192, 0.3209016976010854 } }, + { { 0.000189983755553, 0.33791614643184276 } }, { { 0.000189901411316, 0.355138335743339 } }, + { { 0.000189858125771, 0.37257499116325343 } }, { { 0.00018988047561, 0.3902296886534251 } }, + { { 0.000189979361043, 0.40810079471542193 } }, { { 0.000190146455484, 0.4261790589060274 } }, + { { 0.000190353324626, 0.4444451868731736 } }, { { 0.000190555615846, 0.4628680201799605 } }, + { { 0.000190703715566, 0.4814041855733677 } } } + }; + + /** Number of points in each RSW block */ + static constexpr auto N_rsw = 48; + /** Quadrature weight(s) and point(s) in RSW block. + * + * Each element is a {weight, x, y} tuple. The actual quadrature point in Cartesian coordinates is computed as + * \f$(r, s, w) = (\sin(x * \pi)\cos(y * \pi), \sin(x * \pi)\sin(y * \pi), \cos(x*\pi))\f$ + */ + static constexpr std::array, 100> rsw = { + { { { 8.1432528208e-05, 0.020234976545606537, 0.09080772994667831 } }, + { { 9.9988598909e-05, 0.03079151397572751, 0.1342531343794393 } }, + { { 0.000115619940307, 0.04242857360854053, 0.15933529753293507 } }, + { { 0.000128763209264, 0.05484738576434526, 0.1755947438715271 } }, + { { 0.000139837864337, 0.06786251985158596, 0.18697616413514456 } }, + { { 0.000149187646842, 0.0813498700115767, 0.19538761650599207 } }, + { { 0.000157085567918, 0.09522243553827199, 0.20186005116426667 } }, + { { 0.00016374839481, 0.10941738337466307, 0.20699786823858482 } }, + { { 0.000169350056663, 0.1238884824578983, 0.21117823705345842 } }, + { { 0.000174032276939, 0.13860139230284224, 0.214648399645538 } }, + { { 0.000177912663728, 0.15353059225669063, 0.2175769843484911 } }, + { { 0.000181090810884, 0.16865731115169186, 0.2200827987460456 } }, + { { 0.00018365291326, 0.18396809522031476, 0.22225182965665546 } }, + { { 0.000185675284178, 0.19945379743461106, 0.22414771524450244 } }, + { { 0.000187227056661, 0.21510885155477852, 0.22581843070469 } }, + { { 0.000188372264559, 0.23093073984658202, 0.22730068797403552 } }, + { { 0.000189171432453, 0.24691958951531628, 0.22862290650008202 } }, + { { 0.000189682748045, 0.2630778468811857, 0.2298072630266836 } }, + { { 0.000189962841706, 0.2794099839743444, 0.23087113142300042 } }, + { { 0.0001123301829, 0.03968551111266872, 0.054960154830764885 } }, + { { 0.000125369882671, 0.05128284865997227, 0.09094111503537507 } }, + { { 0.000136626611768, 0.06366816531165158, 0.11608536299300992 } }, + { { 0.000146273685611, 0.07665503777028491, 0.1345711422960511 } }, + { { 0.000154507646669, 0.09011817216271377, 0.14870901993292637 } }, + { { 0.000161509628081, 0.10396985137813632, 0.15986457678287783 } }, + { { 0.000167436663974, 0.11814691335361566, 0.16889103852901027 } }, + { { 0.000172422500244, 0.1326030483948141, 0.17634661387071177 } }, + { { 0.000176581082299, 0.14730399306525144, 0.18261072684190624 } }, + { { 0.000180010412601, 0.16222440366884705, 0.1879496465723912 } }, + { { 0.000182796043733, 0.17734575514755402, 0.1925553133441097 } }, + { { 0.000185014030072, 0.1926548926283216, 0.19656924560520134 } }, + { { 0.000186733350739, 0.20814301188814746, 0.200097776288134 } }, + { { 0.000188017868864, 0.22380492749560826, 0.20322205551846648 } }, + { { 0.000188927892565, 0.23963853422185255, 0.20600478706314848 } }, + { { 0.000189521383251, 0.2556443936885848, 0.20849486479493454 } }, + { { 0.00018985482774, 0.2718253918238082, 0.2107306224656609 } }, + { { 0.000134910593594, 0.061499633318586246, 0.03941231187997733 } }, + { { 0.000144406006837, 0.07373559528460938, 0.06871800867661576 } }, + { { 0.000152679739093, 0.08658700827843208, 0.09122946757333755 } }, + { { 0.000159820877141, 0.0999289206205313, 0.10900938379190972 } }, + { { 0.000165935436862, 0.11367246507966848, 0.12338534873465379 } }, + { { 0.000171127991095, 0.12775309364349502, 0.13524103237312468 } }, + { { 0.00017549527256, 0.14212325590905792, 0.14518318271487132 } }, + { { 0.00017912478508, 0.1567476861502096, 0.15364010084782956 } }, + { { 0.000182095430088, 0.1716002774244783, 0.16092154698853492 } }, + { { 0.000184478852455, 0.18666195504100935, 0.16725631269818478 } }, + { { 0.000186340948171, 0.20191919877017048, 0.17281646358029945 } }, + { { 0.00018774330088, 0.21736299641150908, 0.17773338859450455 } }, + { { 0.000188744454371, 0.23298808801529905, 0.18210867119381738 } }, + { { 0.000189400982938, 0.24879240455908375, 0.1860216021310837 } }, + { { 0.000189768334504, 0.26477663000763413, 0.18953446129275137 } }, + { { 0.000151732703747, 0.08477853700512905, 0.030766587591270468 } }, + { { 0.000158774055748, 0.09743711008460416, 0.05528986099427818 } }, + { { 0.000164909338227, 0.11059913862072224, 0.0752194055844345 } }, + { { 0.000170191521619, 0.12417693175761622, 0.09169938977537076 } }, + { { 0.000174684775314, 0.13810566957703913, 0.10553695851721087 } }, + { { 0.000178455551201, 0.15233701192014826, 0.11731232933908642 } }, + { { 0.000181568756211, 0.16683479184938224, 0.1274504061095836 } }, + { { 0.000184086437066, 0.1815720638121032, 0.13626778554549454 } }, + { { 0.000186067678539, 0.1965290466818661, 0.14400407297575304 } }, + { { 0.000187569058374, 0.21169166823959817, 0.15084309806678883 } }, + { { 0.000188645323635, 0.22705051940312437, 0.15692753210238236 } }, + { { 0.000189350112333, 0.24260008857908136, 0.16236912011127927 } }, + { { 0.000189736618452, 0.25833818378790174, 0.1672559461685385 } }, + { { 0.000164390881515, 0.10903290330610359, 0.025281161699181137 } }, + { { 0.000169630035091, 0.12198193837478237, 0.04633847734202632 } }, + { { 0.000174155310384, 0.13535752608613894, 0.06410395787998656 } }, + { { 0.000178001528239, 0.14909625543129384, 0.0792695442803553 } }, + { { 0.000181211678708, 0.16315007497515954, 0.09235378920630417 } }, + { { 0.000183832315809, 0.17748258789945276, 0.10374964250583865 } }, + { { 0.000185911311984, 0.1920664159933702, 0.11375826933869605 } }, + { { 0.000187496922022, 0.20688130855142844, 0.1226129764676947 } }, + { { 0.000188637561268, 0.22191277278599147, 0.1304962341852584 } }, + { { 0.000189381957581, 0.23715107032095173, 0.13755188473152266 } }, + { { 0.000189779474826, 0.2525904685715583, 0.14389397546287197 } }, + { { 0.000173896392658, 0.1339609140037468, 0.02150357509199766 } }, + { { 0.000177744235987, 0.14711250158052783, 0.03996878606545967 } }, + { { 0.000181001081507, 0.16063578470307313, 0.05596893567563996 } }, + { { 0.000183692031825, 0.1744841423031421, 0.06994970020417009 } }, + { { 0.000185848947321, 0.18862179054505013, 0.08225935428903053 } }, + { { 0.00018750793425, 0.20302152978156687, 0.09317180005715477 } }, + { { 0.00018870802391, 0.2176630803573179, 0.10290384553548745 } }, + { { 0.000189490575218, 0.23253184782671749, 0.11162809740148144 } }, + { { 0.00018989910612, 0.2476179987266268, 0.1194825760856219 } }, + { { 0.000180906501646, 0.15936010813316978, 0.018752312681588317 } }, + { { 0.00018362971216, 0.17265164187758278, 0.03521995255157768 } }, + { { 0.000185842691624, 0.18627468563179544, 0.049777212697449565 } }, + { { 0.000187565410113, 0.20019485384614805, 0.06272455430890266 } }, + { { 0.000188824075183, 0.21438576163747036, 0.07430373526415363 } }, + { { 0.000189649738387, 0.22882760855507525, 0.08470982149542891 } }, + { { 0.000190077553022, 0.2435061043028182, 0.09410056524055427 } }, + { { 0.000185852504148, 0.18508497012826405, 0.016664860454884734 } }, + { { 0.000187624869008, 0.1984688895850843, 0.03155249959679329 } }, + { { 0.000188940443906, 0.21215434282404463, 0.04491769477095502 } }, + { { 0.000189816853927, 0.2261163117357726, 0.056969480016667275 } }, + { { 0.000190277994066, 0.2403359570411621, 0.06787928278558918 } }, + { { 0.000189012564173, 0.2110238405394552, 0.015030097226026596 } }, + { { 0.00018994346378, 0.2244614936370632, 0.028639186244189006 } }, + { { 0.000190452085683, 0.23817805808874687, 0.04100544985660612 } }, + { { 0.000190553449873, 0.23708499670410427, 0.013716092309148088 } } } + }; + +public: + using Weights = Eigen::VectorXd; + using Points = Eigen::Matrix3Xd; + + static auto quadrature() -> std::tuple + { + Weights ws = Weights::Zero(5810); + Points xs = Points::Zero(3, 5810); + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a1(a1); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a2(a2); + } + + { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2>, Eigen::fix)); + std::tie(ws_, xs_) = detail::a3(a3); + } + + // number of pq0 values + constexpr auto pq0_sz = pq0.size(); + detail::constexpr_for<0, pq0_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + auto xs_ = xs(Eigen::all, Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + i * N_pq0>, Eigen::fix)); + std::tie(ws_, xs_) = detail::pq0(pq0[i][0], pq0[i][1]); + }); + + // number of llm values + constexpr auto llm_sz = llm.size(); + detail::constexpr_for<0, llm_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + i * N_llm>, Eigen::fix)); + std::tie(ws_, xs_) = detail::llm(llm[i][0], llm[i][1]); + }); + + // number of rsw values + constexpr auto rsw_sz = rsw.size(); + detail::constexpr_for<0, rsw_sz, 1>([&xs, &ws](auto i) { + auto ws_ = ws(Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + auto xs_ = xs(Eigen::all, + Eigen::seqN(Eigen::fix<+N_a1 + N_a2 + N_a3 + pq0.size() * N_pq0 + llm.size() * N_llm + i * N_rsw>, + Eigen::fix)); + std::tie(ws_, xs_) = detail::rsw(rsw[i][0], rsw[i][1], rsw[i][2]); + }); + + return { ws, xs }; + } +}; +} // namespace detail + diff --git a/src/surface_forces/detail/lebedev_utils.cpp b/src/surface_forces/detail/lebedev_utils.cpp new file mode 100644 index 000000000..cf231d5a5 --- /dev/null +++ b/src/surface_forces/detail/lebedev_utils.cpp @@ -0,0 +1,172 @@ +#include "lebedev_utils.hpp" + +#include +#include + +#include + +namespace detail { +auto +a1(double w) -> std::tuple, Eigen::Matrix> +{ + auto a = 1.0; + + Eigen::Matrix xs{ { +a, -a, 0.0, 0.0, 0.0, 0.0 }, + { 0.0, 0.0, +a, -a, 0.0, 0.0 }, + { 0.0, 0.0, 0.0, 0.0, +a, -a } }; + + return { Eigen::Matrix::Constant(w), xs }; +} + +auto +a2(double w) -> std::tuple, Eigen::Matrix> +{ + auto a = 1.0 / std::sqrt(2); + + Eigen::Matrix xs{ { +a, +a, -a, -a, +a, +a, -a, -a, 0., 0., 0., 0. }, + { +a, -a, +a, -a, 0., 0., 0., 0., +a, +a, -a, -a }, + { 0., 0., 0., 0., +a, -a, +a, -a, +a, -a, +a, -a } }; + + return { Eigen::Matrix::Constant(w), xs }; +} + +auto +a3(double w) -> std::tuple, Eigen::Matrix> +{ + auto a = 1.0 / std::sqrt(3); + + Eigen::Matrix xs{ { +a, +a, +a, +a, -a, -a, -a, -a }, + { +a, +a, -a, -a, +a, +a, -a, -a }, + { +a, -a, +a, -a, +a, -a, +a, -a } }; + + return { Eigen::Matrix::Constant(w), xs }; +} + +auto +pq0(double w, double x) -> std::tuple, Eigen::Matrix> +{ + auto a = std::sin(x * M_PI); + auto b = std::cos(x * M_PI); + + Eigen::Matrix xs{ + { +a, -a, -a, +a, +b, -b, -b, +b, +a, -a, -a, +a, +b, -b, -b, +b, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, + { +b, +b, -b, -b, +a, +a, -a, -a, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, +a, -a, -a, +a, +b, -b, -b, +b }, + { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, +b, +b, -b, -b, +a, +a, -a, -a, +b, +b, -b, -b, +a, +a, -a, -a } + }; + + return { Eigen::Matrix::Constant(w), xs }; +} + +auto +llm(double w, double x) -> std::tuple, Eigen::Matrix> +{ + auto a = std::sin(x * M_PI) / std::sqrt(2); + auto b = std::cos(x * M_PI); + + Eigen::Matrix xs{ + { +a, -a, +a, -a, +a, -a, +a, -a, +a, -a, +a, -a, +a, -a, +a, -a, +b, +b, +b, +b, -b, -b, -b, -b }, + { +a, +a, -a, -a, +a, +a, -a, -a, +b, +b, +b, +b, -b, -b, -b, -b, +a, -a, +a, -a, +a, -a, +a, -a }, + { +b, +b, +b, +b, -b, -b, -b, -b, +a, +a, -a, -a, +a, +a, -a, -a, +a, +a, -a, -a, +a, +a, -a, -a } + }; + + return { Eigen::Matrix::Constant(w), xs }; +} + +auto +rsw(double w, double x, double y) -> std::tuple, Eigen::Matrix> +{ + auto sinx = std::sin(x * M_PI); + auto siny = std::sin(y * M_PI); + auto cosx = std::cos(x * M_PI); + auto cosy = std::cos(y * M_PI); + + auto a = sinx * cosy; + auto b = sinx * siny; + auto c = cosx; + + Eigen::Matrix xs{ + { +a, +c, +b, +b, +c, +a, -a, +c, +b, +b, +c, -a, +a, +c, -b, -b, +c, +a, +a, -c, +b, +b, -c, +a, + -a, +c, -b, -b, +c, -a, -a, -c, +b, +b, -c, -a, +a, -c, -b, -b, -c, +a, -a, -c, -b, -b, -c, -a }, + { +b, +a, +c, +a, +b, +c, +b, -a, +c, -a, +b, +c, -b, +a, +c, +a, -b, +c, +b, +a, -c, +a, +b, -c, + -b, -a, +c, -a, -b, +c, +b, -a, -c, -a, +b, -c, -b, +a, -c, +a, -b, -c, -b, -a, -c, -a, -b, -c }, + { +c, +b, +a, +c, +a, +b, +c, +b, -a, +c, -a, +b, +c, -b, +a, +c, +a, -b, -c, +b, +a, -c, +a, +b, + +c, -b, -a, +c, -a, -b, -c, +b, -a, -c, -a, +b, -c, -b, +a, -c, +a, -b, -c, -b, -a, -c, -a, -b } + }; + + return { Eigen::Matrix::Constant(w), xs }; +} + +auto +n_points_to_degree(size_t N) -> size_t +{ + switch (N) { + case 6: + return 3; + case 14: + return 5; + case 26: + return 7; + case 38: + return 9; + case 50: + return 11; + case 74: + return 13; + case 86: + return 15; + case 110: + return 17; + case 146: + return 19; + case 170: + return 21; + case 194: + return 23; + case 230: + return 25; + case 266: + return 27; + case 302: + return 39; + case 350: + return 31; + case 434: + return 35; + case 590: + return 41; + case 770: + return 47; + case 974: + return 53; + case 1202: + return 59; + case 1454: + return 65; + case 1730: + return 71; + case 2030: + return 77; + case 2354: + return 83; + case 2702: + return 89; + case 3074: + return 95; + case 3470: + return 101; + case 3890: + return 107; + case 4334: + return 113; + case 4802: + return 119; + case 5294: + return 125; + case 5810: + return 131; + default: + // FIXME error handling + std::abort(); + } +} +} // namespace detail diff --git a/src/surface_forces/detail/lebedev_utils.hpp b/src/surface_forces/detail/lebedev_utils.hpp new file mode 100644 index 000000000..d1fcc3cb2 --- /dev/null +++ b/src/surface_forces/detail/lebedev_utils.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include + + +namespace detail { +auto +a1(double w) -> std::tuple, Eigen::Matrix>; + +auto +a2(double w) -> std::tuple, Eigen::Matrix>; + +auto +a3(double w) -> std::tuple, Eigen::Matrix>; + +auto +pq0(double w, double x) -> std::tuple, Eigen::Matrix>; + +auto +llm(double w, double x) -> std::tuple, Eigen::Matrix>; + +auto +rsw(double w, double x, double y) -> std::tuple, Eigen::Matrix>; + +auto +n_points_to_degree(size_t N) -> size_t; +} // namespace detail + diff --git a/src/surface_forces/detail/meta_utils.hpp b/src/surface_forces/detail/meta_utils.hpp new file mode 100644 index 000000000..7292de1b7 --- /dev/null +++ b/src/surface_forces/detail/meta_utils.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +namespace detail { +/** Compile-time loop-application of a function to a variadic argument pack. + * + * @tparam F function to apply. + * @tparam Args variadic argument pack. + * + * @param[in] F function to apply. + * @param[in] Args variadic argument pack. + */ +template +constexpr auto +constexpr_for(F&& f, Args&&... args) -> void +{ + (f(std::forward(args)), ...); +} + +/** Compile-time loop-application of a function. + * + * @tparam Start loop start index. + * @tparam End loop end index. + * @tparam Increment loop increment. + * @tparam F function to apply. + * + * @param[in] F function to apply. + */ +template +constexpr auto +constexpr_for(F&& f) -> void +{ + if constexpr (Start < End) { + f(std::integral_constant()); + constexpr_for(f); + } +} +} // namespace detail \ No newline at end of file diff --git a/src/surface_forces/lebedev.cpp b/src/surface_forces/lebedev.cpp new file mode 100644 index 000000000..61acd2239 --- /dev/null +++ b/src/surface_forces/lebedev.cpp @@ -0,0 +1,146 @@ +/** + * @file lebedev.cpp + * @brief Implementation of the LebedevIntegrator class for surface integration calculations. + */ + +#include "lebedev.h" +#include +#include +#include +#include +#include +#include +#include "surface_forces/LebedevData.h" + + + /** + * @brief Constructor for the LebedevIntegrator class. + * @param filename The name of the file containing the Lebedev grid data. + * @param radius The radius of the sphere. + * @param center Center of the sphere. + */ + LebedevIntegrator::LebedevIntegrator(int nPoints, double radius, const Eigen::Vector3d& center) { + getLebedevData(nPoints); + calculateCartesianPoints(radius, center); + } + + /** + * @brief Get the Cartesian coordinates of the Lebedev grid points. + * @return A matrix containing the Cartesian coordinates of the Lebedev grid points. + */ + Eigen::MatrixXd LebedevIntegrator::getPoints() const { return points; } + + /** + * @brief Get the weights associated with each Lebedev grid point. + * @return A vector containing the weights associated with each Lebedev grid point. + */ + Eigen::VectorXd LebedevIntegrator::getWeights() const { return weights; } + + /** + * @brief Get the normal vectors at each Lebedev grid point. + * @return A matrix containing the normal vectors at each Lebedev grid point. + */ + Eigen::MatrixXd LebedevIntegrator::getNormals() const { return normals; } + + /** + * @brief Read the Lebedev grid data from a file. + * @param filename The name of the file containing the Lebedev grid data. + * @throw std::runtime_error if the file cannot be opened. + */ + void LebedevIntegrator::readLebedevFile(const std::string& filename) { + std::ifstream file(filename); + if (!file.is_open()) { + throw std::runtime_error("Could not open the lebedev data file."); + } + std::string line; + std::vector thetaVec, phiVec, weightVec; + + while (getline(file, line)) { + double theta, phi, weight; + std::istringstream iss(line); + if (!(iss >> theta >> phi >> weight)) { break; } // error + + thetaVec.push_back(theta * M_PI / 180.0); + phiVec.push_back(phi * M_PI / 180.0); + weightVec.push_back(weight); + } + + n = thetaVec.size(); + points = Eigen::MatrixXd(n, 3); + weights = Eigen::VectorXd(n); + normals = Eigen::MatrixXd(n, 3); + + for (int i = 0; i < n; ++i) { + weights[i] = weightVec[i]; + normals.row(i) << cos(thetaVec[i]) * sin(phiVec[i]), sin(thetaVec[i]) * sin(phiVec[i]), cos(phiVec[i]); + } + } + + /** + * @brief Get the Lebedev data for a given number of grid points. + * @param n The number of Lebedev grid points. + */ + void LebedevIntegrator::getLebedevData(int nPoints) { + std::tuple dat = lebedev(nPoints); + weights = std::get<0>(dat); + n = weights.size(); + normals = std::get<1>(dat).transpose(); + points = Eigen::MatrixXd(n, 3); + } + + + /** + * @brief Calculate the Cartesian coordinates of the Lebedev grid points. + * @param radius The radius of the sphere. + * @param center Center of the sphere. + */ + void LebedevIntegrator::calculateCartesianPoints(double radius, const Eigen::Vector3d ¢er) { + for (int i = 0; i < n; ++i) { + points.row(i) = radius * normals.row(i) + center.transpose(); + } + weights *= 4.0 * M_PI * radius * radius; + } + + +/* +This can be used for testing the LebedevIntegrator class. +Eigen::Vector3d pointEField(const Eigen::Vector3d& r) { + double rNorm = r.norm(); + return r / (rNorm * rNorm * rNorm); +} +int main() { + try { + double radius = 4.0; + Eigen::Vector3d shift(5.0, 2.0, 1.0); + LebedevIntegrator integrator("lebedev.txt", radius, shift); + + double sum = integrator.getWeights().sum(); + std::cout << "Sum of weights: " << sum << " Refererence 4 * pi * r**2 " << 4 * M_PI * radius * radius << std::endl; + + Eigen::MatrixXd fields = integrator.getPoints(); + for (int i = 0; i < integrator.n; i++) + { + fields.row(i) = fields.row(i) / (fields.row(i).norm() * fields.row(i).norm() * fields.row(i).norm()); + } + + double integral = 0.0; + for (int i = 0; i < integrator.n; i++) + { + integral += integrator.getWeights()[i] * fields.row(i).dot(integrator.getNormals().row(i)); + } + + std::cout << "Surface Integral: " << integral << " Reference 4 * pi " << 4 * M_PI << std::endl; + + Eigen::VectorXd pots = integrator.getPoints().rowwise().norm().cwiseInverse(); + pots = pots.cwiseProduct(pots); + double potIntegral = integrator.getWeights().dot(pots); + std::cout << "Potential Integral: " << potIntegral << " Reference 1 " << 1 << std::endl; + + + } catch (const std::exception& e) { + std::cerr << "Exception: " << e.what() << std::endl; + } + + return 0; +} +*/ \ No newline at end of file diff --git a/src/surface_forces/lebedev.h b/src/surface_forces/lebedev.h new file mode 100644 index 000000000..5a93bca9c --- /dev/null +++ b/src/surface_forces/lebedev.h @@ -0,0 +1,25 @@ +#ifndef LEBEDEV_H +#define LEBEDEV_H + +#include +#include + +class LebedevIntegrator { +public: + Eigen::MatrixXd points; /**< Matrix storing the Cartesian coordinates of the Lebedev grid points. */ + Eigen::VectorXd weights; /**< Vector storing the weights associated with each Lebedev grid point. */ + Eigen::MatrixXd normals; /**< Matrix storing the normal vectors (to the integration sphere) at each Lebedev grid point. */ + int n; /**< Number of Lebedev grid points. */ + + + LebedevIntegrator(int nPoints, double radius, const Eigen::Vector3d& center); + Eigen::MatrixXd getPoints() const; + Eigen::VectorXd getWeights() const; + Eigen::MatrixXd getNormals() const; +private: + void getLebedevData(int nPoints); + void readLebedevFile(const std::string& filename); + void calculateCartesianPoints(double radius, const Eigen::Vector3d ¢er); +}; + +#endif // LEBEDEV_H \ No newline at end of file diff --git a/src/surface_forces/xcStress.cpp b/src/surface_forces/xcStress.cpp new file mode 100644 index 000000000..c5ce74041 --- /dev/null +++ b/src/surface_forces/xcStress.cpp @@ -0,0 +1,231 @@ +#include "surface_forces/xcStress.h" + +#include "qmfunctions/Density.h" +#include "qmfunctions/Orbital.h" +#include "mrdft/MRDFT.h" +#include "qmfunctions/Density.h" +#include "qmfunctions/density_utils.h" +#include "qmoperators/one_electron/NablaOperator.h" + +using namespace Eigen; +using namespace mrchem; +using namespace std; + +namespace surface_force{ + +/** + * @brief Compute the exchange-correlation stress tensor for LDA functional + * + * @param mrdft_p MRDFT object + * @param rhoGrid MatrixXd with density values, shape (nGrid, 1) + * @return std::vector vector of 3x3 matrices with stress tensor at each grid point + */ +std::vector xcLDAStress(unique_ptr &mrdft_p, Eigen::MatrixXd &rhoGrid){ + int nGrid = rhoGrid.rows(); + std::vector out(nGrid); + Eigen::MatrixXd xcOUT = mrdft_p->functional().evaluate_transposed(rhoGrid); + for (int i = 0; i < nGrid; i++) { + out[i] = Matrix3d::Zero(); + for (int j = 0; j < 3; j++) { + out[i](j, j) = xcOUT(i, 0) - xcOUT(i, 1) * rhoGrid(i); + } + } + return out; +} + +/** + * @brief Compute the exchange-correlation stress tensor for LDA functional for open shell systems + * + * @param mrdft_p MRDFT object + * @param rhoGridAlpha MatrixXd with alpha density values, shape (nGrid, 1) + * @param rhoGridBeta MatrixXd with beta density values, shape (nGrid, 1) + * @return std::vector vector of 3x3 matrices with stress tensor at each grid point + */ +std::vector xcLDASpinStress(unique_ptr &mrdft_p, MatrixXd &rhoGridAlpha, MatrixXd &rhoGridBeta){ + int nGrid = rhoGridAlpha.rows(); + Eigen::MatrixXd inp(rhoGridAlpha.rows(), 2); + std::vector out = std::vector(nGrid); + inp.col(0) = rhoGridAlpha.col(0); + inp.col(1) = rhoGridBeta.col(0); + Eigen::MatrixXd xc = mrdft_p->functional().evaluate_transposed(inp); + for (int i = 0; i < rhoGridAlpha.rows(); i++) { + out[i] = Matrix3d::Zero(); + for (int j = 0; j < 3; j++) { + out[i](j, j) = xc(i, 0) - xc(i, 1) * rhoGridAlpha(i) - xc(i, 2) * rhoGridBeta(i); + } + } + return out; +} + +/** + * @brief Compute the exchange-correlation stress tensor for GGA functional + * + * @param mrdft_p MRDFT object + * @param rhoGrid MatrixXd with density values, shape (nGrid, 1) + * @param nablaRhoGrid MatrixXd with gradient of density values, shape (nGrid, 3) + * @return std::vector vector of 3x3 matrices with stress tensor at each grid point + */ +std::vector xcGGAStress(unique_ptr &mrdft_p, mrcpp::FunctionTreeVector<3> &xc_pots, MatrixXd &rhoGrid, MatrixXd &nablaRhoGrid, Eigen::MatrixXd &gridPos){ + int nGrid = rhoGrid.rows(); + Eigen::MatrixXd inp(rhoGrid.rows(), 4); + inp.col(0) = rhoGrid.col(0); + inp.col(1) = nablaRhoGrid.col(0); + inp.col(2) = nablaRhoGrid.col(1); + inp.col(3) = nablaRhoGrid.col(2); + Eigen::MatrixXd xcOUT = mrdft_p->functional().evaluate_transposed(inp); + std::vector out(nGrid); + std::array pos; + for (int i = 0; i < rhoGrid.rows(); i++) { + out[i] = Matrix3d::Zero(); + pos[0] = gridPos(i, 0); + pos[1] = gridPos(i, 1); + pos[2] = gridPos(i, 2); + for (int j = 0; j < 3; j++) { + out[i](j, j) = xcOUT(i, 0) - rhoGrid(i) * std::get<1>(xc_pots[0])->evalf(pos); + } + for (int j1 = 0; j1 < 3; j1++) { + for (int j2 = 0; j2 < 3; j2++) { + out[i](j1, j2) = out[i](j1, j2) - xcOUT(i, 2 + j1) * nablaRhoGrid(i, j2); + } + } + } + return out; +} + +/** + * @brief Compute the exchange-correlation stress tensor for GGA functional for open shell systems + * + * @param mrdft_p MRDFT object + * @param rhoGridAlpha MatrixXd with alpha density values, shape (nGrid, 1) + * @param rhoGridBeta MatrixXd with beta density values, shape (nGrid, 1) + * @param nablaRhoGridAlpha MatrixXd with gradient of alpha density values, shape (nGrid, 3) + * @param nablaRhoGridBeta MatrixXd with gradient of beta density values, shape (nGrid, 3) + * @return std::vector vector of 3x3 matrices with stress tensor at each grid point + */ +std::vector xcGGASpinStress(unique_ptr &mrdft_p, mrcpp::FunctionTreeVector<3> &xc_pots, MatrixXd &rhoGridAlpha, MatrixXd &rhoGridBeta, MatrixXd &nablaRhoGridAlpha, MatrixXd &nablaRhoGridBeta, Eigen::MatrixXd &gridPos){ + int nGrid = rhoGridAlpha.rows(); + Eigen::MatrixXd inp(rhoGridAlpha.rows(), 8); + std::vector out = std::vector(nGrid); + inp.col(0) = rhoGridAlpha.col(0); + inp.col(1) = rhoGridBeta.col(0); + inp.col(2) = nablaRhoGridAlpha.col(0); + inp.col(3) = nablaRhoGridAlpha.col(1); + inp.col(4) = nablaRhoGridAlpha.col(2); + inp.col(5) = nablaRhoGridBeta.col(0); + inp.col(6) = nablaRhoGridBeta.col(1); + inp.col(7) = nablaRhoGridBeta.col(2); + Eigen::MatrixXd xc = mrdft_p->functional().evaluate_transposed(inp); + std::array pos; + for (int i = 0; i < rhoGridAlpha.rows(); i++) { + out[i] = Matrix3d::Zero(); + pos[0] = gridPos(i, 0); + pos[1] = gridPos(i, 1); + pos[2] = gridPos(i, 2); + for (int j = 0; j < 3; j++) { + out[i](j, j) = xc(i, 0) - std::get<1>(xc_pots[0])->evalf(pos) * rhoGridAlpha(i) - std::get<1>(xc_pots[1])->evalf(pos) * rhoGridBeta(i); + } + for (int j1 = 0; j1 < 3; j1++) { + for (int j2 = 0; j2 < 3; j2++) { + out[i](j1, j2) = out[i](j1, j2) + - xc(i, 3 + j1) * nablaRhoGridAlpha(i, j2) - xc(i, 6 + j1) * nablaRhoGridBeta(i, j2); + } + } + } + return out; +} + +/** + * @brief Compute the exchange-correlation stress tensor on a grid + * + * @param mrdft_p MRDFT object + * @param phi OrbitalVector + * @param nabla NablaOperator (must be set up prior to calling this function) + * @param gridPos MatrixXd with grid positions, shape (nGrid, 3) + * @param isOpenShell bool, true if open shell calculation + * @param prec precision to use in density representation + */ +std::vector getXCStress(unique_ptr &mrdft_p, mrcpp::FunctionTreeVector<3> &xc_pots, std::shared_ptr phi, + std::shared_ptr nabla, MatrixXd &gridPos, bool isOpenShell, double prec){ + + bool isGGA = mrdft_p->functional().isGGA(); + bool isHybrid = mrdft_p->functional().isHybrid(); + if (isHybrid) { + MSG_ABORT("Exact exchange is not implemented for forces computed with surface integrals"); + } + + std::array pos; + int nGrid = gridPos.rows(); + + vector xcStress; + + if (isOpenShell) { + MatrixXd rhoGridAlpha(nGrid, 1); + MatrixXd rhoGridBeta(nGrid, 1); + mrchem::Density rhoA(false); + mrchem::Density rhoB(false); + mrchem::density::compute(prec, rhoA, *phi, DensityType::Alpha); + mrchem::density::compute(prec, rhoB, *phi, DensityType::Beta); + + for (int i = 0; i < nGrid; i++) { // compute density on grid + pos[0] = gridPos(i, 0); + pos[1] = gridPos(i, 1); + pos[2] = gridPos(i, 2); + rhoGridAlpha(i) = rhoA.real().evalf(pos); + rhoGridBeta(i) = rhoB.real().evalf(pos); + } + + if (isGGA) { + mrchem::NablaOperator nablaOP = *nabla; + std::vector nablaRhoAlpha = nablaOP(rhoA); + std::vector nablaRhoBeta = nablaOP(rhoB); + MatrixXd nablaRhoGridAlpha(nGrid, 3); + MatrixXd nablaRhoGridBeta(nGrid, 3); + for (int i = 0; i < nGrid; i++) { + pos[0] = gridPos(i, 0); + pos[1] = gridPos(i, 1); + pos[2] = gridPos(i, 2); + nablaRhoGridAlpha(i, 0) = nablaRhoAlpha[0].real().evalf(pos); + nablaRhoGridAlpha(i, 1) = nablaRhoAlpha[1].real().evalf(pos); + nablaRhoGridAlpha(i, 2) = nablaRhoAlpha[2].real().evalf(pos); + nablaRhoGridBeta(i, 0) = nablaRhoBeta[0].real().evalf(pos); + nablaRhoGridBeta(i, 1) = nablaRhoBeta[1].real().evalf(pos); + nablaRhoGridBeta(i, 2) = nablaRhoBeta[2].real().evalf(pos); + } + + xcStress = xcGGASpinStress(mrdft_p, xc_pots, rhoGridAlpha, rhoGridBeta, nablaRhoGridAlpha, nablaRhoGridBeta, gridPos); + } else { + xcStress = xcLDASpinStress(mrdft_p, rhoGridAlpha, rhoGridBeta); + } + + } else { // closed shell + MatrixXd rhoGrid(nGrid, 1); + mrchem::Density rho(false); + mrchem::density::compute(prec, rho, *phi, DensityType::Total); + + for (int i = 0; i < nGrid; i++) { // compute density on grid + pos[0] = gridPos(i, 0); + pos[1] = gridPos(i, 1); + pos[2] = gridPos(i, 2); + rhoGrid(i) = rho.real().evalf(pos); + } + + if (isGGA) { + mrchem::NablaOperator nablaOP = *nabla; + std::vector nablaRho = nablaOP(rho); + MatrixXd nablaRhoGrid(nGrid, 3); + for (int i = 0; i < nGrid; i++) { + pos[0] = gridPos(i, 0); + pos[1] = gridPos(i, 1); + pos[2] = gridPos(i, 2); + nablaRhoGrid(i, 0) = nablaRho[0].real().evalf(pos); + nablaRhoGrid(i, 1) = nablaRho[1].real().evalf(pos); + nablaRhoGrid(i, 2) = nablaRho[2].real().evalf(pos); + } + xcStress = xcGGAStress(mrdft_p, xc_pots, rhoGrid, nablaRhoGrid, gridPos); + } else { + xcStress = xcLDAStress(mrdft_p, rhoGrid); + } + } + return xcStress; +} +} // namespace surface_force \ No newline at end of file diff --git a/src/surface_forces/xcStress.h b/src/surface_forces/xcStress.h new file mode 100644 index 000000000..5eb19d892 --- /dev/null +++ b/src/surface_forces/xcStress.h @@ -0,0 +1,19 @@ +#pragma once + +#include "mrchem.h" +#include +#include "qmfunctions/Density.h" +#include "qmfunctions/Orbital.h" +#include "mrdft/MRDFT.h" +#include +#include "qmoperators/one_electron/NablaOperator.h" + +namespace surface_force { + +std::vector xcLDAStress(std::unique_ptr &mrdft_p, Eigen::MatrixXd &rhoGrid); +std::vector xcLDASpinStress(std::unique_ptr &mrdft_p, Eigen::MatrixXd &rhoGridAlpha, Eigen::MatrixXd &rhoGridBeta); +std::vector xcGGAStress(std::unique_ptr &mrdft_p, Eigen::MatrixXd &rhoGrid, Eigen::MatrixXd &nablaRhoGrid); +std::vector xcGGASpinStress(std::unique_ptr &mrdft_p, Eigen::MatrixXd &rhoGridAlpha, Eigen::MatrixXd &rhoGridBeta, Eigen::MatrixXd &nablaRhoGridAlpha, Eigen::MatrixXd &nablaRhoGridBeta); +std::vector getXCStress(std::unique_ptr &mrdft_p, mrcpp::FunctionTreeVector<3> &xc_pots, std::shared_ptr phi, std::shared_ptr nabla, Eigen::MatrixXd &gridPos, bool isOpenShell, double prec); + +} // namespace surface_force diff --git a/src/tensor/RankOneOperator.cpp b/src/tensor/RankOneOperator.cpp index b9767ab22..f55bf61a1 100644 --- a/src/tensor/RankOneOperator.cpp +++ b/src/tensor/RankOneOperator.cpp @@ -75,3 +75,4 @@ template ComplexVector RankOneOperator::trace(const Nuclei &nucs) { } // namespace mrchem template class mrchem::RankOneOperator<3>; +template class mrchem::RankOneOperator<6>; diff --git a/src/vc_sqnm/mrchem_optimizer.hpp b/src/vc_sqnm/mrchem_optimizer.hpp index 6a8c36f0f..adbf7c9d1 100644 --- a/src/vc_sqnm/mrchem_optimizer.hpp +++ b/src/vc_sqnm/mrchem_optimizer.hpp @@ -160,6 +160,7 @@ json optimize_positions(json scf_inp, json mol_inp, const json &geopt_inp, std:: if (mrcpp::mpi::grand_master()) { xyzFile.open(jsonOutFileName + ".xyz", std::ios::out); + xyzFile.precision(12); } mrcpp::print::header(printLevel, "Starting geometry optimization using the SQNM method", 1, '='); diff --git a/src/vc_sqnm/sqnm.hpp b/src/vc_sqnm/sqnm.hpp index b3a782ee8..6c661cae3 100644 --- a/src/vc_sqnm/sqnm.hpp +++ b/src/vc_sqnm/sqnm.hpp @@ -149,7 +149,7 @@ namespace sqnm_space this->estimate_step_size = false; } else { - double gainratio = calc_gainratio(f_of_x); + double gainratio = calc_gainratio(f_of_x, df_dx); adjust_stepsize(gainratio); } @@ -257,14 +257,17 @@ namespace sqnm_space } private: - double calc_gainratio(double &f){ - double gr = (f - prev_f) / ( .5 * this->dir_of_descent.dot(prev_df_dx)); + double calc_gainratio(double &f, Eigen::VectorXd &df_dx){ + // double gr = (f - prev_f) / ( .5 * this->dir_of_descent.dot(prev_df_dx)); + double gr = prev_df_dx.dot(df_dx) / (prev_df_dx.norm() * df_dx.norm()); return gr; } void adjust_stepsize(double &gainratio){ - if ( gainratio < 0.5 ) alpha = std::max(alpha * 0.65, alpha0); - else if(gainratio > 1.05) alpha = alpha * 1.05; + // if ( gainratio < 0.5 ) alpha = std::max(alpha * 0.65, alpha0); + // else if(gainratio > 1.05) alpha = alpha * 1.05; + if ( gainratio > 0.5) alpha *= 1.05; + else alpha = std::max(alpha * 0.55, alpha0); } Eigen::MatrixXd calc_ovrlp(){ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ed4f2f4b4..b2412e00a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -28,6 +28,7 @@ add_subdirectory(h2_pol_cube) add_subdirectory(li_scf_pbe0) add_subdirectory(li_pol_lda) add_subdirectory(hf_grad_lda) +add_subdirectory(hf_grad_blyp_surface_force) add_subdirectory(cube_parser) add_subdirectory(h2_scf_cube) add_subdirectory(li_solv) diff --git a/tests/hf_grad_blyp_surface_force/CMakeLists.txt b/tests/hf_grad_blyp_surface_force/CMakeLists.txt new file mode 100644 index 000000000..49a927e51 --- /dev/null +++ b/tests/hf_grad_blyp_surface_force/CMakeLists.txt @@ -0,0 +1,10 @@ +if(ENABLE_MPI) + set(_hf_grad_lda_launcher_surface "${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 1") +endif() + +add_integration_test( + NAME "HF_molecular_gradient_LDA_surface_integral" + LABELS "mrchem;gradient;surface_integral" + COST 200 + LAUNCH_AGENT ${_hf_grad_lda_launcher_surface} + ) diff --git a/tests/hf_grad_blyp_surface_force/hf.inp b/tests/hf_grad_blyp_surface_force/hf.inp new file mode 100644 index 000000000..b8461f59e --- /dev/null +++ b/tests/hf_grad_blyp_surface_force/hf.inp @@ -0,0 +1,33 @@ +world_prec = 1.0e-3 # Overall relative precision +world_size = 6 # Size of simulation box 2^n +world_unit = angstrom + +MPI { + numerically_exact = true # Guarantee identical results in MPI +} + +Molecule { +$coords +F -1.194868474027 -0.244625419775 0.340936636348 +H -1.672505086978 -0.395082674713 1.107306807211 +$end +translate = false +} + +Forces { + method = 'surface_integrals' + radius_factor = 0.6 +} + +WaveFunction { + method = blyp # Wave function method (HF or DFT) +} + +Properties { + geometric_derivative = true # Compute geometric derivative +} + +SCF { + run = false + guess_type = CORE_DZ # Type of initial guess: none, mw, gto +} diff --git a/tests/hf_grad_blyp_surface_force/reference/hf.json b/tests/hf_grad_blyp_surface_force/reference/hf.json new file mode 100644 index 000000000..41fbc0d86 --- /dev/null +++ b/tests/hf_grad_blyp_surface_force/reference/hf.json @@ -0,0 +1,325 @@ +{ + "input": { + "constants": { + "N_a": 6.02214076e+23, + "angstrom2bohrs": 1.8897261246257702, + "boltzmann_constant": 1.380649e-23, + "dipmom_au2debye": 2.5417464739297717, + "e0": 8.8541878128e-12, + "electron_g_factor": -2.00231930436256, + "elementary_charge": 1.602176634e-19, + "fine_structure_constant": 0.0072973525693, + "hartree2ev": 27.211386245988, + "hartree2kcalmol": 627.5094740630558, + "hartree2kjmol": 2625.4996394798254, + "hartree2simagnetizability": 78.9451185, + "hartree2wavenumbers": 219474.6313632, + "light_speed": 137.035999084, + "meter2bohr": 18897261246.2577 + }, + "geom_opt": { + "init_step_size": -0.5, + "max_force_component": 0.005, + "max_history_length": 10, + "max_iter": 100, + "minimal_step_size": 0.01, + "run": false, + "subspace_tolerance": 0.001, + "use_previous_guess": false + }, + "molecule": { + "charge": 0, + "coords": [ + { + "atom": "f", + "r_rms": 5.2927138943e-05, + "xyz": [ + -2.25797417086055, + -0.462275046496363, + 0.6442768685488515 + ] + }, + { + "atom": "h", + "r_rms": 2.6569547399e-05, + "xyz": [ + -3.1605765564318227, + -0.7465980517921813, + 2.0925066015625777 + ] + } + ], + "multiplicity": 1 + }, + "mpi": { + "bank_size": -1, + "numerically_exact": true, + "omp_threads": -1, + "shared_memory_size": 10000 + }, + "mra": { + "basis_order": 5, + "basis_type": "interpolating", + "boxes": [ + 2, + 2, + 2 + ], + "corner": [ + -1, + -1, + -1 + ], + "max_scale": 20, + "min_scale": -6 + }, + "printer": { + "file_name": "hf", + "print_constants": false, + "print_level": 0, + "print_mpi": false, + "print_prec": 6, + "print_width": 75 + }, + "rsp_calculations": {}, + "scf_calculation": { + "fock_operator": { + "coulomb_operator": { + "poisson_prec": 0.001, + "shared_memory": false + }, + "exchange_operator": { + "exchange_prec": -1.0, + "poisson_prec": 0.001 + }, + "kinetic_operator": { + "derivative": "abgv_55" + }, + "nuclear_operator": { + "nuclear_model": "point_like", + "proj_prec": 0.001, + "shared_memory": false, + "smooth_prec": 0.001 + }, + "xc_operator": { + "shared_memory": false, + "xc_functional": { + "cutoff": 0.0, + "functionals": [ + { + "coef": 1.0, + "name": "blyp" + } + ], + "spin": false + } + } + }, + "initial_guess": { + "environment": "None", + "external_field": "None", + "file_CUBE_a": "cube_vectors/CUBE_a_vector.json", + "file_CUBE_b": "cube_vectors/CUBE_b_vector.json", + "file_CUBE_p": "cube_vectors/CUBE_p_vector.json", + "file_basis": "initial_guess/mrchem.bas", + "file_chk": "checkpoint/phi_scf", + "file_gto_a": "initial_guess/mrchem.moa", + "file_gto_b": "initial_guess/mrchem.mob", + "file_gto_p": "initial_guess/mrchem.mop", + "file_phi_a": "initial_guess/phi_a_scf", + "file_phi_b": "initial_guess/phi_b_scf", + "file_phi_p": "initial_guess/phi_p_scf", + "localize": false, + "method": "DFT (BLYP)", + "prec": 0.001, + "relativity": "None", + "restricted": true, + "rotate": true, + "screen": 12.0, + "type": "core", + "zeta": 2 + }, + "properties": { + "dipole_moment": { + "dip-1": { + "operator": "h_e_dip", + "precision": 0.001, + "r_O": [ + 0.0, + 0.0, + 0.0 + ] + } + }, + "geometric_derivative": { + "geom-1": { + "method": "surface_integrals", + "operator": "h_nuc_grad", + "precision": 0.001, + "radius_factor": 0.6, + "smoothing": 0.001, + "surface_integral_precision": "medium" + } + } + } + }, + "schema_name": "mrchem_input", + "schema_version": 1 + }, + "output": { + "properties": { + "center_of_mass": [ + -2.3034482007428676, + -0.47659952984111875, + 0.7172401613655945 + ], + "charge": 0, + "dipole_moment": { + "dip-1": { + "magnitude": 1.7198919865413433, + "r_O": [ + 0.0, + 0.0, + 0.0 + ], + "vector": [ + -0.8972071878281191, + -0.2841157968815553, + 1.4395575436366013 + ], + "vector_el": [ + 22.58513690634613, + 4.622957673378089, + -6.451440874865561 + ], + "vector_nuc": [ + -23.48234409417425, + -4.907073470259644, + 7.890998418502162 + ] + } + }, + "geometric_derivative": { + "geom-1": { + "electronic": [ + 0.1260519015989603, + 0.06708480199000838, + -0.24292966533479632, + 0.30253765872409094, + 0.1843025436999091, + -0.6277289984934219 + ], + "electronic_norm": 0.7739150037080911, + "nuclear": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "nuclear_norm": 0.0, + "total": [ + 0.1260519015989603, + 0.06708480199000838, + -0.24292966533479632, + 0.30253765872409094, + 0.1843025436999091, + -0.6277289984934219 + ], + "total_norm": 0.7739150037080911 + } + }, + "geometry": [ + { + "symbol": "F", + "xyz": [ + -2.25797417086055, + -0.462275046496363, + 0.6442768685488515 + ] + }, + { + "symbol": "H", + "xyz": [ + -3.1605765564318227, + -0.7465980517921813, + 2.0925066015625777 + ] + } + ], + "multiplicity": 1, + "orbital_energies": { + "energy": [ + -16.18899571748805, + 3.1970606960540455, + 4.744873499611058, + 4.767570443715087, + 4.768191193836112 + ], + "occupation": [ + 2.0, + 2.0, + 2.0, + 2.0, + 2.0 + ], + "spin": [ + "p", + "p", + "p", + "p", + "p" + ], + "sum_occupied": 2.5774002314565028 + }, + "scf_energy": { + "E_ee": 94.6510436080992, + "E_eext": 0.0, + "E_el": -87.33167063235598, + "E_en": -329.7709134337061, + "E_kin": 163.8699575241591, + "E_next": 0.0, + "E_nn": 5.2023121410189415, + "E_nuc": 5.2023121410189415, + "E_tot": -82.12935849133704, + "E_x": 0.0, + "E_xc": -16.081758330908208, + "Er_el": 0.0, + "Er_nuc": 0.0, + "Er_tot": 0.0 + } + }, + "provenance": { + "creator": "MRChem", + "mpi_processes": 1, + "nthreads": 8, + "routine": "mrchem.x", + "total_cores": 8, + "version": "1.2.0-alpha" + }, + "rsp_calculations": null, + "scf_calculation": { + "initial_energy": { + "E_ee": 94.6510436080992, + "E_eext": 0.0, + "E_el": -87.33167063235598, + "E_en": -329.7709134337061, + "E_kin": 163.8699575241591, + "E_next": 0.0, + "E_nn": 5.2023121410189415, + "E_nuc": 5.2023121410189415, + "E_tot": -82.12935849133704, + "E_x": 0.0, + "E_xc": -16.081758330908208, + "Er_el": 0.0, + "Er_nuc": 0.0, + "Er_tot": 0.0 + }, + "success": true + }, + "schema_name": "mrchem_output", + "schema_version": 1, + "success": true + } +} diff --git a/tests/hf_grad_blyp_surface_force/reference/hf.out b/tests/hf_grad_blyp_surface_force/reference/hf.out new file mode 100644 index 000000000..5d933f101 --- /dev/null +++ b/tests/hf_grad_blyp_surface_force/reference/hf.out @@ -0,0 +1,288 @@ + + +*************************************************************************** +*** *** +*** *** +*** __ __ ____ ____ _ *** +*** | \/ | _ \ / ___| |__ ___ _ __ ___ *** +*** | |\/| | |_) | | | '_ \ / _ \ '_ ` _ \ *** +*** | | | | _ <| |___| | | | __/ | | | | | *** +*** |_| |_|_| \_\\____|_| |_|\___|_| |_| |_| *** +*** *** +*** VERSION 1.2.0-alpha *** +*** *** +*** Git branch surface_forces *** +*** Git commit hash 1dca98fa8c1278b6baef *** +*** Git commit author moritzgubler *** +*** Git commit date Mon Aug 12 12:32:28 2024 +0200 *** +*** *** +*** Contact: luca.frediani@uit.no *** +*** *** +*** Radovan Bast Magnar Bjorgve *** +*** Roberto Di Remigio Antoine Durdek *** +*** Luca Frediani Gabriel Gerez *** +*** Stig Rune Jensen Jonas Juselius *** +*** Rune Monstad Peter Wind *** +*** *** +*************************************************************************** + +--------------------------------------------------------------------------- + + MPI processes : (no bank) 1 + OpenMP threads : 8 + Total cores : 8 + +--------------------------------------------------------------------------- + +XCFun DFT library Copyright 2009-2020 Ulf Ekstrom and contributors. +See http://dftlibs.org/xcfun/ for more information. + +This is free software; see the source code for copying conditions. +There is ABSOLUTELY NO WARRANTY; not even for MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. For details see the documentation. +Scientific users of this library should cite +U. Ekstrom, L. Visscher, R. Bast, A. J. Thorvaldsen and K. Ruud; +J.Chem.Theor.Comp. 2010, DOI: 10.1021/ct100117s + +--------------------------------------------------------------------------- + + MRCPP version : 1.6.0-alpha + Git branch : HEAD + Git commit hash : 720133372c9717134c5a + Git commit author : gitpeterwind + Git commit date : Thu Feb 15 13:44:31 2024 +0100 + + Linear algebra : EIGEN v3.4.0 + Parallelization : MPI/OpenMP (8 threads) + +--------------------------------------------------------------------------- + + + +=========================================================================== + MultiResolution Analysis +--------------------------------------------------------------------------- + polynomial order : 5 + polynomial type : Interpolating +--------------------------------------------------------------------------- + total boxes : 8 + boxes : [ 2 2 2 ] + unit lengths : [ 64.00000 64.00000 64.00000 ] + scaling factor : [ 1.00000 1.00000 1.00000 ] + lower bounds : [ -64.00000 -64.00000 -64.00000 ] + upper bounds : [ 64.00000 64.00000 64.00000 ] + total length : [ 128.00000 128.00000 128.00000 ] +=========================================================================== + + + +*************************************************************************** +*** *** +*** Initializing Molecule *** +*** *** +*************************************************************************** + + +=========================================================================== + Molecule +--------------------------------------------------------------------------- + Charge : 0 + Multiplicity : 1 +--------------------------------------------------------------------------- + N Atom : x y z +--------------------------------------------------------------------------- + 0 F : -2.257974 -0.462275 0.644277 + 1 H : -3.160577 -0.746598 2.092507 +--------------------------------------------------------------------------- + Center of mass : -2.303448 -0.476600 0.717240 +=========================================================================== + + + +*************************************************************************** +*** *** +*** Computing Initial Guess Wavefunction *** +*** *** +*************************************************************************** + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Calculation : Compute initial orbitals + Method : Diagonalize Core Hamiltonian matrix + Precision : 1.00000e-03 + Restricted : True + AO basis : Hydrogenic orbitals + Zeta quality : 2 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +=========================================================================== + Molecular Orbitals +--------------------------------------------------------------------------- + Alpha electrons : 5 + Beta electrons : 5 + Total electrons : 10 +--------------------------------------------------------------------------- + n Occ Spin : Norm +--------------------------------------------------------------------------- + 0 2 p : 9.996812789590e-01 + 1 2 p : 9.998694293756e-01 + 2 2 p : 9.999998231017e-01 + 3 2 p : 9.999999836389e-01 + 4 2 p : 9.999998001090e-01 +=========================================================================== + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Calculation : Compute initial energy + Method : DFT (BLYP) + Relativity : None + Environment : None + External fields : None + Precision : 1.00000e-03 + Localization : Off +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +=========================================================================== + Molecular Energy (initial) +--------------------------------------------------------------------------- + Kinetic energy : (au) 163.869957524159 + E-N energy : (au) -329.770913433706 + Coulomb energy : (au) 94.651043608099 + Exchange energy : (au) 0.000000000000 + X-C energy : (au) -16.081758330908 + N-N energy : (au) 5.202312141019 +--------------------------------------------------------------------------- + Electronic energy : (au) -87.331670632356 + Nuclear energy : (au) 5.202312141019 +--------------------------------------------------------------------------- + Total energy : (au) -8.212935849134e+01 + : (kcal/mol) -5.153695055204e+04 + : (kJ/mol) -2.156306011097e+05 + : (eV) -2.234853696043e+03 +=========================================================================== + + +=========================================================================== + Orbital Energies (initial) +--------------------------------------------------------------------------- + n Occ Spin : Epsilon +--------------------------------------------------------------------------- + 0 2 p : (au) -16.188995717488 + 1 2 p : (au) 3.197060696054 + 2 2 p : (au) 4.744873499611 + 3 2 p : (au) 4.767570443715 + 4 2 p : (au) 4.768191193836 +--------------------------------------------------------------------------- + Sum occupied : (au) 2.577400231457 +=========================================================================== + + + +*************************************************************************** +*** *** +*** Printing Molecular Properties *** +*** *** +*************************************************************************** + + +=========================================================================== + Molecule +--------------------------------------------------------------------------- + Charge : 0 + Multiplicity : 1 +--------------------------------------------------------------------------- + N Atom : x y z +--------------------------------------------------------------------------- + 0 F : -2.257974 -0.462275 0.644277 + 1 H : -3.160577 -0.746598 2.092507 +--------------------------------------------------------------------------- + Center of mass : -2.303448 -0.476600 0.717240 +=========================================================================== + + +=========================================================================== + Molecular Energy (final) +--------------------------------------------------------------------------- + Kinetic energy : (au) 163.869957524159 + E-N energy : (au) -329.770913433706 + Coulomb energy : (au) 94.651043608099 + Exchange energy : (au) 0.000000000000 + X-C energy : (au) -16.081758330908 + N-N energy : (au) 5.202312141019 +--------------------------------------------------------------------------- + Electronic energy : (au) -87.331670632356 + Nuclear energy : (au) 5.202312141019 +--------------------------------------------------------------------------- + Total energy : (au) -8.212935849134e+01 + : (kcal/mol) -5.153695055204e+04 + : (kJ/mol) -2.156306011097e+05 + : (eV) -2.234853696043e+03 +=========================================================================== + + +=========================================================================== + Orbital Energies (final) +--------------------------------------------------------------------------- + n Occ Spin : Epsilon +--------------------------------------------------------------------------- + 0 2 p : (au) -16.188995717488 + 1 2 p : (au) 3.197060696054 + 2 2 p : (au) 4.744873499611 + 3 2 p : (au) 4.767570443715 + 4 2 p : (au) 4.768191193836 +--------------------------------------------------------------------------- + Sum occupied : (au) 2.577400231457 +=========================================================================== + + +=========================================================================== + Dipole Moment (dip-1) +--------------------------------------------------------------------------- + r_O : 0.000000 0.000000 0.000000 +--------------------------------------------------------------------------- + Electronic vector : 22.585137 4.622958 -6.451441 + Magnitude : (au) 23.939115 + : (Debye) 60.847162 +--------------------------------------------------------------------------- + Nuclear vector : -23.482344 -4.907073 7.890998 + Magnitude : (au) 25.254063 + : (Debye) 64.189426 +--------------------------------------------------------------------------- + Total vector : -0.897207 -0.284116 1.439558 + Magnitude : (au) 1.719892 + : (Debye) 4.371529 +=========================================================================== + + +=========================================================================== + Geometric Derivative (geom-1) +--------------------------------------------------------------------------- + Total : 0.126052 0.067085 -0.242930 + : 0.302538 0.184303 -0.627729 + Norm : (au) 0.773915 +--------------------------------------------------------------------------- + Nuclear : 0.000000 0.000000 0.000000 + : 0.000000 0.000000 0.000000 + Norm : (au) 0.000000 +--------------------------------------------------------------------------- + Electronic : 0.126052 0.067085 -0.242930 + : 0.302538 0.184303 -0.627729 + Norm : (au) 0.773915 +--------------------------------------------------------------------------- + Est. var. of force error: (au) 4.0925e-01 +=========================================================================== + + + + +*************************************************************************** +*** *** +*** Exiting MRChem *** +*** *** +*** Wall time : 0h 0m 2s *** +*** *** +*************************************************************************** + + diff --git a/tests/hf_grad_blyp_surface_force/test b/tests/hf_grad_blyp_surface_force/test new file mode 100755 index 000000000..9ccec52d7 --- /dev/null +++ b/tests/hf_grad_blyp_surface_force/test @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 + +import math +import json +import sys +from pathlib import Path +from itertools import repeat +from functools import reduce + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +from tester import * # isort:skip + +options = script_cli() + +# nuclear component of the molecular gradient as computed by Psi4 +psi4_nuc_grad = [ + -1.568919559280, + -0.494215317058, + 2.517338742705, + 1.568919559280, + 0.494215317058, + -2.517338742705, +] + +# compare against reference +filters = { + SUM_OCCUPIED: rel_tolerance(1.0e-6), + E_KIN: rel_tolerance(1.0e-6), + E_EN: rel_tolerance(1.0e-6), + E_EE: rel_tolerance(1.0e-6), + E_X: rel_tolerance(1.0e-6), + E_XC: rel_tolerance(1.0e-6), + E_EEXT: rel_tolerance(1.0e-6), + E_NEXT: rel_tolerance(1.0e-6), + E_EL: rel_tolerance(1.0e-6), + GEOMETRIC_DERIVATIVE(1, "total"): rel_tolerance(1.0e-6), +} + +ierr = run(options, input_file="hf", filters=filters) + +# compare nuclear component of the molecular gradient with Psi4 +with Path("hf.json").open("r") as o: + nuc_grad = json.load(o)["output"]["properties"]["geometric_derivative"]["geom-1"]["nuclear"] +passed, message = compare_values( + nuc_grad, + psi4_nuc_grad, + "MRChem vs. Psi4 nuclear component of the molecular gradient", + rtol=1.0e-6, + atol=1.0e-6, +) +sys.stdout.write(f"{message}\n") +ierr += 0 if passed else 137 + +sys.exit(ierr) diff --git a/tests/hf_grad_lda/hf.inp b/tests/hf_grad_lda/hf.inp index 4109d374e..43ebe5f04 100644 --- a/tests/hf_grad_lda/hf.inp +++ b/tests/hf_grad_lda/hf.inp @@ -14,6 +14,10 @@ $end translate = false } +Forces { + method = 'hellmann_feynman' +} + WaveFunction { method = LDA # Wave function method (HF or DFT) }