diff --git a/flow/src/wF0El.cpp b/flow/src/wF0El.cpp index 45a27a4c9a9cf0bf07eb4a03522be0241d7896ec..5643219538e53a449da43f1c0d6ca8f020c465dc 100644 --- a/flow/src/wF0El.cpp +++ b/flow/src/wF0El.cpp @@ -24,7 +24,7 @@ using namespace flow; */ double F0ElRho::eval(Element const &e, std::vector<double> const &u, size_t k) const { - double gradU = e.computeGrad(u, k).norm(); // norm of velocity + double gradU = e.computeGradient(u, k).norm(); // norm of velocity if (gradU < gradUC) // true density { @@ -45,7 +45,7 @@ double F0ElRho::eval(Element const &e, std::vector<double> const &u, size_t k) c */ double F0ElRho::evalD(Element const &e, std::vector<double> const &u, size_t k) const { - double gradU = e.computeGrad(u, k).norm(); // norm of velocity + double gradU = e.computeGradient(u, k).norm(); // norm of velocity if (gradU < gradUC) // true density { @@ -92,7 +92,8 @@ void F0ElRhoL::write(std::ostream &out) const */ double F0ElMach::eval(Element const &e, std::vector<double> const &u, size_t k) const { - double gradU2 = e.computeGrad2(u, k); // velocity squared + Eigen::VectorXd gradU = e.computeGradient(u, k); // velocity + double gradU2 = gradU.squaredNorm(); // velocity squared double a2 = 1 / (mInf * mInf) + 0.5 * (gamma - 1) * (1 - gradU2); // speed of sound squared return sqrt(gradU2) / sqrt(a2); @@ -103,7 +104,8 @@ double F0ElMach::eval(Element const &e, std::vector<double> const &u, size_t k) */ double F0ElMach::evalD(Element const &e, std::vector<double> const &u, size_t k) const { - double gradU2 = e.computeGrad2(u, k); + Eigen::VectorXd gradU = e.computeGradient(u, k); // velocity + double gradU2 = gradU.squaredNorm(); // velocity squared double a2 = 1 / (mInf * mInf) + 0.5 * (gamma - 1) * (1 - gradU2); return 1 / sqrt(gradU2 * a2) + 0.5 * (gamma - 1) * sqrt(gradU2) / sqrt(a2 * a2 * a2); // has to be multiplied by grad u to recover true derivative @@ -140,7 +142,8 @@ void F0ElMachL::write(std::ostream &out) const */ double F0ElCp::eval(Element const &e, std::vector<double> const &u, size_t k) const { - double gradU2 = e.computeGrad2(u, k); // velocity squared + Eigen::VectorXd gradU = e.computeGradient(u, k); // velocity + double gradU2 = gradU.squaredNorm(); // velocity squared //particularized: 2 / (gamma * mInf * mInf) * (pow(1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - gradU2), gamma / (gamma - 1)) - 1); double a = 1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - gradU2); @@ -155,7 +158,8 @@ double F0ElCp::eval(Element const &e, std::vector<double> const &u, size_t k) co */ double F0ElCp::evalD(Element const &e, std::vector<double> const &u, size_t k) const { - double gradU2 = e.computeGrad2(u, k); // velocity squared + Eigen::VectorXd gradU = e.computeGradient(u, k); // velocity + double gradU2 = gradU.squaredNorm(); // velocity squared //particularized: -2 * pow(1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - gradU2), 1 / (gamma - 1)); double a = 1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - gradU2); @@ -175,7 +179,9 @@ void F0ElCp::write(std::ostream &out) const */ double F0ElCpL::eval(Element const &e, std::vector<double> const &u, size_t k) const { - return 1 - e.computeGrad2(u, k); + Eigen::VectorXd gradU = e.computeGradient(u, k); // velocity + double gradU2 = gradU.squaredNorm(); // velocity squared + return 1 - gradU2; } double F0ElCpL::evalD(Element const &e, std::vector<double> const &u, size_t k) const { diff --git a/flow/src/wKuttaResidual.cpp b/flow/src/wKuttaResidual.cpp index 59c2010a5453f0d76a357af6d4f6b32e23aa9b57..d7adcac995d1b079033d0e95dcab1272eaae953d 100644 --- a/flow/src/wKuttaResidual.cpp +++ b/flow/src/wKuttaResidual.cpp @@ -40,7 +40,7 @@ Eigen::MatrixXd KuttaResidual::buildFixed(KuttaElement const &ke, std::vector<do size_t nRow = ke.nRow; // Velocity - Eigen::RowVectorXd Aup = ke.volE->computeGrad(phi, 0).transpose() * ke.volE->getVMem().getJinv(0) * ke.volE->getVCache().getDsf(0); + Eigen::RowVectorXd Aup = ke.volE->computeGradient(phi, 0).transpose() * ke.volE->getVMem().getJinv(0) * ke.volE->getVCache().getDsf(0); // Build Eigen::MatrixXd A = Eigen::MatrixXd::Zero(nRow, ke.nCol); @@ -72,7 +72,8 @@ Eigen::VectorXd KuttaResidual::build(KuttaElement const &ke, std::vector<double> size_t nRow = ke.nRow; // Velocity - double dPhi2 = ke.volE->computeGrad2(phi, 0); + Eigen::VectorXd dPhi = ke.volE->computeGradient(phi, 0); + double dPhi2 = dPhi.squaredNorm(); // Build Eigen::VectorXd b = Eigen::VectorXd::Zero(nRow); @@ -125,7 +126,7 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> KuttaResidual::buildGradientMesh(Ku size_t nSur = ke.surE->nodes.size(); // velocity - Eigen::VectorXd dPhi = ke.volE->computeGrad(phi, 0); + Eigen::VectorXd dPhi = ke.volE->computeGradient(phi, 0); // Build Eigen::MatrixXd Av = Eigen::MatrixXd::Zero(nRow, nDim * nCol); diff --git a/flow/src/wLoadFunctional.cpp b/flow/src/wLoadFunctional.cpp index a251f54f689d3fe9ec25a4f6112e467844faf324..feefdaf9b2fdfc89b04b9fcb2dec2dd8a58acd17 100644 --- a/flow/src/wLoadFunctional.cpp +++ b/flow/src/wLoadFunctional.cpp @@ -65,7 +65,7 @@ Eigen::MatrixXd LoadFunctional::buildGradientFlow(Element const &e, Element cons Mem &mem = e.getVMem(); // Gradient of pressure force coefficient in associated volume - Eigen::MatrixXd dfcp = e.normal() * cp.evalD(eV, phi, 0) * eV.computeGrad(phi, 0).transpose() * eV.getVMem().getJinv(0) * eV.getVCache().getDsf(0); + Eigen::MatrixXd dfcp = e.normal() * cp.evalD(eV, phi, 0) * eV.computeGradient(phi, 0).transpose() * eV.getVMem().getJinv(0) * eV.getVCache().getDsf(0); // Integrate cp on the surface Eigen::MatrixXd A = Eigen::MatrixXd::Zero(3 * e.nodes.size(), eV.nodes.size()); @@ -99,7 +99,7 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> LoadFunctional::buildGradientMesh(E Eigen::Vector3d nrm = e.normal(); // unit normal // Gradients double dCp = cp.evalD(eV, phi, 0); // pressure coefficient - Eigen::VectorXd dPhi = eV.computeGrad(phi, 0); // potential + Eigen::VectorXd dPhi = eV.computeGradient(phi, 0); // potential Eigen::MatrixXd const &iJ = eV.getVMem().getJinv(0); // inverse Jacobian std::vector<Eigen::MatrixXd> const &dJ = eV.getVMem().getGradJ(0); // Jacobian std::vector<Eigen::Vector3d> dNrm = e.gradientNormal(); // unit normal diff --git a/flow/src/wNewton.cpp b/flow/src/wNewton.cpp index 4ac08c51708639d0c16c8e06b8a2aabda7e75665..71a50f75ca6e842d13d9e4d35807aa3d217c4520 100644 --- a/flow/src/wNewton.cpp +++ b/flow/src/wNewton.cpp @@ -502,7 +502,7 @@ void Newton::findUpwd() { tbb::parallel_do(pbl->medium->adjMap.begin(), pbl->medium->adjMap.end(), [&](std::pair<Element *, std::vector<Element *>> &p) { // Opposite velocity vector - Eigen::VectorXd vel_ = -p.first->computeGrad(phi, 0); + Eigen::VectorXd vel_ = -p.first->computeGradient(phi, 0); vel_.normalize(); // Best alignement strategy // -> find (cgU-cgE) \dot vel_ closest to one diff --git a/flow/src/wPotentialResidual.cpp b/flow/src/wPotentialResidual.cpp index ff2054788bdefe5fd12d4ebcfcbdaffb128f1552..f98adbc55f97dd7e3126fb12c4e7c300239e2570 100644 --- a/flow/src/wPotentialResidual.cpp +++ b/flow/src/wPotentialResidual.cpp @@ -65,7 +65,7 @@ Eigen::VectorXd PotentialResidual::build(Element const &e, Element const &eU, st // Subsonic contribution Eigen::VectorXd b = Eigen::VectorXd::Zero(e.nodes.size()); for (size_t k = 0; k < gauss.getN(); ++k) - b += fluid.rho.eval(e, phi, k) * (mem.getJinv(k) * cache.getDsf(k)).transpose() * e.computeGrad(phi, k) * gauss.getW(k) * mem.getDetJ(k); + b += fluid.rho.eval(e, phi, k) * (mem.getJinv(k) * cache.getDsf(k)).transpose() * e.computeGradient(phi, k) * gauss.getW(k) * mem.getDetJ(k); // Supersonic contribution double mach = fluid.mach.eval(e, phi, 0); @@ -77,7 +77,7 @@ Eigen::VectorXd PotentialResidual::build(Element const &e, Element const &eU, st b *= 1 - mu; // contribution of upwind element for (size_t k = 0; k < gauss.getN(); ++k) - b += mu * rhoU * (mem.getJinv(k) * cache.getDsf(k)).transpose() * e.computeGrad(phi, k) * gauss.getW(k) * mem.getDetJ(k); + b += mu * rhoU * (mem.getJinv(k) * cache.getDsf(k)).transpose() * e.computeGradient(phi, k) * gauss.getW(k) * mem.getDetJ(k); } return b; } @@ -107,7 +107,7 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> PotentialResidual::buildGradientFlo double wdj = gauss.getW(k) * mem.getDetJ(k); // Shape functions and solution gradient Eigen::MatrixXd const &dSf = mem.getJinv(k) * cache.getDsf(k); - Eigen::VectorXd dPhi = e.computeGrad(phi, k); + Eigen::VectorXd dPhi = e.computeGradient(phi, k); // rho * grad_phi*grad_psi + drho * grad_phi*grad_psi A1 += fluid.rho.eval(e, phi, k) * dSf.transpose() * dSf * wdj; @@ -123,7 +123,7 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> PotentialResidual::buildGradientFlo double mu = muC * (1 - (mCO * mCO) / (mach * mach)); double dmu = 2 * muC * mCO * mCO / (mach * mach * mach); // density and gradients on upwind elements - Eigen::VectorXd dPhiU = eU.computeGrad(phi, 0); + Eigen::VectorXd dPhiU = eU.computeGradient(phi, 0); double rhoU = fluid.rho.eval(eU, phi, 0); double dRhoU = fluid.rho.evalD(eU, phi, 0); Eigen::MatrixXd const &dSfU = eU.getVMem().getJinv(0) * eU.getVCache().getDsf(0); @@ -137,7 +137,7 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> PotentialResidual::buildGradientFlo double wdj = gauss.getW(k) * mem.getDetJ(k); // Shape functions and solution gradient Eigen::MatrixXd const &dSf = mem.getJinv(k) * cache.getDsf(k); - Eigen::VectorXd dPhi = e.computeGrad(phi, k); + Eigen::VectorXd dPhi = e.computeGradient(phi, k); // mu*drhoU*grad_phi*grad_psi A2 += mu * dRhoU * dSf.transpose() * dPhi * dPhiU.transpose() * dSfU * wdj; @@ -173,7 +173,7 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> PotentialResidual::buildGradientMes for (size_t k = 0; k < gauss.getN(); ++k) { // Density and gradients - Eigen::VectorXd dPhi = e.computeGrad(phi, k); + Eigen::VectorXd dPhi = e.computeGradient(phi, k); double rho = fluid.rho.eval(e, phi, k); double dRho = fluid.rho.evalD(e, phi, k); Eigen::MatrixXd const &dSf = cache.getDsf(k); @@ -205,7 +205,7 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> PotentialResidual::buildGradientMes double mu = muC * (1 - (mCO * mCO) / (mach * mach)); double dmu = 2 * muC * mCO * mCO / (mach * mach * mach); // upwind density and gradient - Eigen::VectorXd dPhiU = eU.computeGrad(phi, 0); + Eigen::VectorXd dPhiU = eU.computeGradient(phi, 0); double rhoU = fluid.rho.eval(eU, phi, 0); double dRhoU = fluid.rho.evalD(eU, phi, 0); Eigen::MatrixXd const &iJU = eU.getVMem().getJinv(0); @@ -217,7 +217,7 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> PotentialResidual::buildGradientMes for (size_t k = 0; k < gauss.getN(); ++k) { // Density, Mach and Gradients - Eigen::VectorXd dPhi = e.computeGrad(phi, k); + Eigen::VectorXd dPhi = e.computeGradient(phi, k); double rho = fluid.rho.eval(e, phi, k); double dM = fluid.mach.evalD(e, phi, k); Eigen::MatrixXd const &dSf = cache.getDsf(k); diff --git a/flow/src/wSolver.cpp b/flow/src/wSolver.cpp index c90dda9f650ce5df742dbd6e46e7b580b62e7aa1..d44e29dcfdaa7af01618a2e658dfe728fec40961 100644 --- a/flow/src/wSolver.cpp +++ b/flow/src/wSolver.cpp @@ -228,7 +228,7 @@ void Solver::computeFlow() U[n->row] = Eigen::Vector3d::Zero(); for (auto e : p.second) { - Eigen::VectorXd grad = e->computeGrad(phi, 0); + Eigen::VectorXd grad = e->computeGradient(phi, 0); for (size_t i = 0; i < grad.size(); ++i) U[n->row](i) += grad(i); } diff --git a/flow/src/wWakeResidual.cpp b/flow/src/wWakeResidual.cpp index 934b69a295aa60cfb05d0e9223c6c1541db0bdb6..0b111e233d2e82a703972e027aa134bbe739a014 100644 --- a/flow/src/wWakeResidual.cpp +++ b/flow/src/wWakeResidual.cpp @@ -55,8 +55,8 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> WakeResidual::buildFixed(WakeElemen Eigen::VectorXd dSfp(nRow); dSfp = 0.5 * sqrt(sMem.getVol()) * dSf * vUpJ.transpose() * vi; // Velocity - Eigen::RowVectorXd Aup = we.volUpE->computeGrad(phi, 0).transpose() * vUpJ * vUpDsf; - Eigen::RowVectorXd Alw = we.volLwE->computeGrad(phi, 0).transpose() * vLwJ * vLwDsf; + Eigen::RowVectorXd Aup = we.volUpE->computeGradient(phi, 0).transpose() * vUpJ * vUpDsf; + Eigen::RowVectorXd Alw = we.volLwE->computeGradient(phi, 0).transpose() * vLwJ * vLwDsf; // Build Eigen::MatrixXd Au = Eigen::MatrixXd::Zero(nRow, we.nColUp); @@ -101,8 +101,10 @@ std::tuple<Eigen::VectorXd, Eigen::VectorXd> WakeResidual::build(WakeElement con Eigen::VectorXd dSfp(nRow); dSfp = 0.5 * sqrt(sMem.getVol()) * dSf * we.volUpE->getVMem().getJinv(0).transpose() * vi; // Velocity squared - double dPhi2u = we.volUpE->computeGrad2(phi, 0); - double dPhi2l = we.volLwE->computeGrad2(phi, 0); + Eigen::VectorXd dPhiU = we.volUpE->computeGradient(phi, 0); + Eigen::VectorXd dPhiL = we.volLwE->computeGradient(phi, 0); + double dPhi2u = dPhiU.squaredNorm(); + double dPhi2l = dPhiL.squaredNorm(); // Build Eigen::VectorXd bu = Eigen::VectorXd::Zero(nRow); @@ -193,8 +195,8 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd, Eigen::MatrixXd> WakeResidual::buil } } // Gradients of potential - Eigen::VectorXd dPhiUp = we.volUpE->computeGrad(phi, 0); - Eigen::VectorXd dPhiLw = we.volLwE->computeGrad(phi, 0); + Eigen::VectorXd dPhiUp = we.volUpE->computeGradient(phi, 0); + Eigen::VectorXd dPhiLw = we.volLwE->computeGradient(phi, 0); // Build Eigen::MatrixXd Au = Eigen::MatrixXd::Zero(nRow, nDim * nColUp); diff --git a/heat/src/heat.h b/heat/src/heat.h index 479b9945ae3087528f31e468b78f6a9390cb5296..5084a8f82a0c8da88c216c62e8b4ff5a3ecfc785 100644 --- a/heat/src/heat.h +++ b/heat/src/heat.h @@ -48,6 +48,8 @@ class Extractor; class NodePair; +class HeatTerm; + // not used yet class DisplayHook; }; // namespace heat diff --git a/heat/src/wHeatTerm.cpp b/heat/src/wHeatTerm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..057e139c461a5f2b5d2b2a240d158a8ef448db9b --- /dev/null +++ b/heat/src/wHeatTerm.cpp @@ -0,0 +1,154 @@ +/* + * Copyright 2020 University of Liège + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wHeatTerm.h" + +#include "wElement.h" +#include "wCache.h" +#include "wGauss.h" +#include "wMem.h" +#include "wFct0.h" +#include "wFct2.h" + +using namespace heat; +using namespace tbox; + +/** + * @brief Build volume terms for the heat equation on one element + */ +Eigen::MatrixXd HeatTerm::build(Element const &e, std::vector<double> const &u, Fct2 const &f, bool fake) +{ + // Get precomputed values + Cache &cache = e.getVCache(); + Gauss &gauss = cache.getVGauss(); + + Eigen::MatrixXd K = Eigen::MatrixXd::Zero(e.nodes.size(), e.nodes.size()); + if (fake) // fake run - fill MPI job list + { + for (size_t k = 0; k < gauss.getN(); ++k) + { + Eigen::MatrixXd fk; + f.eval(e, u, k, fk, fake); + } + } + else // true run - use MPI cached results + { + // Gauss integration + Mem &mem = e.getVMem(); + for (size_t k = 0; k < gauss.getN(); ++k) + { + // Jacobian inverse, shape functions and function evaluation + Eigen::MatrixXd const &J = mem.getJinv(k); + Eigen::MatrixXd const &dff = cache.getDsf(k); + Eigen::MatrixXd fk; + f.eval(e, u, k, fk, fake); + + // Elementary stiffness matrix + K += (fk * J * dff).transpose() * J * dff * gauss.getW(k) * mem.getDetJ(k); + } + } + return K; +} + +/** + * @brief Build surface/volume flux on one element + */ +Eigen::VectorXd HeatTerm::build(Element const &e, std::vector<double> const &u, Fct0 const &f) +{ + // Get precomputed values + Cache &cache = e.getVCache(); + Gauss &gauss = cache.getVGauss(); + Mem &mem = e.getVMem(); + + // Gauss integration + Eigen::VectorXd s = Eigen::VectorXd::Zero(e.nodes.size()); + for (size_t k = 0; k < gauss.getN(); ++k) + s += cache.getSf(k) * f.eval(e, u, k) * gauss.getW(k) * mem.getDetJ(k); + return s; +} + +/** + * @brief Build volume flux of the heat equation on one element + * @todo not used + */ +Eigen::VectorXd HeatTerm::build2(Element const &e, std::vector<double> const &u, Fct2 const &f) +{ + // Get precomputed values + Cache &cache = e.getVCache(); + Gauss &gauss = cache.getVGauss(); + Mem &mem = e.getVMem(); + + // Gauss integration + Eigen::VectorXd qV = Eigen::VectorXd::Zero(e.nodes.size()); + for (size_t k = 0; k < gauss.getN(); ++k) + { + // Shape functions, gradient and flux evaluation + Eigen::MatrixXd const &dff = cache.getDsf(k); + Eigen::MatrixXd fk(2, 2); + f.eval(e, u, k, fk, false); + + // Elementary flux vector + qV += (fk * e.computeGradient(u, k)).transpose() * mem.getJinv(k) * dff * gauss.getW(k) * mem.getDetJ(k); + } + return qV; +} + +/** + * @brief Compute (integrate) volume flux + */ +Eigen::VectorXd HeatTerm::computeFlux(Element const &e, std::vector<double> const &u, Fct2 const &f) +{ + // Get precomputed values + Cache &cache = e.getVCache(); + Gauss &gauss = cache.getVGauss(); + Mem &mem = e.getVMem(); + + // Gauss integration + Eigen::VectorXd qV = Eigen::Vector2d::Zero(); // 2 dimensions + for (size_t k = 0; k < gauss.getN(); ++k) + { + // Gradient and matrix function evaluation + Eigen::VectorXd gradk = e.computeGradient(u, k); + Eigen::MatrixXd fk(2, 2); + f.eval(e, u, k, fk, false); + + qV -= fk * gradk * gauss.getW(k) * mem.getDetJ(k); + } + return qV; +} + +/** + * @brief Compute (integrate) matrix + */ +Eigen::MatrixXd HeatTerm::computeMatrix(Element const &e, std::vector<double> const &u, Fct2 const &f) +{ + // Get precomputed values + Cache &cache = e.getVCache(); + Gauss &gauss = cache.getVGauss(); + Mem &mem = e.getVMem(); + + // Gauss integration + Eigen::MatrixXd out = Eigen::Matrix2d::Zero(); // 2 dimensions, should match fk size + for (size_t k = 0; k < gauss.getN(); ++k) + { + // Function evaluation + Eigen::MatrixXd fk; + f.eval(e, u, k, fk, false); + + out += fk * gauss.getW(k) * mem.getDetJ(k); + } + return out; +} diff --git a/heat/src/wHeatTerm.h b/heat/src/wHeatTerm.h new file mode 100644 index 0000000000000000000000000000000000000000..3bbfada2079b4f9522c599c208f0baca3b57a5fc --- /dev/null +++ b/heat/src/wHeatTerm.h @@ -0,0 +1,45 @@ +/* + * Copyright 2020 University of Liège + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WHEATTERM_H +#define WHEATTERM_H + +#include "heat.h" + +#include <vector> +#include <Eigen/Dense> + +namespace heat +{ + +/** + * @brief Formulation of heat terms + */ +class HEAT_API HeatTerm +{ +public: + // Volume + static Eigen::MatrixXd build(tbox::Element const &e, std::vector<double> const &u, tbox::Fct2 const &f, bool fake); + static Eigen::VectorXd build2(tbox::Element const &e, std::vector<double> const &u, tbox::Fct2 const &f); + // Boundary and Source + static Eigen::VectorXd build(tbox::Element const &e, std::vector<double> const &u, tbox::Fct0 const &f); + // Functionals + static Eigen::VectorXd computeFlux(tbox::Element const &e, std::vector<double> const &u, tbox::Fct2 const &f); + static Eigen::MatrixXd computeMatrix(tbox::Element const &e, std::vector<double> const &u, tbox::Fct2 const &f); +}; + +} // namespace heat +#endif //WHEATTERM_H diff --git a/heat/src/wSolver.cpp b/heat/src/wSolver.cpp index 8600d1ea6c25e5b0c224136cfa68501c53228027..685cabd12719e02da28920275a06d8cc604eee26 100644 --- a/heat/src/wSolver.cpp +++ b/heat/src/wSolver.cpp @@ -29,6 +29,7 @@ #include "wDirichlet.h" #include "wDisplayHook.h" #include "wPeriodic.h" +#include "wHeatTerm.h" #include "wResults.h" #include "wMshExport.h" #include "wLinearSolver.h" @@ -263,14 +264,14 @@ void Solver::start(MshExport *mshWriter) //std::cout << "processing element #" << e->no << "\n"; // (flux moyen . volume) sur l'element - Eigen::VectorXd qV = e->computeqV(T1, mat->k); + Eigen::VectorXd qV = HeatTerm::computeFlux(*e, T1, mat->k); double V = e->computeV(); if (save) { // gradient of T at GP 0 - Eigen::VectorXd grad = e->computeGrad(T1, 0); + Eigen::VectorXd grad = e->computeGradient(T1, 0); int i = e->no - 1; gradT_x[i] = grad(0); gradT_y[i] = grad(1); @@ -280,7 +281,7 @@ void Solver::start(MshExport *mshWriter) kgradT[i] = Eigen::Vector3d(qV(0) / V, qV(1) / V, 0); // mean k over the element - Eigen::MatrixXd kmean = e->computeV(T1, mat->k) / V; + Eigen::MatrixXd kmean = HeatTerm::computeMatrix(*e, T1, mat->k) / V; kmoy11[i] = kmean(0, 0); kmoy22[i] = kmean(1, 1); kmoy12[i] = kmean(0, 1); @@ -378,7 +379,7 @@ void Solver::buildK(Eigen::SparseMatrix<double, Eigen::RowMajor> &K2, Eigen::Map return; //std::cout << "processing element #" << e->no << "\n"; - Eigen::MatrixXd Ke = e->buildK(T1, mat->k, false); + Eigen::MatrixXd Ke = HeatTerm::build(*e, T1, mat->k, false); // assembly tbb::spin_mutex::scoped_lock lock(mutex); @@ -411,7 +412,7 @@ void Solver::buildK(Eigen::SparseMatrix<double, Eigen::RowMajor> &K2, Eigen::Map [&](Element *e) { if (e->type() != ELTYPE::TRI3) return; - Eigen::MatrixXd Ke = e->buildK(T1, mat->k, true); // bidon + Eigen::MatrixXd Ke = HeatTerm::build(*e, T1, mat->k, true); // bidon }); } @@ -436,7 +437,7 @@ void Solver::buildK(Eigen::SparseMatrix<double, Eigen::RowMajor> &K2, Eigen::Map [&](Element *e) { if (e->type() != ELTYPE::TRI3) return; - Eigen::MatrixXd Ke = e->buildK(T1, mat->k, false); + Eigen::MatrixXd Ke = HeatTerm::build(*e, T1, mat->k, false); // assembly //tbb::spin_mutex::scoped_lock lock(mutex); @@ -531,8 +532,7 @@ void Solver::buildK(Eigen::SparseMatrix<double, Eigen::RowMajor> &K2, Eigen::Map //std::cout << "processing element #" << e->no << "\n"; // ** Ce matrix => K matrix - Fct0C f(1.0); - Eigen::VectorXd Ce = e->builds(T1, f); + Eigen::VectorXd Ce = HeatTerm::build(*e, T1, Fct0C(1.0)); // assembly tbb::spin_mutex::scoped_lock lock(mutex); @@ -603,7 +603,7 @@ void Solver::buildqint(Eigen::VectorXd &qint) return; //std::cout << "processing element #" << e->no << "\n"; - Eigen::VectorXd qe = e->computeqint(T1, mat->k); + Eigen::VectorXd qe = HeatTerm::build2(*e, T1, mat->k); // assembly tbb::spin_mutex::scoped_lock lock(mutex); @@ -654,7 +654,7 @@ void Solver::builds(Eigen::Map<Eigen::VectorXd> &s) //std::cout << "processing element #" << e->no << "\n"; // ** se vector => s vector - Eigen::VectorXd se = e->builds(T1, src->f); + Eigen::VectorXd se = HeatTerm::build(*e, T1, src->f); // assembly tbb::spin_mutex::scoped_lock lock(mutex); @@ -694,7 +694,7 @@ void Solver::buildq(Eigen::Map<Eigen::VectorXd> &q) //std::cout << "processing element #" << e->no << "\n"; // ** qe vector => q vector - Eigen::VectorXd qe = e->builds(T1, bnd->f); + Eigen::VectorXd qe = HeatTerm::build(*e, T1, bnd->f); // assembly tbb::spin_mutex::scoped_lock lock(mutex); diff --git a/mirrors/src/mirrors.h b/mirrors/src/mirrors.h index e2462ea35ed2eb7094ab68237f4a47b083755d1d..df88ff4147ada4b5010b8c457800924774301d20 100644 --- a/mirrors/src/mirrors.h +++ b/mirrors/src/mirrors.h @@ -46,6 +46,7 @@ class TNeumann; class TSource; class MSurface; class ANSYSSolution; +class ThermoMecaTerm; }; // namespace mirrors #endif //MIRRORS_H diff --git a/mirrors/src/wSolver.cpp b/mirrors/src/wSolver.cpp index 2038d523c6a5ff925648d764b0887f4dbd18a54f..ef21f944c25d3136485a14c69951b80b2d782b83 100644 --- a/mirrors/src/wSolver.cpp +++ b/mirrors/src/wSolver.cpp @@ -24,19 +24,14 @@ #include "wTNeumann.h" #include "wTSource.h" #include "wMSurface.h" +#include "wThermoMecaTerm.h" #include "wTag.h" #include "wMshData.h" #include "wElement.h" #include "wNode.h" #include "wANSYSSolution.h" #include <map> -#include "wTag.h" #include <math.h> -#include "wHex8.h" -#include "wQuad4.h" -#include "wTri3.h" -#include "wCacheHex8.h" -#include "wGaussHex8.h" #include "wResults.h" #include "wMshExport.h" #include "wLinearSolver.h" @@ -180,7 +175,7 @@ void Solver::start(MshExport *mshWriter) if (e->type() != ELTYPE::HEX8 && e->type() != ELTYPE::TETRA4) return; //if the element is not a tetrahedron or a hexahedron, it is not treated - Eigen::MatrixXd K_e = e->buildK_mechanical(H); + Eigen::MatrixXd K_e = ThermoMecaTerm::buildK(*e, H); for (size_t ii = 0; ii < e->nodes.size(); ++ii) { @@ -215,7 +210,7 @@ void Solver::start(MshExport *mshWriter) if (e->type() != ELTYPE::HEX8 && e->type() != ELTYPE::TETRA4) return; //if the element is not a tetrahedron or a hexahedron, it is not treated - Eigen::MatrixXd L_e = e->buildL_thermal(K_conductivity); + Eigen::MatrixXd L_e = ThermoMecaTerm::buildL(*e, K_conductivity); for (size_t ii = 0; ii < e->nodes.size(); ++ii) { @@ -255,7 +250,7 @@ void Solver::start(MshExport *mshWriter) if (e->type() != ELTYPE::HEX8 && e->type() != ELTYPE::TETRA4) return; //if the element is not a tetrahedron or a hexahedron, it is not treated - Eigen::MatrixXd S_e = e->buildS_thermomechanical(D); + Eigen::MatrixXd S_e = ThermoMecaTerm::buildS(*e, D); for (size_t ii = 0; ii < e->nodes.size(); ++ii) { @@ -300,7 +295,7 @@ void Solver::start(MshExport *mshWriter) if (e->type() != ELTYPE::HEX8 && e->type() != ELTYPE::TETRA4) continue; //if the element is not a tetrahedron or a hexahedron, it is not treated - Eigen::MatrixXd N_e = e->buildM(); + Eigen::MatrixXd N_e = ThermoMecaTerm::buildM(*e); for (size_t ii = 0; ii < e->nodes.size(); ++ii) { @@ -343,7 +338,7 @@ void Solver::start(MshExport *mshWriter) if (e->type() != ELTYPE::HEX8 && e->type() != ELTYPE::TETRA4) continue; //if the element is not a triangle or a quadrangle, it is not treated - Eigen::MatrixXd N_e = e->buildS(); + Eigen::MatrixXd N_e = ThermoMecaTerm::buildM(*e); for (size_t ii = 0; ii < e->nodes.size(); ++ii) { @@ -370,7 +365,7 @@ void Solver::start(MshExport *mshWriter) if (e->type() != ELTYPE::HEX8 && e->type() != ELTYPE::TETRA4) continue; //if the element is not a triangle or a quadrangle, it is not treated - Eigen::MatrixXd N_e = e->buildS(); + Eigen::MatrixXd N_e = ThermoMecaTerm::buildM(*e); for (size_t ii = 0; ii < e->nodes.size(); ++ii) { @@ -634,7 +629,7 @@ void Solver::start(MshExport *mshWriter) if (e->type() != ELTYPE::HEX8 && e->type() != ELTYPE::TETRA4) continue; //if the element is not a triangle or a quadrangle, it is not treated - Eigen::MatrixXd N_e = e->buildS(); + Eigen::MatrixXd N_e = ThermoMecaTerm::buildM(*e); for (size_t ii = 0; ii < e->nodes.size(); ++ii) { @@ -748,10 +743,8 @@ void Solver::start(MshExport *mshWriter) for (auto e : current_tag.elems) { - if (e->type() == ELTYPE::HEX8) - e->strain_stress(Strain, Sigma, H, u); - else if (e->type() == ELTYPE::TETRA4) - e->strain_stress(Strain, Sigma, H, u); + if (e->type() == ELTYPE::HEX8 || e->type() == ELTYPE::TETRA4) + ThermoMecaTerm::strain_stress(*e, H, u, Strain, Sigma); else continue; diff --git a/mirrors/src/wThermoMecaTerm.cpp b/mirrors/src/wThermoMecaTerm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d8a005e514e73d069390e4e06f0a6c1803aa6447 --- /dev/null +++ b/mirrors/src/wThermoMecaTerm.cpp @@ -0,0 +1,179 @@ +/* + * Copyright 2020 University of Liège + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain k copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wThermoMecaTerm.h" + +#include "wElement.h" +#include "wCache.h" +#include "wGauss.h" +#include "wMem.h" +#include "wNode.h" + +using namespace mirrors; +using namespace tbox; + +/** + * @brief Build volume/surface mass matrix for the thermo-mechanical equation on one element + */ +Eigen::MatrixXd ThermoMecaTerm::buildM(Element const &e) +{ + // Get precomputed values + Cache &cache = e.getVCache(); + Gauss &gauss = cache.getVGauss(); + Mem &mem = e.getVMem(); + + // Mass matrix + Eigen::MatrixXd M = Eigen::MatrixXd::Zero(e.nodes.size(), e.nodes.size()); + for (size_t k = 0; k < gauss.getN(); ++k) + { + // Shape functions + Eigen::VectorXd const &ff = cache.getSf(k); + M += ff * ff.transpose() * gauss.getW(k) * mem.getDetJ(k); + } + return M; +} + +/** + * @brief Build mechanical matrix for the thermo-mechanical equation on one element + */ +Eigen::MatrixXd ThermoMecaTerm::buildK(tbox::Element const &e, Eigen::MatrixXd const &H) +{ + // Get precomputed values + Cache &cache = e.getVCache(); + Gauss &gauss = cache.getVGauss(); + Mem &mem = e.getVMem(); + size_t ns = e.nodes.size(); // number of nodes + + // Meca matrix + Eigen::MatrixXd K = Eigen::MatrixXd::Zero(3 * ns, 3 * ns); // 3 dimensions + for (size_t k = 0; k < gauss.getN(); ++k) + { + // Jacobian inverse + Eigen::Matrix3d const &invJ = mem.getJinv(k); + // Fill B matrix (shape functions) + Eigen::MatrixXd const &dff = cache.getDsf(k); + Eigen::MatrixXd B = Eigen::MatrixXd::Zero(6, 3 * ns); + for (size_t i = 0; i < ns; ++i) + { + // Compute [Ni,x Ni,y, Ni_z] + Eigen::Vector3d dN = invJ * dff.col(i); + B(0, 3 * i) = dN(0); + B(1, 3 * i + 1) = dN(1); + B(2, 3 * i + 2) = dN(2); + B(3, 3 * i + 1) = dN(2); + B(3, 3 * i + 2) = dN(1); + B(4, 3 * i) = dN(2); + B(4, 3 * i + 2) = dN(0); + B(5, 3 * i) = dN(1); + B(5, 3 * i + 1) = dN(0); + } + + // Compute stiffness matrix + K += B.transpose() * H * B * gauss.getW(k) * mem.getDetJ(k); + } + return K; +} + +/** + * @brief Build thermal matrix for the thermo-mechanical equation on one element + */ +Eigen::MatrixXd ThermoMecaTerm::buildL(Element const &e, Eigen::MatrixXd const &C) +{ + // Get precomputed values + Cache &cache = e.getVCache(); + Gauss &gauss = cache.getVGauss(); + Mem &mem = e.getVMem(); + + // Thermal matrix + Eigen::MatrixXd L = Eigen::MatrixXd::Zero(e.nodes.size(), e.nodes.size()); + for (size_t k = 0; k < gauss.getN(); ++k) + { + // Jacobian + double detJ = mem.getDetJ(k); + Eigen::Matrix3d const &J = mem.getJinv(k); + Eigen::MatrixXd const &dff = cache.getDsf(k); + + // [AC] I refactored this from an entry by entry assembly to a full matrix multiplication, + // but as nothing tests this method, I could not check the results. + L += (C * J * dff).transpose() * J * dff * gauss.getW(k) * detJ; + } + return L; +} + +/** + * @brief Build thermo-mechanical matrix for the thermo-mechanical equation on one element + */ +Eigen::MatrixXd ThermoMecaTerm::buildS(Element const &e, Eigen::MatrixXd const &D) +{ + // Get precomputed values + Cache &cache = e.getVCache(); + Gauss &gauss = cache.getVGauss(); + Mem &mem = e.getVMem(); + size_t ns = e.nodes.size(); // number of nodes + + // TM matrix + Eigen::MatrixXd S = Eigen::MatrixXd::Zero(3 * ns, ns); // 3 dimensions + for (size_t k = 0; k < gauss.getN(); ++k) + { + // Jacobian and shape functions + double detJ = mem.getDetJ(k); + Eigen::Matrix3d const &J = mem.getJinv(k); + Eigen::MatrixXd const &dff = cache.getDsf(k); + + // S + for (size_t i = 0; i < ns; ++i) + S.block(i * 3, 0, 3, ns) += D * J * dff.col(i) * cache.getSf(k).transpose() * gauss.getW(k) * detJ; + } + return S; +} + +/** + * @brief Compute strain and stresses on one element + */ +void ThermoMecaTerm::strain_stress(Element const &e, Eigen::MatrixXd const &H, std::vector<double> const &u, Eigen::MatrixXd &Strain, Eigen::MatrixXd &Stress) +{ + // Get precomputed values + Cache &cache = e.getVCache(); + Gauss &gauss = cache.getVGauss(); + Mem &mem = e.getVMem(); + size_t ns = e.nodes.size(); // number of nodes + + Strain = Stress = Eigen::Matrix3d::Zero(); // 3 dimensions + Eigen::MatrixXd u_e(3, ns); + // store the solution + for (size_t i = 0; i < ns; ++i) + { + u_e(0, i) = u[3 * (e.nodes[i]->row)]; + u_e(1, i) = u[3 * (e.nodes[i]->row) + 1]; + u_e(2, i) = u[3 * (e.nodes[i]->row) + 2]; + } + for (size_t k = 0; k < gauss.getN(); ++k) + { + // Jacobian and strain + Eigen::Matrix3d const &J = mem.getJinv(k); + Eigen::MatrixXd const &dff = cache.getDsf(k); + Eigen::Matrix3d du_d_Phi = Eigen::Matrix3d::Zero(); + for (size_t i = 0; i < ns; ++i) + du_d_Phi += dff.col(i) * u_e.col(i).transpose(); + Strain += ((J * du_d_Phi) + (J * du_d_Phi).transpose()) / ns / 2; + } + // stress + for (size_t i = 0; i < 3; ++i) + for (size_t j = 0; j < 3; ++j) + for (size_t k = 0; k < 3; ++k) + for (size_t l = 0; l < 3; ++l) + Stress(i, j) += H(i * 3 + j, k * 3 + l) * Strain(k, l); +} diff --git a/mirrors/src/wThermoMecaTerm.h b/mirrors/src/wThermoMecaTerm.h new file mode 100644 index 0000000000000000000000000000000000000000..c02674b5be674cdb0958a8e9c114b57875f8a6ce --- /dev/null +++ b/mirrors/src/wThermoMecaTerm.h @@ -0,0 +1,45 @@ +/* + * Copyright 2020 University of Liège + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WTHERMOMECATERM_H +#define WTHERMOMECATERM_H + +#include "mirrors.h" + +#include <vector> +#include <Eigen/Dense> + +namespace mirrors +{ + +/** + * @brief Formulation of thermo-mechanical terms + */ +class MIRRORS_API ThermoMecaTerm +{ +public: + // Mass matrix + static Eigen::MatrixXd buildM(tbox::Element const &e); + // Thermo-mechanical matrices + static Eigen::MatrixXd buildK(tbox::Element const &e, Eigen::MatrixXd const &H); + static Eigen::MatrixXd buildL(tbox::Element const &e, Eigen::MatrixXd const &C); + static Eigen::MatrixXd buildS(tbox::Element const &e, Eigen::MatrixXd const &D); + // Strain/stress computation + static void strain_stress(tbox::Element const &e, Eigen::MatrixXd const &H, std::vector<double> const &u, Eigen::MatrixXd &Strain, Eigen::MatrixXd &Stress); +}; + +} // namespace mirrors +#endif //WTHERMOMECATERM_H diff --git a/tbox/src/wElement.cpp b/tbox/src/wElement.cpp index 303f6efad44a566e5b885c2d1c6da4d4627f5e52..aa8fba025e73710a0ced04b034a157f469686070 100644 --- a/tbox/src/wElement.cpp +++ b/tbox/src/wElement.cpp @@ -57,31 +57,8 @@ operator<<(std::ostream &out, ELTYPE const &obj) return out; } -TBOX_API std::ostream & -operator<<(std::ostream &out, MATTYPE const &obj) -{ - switch (obj) - { - case MATTYPE::MAT_K: - out << "MAT_K"; - break; - case MATTYPE::MAT_M: - out << "MAT_M"; - break; - case MATTYPE::MAT_S: - out << "MAT_S"; - break; - default: - out << "UNKNOWN-" << static_cast<int>(obj); - break; - } - return out; -} - } // namespace tbox -// ------------------------------------------------------------------------------------ - Element::Element(int n, Tag *_ptag, Tag *_etag, std::vector<Tag *> &_parts, std::vector<Node *> &nods) : wObject(), order(2), no(n), ptag(_ptag), etag(_etag), parts(_parts), @@ -96,85 +73,9 @@ Element::Element(int n, Tag *_ptag, Tag *_etag, p->elems.push_back(this); } -void Element::write(std::ostream &out) const -{ - out << type() << " #" << no << ":"; - - out << " nodes=[ "; - for (auto n : nodes) - out << "#" << n->no << ' '; - out << "]"; - - if (ptag) - out << " ptag #" << ptag->no; - if (etag) - out << " etag #" << etag->no; - if (!parts.empty()) - { - out << " parts=[ "; - for (auto p : parts) - out << "#" << p->no << ' '; - out << "]"; - } -} - -/** - * @brief Test fct - calculate K and print it - */ -void Element::buildK_test() -{ - getVMem().update(true); - std::vector<double> u; - Eigen::MatrixXd K = buildK(u, Fct0C(1.0)); - std::cout << "K=" << K << '\n'; -} - -/** - * @brief Test fct - calculate M and print it - */ -void Element::buildM_test() -{ - getVMem().update(true); - Eigen::MatrixXd M = buildM(); - std::cout << "M=" << M << '\n'; -} - -/** - * @brief Test fct - calculate S and print it - */ -void Element::buildS_test() -{ - getVMem().update(true); - Eigen::MatrixXd S = buildS(); - std::cout << "S=" << S << '\n'; -} - -/** - * @brief Test fct - calculate s and print it - */ -void Element::builds_test() -{ - getVMem().update(true); - std::vector<double> u; - Eigen::VectorXd s = builds(u, Fct0C(1.0)); - std::cout << "s=" << s << '\n'; -} - -/** - * @brief Return the values extrapolated at all the element nodes - * based on the values at Gauss points - * @authors Kim Liegeois - */ -Eigen::MatrixXd Element::gp2node(Eigen::MatrixXd &values_at_gp) +Mem &Element::getVMem() const { - Cache &cache = getVCache(); - size_t ngp = cache.getVGauss().getN(); - - Eigen::MatrixXd A(ngp, nodes.size()); - for (size_t i = 0; i < ngp; ++i) - A.row(i) = cache.getSf(i).transpose(); - - return (A.transpose() * A).inverse() * A.transpose() * values_at_gp; // nodes.size() * 18 + throw std::runtime_error("Element::getVMem not implemented\n"); } double Element::buildJ(size_t k, Eigen::MatrixXd &J, Eigen::MatrixXd &iJ) const @@ -193,37 +94,23 @@ void Element::buildGradientJ(size_t k, std::vector<double> &dDetJ) const { throw std::runtime_error("Element::buildGradientJ not implemented\n"); } -std::vector<double> Element::buildGradientV(int dim) const -{ - throw std::runtime_error("Element::buildGradientV not implemented\n"); -} -Eigen::MatrixXd Element::buildK(std::vector<double> const &u, Fct0 const &fct) -{ - throw std::runtime_error("Element::buildK not implemented\n"); -} -Eigen::MatrixXd Element::buildK(std::vector<double> const &u, Fct2 const &fct, bool fake) -{ - throw std::runtime_error("Element::buildK not implemented\n"); -} -//--------------------- -Eigen::MatrixXd Element::buildK_mechanical(Eigen::MatrixXd const &H) + +double Element::computeV() const { - throw std::runtime_error("Element::buildK_mechanical not implemented\n"); + throw std::runtime_error("Element::computeV not implemented\n"); } - -Eigen::MatrixXd Element::buildS_thermomechanical(Eigen::MatrixXd const &D) +std::vector<double> Element::buildGradientV(int dim) const { - throw std::runtime_error("Element::buildS_thermomechanical not implemented\n"); + throw std::runtime_error("Element::buildGradientV not implemented\n"); } -Eigen::MatrixXd Element::buildL_thermal(Eigen::MatrixXd const &C) +std::vector<Eigen::Vector3d> Element::computeTangents() const { - throw std::runtime_error("Element::buildL_thermial not implemented\n"); + throw std::runtime_error("Element::computeTangents not implemented\n"); } - -void Element::strain_stress(Eigen::MatrixXd &Strain, Eigen::MatrixXd &Stress, Eigen::MatrixXd const &H, std::vector<double> const &u) +std::vector<Eigen::Vector3d> Element::buildTangents(size_t k) const { - throw std::runtime_error("Element::strain_stress not implemented\n"); + throw std::runtime_error("Element::buildTangents not implemented\n"); } Eigen::Vector3d Element::normal() const @@ -235,67 +122,45 @@ std::vector<Eigen::Vector3d> Element::gradientNormal() const throw std::runtime_error("Element::gradientNormal not implemented\n"); } -std::vector<Eigen::Vector3d> Element::computeTangents() const -{ - throw std::runtime_error("Element::computeTangents not implemented\n"); -} -std::vector<Eigen::Vector3d> Element::buildTangents(size_t k) const +/** + * @brief Return the values extrapolated at all the element nodes + * based on the values at Gauss points + */ +Eigen::MatrixXd Element::gp2node(Eigen::MatrixXd &values_at_gp) const { - throw std::runtime_error("Element::buildTangents not implemented\n"); -} + Cache &cache = getVCache(); + size_t ngp = cache.getVGauss().getN(); -//--------------------- -Eigen::MatrixXd Element::buildM() -{ - throw std::runtime_error("Element::buildM not implemented\n"); -} -Eigen::MatrixXd Element::buildS() -{ - throw std::runtime_error("Element::buildS not implemented\n"); -} -Eigen::VectorXd Element::builds(std::vector<double> const &u, Fct0 const &f) -{ - throw std::runtime_error("Element::builds not implemented\n"); -} -Eigen::VectorXd Element::builds(std::vector<double> const &u, Fct1 const &f) -{ - throw std::runtime_error("Element::builds not implemented\n"); -} -Eigen::MatrixXd Element::build(MATTYPE type) -{ - throw std::runtime_error("Element::build not implemented\n"); -} -Eigen::VectorXd Element::computeGrad(std::vector<double> const &u, size_t k) const -{ - throw std::runtime_error("Element::computeGrad not implemented\n"); -} -double Element::computeGrad2(std::vector<double> const &u, size_t k) const -{ - throw std::runtime_error("Element::computeGrad2 not implemented\n"); -} -Eigen::VectorXd Element::computeqV(std::vector<double> const &u, Fct2 const &fct) -{ - throw std::runtime_error("Element::computeqV not implemented\n"); -} -Eigen::VectorXd Element::computeqint(std::vector<double> const &u, Fct2 const &fct) -{ - throw std::runtime_error("Element::computeqint not implemented\n"); -} -double Element::computeV(std::vector<double> const &u, Fct0 const &fct) -{ - throw std::runtime_error("Element::computeV not implemented\n"); -} -Eigen::MatrixXd Element::computeV(std::vector<double> const &u, Fct2 const &fct) -{ - throw std::runtime_error("Element::computeV not implemented\n"); + Eigen::MatrixXd A(ngp, nodes.size()); + for (size_t i = 0; i < ngp; ++i) + A.row(i) = cache.getSf(i).transpose(); + + return (A.transpose() * A).inverse() * A.transpose() * values_at_gp; // nodes.size() * 18 } -double Element::computeV() +Eigen::VectorXd Element::computeGradient(std::vector<double> const &u, size_t k) const { - return computeV(std::vector<double>(), Fct0C(1.0)); + throw std::runtime_error("Element::computeGradient not implemented\n"); } -Mem &Element::getVMem() const +void Element::write(std::ostream &out) const { - throw std::runtime_error("Element::getVMem not implemented\n"); + out << type() << " #" << no << ":"; + + out << " nodes=[ "; + for (auto n : nodes) + out << "#" << n->no << ' '; + out << "]"; + + if (ptag) + out << " ptag #" << ptag->no; + if (etag) + out << " etag #" << etag->no; + if (!parts.empty()) + { + out << " parts=[ "; + for (auto p : parts) + out << "#" << p->no << ' '; + out << "]"; + } } diff --git a/tbox/src/wElement.h b/tbox/src/wElement.h index 068f1bece6d8864928828750312b1d058d4bd37d..72c4dd9b92680ff801c2583ab7c8fa8ef41eeccc 100644 --- a/tbox/src/wElement.h +++ b/tbox/src/wElement.h @@ -43,16 +43,6 @@ enum class ELTYPE TBOX_API std::ostream &operator<<(std::ostream &out, ELTYPE const &obj); #endif -enum class MATTYPE -{ - MAT_K, - MAT_M, - MAT_S -}; -#ifndef SWIG -TBOX_API std::ostream &operator<<(std::ostream &out, MATTYPE const &obj); -#endif - /** * @brief Base finite element class * @authors Romain Boman, Kim Liegeois, Adrien Crovato @@ -77,48 +67,30 @@ public: return ELTYPE::UNKNOWN; } - // test functions - void buildK_test(); - void buildM_test(); - void buildS_test(); - void builds_test(); - #ifndef SWIG - virtual Eigen::MatrixXd gp2node(Eigen::MatrixXd &values_at_gp); +protected: + // Jacobian virtual double buildJ(size_t k, Eigen::MatrixXd &J, Eigen::MatrixXd &iJ) const; virtual double buildJ(size_t k) const; virtual void buildGradientJ(size_t k, std::vector<double> &dDetJ, std::vector<Eigen::MatrixXd> &dJ) const; virtual void buildGradientJ(size_t k, std::vector<double> &dDetJ) const; - virtual std::vector<double> buildGradientV(int dim) const; - //-------------------- - virtual void write(std::ostream &out) const override; - virtual Eigen::MatrixXd buildK(std::vector<double> const &u, Fct0 const &fct); - virtual Eigen::MatrixXd buildK(std::vector<double> const &u, Fct2 const &fct, bool fake); - //--------------------- - virtual Eigen::MatrixXd buildK_mechanical(Eigen::MatrixXd const &H); - virtual Eigen::MatrixXd buildS_thermomechanical(Eigen::MatrixXd const &D); - virtual Eigen::MatrixXd buildL_thermal(Eigen::MatrixXd const &C); - virtual void strain_stress(Eigen::MatrixXd &Strain, Eigen::MatrixXd &Stress, Eigen::MatrixXd const &H, std::vector<double> const &u); - virtual Eigen::Vector3d normal() const; - virtual std::vector<Eigen::Vector3d> gradientNormal() const; - virtual std::vector<Eigen::Vector3d> computeTangents() const; - virtual std::vector<Eigen::Vector3d> buildTangents(size_t k) const; - //--------------------- - virtual Eigen::MatrixXd buildM(); - virtual Eigen::MatrixXd buildS(); - virtual Eigen::VectorXd builds(std::vector<double> const &u, Fct0 const &f); - virtual Eigen::VectorXd builds(std::vector<double> const &u, Fct1 const &f); - virtual Eigen::MatrixXd build(MATTYPE type); - virtual Eigen::VectorXd computeGrad(std::vector<double> const &u, size_t k) const; - virtual double computeGrad2(std::vector<double> const &u, size_t k) const; - virtual Eigen::VectorXd computeqV(std::vector<double> const &u, Fct2 const &fct); - virtual Eigen::VectorXd computeqint(std::vector<double> const &u, Fct2 const &fct); - virtual double computeV(std::vector<double> const &u, Fct0 const &fct); - virtual Eigen::MatrixXd computeV(std::vector<double> const &u, Fct2 const &fct); - virtual double computeV(); +public: + // Getters virtual Cache &getVCache() const = 0; virtual Mem &getVMem() const; + // Volume (@todo private) + virtual double computeV() const; + virtual std::vector<double> buildGradientV(int dim) const; + // Tangent and normal vectors (@todo private) + virtual std::vector<Eigen::Vector3d> computeTangents() const; + virtual std::vector<Eigen::Vector3d> buildTangents(size_t k) const; + virtual Eigen::Vector3d normal() const; + virtual std::vector<Eigen::Vector3d> gradientNormal() const; + // Utilities + virtual Eigen::VectorXd computeGradient(std::vector<double> const &u, size_t k) const; + virtual Eigen::MatrixXd gp2node(Eigen::MatrixXd &values_at_gp) const; + virtual void write(std::ostream &out) const override; #endif }; diff --git a/tbox/src/wFct2.cpp b/tbox/src/wFct2.cpp index 4b83977ab0b2b536087ca74f0f56d235a52e08d1..2bf6ac7adb8454b9a666494f23b02a375b73fa31 100644 --- a/tbox/src/wFct2.cpp +++ b/tbox/src/wFct2.cpp @@ -106,7 +106,7 @@ void Fct2UdU::eval(Element const &e, upg += ff(i) * u[e.nodes[i]->row]; //gradU au pg => gradupg - Eigen::VectorXd gradupg = e.computeGrad(u, k); + Eigen::VectorXd gradupg = e.computeGradient(u, k); this->eval(e, k, upg, gradupg, out, fake); } diff --git a/tbox/src/wHex8.cpp b/tbox/src/wHex8.cpp index da1332f572e05d3ca27238dc4604c04b581ce29a..ae4c523af2c6a7ad95f3fa13b3667711ec455eac 100644 --- a/tbox/src/wHex8.cpp +++ b/tbox/src/wHex8.cpp @@ -20,7 +20,6 @@ #include "wCacheHex8.h" #include "wMemHex8.h" #include "wNode.h" -#include "wFct0.h" using namespace tbox; @@ -70,179 +69,9 @@ double Hex8::buildJ(size_t k, Eigen::MatrixXd &J, Eigen::MatrixXd &iJ) const } /** - * @brief Compute stiffness matrix for scalar field - * - * K_ij(8,8) = int f*dN_j*dN_i dV - */ -Eigen::MatrixXd Hex8::buildK(std::vector<double> const &u, Fct0 const &fct) -{ - CacheHex8 &cache = getCache(order); - GaussHex8 &gauss = cache.gauss; - MemHex8 &mem = getMem(); - - // Gauss integration - Eigen::MatrixXd K = Eigen::Matrix<double, 8, 8>::Zero(); - for (size_t k = 0; k < gauss.getN(); ++k) - { - // Jacobian inverse and shape functions - Eigen::Matrix3d const &J = mem.getJinv(k); - Eigen::MatrixXd const &dff = cache.getDsf(k); - - // Elementary stiffness matrix - K += (J * dff).transpose() * J * dff * fct.eval(*this, u, k) * gauss.getW(k) * mem.getDetJ(k); - } - return K; -} - -/** - * @brief Compute linear elasticity stiffness matrix - * - * K_ij(24,24) = int eps_k H_ijkl eps_l dV = B(24,6)H(6,6)B(6,24) - */ -Eigen::MatrixXd Hex8::buildK_mechanical(Eigen::MatrixXd const &H) -{ - CacheHex8 &cache = getCache(order); - GaussHex8 &gauss = cache.gauss; - MemHex8 &mem = getMem(); - - Eigen::MatrixXd K = Eigen::MatrixXd::Zero(24, 24); - for (size_t k = 0; k < gauss.getN(); ++k) - { - // Jacobian inverse - Eigen::Matrix3d const &invJ = mem.getJinv(k); - // Fill B matrix (shape functions) - Eigen::MatrixXd const &dff = cache.getDsf(k); - Eigen::MatrixXd B = Eigen::MatrixXd::Zero(6, 3 * nodes.size()); - for (size_t i = 0; i < nodes.size(); ++i) - { - // Compute [Ni,x Ni,y, Ni_z] - Eigen::Vector3d dN = invJ * dff.col(i); - B(0, 3 * i) = dN(0); - B(1, 3 * i + 1) = dN(1); - B(2, 3 * i + 2) = dN(2); - B(3, 3 * i + 1) = dN(2); - B(3, 3 * i + 2) = dN(1); - B(4, 3 * i) = dN(2); - B(4, 3 * i + 2) = dN(0); - B(5, 3 * i) = dN(1); - B(5, 3 * i + 1) = dN(0); - } - - // Compute stiffness matrix - K += B.transpose() * H * B * gauss.getW(k) * mem.getDetJ(k); - } - return K; -} - -/** - * @brief Compute thermomecanical matrix - */ -Eigen::MatrixXd Hex8::buildS_thermomechanical(Eigen::MatrixXd const &D) -{ - CacheHex8 &cache = getCache(order); - GaussHex8 &gauss = cache.gauss; - MemHex8 &mem = getMem(); - - Eigen::MatrixXd S_e = Eigen::MatrixXd::Zero(24, 8); - for (size_t a = 0; a < gauss.getN(); ++a) - { - // Jacobian and shape functions - double detJ = mem.getDetJ(a); - Eigen::Matrix3d const &J = mem.getJinv(a); - Eigen::MatrixXd const &dff = cache.getDsf(a); - - // S - for (size_t i = 0; i < nodes.size(); ++i) - S_e.block(i * 3, 0, 3, nodes.size()) += D * J * dff.col(i) * cache.getSf(a).transpose() * gauss.getW(a) * detJ; - } - return S_e; -} - -/** - * @brief Compute thermal matrix + * @brief Compute the element volume */ -Eigen::MatrixXd Hex8::buildL_thermal(Eigen::MatrixXd const &C) -{ - CacheHex8 &cache = getCache(order); - GaussHex8 &gauss = cache.gauss; - MemHex8 &mem = getMem(); - - // Gauss integration - Eigen::MatrixXd L_e = Eigen::Matrix<double, 8, 8>::Zero(); - for (size_t a = 0; a < gauss.getN(); ++a) - { - // Jacobian - double detJ = mem.getDetJ(a); - Eigen::Matrix3d const &J = mem.getJinv(a); - Eigen::MatrixXd const &dff = cache.getDsf(a); - - // [AC] I refactored this from an entry by entry assembly to a full matrix multiplication, - // but as nothing tests this method, I could not check the results. - L_e += (C * J * dff).transpose() * J * dff * gauss.getW(a) * detJ; - } - return L_e; -} - -void Hex8::strain_stress(Eigen::MatrixXd &Strain, Eigen::MatrixXd &Stress, Eigen::MatrixXd const &H, std::vector<double> const &u) -{ - CacheHex8 &cache = getCache(order); - GaussHex8 &gauss = cache.gauss; - MemHex8 &mem = getMem(); - - Strain = Stress = Eigen::Matrix3d::Zero(); - Eigen::MatrixXd u_e(3, nodes.size()); - for (size_t i = 0; i < nodes.size(); ++i) - { - u_e(0, i) = u[3 * (nodes[i]->row)]; - u_e(1, i) = u[3 * (nodes[i]->row) + 1]; - u_e(2, i) = u[3 * (nodes[i]->row) + 2]; - } - for (size_t a = 0; a < gauss.getN(); ++a) - { - // Jacobian and strain - Eigen::Matrix3d const &J = mem.getJinv(a); - Eigen::MatrixXd const &dff = cache.getDsf(a); - Eigen::Matrix3d du_d_Phi = Eigen::Matrix3d::Zero(); - for (size_t i = 0; i < nodes.size(); ++i) - du_d_Phi += dff.col(i) * u_e.col(i).transpose(); - Strain += ((J * du_d_Phi) + (J * du_d_Phi).transpose()) / nodes.size() / 2; - } - // stress - for (size_t i = 0; i < 3; ++i) - for (size_t j = 0; j < 3; ++j) - for (size_t k = 0; k < 3; ++k) - for (size_t l = 0; l < 3; ++l) - Stress(i, j) += H(i * 3 + j, k * 3 + l) * Strain(k, l); -} - -/** - * @brief Compute mass matrix - * - * M_ij(8,8) = int N_i*N_j dV - */ -Eigen::MatrixXd Hex8::buildM() -{ - CacheHex8 &cache = getCache(order); - GaussHex8 &gauss = cache.gauss; - MemHex8 &mem = getMem(); - - // Gauss integration - Eigen::MatrixXd M = Eigen::Matrix<double, 8, 8>::Zero(); - for (size_t k = 0; k < gauss.getN(); ++k) - { - // Shape functions - Eigen::VectorXd const &ff = cache.getSf(k); - M += ff * ff.transpose() * gauss.getW(k) * mem.getDetJ(k); - } - return M; -} - -/** - * @brief Compute intergal of scalar function - * - * I = int f dV - */ -double Hex8::computeV(std::vector<double> const &u, Fct0 const &fct) +double Hex8::computeV() const { CacheHex8 &cache = getCache(order); GaussHex8 &gauss = cache.gauss; @@ -251,14 +80,6 @@ double Hex8::computeV(std::vector<double> const &u, Fct0 const &fct) // Gauss integration double V = 0.0; for (size_t k = 0; k < gauss.getN(); ++k) - V += fct.eval(*this, u, k) * gauss.getW(k) * mem.getDetJ(k); + V += gauss.getW(k) * mem.getDetJ(k); return V; } - -/** - * @brief Return the element volume - */ -double Hex8::computeV() -{ - return getMem().getVol(); -} diff --git a/tbox/src/wHex8.h b/tbox/src/wHex8.h index 1c563df033a1ca4381e156159434978d06f87461..bf39aaa5123a926d59a7182cb9d8da7b329b0a32 100644 --- a/tbox/src/wHex8.h +++ b/tbox/src/wHex8.h @@ -33,21 +33,17 @@ class TBOX_API Hex8 : public Element { #ifndef SWIG friend class MemHex8; + +private: MemHex8 *pmem; ///< private memory of precalculated values inline static CacheHex8 &getCache(int n); inline MemHex8 &getMem() const; - virtual double buildJ(size_t k, Eigen::MatrixXd &J, Eigen::MatrixXd &iJ) const override; - virtual Eigen::MatrixXd buildK(std::vector<double> const &u, Fct0 const &fct) override; - virtual Eigen::MatrixXd buildM() override; - virtual Eigen::MatrixXd buildK_mechanical(Eigen::MatrixXd const &H) override; - virtual Eigen::MatrixXd buildS_thermomechanical(Eigen::MatrixXd const &D) override; - virtual Eigen::MatrixXd buildL_thermal(Eigen::MatrixXd const &C) override; - - virtual void strain_stress(Eigen::MatrixXd &Strain, Eigen::MatrixXd &Stress, Eigen::MatrixXd const &H, std::vector<double> const &u) override; +protected: + virtual double buildJ(size_t k, Eigen::MatrixXd &J, Eigen::MatrixXd &iJ) const override; - virtual double computeV(std::vector<double> const &u, Fct0 const &fct) override; - virtual double computeV() override; +public: // @todo + virtual double computeV() const override; #endif public: diff --git a/tbox/src/wLine2.cpp b/tbox/src/wLine2.cpp index 9e34ca2267eda0fc1777103aa84a6d80b1f8db93..85dce33b026da3146b4f99bda70d84fd5bd29a1d 100644 --- a/tbox/src/wLine2.cpp +++ b/tbox/src/wLine2.cpp @@ -20,8 +20,6 @@ #include "wCacheLine2.h" #include "wMemLine2.h" #include "wNode.h" -#include "wFct0.h" -#include "wFct1.h" using namespace tbox; @@ -52,59 +50,6 @@ Cache &Line2::getVCache() const return getCache(order); } -/** - * @brief Compute element tangent vectors - */ -std::vector<Eigen::Vector3d> Line2::computeTangents() const -{ - return std::vector<Eigen::Vector3d>{nodes[1]->pos - nodes[0]->pos}; -} - -/** - * @brief Build element tangent vectors using shape functions at Gauss point k - */ -std::vector<Eigen::Vector3d> Line2::buildTangents(size_t k) const -{ - Eigen::MatrixXd const &dff = getCache(order).getDsf(k); - - std::vector<Eigen::Vector3d> t(1, Eigen::Vector3d::Zero()); - size_t i = 0; - for (auto it = nodes.begin(); it != nodes.end(); ++it, ++i) - { - t[0] += (*it)->pos * dff(0, i); - } - return t; -} - -/** - * @brief Compute element unit normal vector - */ -Eigen::Vector3d Line2::normal() const -{ - Eigen::Vector3d t = this->computeTangents()[0].normalized(); - return Eigen::Vector3d(-t(1), t(0), 0.); -} - -/** - * @brief Compute gradient of element unit normal vector with respect to each node coordinate - */ -std::vector<Eigen::Vector3d> Line2::gradientNormal() const -{ - // Compute normal and norm - Eigen::Vector3d t = this->computeTangents()[0]; - Eigen::Vector3d n = Eigen::Vector3d(-t(1), t(0), 0.); - double nn = n.norm(); - - // Compute gradients - Eigen::Matrix3d inn = (Eigen::Matrix3d::Identity() - n * n.transpose() / (nn * nn)) / nn; // gradient of n/|n| - std::vector<Eigen::Vector3d> dn(2 * 2); // 2 nodes and 2 dimensions - dn[0] = inn * Eigen::Vector3d(0, -1, 0); - dn[1] = inn * Eigen::Vector3d(1, 0, 0); - dn[2] = inn * Eigen::Vector3d(0, 1, 0); - dn[3] = inn * Eigen::Vector3d(-1, 0, 0); // outer gradient times gradient of t (pos) wtr x - return dn; -} - /** * @brief Compute Jacobian determinant at Gauss point k * @@ -141,7 +86,22 @@ void Line2::buildGradientJ(size_t k, std::vector<double> &dDetJ) const } /** - * @brief Compute volume gradient with respect to each node coordinate + * @brief Compute the element length + */ +double Line2::computeV() const +{ + CacheLine2 &cache = getCache(order); + GaussLine2 &gauss = cache.gauss; + MemLine2 &mem = getMem(); + + // Gauss integration + double V = 0.0; + for (size_t k = 0; k < gauss.getN(); ++k) + V += gauss.getW(k) * mem.getDetJ(k); + return V; +} +/** + * @brief Compute length gradient with respect to each node coordinate * * dV[i] = w_k * dDetJ[i]_k */ @@ -163,74 +123,54 @@ std::vector<double> Line2::buildGradientV(int dim) const } /** - * @brief Compute flux vector - * - * s_i(2) = int f * N_i dV + * @brief Compute element tangent vectors */ -Eigen::VectorXd Line2::builds(std::vector<double> const &u, Fct0 const &f) +std::vector<Eigen::Vector3d> Line2::computeTangents() const { - CacheLine2 &cache = getCache(order); - GaussLine2 &gauss = cache.gauss; - MemLine2 &mem = getMem(); - - // Gauss integration - Eigen::VectorXd s = Eigen::Vector2d::Zero(); - for (size_t k = 0; k < gauss.getN(); ++k) - s += cache.getSf(k) * f.eval(*this, u, k) * gauss.getW(k) * mem.getDetJ(k); - return s; + return std::vector<Eigen::Vector3d>{nodes[1]->pos - nodes[0]->pos}; } /** - * @brief Compute flux vector - * - * s_i(2) = int f_j*n_j * N_i dV + * @brief Build element tangent vectors using shape functions at Gauss point k */ -Eigen::VectorXd Line2::builds(std::vector<double> const &u, Fct1 const &f) +std::vector<Eigen::Vector3d> Line2::buildTangents(size_t k) const { - CacheLine2 &cache = getCache(order); - GaussLine2 &gauss = cache.gauss; - MemLine2 &mem = getMem(); + Eigen::MatrixXd const &dff = getCache(order).getDsf(k); - // Gauss integration - Eigen::VectorXd s = Eigen::Vector2d::Zero(); - for (size_t k = 0; k < gauss.getN(); ++k) - s += cache.getSf(k) * (f.eval(*this, u, k).dot(normal())) * gauss.getW(k) * mem.getDetJ(k); - return s; + std::vector<Eigen::Vector3d> t(1, Eigen::Vector3d::Zero()); + size_t i = 0; + for (auto it = nodes.begin(); it != nodes.end(); ++it, ++i) + { + t[0] += (*it)->pos * dff(0, i); + } + return t; } /** - * @brief Compute square of gradient along element - * - * grad = (Delta_U / Delta_L)^2 + * @brief Compute element unit normal vector */ -double Line2::computeGrad2(std::vector<double> const &u, size_t k) const +Eigen::Vector3d Line2::normal() const { - double dUdL = (u[nodes[1]->row] - u[nodes[0]->row]) / getMem().getVol(); // V = length of the element - return dUdL * dUdL; + Eigen::Vector3d t = this->computeTangents()[0].normalized(); + return Eigen::Vector3d(-t(1), t(0), 0.); } /** - * @brief Compute intergal of scalar function - * - * I = int f dV + * @brief Compute gradient of element unit normal vector with respect to each node coordinate */ -double Line2::computeV(std::vector<double> const &u, Fct0 const &fct) +std::vector<Eigen::Vector3d> Line2::gradientNormal() const { - CacheLine2 &cache = getCache(order); - GaussLine2 &gauss = cache.gauss; - MemLine2 &mem = getMem(); - - // Gauss integration - double V = 0.0; - for (size_t k = 0; k < gauss.getN(); ++k) - V += fct.eval(*this, u, k) * gauss.getW(k) * mem.getDetJ(k); - return V; -} + // Compute normal and norm + Eigen::Vector3d t = this->computeTangents()[0]; + Eigen::Vector3d n = Eigen::Vector3d(-t(1), t(0), 0.); + double nn = n.norm(); -/** - * @brief Return the element length - */ -double Line2::computeV() -{ - return getMem().getVol(); + // Compute gradients + Eigen::Matrix3d inn = (Eigen::Matrix3d::Identity() - n * n.transpose() / (nn * nn)) / nn; // gradient of n/|n| + std::vector<Eigen::Vector3d> dn(2 * 2); // 2 nodes and 2 dimensions + dn[0] = inn * Eigen::Vector3d(0, -1, 0); + dn[1] = inn * Eigen::Vector3d(1, 0, 0); + dn[2] = inn * Eigen::Vector3d(0, 1, 0); + dn[3] = inn * Eigen::Vector3d(-1, 0, 0); // outer gradient times gradient of t (pos) wtr x + return dn; } diff --git a/tbox/src/wLine2.h b/tbox/src/wLine2.h index 4e033f3e3e902153a0012ea4098c4a47f1a2a9cf..9e6e5f0de9dc05c7a676de610640515aec8b1baa 100644 --- a/tbox/src/wLine2.h +++ b/tbox/src/wLine2.h @@ -33,20 +33,21 @@ class TBOX_API Line2 : public Element { #ifndef SWIG friend class MemLine2; + +private: MemLine2 *pmem; ///< private memory of precalculated values inline MemLine2 &getMem() const; inline static CacheLine2 &getCache(int n); + +protected: virtual double buildJ(size_t k) const override; virtual void buildGradientJ(size_t k, std::vector<double> &dDetJ) const override; - virtual std::vector<double> buildGradientV(int dim) const override; - - virtual Eigen::VectorXd builds(std::vector<double> const &u, Fct0 const &f) override; - virtual Eigen::VectorXd builds(std::vector<double> const &u, Fct1 const &f) override; - - virtual double computeGrad2(std::vector<double> const &u, size_t k) const override; - virtual double computeV(std::vector<double> const &u, Fct0 const &fct) override; - virtual double computeV() override; +public: // @todo + virtual double computeV() const override; + virtual std::vector<double> buildGradientV(int dim) const override; + virtual Eigen::Vector3d normal() const override; + virtual std::vector<Eigen::Vector3d> gradientNormal() const override; virtual std::vector<Eigen::Vector3d> computeTangents() const override; virtual std::vector<Eigen::Vector3d> buildTangents(size_t k) const override; #endif @@ -59,8 +60,6 @@ public: #ifndef SWIG virtual Mem &getVMem() const override; virtual Cache &getVCache() const override; - virtual Eigen::Vector3d normal() const override; - virtual std::vector<Eigen::Vector3d> gradientNormal() const override; #endif }; diff --git a/tbox/src/wMemHex8.cpp b/tbox/src/wMemHex8.cpp index aa8398b478c62edfa7b3d58dd50e9a0e0f444744..c815f2025241d25ffaf9c35f40d079999f1c0fdd 100644 --- a/tbox/src/wMemHex8.cpp +++ b/tbox/src/wMemHex8.cpp @@ -44,7 +44,7 @@ void MemHex8::update(bool sameDim) cg /= e.nodes.size(); // Memory is now valid and the volume can be computed valid = true; - vol = e.Element::computeV(); + vol = e.computeV(); // Update gradient if they are needed if (validG) diff --git a/tbox/src/wMemLine2.cpp b/tbox/src/wMemLine2.cpp index 074a6bc6e5b619427bf3978ba19de9a9fc0557b4..8e0c8022ec509f26c9e55bb14802cbb62368c011 100644 --- a/tbox/src/wMemLine2.cpp +++ b/tbox/src/wMemLine2.cpp @@ -41,7 +41,7 @@ void MemLine2::update(bool sameDim) cg /= e.nodes.size(); // Memory is now valid and the volume can be computed valid = true; - vol = e.Element::computeV(); + vol = e.computeV(); // Update gradient if they are needed if (validG) diff --git a/tbox/src/wMemQuad4.cpp b/tbox/src/wMemQuad4.cpp index ad205b1844451cbf14a53c739464d207fbcc8240..50ee3b51eeb5e3fceed1e16ac27ccf2f6e4b2b63 100644 --- a/tbox/src/wMemQuad4.cpp +++ b/tbox/src/wMemQuad4.cpp @@ -51,7 +51,7 @@ void MemQuad4::update(bool sameDim) cg /= e.nodes.size(); // Memory is now valid and the volume can be computed valid = true; - vol = e.Element::computeV(); + vol = e.computeV(); // Update gradient if they are needed if (validG) diff --git a/tbox/src/wMemTetra4.cpp b/tbox/src/wMemTetra4.cpp index 349ca6498ffd7a64d7f5ba5904f317242b8c6991..5be98b0c5ab2aeccd9dd2b28ad58899c27588df2 100644 --- a/tbox/src/wMemTetra4.cpp +++ b/tbox/src/wMemTetra4.cpp @@ -44,7 +44,7 @@ void MemTetra4::update(bool sameDim) cg /= e.nodes.size(); // Memory is now valid and the volume can be computed valid = true; - vol = e.Element::computeV(); + vol = e.computeV(); // Update gradient if they are needed if (validG) diff --git a/tbox/src/wMemTri3.cpp b/tbox/src/wMemTri3.cpp index 4f10a2b806c26c428ead252a1b7ae4eee49aca05..707e7d55838171ad620a1c20f85f5f1b7547aaaf 100644 --- a/tbox/src/wMemTri3.cpp +++ b/tbox/src/wMemTri3.cpp @@ -51,7 +51,7 @@ void MemTri3::update(bool sameDim) cg /= e.nodes.size(); // Memory is now valid and the volume can be computed valid = true; - vol = e.Element::computeV(); + vol = e.computeV(); // Update gradient if they are needed if (validG) diff --git a/tbox/src/wMshDeform.cpp b/tbox/src/wMshDeform.cpp index dd87d8eddd6c32ef9d5e5aab8fe74faba7ed5d86..6eacfebaa80367dea2cc0be5c5976513f3141a54 100644 --- a/tbox/src/wMshDeform.cpp +++ b/tbox/src/wMshDeform.cpp @@ -21,6 +21,8 @@ #include "wTag.h" #include "wNode.h" #include "wElement.h" +#include "wCache.h" +#include "wGauss.h" #include "wMem.h" #include "wGmres.h" @@ -227,6 +229,68 @@ void MshDeform::savePos() initPos[nDim * i + m] = movBndNodes[i]->pos(m); } +/** + * @brief Compute mechanical stiffness matrix for one element + * + * K_ij(6,6) = int eps_k H_ijkl eps_l dV = B(6,3)H(3,3)B(3,6) + * K_ij(12,12) = int eps_k H_ijkl eps_l dV = B(12,6)H(6,6)B(6,12) + * @todo should be in a dedicated static class + */ +Eigen::MatrixXd MshDeform::buildK(tbox::Element const &e, Eigen::MatrixXd const &H) +{ + // Get precomputed values + Cache &cache = e.getVCache(); + Gauss &gauss = cache.getVGauss(); + Mem &mem = e.getVMem(); + size_t ns = e.nodes.size(); // number of nodes + + // Elementary stiffness matrix + Eigen::MatrixXd K = Eigen::MatrixXd::Zero(nDim * ns, nDim * ns); + for (size_t k = 0; k < gauss.getN(); ++k) + { + // Jacobian inverse + Eigen::MatrixXd const &iJ = mem.getJinv(k); + // Fill B matrix (shape functions) + Eigen::MatrixXd const &dff = cache.getDsf(k); + Eigen::MatrixXd B; + if (nDim == 2) + { + B = Eigen::MatrixXd::Zero(3, 2 * ns); + for (size_t i = 0; i < ns; ++i) + { + // Compute [Ni,x Ni,y] + Eigen::VectorXd dN = iJ * dff.col(i); + B(0, 2 * i) = dN(0); + B(1, 2 * i + 1) = dN(1); + B(2, 2 * i + 1) = dN(0); + B(2, 2 * i) = dN(1); + } + } + else + { + B = Eigen::MatrixXd::Zero(6, 3 * ns); + for (size_t i = 0; i < ns; ++i) + { + // Compute [Ni,x Ni,y Ni,z] + Eigen::VectorXd dN = iJ * dff.col(i); + B(0, 3 * i) = dN(0); + B(1, 3 * i + 1) = dN(1); + B(2, 3 * i + 2) = dN(2); + B(3, 3 * i + 1) = dN(2); + B(3, 3 * i + 2) = dN(1); + B(4, 3 * i) = dN(2); + B(4, 3 * i + 2) = dN(0); + B(5, 3 * i) = dN(1); + B(5, 3 * i + 1) = dN(0); + } + } + + // Compute stiffness matrix + K += B.transpose() * H * B * gauss.getW(k) * mem.getDetJ(k); + } + return K; +} + /** * @brief Build the mesh deformation matrix using linear elasticity law * @@ -280,7 +344,7 @@ void MshDeform::build(Eigen::SparseMatrix<double, Eigen::RowMajor> &K) } // Elementary stiffness matrix - Eigen::MatrixXd Ke = e->buildK_mechanical(H); + Eigen::MatrixXd Ke = this->buildK(*e, H); // Assembly // tbb::spin_mutex::scoped_lock lock(mutex); diff --git a/tbox/src/wMshDeform.h b/tbox/src/wMshDeform.h index a4a30036d1a649c1165eeed91413c01a7a9f21e3..4547383ae817b8c326fcbcbdbd7301c2ec2e2f76 100644 --- a/tbox/src/wMshDeform.h +++ b/tbox/src/wMshDeform.h @@ -58,6 +58,7 @@ private: std::vector<double> initPos; ///< initial positions of nodes before mesh deformation void uniqueSort(std::vector<Node *> &nodes); + Eigen::MatrixXd buildK(tbox::Element const &e, Eigen::MatrixXd const &H); public: std::shared_ptr<MshData> msh; diff --git a/tbox/src/wQuad4.cpp b/tbox/src/wQuad4.cpp index c44ab416db48fcde6b60c8115a704aa32c25b04e..d3981e8b5325e0dfd4b6b50447a65b2de5ae17fa 100644 --- a/tbox/src/wQuad4.cpp +++ b/tbox/src/wQuad4.cpp @@ -20,7 +20,6 @@ #include "wCacheQuad4.h" #include "wMemQuad4.h" #include "wNode.h" -#include "wFct0.h" using namespace tbox; @@ -51,44 +50,6 @@ Cache &Quad4::getVCache() const return getCache(order); } -/** - * @brief Compute element tangent vectors - */ -std::vector<Eigen::Vector3d> Quad4::computeTangents() const -{ - Eigen::Vector3d x1 = nodes[0]->pos; - Eigen::Vector3d x3 = nodes[2]->pos; - Eigen::Vector3d x4 = nodes[3]->pos; - - return std::vector<Eigen::Vector3d>{(x3 - x1), (x4 - x1)}; -} - -/** - * @brief Build element tangent vectors using shape functions at Gauss point k - */ -std::vector<Eigen::Vector3d> Quad4::buildTangents(size_t k) const -{ - Eigen::MatrixXd const &dff = getCache(order).getDsf(k); - - std::vector<Eigen::Vector3d> t(2, Eigen::Vector3d::Zero()); - size_t i = 0; - for (auto it = nodes.begin(); it != nodes.end(); ++it, ++i) - { - t[0] += (*it)->pos * dff(0, i); - t[1] += (*it)->pos * dff(1, i); - } - return t; -} - -/** - * @brief Compute element unit normal vector - */ -Eigen::Vector3d Quad4::normal() const -{ - std::vector<Eigen::Vector3d> ts = this->computeTangents(); - return ts[0].cross(ts[1]).normalized(); -} - /** * @brief Compute Jacobian determinant at Gauss point k * @@ -118,68 +79,55 @@ double Quad4::buildJ(size_t k, Eigen::MatrixXd &J, Eigen::MatrixXd &iJ) const } /** - * @brief Compute mass matrix - * - * S_ij(4,4) = int N_i*N_j dV + * @brief Return the element surface */ -Eigen::MatrixXd Quad4::buildS() +double Quad4::computeV() const { CacheQuad4 &cache = getCache(order); GaussQuad4 &gauss = cache.gauss; MemQuad4 &mem = getMem(); // Gauss integration - Eigen::MatrixXd S = Eigen::Matrix4d::Zero(); + double V = 0.0; for (size_t k = 0; k < gauss.getN(); ++k) - { - // Shape functions - Eigen::VectorXd const &ff = cache.getSf(k); - - // Mass matrix - S += ff * ff.transpose() * gauss.getW(k) * mem.getDetJ(k); - } - return S; + V += gauss.getW(k) * mem.getDetJ(k); + return V; } /** - * @brief API for build methods + * @brief Compute element tangent vectors */ -Eigen::MatrixXd Quad4::build(MATTYPE type) +std::vector<Eigen::Vector3d> Quad4::computeTangents() const { - switch (type) - { - case MATTYPE::MAT_S: - return buildS(); - break; - default: - std::stringstream out; - out << "Quad4 cannot build " << type; - throw std::runtime_error(out.str()); - } + Eigen::Vector3d x1 = nodes[0]->pos; + Eigen::Vector3d x3 = nodes[2]->pos; + Eigen::Vector3d x4 = nodes[3]->pos; + + return std::vector<Eigen::Vector3d>{(x3 - x1), (x4 - x1)}; } /** - * @brief Compute intergal of scalar function - * - * I = int f dV + * @brief Build element tangent vectors using shape functions at Gauss point k */ -double Quad4::computeV(std::vector<double> const &u, Fct0 const &fct) +std::vector<Eigen::Vector3d> Quad4::buildTangents(size_t k) const { - CacheQuad4 &cache = getCache(order); - GaussQuad4 &gauss = cache.gauss; - MemQuad4 &mem = getMem(); + Eigen::MatrixXd const &dff = getCache(order).getDsf(k); - // Gauss integration - double V = 0.0; - for (size_t k = 0; k < gauss.getN(); ++k) - V += fct.eval(*this, u, k) * gauss.getW(k) * mem.getDetJ(k); - return V; + std::vector<Eigen::Vector3d> t(2, Eigen::Vector3d::Zero()); + size_t i = 0; + for (auto it = nodes.begin(); it != nodes.end(); ++it, ++i) + { + t[0] += (*it)->pos * dff(0, i); + t[1] += (*it)->pos * dff(1, i); + } + return t; } /** - * @brief Return the element surface + * @brief Compute element unit normal vector */ -double Quad4::computeV() +Eigen::Vector3d Quad4::normal() const { - return getMem().getVol(); -} \ No newline at end of file + std::vector<Eigen::Vector3d> ts = this->computeTangents(); + return ts[0].cross(ts[1]).normalized(); +} diff --git a/tbox/src/wQuad4.h b/tbox/src/wQuad4.h index fa8d1060fc08d652b1df520a6d46ce4e9c37f2f0..0e3975b50c0d2323a7bb2f1c2bde585bc747c375 100644 --- a/tbox/src/wQuad4.h +++ b/tbox/src/wQuad4.h @@ -33,20 +33,21 @@ class TBOX_API Quad4 : public Element { #ifndef SWIG friend class MemQuad4; + +private: MemQuad4 *pmem; ///< private memory of precalculated values inline static CacheQuad4 &getCache(int n); inline MemQuad4 &getMem() const; + +protected: virtual double buildJ(size_t k, Eigen::MatrixXd &J, Eigen::MatrixXd &iJ) const override; virtual double buildJ(size_t k) const override; - virtual Eigen::MatrixXd build(MATTYPE type) override; - virtual Eigen::MatrixXd buildS() override; - - virtual double computeV(std::vector<double> const &u, Fct0 const &fct) override; - virtual double computeV() override; - +public: // @todo + virtual double computeV() const override; virtual std::vector<Eigen::Vector3d> computeTangents() const override; virtual std::vector<Eigen::Vector3d> buildTangents(size_t k) const override; + virtual Eigen::Vector3d normal() const override; #endif public: @@ -57,7 +58,6 @@ public: #ifndef SWIG virtual Cache &getVCache() const override; virtual Mem &getVMem() const override; - virtual Eigen::Vector3d normal() const override; #endif }; diff --git a/tbox/src/wTetra4.cpp b/tbox/src/wTetra4.cpp index e488be5814bee278b29ed023bd3b1f6afbd2e811..e7b8e5e3716cb6209013558bcc63c23cbd2b460a 100644 --- a/tbox/src/wTetra4.cpp +++ b/tbox/src/wTetra4.cpp @@ -20,7 +20,6 @@ #include "wCacheTetra4.h" #include "wMemTetra4.h" #include "wNode.h" -#include "wFct0.h" using namespace tbox; @@ -96,204 +95,48 @@ void Tetra4::buildGradientJ(size_t k, std::vector<double> &dDetJ, std::vector<Ei for (size_t i = 0; i < dDetJ.size(); ++i) dDetJ[i] = detJ * (iJ * dJ[i]).trace(); } -/** - * @brief Compute volume gradient with respect to each node coordinate - * - * dV[i] = w_k * dDetJ[i]_k - */ -std::vector<double> Tetra4::buildGradientV(int dim) const -{ - GaussTetra4 &gauss = getCache(order).gauss; - MemTetra4 &mem = getMem(); - - // Gradient of volume - std::vector<double> dVol(4 * dim, 0.); // 4 nodes - for (size_t k = 0; k < gauss.getN(); ++k) - { - double w = gauss.getW(k); // GP weight - std::vector<double> dDetJ = mem.getGradDetJ(k); // gradient of Jacobian determinant - for (size_t i = 0; i < dDetJ.size(); ++i) - dVol[i] += w * dDetJ[i]; - } - return dVol; -} /** - * @brief Compute mass matrix - * - * M_ij(4,4) = int N_i*N_j dV - */ -Eigen::MatrixXd Tetra4::buildM() -{ - CacheTetra4 &cache = getCache(order); - GaussTetra4 &gauss = cache.gauss; - MemTetra4 &mem = getMem(); - - // Gauss integration - Eigen::MatrixXd M = Eigen::Matrix4d::Zero(); - for (size_t k = 0; k < gauss.getN(); ++k) - { - // Shape functions - Eigen::VectorXd const &ff = cache.getSf(k); - M += ff * ff.transpose() * gauss.getW(k) * mem.getDetJ(k); - } - return M; -} - -/** - * @brief Compute stiffness matrix for scalar field - * - * K_ij(4,4) = int f*dN_j*dN_i dV + * @brief Return the element volume */ -Eigen::MatrixXd Tetra4::buildK(std::vector<double> const &u, Fct0 const &fct) +double Tetra4::computeV() const { CacheTetra4 &cache = getCache(order); GaussTetra4 &gauss = cache.gauss; MemTetra4 &mem = getMem(); // Gauss integration - Eigen::MatrixXd K = Eigen::Matrix4d::Zero(); + double V = 0.0; for (size_t k = 0; k < gauss.getN(); ++k) - { - // Jacobian inverse and shape functions - Eigen::Matrix3d const &J = mem.getJinv(k); - Eigen::MatrixXd const &dff = cache.getDsf(k); - - // Elementary stiffness matrix - K += (J * dff).transpose() * J * dff * fct.eval(*this, u, k) * gauss.getW(k) * mem.getDetJ(k); - } - return K; + V += gauss.getW(k) * mem.getDetJ(k); + return V; } - /** - * @brief Compute linear elasticity stiffness matrix + * @brief Compute volume gradient with respect to each node coordinate * - * K_ij(12,12) = int eps_k H_ijkl eps_l dV = B(12,6)H(6,6)B(6,12) + * dV[i] = w_k * dDetJ[i]_k */ -Eigen::MatrixXd Tetra4::buildK_mechanical(Eigen::MatrixXd const &H) +std::vector<double> Tetra4::buildGradientV(int dim) const { - CacheTetra4 &cache = getCache(order); - GaussTetra4 &gauss = cache.gauss; + GaussTetra4 &gauss = getCache(order).gauss; MemTetra4 &mem = getMem(); - Eigen::MatrixXd K = Eigen::MatrixXd::Zero(12, 12); + // Gradient of volume + std::vector<double> dVol(4 * dim, 0.); // 4 nodes for (size_t k = 0; k < gauss.getN(); ++k) { - // Jacobian inverse - Eigen::Matrix3d const &invJ = mem.getJinv(k); - // Fill B matrix (shape functions) - Eigen::MatrixXd const &dff = cache.getDsf(k); - Eigen::MatrixXd B = Eigen::MatrixXd::Zero(6, 3 * nodes.size()); - for (size_t i = 0; i < nodes.size(); ++i) - { - // Compute [Ni,x Ni,y, Ni_z] - Eigen::Vector3d dN = invJ * dff.col(i); - B(0, 3 * i) = dN(0); - B(1, 3 * i + 1) = dN(1); - B(2, 3 * i + 2) = dN(2); - B(3, 3 * i + 1) = dN(2); - B(3, 3 * i + 2) = dN(1); - B(4, 3 * i) = dN(2); - B(4, 3 * i + 2) = dN(0); - B(5, 3 * i) = dN(1); - B(5, 3 * i + 1) = dN(0); - } - - // Compute stiffness matrix - K += B.transpose() * H * B * gauss.getW(k) * mem.getDetJ(k); - } - return K; -} - -/** - * @brief Compute thermomechanical mass matrix - */ -Eigen::MatrixXd Tetra4::buildS_thermomechanical(Eigen::MatrixXd const &D) -{ - CacheTetra4 &cache = getCache(order); - GaussTetra4 &gauss = cache.gauss; - MemTetra4 &mem = getMem(); - - // Gauss integration - Eigen::MatrixXd S_e = Eigen::MatrixXd::Zero(12, 4); - for (size_t a = 0; a < gauss.getN(); ++a) - { - // Jacobian and shape functions - double detJ = mem.getDetJ(a); - Eigen::Matrix3d const &J = mem.getJinv(a); - Eigen::MatrixXd const &dff = cache.getDsf(a); - - // S - for (size_t i = 0; i < nodes.size(); ++i) - S_e.block(i * 3, 0, 3, nodes.size()) += D * J * dff.col(i) * cache.getSf(a).transpose() * gauss.getW(a) * detJ; - } - return S_e; -} - -/** - * @brief Compute thermal matrix - */ -Eigen::MatrixXd Tetra4::buildL_thermal(Eigen::MatrixXd const &C) -{ - CacheTetra4 &cache = getCache(order); - GaussTetra4 &gauss = cache.gauss; - MemTetra4 &mem = getMem(); - - // Gauss integration - Eigen::MatrixXd L_e = Eigen::Matrix4d::Zero(); - for (size_t a = 0; a < gauss.getN(); ++a) - { - // Jacobian - double detJ = mem.getDetJ(a); - Eigen::Matrix3d const &J = mem.getJinv(a); - Eigen::MatrixXd const &dff = cache.getDsf(a); - - // [AC] I refactored this from an entry by entry assembly to a full matrix multiplication, - // but as nothing tests this method, I could not check the results. - L_e += (C * J * dff).transpose() * J * dff * gauss.getW(a) * detJ; - } - return L_e; -} - -/** - * @brief Compute stress and strain - */ -void Tetra4::strain_stress(Eigen::MatrixXd &Strain, Eigen::MatrixXd &Stress, Eigen::MatrixXd const &H, std::vector<double> const &u) -{ - CacheTetra4 &cache = getCache(order); - GaussTetra4 &gauss = cache.gauss; - MemTetra4 &mem = getMem(); - - Strain = Stress = Eigen::Matrix3d::Zero(); - Eigen::MatrixXd u_e(3, nodes.size()); - for (size_t i = 0; i < nodes.size(); ++i) - { - u_e(0, i) = u[3 * (nodes[i]->row)]; - u_e(1, i) = u[3 * (nodes[i]->row) + 1]; - u_e(2, i) = u[3 * (nodes[i]->row) + 2]; - } - for (size_t a = 0; a < gauss.getN(); ++a) - { - // Jacobian and strain - Eigen::Matrix3d const &J = mem.getJinv(a); - Eigen::MatrixXd const &dff = cache.getDsf(a); - Eigen::Matrix3d du_d_Phi = Eigen::Matrix3d::Zero(); - for (size_t i = 0; i < nodes.size(); ++i) - du_d_Phi += dff.col(i) * u_e.col(i).transpose(); - Strain += ((J * du_d_Phi) + (J * du_d_Phi).transpose()) / nodes.size() / 2; + double w = gauss.getW(k); // GP weight + std::vector<double> dDetJ = mem.getGradDetJ(k); // gradient of Jacobian determinant + for (size_t i = 0; i < dDetJ.size(); ++i) + dVol[i] += w * dDetJ[i]; } - // stress - for (size_t i = 0; i < 3; ++i) - for (size_t j = 0; j < 3; ++j) - for (size_t k = 0; k < 3; ++k) - for (size_t l = 0; l < 3; ++l) - Stress(i, j) += H(i * 3 + j, k * 3 + l) * Strain(k, l); + return dVol; } /** * @brief Compute gradient of a scalar field at Gauss point k */ -Eigen::VectorXd Tetra4::computeGrad(std::vector<double> const &u, size_t k) const +Eigen::VectorXd Tetra4::computeGradient(std::vector<double> const &u, size_t k) const { // Solution vector Eigen::Vector4d ue; @@ -302,37 +145,3 @@ Eigen::VectorXd Tetra4::computeGrad(std::vector<double> const &u, size_t k) cons // gradient in global axis: inv(J)_ij * d_jN_i * ue_i return getMem().getJinv(k) * getCache(order).getDsf(k) * ue; } - -/** - * @brief Compute square of gradient of a scalar field at Gauss point k - */ -double Tetra4::computeGrad2(std::vector<double> const &u, size_t k) const -{ - return computeGrad(u, k).squaredNorm(); -} - -/** - * @brief Compute intergal of scalar function - * - * I = int f dV - */ -double Tetra4::computeV(std::vector<double> const &u, Fct0 const &fct) -{ - CacheTetra4 &cache = getCache(order); - GaussTetra4 &gauss = cache.gauss; - MemTetra4 &mem = getMem(); - - // Gauss integration - double V = 0.0; - for (size_t k = 0; k < gauss.getN(); ++k) - V += fct.eval(*this, u, k) * gauss.getW(k) * mem.getDetJ(k); - return V; -} - -/** - * @brief Return the element volume - */ -double Tetra4::computeV() -{ - return getMem().getVol(); -} diff --git a/tbox/src/wTetra4.h b/tbox/src/wTetra4.h index f524f9c9243994d196274a59768b400e3fb0a6a0..cc2bdb3970b4939322dfad8537dae06162d94798 100644 --- a/tbox/src/wTetra4.h +++ b/tbox/src/wTetra4.h @@ -33,25 +33,19 @@ class TBOX_API Tetra4 : public Element { #ifndef SWIG friend class MemTetra4; + +private: MemTetra4 *pmem; ///< private memory of precalculated values inline static CacheTetra4 &getCache(int n); inline MemTetra4 &getMem() const; + +protected: virtual double buildJ(size_t k, Eigen::MatrixXd &J, Eigen::MatrixXd &iJ) const override; virtual void buildGradientJ(size_t k, std::vector<double> &dDetJ, std::vector<Eigen::MatrixXd> &dJ) const override; - virtual std::vector<double> buildGradientV(int dim) const override; - virtual Eigen::MatrixXd buildM() override; - virtual Eigen::MatrixXd buildK(std::vector<double> const &u, Fct0 const &fct) override; - virtual Eigen::MatrixXd buildK_mechanical(Eigen::MatrixXd const &H) override; - - virtual Eigen::MatrixXd buildS_thermomechanical(Eigen::MatrixXd const &D) override; - virtual Eigen::MatrixXd buildL_thermal(Eigen::MatrixXd const &C) override; - virtual void strain_stress(Eigen::MatrixXd &Strain, Eigen::MatrixXd &Stress, Eigen::MatrixXd const &H, std::vector<double> const &u) override; - - virtual Eigen::VectorXd computeGrad(std::vector<double> const &u, size_t k) const override; - virtual double computeGrad2(std::vector<double> const &u, size_t k) const override; - virtual double computeV(std::vector<double> const &u, Fct0 const &fct) override; - virtual double computeV() override; +public: // @todo + virtual double computeV() const override; + virtual std::vector<double> buildGradientV(int dim) const override; #endif public: @@ -62,6 +56,7 @@ public: #ifndef SWIG virtual Cache &getVCache() const override; virtual Mem &getVMem() const override; + virtual Eigen::VectorXd computeGradient(std::vector<double> const &u, size_t k) const override; #endif }; diff --git a/tbox/src/wTri3.cpp b/tbox/src/wTri3.cpp index 2be7fa463b9b24f7b95fa9024294bcf767a2a7c4..f145c4ed2bc8b947ed188c6e1c990f7f54e34849 100644 --- a/tbox/src/wTri3.cpp +++ b/tbox/src/wTri3.cpp @@ -20,9 +20,6 @@ #include "wCacheTri3.h" #include "wMemTri3.h" #include "wNode.h" -#include "wFct0.h" -#include "wFct1.h" -#include "wFct2.h" using namespace tbox; @@ -53,69 +50,6 @@ Cache &Tri3::getVCache() const return getCache(order); } -/** - * @brief Compute element tangent vectors - */ -std::vector<Eigen::Vector3d> Tri3::computeTangents() const -{ - Eigen::Vector3d x1 = nodes[0]->pos; - Eigen::Vector3d x2 = nodes[1]->pos; - Eigen::Vector3d x3 = nodes[2]->pos; - - return std::vector<Eigen::Vector3d>{(x2 - x1), (x3 - x1)}; -} - -/** - * @brief Build element tangent vectors using shape functions at Gauss point k - */ -std::vector<Eigen::Vector3d> Tri3::buildTangents(size_t k) const -{ - Eigen::MatrixXd const &dff = getCache(order).getDsf(k); - - std::vector<Eigen::Vector3d> t(2, Eigen::Vector3d::Zero()); - size_t i = 0; - for (auto it = nodes.begin(); it != nodes.end(); ++it, ++i) - { - t[0] += (*it)->pos * dff(0, i); - t[1] += (*it)->pos * dff(1, i); - } - return t; -} - -/** - * @brief Compute element unit normal vector - */ -Eigen::Vector3d Tri3::normal() const -{ - std::vector<Eigen::Vector3d> ts = this->computeTangents(); - return ts[0].cross(ts[1]).normalized(); -} - -/** - * @brief Compute gradient of element unit normal vector with respect to each node coordinate - */ -std::vector<Eigen::Vector3d> Tri3::gradientNormal() const -{ - // Compute normal and norm - std::vector<Eigen::Vector3d> ts = this->computeTangents(); - Eigen::Vector3d n = ts[0].cross(ts[1]); - double nn = n.norm(); - - // Compute gradients - Eigen::Matrix3d inn = (Eigen::Matrix3d::Identity() - n * n.transpose() / (nn * nn)) / nn; // gradient of n/|n| - std::vector<Eigen::Vector3d> dn(3 * 3); // 3 nodes and 3 dimensions - for (size_t i = 0; i < 3; ++i) - { - for (size_t j = 0; j < 3; ++j) - { - Eigen::Matrix3d dx = Eigen::Matrix3d::Zero(); - dx(j, i) = 1; // dpos_i / dx_j - dn[i * 3 + j] = inn * ((dx.col(1) - dx.col(0)).cross(ts[1]) + (ts[0]).cross(dx.col(2) - dx.col(0))); // outer gradient times gradient of cross product - } - } - return dn; -} - /** * @brief Compute Jacobian determinant at Gauss point k * @@ -197,6 +131,22 @@ void Tri3::buildGradientJ(size_t k, std::vector<double> &dDetJ, std::vector<Eige for (size_t i = 0; i < dDetJ.size(); ++i) dDetJ[i] = detJ * (iJ * dJ[i]).trace(); } + +/** + * @brief Return the element surface + */ +double Tri3::computeV() const +{ + CacheTri3 &cache = getCache(order); + GaussTri3 &gauss = cache.gauss; + MemTri3 &mem = getMem(); + + // Gauss integration + double V = 0.0; + for (size_t k = 0; k < gauss.getN(); ++k) + V += gauss.getW(k) * mem.getDetJ(k); + return V; +} /** * @brief Compute volume gradient with respect to each node coordinate * @@ -220,168 +170,72 @@ std::vector<double> Tri3::buildGradientV(int dim) const } /** - * @brief Compute stiffness matrix for scalar field - * - * K_ij(3,3) = int f*dN_j*dN_i dV - */ -Eigen::MatrixXd Tri3::buildK(std::vector<double> const &u, Fct0 const &fct) -{ - CacheTri3 &cache = getCache(order); - GaussTri3 &gauss = cache.gauss; - MemTri3 &mem = getMem(); - - // Gauss integration - Eigen::MatrixXd K = Eigen::Matrix3d::Zero(); - for (size_t k = 0; k < gauss.getN(); ++k) - { - // Jacobian inverse and shape functions - Eigen::Matrix2d const &J = mem.getJinv(k); - Eigen::MatrixXd const &dff = cache.getDsf(k); - - // Elementary stiffness matrix - K += (J * dff).transpose() * J * dff * fct.eval(*this, u, k) * gauss.getW(k) * mem.getDetJ(k); - } - return K; -} - -/** - * @brief Compute stiffness matrix for scalar field - * - * K_ij(3,3) = int [f]*dN_j*dN_i dV + * @brief Compute element tangent vectors */ -Eigen::MatrixXd Tri3::buildK(std::vector<double> const &u, Fct2 const &fct, bool fake) +std::vector<Eigen::Vector3d> Tri3::computeTangents() const { - CacheTri3 &cache = getCache(order); - GaussTri3 &gauss = cache.gauss; - - Eigen::MatrixXd K = Eigen::Matrix3d::Zero(); - if (fake) // fake run - fill MPI job list - { - for (size_t k = 0; k < gauss.getN(); ++k) - { - Eigen::MatrixXd fk; - fct.eval(*this, u, k, fk, fake); - } - } - else // true run - use MPI cached results - { - // Gauss integration - MemTri3 &mem = getMem(); - for (size_t k = 0; k < gauss.getN(); ++k) - { - // Jacobian inverse, shape functions and function evaluation - Eigen::Matrix2d const &J = mem.getJinv(k); - Eigen::MatrixXd const &dff = cache.getDsf(k); - Eigen::MatrixXd fk; - fct.eval(*this, u, k, fk, fake); + Eigen::Vector3d x1 = nodes[0]->pos; + Eigen::Vector3d x2 = nodes[1]->pos; + Eigen::Vector3d x3 = nodes[2]->pos; - // Elementary stiffness matrix - K += (fk * J * dff).transpose() * J * dff * gauss.getW(k) * mem.getDetJ(k); - } - } - return K; + return std::vector<Eigen::Vector3d>{(x2 - x1), (x3 - x1)}; } /** - * @brief Compute mechanical stiffness matrix - * - * K_ij(6,6) = int eps_k H_ijkl eps_l dV = B(6,3)H(3,3)B(3,6) + * @brief Build element tangent vectors using shape functions at Gauss point k */ -Eigen::MatrixXd Tri3::buildK_mechanical(Eigen::MatrixXd const &H) +std::vector<Eigen::Vector3d> Tri3::buildTangents(size_t k) const { - CacheTri3 &cache = getCache(order); - GaussTri3 &gauss = cache.gauss; - MemTri3 &mem = getMem(); + Eigen::MatrixXd const &dff = getCache(order).getDsf(k); - // Gauss integration - Eigen::MatrixXd K = Eigen::MatrixXd::Zero(6, 6); - for (size_t k = 0; k < gauss.getN(); ++k) + std::vector<Eigen::Vector3d> t(2, Eigen::Vector3d::Zero()); + size_t i = 0; + for (auto it = nodes.begin(); it != nodes.end(); ++it, ++i) { - // Jacobian inverse - Eigen::Matrix2d const &invJ = mem.getJinv(k); - // Fill B matrix (shape functions) - Eigen::MatrixXd const &dff = cache.getDsf(k); - Eigen::MatrixXd B = Eigen::MatrixXd::Zero(3, 6); - for (size_t i = 0; i < nodes.size(); ++i) - { - // Compute [Ni,x Ni,y] - Eigen::Vector2d dN = invJ * dff.col(i); - B(0, 2 * i) = dN(0); - B(1, 2 * i + 1) = dN(1); - B(2, 2 * i + 1) = dN(0); - B(2, 2 * i) = dN(1); - } - - // Compute stiffness matrix - K += B.transpose() * H * B * gauss.getW(k) * mem.getDetJ(k); + t[0] += (*it)->pos * dff(0, i); + t[1] += (*it)->pos * dff(1, i); } - return K; -} - -/** - * @brief Compute flux vector for a scalar field - * - * s_i(3) = int f*N_i dV - */ -Eigen::VectorXd Tri3::builds(std::vector<double> const &u, Fct0 const &f) -{ - CacheTri3 &cache = getCache(order); - GaussTri3 &gauss = cache.gauss; - MemTri3 &mem = getMem(); - - // Gauss integration - Eigen::VectorXd s = Eigen::Vector3d::Zero(); - for (size_t k = 0; k < gauss.getN(); ++k) - s += cache.getSf(k) * f.eval(*this, u, k) * gauss.getW(k) * mem.getDetJ(k); - return s; + return t; } /** - * @brief Compute flux vector for scalar field - * - * s_i(3) = int f_j*n_j * N_i dV + * @brief Compute element unit normal vector */ -Eigen::VectorXd Tri3::builds(std::vector<double> const &u, Fct1 const &f) +Eigen::Vector3d Tri3::normal() const { - CacheTri3 &cache = getCache(order); - GaussTri3 &gauss = cache.gauss; - MemTri3 &mem = getMem(); - - // Gauss integration - Eigen::VectorXd s = Eigen::Vector3d::Zero(); - for (size_t k = 0; k < gauss.getN(); ++k) - s += cache.getSf(k) * (f.eval(*this, u, k).dot(normal())) * gauss.getW(k) * mem.getDetJ(k); - return s; + std::vector<Eigen::Vector3d> ts = this->computeTangents(); + return ts[0].cross(ts[1]).normalized(); } /** - * @brief Compute mass matrix - * - * S_ij(3,3) = int N_i*N_j dV + * @brief Compute gradient of element unit normal vector with respect to each node coordinate */ -Eigen::MatrixXd Tri3::buildS() +std::vector<Eigen::Vector3d> Tri3::gradientNormal() const { - CacheTri3 &cache = getCache(order); - GaussTri3 &gauss = cache.gauss; - MemTri3 &mem = getMem(); + // Compute normal and norm + std::vector<Eigen::Vector3d> ts = this->computeTangents(); + Eigen::Vector3d n = ts[0].cross(ts[1]); + double nn = n.norm(); - // Gauss integration - Eigen::MatrixXd S = Eigen::Matrix3d::Zero(); - for (size_t k = 0; k < gauss.getN(); ++k) + // Compute gradients + Eigen::Matrix3d inn = (Eigen::Matrix3d::Identity() - n * n.transpose() / (nn * nn)) / nn; // gradient of n/|n| + std::vector<Eigen::Vector3d> dn(3 * 3); // 3 nodes and 3 dimensions + for (size_t i = 0; i < 3; ++i) { - // Shape functions - Eigen::VectorXd const &ff = cache.getSf(k); - - // Mass matrix - S += ff * ff.transpose() * gauss.getW(k) * mem.getDetJ(k); + for (size_t j = 0; j < 3; ++j) + { + Eigen::Matrix3d dx = Eigen::Matrix3d::Zero(); + dx(j, i) = 1; // dpos_i / dx_j + dn[i * 3 + j] = inn * ((dx.col(1) - dx.col(0)).cross(ts[1]) + (ts[0]).cross(dx.col(2) - dx.col(0))); // outer gradient times gradient of cross product + } } - return S; + return dn; } /** * @brief Compute gradient of a scalar field at Gauss point k */ -Eigen::VectorXd Tri3::computeGrad(std::vector<double> const &u, size_t k) const +Eigen::VectorXd Tri3::computeGradient(std::vector<double> const &u, size_t k) const { // Solution vector Eigen::Vector3d ue; @@ -390,112 +244,3 @@ Eigen::VectorXd Tri3::computeGrad(std::vector<double> const &u, size_t k) const // Gradient in global axis: inv(J)_ij * d_jN_i * ue_i return getMem().getJinv(k) * getCache(order).getDsf(k) * ue; } - -/** - * @brief Compute square of gradient of a scalar field at Gauss point k - */ -double Tri3::computeGrad2(std::vector<double> const &u, size_t k) const -{ - return computeGrad(u, k).squaredNorm(); -} - -/** - * @brief Compute flux - * - * qV_i(3) = int [f] gradu N_i dV - */ -Eigen::VectorXd Tri3::computeqint(std::vector<double> const &u, Fct2 const &fct) -{ - CacheTri3 &cache = getCache(order); - GaussTri3 &gauss = cache.gauss; - MemTri3 &mem = getMem(); - - // Gauss integration - Eigen::VectorXd qV = Eigen::Vector3d::Zero(); - for (size_t k = 0; k < gauss.getN(); ++k) - { - // Shape functions, gradient and flux evaluation - Eigen::MatrixXd const &dff = cache.getDsf(k); - Eigen::MatrixXd fk(2, 2); - fct.eval(*this, u, k, fk, false); - - // Elementary flux vector - qV += (fk * computeGrad(u, k)).transpose() * mem.getJinv(k) * dff * gauss.getW(k) * mem.getDetJ(k); - } - return qV; -} - -/** - * @brief Compute flux - * - * qV_i(3) = int -[f] gradu dV - */ -Eigen::VectorXd Tri3::computeqV(std::vector<double> const &u, Fct2 const &fct) -{ - CacheTri3 &cache = getCache(order); - GaussTri3 &gauss = cache.gauss; - MemTri3 &mem = getMem(); - - // Gauss integration - Eigen::VectorXd qV = Eigen::Vector2d::Zero(); - for (size_t k = 0; k < gauss.getN(); ++k) - { - // Gradient and matrix function evaluation - Eigen::VectorXd gradk = computeGrad(u, k); - Eigen::MatrixXd fk(2, 2); - fct.eval(*this, u, k, fk, false); - - qV -= fk * gradk * gauss.getW(k) * mem.getDetJ(k); - } - return qV; -} - -/** - * @brief Compute intergal of scalar function - * - * I = int f dV - */ -double Tri3::computeV(std::vector<double> const &u, Fct0 const &fct) -{ - CacheTri3 &cache = getCache(order); - GaussTri3 &gauss = cache.gauss; - MemTri3 &mem = getMem(); - - // Gauss integration - double V = 0.0; - for (size_t k = 0; k < gauss.getN(); ++k) - V += fct.eval(*this, u, k) * gauss.getW(k) * mem.getDetJ(k); - return V; -} - -/** - * @brief Compute intergal of matrix function - * - * I = int [f] dV - */ -Eigen::MatrixXd Tri3::computeV(std::vector<double> const &u, Fct2 const &fct) -{ - CacheTri3 &cache = getCache(order); - GaussTri3 &gauss = cache.gauss; - MemTri3 &mem = getMem(); - - // Gauss integration - Eigen::MatrixXd out = Eigen::Matrix2d::Zero(); /* @todo out should be resized to match fk size */ - for (size_t k = 0; k < gauss.getN(); ++k) - { - // Function evaluation - Eigen::MatrixXd fk; - fct.eval(*this, u, k, fk, false); - - out += fk * gauss.getW(k) * mem.getDetJ(k); - } - return out; -} - -/** - * @brief Return the element surface - */ -double Tri3::computeV() -{ - return getMem().getVol(); -} diff --git a/tbox/src/wTri3.h b/tbox/src/wTri3.h index bea667503ed240fc0e2ba09a4d214813d8057ccb..bb82eab1bb13448d34c42172d74eb1476c92a0d9 100644 --- a/tbox/src/wTri3.h +++ b/tbox/src/wTri3.h @@ -33,30 +33,23 @@ class TBOX_API Tri3 : public Element { #ifndef SWIG friend class MemTri3; + +private: MemTri3 *pmem; ///< private memory of precalculated values inline MemTri3 &getMem() const; inline static CacheTri3 &getCache(int order); + +protected: virtual double buildJ(size_t k, Eigen::MatrixXd &J, Eigen::MatrixXd &iJ) const override; virtual double buildJ(size_t k) const override; virtual void buildGradientJ(size_t k, std::vector<double> &dDetJ, std::vector<Eigen::MatrixXd> &dJ) const override; virtual void buildGradientJ(size_t k, std::vector<double> &dDetJ) const override; - virtual std::vector<double> buildGradientV(int dim) const override; - - virtual Eigen::MatrixXd buildK(std::vector<double> const &u, Fct0 const &fct) override; - virtual Eigen::MatrixXd buildK(std::vector<double> const &u, Fct2 const &fct, bool fake) override; - virtual Eigen::MatrixXd buildK_mechanical(Eigen::MatrixXd const &H) override; - virtual Eigen::VectorXd builds(std::vector<double> const &u, Fct0 const &f) override; - virtual Eigen::VectorXd builds(std::vector<double> const &u, Fct1 const &f) override; - virtual Eigen::MatrixXd buildS() override; - - virtual Eigen::VectorXd computeGrad(std::vector<double> const &u, size_t k) const override; - virtual double computeGrad2(std::vector<double> const &u, size_t k) const override; - virtual Eigen::VectorXd computeqV(std::vector<double> const &u, Fct2 const &fct) override; - virtual Eigen::VectorXd computeqint(std::vector<double> const &u, Fct2 const &fct) override; - virtual double computeV(std::vector<double> const &u, Fct0 const &fct) override; - virtual Eigen::MatrixXd computeV(std::vector<double> const &u, Fct2 const &fct) override; - virtual double computeV() override; +public: // @todo + virtual double computeV() const override; + virtual std::vector<double> buildGradientV(int dim) const override; + virtual Eigen::Vector3d normal() const override; + virtual std::vector<Eigen::Vector3d> gradientNormal() const override; virtual std::vector<Eigen::Vector3d> computeTangents() const override; virtual std::vector<Eigen::Vector3d> buildTangents(size_t k) const override; #endif @@ -69,8 +62,7 @@ public: #ifndef SWIG virtual Mem &getVMem() const override; virtual Cache &getVCache() const override; - virtual Eigen::Vector3d normal() const override; - virtual std::vector<Eigen::Vector3d> gradientNormal() const override; + virtual Eigen::VectorXd computeGradient(std::vector<double> const &u, size_t k) const override; #endif }; diff --git a/tbox/tests/fem/elem1s.py b/tbox/tests/fem/elem1s.py index 6bcca62a71048ed581a859f1597bcb0ed047e9a0..a14f11b9117986a5ce5f4f47db6eccd0eb027019 100644 --- a/tbox/tests/fem/elem1s.py +++ b/tbox/tests/fem/elem1s.py @@ -13,10 +13,6 @@ def main(**d): el = msh.ntags['S1'].elems[0] print(el) - #el.buildM_test() - el.buildK_test() - el.buildS_test() - el.builds_test() # 1 hex print('='*80+'\nTesting Hex\n'+'='*80) @@ -24,10 +20,6 @@ def main(**d): el = msh.ntags['Volume'].elems[0] print(el) - el.buildM_test() - el.buildK_test() - #el.buildS_test() - #el.builds_test() # 1 quad print('='*80+'\nTesting Quad\n'+'='*80) @@ -36,10 +28,6 @@ def main(**d): el = msh.ntags['S1'].elems[0] print(el) - #el.buildM_test() - #el.buildK_test() - el.buildS_test() - #el.builds_test() if __name__ == "__main__": diff --git a/waves/src/wTimeIntegration.cpp b/waves/src/wTimeIntegration.cpp index b2603d6755851293d9fe897ff8bf9349667d948a..d958627397747f8a6bd35e424fcfcee28f11d3ed 100644 --- a/waves/src/wTimeIntegration.cpp +++ b/waves/src/wTimeIntegration.cpp @@ -24,6 +24,7 @@ #include "wProblem.h" #include "wMedium.h" #include "wBoundary.h" +#include "wWaveTerm.h" #include "wFct0.h" #include "wMshExport.h" #include <typeinfo> @@ -108,7 +109,7 @@ void TimeIntegration::buildS(Eigen::SparseMatrix<double, Eigen::RowMajor> &S2) //std::cout << "processing element #" << e->no << "\n"; // ** Se matrix => S vector - Eigen::MatrixXd Se = e->buildS(); + Eigen::MatrixXd Se = WaveTerm::buildM(*e); // assembly tbb::spin_mutex::scoped_lock lock(mutex); @@ -165,10 +166,10 @@ void TimeIntegration::buildKM_tbb_lambda(Eigen::SparseMatrix<double, Eigen::RowM //std::cout << "processing element #" << e->no << "\n"; // ** Me matrix => Md vector - Eigen::MatrixXd Me = e->buildM(); + Eigen::MatrixXd Me = WaveTerm::buildM(*e); // ** Ke matrix => K matrix - Eigen::MatrixXd Ke = e->buildK(u, Fct0C(1.0)); + Eigen::MatrixXd Ke = WaveTerm::buildK(*e, u); // assembly tbb::spin_mutex::scoped_lock lock(mutex); @@ -195,7 +196,7 @@ void TimeIntegration::buildKM_tbb_lambda(Eigen::SparseMatrix<double, Eigen::RowM std::cout << "[cpu] " << chrono1 << '\n'; } -void TimeIntegration::build(MATTYPE type, Eigen::SparseMatrix<double, Eigen::RowMajor> &A2) +/*void TimeIntegration::build(MATTYPE type, Eigen::SparseMatrix<double, Eigen::RowMajor> &A2) { tbb::spin_mutex mutex; tbb::task_scheduler_init init(nthreads); // TODO mettre ça ailleurs... @@ -235,7 +236,7 @@ void TimeIntegration::build(MATTYPE type, Eigen::SparseMatrix<double, Eigen::Row std::cout << "S (" << A2.rows() << "," << A2.cols() << ") nnz=" << A2.nonZeros() << "\n"; chrono1.read(); std::cout << "[cpu] " << chrono1 << '\n'; -} +}*/ void TimeIntegration::write(std::ostream &out) const { diff --git a/waves/src/wTimeIntegration.h b/waves/src/wTimeIntegration.h index e34250c2e746a565c45af4d453bd754704e953d4..824bde9b425a29531ce5710d7a23a2713af705a5 100644 --- a/waves/src/wTimeIntegration.h +++ b/waves/src/wTimeIntegration.h @@ -78,7 +78,7 @@ public: void setGUI(DisplayHook &hook) { dhook = &hook; } - void build(tbox::MATTYPE type, Eigen::SparseMatrix<double, Eigen::RowMajor> &A2); + //void build(tbox::MATTYPE type, Eigen::SparseMatrix<double, Eigen::RowMajor> &A2); void stop() { stopit = true; } diff --git a/waves/src/wWaveTerm.cpp b/waves/src/wWaveTerm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e39582ec569b9782b05a1324817b0b2f6de3306e --- /dev/null +++ b/waves/src/wWaveTerm.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2020 University of Liège + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wWaveTerm.h" + +#include "wElement.h" +#include "wCache.h" +#include "wGauss.h" +#include "wMem.h" + +using namespace waves; +using namespace tbox; + +/** + * @brief Build volume stiffness matrix for the waves equation on one element + */ +Eigen::MatrixXd WaveTerm::buildK(Element const &e, std::vector<double> const &u) +{ + // Get precomputed values + Cache &cache = e.getVCache(); + Gauss &gauss = cache.getVGauss(); + Mem &mem = e.getVMem(); + + // Stiffness matrix + Eigen::MatrixXd K = Eigen::MatrixXd::Zero(e.nodes.size(), e.nodes.size()); + for (size_t k = 0; k < gauss.getN(); ++k) + { + // Jacobian inverse and shape functions + Eigen::Matrix3d const &J = mem.getJinv(k); + Eigen::MatrixXd const &dff = cache.getDsf(k); + + // Elementary stiffness matrix + K += (J * dff).transpose() * J * dff * gauss.getW(k) * mem.getDetJ(k); + } + return K; +} + +/** + * @brief Build volume/surface mass matrix for the waves equation on one element + */ +Eigen::MatrixXd WaveTerm::buildM(Element const &e) +{ + // Get precomputed values + Cache &cache = e.getVCache(); + Gauss &gauss = cache.getVGauss(); + Mem &mem = e.getVMem(); + + // Mass matrix + Eigen::MatrixXd M = Eigen::MatrixXd::Zero(e.nodes.size(), e.nodes.size()); + for (size_t k = 0; k < gauss.getN(); ++k) + { + // Shape functions + Eigen::VectorXd const &ff = cache.getSf(k); + M += ff * ff.transpose() * gauss.getW(k) * mem.getDetJ(k); + } + return M; +} diff --git a/waves/src/wWaveTerm.h b/waves/src/wWaveTerm.h new file mode 100644 index 0000000000000000000000000000000000000000..12e60a89f0a9d8c2c3b67e8fa7acb3bba6d17e37 --- /dev/null +++ b/waves/src/wWaveTerm.h @@ -0,0 +1,41 @@ +/* + * Copyright 2020 University of Liège + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WWAVETERM_H +#define WWAVETERM_H + +#include "waves.h" + +#include <vector> +#include <Eigen/Dense> + +namespace waves +{ + +/** + * @brief Formulation of wave terms + */ +class WAVES_API WaveTerm +{ +public: + // Stiffness matrix + static Eigen::MatrixXd buildK(tbox::Element const &e, std::vector<double> const &u); + // Mass matrix + static Eigen::MatrixXd buildM(tbox::Element const &e); +}; + +} // namespace waves +#endif //WWAVETERM_H diff --git a/waves/src/waves.h b/waves/src/waves.h index 300ba7cb385088f8fc8d7f133c0fbc271eb0da86..d63fdfd5ba2dc66de0552e04d21e7128d29f8041 100644 --- a/waves/src/waves.h +++ b/waves/src/waves.h @@ -40,6 +40,8 @@ class Boundary; class DisplayHook; +class WaveTerm; + class TimeIntegration; class ForwardEuler; class RungeKutta;