Added computation of internal forces in the converged state
This commit is contained in:
parent
366727ced6
commit
7f543ef21a
|
|
@ -1131,6 +1131,260 @@ void DRMSimulationModel::updateNodalExternalForces(
|
||||||
pMesh->totalExternalForcesNorm = totalExternalForcesNorm;
|
pMesh->totalExternalForcesNorm = totalExternalForcesNorm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::array<Vector6d, 4>> DRMSimulationModel::computeInternalForces(
|
||||||
|
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>> &fixedVertices)
|
||||||
|
{
|
||||||
|
std::vector<std::array<std::pair<int, Vector6d>, 4>>
|
||||||
|
internalForcesContributionsFromEachEdge_axial(pMesh->EN(),
|
||||||
|
std::array<std::pair<int, Vector6d>, 4>{
|
||||||
|
std::pair<int, Vector6d>(-1, Vector6d())});
|
||||||
|
std::vector<std::array<std::pair<int, Vector6d>, 4>>
|
||||||
|
internalForcesContributionsFromEachEdge_torsion(pMesh->EN(),
|
||||||
|
std::array<std::pair<int, Vector6d>, 4>{
|
||||||
|
std::pair<int, Vector6d>(-1,
|
||||||
|
Vector6d())});
|
||||||
|
std::vector<std::array<std::pair<int, Vector6d>, 4>>
|
||||||
|
internalForcesContributionsFromEachEdge_firstBending(
|
||||||
|
pMesh->EN(),
|
||||||
|
std::array<std::pair<int, Vector6d>, 4>{std::pair<int, Vector6d>(-1, Vector6d())});
|
||||||
|
std::vector<std::array<std::pair<int, Vector6d>, 4>>
|
||||||
|
internalForcesContributionsFromEachEdge_secondBending(
|
||||||
|
pMesh->EN(),
|
||||||
|
std::array<std::pair<int, Vector6d>, 4>{std::pair<int, Vector6d>(-1, Vector6d())});
|
||||||
|
// omp_lock_t writelock;
|
||||||
|
// omp_init_lock(&writelock);
|
||||||
|
//#ifdef ENABLE_OPENMP
|
||||||
|
//#pragma omp parallel for schedule(static) num_threads(5)
|
||||||
|
//#endif
|
||||||
|
std::for_each(
|
||||||
|
#ifdef ENABLE_PARALLEL_DRM
|
||||||
|
std::execution::par_unseq,
|
||||||
|
#endif
|
||||||
|
pMesh->edge.begin(),
|
||||||
|
pMesh->edge.end(),
|
||||||
|
[&](const EdgeType &e)
|
||||||
|
// for (int ei = 0; ei < pMesh->EN(); ei++)
|
||||||
|
{
|
||||||
|
const int ei = pMesh->getIndex(e);
|
||||||
|
// const EdgeType &e = pMesh->edge[ei];
|
||||||
|
const SimulationMesh::VertexType &ev_j = *e.cV(0);
|
||||||
|
const SimulationMesh::VertexType &ev_jplus1 = *e.cV(1);
|
||||||
|
const Element &element = pMesh->elements[e];
|
||||||
|
const Element::LocalFrame &ef = element.frame;
|
||||||
|
const VectorType t3CrossN_j = Cross(ef.t3, ev_j.cN());
|
||||||
|
const VectorType t3CrossN_jplus1 = Cross(ef.t3, ev_jplus1.cN());
|
||||||
|
const double theta1_j = ef.t1.dot(t3CrossN_j);
|
||||||
|
const double theta1_jplus1 = ef.t1.dot(t3CrossN_jplus1);
|
||||||
|
const double theta2_j = ef.t2.dot(t3CrossN_j);
|
||||||
|
const double theta2_jplus1 = ef.t2.dot(t3CrossN_jplus1);
|
||||||
|
const double theta3_j = computeTheta3(e, ev_j);
|
||||||
|
const double theta3_jplus1 = computeTheta3(e, ev_jplus1);
|
||||||
|
// element.rotationalDisplacements_j.theta1 = theta1_j;
|
||||||
|
// element.rotationalDisplacements_jplus1.theta1 = theta1_jplus1;
|
||||||
|
// element.rotationalDisplacements_j.theta2 = theta2_j;
|
||||||
|
// element.rotationalDisplacements_jplus1.theta2 = theta2_jplus1;
|
||||||
|
// element.rotationalDisplacements_j.theta3 = theta3_j;
|
||||||
|
// element.rotationalDisplacements_jplus1.theta3 = theta3_jplus1;
|
||||||
|
// std::array<std::pair<int, Vector6d>, 4> internalForcesContributionFromThisEdge{
|
||||||
|
// std::pair<int, Vector6d>(-1, Vector6d())};
|
||||||
|
std::array<std::pair<int, Vector6d>, 4> internalForcesContributionFromThisEdge_axial{
|
||||||
|
std::pair<int, Vector6d>(-1, Vector6d())};
|
||||||
|
std::array<std::pair<int, Vector6d>, 4> internalForcesContributionFromThisEdge_torsion{
|
||||||
|
std::pair<int, Vector6d>(-1, Vector6d())};
|
||||||
|
std::array<std::pair<int, Vector6d>, 4>
|
||||||
|
internalForcesContributionFromThisEdge_firstBending{
|
||||||
|
std::pair<int, Vector6d>(-1, Vector6d())};
|
||||||
|
std::array<std::pair<int, Vector6d>, 4>
|
||||||
|
internalForcesContributionFromThisEdge_secondBending{
|
||||||
|
std::pair<int, Vector6d>(-1, Vector6d())};
|
||||||
|
for (VertexIndex evi = 0; evi < 2; evi++) {
|
||||||
|
const SimulationMesh::VertexType &ev = *e.cV(evi);
|
||||||
|
const Node &edgeNode = pMesh->nodes[ev];
|
||||||
|
internalForcesContributionFromThisEdge_axial[evi].first = edgeNode.vi;
|
||||||
|
|
||||||
|
const VertexPointer &rev_j = edgeNode.referenceElement->cV(0);
|
||||||
|
const VertexPointer &rev_jplus1 = edgeNode.referenceElement->cV(1);
|
||||||
|
// refElemOtherVertex can be precomputed
|
||||||
|
const VertexPointer &refElemOtherVertex = rev_j == &ev ? rev_jplus1 : rev_j;
|
||||||
|
const Node &refElemOtherVertexNode = pMesh->nodes[refElemOtherVertex];
|
||||||
|
if (edgeNode.referenceElement != &e) {
|
||||||
|
internalForcesContributionFromThisEdge_axial[evi + 2].first
|
||||||
|
= refElemOtherVertexNode.vi;
|
||||||
|
}
|
||||||
|
const size_t vi = edgeNode.vi;
|
||||||
|
// #pragma omp parallel for schedule(static) num_threads(6)
|
||||||
|
for (DoFType dofi = DoF::Ux; dofi < DoF::NumDoF; dofi++) {
|
||||||
|
const bool isDofConstrainedFor_ev = isVertexConstrained[edgeNode.vi]
|
||||||
|
&& fixedVertices.at(edgeNode.vi)
|
||||||
|
.contains(dofi);
|
||||||
|
if (!isDofConstrainedFor_ev) {
|
||||||
|
DifferentiateWithRespectTo dui{ev, dofi};
|
||||||
|
// Axial force computation
|
||||||
|
const double e_k = element.length - element.initialLength;
|
||||||
|
const double e_kDeriv = computeDerivativeElementLength(e, dui);
|
||||||
|
const double axialForce_dofi = e_kDeriv * e_k * element.rigidity.axial;
|
||||||
|
|
||||||
|
#ifdef POLYSCOPE_DEFINED
|
||||||
|
if (std::isnan(axialForce_dofi)) {
|
||||||
|
std::cerr << "nan in axial" << evi << std::endl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Torsional force computation
|
||||||
|
const double theta1_j_deriv = computeDerivativeTheta1(e, 0, evi, dofi);
|
||||||
|
const double theta1_jplus1_deriv = computeDerivativeTheta1(e, 1, evi, dofi);
|
||||||
|
const double theta1Diff = theta1_jplus1 - theta1_j;
|
||||||
|
const double theta1DiffDerivative = theta1_jplus1_deriv - theta1_j_deriv;
|
||||||
|
const double torsionalForce_dofi = theta1DiffDerivative * theta1Diff
|
||||||
|
* element.rigidity.torsional;
|
||||||
|
#ifdef POLYSCOPE_DEFINED
|
||||||
|
if (std::isnan(torsionalForce_dofi)) {
|
||||||
|
std::cerr << "nan in torsional" << evi << std::endl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// First bending force computation
|
||||||
|
////theta2_j derivative
|
||||||
|
const double theta2_j_deriv = computeDerivativeTheta2(e, 0, evi, dofi);
|
||||||
|
////theta2_jplus1 derivative
|
||||||
|
const double theta2_jplus1_deriv = computeDerivativeTheta2(e, 1, evi, dofi);
|
||||||
|
////1st in bracket term
|
||||||
|
const double firstBendingForce_inBracketsTerm_0 = theta2_j_deriv * 2
|
||||||
|
* theta2_j;
|
||||||
|
////2nd in bracket term
|
||||||
|
const double firstBendingForce_inBracketsTerm_1 = theta2_jplus1_deriv
|
||||||
|
* theta2_j;
|
||||||
|
////3rd in bracket term
|
||||||
|
const double firstBendingForce_inBracketsTerm_2 = theta2_j_deriv
|
||||||
|
* theta2_jplus1;
|
||||||
|
////4th in bracket term
|
||||||
|
const double firstBendingForce_inBracketsTerm_3 = 2 * theta2_jplus1_deriv
|
||||||
|
* theta2_jplus1;
|
||||||
|
// 3rd term computation
|
||||||
|
const double firstBendingForce_inBracketsTerm
|
||||||
|
= firstBendingForce_inBracketsTerm_0
|
||||||
|
+ firstBendingForce_inBracketsTerm_1
|
||||||
|
+ firstBendingForce_inBracketsTerm_2
|
||||||
|
+ firstBendingForce_inBracketsTerm_3;
|
||||||
|
const double firstBendingForce_dofi = firstBendingForce_inBracketsTerm
|
||||||
|
* element.rigidity.firstBending;
|
||||||
|
|
||||||
|
// Second bending force computation
|
||||||
|
////theta2_j derivative
|
||||||
|
const double theta3_j_deriv = computeDerivativeTheta3(e, ev_j, dui);
|
||||||
|
////theta2_jplus1 derivative
|
||||||
|
const double theta3_jplus1_deriv = computeDerivativeTheta3(e,
|
||||||
|
ev_jplus1,
|
||||||
|
dui);
|
||||||
|
////1st in bracket term
|
||||||
|
const double secondBendingForce_inBracketsTerm_0 = theta3_j_deriv * 2
|
||||||
|
* theta3_j;
|
||||||
|
////2nd in bracket term
|
||||||
|
const double secondBendingForce_inBracketsTerm_1 = theta3_jplus1_deriv
|
||||||
|
* theta3_j;
|
||||||
|
////3rd in bracket term
|
||||||
|
const double secondBendingForce_inBracketsTerm_2 = theta3_j_deriv
|
||||||
|
* theta3_jplus1;
|
||||||
|
////4th in bracket term
|
||||||
|
const double secondBendingForce_inBracketsTerm_3 = theta3_jplus1_deriv * 2
|
||||||
|
* theta3_jplus1;
|
||||||
|
// 3rd term computation
|
||||||
|
const double secondBendingForce_inBracketsTerm
|
||||||
|
= secondBendingForce_inBracketsTerm_0
|
||||||
|
+ secondBendingForce_inBracketsTerm_1
|
||||||
|
+ secondBendingForce_inBracketsTerm_2
|
||||||
|
+ secondBendingForce_inBracketsTerm_3;
|
||||||
|
double secondBendingForce_dofi = secondBendingForce_inBracketsTerm
|
||||||
|
* element.rigidity.secondBending;
|
||||||
|
internalForcesContributionFromThisEdge_axial[evi].second[dofi]
|
||||||
|
= axialForce_dofi;
|
||||||
|
internalForcesContributionFromThisEdge_torsion[evi].second[dofi]
|
||||||
|
= torsionalForce_dofi;
|
||||||
|
internalForcesContributionFromThisEdge_firstBending[evi].second[dofi]
|
||||||
|
= firstBendingForce_dofi;
|
||||||
|
internalForcesContributionFromThisEdge_secondBending[evi].second[dofi]
|
||||||
|
= secondBendingForce_dofi;
|
||||||
|
}
|
||||||
|
if (edgeNode.referenceElement != &e) {
|
||||||
|
const bool isDofConstrainedFor_refElemOtherVertex
|
||||||
|
= isVertexConstrained[refElemOtherVertexNode.vi]
|
||||||
|
&& fixedVertices.at(refElemOtherVertexNode.vi).contains(dofi);
|
||||||
|
if (!isDofConstrainedFor_refElemOtherVertex) {
|
||||||
|
DifferentiateWithRespectTo dui{*refElemOtherVertex, dofi};
|
||||||
|
////theta3_j derivative
|
||||||
|
const double theta3_j_deriv = computeDerivativeTheta3(e, ev_j, dui);
|
||||||
|
////theta3_jplus1 derivative
|
||||||
|
const double theta3_jplus1_deriv = computeDerivativeTheta3(e,
|
||||||
|
ev_jplus1,
|
||||||
|
dui);
|
||||||
|
////1st in bracket term
|
||||||
|
const double secondBendingForce_inBracketsTerm_0 = theta3_j_deriv * 2
|
||||||
|
* theta3_j;
|
||||||
|
////2nd in bracket term
|
||||||
|
const double secondBendingForce_inBracketsTerm_1 = theta3_jplus1_deriv
|
||||||
|
* theta3_j;
|
||||||
|
////3rd in bracket term
|
||||||
|
const double secondBendingForce_inBracketsTerm_2 = theta3_j_deriv
|
||||||
|
* theta3_jplus1;
|
||||||
|
////4th in bracket term
|
||||||
|
const double secondBendingForce_inBracketsTerm_3 = theta3_jplus1_deriv
|
||||||
|
* 2 * theta3_jplus1;
|
||||||
|
|
||||||
|
// 4th term computation
|
||||||
|
const double secondBendingForce_inBracketsTerm
|
||||||
|
= secondBendingForce_inBracketsTerm_0
|
||||||
|
+ secondBendingForce_inBracketsTerm_1
|
||||||
|
+ secondBendingForce_inBracketsTerm_2
|
||||||
|
+ secondBendingForce_inBracketsTerm_3;
|
||||||
|
const double secondBendingForce_dofi = secondBendingForce_inBracketsTerm
|
||||||
|
* element.rigidity.secondBending;
|
||||||
|
internalForcesContributionFromThisEdge_secondBending[evi + 2].second[dofi]
|
||||||
|
= secondBendingForce_dofi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internalForcesContributionsFromEachEdge_axial[ei]
|
||||||
|
= internalForcesContributionFromThisEdge_axial;
|
||||||
|
internalForcesContributionsFromEachEdge_torsion[ei]
|
||||||
|
= internalForcesContributionFromThisEdge_torsion;
|
||||||
|
internalForcesContributionsFromEachEdge_firstBending[ei]
|
||||||
|
= internalForcesContributionFromThisEdge_firstBending;
|
||||||
|
internalForcesContributionsFromEachEdge_secondBending[ei]
|
||||||
|
= internalForcesContributionFromThisEdge_secondBending;
|
||||||
|
});
|
||||||
|
|
||||||
|
//#pragma omp parallel for schedule(static) num_threads(8)
|
||||||
|
|
||||||
|
std::vector<std::array<Vector6d, 4>> perVertexInternalForces(pMesh->VN(), {0});
|
||||||
|
for (size_t ei = 0; ei < pMesh->EN(); ei++) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
std::pair<int, Vector6d> internalForcePair_axial
|
||||||
|
= internalForcesContributionsFromEachEdge_axial[ei][i];
|
||||||
|
std::pair<int, Vector6d> internalForcePair_torsion
|
||||||
|
= internalForcesContributionsFromEachEdge_torsion[ei][i];
|
||||||
|
std::pair<int, Vector6d> internalForcePair_firstBending
|
||||||
|
= internalForcesContributionsFromEachEdge_firstBending[ei][i];
|
||||||
|
std::pair<int, Vector6d> internalForcePair_secondBending
|
||||||
|
= internalForcesContributionsFromEachEdge_secondBending[ei][i];
|
||||||
|
int vi = internalForcePair_axial.first;
|
||||||
|
if (i > 1 && vi == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
perVertexInternalForces[vi][0] = perVertexInternalForces[vi][0]
|
||||||
|
+ internalForcePair_axial.second;
|
||||||
|
perVertexInternalForces[vi][1] = perVertexInternalForces[vi][1]
|
||||||
|
+ internalForcePair_torsion.second;
|
||||||
|
perVertexInternalForces[vi][2] = perVertexInternalForces[vi][2]
|
||||||
|
+ internalForcePair_firstBending.second;
|
||||||
|
perVertexInternalForces[vi][3] = perVertexInternalForces[vi][3]
|
||||||
|
+ internalForcePair_secondBending.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return perVertexInternalForces;
|
||||||
|
}
|
||||||
|
|
||||||
void DRMSimulationModel::updateResidualForces()
|
void DRMSimulationModel::updateResidualForces()
|
||||||
{
|
{
|
||||||
pMesh->totalResidualForcesNorm = 0;
|
pMesh->totalResidualForcesNorm = 0;
|
||||||
|
|
@ -1762,6 +2016,49 @@ SimulationResults DRMSimulationModel::computeResults(const std::shared_ptr<Simul
|
||||||
results.debug_drmDisplacements = results.displacements;
|
results.debug_drmDisplacements = results.displacements;
|
||||||
results.internalPotentialEnergy = computeTotalInternalPotentialEnergy();
|
results.internalPotentialEnergy = computeTotalInternalPotentialEnergy();
|
||||||
|
|
||||||
|
#ifdef COMPUTE_INTERNAL_FORCES
|
||||||
|
results.perVertexInternalForces = computeInternalForces(pJob->constrainedVertices);
|
||||||
|
std::vector<double> perVertexInternalForces_axial = [=]() {
|
||||||
|
std::vector<double> axialInternalForces;
|
||||||
|
axialInternalForces.reserve(results.perVertexInternalForces.size());
|
||||||
|
for (const std::array<Vector6d, 4> &internalForces : results.perVertexInternalForces) {
|
||||||
|
axialInternalForces.push_back(internalForces[0].norm());
|
||||||
|
}
|
||||||
|
return axialInternalForces;
|
||||||
|
}();
|
||||||
|
const auto pCurvNet = pMesh->registerForDrawing();
|
||||||
|
pCurvNet->addNodeScalarQuantity("axial forces", perVertexInternalForces_axial);
|
||||||
|
std::vector<double> perVertexInternalForces_torsion = [=]() {
|
||||||
|
std::vector<double> axialInternalForces;
|
||||||
|
axialInternalForces.reserve(results.perVertexInternalForces.size());
|
||||||
|
for (const std::array<Vector6d, 4> &internalForces : results.perVertexInternalForces) {
|
||||||
|
axialInternalForces.push_back(internalForces[1].norm());
|
||||||
|
}
|
||||||
|
return axialInternalForces;
|
||||||
|
}();
|
||||||
|
pCurvNet->addNodeScalarQuantity("torsional forces", perVertexInternalForces_torsion);
|
||||||
|
std::vector<double> perVertexInternalForces_firstBending = [=]() {
|
||||||
|
std::vector<double> axialInternalForces;
|
||||||
|
axialInternalForces.reserve(results.perVertexInternalForces.size());
|
||||||
|
for (const std::array<Vector6d, 4> &internalForces : results.perVertexInternalForces) {
|
||||||
|
axialInternalForces.push_back(internalForces[2].norm());
|
||||||
|
}
|
||||||
|
return axialInternalForces;
|
||||||
|
}();
|
||||||
|
pCurvNet->addNodeScalarQuantity("first bending forces",
|
||||||
|
perVertexInternalForces_firstBending);
|
||||||
|
std::vector<double> perVertexInternalForces_secondBending = [=]() {
|
||||||
|
std::vector<double> axialInternalForces;
|
||||||
|
axialInternalForces.reserve(results.perVertexInternalForces.size());
|
||||||
|
for (const std::array<Vector6d, 4> &internalForces : results.perVertexInternalForces) {
|
||||||
|
axialInternalForces.push_back(internalForces[3].norm());
|
||||||
|
}
|
||||||
|
return axialInternalForces;
|
||||||
|
}();
|
||||||
|
pCurvNet->addNodeScalarQuantity("second bending forces",
|
||||||
|
perVertexInternalForces_secondBending);
|
||||||
|
polyscope::show();
|
||||||
|
#endif
|
||||||
results.rotationalDisplacementQuaternion.resize(pMesh->VN());
|
results.rotationalDisplacementQuaternion.resize(pMesh->VN());
|
||||||
results.debug_q_f1.resize(pMesh->VN());
|
results.debug_q_f1.resize(pMesh->VN());
|
||||||
results.debug_q_normal.resize(pMesh->VN());
|
results.debug_q_normal.resize(pMesh->VN());
|
||||||
|
|
@ -2666,6 +2963,7 @@ SimulationResults DRMSimulationModel::executeSimulation(const std::shared_ptr<Si
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulationResults results = executeSimulation(pJob); //calling the virtual function
|
SimulationResults results = executeSimulation(pJob); //calling the virtual function
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -254,6 +254,9 @@ private:
|
||||||
|
|
||||||
void reset(const std::shared_ptr<SimulationJob> &pJob);
|
void reset(const std::shared_ptr<SimulationJob> &pJob);
|
||||||
|
|
||||||
|
std::vector<std::array<Vector6d, 4>> computeInternalForces(
|
||||||
|
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>> &fixedVertices);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DRMSimulationModel();
|
DRMSimulationModel();
|
||||||
SimulationResults executeSimulation(const std::shared_ptr<SimulationJob> &pJob,
|
SimulationResults executeSimulation(const std::shared_ptr<SimulationJob> &pJob,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue