Refactoring

This commit is contained in:
Iason 2020-12-03 20:56:03 +02:00
parent 9668d030ea
commit a67003cdd2
10 changed files with 371 additions and 221 deletions

View File

@ -12,7 +12,7 @@ struct RectangularBeamDimensions {
: b(width), h(height) { : b(width), h(height) {
assert(width > 0 && height > 0); assert(width > 0 && height > 0);
} }
RectangularBeamDimensions() : b(1), h(1) {} RectangularBeamDimensions() : b(0.01), h(0.01) {}
}; };
struct CylindricalElementDimensions { struct CylindricalElementDimensions {

View File

@ -10,13 +10,13 @@
void FormFinder::reset() { void FormFinder::reset() {
Dt = Dtini; Dt = Dtini;
t = 0; mCurrentSimulationStep = 0;
currentSimulationStep = 0;
history.clear(); history.clear();
// theta3Derivatives = constrainedVertices.clear();
// Eigen::Tensor<double, 4>(DoF::NumDoFType, mesh->VN(), mesh->EN(), rigidSupports.clear();
// mesh->VN()); mesh.release();
// theta3Derivatives.setZero(); plotYValues.clear();
plotHandle.reset();
} }
VectorType FormFinder::computeDisplacementDifferenceDerivative( VectorType FormFinder::computeDisplacementDifferenceDerivative(
@ -40,6 +40,7 @@ VectorType FormFinder::computeDisplacementDifferenceDerivative(
VectorType FormFinder::computeDerivativeOfNormal( VectorType FormFinder::computeDerivativeOfNormal(
const VertexType &v, const DifferentiateWithRespectTo &dui) const { const VertexType &v, const DifferentiateWithRespectTo &dui) const {
const size_t vi = mesh->getIndex(v);
VectorType normalDerivative(0, 0, 0); VectorType normalDerivative(0, 0, 0);
if (&dui.v != &v || if (&dui.v != &v ||
(dui.dofi == 0 || dui.dofi == 1 || dui.dofi == 2 || dui.dofi == 5)) { (dui.dofi == 0 || dui.dofi == 1 || dui.dofi == 2 || dui.dofi == 5)) {
@ -184,7 +185,9 @@ FormFinder::computeDerivativeT2(const EdgeType &e,
const DoFType dofi = dui.dofi; const DoFType dofi = dui.dofi;
const VertexType &v_j = *e.cV(0); const VertexType &v_j = *e.cV(0);
const size_t vi_j = mesh->getIndex(v_j);
const VertexType &v_jplus1 = *e.cV(1); const VertexType &v_jplus1 = *e.cV(1);
const size_t vi_jplus1 = mesh->getIndex(v_jplus1);
const VectorType r = (v_j.cN() + v_jplus1.cN()).Normalize(); const VectorType r = (v_j.cN() + v_jplus1.cN()).Normalize();
const VectorType derivativeR_j = const VectorType derivativeR_j =
@ -231,7 +234,9 @@ FormFinder::computeDerivativeT3(const EdgeType &e,
const VectorType &t2 = element.frame.t2; const VectorType &t2 = element.frame.t2;
const VectorType t1CrossT2 = Cross(t1, t2); const VectorType t1CrossT2 = Cross(t1, t2);
const VertexType &v_j = *e.cV(0); const VertexType &v_j = *e.cV(0);
const size_t vi_j = mesh->getIndex(v_j);
const VertexType &v_jplus1 = *e.cV(1); const VertexType &v_jplus1 = *e.cV(1);
const size_t vi_jplus1 = mesh->getIndex(v_jplus1);
const VectorType derivativeT1_j = const VectorType derivativeT1_j =
dui.dofi < 3 && &v_j == &dui.v dui.dofi < 3 && &v_j == &dui.v
? mesh->elements[e].derivativeT1_j[dui.dofi] ? mesh->elements[e].derivativeT1_j[dui.dofi]
@ -279,6 +284,7 @@ double FormFinder::computeDerivativeTheta1(const EdgeType &e,
const VertexIndex &dwrt_evi, const VertexIndex &dwrt_evi,
const DoFType &dwrt_dofi) const { const DoFType &dwrt_dofi) const {
const VertexType &v = *e.cV(evi); const VertexType &v = *e.cV(evi);
const size_t vi = mesh->getIndex(v);
const Element &element = mesh->elements[e]; const Element &element = mesh->elements[e];
const VectorType derivativeT1 = element.derivativeT1[dwrt_evi][dwrt_dofi]; const VectorType derivativeT1 = element.derivativeT1[dwrt_evi][dwrt_dofi];
const VectorType derivativeT3 = element.derivativeT3[dwrt_evi][dwrt_dofi]; const VectorType derivativeT3 = element.derivativeT3[dwrt_evi][dwrt_dofi];
@ -617,6 +623,7 @@ void FormFinder::updateResidualForcesOnTheFly(
internalForcesContributionFromThisEdge[evi + 2].first = internalForcesContributionFromThisEdge[evi + 2].first =
refElemOtherVertexNode.vi; refElemOtherVertexNode.vi;
} }
const size_t vi = edgeNode.vi;
// #pragma omp parallel for schedule(static) num_threads(6) // #pragma omp parallel for schedule(static) num_threads(6)
for (DoFType dofi = DoF::Ux; dofi < DoF::NumDoF; dofi++) { for (DoFType dofi = DoF::Ux; dofi < DoF::NumDoF; dofi++) {
const bool isDofConstrainedFor_ev = const bool isDofConstrainedFor_ev =
@ -765,11 +772,16 @@ void FormFinder::updateResidualForcesOnTheFly(
} }
} }
for (size_t vi = 0; vi < mesh->VN(); vi++) { for (size_t vi = 0; vi < mesh->VN(); vi++) {
const double residualForceNorm = (mesh->nodes[vi].force.residual).norm(); const Vector6d &nodeResidualForce = mesh->nodes[vi].force.residual;
const double residualForceNorm = nodeResidualForce.norm();
totalResidualForcesNorm += residualForceNorm; totalResidualForcesNorm += residualForceNorm;
} }
mesh->previousTotalResidualForcesNorm = mesh->totalResidualForcesNorm; mesh->previousTotalResidualForcesNorm = mesh->totalResidualForcesNorm;
mesh->totalResidualForcesNorm = totalResidualForcesNorm; mesh->totalResidualForcesNorm = totalResidualForcesNorm;
// plotYValues.push_back(totalResidualForcesNorm);
// auto xPlot = matplot::linspace(0, plotYValues.size(), plotYValues.size());
// plotHandle = matplot::scatter(xPlot, plotYValues);
} }
void FormFinder::updateNodalExternalForces( void FormFinder::updateNodalExternalForces(
@ -901,6 +913,7 @@ FormFinder::FormFinder() {}
void FormFinder::updateNodalMasses() { void FormFinder::updateNodalMasses() {
const double gamma = 0.8; const double gamma = 0.8;
for (VertexType &v : mesh->vert) { for (VertexType &v : mesh->vert) {
const size_t vi = mesh->getIndex(v);
double translationalSumSk = 0; double translationalSumSk = 0;
double rotationalSumSk_I2 = 0; double rotationalSumSk_I2 = 0;
double rotationalSumSk_I3 = 0; double rotationalSumSk_I3 = 0;
@ -955,6 +968,7 @@ void FormFinder::updateNodalMasses() {
void FormFinder::updateNodalAccelerations() { void FormFinder::updateNodalAccelerations() {
for (VertexType &v : mesh->vert) { for (VertexType &v : mesh->vert) {
Node &node = mesh->nodes[v]; Node &node = mesh->nodes[v];
const VertexIndex vi = mesh->getIndex(v);
for (DoFType dofi = DoF::Ux; dofi < DoF::NumDoF; dofi++) { for (DoFType dofi = DoF::Ux; dofi < DoF::NumDoF; dofi++) {
if (dofi == DoF::Ux || dofi == DoF::Uy || dofi == DoF::Uz) { if (dofi == DoF::Ux || dofi == DoF::Uy || dofi == DoF::Uz) {
node.acceleration[dofi] = node.acceleration[dofi] =
@ -964,10 +978,10 @@ void FormFinder::updateNodalAccelerations() {
node.force.residual[dofi] / node.rotationalMass_J; node.force.residual[dofi] / node.rotationalMass_J;
} else if (dofi == DoF::Ny) { } else if (dofi == DoF::Ny) {
node.acceleration[dofi] = node.acceleration[dofi] =
node.force.residual[dofi] / node.rotationalMass_I2; node.force.residual[dofi] / node.rotationalMass_I3;
} else if (dofi == DoF::Nr) { } else if (dofi == DoF::Nr) {
node.acceleration[dofi] = node.acceleration[dofi] =
node.force.residual[dofi] / node.rotationalMass_I3; node.force.residual[dofi] / node.rotationalMass_I2;
} }
} }
} }
@ -975,6 +989,7 @@ void FormFinder::updateNodalAccelerations() {
void FormFinder::updateNodalVelocities() { void FormFinder::updateNodalVelocities() {
for (VertexType &v : mesh->vert) { for (VertexType &v : mesh->vert) {
const VertexIndex vi = mesh->getIndex(v);
Node &node = mesh->nodes[v]; Node &node = mesh->nodes[v];
node.velocity = node.velocity + node.acceleration * Dt; node.velocity = node.velocity + node.acceleration * Dt;
} }
@ -1008,17 +1023,16 @@ void FormFinder::updateNodePosition(
} }
node.previousLocation = previousLocation; node.previousLocation = previousLocation;
v.P() = node.initialLocation + displacementVector; v.P() = node.initialLocation + displacementVector;
if (shouldApplyInitialDistortion && currentSimulationStep < 40) { if (shouldApplyInitialDistortion && mCurrentSimulationStep < 40) {
VectorType desiredInitialDisplacement(0, 0, 0.1); VectorType desiredInitialDisplacement(0, 0, 0.1);
v.P() = v.P() + desiredInitialDisplacement; v.P() = v.P() + desiredInitialDisplacement;
} }
} }
void FormFinder::applyDisplacements( void FormFinder::updateNodeNormal(
VertexType &v,
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>> const std::unordered_map<VertexIndex, std::unordered_set<DoFType>>
&fixedVertices) { &fixedVertices) {
for (VertexType &v : mesh->vert) {
updateNodePosition(v, fixedVertices);
Node &node = mesh->nodes[v]; Node &node = mesh->nodes[v];
const VertexIndex &vi = node.vi; const VertexIndex &vi = node.vi;
VectorType normalDisplacementVector(0, 0, 0); VectorType normalDisplacementVector(0, 0, 0);
@ -1032,8 +1046,9 @@ void FormFinder::applyDisplacements(
const double &nx = v.N()[0], ny = v.N()[1]; const double &nx = v.N()[0], ny = v.N()[1];
const double nxnyMagnitude = std::pow(nx, 2) + std::pow(ny, 2); const double nxnyMagnitude = std::pow(nx, 2) + std::pow(ny, 2);
if (nxnyMagnitude > 1) { if (nxnyMagnitude > 1) {
v.N() = VectorType(nx / std::sqrt(nxnyMagnitude), VectorType newNormal(nx / std::sqrt(nxnyMagnitude),
ny / std::sqrt(nxnyMagnitude), 0); ny / std::sqrt(nxnyMagnitude), 0);
v.N() = newNormal;
} else { } else {
const double nzSquared = 1.0 - nxnyMagnitude; const double nzSquared = 1.0 - nxnyMagnitude;
const double nz = std::sqrt(nzSquared); const double nz = std::sqrt(nzSquared);
@ -1053,7 +1068,18 @@ void FormFinder::applyDisplacements(
node.nR = g1.dot(v.cN()); node.nR = g1.dot(v.cN());
} }
} }
void FormFinder::applyDisplacements(
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>>
&fixedVertices) {
for (VertexType &v : mesh->vert) {
updateNodePosition(v, fixedVertices);
updateNodeNormal(v, fixedVertices);
}
updateElementalFrames(); updateElementalFrames();
if (mShouldDraw) {
mesh->updateEigenEdgeAndVertices();
}
} }
void FormFinder::updateElementalFrames() { void FormFinder::updateElementalFrames() {
@ -1098,10 +1124,10 @@ void FormFinder::updateKineticEnergy() {
// const double rotationalVelocityNorm = std::sqrt( // const double rotationalVelocityNorm = std::sqrt(
// std::pow(node.velocity[3], 2) + std::pow(node.velocity[4], 2) + // std::pow(node.velocity[3], 2) + std::pow(node.velocity[4], 2) +
// std::pow(node.velocity[5], 2)); // std::pow(node.velocity[5], 2));
node.kineticEnergy += // node.kineticEnergy +=
0.5 * node.rotationalMass_J * pow(node.velocity[3], 2) + // 0.5 * node.rotationalMass_J * pow(node.velocity[3], 2) +
0.5 * node.rotationalMass_I3 * pow(node.velocity[4], 2) + // 0.5 * node.rotationalMass_I3 * pow(node.velocity[4], 2) +
0.5 * node.rotationalMass_I2 * pow(node.velocity[5], 2); // 0.5 * node.rotationalMass_I2 * pow(node.velocity[5], 2);
mesh->currentTotalKineticEnergy += node.kineticEnergy; mesh->currentTotalKineticEnergy += node.kineticEnergy;
} }
@ -1244,7 +1270,7 @@ FormFinder::computeResults(const SimulationMesh &initialMesh) {
displacements[vi] = mesh->nodes[vi].displacements; displacements[vi] = mesh->nodes[vi].displacements;
} }
history.numberOfSteps = currentSimulationStep; history.numberOfSteps = mCurrentSimulationStep;
return SimulationResults{history, displacements}; return SimulationResults{history, displacements};
} }
@ -1478,6 +1504,9 @@ void FormFinder::draw(const std::string &screenshotsFolder = {}) {
ImGui::InputInt("Simulation drawing step", ImGui::InputInt("Simulation drawing step",
&mDrawingStep); // set a int variable &mDrawingStep); // set a int variable
ImGui::Checkbox("Enable drawing",
&mShouldDraw); // set a int variable
ImGui::Text("Number of simulation steps: %zu", mCurrentSimulationStep);
ImGui::PopItemWidth(); ImGui::PopItemWidth();
}; };
@ -1493,7 +1522,7 @@ void FormFinder::draw(const std::string &screenshotsFolder = {}) {
} }
polyscope::screenshot( polyscope::screenshot(
std::filesystem::path(screenshotsFolder) std::filesystem::path(screenshotsFolder)
.append(std::to_string(currentSimulationStep) + ".png") .append(std::to_string(mCurrentSimulationStep) + ".png")
.string(), .string(),
false); false);
} else { } else {
@ -1507,6 +1536,8 @@ FormFinder::executeSimulation(const SimulationJob &job, const bool &beVerbose,
const size_t &maxDRMIterations) { const size_t &maxDRMIterations) {
assert(job.mesh.operator bool()); assert(job.mesh.operator bool());
auto t1 = std::chrono::high_resolution_clock::now(); auto t1 = std::chrono::high_resolution_clock::now();
reset();
mShouldDraw = shouldDraw;
constrainedVertices = job.fixedVertices; constrainedVertices = job.fixedVertices;
if (!job.nodalForcedDisplacements.empty()) { if (!job.nodalForcedDisplacements.empty()) {
@ -1526,19 +1557,19 @@ FormFinder::executeSimulation(const SimulationJob &job, const bool &beVerbose,
std::cout << "Executing simulation for mesh with:" << mesh->VN() std::cout << "Executing simulation for mesh with:" << mesh->VN()
<< " nodes and " << mesh->EN() << " elements." << std::endl; << " nodes and " << mesh->EN() << " elements." << std::endl;
} }
reset();
computeRigidSupports(); computeRigidSupports();
if (shouldDraw) {
const std::string deformedMeshName = "Deformed edge mesh";
if (mShouldDraw) {
if (!polyscope::state::initialized) { if (!polyscope::state::initialized) {
initPolyscope(); initPolyscope();
} }
const std::string deformedMeshName = "Deformed edge mesh";
if (!polyscope::hasCurveNetwork(deformedMeshName)) { if (!polyscope::hasCurveNetwork(deformedMeshName)) {
polyscope::registerCurveNetwork( polyscope::registerCurveNetwork(
deformedMeshName, mesh->getEigenVertices(), mesh->getEigenEdges()); deformedMeshName, mesh->getEigenVertices(), mesh->getEigenEdges());
} }
registerWorldAxes(); // registerWorldAxes();
} }
// const double beamRadius = mesh.getBeamDimensions()[0].od / 2; // const double beamRadius = mesh.getBeamDimensions()[0].od / 2;
// std::cout << "BeamRadius:" << beamRadius << std::endl; // std::cout << "BeamRadius:" << beamRadius << std::endl;
@ -1603,7 +1634,7 @@ FormFinder::executeSimulation(const SimulationJob &job, const bool &beVerbose,
updateNodalExternalForces(job.nodalExternalForces, constrainedVertices); updateNodalExternalForces(job.nodalExternalForces, constrainedVertices);
// } // }
while (currentSimulationStep < maxDRMIterations) { while (mCurrentSimulationStep < maxDRMIterations) {
// while (true) { // while (true) {
updateNormalDerivatives(); updateNormalDerivatives();
updateT1Derivatives(); updateT1Derivatives();
@ -1665,8 +1696,8 @@ FormFinder::executeSimulation(const SimulationJob &job, const bool &beVerbose,
// assert(std::isfinite(mesh.currentTotalKineticEnergy)); // assert(std::isfinite(mesh.currentTotalKineticEnergy));
// mesh.printVertexCoordinates(mesh.VN() / 2); // mesh.printVertexCoordinates(mesh.VN() / 2);
// draw(); // draw();
if (shouldDraw && if (mShouldDraw &&
currentSimulationStep % mDrawingStep == 0 /* && mCurrentSimulationStep % mDrawingStep == 0 /* &&
currentSimulationStep > maxDRMIterations*/) { currentSimulationStep > maxDRMIterations*/) {
// std::string saveTo = std::filesystem::current_path() // std::string saveTo = std::filesystem::current_path()
// .append("Debugging_files") // .append("Debugging_files")
@ -1691,11 +1722,11 @@ currentSimulationStep > maxDRMIterations*/) {
// << std::endl; // << std::endl;
draw(); draw();
} }
if (currentSimulationStep != 0) { if (mCurrentSimulationStep != 0) {
history.stepPulse(*mesh); history.stepPulse(*mesh);
} }
// t = t + Dt; // t = t + Dt;
currentSimulationStep++; mCurrentSimulationStep++;
// std::cout << "Kinetic energy:" << mesh.currentTotalKineticEnergy // std::cout << "Kinetic energy:" << mesh.currentTotalKineticEnergy
// << std::endl; // << std::endl;
// std::cout << "Residual forces norm:" << mesh.totalResidualForcesNorm // std::cout << "Residual forces norm:" << mesh.totalResidualForcesNorm
@ -1704,8 +1735,8 @@ currentSimulationStep > maxDRMIterations*/) {
if (/*mesh.totalPotentialEnergykN < 10 ||*/ if (/*mesh.totalPotentialEnergykN < 10 ||*/
mesh->totalResidualForcesNorm < totalResidualForcesNormThreshold) { mesh->totalResidualForcesNorm < totalResidualForcesNormThreshold) {
if (beVerbose) { if (beVerbose) {
std::cout << "Convergence after " << currentSimulationStep << " steps" std::cout << "Convergence after " << mCurrentSimulationStep
<< std::endl; << " steps" << std::endl;
std::cout << "Residual force of magnitude:" std::cout << "Residual force of magnitude:"
<< mesh->previousTotalResidualForcesNorm << std::endl; << mesh->previousTotalResidualForcesNorm << std::endl;
std::cout << "Kinetic energy:" << mesh->currentTotalKineticEnergy std::cout << "Kinetic energy:" << mesh->currentTotalKineticEnergy
@ -1737,17 +1768,17 @@ currentSimulationStep > maxDRMIterations*/) {
// << " kNm" // << " kNm"
// << std::endl; // << std::endl;
// reset displacements to previous position where the peak occured // reset displacements to previous position where the peak occured
for (VertexType &v : mesh->vert) { // for (VertexType &v : mesh->vert) {
Node &node = mesh->nodes[v]; // Node &node = mesh->nodes[v];
node.displacements = node.displacements - node.velocity * Dt; // node.displacements = node.displacements - node.velocity * Dt;
} // }
applyDisplacements(constrainedVertices); // applyDisplacements(constrainedVertices, shouldDraw);
if (!job.nodalForcedDisplacements.empty()) { // if (!job.nodalForcedDisplacements.empty()) {
applyForcedDisplacements( // applyForcedDisplacements(
job.nodalForcedDisplacements); // job.nodalForcedDisplacements);
} // }
updateElementalLengths(); // updateElementalLengths();
resetVelocities(); resetVelocities();
Dt = Dt * xi; Dt = Dt * xi;
// std::cout << "Residual forces norm:" << // std::cout << "Residual forces norm:" <<
@ -1755,7 +1786,7 @@ currentSimulationStep > maxDRMIterations*/) {
// << std::endl; // << std::endl;
} }
} }
if (currentSimulationStep == maxDRMIterations) { if (mCurrentSimulationStep == maxDRMIterations) {
std::cout << "Did not reach equilibrium before reaching the maximum number " std::cout << "Did not reach equilibrium before reaching the maximum number "
"of DRM steps (" "of DRM steps ("
<< maxDRMIterations << "). Breaking simulation" << std::endl; << maxDRMIterations << "). Breaking simulation" << std::endl;
@ -1768,16 +1799,16 @@ currentSimulationStep > maxDRMIterations*/) {
<< std::endl; << std::endl;
std::cout << "Time/(node*iteration) " std::cout << "Time/(node*iteration) "
<< simulationDuration / << simulationDuration /
(static_cast<double>(currentSimulationStep) * mesh->VN()) (static_cast<double>(mCurrentSimulationStep) * mesh->VN())
<< "s" << std::endl; << "s" << std::endl;
} }
// mesh.printVertexCoordinates(mesh.VN() / 2); // mesh.printVertexCoordinates(mesh.VN() / 2);
if (shouldDraw) { if (mShouldDraw) {
draw(); draw();
}
// if (!polyscope::hasCurveNetwork(deformedMeshName)) { // if (!polyscope::hasCurveNetwork(deformedMeshName)) {
// polyscope::removeCurveNetwork(deformedMeshName); polyscope::removeCurveNetwork(deformedMeshName);
// } // }
}
// debugger.createPlots(); // debugger.createPlots();
SimulationResults results = computeResults(*job.mesh); SimulationResults results = computeResults(*job.mesh);
// Eigen::write_binary("optimizedResult.eigenBin", // Eigen::write_binary("optimizedResult.eigenBin",

View File

@ -2,6 +2,7 @@
#define BEAMFORMFINDER_HPP #define BEAMFORMFINDER_HPP
#include "elementalmesh.hpp" #include "elementalmesh.hpp"
#include "matplot/matplot.h"
#include "polyscope/curve_network.h" #include "polyscope/curve_network.h"
#include "polyscope/polyscope.h" #include "polyscope/polyscope.h"
#include "simulationresult.hpp" #include "simulationresult.hpp"
@ -25,11 +26,14 @@ class FormFinder {
private: private:
const double Dtini{0.1}; const double Dtini{0.1};
double Dt{Dtini}; double Dt{Dtini};
double t{0};
const double xi{0.9969}; const double xi{0.9969};
const double totalResidualForcesNormThreshold{300}; const double totalResidualForcesNormThreshold{10};
size_t currentSimulationStep{0}; size_t mCurrentSimulationStep{0};
int mDrawingStep{1}; int mDrawingStep{5};
bool mShouldDraw{false};
matplot::line_handle plotHandle;
std::vector<double> plotYValues;
std::unique_ptr<SimulationMesh> mesh; std::unique_ptr<SimulationMesh> mesh;
std::unordered_map<VertexIndex, std::unordered_set<DoFType>> std::unordered_map<VertexIndex, std::unordered_set<DoFType>>
constrainedVertices; constrainedVertices;
@ -63,7 +67,7 @@ private:
const std::unordered_map<VertexIndex, Eigen::Vector3d> const std::unordered_map<VertexIndex, Eigen::Vector3d>
nodalForcedDisplacements); nodalForcedDisplacements);
::Vector6d computeElementTorsionalForce( Vector6d computeElementTorsionalForce(
const Element &element, const Vector6d &displacementDifference, const Element &element, const Vector6d &displacementDifference,
const std::unordered_set<DoFType> &constrainedDof); const std::unordered_set<DoFType> &constrainedDof);
@ -97,12 +101,12 @@ private:
const Vector6d &elementInternalForce, const Vector6d &elementInternalForce,
const std::unordered_set<DoFType> &nodalFixedDof); const std::unordered_set<DoFType> &nodalFixedDof);
::Vector6d computeElementInternalForce( Vector6d computeElementInternalForce(
const Element &elem, const Node &n0, const Node &n1, const Element &elem, const Node &n0, const Node &n1,
const std::unordered_set<DoFType> &n0ConstrainedDof, const std::unordered_set<DoFType> &n0ConstrainedDof,
const std::unordered_set<DoFType> &n1ConstrainedDof); const std::unordered_set<DoFType> &n1ConstrainedDof);
::Vector6d computeElementAxialForce(const ::EdgeType &e) const; Vector6d computeElementAxialForce(const ::EdgeType &e) const;
VectorType computeDisplacementDifferenceDerivative( VectorType computeDisplacementDifferenceDerivative(
const EdgeType &e, const DifferentiateWithRespectTo &dui) const; const EdgeType &e, const DifferentiateWithRespectTo &dui) const;
double double
@ -167,6 +171,11 @@ private:
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>> const std::unordered_map<VertexIndex, std::unordered_set<DoFType>>
&fixedVertices); &fixedVertices);
void updateNodeNormal(
VertexType &v,
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>>
&fixedVertices);
public: public:
FormFinder(); FormFinder();
SimulationResults executeSimulation( SimulationResults executeSimulation(

View File

@ -12,36 +12,7 @@ Eigen::MatrixX3d VCGEdgeMesh::getEigenEdgeNormals() const {
return eigenEdgeNormals; return eigenEdgeNormals;
} }
std::vector<CylindricalElementDimensions> bool VCGEdgeMesh::savePly(const std::string plyFilename) {}
VCGEdgeMesh::getBeamDimensions() const {
return handleBeamDimensions._handle->data;
}
std::vector<ElementMaterial> VCGEdgeMesh::getBeamMaterial() const {
return handleBeamMaterial._handle->data;
}
bool VCGEdgeMesh::savePly(const std::string plyFilename) {
nanoply::NanoPlyWrapper<VCGEdgeMesh>::CustomAttributeDescriptor customAttrib;
customAttrib.GetMeshAttrib(plyFilename);
customAttrib.AddEdgeAttribDescriptor<CylindricalElementDimensions, float, 2>(
plyPropertyBeamDimensionsID, nanoply::NNP_LIST_UINT8_FLOAT32,
&handleBeamDimensions[0]);
customAttrib.AddEdgeAttribDescriptor<vcg::Point2f, float, 2>(
plyPropertyBeamMaterialID, nanoply::NNP_LIST_UINT8_FLOAT32,
&handleBeamMaterial[0]);
// Load the ply file
unsigned int mask = 0;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTCOORD;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEINDEX;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEATTRIB;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTNORMAL;
if (nanoply::NanoPlyWrapper<VCGEdgeMesh>::SaveModel(
plyFilename.c_str(), *this, mask, customAttrib, false) != 0) {
return false;
}
return true;
}
void VCGEdgeMesh::GeneratedRegularSquaredPattern( void VCGEdgeMesh::GeneratedRegularSquaredPattern(
const double angleDeg, std::vector<std::vector<vcg::Point2d>> &pattern, const double angleDeg, std::vector<std::vector<vcg::Point2d>> &pattern,
@ -114,11 +85,11 @@ void VCGEdgeMesh::createSpiral(const float &degreesOfArm,
// setDefaultAttributes(); // setDefaultAttributes();
} }
bool VCGEdgeMesh::createGrid(const size_t squareGridDimension) { bool VCGEdgeMesh::createSpanGrid(const size_t squareGridDimension) {
return createGrid(squareGridDimension, squareGridDimension); return createSpanGrid(squareGridDimension, squareGridDimension);
} }
bool VCGEdgeMesh::createGrid(const size_t desiredWidth, bool VCGEdgeMesh::createSpanGrid(const size_t desiredWidth,
const size_t desiredHeight) { const size_t desiredHeight) {
std::cout << "Grid of dimensions:" << desiredWidth << "," << desiredHeight std::cout << "Grid of dimensions:" << desiredWidth << "," << desiredHeight
<< std::endl; << std::endl;
@ -229,44 +200,38 @@ bool VCGEdgeMesh::loadUsingNanoply(const std::string &plyFilename) {
this->Clear(); this->Clear();
// assert(plyFileHasAllRequiredFields(plyFilename)); // assert(plyFileHasAllRequiredFields(plyFilename));
nanoply::NanoPlyWrapper<VCGEdgeMesh>::CustomAttributeDescriptor customAttrib;
customAttrib.GetMeshAttrib(plyFilename);
customAttrib.AddEdgeAttribDescriptor<RectangularBeamDimensions, float, 2>(
plyPropertyBeamDimensionsID, nanoply::NNP_LIST_UINT8_FLOAT32, nullptr);
customAttrib.AddEdgeAttribDescriptor<vcg::Point2f, float, 2>(
plyPropertyBeamMaterialID, nanoply::NNP_LIST_UINT8_FLOAT32, nullptr);
// Load the ply file // Load the ply file
unsigned int mask = 0; unsigned int mask = 0;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTCOORD; mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTCOORD;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTNORMAL; mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTNORMAL;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEINDEX; mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEINDEX;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEATTRIB; if (nanoply::NanoPlyWrapper<VCGEdgeMesh>::LoadModel(plyFilename.c_str(),
if (nanoply::NanoPlyWrapper<VCGEdgeMesh>::LoadModel( *this, mask) != 0) {
plyFilename.c_str(), *this, mask, customAttrib) != 0) {
return false; return false;
} }
return true; return true;
} }
bool VCGEdgeMesh::plyFileHasAllRequiredFields(const std::string &plyFilename) { // bool VCGEdgeMesh::plyFileHasAllRequiredFields(const std::string &plyFilename)
const nanoply::Info info(plyFilename); // {
const std::vector<nanoply::PlyElement>::const_iterator edgeElemIt = // const nanoply::Info info(plyFilename);
std::find_if(info.elemVec.begin(), info.elemVec.end(), // const std::vector<nanoply::PlyElement>::const_iterator edgeElemIt =
[&](const nanoply::PlyElement &plyElem) { // std::find_if(info.elemVec.begin(), info.elemVec.end(),
return plyElem.plyElem == nanoply::NNP_EDGE_ELEM; // [&](const nanoply::PlyElement &plyElem) {
}); // return plyElem.plyElem == nanoply::NNP_EDGE_ELEM;
if (edgeElemIt == info.elemVec.end()) { // });
std::cerr << "Ply file is missing edge elements." << std::endl; // if (edgeElemIt == info.elemVec.end()) {
return false; // std::cerr << "Ply file is missing edge elements." << std::endl;
} // return false;
// }
const std::vector<nanoply::PlyProperty> &edgePropertyVector = // const std::vector<nanoply::PlyProperty> &edgePropertyVector =
edgeElemIt->propVec; // edgeElemIt->propVec;
return hasPlyEdgeProperty(plyFilename, edgePropertyVector, // return hasPlyEdgeProperty(plyFilename, edgePropertyVector,
plyPropertyBeamDimensionsID) && // plyPropertyBeamDimensionsID) &&
hasPlyEdgeProperty(plyFilename, edgePropertyVector, // hasPlyEdgeProperty(plyFilename, edgePropertyVector,
plyPropertyBeamMaterialID); // plyPropertyBeamMaterialID);
} //}
bool VCGEdgeMesh::hasPlyEdgeProperty( bool VCGEdgeMesh::hasPlyEdgeProperty(
const std::string &plyFilename, const std::string &plyFilename,
@ -316,13 +281,7 @@ void VCGEdgeMesh::getEdges(Eigen::MatrixX3d &edgeStartingPoints,
} }
} }
VCGEdgeMesh::VCGEdgeMesh() { VCGEdgeMesh::VCGEdgeMesh() {}
handleBeamDimensions = vcg::tri::Allocator<VCGEdgeMesh>::AddPerEdgeAttribute<
CylindricalElementDimensions>(*this, plyPropertyBeamDimensionsID);
handleBeamMaterial =
vcg::tri::Allocator<VCGEdgeMesh>::AddPerEdgeAttribute<ElementMaterial>(
*this, plyPropertyBeamMaterialID);
}
void VCGEdgeMesh::updateEigenEdgeAndVertices() { void VCGEdgeMesh::updateEigenEdgeAndVertices() {
getEdges(eigenEdges); getEdges(eigenEdges);

View File

@ -29,11 +29,6 @@ class VCGEdgeMeshEdgeType
class VCGEdgeMesh : public vcg::tri::TriMesh<std::vector<VCGEdgeMeshVertexType>, class VCGEdgeMesh : public vcg::tri::TriMesh<std::vector<VCGEdgeMeshVertexType>,
std::vector<VCGEdgeMeshEdgeType>> { std::vector<VCGEdgeMeshEdgeType>> {
const std::string plyPropertyBeamDimensionsID{"beam_dimensions"};
const std::string plyPropertyBeamMaterialID{"beam_material"};
VCGEdgeMesh::PerEdgeAttributeHandle<CylindricalElementDimensions>
handleBeamDimensions;
VCGEdgeMesh::PerEdgeAttributeHandle<ElementMaterial> handleBeamMaterial;
protected: protected:
Eigen::MatrixX2i eigenEdges; Eigen::MatrixX2i eigenEdges;
@ -75,15 +70,13 @@ public:
bool savePly(const std::string plyFilename); bool savePly(const std::string plyFilename);
bool createGrid(const size_t squareGridDimension); bool createSpanGrid(const size_t squareGridDimension);
bool createGrid(const size_t desiredWidth, const size_t desiredHeight); bool createSpanGrid(const size_t desiredWidth, const size_t desiredHeight);
void createSpiral(const float &degreesOfArm, const size_t &numberOfSamples); void createSpiral(const float &degreesOfArm, const size_t &numberOfSamples);
Eigen::MatrixX2i getEigenEdges() const; Eigen::MatrixX2i getEigenEdges() const;
Eigen::MatrixX3d getEigenVertices() const; Eigen::MatrixX3d getEigenVertices() const;
Eigen::MatrixX3d getEigenEdgeNormals() const; Eigen::MatrixX3d getEigenEdgeNormals() const;
std::vector<CylindricalElementDimensions> getBeamDimensions() const;
std::vector<ElementMaterial> getBeamMaterial() const;
void printVertexCoordinates(const size_t &vi) const; void printVertexCoordinates(const size_t &vi) const;
void registerForDrawing() const; void registerForDrawing() const;

View File

@ -1,5 +1,21 @@
#include "elementalmesh.hpp" #include "elementalmesh.hpp"
SimulationMesh::SimulationMesh(VCGEdgeMesh &mesh) {
vcg::tri::MeshAssert<VCGEdgeMesh>::VertexNormalNormalized(mesh);
vcg::tri::Append<VCGEdgeMesh, ConstVCGEdgeMesh>::MeshCopy(*this, mesh);
elements = vcg::tri::Allocator<VCGEdgeMesh>::GetPerEdgeAttribute<Element>(
*this, std::string("Elements"));
nodes = vcg::tri::Allocator<VCGEdgeMesh>::GetPerVertexAttribute<Node>(
*this, std::string("Nodes"));
vcg::tri::UpdateTopology<VCGEdgeMesh>::VertexEdge(*this);
initializeNodes();
initializeElements();
label = mesh.getLabel();
eigenEdges = mesh.getEigenEdges();
eigenVertices = mesh.getEigenVertices();
}
SimulationMesh::SimulationMesh(FlatPattern &pattern) { SimulationMesh::SimulationMesh(FlatPattern &pattern) {
vcg::tri::MeshAssert<FlatPattern>::VertexNormalNormalized(pattern); vcg::tri::MeshAssert<FlatPattern>::VertexNormalNormalized(pattern);
@ -16,9 +32,8 @@ SimulationMesh::SimulationMesh(FlatPattern &pattern) {
eigenVertices = pattern.getEigenVertices(); eigenVertices = pattern.getEigenVertices();
} }
SimulationMesh::SimulationMesh(SimulationMesh &elementalMesh) { SimulationMesh::SimulationMesh(SimulationMesh &mesh) {
vcg::tri::Append<VCGEdgeMesh, ConstVCGEdgeMesh>::MeshCopy(*this, vcg::tri::Append<VCGEdgeMesh, ConstVCGEdgeMesh>::MeshCopy(*this, mesh);
elementalMesh);
elements = vcg::tri::Allocator<VCGEdgeMesh>::GetPerEdgeAttribute<Element>( elements = vcg::tri::Allocator<VCGEdgeMesh>::GetPerEdgeAttribute<Element>(
*this, std::string("Elements")); *this, std::string("Elements"));
nodes = vcg::tri::Allocator<VCGEdgeMesh>::GetPerVertexAttribute<Node>( nodes = vcg::tri::Allocator<VCGEdgeMesh>::GetPerVertexAttribute<Node>(
@ -27,16 +42,16 @@ SimulationMesh::SimulationMesh(SimulationMesh &elementalMesh) {
initializeNodes(); initializeNodes();
for (size_t ei = 0; ei < EN(); ei++) { for (size_t ei = 0; ei < EN(); ei++) {
elements[ei] = elementalMesh.elements[ei]; elements[ei] = mesh.elements[ei];
} }
label = label; label = mesh.label;
eigenEdges = elementalMesh.getEigenEdges(); eigenEdges = mesh.getEigenEdges();
eigenVertices = elementalMesh.getEigenVertices(); eigenVertices = mesh.getEigenVertices();
} }
void SimulationMesh::computeElementalProperties() { void SimulationMesh::computeElementalProperties() {
const std::vector<CylindricalElementDimensions> elementalDimensions = const std::vector<RectangularBeamDimensions> elementalDimensions =
getBeamDimensions(); getBeamDimensions();
const std::vector<ElementMaterial> elementalMaterials = getBeamMaterial(); const std::vector<ElementMaterial> elementalMaterials = getBeamMaterial();
assert(EN() == elementalDimensions.size() && assert(EN() == elementalDimensions.size() &&
@ -102,6 +117,10 @@ void SimulationMesh::initializeElements() {
for (const EdgeType &e : edge) { for (const EdgeType &e : edge) {
Element &element = elements[e]; Element &element = elements[e];
element.ei = getIndex(e); element.ei = getIndex(e);
// Initialize dimensions
element.properties.dimensions = CrossSectionType(1, 1);
// Initialize material
element.properties.material = ElementMaterial();
// Initialize lengths // Initialize lengths
const VCGEdgeMesh::CoordType p0 = e.cP(0); const VCGEdgeMesh::CoordType p0 = e.cP(0);
const VCGEdgeMesh::CoordType p1 = e.cP(1); const VCGEdgeMesh::CoordType p1 = e.cP(1);
@ -109,16 +128,7 @@ void SimulationMesh::initializeElements() {
element.initialLength = s.Length(); element.initialLength = s.Length();
element.length = element.initialLength; element.length = element.initialLength;
// Initialize const factors // Initialize const factors
element.axialConstFactor = element.updateConstFactors();
element.properties.E * element.properties.A / element.initialLength;
element.torsionConstFactor =
element.properties.G * element.properties.J / element.initialLength;
element.firstBendingConstFactor = 2 * element.properties.E *
element.properties.I2 /
element.initialLength;
element.secondBendingConstFactor = 2 * element.properties.E *
element.properties.I3 /
element.initialLength;
element.derivativeT1.resize( element.derivativeT1.resize(
2, std::vector<VectorType>(6, VectorType(0, 0, 0))); 2, std::vector<VectorType>(6, VectorType(0, 0, 0)));
element.derivativeT2.resize( element.derivativeT2.resize(
@ -152,6 +162,91 @@ void SimulationMesh::updateElementalLengths() {
} }
} }
void SimulationMesh::setBeamCrossSection(const double &firstDimension,
const double &secondDimension) {
for (size_t ei = 0; ei < EN(); ei++) {
elements[ei].properties.setDimensions(
CrossSectionType{firstDimension, secondDimension});
elements[ei].updateConstFactors();
}
}
void SimulationMesh::setBeamMaterial(const double &pr, const double &ym) {
for (size_t ei = 0; ei < EN(); ei++) {
elements[ei].properties.setMaterial(ElementMaterial{pr, ym});
elements[ei].updateConstFactors();
}
}
std::vector<RectangularBeamDimensions> SimulationMesh::getBeamDimensions() {
std::vector<RectangularBeamDimensions> beamDimensions(EN());
for (size_t ei = 0; ei < EN(); ei++) {
beamDimensions[ei] = elements[ei].properties.dimensions;
}
return beamDimensions;
}
std::vector<ElementMaterial> SimulationMesh::getBeamMaterial() {
std::vector<ElementMaterial> beamMaterial(EN());
for (size_t ei = 0; ei < EN(); ei++) {
beamMaterial[ei] = elements[ei].properties.material;
}
return beamMaterial;
}
bool SimulationMesh::loadFromPly(const string &plyFilename) {
this->Clear();
// assert(plyFileHasAllRequiredFields(plyFilename));
// Load the ply file
VCGEdgeMesh::PerEdgeAttributeHandle<RectangularBeamDimensions>
handleBeamDimensions;
VCGEdgeMesh::PerEdgeAttributeHandle<ElementMaterial> handleBeamMaterial;
handleBeamDimensions =
vcg::tri::Allocator<VCGEdgeMesh>::AddPerEdgeAttribute<CrossSectionType>(
*this, plyPropertyBeamDimensionsID);
handleBeamMaterial =
vcg::tri::Allocator<VCGEdgeMesh>::AddPerEdgeAttribute<ElementMaterial>(
*this, plyPropertyBeamMaterialID);
nanoply::NanoPlyWrapper<VCGEdgeMesh>::CustomAttributeDescriptor customAttrib;
customAttrib.GetMeshAttrib(plyFilename);
customAttrib.AddEdgeAttribDescriptor<RectangularBeamDimensions, float, 2>(
plyPropertyBeamDimensionsID, nanoply::NNP_LIST_UINT8_FLOAT32, nullptr);
customAttrib.AddEdgeAttribDescriptor<vcg::Point2f, float, 2>(
plyPropertyBeamMaterialID, nanoply::NNP_LIST_UINT8_FLOAT32, nullptr);
unsigned int mask = 0;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTCOORD;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTNORMAL;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEINDEX;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEATTRIB;
if (nanoply::NanoPlyWrapper<SimulationMesh>::LoadModel(plyFilename.c_str(),
*this, mask) != 0) {
return false;
}
return true;
}
bool SimulationMesh::savePly(const std::string &plyFilename) {
nanoply::NanoPlyWrapper<VCGEdgeMesh>::CustomAttributeDescriptor customAttrib;
customAttrib.GetMeshAttrib(plyFilename);
customAttrib.AddEdgeAttribDescriptor<RectangularBeamDimensions, float, 2>(
plyPropertyBeamDimensionsID, nanoply::NNP_LIST_UINT8_FLOAT32,
getBeamDimensions().data());
customAttrib.AddEdgeAttribDescriptor<vcg::Point2f, float, 2>(
plyPropertyBeamMaterialID, nanoply::NNP_LIST_UINT8_FLOAT32,
getBeamMaterial().data());
// Load the ply file
unsigned int mask = 0;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTCOORD;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEINDEX;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEATTRIB;
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTNORMAL;
if (nanoply::NanoPlyWrapper<VCGEdgeMesh>::SaveModel(
plyFilename.c_str(), *this, mask, customAttrib, false) != 0) {
return false;
}
return true;
}
SimulationMesh::EdgePointer SimulationMesh::EdgePointer
SimulationMesh::getReferenceElement(const VCGEdgeMesh::VertexType &v) { SimulationMesh::getReferenceElement(const VCGEdgeMesh::VertexType &v) {
const VertexIndex vi = getIndex(v); const VertexIndex vi = getIndex(v);
@ -207,3 +302,51 @@ double computeAngle(const VectorType &vector0, const VectorType &vector1,
} }
return angle; return angle;
} }
void Element::Properties::computeMaterialProperties(
const ElementMaterial &material) {
E = material.youngsModulusGPascal * std::pow(10, 9);
G = E / (2 * (1 + material.poissonsRatio));
}
void Element::Properties::computeDimensionsProperties(
const RectangularBeamDimensions &dimensions) {
A = (dimensions.b * dimensions.h);
I2 = dimensions.b * std::pow(dimensions.h, 3) / 12;
I3 = dimensions.h * std::pow(dimensions.b, 3) / 12;
J = I2 + I3;
}
void Element::Properties::computeDimensionsProperties(
const CylindricalElementDimensions &dimensions) {
A = M_PI * (std::pow(dimensions.od / 2, 2) - std::pow(dimensions.id / 2, 2));
I2 = M_PI * (std::pow(dimensions.od, 4) - std::pow(dimensions.id, 4)) / 64;
I3 = I2;
J = I2 + I3;
}
void Element::Properties::setDimensions(const CrossSectionType &dimensions) {
this->dimensions = dimensions;
computeDimensionsProperties(dimensions);
}
void Element::Properties::setMaterial(const ElementMaterial &material) {
this->material = material;
computeMaterialProperties(material);
}
Element::Properties::Properties(const CrossSectionType &dimensions,
const ElementMaterial &material)
: dimensions(dimensions), material(material) {
computeDimensionsProperties(dimensions);
computeMaterialProperties(material);
}
void Element::updateConstFactors() {
axialConstFactor = properties.E * properties.A / initialLength;
torsionConstFactor = properties.G * properties.J / initialLength;
firstBendingConstFactor = 2 * properties.E * properties.I2 / initialLength;
secondBendingConstFactor = 2 * properties.E * properties.I3 / initialLength;
int i = 0;
i++;
}

View File

@ -7,6 +7,7 @@
struct Element; struct Element;
struct Node; struct Node;
using CrossSectionType = RectangularBeamDimensions;
class SimulationMesh : public VCGEdgeMesh { class SimulationMesh : public VCGEdgeMesh {
private: private:
@ -15,6 +16,9 @@ private:
void initializeElements(); void initializeElements();
EdgePointer getReferenceElement(const VertexType &v); EdgePointer getReferenceElement(const VertexType &v);
const std::string plyPropertyBeamDimensionsID{"beam_dimensions"};
const std::string plyPropertyBeamMaterialID{"beam_material"};
public: public:
PerEdgeAttributeHandle<Element> elements; PerEdgeAttributeHandle<Element> elements;
PerVertexAttributeHandle<Node> nodes; PerVertexAttributeHandle<Node> nodes;
@ -22,55 +26,43 @@ public:
SimulationMesh(ConstVCGEdgeMesh &edgeMesh); SimulationMesh(ConstVCGEdgeMesh &edgeMesh);
SimulationMesh(SimulationMesh &elementalMesh); SimulationMesh(SimulationMesh &elementalMesh);
void updateElementalLengths(); void updateElementalLengths();
void setBeamCrossSection(const double &firstDimension,
const double &secondDimension);
void setBeamMaterial(const double &pr, const double &ym);
std::vector<VCGEdgeMesh::EdgePointer> std::vector<VCGEdgeMesh::EdgePointer>
getIncidentElements(const VCGEdgeMesh::VertexType &v); getIncidentElements(const VCGEdgeMesh::VertexType &v);
bool loadFromPly(const string &plyFilename);
std::vector<CrossSectionType> getBeamDimensions();
std::vector<ElementMaterial> getBeamMaterial();
double previousTotalKineticEnergy{0}; double previousTotalKineticEnergy{0};
double previousTotalResidualForcesNorm{0}; double previousTotalResidualForcesNorm{0};
double currentTotalKineticEnergy{0}; double currentTotalKineticEnergy{0};
double totalResidualForcesNorm{0}; double totalResidualForcesNorm{0};
double totalPotentialEnergykN{0}; double totalPotentialEnergykN{0};
bool savePly(const std::string &plyFilename);
}; };
struct Element { struct Element {
struct Properties { struct Properties {
CrossSectionType dimensions;
ElementMaterial material;
double E{0}; // youngs modulus in pascal double E{0}; // youngs modulus in pascal
double G{0}; // shear modulus double G{0}; // shear modulus
double A{0}; // cross sectional area double A{0}; // cross sectional area
double I2{0}; // second moment of inertia double I2{0}; // second moment of inertia
double I3{0}; // third moment of inertia double I3{0}; // third moment of inertia
double J{0}; // torsional constant (polar moment of inertia) double J{0}; // torsional constant (polar moment of inertia)
void computeMaterialProperties(const ElementMaterial &material) { void computeMaterialProperties(const ElementMaterial &material);
E = material.youngsModulusGPascal * std::pow(10, 9);
G = E / (2 * (1 + material.poissonsRatio));
}
void void
computeDimensionsProperties(const RectangularBeamDimensions &dimensions) { computeDimensionsProperties(const RectangularBeamDimensions &dimensions);
A = (dimensions.b * dimensions.h); void
I2 = dimensions.b * std::pow(dimensions.h, 3) / 12; computeDimensionsProperties(const CylindricalElementDimensions &dimensions);
I3 = dimensions.h * std::pow(dimensions.b, 3) / 12; void setDimensions(const CrossSectionType &dimensions);
} void setMaterial(const ElementMaterial &material);
void computeDimensionsProperties( Properties(const CrossSectionType &dimensions,
const CylindricalElementDimensions &dimensions) { const ElementMaterial &material);
A = M_PI *
(std::pow(dimensions.od / 2, 2) - std::pow(dimensions.id / 2, 2));
I2 =
M_PI * (std::pow(dimensions.od, 4) - std::pow(dimensions.id, 4)) / 64;
I3 = I2;
}
Properties(const RectangularBeamDimensions &dimensions,
const ElementMaterial &material) {
computeDimensionsProperties(dimensions);
computeMaterialProperties(material);
J = I2 + I3;
}
Properties(const CylindricalElementDimensions &dimensions,
const ElementMaterial &material) {
computeDimensionsProperties(dimensions);
computeMaterialProperties(material);
J = I2 + I3;
}
Properties() {} Properties() {}
}; };
@ -80,6 +72,8 @@ struct Element {
VectorType t3; VectorType t3;
}; };
void updateConstFactors();
EdgeIndex ei; EdgeIndex ei;
double length{0}; double length{0};
Properties properties; Properties properties;

View File

@ -17,8 +17,9 @@ FlatPattern::FlatPattern(const string &filename, bool addNormalsIfAbsent) {
} }
vcg::tri::UpdateTopology<FlatPattern>::VertexEdge(*this); vcg::tri::UpdateTopology<FlatPattern>::VertexEdge(*this);
scale();
// scale(); updateEigenEdgeAndVertices();
} }
FlatPattern::FlatPattern(const std::vector<size_t> &numberOfNodesPerSlot, FlatPattern::FlatPattern(const std::vector<size_t> &numberOfNodesPerSlot,
@ -31,6 +32,7 @@ FlatPattern::FlatPattern(const std::vector<size_t> &numberOfNodesPerSlot,
v.N() = CoordType(0, 0, 1); v.N() = CoordType(0, 0, 1);
} }
} }
scale();
updateEigenEdgeAndVertices(); updateEigenEdgeAndVertices();
} }

View File

@ -27,7 +27,7 @@ private:
void removeDuplicateVertices(); void removeDuplicateVertices();
void scale(); void scale();
const double desiredBaseTriangleCentralEdgeSize{0.25 / std::tan(M_PI / 6)}; const double desiredBaseTriangleCentralEdgeSize{0.025};
}; };
#endif // FLATPATTERN_HPP #endif // FLATPATTERN_HPP

View File

@ -97,6 +97,26 @@ struct SimulationJob {
->setEnabled(true); ->setEnabled(true);
} }
} }
static std::unordered_map<size_t, std::unordered_set<int>>
constructFixedVerticesSpanGrid(const size_t &spanGridSize,
const size_t &gridVertices) {
std::unordered_map<size_t, std::unordered_set<int>> fixedVertices;
for (size_t vi = 0; vi < spanGridSize - 1; vi++) {
fixedVertices[vi] = {0, 1, 2};
}
for (size_t vi = gridVertices - 1 - (spanGridSize - 2); vi < gridVertices;
vi++) {
fixedVertices[vi] = {0, 1, 2};
}
for (size_t vi = spanGridSize - 1;
vi < gridVertices - 1 - (spanGridSize - 2) - spanGridSize + 1;
vi += spanGridSize + 1) {
fixedVertices[vi] = {0, 1, 2};
fixedVertices[vi + spanGridSize] = {0, 1, 2};
}
return fixedVertices;
}
}; };
struct SimulationResults { struct SimulationResults {
@ -163,33 +183,32 @@ struct SimulationResults {
}); });
// per node external forces // per node external forces
std::vector<std::array<double, 3>> externalForces(job.mesh->VN()); std::vector<std::array<double, 3>> externalForces(job.mesh->VN());
std::vector<std::array<double, 3>> externalMoments(job.mesh->VN());
for (const auto &forcePair : job.nodalExternalForces) { for (const auto &forcePair : job.nodalExternalForces) {
auto index = forcePair.first; auto index = forcePair.first;
auto force = forcePair.second; auto force = forcePair.second;
externalForces[index] = {force[0], force[1], force[2]}; externalForces[index] = {force[0], force[1], force[2]};
externalMoments[index] = {force[3], force[4], 0};
} }
polyscope::getCurveNetwork(undeformedMeshName) polyscope::getCurveNetwork(undeformedMeshName)
->addNodeColorQuantity("Boundary conditions", nodeColors); ->addNodeColorQuantity("Boundary conditions", nodeColors)
polyscope::getCurveNetwork(undeformedMeshName)
->getQuantity("Boundary conditions")
->setEnabled(true); ->setEnabled(true);
polyscope::getCurveNetwork(undeformedMeshName) polyscope::getCurveNetwork(undeformedMeshName)
->addNodeVectorQuantity("External force", externalForces); ->addNodeVectorQuantity("External force", externalForces)
polyscope::getCurveNetwork(undeformedMeshName)
->getQuantity("External force")
->setEnabled(true); ->setEnabled(true);
polyscope::getCurveNetwork(undeformedMeshName)
->addNodeVectorQuantity("External moments", externalMoments)
->setEnabled(true);
polyscope::getCurveNetwork(deformedMeshName) polyscope::getCurveNetwork(deformedMeshName)
->addNodeColorQuantity("Boundary conditions", nodeColors); ->addNodeColorQuantity("Boundary conditions", nodeColors)
polyscope::getCurveNetwork(deformedMeshName)
->getQuantity("Boundary conditions")
->setEnabled(false); ->setEnabled(false);
polyscope::getCurveNetwork(deformedMeshName) polyscope::getCurveNetwork(deformedMeshName)
->addNodeVectorQuantity("External force", externalForces); ->addNodeVectorQuantity("External force", externalForces)
polyscope::getCurveNetwork(deformedMeshName)
->getQuantity("External force")
->setEnabled(true); ->setEnabled(true);
// polyscope::show(); // polyscope::show();