#ifndef BEAMFORMFINDER_HPP #define BEAMFORMFINDER_HPP #include "simulationmesh.hpp" #include "matplot/matplot.h" #include "simulation_structs.hpp" #include #include #include struct SimulationJob; enum DoF { Ux = 0, Uy, Uz, Nx, Ny, Nr, NumDoF }; using DoFType = int; using EdgeType = VCGEdgeMesh::EdgeType; using VertexType = VCGEdgeMesh::VertexType; struct DifferentiateWithRespectTo { const VertexType &v; const DoFType &dofi; }; class DRMSimulationModel { public: struct Settings { bool isDebugMode{false}; int debugModeStep{100000}; bool shouldDraw{false}; bool beVerbose{false}; bool shouldCreatePlots{false}; int drawingStep{1}; double totalTranslationalKineticEnergyThreshold{1e-8}; double residualForcesMovingAverageDerivativeNormThreshold{1e-8}; double residualForcesMovingAverageNormThreshold{1e-8}; double Dtini{0.1}; double xi{0.9969}; int maxDRMIterations{0}; bool shouldUseTranslationalKineticEnergyThreshold{false}; int gradualForcedDisplacementSteps{50}; int desiredGradualExternalLoadsSteps{1}; double gamma{0.8}; std::optional displacementCap; double totalResidualForcesNormThreshold{1e-3}; double totalExternalForcesNormPercentageTermination{1e-3}; bool useAverage{false}; double averageResidualForcesCriterionThreshold{1e-3}; Settings() {} }; private: Settings mSettings; double Dt{mSettings.Dtini}; bool checkedForMaximumMoment{false}; bool shouldTemporarilyDampForces{false}; bool shouldTemporarilyAmplifyForces{true}; double externalMomentsNorm{0}; size_t mCurrentSimulationStep{0}; matplot::line_handle plotHandle; std::vector plotYValues; size_t numOfDampings{0}; int externalLoadStep{1}; const std::string meshPolyscopeLabel{"Simulation mesh"}; std::unique_ptr pMesh; std::unordered_map> constrainedVertices; SimulationHistory history; // Eigen::Tensor theta3Derivatives; // std::unordered_map theta3Derivatives; bool shouldApplyInitialDistortion = false; std::unordered_set rigidSupports; void reset(); void updateNodalInternalForces( const std::unordered_map> &fixedVertices); void updateNodalExternalForces( const std::unordered_map &nodalForces, const std::unordered_map> &fixedVertices); void updateResidualForces(); void updateRotationalDisplacements(); void updateElementalLengths(); void updateNodalMasses(); void updateNodalAccelerations(); void updateNodalVelocities(); void updateNodalDisplacements(); void applyForcedDisplacements( const std::unordered_map &nodalForcedDisplacements); Vector6d computeElementTorsionalForce(const Element &element, const Vector6d &displacementDifference, const std::unordered_set &constrainedDof); // BeamFormFinder::Vector6d computeElementFirstBendingForce( // const Element &element, const Vector6d &displacementDifference, // const std::unordered_set &constrainedDof); // BeamFormFinder::Vector6d computeElementSecondBendingForce( // const Element &element, const Vector6d &displacementDifference, // const std::unordered_set &constrainedDof); void updateKineticEnergy(); void resetVelocities(); SimulationResults computeResults(const std::shared_ptr &pJob); void updateNodePosition( VertexType &v, const std::unordered_map> &fixedVertices); void applyDisplacements( const std::unordered_map> &fixedVertices); #ifdef POLYSCOPE_DEFINED void draw(const string &screenshotsFolder= {}); #endif void updateNodalInternalForce(Vector6d &nodalInternalForce, const Vector6d &elementInternalForce, const std::unordered_set &nodalFixedDof); Vector6d computeElementInternalForce( const Element &elem, const Node &n0, const Node &n1, const std::unordered_set &n0ConstrainedDof, const std::unordered_set &n1ConstrainedDof); Vector6d computeElementAxialForce(const ::EdgeType &e) const; VectorType computeDisplacementDifferenceDerivative( const EdgeType &e, const DifferentiateWithRespectTo &dui) const; double computeDerivativeElementLength(const EdgeType &e, const DifferentiateWithRespectTo &dui) const; VectorType computeDerivativeT1(const EdgeType &e, const DifferentiateWithRespectTo &dui) const; VectorType computeDerivativeOfNormal(const VertexType &v, const DifferentiateWithRespectTo &dui) const; VectorType computeDerivativeT3(const EdgeType &e, const DifferentiateWithRespectTo &dui) const; VectorType computeDerivativeT2(const EdgeType &e, const DifferentiateWithRespectTo &dui) const; double computeDerivativeTheta2(const EdgeType &e, const VertexIndex &evi, const VertexIndex &dwrt_evi, const DoFType &dwrt_dofi) const; void updateElementalFrames(); VectorType computeDerivativeOfR(const EdgeType &e, const DifferentiateWithRespectTo &dui) const; bool isRigidSupport(const VertexType &v) const; static double computeDerivativeOfNorm(const VectorType &x, const VectorType &derivativeOfX); static VectorType computeDerivativeOfCrossProduct( const VectorType &a, const VectorType &derivativeOfA, const VectorType &b, const VectorType &derivativeOfB); double computeTheta3(const EdgeType &e, const VertexType &v); double computeDerivativeTheta3(const EdgeType &e, const VertexType &v, const DifferentiateWithRespectTo &dui) const; double computeTotalPotentialEnergy(); void computeRigidSupports(); void updateNormalDerivatives(); void updateT1Derivatives(); void updateT2Derivatives(); void updateT3Derivatives(); void updateRDerivatives(); double computeDerivativeTheta1(const EdgeType &e, const VertexIndex &evi, const VertexIndex &dwrt_evi, const DoFType &dwrt_dofi) const; // void updatePositionsOnTheFly( // const std::unordered_map> // &fixedVertices); void updateResidualForcesOnTheFly( const std::unordered_map> &fixedVertices); void updatePositionsOnTheFly( const std::unordered_map> &fixedVertices); void updateNodeNormal( VertexType &v, const std::unordered_map> &fixedVertices); void applyForcedNormals( const std::unordered_map nodalForcedRotations); void printCurrentState() const; void printDebugInfo() const; double computeTotalInternalPotentialEnergy(); void applySolutionGuess(const SimulationResults &solutionGuess, const std::shared_ptr &pJob); void updateNodeNr(VertexType &v); public: DRMSimulationModel(); SimulationResults executeSimulation(const std::shared_ptr &pJob, const Settings &settings = Settings(), const SimulationResults &solutionGuess = SimulationResults()); static void runUnitTests(); }; template PointType Cross(PointType p1, PointType p2) { return p1 ^ p2; } inline size_t currentStep{0}; inline bool TriggerBreakpoint(const VertexIndex &vi, const EdgeIndex &ei, const DoFType &dofi) { const size_t numberOfVertices = 10; const VertexIndex middleNodeIndex = numberOfVertices / 2; // return vi == middleNodeIndex && dofi == 1; return dofi == 1 && ((vi == 1 && ei == 0) || (vi == 9 && ei == 9)); } inline bool TriggerBreakpoint(const VertexIndex &vi, const EdgeIndex &ei) { const size_t numberOfVertices = 10; const VertexIndex middleNodeIndex = numberOfVertices / 2; return (vi == middleNodeIndex); // return (vi == 0 || vi == numberOfVertices - 1) && currentStep == 1; return (vi == 1 && ei == 0) || (vi == 9 && ei == 9); } #endif // BEAMFORMFINDER_HPP