//#####################################################################
// Copyright 2002-2007, Robert Bridson, Ronald Fedkiw, Geoffrey Irving, Neil Molino, Igor Neverov, Andrew Selle, Tamar Shinar, Eftychios Sifakis, Joseph Teran.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class LINEAR_ALTITUDE_SPRINGS_3D
//#####################################################################
#ifndef __LINEAR_ALTITUDE_SPRINGS_3D__
#define __LINEAR_ALTITUDE_SPRINGS_3D__

#include <Core/Meshes/TETRAHEDRALIZED_VOLUME.h>
#include <Deformables/Forces/LINEAR_ALTITUDE_SPRINGS.h>
namespace PhysBAM{

template<class T>
class LINEAR_ALTITUDE_SPRINGS_3D:public LINEAR_ALTITUDE_SPRINGS<VECTOR<T,3>,3>
{
    typedef VECTOR<T,3> TV;typedef typename TV::SPIN T_SPIN;
    typedef LINEAR_ALTITUDE_SPRINGS<VECTOR<T,3>,3> BASE;typedef typename BASE::SPRING_STATE SPRING_STATE;typedef typename BASE::SPRING_PARAMETER SPRING_PARAMETER;
    using BASE::use_springs_compressed_beyond_threshold;using BASE::spring_compression_fraction_threshold;using BASE::print_number_used;
    using BASE::force_elements;
public:
    using BASE::particles;using BASE::Invalidate_CFL;
    using BASE::max_strain_per_time_step;using BASE::mesh;using BASE::use_rest_state_for_strain_rate;
    using BASE::spring_states;using BASE::spring_states_all_springs;
    using BASE::use_plasticity;using BASE::use_shortest_spring_only;
    using BASE::cache_strain;using BASE::strains_of_spring;using BASE::strains_of_spring_all_springs;
    using BASE::parameters;using BASE::Compute_Plasticity;

    LINEAR_ALTITUDE_SPRINGS_3D(DEFORMABLE_PARTICLES<TV>& particles,TETRAHEDRON_MESH& tetrahedron_mesh);
    virtual ~LINEAR_ALTITUDE_SPRINGS_3D();

//#####################################################################
    void Set_Restlength_From_Particles();
    void Set_Restlength_From_Material_Coordinates(ARRAY_VIEW<const TV> material_coordinates);
    void Set_Overdamping_Fraction(const T overdamping_fraction); // 1 is critically damped
    void Set_Overdamping_Fraction(const ARRAY<VECTOR<T,4> >& overdamping_fraction); // 1 is critically damped
    void Fill_Node_Indices(int i,int j,int k,int l,int isolated_node_number,int& node1,int& node2,int& node3,int& node4) const;
    bool Fill_Spring_State(int t,int isolated_node_number,int node1,int node2,int node3,int node4,SPRING_STATE& state);
    void Update_Position_Based_State(const T time,const bool is_position_update,const bool update_hessian) override;
    void Add_Forces(ARRAY_VIEW<TV> F,const T time) const override;
    void Add_Velocity_Dependent_Forces(ARRAY_VIEW<const TV> V,ARRAY_VIEW<TV> F,const T time) const override;
    void Add_Force_Derivatives(ARRAY_VIEW<const TV> V,ARRAY_VIEW<TV> F,const T time,bool transpose=false) const override;
    bool Compute_Strain_Rate_And_Strain(int t,int isolated_node_number,int node1,int node2,int node3,int node4,T& strain_rate,T& strain) const;
    T CFL_Strain_Rate() const override;

    T Potential_Energy(const int t,const T time) const;
    T Potential_Energy(const T time) const override;
//#####################################################################
};

template<class T> LINEAR_ALTITUDE_SPRINGS_3D<T>*
Create_Altitude_Springs(DEFORMABLE_PARTICLES<VECTOR<T,3> >& particles,TETRAHEDRON_MESH& mesh,
    const T stiffness=200,const T overdamping_fraction=2,const bool use_compressed_by_threshold_only=true,const T fraction_compression=.1,const bool limit_time_step_by_strain_rate=true,
    const T max_strain_per_time_step=.1,const bool use_rest_state_for_strain_rate=true,const T restlength_enlargement_fraction=0,const bool verbose=true);

template<class T> LINEAR_ALTITUDE_SPRINGS_3D<T>*
Create_Altitude_Springs(TETRAHEDRALIZED_VOLUME<T>& tetrahedralized_volume,
    const T stiffness=4/(1+sqrt((T)2)),const T overdamping_fraction=2,const bool use_compressed_by_threshold_only=true,const T fraction_compression=.1,
    const bool limit_time_step_by_strain_rate=true,const T max_strain_per_time_step=.1,const bool use_rest_state_for_strain_rate=true,const T restlength_enlargement_fraction=0,
    const bool verbose=true);

}
#endif
