/* Fesslix - Stochastic Analysis
 * Copyright (C) 2010-2016 Wolfgang Betz
 *
 * Fesslix is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Fesslix is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Fesslix.  If not, see <http://www.gnu.org/licenses/>. 
 */

#ifndef fesslix_flxfem_H
#define fesslix_flxfem_H

#include "flxfem_elements.h"


class FLXFEM_EXPORT flxStiffnessMtxBase {
  protected:
    flxFEM* FEM;
    /**
    * @brief assembly or reassembly
    */
    bool reassembly;
    /**
    * @brief Number of DOFs which are not fixed
    */
    tnlong DofA;
    /**
    * @brief Number of DOFs which are fixed
    */
    tnlong FixA;
    /**
    * @brief Number of DOFs which are fixed and have a predescribed displacement
    */
    tnlong preDispA;
    /**
    * @brief Number of DOFs (fixed and not fixed)
    */
    tnlong DofSum;
    /**
    * @brief Stiffness Matrix (DofAxDofA)
    */
    FlxMtx_baseS* StfMtx;
    /**
    * @brief Stiffness Matrix (preDispAxDofA)
    */
    FlxMtxSpars** StfMtx_2x;
    /**
    * @brief Force Vector (DofA)
    */
    flxVec* ForceVec;
    flxVec* ForceVec_fixed;
    flxVec* ForceVec_internal;
    flxVec* ForceVec_internal_fixed;
    /**
    * @brief Force Vector for predisplacements (DofA)
    */
    flxVec* ForceVec_2;
    /**
    * @brief Solution Vector (DofA)
    */
    flxVec* SolutionVec;
    /**
    * @brief predisplacement vector (preDispA)
    */
    flxVec* preDisplVec;
    /**
    * @brief Assembly-Matrices (1)
    */
    FlxMtxSym* Mtx1;
    /**
    * @brief Assembly-Matrices (2)
    */
    FlxMtx** Mtx2x;
    /**
    * @brief create the stiffness matrix from MtxX
    */
    virtual void build_stf();
    /**
    * @brief prepares the stiffness matrix for reassembly
    */
    virtual void prepare_stf_for_reassembly();
    /**
    * @brief returns true if this matrix is already assembled
    */
    const bool Stf_is_assembled()const {return reassembly;};
    /**
    * @brief allocate memory for the solution vector
    */
    virtual void allocate_SolutionVec() = 0;
  public:
    /**
    * @brief assembles the DOFs of the finite element problem
    */
    flxStiffnessMtxBase(flxFEM* FEM);
    virtual ~flxStiffnessMtxBase();
    /**
    * @brief returns the size of the stiffness matrix
    */
    virtual const tnlong get_size() const { return StfMtx->ncols(); }
    const tnlong get_dofA() const {return DofA;}
    const tnlong get_dofFixA() const { return FixA;}
    /**
    * @brief returns an index corresponding to the matrix in which the index is stored
    * @brief if this function returns 0, the value is not stored at all
    * NOTE make sure i<=j
    */
    const int StfCoeff_is_stored(const tnlong i, const tnlong j) const;
    /**
    * @brief add a value to the stiffness matrix
    */
    void Stf_set_value(tnlong i, tnlong j, const tdouble& v);
    /**
    * @brief add a column vector of length N to the stiffness matrix
    */
    void Stf_set_value(tnlong i, tnlong j, const tdouble* v, const tuint N);
    /**
    * @brief add a value to the stiffness matrix
    */
    void Stf_set_predispl_value(tnlong i, const tdouble& v);
    /**
    * @brief add a value to the force vector
    */
    void ForceVec_set_value(const tnlong i, const tdouble& v);
    /**
    * @brief add a vector of length N to the force vector
    */
    void ForceVec_set_value(const tnlong i, const tdouble* v, const tuint N);
    /**
    * @brief assembles the stiffness matrix
    */
    virtual void assemble_stf();
    /**
    * @brief assembles the forces
    */
    virtual void assemble_forc(const bool errSerious=true);
    /**
    * @brief solve the system
    */
    virtual const double solve(tdouble &eps, tnlong& iter, tuint pcn, bool startZero,const bool errSerious=true, const bool verboseOutput=true);
    /**
    * @brief update the 'element' displacement vector (only for SSFEM)
    */
    void update_displVec_GeoEls();
    /**
    * @brief get component from the solution vector
    */
    virtual const tdouble get_U(const tnlong dofindex) const = 0;
    /**
    * @brief get sub-vector of length N from the solution vector ... v points to first element of sub-vector
    */
    virtual void get_U(const tnlong dofindex, tdouble *v, const tuint N) const = 0;
    /**
    * @brief get component from the force vector
    */
    virtual const tdouble get_F(const flxDOFn* Dof) = 0;
    /**
    * @brief get component from the solution vector
    */
    virtual void output_solVec(std::ostream& sout, bool verbose);
    /**
    * @brief print the stiffness matrix
    */
    virtual void output_StfMtx(std::ostream& sout);
    /**
    * @brief print the force vector
    */
    virtual void output_ForceVec(std::ostream& sout);    
    /**
    * @brief checks if the matrix is positive definite
    */
    virtual const bool isPositiveDefinite(tuint& r) const;
    /**
    * @brief returns true, if condensation is allowed
    */
    virtual const bool condensation_is_allowed() const { return true; }
};

class FLXFEM_EXPORT flxStiffnessMtxFEM : public flxStiffnessMtxBase {
  protected:
    virtual void allocate_SolutionVec();
  public:
    flxStiffnessMtxFEM(flxFEM* FEM) : flxStiffnessMtxBase(FEM) {};
    virtual ~flxStiffnessMtxFEM() {};   
    virtual const tdouble get_U(const tnlong dofindex) const;
    virtual void get_U(const tnlong dofindex, tdouble *v, const tuint N) const;
    virtual const tdouble get_F(const flxDOFn* Dof);
};

class FLXFEM_EXPORT flxFEM {
  public:
    FlxConstantBox* ConstantBox;
    flxStiffnessMtxBase* StiffnessMtx;
    flxVertexList VertexList;   
    flxEdgeList EdgeList;
    flxFaceList FaceList;
    flxBoxList BoxList;
    flxElementList ElementList;
    flxMaterialList MaterialList;
    flxCrossSecList CrossSecList;
    FlxLoadCaseBox LoadCaseBox;
  protected:
    
  public:
    flxFEM(FlxConstantBox* constBox);
    virtual ~flxFEM();
    FlxConstantBox* get_ConstantBox() {return ConstantBox;};
    virtual void assembleDOF();
    /**
    * @brief output Element properties
    */
    virtual void plot_ElProp(std::ostream& sout, const std::vector<FlxElementInfo::elInfo>& V, FlxMtxConstFun* ppdim, FlxSMtx* elmtx, const int prec, const int fixW);
};
typedef flxFEM* flxFEM_ptr;
  


#endif // fesslix_flxfem_H


