/*
Copyright 2007-2023. Algoryx Simulation AB.

All AGX source code, intellectual property, documentation, sample code,
tutorials, scene files and technical white papers, are copyrighted, proprietary
and confidential material of Algoryx Simulation AB. You may not download, read,
store, distribute, publish, copy or otherwise disseminate, use or expose this
material unless having a written signed agreement with Algoryx Simulation AB, or having been
advised so by Algoryx Simulation AB for a time limited evaluation, or having purchased a
valid commercial license from Algoryx Simulation AB.

Algoryx Simulation AB disclaims all responsibilities for loss or damage caused
from using this software, unless otherwise stated in written agreements with
Algoryx Simulation AB.
*/


#ifndef AGXHYDRAULICS_VARIABLE_DISPLACEMENT_PUMP_H
#define AGXHYDRAULICS_VARIABLE_DISPLACEMENT_PUMP_H

#include <agxPowerLine/TranslationalUnit.h>
#include <agxHydraulics/PressureConnector.h>


namespace agxPowerLine
{
  class RotationalDimension;
}

namespace agxHydraulics
{
  AGX_DECLARE_POINTER_TYPES(VariableDisplacementPump);


  /**
  The VariableDisplacementPump is a pressure regulated pump that automatically
  alters its own displacement in order to maintain a target pressure. As the
  pressure increases above the cutoff pressure the displacement is reduced in
  order to maintain the target pressure.

  The pressure at which the displacement starts to decrease is called the
  cutoff pressure and the pressure at which the displacement reaches zero is
  called the deadhead pressure. The pump is then completely passive.

  The pressure regulation is realized using a poppet called the regulator. The
  regulator is pushed on by the fluid in the pump, but held in place by a
  spring. The larger the area the larger the force on the poppet and the
  quicker the pump will respond to changes in the pressure. However, a too
  quickly responding regulator may start to oscilate after a sudden pressure
  change.

  The pump has an internal leakage parameter that defines the leakage in the
  pump as the pressure increases.
  */
  class AGXHYDRAULICS_EXPORT VariableDisplacementPump : public agxHydraulics::PressureConnector
  {
    public:
      /**
      \param cutoffPressure - The pressure at which displacement starts to
                              decrease rapidly with increasing pressure.
      \param deadheadPressure - The pressure above which the pump produces no flow.
      \param internalLeakage - Leakage-per-pressure parameter.
      \param displacement - Fluid volume displaced per radian of rotation at the input.
      \param regulatorArea - The responsiveness of the regulator.
      */
      VariableDisplacementPump(
          agx::Real cutoffPressure, agx::Real deadheadPressure,
          agx::Real internalLeakage, agx::Real displacement,
          agx::Real regulatorArea);


      /**
      Set displacement of the pump, i.e., the volume of fluid moved for every
      unit of rotation of the input shaft, while the pressure is less than the
      cutoff pressure.
      */
      void setDisplacement(agx::Real displacement);

      /**
      \return The volume of fluid moved for every unit of rotation of the input
              shaft for pressures less than the cutoff pressure.
      */
      agx::Real getDisplacement() const;


      /**
      \return The area of the contact surface between the fluid and the regulator.
      */
      agx::Real getRegulatorArea() const;


      /**
      \return The pressure at which the pump reaches zero displacement.
      */
      agx::Real getDeadheadPressure() const;


      /**
      \return The pressure currently generated by the pump.
      */
      virtual agx::Real getPressure() const override;





    // Deprecated methods.
    public:
      /**
      \deprecated Use getDeadheadPressure instead.
      \see getDeadheadPressure
      \return The deadhead pressure.
      */
      agx::Real getMaximumPressure() const;

      /**
      \deprecated Uset getDisplacement instead.
      \see getDisplacement
      \return The volume of fluid moved for every unit of rotation of the input shaft.
      */
      agx::Real getFlowRatio() const;

      /**
      \deprecated Use setDisplacement instead.
      \see setDisplacement
      Set the volume of fluid that is moved for every unit of rotation of the input shaft.
      */
      void setFlowRatio(agx::Real ratio);


      /**
      \deprecated Use getRegulatorArea instead.
      \see getRegulatorArea
      \return The area of the regulator.
      */
      agx::Real getCompensatorArea() const;



    // Methods called by the rest of the PowerLine/Hydraulics frame work.
    public:
      DOXYGEN_START_INTERNAL_BLOCK()
#ifndef SWIG
      /**
      Stores internal data into stream.
      */
      virtual bool store(agxStream::StorageStream& str) const override;

      /**
      Restores internal data from stream.
      */
      virtual bool restore(agxStream::StorageStream& str) override;

      AGXSTREAM_DECLARE_SERIALIZABLE(agxHydraulics::VariableDisplacementPump);
      VariableDisplacementPump() {}
#endif

      /**
      */
      agx::ElementaryConstraint* getSpringForceConstraint() const;

      /**
      */
      agx::ElementaryConstraint* getUpperSpringStopperConstraint() const;

      /**
      */
      agx::ElementaryConstraint* getLowerSpringStopperConstraint() const;


      /**
      Inform the pump of which RotationalDimension it is connected to. Called
      by the PumpConstraintImplementation when it is informed of the connections
      included in the constraint.
      */
      void setRotationalDimension(agxPowerLine::RotationalDimension* rotationalDimension);

      /**
      \return The RotationalDimension that is connected to the input of the pump.
      */
      agxPowerLine::RotationalDimension* getRotationalDimension();

      /**
      \return The TranslationalDimension representing the poppet. This is an
      internal dimension owned by the pump.
      */
      agxPowerLine::TranslationalDimension* getPoppetDimension();

      /**
      Create the multibody pump constraint. It connects the input rotational
      dimension to the connected output flow dimensions and to the poppet
      translational dimension.
      */
      virtual agxPowerLine::PhysicalDimensionMultiBodyConstraintImplementation* createConstraint() override;

      DOXYGEN_END_INTERNAL_BLOCK()

      virtual agx::RegularizationParameters::VariableType calculateComplianceAndDamping(
          const agx::Real timeStep, agx::Real& compliance, agx::Real& damping) override;

      DOXYGEN_START_INTERNAL_BLOCK()

      /**
      Add the constraint that holds the poppet in place to a Simulation.
      Called by the PumpConstraintImplementation when it knows
      which Simulation that the pump is part of.
      */
      virtual bool addNotification(agxSDK::Simulation* simulation) override;

#ifndef SWIG
      virtual bool removeNotification(agxUtil::ConstraintHolder* holder, agxSDK::Simulation* simulation) override;
#endif
      DOXYGEN_END_INTERNAL_BLOCK()



    private:
      /// The physical dimension that represent the position of the spring loaded poppet.
      agxPowerLine::TranslationalUnitRef m_poppetUnit;

      /// Constraint that holds the poppet at the full flow position.
      agx::ConstraintRef m_springConstraint;

      // The rotational dimension that is driving the pump. Owned by some Unit.
      agxPowerLine::RotationalDimension* m_rotationalDimension;

      agx::Real m_springRestPosition;
      agx::Real m_springConstant;

      agx::Real m_deadheadPressure;

      agx::Real m_internalLeakage;
      agx::Real m_regulatorArea;
  };
}

#endif

