<commit_before>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_NONLININTEG
#define MFEM_NONLININTEG

#include "../config/config.hpp"
#include "fe.hpp"
#include "coefficient.hpp"
#include "fespace.hpp"

namespace mfem
{

/** @brief This class is used to express the local action of a general nonlinear
    finite element operator. In addition it may provide the capability to
    assemble the local gradient operator and to compute the local energy. */
class NonlinearFormIntegrator
{
protected:
   const IntegrationRule *IntRule;

   NonlinearFormIntegrator(const IntegrationRule *ir = NULL)
      : IntRule(ir) { }

public:
   /** @brief Prescribe a fixed IntegrationRule to use (when @a ir != NULL) or
       let the integrator choose (when @a ir == NULL). */
   void SetIntRule(const IntegrationRule *ir)
   {
      IntRule = ir;
   }

   /// Prescribe a fixed IntegrationRule to use.
   void SetIntegrationRule(const IntegrationRule &irule)
   {
      IntRule = &irule;
   }

   /// Perform the local action of the NonlinearFormIntegrator
   virtual void AssembleElementVector(const FiniteElement &el,
                                      ElementTransformation &Tr,
                                      const Vector &elfun, Vector &elvect);

   /// @brief Perform the local action of the NonlinearFormIntegrator resulting
   /// from a face integral term.
   virtual void AssembleFaceVector(const FiniteElement &el1,
                                   const FiniteElement &el2,
                                   FaceElementTransformations &Tr,
                                   const Vector &elfun, Vector &elvect);

   /// Assemble the local gradient matrix
   virtual void AssembleElementGrad(const FiniteElement &el,
                                    ElementTransformation &Tr,
                                    const Vector &elfun, DenseMatrix &elmat);

   /// @brief Assemble the local action of the gradient of the
   /// NonlinearFormIntegrator resulting from a face integral term.
   virtual void AssembleFaceGrad(const FiniteElement &el1,
                                 const FiniteElement &el2,
                                 FaceElementTransformations &Tr,
                                 const Vector &elfun, DenseMatrix &elmat);

   /// Compute the local energy
   virtual double GetElementEnergy(const FiniteElement &el,
                                   ElementTransformation &Tr,
                                   const Vector &elfun);

   /// Method defining partial assembly.
   /** The result of the partial assembly is stored internally so that it can be
       used later in the methods AddMultPA(). */
   virtual void AssemblePA(const FiniteElementSpace &fes);

   /** The result of the partial assembly is stored internally so that it can be
       used later in the methods AddMultPA().
       Used with BilinearFormIntegrators that have different spaces. */
   virtual void AssemblePA(const FiniteElementSpace &trial_fes,
                           const FiniteElementSpace &test_fes);

   /// Method for partially assembled action.
   /** Perform the action of integrator on the input @a x and add the result to
       the output @a y. Both @a x and @a y are E-vectors, i.e. they represent
       the element-wise discontinuous version of the FE space.

       This method can be called only after the method AssemblePA() has been
       called. */
   virtual void AddMultPA(const Vector &x, Vector &y) const;

   virtual ~NonlinearFormIntegrator() { }
};

/** The abstract base class BlockNonlinearFormIntegrator is
    a generalization of the NonlinearFormIntegrator class suitable
    for block state vectors. */
class BlockNonlinearFormIntegrator
{
public:
   /// Compute the local energy
   virtual double GetElementEnergy(const Array<const FiniteElement *>&el,
                                   ElementTransformation &Tr,
                                   const Array<const Vector *>&elfun);

   /// Perform the local action of the BlockNonlinearFormIntegrator
   virtual void AssembleElementVector(const Array<const FiniteElement *> &el,
                                      ElementTransformation &Tr,
                                      const Array<const Vector *> &elfun,
                                      const Array<Vector *> &elvec);

   virtual void AssembleFaceVector(const Array<const FiniteElement *> &el1,
                                   const Array<const FiniteElement *> &el2,
                                   FaceElementTransformations &Tr,
                                   const Array<const Vector *> &elfun,
                                   const Array<Vector *> &elvect);

   /// Assemble the local gradient matrix
   virtual void AssembleElementGrad(const Array<const FiniteElement*> &el,
                                    ElementTransformation &Tr,
                                    const Array<const Vector *> &elfun,
                                    const Array2D<DenseMatrix *> &elmats);

   virtual void AssembleFaceGrad(const Array<const FiniteElement *>&el1,
                                 const Array<const FiniteElement *>&el2,
                                 FaceElementTransformations &Tr,
                                 const Array<const Vector *> &elfun,
                                 const Array2D<DenseMatrix *> &elmats);

   virtual ~BlockNonlinearFormIntegrator() { }
};

/// Abstract class for hyperelastic models
class HyperelasticModel
{
protected:
   ElementTransformation *Ttr; /**< Reference-element to target-element
                                    transformation. */

public:
   HyperelasticModel() : Ttr(NULL) { }
   virtual ~HyperelasticModel() { }

   /// A reference-element to target-element transformation that can be used to
   /// evaluate Coefficient%s.
   /** @note It is assumed that _Ttr.SetIntPoint() is already called for the
       point of interest. */
   void SetTransformation(ElementTransformation &_Ttr)
   {
      Ttr = &_Ttr;
   }

   /** @brief Evaluate the strain energy density function, W = W(Jpt).
       @param[in] Jpt  Represents the target->physical transformation
                       Jacobian matrix. */
   virtual double EvalW(const DenseMatrix &Jpt) const = 0;

   /** @brief Evaluate the 1st Piola-Kirchhoff stress tensor, P = P(Jpt).
       @param[in] Jpt  Represents the target->physical transformation
                       Jacobian matrix.
       @param[out]  P  The evaluated 1st Piola-Kirchhoff stress tensor. */
   virtual void EvalP(const DenseMatrix &Jpt, DenseMatrix &P) const = 0;

   /** @brief Evaluate the derivative of the 1st Piola-Kirchhoff stress tensor
       and assemble its contribution to the local gradient matrix 'A'.
       @param[in] Jpt     Represents the target->physical transformation
                          Jacobian matrix.
       @param[in] DS      Gradient of the basis matrix (dof x dim).
       @param[in] weight  Quadrature weight coefficient for the point.
       @param[in,out]  A  Local gradient matrix where the contribution from this
                          point will be added.

       Computes weight * d(dW_dxi)_d(xj) at the current point, for all i and j,
       where x1 ... xn are the FE dofs. This function is usually defined using
       the matrix invariants and their derivatives.
   */
   virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
                          const double weight, DenseMatrix &A) const = 0;
};

/** Inverse-harmonic hyperelastic model with a strain energy density function
    given by the formula: W(J) = (1/2) det(J) Tr((J J^t)^{-1}) where J is the
    deformation gradient. */
class InverseHarmonicModel : public HyperelasticModel
{
protected:
   mutable DenseMatrix Z, S; // dim x dim
   mutable DenseMatrix G, C; // dof x dim

public:
   virtual double EvalW(const DenseMatrix &J) const;

   virtual void EvalP(const DenseMatrix &J, DenseMatrix &P) const;

   virtual void AssembleH(const DenseMatrix &J, const DenseMatrix &DS,
                          const double weight, DenseMatrix &A) const;
};

/** Neo-Hookean hyperelastic model with a strain energy density function given
    by the formula: \f$(\mu/2)(\bar{I}_1 - dim) + (K/2)(det(J)/g - 1)^2\f$ where
    J is the deformation gradient and \f$\bar{I}_1 = (det(J))^{-2/dim} Tr(J
    J^t)\f$. The parameters \f$\mu\f$ and K are the shear and bulk moduli,
    respectively, and g is a reference volumetric scaling. */
class NeoHookeanModel : public HyperelasticModel
{
protected:
   mutable double mu, K, g;
   Coefficient *c_mu, *c_K, *c_g;
   bool have_coeffs;

   mutable DenseMatrix Z;    // dim x dim
   mutable DenseMatrix G, C; // dof x dim

   inline void EvalCoeffs() const;

public:
   NeoHookeanModel(double _mu, double _K, double _g = 1.0)
      : mu(_mu), K(_K), g(_g), have_coeffs(false)
   {
      c_mu = c_K = c_g = NULL;
   }

   NeoHookeanModel(Coefficient &_mu, Coefficient &_K, Coefficient *_g = NULL)
      : mu(0.0), K(0.0), g(1.0), c_mu(&_mu), c_K(&_K), c_g(_g),
        have_coeffs(true) { }

   virtual double EvalW(const DenseMatrix &J) const;

   virtual void EvalP(const DenseMatrix &J, DenseMatrix &P) const;

   virtual void AssembleH(const DenseMatrix &J, const DenseMatrix &DS,
                          const double weight, DenseMatrix &A) const;
};

/** Hyperelastic integrator for any given HyperelasticModel.

    Represents @f$ \int W(Jpt) dx @f$ over a target zone, where W is the
    @a model's strain energy density function, and Jpt is the Jacobian of the
    target->physical coordinates transformation. The target configuration is
    given by the current mesh at the time of the evaluation of the integrator.
*/
class HyperelasticNLFIntegrator : public NonlinearFormIntegrator
{
private:
   HyperelasticModel *model;

   //   Jrt: the Jacobian of the target-to-reference-element transformation.
   //   Jpr: the Jacobian of the reference-to-physical-element transformation.
   //   Jpt: the Jacobian of the target-to-physical-element transformation.
   //     P: represents dW_d(Jtp) (dim x dim).
   //   DSh: gradients of reference shape functions (dof x dim).
   //    DS: gradients of the shape functions in the target (stress-free)
   //        configuration (dof x dim).
   // PMatI: coordinates of the deformed configuration (dof x dim).
   // PMatO: reshaped view into the local element contribution to the operator
   //        output - the result of AssembleElementVector() (dof x dim).
   DenseMatrix DSh, DS, Jrt, Jpr, Jpt, P, PMatI, PMatO;

public:
   /** @param[in] m  HyperelasticModel that will be integrated. */
   HyperelasticNLFIntegrator(HyperelasticModel *m) : model(m) { }

   /** @brief Computes the integral of W(Jacobian(Trt)) over a target zone
       @param[in] el     Type of FiniteElement.
       @param[in] Ttr    Represents ref->target coordinates transformation.
       @param[in] elfun  Physical coordinates of the zone. */
   virtual double GetElementEnergy(const FiniteElement &el,
                                   ElementTransformation &Ttr,
                                   const Vector &elfun);

   virtual void AssembleElementVector(const FiniteElement &el,
                                      ElementTransformation &Ttr,
                                      const Vector &elfun, Vector &elvect);

   virtual void AssembleElementGrad(const FiniteElement &el,
                                    ElementTransformation &Ttr,
                                    const Vector &elfun, DenseMatrix &elmat);
};

/** Hyperelastic incompressible Neo-Hookean integrator with the PK1 stress
    \f$P = \mu F - p F^{-T}\f$ where \f$\mu\f$ is the shear modulus,
    \f$p\f$ is the pressure, and \f$F\f$ is the deformation gradient */
class IncompressibleNeoHookeanIntegrator : public BlockNonlinearFormIntegrator
{
private:
   Coefficient *c_mu;
   DenseMatrix DSh_u, DS_u, J0i, J, J1, Finv, P, F, FinvT;
   DenseMatrix PMatI_u, PMatO_u, PMatI_p, PMatO_p, Z, G, C;
   Vector Sh_p;

public:
   IncompressibleNeoHookeanIntegrator(Coefficient &_mu) : c_mu(&_mu) { }

   virtual double GetElementEnergy(const Array<const FiniteElement *>&el,
                                   ElementTransformation &Tr,
                                   const Array<const Vector *> &elfun);

   /// Perform the local action of the NonlinearFormIntegrator
   virtual void AssembleElementVector(const Array<const FiniteElement *> &el,
                                      ElementTransformation &Tr,
                                      const Array<const Vector *> &elfun,
                                      const Array<Vector *> &elvec);

   /// Assemble the local gradient matrix
   virtual void AssembleElementGrad(const Array<const FiniteElement*> &el,
                                    ElementTransformation &Tr,
                                    const Array<const Vector *> &elfun,
                                    const Array2D<DenseMatrix *> &elmats);
};

class VectorConvectionNLFIntegrator : public NonlinearFormIntegrator
{
private:
   Coefficient *Q{};
   DenseMatrix dshape, dshapex, EF, gradEF, ELV, elmat_comp;
   Vector shape;
   // PA extension
   Vector pa_data;
   const DofToQuad *maps;         ///< Not owned
   const GeometricFactors *geom;  ///< Not owned
   int dim, ne, nq;
public:
   VectorConvectionNLFIntegrator(Coefficient &q): Q(&q) { }

   VectorConvectionNLFIntegrator() = default;

   static const IntegrationRule &GetRule(const FiniteElement &fe,
                                         ElementTransformation &T);

   virtual void AssembleElementVector(const FiniteElement &el,
                                      ElementTransformation &trans,
                                      const Vector &elfun,
                                      Vector &elvect);

   virtual void AssembleElementGrad(const FiniteElement &el,
                                    ElementTransformation &trans,
                                    const Vector &elfun,
                                    DenseMatrix &elmat);

   using NonlinearFormIntegrator::AssemblePA;

   virtual void AssemblePA(const FiniteElementSpace &fes);

   virtual void AddMultPA(const Vector &x, Vector &y) const;
};

/** @brief This class is used to assemble the skew-symmetric form of the
nonlinear  term arising in the Navier Stokes equations
\f$(u \cdot \nabla v, w )\f$*/
class ConvectiveVectorConvectionNLFIntegrator : public VectorConvectionNLFIntegrator
{
private:
   Coefficient *Q{};
   DenseMatrix dshape, dshapex, EF, gradEF, ELV, elmat_comp;
   Vector shape;
public:
   ConvectiveVectorConvectionNLFIntegrator(Coefficient &q): Q(&q) { }

   ConvectiveVectorConvectionNLFIntegrator() = default;

   static const IntegrationRule &GetRule(const FiniteElement &fe,
                                         ElementTransformation &T);

   virtual void AssembleElementGrad(const FiniteElement &el,
                                    ElementTransformation &trans,
                                    const Vector &elfun,
                                    DenseMatrix &elmat);

};
/** @brief This class is used to assemble the skew-symmetric form of the nonlinear
term arising in the Navier Stokes equations \f$.5*(u \cdot \nabla v, w ) -
.5*(u \cdot \nabla w, v )\f$ */
class SkewSymmetricVectorConvectionNLFIntegrator : public
   NonlinearFormIntegrator
{
private:
   Coefficient *Q{};
   DenseMatrix dshape, dshapex, EF, gradEF, ELV, elmat_comp;
   Vector shape;
public:
   SkewSymmetricVectorConvectionNLFIntegrator(Coefficient &q): Q(&q) { }

   SkewSymmetricVectorConvectionNLFIntegrator() = default;

   static const IntegrationRule &GetRule(const FiniteElement &fe,
                                         ElementTransformation &T);

   virtual void AssembleElementGrad(const FiniteElement &el,
                                    ElementTransformation &trans,
                                    const Vector &elfun,
                                    DenseMatrix &elmat);

};

}

#endif
<commit_msg>switch integrator to inherit from VectorConvectionNLFIntegrator<commit_after>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_NONLININTEG
#define MFEM_NONLININTEG

#include "../config/config.hpp"
#include "fe.hpp"
#include "coefficient.hpp"
#include "fespace.hpp"

namespace mfem
{

/** @brief This class is used to express the local action of a general nonlinear
    finite element operator. In addition it may provide the capability to
    assemble the local gradient operator and to compute the local energy. */
class NonlinearFormIntegrator
{
protected:
   const IntegrationRule *IntRule;

   NonlinearFormIntegrator(const IntegrationRule *ir = NULL)
      : IntRule(ir) { }

public:
   /** @brief Prescribe a fixed IntegrationRule to use (when @a ir != NULL) or
       let the integrator choose (when @a ir == NULL). */
   void SetIntRule(const IntegrationRule *ir)
   {
      IntRule = ir;
   }

   /// Prescribe a fixed IntegrationRule to use.
   void SetIntegrationRule(const IntegrationRule &irule)
   {
      IntRule = &irule;
   }

   /// Perform the local action of the NonlinearFormIntegrator
   virtual void AssembleElementVector(const FiniteElement &el,
                                      ElementTransformation &Tr,
                                      const Vector &elfun, Vector &elvect);

   /// @brief Perform the local action of the NonlinearFormIntegrator resulting
   /// from a face integral term.
   virtual void AssembleFaceVector(const FiniteElement &el1,
                                   const FiniteElement &el2,
                                   FaceElementTransformations &Tr,
                                   const Vector &elfun, Vector &elvect);

   /// Assemble the local gradient matrix
   virtual void AssembleElementGrad(const FiniteElement &el,
                                    ElementTransformation &Tr,
                                    const Vector &elfun, DenseMatrix &elmat);

   /// @brief Assemble the local action of the gradient of the
   /// NonlinearFormIntegrator resulting from a face integral term.
   virtual void AssembleFaceGrad(const FiniteElement &el1,
                                 const FiniteElement &el2,
                                 FaceElementTransformations &Tr,
                                 const Vector &elfun, DenseMatrix &elmat);

   /// Compute the local energy
   virtual double GetElementEnergy(const FiniteElement &el,
                                   ElementTransformation &Tr,
                                   const Vector &elfun);

   /// Method defining partial assembly.
   /** The result of the partial assembly is stored internally so that it can be
       used later in the methods AddMultPA(). */
   virtual void AssemblePA(const FiniteElementSpace &fes);

   /** The result of the partial assembly is stored internally so that it can be
       used later in the methods AddMultPA().
       Used with BilinearFormIntegrators that have different spaces. */
   virtual void AssemblePA(const FiniteElementSpace &trial_fes,
                           const FiniteElementSpace &test_fes);

   /// Method for partially assembled action.
   /** Perform the action of integrator on the input @a x and add the result to
       the output @a y. Both @a x and @a y are E-vectors, i.e. they represent
       the element-wise discontinuous version of the FE space.

       This method can be called only after the method AssemblePA() has been
       called. */
   virtual void AddMultPA(const Vector &x, Vector &y) const;

   virtual ~NonlinearFormIntegrator() { }
};

/** The abstract base class BlockNonlinearFormIntegrator is
    a generalization of the NonlinearFormIntegrator class suitable
    for block state vectors. */
class BlockNonlinearFormIntegrator
{
public:
   /// Compute the local energy
   virtual double GetElementEnergy(const Array<const FiniteElement *>&el,
                                   ElementTransformation &Tr,
                                   const Array<const Vector *>&elfun);

   /// Perform the local action of the BlockNonlinearFormIntegrator
   virtual void AssembleElementVector(const Array<const FiniteElement *> &el,
                                      ElementTransformation &Tr,
                                      const Array<const Vector *> &elfun,
                                      const Array<Vector *> &elvec);

   virtual void AssembleFaceVector(const Array<const FiniteElement *> &el1,
                                   const Array<const FiniteElement *> &el2,
                                   FaceElementTransformations &Tr,
                                   const Array<const Vector *> &elfun,
                                   const Array<Vector *> &elvect);

   /// Assemble the local gradient matrix
   virtual void AssembleElementGrad(const Array<const FiniteElement*> &el,
                                    ElementTransformation &Tr,
                                    const Array<const Vector *> &elfun,
                                    const Array2D<DenseMatrix *> &elmats);

   virtual void AssembleFaceGrad(const Array<const FiniteElement *>&el1,
                                 const Array<const FiniteElement *>&el2,
                                 FaceElementTransformations &Tr,
                                 const Array<const Vector *> &elfun,
                                 const Array2D<DenseMatrix *> &elmats);

   virtual ~BlockNonlinearFormIntegrator() { }
};

/// Abstract class for hyperelastic models
class HyperelasticModel
{
protected:
   ElementTransformation *Ttr; /**< Reference-element to target-element
                                    transformation. */

public:
   HyperelasticModel() : Ttr(NULL) { }
   virtual ~HyperelasticModel() { }

   /// A reference-element to target-element transformation that can be used to
   /// evaluate Coefficient%s.
   /** @note It is assumed that _Ttr.SetIntPoint() is already called for the
       point of interest. */
   void SetTransformation(ElementTransformation &_Ttr)
   {
      Ttr = &_Ttr;
   }

   /** @brief Evaluate the strain energy density function, W = W(Jpt).
       @param[in] Jpt  Represents the target->physical transformation
                       Jacobian matrix. */
   virtual double EvalW(const DenseMatrix &Jpt) const = 0;

   /** @brief Evaluate the 1st Piola-Kirchhoff stress tensor, P = P(Jpt).
       @param[in] Jpt  Represents the target->physical transformation
                       Jacobian matrix.
       @param[out]  P  The evaluated 1st Piola-Kirchhoff stress tensor. */
   virtual void EvalP(const DenseMatrix &Jpt, DenseMatrix &P) const = 0;

   /** @brief Evaluate the derivative of the 1st Piola-Kirchhoff stress tensor
       and assemble its contribution to the local gradient matrix 'A'.
       @param[in] Jpt     Represents the target->physical transformation
                          Jacobian matrix.
       @param[in] DS      Gradient of the basis matrix (dof x dim).
       @param[in] weight  Quadrature weight coefficient for the point.
       @param[in,out]  A  Local gradient matrix where the contribution from this
                          point will be added.

       Computes weight * d(dW_dxi)_d(xj) at the current point, for all i and j,
       where x1 ... xn are the FE dofs. This function is usually defined using
       the matrix invariants and their derivatives.
   */
   virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
                          const double weight, DenseMatrix &A) const = 0;
};

/** Inverse-harmonic hyperelastic model with a strain energy density function
    given by the formula: W(J) = (1/2) det(J) Tr((J J^t)^{-1}) where J is the
    deformation gradient. */
class InverseHarmonicModel : public HyperelasticModel
{
protected:
   mutable DenseMatrix Z, S; // dim x dim
   mutable DenseMatrix G, C; // dof x dim

public:
   virtual double EvalW(const DenseMatrix &J) const;

   virtual void EvalP(const DenseMatrix &J, DenseMatrix &P) const;

   virtual void AssembleH(const DenseMatrix &J, const DenseMatrix &DS,
                          const double weight, DenseMatrix &A) const;
};

/** Neo-Hookean hyperelastic model with a strain energy density function given
    by the formula: \f$(\mu/2)(\bar{I}_1 - dim) + (K/2)(det(J)/g - 1)^2\f$ where
    J is the deformation gradient and \f$\bar{I}_1 = (det(J))^{-2/dim} Tr(J
    J^t)\f$. The parameters \f$\mu\f$ and K are the shear and bulk moduli,
    respectively, and g is a reference volumetric scaling. */
class NeoHookeanModel : public HyperelasticModel
{
protected:
   mutable double mu, K, g;
   Coefficient *c_mu, *c_K, *c_g;
   bool have_coeffs;

   mutable DenseMatrix Z;    // dim x dim
   mutable DenseMatrix G, C; // dof x dim

   inline void EvalCoeffs() const;

public:
   NeoHookeanModel(double _mu, double _K, double _g = 1.0)
      : mu(_mu), K(_K), g(_g), have_coeffs(false)
   {
      c_mu = c_K = c_g = NULL;
   }

   NeoHookeanModel(Coefficient &_mu, Coefficient &_K, Coefficient *_g = NULL)
      : mu(0.0), K(0.0), g(1.0), c_mu(&_mu), c_K(&_K), c_g(_g),
        have_coeffs(true) { }

   virtual double EvalW(const DenseMatrix &J) const;

   virtual void EvalP(const DenseMatrix &J, DenseMatrix &P) const;

   virtual void AssembleH(const DenseMatrix &J, const DenseMatrix &DS,
                          const double weight, DenseMatrix &A) const;
};

/** Hyperelastic integrator for any given HyperelasticModel.

    Represents @f$ \int W(Jpt) dx @f$ over a target zone, where W is the
    @a model's strain energy density function, and Jpt is the Jacobian of the
    target->physical coordinates transformation. The target configuration is
    given by the current mesh at the time of the evaluation of the integrator.
*/
class HyperelasticNLFIntegrator : public NonlinearFormIntegrator
{
private:
   HyperelasticModel *model;

   //   Jrt: the Jacobian of the target-to-reference-element transformation.
   //   Jpr: the Jacobian of the reference-to-physical-element transformation.
   //   Jpt: the Jacobian of the target-to-physical-element transformation.
   //     P: represents dW_d(Jtp) (dim x dim).
   //   DSh: gradients of reference shape functions (dof x dim).
   //    DS: gradients of the shape functions in the target (stress-free)
   //        configuration (dof x dim).
   // PMatI: coordinates of the deformed configuration (dof x dim).
   // PMatO: reshaped view into the local element contribution to the operator
   //        output - the result of AssembleElementVector() (dof x dim).
   DenseMatrix DSh, DS, Jrt, Jpr, Jpt, P, PMatI, PMatO;

public:
   /** @param[in] m  HyperelasticModel that will be integrated. */
   HyperelasticNLFIntegrator(HyperelasticModel *m) : model(m) { }

   /** @brief Computes the integral of W(Jacobian(Trt)) over a target zone
       @param[in] el     Type of FiniteElement.
       @param[in] Ttr    Represents ref->target coordinates transformation.
       @param[in] elfun  Physical coordinates of the zone. */
   virtual double GetElementEnergy(const FiniteElement &el,
                                   ElementTransformation &Ttr,
                                   const Vector &elfun);

   virtual void AssembleElementVector(const FiniteElement &el,
                                      ElementTransformation &Ttr,
                                      const Vector &elfun, Vector &elvect);

   virtual void AssembleElementGrad(const FiniteElement &el,
                                    ElementTransformation &Ttr,
                                    const Vector &elfun, DenseMatrix &elmat);
};

/** Hyperelastic incompressible Neo-Hookean integrator with the PK1 stress
    \f$P = \mu F - p F^{-T}\f$ where \f$\mu\f$ is the shear modulus,
    \f$p\f$ is the pressure, and \f$F\f$ is the deformation gradient */
class IncompressibleNeoHookeanIntegrator : public BlockNonlinearFormIntegrator
{
private:
   Coefficient *c_mu;
   DenseMatrix DSh_u, DS_u, J0i, J, J1, Finv, P, F, FinvT;
   DenseMatrix PMatI_u, PMatO_u, PMatI_p, PMatO_p, Z, G, C;
   Vector Sh_p;

public:
   IncompressibleNeoHookeanIntegrator(Coefficient &_mu) : c_mu(&_mu) { }

   virtual double GetElementEnergy(const Array<const FiniteElement *>&el,
                                   ElementTransformation &Tr,
                                   const Array<const Vector *> &elfun);

   /// Perform the local action of the NonlinearFormIntegrator
   virtual void AssembleElementVector(const Array<const FiniteElement *> &el,
                                      ElementTransformation &Tr,
                                      const Array<const Vector *> &elfun,
                                      const Array<Vector *> &elvec);

   /// Assemble the local gradient matrix
   virtual void AssembleElementGrad(const Array<const FiniteElement*> &el,
                                    ElementTransformation &Tr,
                                    const Array<const Vector *> &elfun,
                                    const Array2D<DenseMatrix *> &elmats);
};

class VectorConvectionNLFIntegrator : public NonlinearFormIntegrator
{
private:
   Coefficient *Q{};
   DenseMatrix dshape, dshapex, EF, gradEF, ELV, elmat_comp;
   Vector shape;
   // PA extension
   Vector pa_data;
   const DofToQuad *maps;         ///< Not owned
   const GeometricFactors *geom;  ///< Not owned
   int dim, ne, nq;
public:
   VectorConvectionNLFIntegrator(Coefficient &q): Q(&q) { }

   VectorConvectionNLFIntegrator() = default;

   static const IntegrationRule &GetRule(const FiniteElement &fe,
                                         ElementTransformation &T);

   virtual void AssembleElementVector(const FiniteElement &el,
                                      ElementTransformation &trans,
                                      const Vector &elfun,
                                      Vector &elvect);

   virtual void AssembleElementGrad(const FiniteElement &el,
                                    ElementTransformation &trans,
                                    const Vector &elfun,
                                    DenseMatrix &elmat);

   using NonlinearFormIntegrator::AssemblePA;

   virtual void AssemblePA(const FiniteElementSpace &fes);

   virtual void AddMultPA(const Vector &x, Vector &y) const;
};

/** @brief This class is used to assemble the skew-symmetric form of the
nonlinear  term arising in the Navier Stokes equations
\f$(u \cdot \nabla v, w )\f$*/
class ConvectiveVectorConvectionNLFIntegrator : public VectorConvectionNLFIntegrator
{
public:
   ConvectiveVectorConvectionNLFIntegrator(Coefficient &q): Q(&q) { }

   ConvectiveVectorConvectionNLFIntegrator() = default;

   virtual void AssembleElementGrad(const FiniteElement &el,
                                    ElementTransformation &trans,
                                    const Vector &elfun,
                                    DenseMatrix &elmat);

};
/** @brief This class is used to assemble the skew-symmetric form of the nonlinear
term arising in the Navier Stokes equations \f$.5*(u \cdot \nabla v, w ) -
.5*(u \cdot \nabla w, v )\f$ */
class SkewSymmetricVectorConvectionNLFIntegrator : public
   VectorConvectionNLFIntegrator
{
public:
   SkewSymmetricVectorConvectionNLFIntegrator(Coefficient &q): Q(&q) { }

   SkewSymmetricVectorConvectionNLFIntegrator() = default;

   virtual void AssembleElementGrad(const FiniteElement &el,
                                    ElementTransformation &trans,
                                    const Vector &elfun,
                                    DenseMatrix &elmat);

};

}

#endif
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkTransmitPolyDataPiece.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkTransmitPolyDataPiece.h"

#include "vtkCellData.h"
#include "vtkExtractPolyDataPiece.h"
#include "vtkMultiProcessController.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"

vtkCxxRevisionMacro(vtkTransmitPolyDataPiece, "1.12");
vtkStandardNewMacro(vtkTransmitPolyDataPiece);

vtkCxxSetObjectMacro(vtkTransmitPolyDataPiece,Controller,
                     vtkMultiProcessController);

//----------------------------------------------------------------------------
vtkTransmitPolyDataPiece::vtkTransmitPolyDataPiece()
{
  this->CreateGhostCells = 1;

  // Controller keeps a reference to this object as well.
  this->Controller = NULL;
  this->SetController(vtkMultiProcessController::GetGlobalController());

  this->Buffer = vtkPolyData::New();
  this->BufferPiece = -1;
  this->BufferNumberOfPieces = 0;
  this->BufferGhostLevel = 0;
}

//----------------------------------------------------------------------------
vtkTransmitPolyDataPiece::~vtkTransmitPolyDataPiece()
{
  this->Buffer->Delete();
  this->Buffer = NULL;
  this->SetController(NULL);
}

//----------------------------------------------------------------------------
void vtkTransmitPolyDataPiece::ComputeInputUpdateExtents(vtkDataObject *out)
{
  vtkPolyData *input = this->GetInput();

  out = out;
  if (this->GetInput() == NULL)
    {
    vtkErrorMacro("Missing input");
    return;
    }

  if (this->Controller == NULL)
    {
    input->SetUpdateNumberOfPieces(1);
    input->SetUpdatePiece(0);
    input->SetUpdateGhostLevel(0);
    return;
    }

  if (this->Controller->GetLocalProcessId() == 0)
    { // Request everything.
    input->SetUpdateNumberOfPieces(1);
    input->SetUpdatePiece(0);
    input->SetUpdateGhostLevel(0);
    }
  else
    { // Request nothing.
    input->SetUpdateNumberOfPieces(0);
    input->SetUpdatePiece(0);
    input->SetUpdateGhostLevel(0);
    }
}

//----------------------------------------------------------------------------
void vtkTransmitPolyDataPiece::ExecuteInformation()
{
  if (this->GetOutput() == NULL)
    {
    vtkErrorMacro("Missing output");
    return;
    }
  this->GetOutput()->SetMaximumNumberOfPieces(-1);
}

//----------------------------------------------------------------------------
void vtkTransmitPolyDataPiece::Execute()
{
  int procId;
  vtkPolyData *output = this->GetOutput();
  int updateGhostLevel = output->GetUpdateGhostLevel();

  // Just use the buffer if possible.
  if (output->GetPipelineMTime() < this->Buffer->GetMTime()
      && output->GetUpdatePiece() == this->BufferPiece
      && output->GetUpdateNumberOfPieces() == this->BufferNumberOfPieces
      && updateGhostLevel <= this->BufferGhostLevel)
    {
    // We deep copy, because we do not want to modify the buffer
    // when we remove ghost cells from the output.
    output->DeepCopy(this->Buffer);
    if (updateGhostLevel < this->BufferGhostLevel)
      {
      output->RemoveGhostCells(updateGhostLevel+1);
      }
    return;
    }

  if (this->Controller == NULL)
    {
    vtkErrorMacro("Could not find Controller.");
    return;
    }

  procId = this->Controller->GetLocalProcessId();
  if (procId == 0)
    {
    // It is important to synchronize these calls (all processes execute)
    // cerr << "Root Execute\n";
    this->RootExecute();
    }
  else
    {
    // cerr << "Satellite Execute " << procId << endl;
    this->SatelliteExecute(procId);
    }

  // Save the output in the buffer.
  this->Buffer->ShallowCopy(output);
  // Piece inforomation is not set by this point.
  // We do not have access to buffers piece, so save in ivars.
  this->BufferPiece = output->GetUpdatePiece();
  this->BufferNumberOfPieces = output->GetUpdateNumberOfPieces();
  this->BufferGhostLevel = updateGhostLevel;
}

//----------------------------------------------------------------------------
void vtkTransmitPolyDataPiece::RootExecute()
{
  vtkPolyData *input = this->GetInput();
  vtkPolyData *tmp = vtkPolyData::New();
  vtkPolyData *output = this->GetOutput();
  vtkExtractPolyDataPiece *extract = vtkExtractPolyDataPiece::New();
  int ext[3];
  int numProcs, i;

  if (output->GetUpdatePiece() != 0)
    {
    vtkWarningMacro(<< "Piece " << output->GetUpdatePiece()
                    << " does not match process 0.  "
                    << "Altering request to try to avoid a deadlock.");
    }

  // First, set up the pipeline and handle local request.
  tmp->ShallowCopy(input);
  tmp->SetReleaseDataFlag(0);
  extract->SetCreateGhostCells(this->CreateGhostCells);
  extract->SetInput(tmp);
  extract->GetOutput()->SetUpdateNumberOfPieces(
                                output->GetUpdateNumberOfPieces());
  extract->GetOutput()->SetUpdatePiece(0);
  extract->GetOutput()->SetUpdateGhostLevel(output->GetUpdateGhostLevel());

  extract->Update();
  // Copy geometry without copying information.
  output->CopyStructure(extract->GetOutput());
  output->GetPointData()->PassData(extract->GetOutput()->GetPointData());
  output->GetCellData()->PassData(extract->GetOutput()->GetCellData());

  // Now do each of the satellite requests.
  numProcs = this->Controller->GetNumberOfProcesses();
  for (i = 1; i < numProcs; ++i)
    {
    this->Controller->Receive(ext, 3, i, 22341);
    if (ext[1] != output->GetUpdateNumberOfPieces())
      {
      vtkWarningMacro("Number of pieces mismatch between processes.");
      }
    extract->GetOutput()->SetUpdateNumberOfPieces(ext[1]);
    extract->GetOutput()->SetUpdatePiece(ext[0]);
    extract->GetOutput()->SetUpdateGhostLevel(ext[2]);
    extract->Update();
    this->Controller->Send(extract->GetOutput(), i, 22342);
    }
  tmp->Delete();
  extract->Delete();
}

//----------------------------------------------------------------------------
void vtkTransmitPolyDataPiece::SatelliteExecute(int)
{
  vtkPolyData *tmp = vtkPolyData::New();
  vtkPolyData *output = this->GetOutput();
  int ext[3];

  ext[0] = output->GetUpdatePiece();
  ext[1] = output->GetUpdateNumberOfPieces();
  ext[2] = output->GetUpdateGhostLevel();

  this->Controller->Send(ext, 3, 0, 22341);
  this->Controller->Receive(tmp, 0, 22342);

  // Copy geometry without copying information.
  output->CopyStructure(tmp);
  output->GetPointData()->PassData(tmp->GetPointData());
  output->GetCellData()->PassData(tmp->GetCellData());

  tmp->Delete();
}

//----------------------------------------------------------------------------
void vtkTransmitPolyDataPiece::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Create Ghost Cells: " << (this->CreateGhostCells ? "On\n" : "Off\n");

  os << indent << "Controller: (" << this->Controller << ")\n";

}

<commit_msg>Need to pass field data as well.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkTransmitPolyDataPiece.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkTransmitPolyDataPiece.h"

#include "vtkCellData.h"
#include "vtkExtractPolyDataPiece.h"
#include "vtkMultiProcessController.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"

vtkCxxRevisionMacro(vtkTransmitPolyDataPiece, "1.13");
vtkStandardNewMacro(vtkTransmitPolyDataPiece);

vtkCxxSetObjectMacro(vtkTransmitPolyDataPiece,Controller,
                     vtkMultiProcessController);

//----------------------------------------------------------------------------
vtkTransmitPolyDataPiece::vtkTransmitPolyDataPiece()
{
  this->CreateGhostCells = 1;

  // Controller keeps a reference to this object as well.
  this->Controller = NULL;
  this->SetController(vtkMultiProcessController::GetGlobalController());

  this->Buffer = vtkPolyData::New();
  this->BufferPiece = -1;
  this->BufferNumberOfPieces = 0;
  this->BufferGhostLevel = 0;
}

//----------------------------------------------------------------------------
vtkTransmitPolyDataPiece::~vtkTransmitPolyDataPiece()
{
  this->Buffer->Delete();
  this->Buffer = NULL;
  this->SetController(NULL);
}

//----------------------------------------------------------------------------
void vtkTransmitPolyDataPiece::ComputeInputUpdateExtents(vtkDataObject *out)
{
  vtkPolyData *input = this->GetInput();

  out = out;
  if (this->GetInput() == NULL)
    {
    vtkErrorMacro("Missing input");
    return;
    }

  if (this->Controller == NULL)
    {
    input->SetUpdateNumberOfPieces(1);
    input->SetUpdatePiece(0);
    input->SetUpdateGhostLevel(0);
    return;
    }

  if (this->Controller->GetLocalProcessId() == 0)
    { // Request everything.
    input->SetUpdateNumberOfPieces(1);
    input->SetUpdatePiece(0);
    input->SetUpdateGhostLevel(0);
    }
  else
    { // Request nothing.
    input->SetUpdateNumberOfPieces(0);
    input->SetUpdatePiece(0);
    input->SetUpdateGhostLevel(0);
    }
}

//----------------------------------------------------------------------------
void vtkTransmitPolyDataPiece::ExecuteInformation()
{
  if (this->GetOutput() == NULL)
    {
    vtkErrorMacro("Missing output");
    return;
    }
  this->GetOutput()->SetMaximumNumberOfPieces(-1);
}

//----------------------------------------------------------------------------
void vtkTransmitPolyDataPiece::Execute()
{
  int procId;
  vtkPolyData *output = this->GetOutput();
  int updateGhostLevel = output->GetUpdateGhostLevel();

  // Just use the buffer if possible.
  if (output->GetPipelineMTime() < this->Buffer->GetMTime()
      && output->GetUpdatePiece() == this->BufferPiece
      && output->GetUpdateNumberOfPieces() == this->BufferNumberOfPieces
      && updateGhostLevel <= this->BufferGhostLevel)
    {
    // We deep copy, because we do not want to modify the buffer
    // when we remove ghost cells from the output.
    output->DeepCopy(this->Buffer);
    if (updateGhostLevel < this->BufferGhostLevel)
      {
      output->RemoveGhostCells(updateGhostLevel+1);
      }
    return;
    }

  if (this->Controller == NULL)
    {
    vtkErrorMacro("Could not find Controller.");
    return;
    }

  procId = this->Controller->GetLocalProcessId();
  if (procId == 0)
    {
    // It is important to synchronize these calls (all processes execute)
    // cerr << "Root Execute\n";
    this->RootExecute();
    }
  else
    {
    // cerr << "Satellite Execute " << procId << endl;
    this->SatelliteExecute(procId);
    }

  // Save the output in the buffer.
  this->Buffer->ShallowCopy(output);
  // Piece inforomation is not set by this point.
  // We do not have access to buffers piece, so save in ivars.
  this->BufferPiece = output->GetUpdatePiece();
  this->BufferNumberOfPieces = output->GetUpdateNumberOfPieces();
  this->BufferGhostLevel = updateGhostLevel;
}

//----------------------------------------------------------------------------
void vtkTransmitPolyDataPiece::RootExecute()
{
  vtkPolyData *input = this->GetInput();
  vtkPolyData *tmp = vtkPolyData::New();
  vtkPolyData *output = this->GetOutput();
  vtkExtractPolyDataPiece *extract = vtkExtractPolyDataPiece::New();
  int ext[3];
  int numProcs, i;

  if (output->GetUpdatePiece() != 0)
    {
    vtkWarningMacro(<< "Piece " << output->GetUpdatePiece()
                    << " does not match process 0.  "
                    << "Altering request to try to avoid a deadlock.");
    }

  // First, set up the pipeline and handle local request.
  tmp->ShallowCopy(input);
  tmp->SetReleaseDataFlag(0);
  extract->SetCreateGhostCells(this->CreateGhostCells);
  extract->SetInput(tmp);
  extract->GetOutput()->SetUpdateNumberOfPieces(
                                output->GetUpdateNumberOfPieces());
  extract->GetOutput()->SetUpdatePiece(0);
  extract->GetOutput()->SetUpdateGhostLevel(output->GetUpdateGhostLevel());

  extract->Update();
  // Copy geometry without copying information.
  output->CopyStructure(extract->GetOutput());
  output->GetPointData()->PassData(extract->GetOutput()->GetPointData());
  output->GetCellData()->PassData(extract->GetOutput()->GetCellData());
  output->GetFieldData()->PassData(extract->GetOutput()->GetFieldData());

  // Now do each of the satellite requests.
  numProcs = this->Controller->GetNumberOfProcesses();
  for (i = 1; i < numProcs; ++i)
    {
    this->Controller->Receive(ext, 3, i, 22341);
    if (ext[1] != output->GetUpdateNumberOfPieces())
      {
      vtkWarningMacro("Number of pieces mismatch between processes.");
      }
    extract->GetOutput()->SetUpdateNumberOfPieces(ext[1]);
    extract->GetOutput()->SetUpdatePiece(ext[0]);
    extract->GetOutput()->SetUpdateGhostLevel(ext[2]);
    extract->Update();
    this->Controller->Send(extract->GetOutput(), i, 22342);
    }
  tmp->Delete();
  extract->Delete();
}

//----------------------------------------------------------------------------
void vtkTransmitPolyDataPiece::SatelliteExecute(int)
{
  vtkPolyData *tmp = vtkPolyData::New();
  vtkPolyData *output = this->GetOutput();
  int ext[3];

  ext[0] = output->GetUpdatePiece();
  ext[1] = output->GetUpdateNumberOfPieces();
  ext[2] = output->GetUpdateGhostLevel();

  this->Controller->Send(ext, 3, 0, 22341);
  this->Controller->Receive(tmp, 0, 22342);

  // Copy geometry without copying information.
  output->CopyStructure(tmp);
  output->GetPointData()->PassData(tmp->GetPointData());
  output->GetCellData()->PassData(tmp->GetCellData());
  output->GetFieldData()->PassData(tmp->GetFieldData());

  tmp->Delete();
}

//----------------------------------------------------------------------------
void vtkTransmitPolyDataPiece::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Create Ghost Cells: " << (this->CreateGhostCells ? "On\n" : "Off\n");

  os << indent << "Controller: (" << this->Controller << ")\n";

}

<|endoftext|>


<commit_before>
#include "bsaarchive.hpp"

#include <algorithm>
#include <sstream>
#include <fstream>

namespace Archives
{

void BsaArchive::loadNamed(size_t count, std::istream& stream)
{
    std::vector<std::string> names; names.reserve(count);
    std::vector<Entry> entries; entries.reserve(count);

    std::streamsize base = stream.tellg();
    if(!stream.seekg(std::streampos(count) * -18, std::ios_base::end))
        throw std::runtime_error("Failed to seek to archive footer ("+std::to_string(count)+" entries)");

    for(size_t i = 0;i < count;++i)
    {
        std::array<char,13> name;
        stream.read(name.data(), name.size()-1);
        name.back() = '\0'; // Ensure null termination
        std::replace(name.begin(), name.end(), '\\', '/');
        names.push_back(std::string(name.data()));

        const bool isCompressed = read_le16(stream) != 0;
        if(isCompressed)
            throw std::runtime_error("Compressed entries not supported");

        Entry entry;
        entry.mStart = ((i == 0) ? base : entries[i-1].mEnd);
        entry.mEnd = entry.mStart + read_le32(stream);
        entries.push_back(entry);
    }

    if(!stream.good())
        throw std::runtime_error("Failed reading archive footer");

    for(const std::string &name : names)
    {
        auto iter = std::lower_bound(mLookupName.begin(), mLookupName.end(), name);
        if(iter == mLookupName.end() || *iter != name)
            mLookupName.insert(iter, name);
    }

    mEntries.resize(mLookupName.size());
    for(size_t i = 0;i < count;++i)
    {
        auto iter = std::find(mLookupName.cbegin(), mLookupName.cend(), names[i]);
        mEntries[std::distance(mLookupName.cbegin(), iter)] = entries[i];
    }
}

void BsaArchive::load(const std::string &fname)
{
    mFilename = fname;

    std::ifstream stream(mFilename, std::ios::binary);
    if(!stream.is_open())
        throw std::runtime_error("Failed to open "+mFilename);

    size_t count = read_le16(stream);

    mEntries.reserve(count);
    loadNamed(count, stream);
}

IStreamPtr BsaArchive::open(const Entry &entry)
{
    std::unique_ptr<std::istream> stream(new std::ifstream(mFilename, std::ios::binary));
    if(!stream->seekg(entry.mStart))
        return IStreamPtr(nullptr);
    return IStreamPtr(new ConstrainedFileStream(std::move(stream), entry.mStart, entry.mEnd));
}

IStreamPtr BsaArchive::open(const char *name)
{
    auto iter = std::lower_bound(mLookupName.begin(), mLookupName.end(), name);
    if(iter == mLookupName.end() || *iter != name)
        return IStreamPtr(nullptr);
    return open(mEntries[std::distance(mLookupName.begin(), iter)]);
}

bool BsaArchive::exists(const char *name) const
{
    return std::binary_search(mLookupName.begin(), mLookupName.end(), name);
}

} // namespace Archives
<commit_msg>Minor bsaarchive clean-up and optimization.<commit_after>#include <algorithm>
#include <sstream>
#include <fstream>

#include "bsaarchive.hpp"
#include "../dos/DOSUtils.h"

namespace Archives
{

void BsaArchive::loadNamed(size_t count, std::istream& stream)
{
    std::vector<std::string> names; names.reserve(count);
    std::vector<Entry> entries; entries.reserve(count);

    std::streamsize base = stream.tellg();
    if(!stream.seekg(std::streampos(count) * -18, std::ios_base::end))
        throw std::runtime_error("Failed to seek to archive footer ("+std::to_string(count)+" entries)");

    for(size_t i = 0;i < count;++i)
    {
        DOSUtils::FilenameBuffer name;
        stream.read(name.data(), name.size()-1);
        name.back() = '\0'; // Ensure null termination
        std::replace(name.begin(), name.end(), '\\', '/');
        names.emplace_back(std::string(name.data()));

        const bool isCompressed = read_le16(stream) != 0;
        if(isCompressed)
            throw std::runtime_error("Compressed entries not supported");

        Entry entry;
        entry.mStart = (i == 0) ? base : entries[i-1].mEnd;
        entry.mEnd = entry.mStart + read_le32(stream);
        entries.emplace_back(std::move(entry));
    }

    if(!stream.good())
        throw std::runtime_error("Failed reading archive footer");

    for(const std::string &name : names)
    {
        auto iter = std::lower_bound(mLookupName.begin(), mLookupName.end(), name);
        if(iter == mLookupName.end() || *iter != name)
            mLookupName.insert(iter, name);
    }

    mEntries.resize(mLookupName.size());
    for(size_t i = 0;i < count;++i)
    {
        auto iter = std::lower_bound(mLookupName.cbegin(), mLookupName.cend(), names[i]);
        mEntries[std::distance(mLookupName.cbegin(), iter)] = entries[i];
    }
}

void BsaArchive::load(const std::string &fname)
{
    mFilename = fname;

    std::ifstream stream(mFilename, std::ios::binary);
    if(!stream.is_open())
        throw std::runtime_error("Failed to open "+mFilename);

    size_t count = read_le16(stream);

    mEntries.reserve(count);
    loadNamed(count, stream);
}

IStreamPtr BsaArchive::open(const Entry &entry)
{
    std::unique_ptr<std::istream> stream(new std::ifstream(mFilename, std::ios::binary));
    if(!stream->seekg(entry.mStart))
        return IStreamPtr(nullptr);
    return IStreamPtr(new ConstrainedFileStream(std::move(stream), entry.mStart, entry.mEnd));
}

IStreamPtr BsaArchive::open(const char *name)
{
    auto iter = std::lower_bound(mLookupName.begin(), mLookupName.end(), name);
    if(iter == mLookupName.end() || *iter != name)
        return IStreamPtr(nullptr);
    return open(mEntries[std::distance(mLookupName.begin(), iter)]);
}

bool BsaArchive::exists(const char *name) const
{
    return std::binary_search(mLookupName.begin(), mLookupName.end(), name);
}

} // namespace Archives
<|endoftext|>


<commit_before><commit_msg>Meme patch<commit_after><|endoftext|>


<commit_before>//
//  6502AllRAM.cpp
//  CLK
//
//  Created by Thomas Harte on 13/07/2015.
//  Copyright 2015 Thomas Harte. All rights reserved.
//

#include "6502AllRAM.hpp"

#include <algorithm>
#include <cstring>

#include "../../../Components/6526/6526.hpp"

//#define BE_NOISY

using namespace CPU::MOS6502;

namespace {

using Type = CPU::MOS6502Esque::Type;

template <Type type, bool has_cias> class ConcreteAllRAMProcessor: public AllRAMProcessor, public BusHandler {
	public:
		ConcreteAllRAMProcessor(size_t memory_size) :
			AllRAMProcessor(memory_size),
			mos6502_(*this),
			cia1_(cia1_handler_),
			cia2_(cia2_handler_) {
			mos6502_.set_power_on(false);
		}

		inline Cycles perform_bus_operation(BusOperation operation, uint32_t address, uint8_t *value) {
			timestamp_ += Cycles(1);

			if constexpr (has_cias) {
				cia1_.run_for(HalfCycles(2));
				cia2_.run_for(HalfCycles(2));
			}

			if(isAccessOperation(operation)) {
				if(operation == BusOperation::ReadOpcode) {
#ifdef BE_NOISY
					printf("[%04x] %02x a:%04x x:%04x y:%04x p:%02x s:%02x\n", address, memory_[address],
						mos6502_.get_value_of_register(Register::A),
						mos6502_.get_value_of_register(Register::X),
						mos6502_.get_value_of_register(Register::Y),
						mos6502_.get_value_of_register(Register::Flags) & 0xff,
						mos6502_.get_value_of_register(Register::StackPointer) & 0xff);
#endif
					check_address_for_trap(address);
					--instructions_;
				}

				if(isReadOperation(operation)) {
					*value = memory_[address];

					if constexpr (has_cias) {
						if((address & 0xff00) == 0xdc00) {
							*value = cia1_.read(address);
						} else if((address & 0xff00) == 0xdd00) {
							*value = cia2_.read(address);
						}

					}

#ifdef BE_NOISY
//					if((address&0xff00) == 0x100) {
						printf("%04x -> %02x\n", address, *value);
//					}
#endif
				} else {
					memory_[address] = *value;

					if constexpr (has_cias) {
						if((address & 0xff00) == 0xdc00) {
							cia1_.write(address, *value);
						} else if((address & 0xff00) == 0xdd00) {
							cia2_.write(address, *value);
						}
					}
#ifdef BE_NOISY
//					if((address&0xff00) == 0x100) {
						printf("%04x <- %02x\n", address, *value);
//					}
#endif
				}
			}

			mos6502_.set_irq_line(cia1_.get_interrupt_line());
			mos6502_.set_nmi_line(cia2_.get_interrupt_line());

			return Cycles(1);
		}

		void run_for(const Cycles cycles) {
			mos6502_.run_for(cycles);
		}

		void run_for_instructions(int count) {
			instructions_ = count;
			while(instructions_) {
				mos6502_.run_for(Cycles(1));
			}
		}

		bool is_jammed() {
			return mos6502_.is_jammed();
		}

		void set_irq_line(bool value) {
			mos6502_.set_irq_line(value);
		}

		void set_nmi_line(bool value) {
			mos6502_.set_nmi_line(value);
		}

		uint16_t get_value_of_register(Register r) {
			return mos6502_.get_value_of_register(r);
		}

		void set_value_of_register(Register r, uint16_t value) {
			mos6502_.set_value_of_register(r, value);
		}

	private:
		CPU::MOS6502Esque::Processor<type, ConcreteAllRAMProcessor, false> mos6502_;
		int instructions_ = 0;

		class PortHandler: public MOS::MOS6526::PortHandler {};
		PortHandler cia1_handler_, cia2_handler_;

		MOS::MOS6526::MOS6526<PortHandler, MOS::MOS6526::Personality::P6526> cia1_, cia2_;
};

}

AllRAMProcessor *AllRAMProcessor::Processor(Type type, bool has_cias) {
#define Bind(p) \
	case p: \
		if(has_cias) return new ConcreteAllRAMProcessor<p, true>(type == Type::TWDC65816 ? 16*1024*1024 : 64*1024);	\
		else return new ConcreteAllRAMProcessor<p, false>(type == Type::TWDC65816 ? 16*1024*1024 : 64*1024);	\

	switch(type) {
		default:
		Bind(Type::T6502)
		Bind(Type::TNES6502)
		Bind(Type::TSynertek65C02)
		Bind(Type::TWDC65C02)
		Bind(Type::TRockwell65C02)
		Bind(Type::TWDC65816)
	}
#undef Bind
}
<commit_msg>Increases compile-time logging options.<commit_after>//
//  6502AllRAM.cpp
//  CLK
//
//  Created by Thomas Harte on 13/07/2015.
//  Copyright 2015 Thomas Harte. All rights reserved.
//

#include "6502AllRAM.hpp"

#include <algorithm>
#include <cstring>

#include "../../../Components/6526/6526.hpp"

//#define BE_NOISY
using namespace CPU::MOS6502;

namespace {

static constexpr bool LogAllReads = false;
static constexpr bool LogAllWrites = false;
static constexpr bool LogCIAAccesses = true;
static constexpr bool LogProgramCounter = false;

using Type = CPU::MOS6502Esque::Type;

template <Type type, bool has_cias> class ConcreteAllRAMProcessor: public AllRAMProcessor, public BusHandler {
	public:
		ConcreteAllRAMProcessor(size_t memory_size) :
			AllRAMProcessor(memory_size),
			mos6502_(*this),
			cia1_(cia1_handler_),
			cia2_(cia2_handler_) {
			mos6502_.set_power_on(false);
		}

		inline Cycles perform_bus_operation(BusOperation operation, uint32_t address, uint8_t *value) {
			timestamp_ += Cycles(1);

			if constexpr (has_cias) {
				cia1_.run_for(HalfCycles(2));
				cia2_.run_for(HalfCycles(2));
			}

			if(isAccessOperation(operation)) {
				if(operation == BusOperation::ReadOpcode) {
					if constexpr (LogProgramCounter) {
						printf("[%04x] %02x a:%04x x:%04x y:%04x p:%02x s:%02x\n", address, memory_[address],
							mos6502_.get_value_of_register(Register::A),
							mos6502_.get_value_of_register(Register::X),
							mos6502_.get_value_of_register(Register::Y),
							mos6502_.get_value_of_register(Register::Flags) & 0xff,
							mos6502_.get_value_of_register(Register::StackPointer) & 0xff);
					}
					check_address_for_trap(address);
					--instructions_;
				}

				if(isReadOperation(operation)) {
					*value = memory_[address];

					if constexpr (has_cias) {
						if((address & 0xff00) == 0xdc00) {
							*value = cia1_.read(address);
							if constexpr (LogCIAAccesses) {
								printf("[%d] CIA1: %04x -> %02x\n", timestamp_.as<int>(), address, *value);
							}
						} else if((address & 0xff00) == 0xdd00) {
							*value = cia2_.read(address);
							if constexpr (LogCIAAccesses) {
								printf("[%d] CIA2: %04x -> %02x\n", timestamp_.as<int>(), address, *value);
							}
						}
					}

					if constexpr (LogAllReads) {
//						if((address&0xff00) == 0x100) {
							printf("%04x -> %02x\n", address, *value);
//						}
					}
				} else {
					memory_[address] = *value;

					if constexpr (has_cias) {
						if((address & 0xff00) == 0xdc00) {
							cia1_.write(address, *value);
							if constexpr (LogCIAAccesses) {
								printf("[%d] CIA1: %04x <- %02x\n", timestamp_.as<int>(), address, *value);
							}
						} else if((address & 0xff00) == 0xdd00) {
							cia2_.write(address, *value);
							if constexpr (LogCIAAccesses) {
								printf("[%d] CIA2: %04x <- %02x\n", timestamp_.as<int>(), address, *value);
							}
						}
					}

					if constexpr (LogAllWrites) {
//						if((address&0xff00) == 0x100) {
							printf("%04x <- %02x\n", address, *value);
//						}
					}
				}
			}

			mos6502_.set_irq_line(cia1_.get_interrupt_line());
			mos6502_.set_nmi_line(cia2_.get_interrupt_line());

			return Cycles(1);
		}

		void run_for(const Cycles cycles) {
			mos6502_.run_for(cycles);
		}

		void run_for_instructions(int count) {
			instructions_ = count;
			while(instructions_) {
				mos6502_.run_for(Cycles(1));
			}
		}

		bool is_jammed() {
			return mos6502_.is_jammed();
		}

		void set_irq_line(bool value) {
			mos6502_.set_irq_line(value);
		}

		void set_nmi_line(bool value) {
			mos6502_.set_nmi_line(value);
		}

		uint16_t get_value_of_register(Register r) {
			return mos6502_.get_value_of_register(r);
		}

		void set_value_of_register(Register r, uint16_t value) {
			mos6502_.set_value_of_register(r, value);
		}

	private:
		CPU::MOS6502Esque::Processor<type, ConcreteAllRAMProcessor, false> mos6502_;
		int instructions_ = 0;

		class PortHandler: public MOS::MOS6526::PortHandler {};
		PortHandler cia1_handler_, cia2_handler_;

		MOS::MOS6526::MOS6526<PortHandler, MOS::MOS6526::Personality::P6526> cia1_, cia2_;
};

}

AllRAMProcessor *AllRAMProcessor::Processor(Type type, bool has_cias) {
#define Bind(p) \
	case p: \
		if(has_cias) return new ConcreteAllRAMProcessor<p, true>(type == Type::TWDC65816 ? 16*1024*1024 : 64*1024);	\
		else return new ConcreteAllRAMProcessor<p, false>(type == Type::TWDC65816 ? 16*1024*1024 : 64*1024);	\

	switch(type) {
		default:
		Bind(Type::T6502)
		Bind(Type::TNES6502)
		Bind(Type::TSynertek65C02)
		Bind(Type::TWDC65C02)
		Bind(Type::TRockwell65C02)
		Bind(Type::TWDC65816)
	}
#undef Bind
}
<|endoftext|>


<commit_before>/*
   Copyright 2012-2015 Alex Zhondin <qtinuum.team@gmail.com>
   Copyright 2015-2016 Alexandra Cherdantseva <neluhus.vagus@gmail.com>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include "PropertyDelegateInt.h"
#include "Core/PropertyInt.h"
#include "Delegates/PropertyEditorAux.h"
#include "Delegates/PropertyDelegateFactory.h"
#include "Delegates/PropertyEditorHandler.h"

#include <QCoreApplication>
#include <QSpinBox>
#include <QLocale>

class QtnPropertyIntSpinBoxHandler
	: public QtnPropertyEditorHandlerVT<QtnPropertyIntBase, QSpinBox>
{
public:
	QtnPropertyIntSpinBoxHandler(
		QtnPropertyIntBase &property, QSpinBox &editor);

protected:
	virtual void updateEditor() override;
};

static bool regIntDelegate = QtnPropertyDelegateFactory::staticInstance()
	.registerDelegateDefault(
		&QtnPropertyIntBase::staticMetaObject
		, &qtnCreateDelegate<QtnPropertyDelegateInt, QtnPropertyIntBase>
		, "SpinBox");

QtnPropertyDelegateInt::QtnPropertyDelegateInt(QtnPropertyIntBase &owner)
	: QtnPropertyDelegateTyped<QtnPropertyIntBase>(owner)
{
}

QWidget *QtnPropertyDelegateInt::createValueEditorImpl(
	QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo)
{
	auto spinBox = new QSpinBox(parent);
	spinBox->setGeometry(rect);

	new QtnPropertyIntSpinBoxHandler(owner(), *spinBox);

	spinBox->selectAll();

	if (owner().isEditableByUser())
		qtnInitNumEdit(spinBox, inplaceInfo, NUM_SIGNED_INT);

	return spinBox;
}

bool QtnPropertyDelegateInt::acceptKeyPressedForInplaceEditImpl(
	QKeyEvent *keyEvent) const
{
	if (QtnPropertyDelegateTyped<QtnPropertyIntBase>::
		acceptKeyPressedForInplaceEditImpl(keyEvent))
	{
		return true;
	}

	return qtnAcceptForNumEdit(keyEvent, NUM_SIGNED_INT);
}

bool QtnPropertyDelegateInt::propertyValueToStr(QString &strValue) const
{
	strValue = QLocale().toString(owner().value());
	return true;
}

QtnPropertyIntSpinBoxHandler::QtnPropertyIntSpinBoxHandler(
	QtnPropertyIntBase &property, QSpinBox &editor)
	: QtnPropertyEditorHandlerVT(property, editor)
{
	if (!property.isEditableByUser())
		editor.setReadOnly(true);

	editor.setRange(property.minValue(), property.maxValue());
	editor.setSingleStep(property.stepValue());

	updateEditor();

	editor.setKeyboardTracking(false);
	editor.installEventFilter(this);
	QObject::connect(
		&editor,
		static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
		this,
		&QtnPropertyIntSpinBoxHandler::onValueChanged);
}

void QtnPropertyIntSpinBoxHandler::updateEditor()
{
	updating++;

	if (property().valueIsHidden())
	{
		editor().setValue(editor().minimum());
		editor().setSpecialValueText(
			QtnMultiProperty::getMultiValuePlaceholder());
	} else
	{
		editor().setValue(property().value());
		editor().setSpecialValueText(QString());
	}

	editor().selectAll();

	updating--;
}
<commit_msg>fix forgotten include<commit_after>/*
   Copyright 2012-2015 Alex Zhondin <qtinuum.team@gmail.com>
   Copyright 2015-2016 Alexandra Cherdantseva <neluhus.vagus@gmail.com>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include "PropertyDelegateInt.h"
#include "Core/PropertyInt.h"
#include "Delegates/PropertyEditorAux.h"
#include "Delegates/PropertyDelegateFactory.h"
#include "Delegates/PropertyEditorHandler.h"
#include "MultiProperty.h"

#include <QCoreApplication>
#include <QSpinBox>
#include <QLocale>

class QtnPropertyIntSpinBoxHandler
	: public QtnPropertyEditorHandlerVT<QtnPropertyIntBase, QSpinBox>
{
public:
	QtnPropertyIntSpinBoxHandler(
		QtnPropertyIntBase &property, QSpinBox &editor);

protected:
	virtual void updateEditor() override;
};

static bool regIntDelegate = QtnPropertyDelegateFactory::staticInstance()
	.registerDelegateDefault(
		&QtnPropertyIntBase::staticMetaObject
		, &qtnCreateDelegate<QtnPropertyDelegateInt, QtnPropertyIntBase>
		, "SpinBox");

QtnPropertyDelegateInt::QtnPropertyDelegateInt(QtnPropertyIntBase &owner)
	: QtnPropertyDelegateTyped<QtnPropertyIntBase>(owner)
{
}

QWidget *QtnPropertyDelegateInt::createValueEditorImpl(
	QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo)
{
	auto spinBox = new QSpinBox(parent);
	spinBox->setGeometry(rect);

	new QtnPropertyIntSpinBoxHandler(owner(), *spinBox);

	spinBox->selectAll();

	if (owner().isEditableByUser())
		qtnInitNumEdit(spinBox, inplaceInfo, NUM_SIGNED_INT);

	return spinBox;
}

bool QtnPropertyDelegateInt::acceptKeyPressedForInplaceEditImpl(
	QKeyEvent *keyEvent) const
{
	if (QtnPropertyDelegateTyped<QtnPropertyIntBase>::
		acceptKeyPressedForInplaceEditImpl(keyEvent))
	{
		return true;
	}

	return qtnAcceptForNumEdit(keyEvent, NUM_SIGNED_INT);
}

bool QtnPropertyDelegateInt::propertyValueToStr(QString &strValue) const
{
	strValue = QLocale().toString(owner().value());
	return true;
}

QtnPropertyIntSpinBoxHandler::QtnPropertyIntSpinBoxHandler(
	QtnPropertyIntBase &property, QSpinBox &editor)
	: QtnPropertyEditorHandlerVT(property, editor)
{
	if (!property.isEditableByUser())
		editor.setReadOnly(true);

	editor.setRange(property.minValue(), property.maxValue());
	editor.setSingleStep(property.stepValue());

	updateEditor();

	editor.setKeyboardTracking(false);
	editor.installEventFilter(this);
	QObject::connect(
		&editor,
		static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
		this,
		&QtnPropertyIntSpinBoxHandler::onValueChanged);
}

void QtnPropertyIntSpinBoxHandler::updateEditor()
{
	updating++;

	if (property().valueIsHidden())
	{
		editor().setValue(editor().minimum());
		editor().setSpecialValueText(
			QtnMultiProperty::getMultiValuePlaceholder());
	} else
	{
		editor().setValue(property().value());
		editor().setSpecialValueText(QString());
	}

	editor().selectAll();

	updating--;
}
<|endoftext|>


<commit_before>/*
**  Copyright (C) 2013 Aldebaran Robotics
**  See COPYING for the license
*/
#include <boost/python.hpp>
#include <map>

#include <qitype/anyobject.hpp>
#include <qitype/objectfactory.hpp>
#include <qipython/gil.hpp>
#include <qipython/pyobjectfactory.hpp>
#include <qipython/pyobject.hpp>
#include <qipython/error.hpp>

qiLogCategory("qipy.factory");

namespace qi {
  namespace py {
    class PyCreateException : std::exception
    {
    public:
      PyCreateException(std::string &name) : _name(name) {}
      virtual ~PyCreateException() throw() {}
      char const * what() const throw() { return std::string(_name + " not found").c_str(); }

    private:
      std::string _name;
    };

    void translate_pycreateexception(PyCreateException const& e)
    {
      PyErr_SetString(PyExc_RuntimeError, e.what());
    }

    static boost::python::object pycreate_object(boost::python::str name)
    {
      GILScopedLock lock;
      std::string objectName = boost::python::extract<std::string>(name);
      qi::AnyObject object = qi::createObject(objectName);

      if(!object)
        throw PyCreateException(objectName);

      return makePyQiObject(object, objectName);
    }

    static qi::AnyObject pyconstruct_object(boost::python::object class_)
    {
      GILScopedLock lock;
      qi::AnyObject obj;
      PY_CATCH_ERROR(obj = makeQiAnyObject(class_()));
      return obj;
    }

    static void pyregister_object_factory(boost::python::str class_name, boost::python::object class_)
    {
      std::string name = boost::python::extract<std::string>(class_name);
      boost::function<qi::AnyObject()> func = boost::bind(&qi::py::pyconstruct_object, class_);
      qi::registerObjectFactory(name, AnyFunction::from(func));
    }

    void export_pyobjectfactory()
    {
      boost::python::register_exception_translator<PyCreateException>(&translate_pycreateexception);
      boost::python::def("createObject", &qi::py::pycreate_object);
      boost::python::def("registerObjectFactory", &qi::py::pyregister_object_factory);
    }
  }
}
<commit_msg>Add createObject with args in Python<commit_after>/*
**  Copyright (C) 2013 Aldebaran Robotics
**  See COPYING for the license
*/
#include <boost/python.hpp>
#include <map>

#include <qitype/anyobject.hpp>
#include <qitype/objectfactory.hpp>
#include <qipython/gil.hpp>
#include <qipython/pyobjectfactory.hpp>
#include <qipython/pyobject.hpp>
#include <qipython/error.hpp>
#include <boost/python/raw_function.hpp>

qiLogCategory("qipy.factory");

namespace qi {
  namespace py {
    class PyCreateException : std::exception
    {
    public:
      PyCreateException(const std::string &name) : _name(name) {}
      virtual ~PyCreateException() throw() {}
      char const * what() const throw() { return std::string(_name + " not found").c_str(); }

    private:
      std::string _name;
    };

    void translate_pycreateexception(PyCreateException const& e)
    {
      PyErr_SetString(PyExc_RuntimeError, e.what());
    }

    static qi::AnyObject pyconstruct_object(boost::python::object class_)
    {
      GILScopedLock lock;
      qi::AnyObject obj;
      PY_CATCH_ERROR(obj = makeQiAnyObject(class_()));
      return obj;
    }

    static void pyregister_object_factory(boost::python::str class_name, boost::python::object class_)
    {
      std::string name = boost::python::extract<std::string>(class_name);
      boost::function<qi::AnyObject()> func = boost::bind(&qi::py::pyconstruct_object, class_);
      qi::registerObjectFactory(name, AnyFunction::from(func));
    }

    static boost::python::object pycreate_object_args(boost::python::tuple pyargs,
                                                      boost::python::dict kwargs)
    {
      int           len        = boost::python::len(pyargs);
      std::string   objectName = boost::python::extract<std::string>(pyargs[0]);
      qi::AnyObject object;

      qi::AnyReferenceVector args;
      for (int i = 1; i < len; ++i)
        args.push_back(AnyReference::from(boost::python::object(pyargs[i])));
      object = qi::createObject(objectName, args);

      if(!object)
        throw PyCreateException(objectName);
      return makePyQiObject(object, objectName);
    }

    void export_pyobjectfactory()
    {
      boost::python::register_exception_translator<PyCreateException>(&translate_pycreateexception);
      boost::python::def("createObject", boost::python::raw_function(&pycreate_object_args, 1));
      boost::python::def("registerObjectFactory", &qi::py::pyregister_object_factory);
    }
  }
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkDataSetTriangleFilter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkDataSetTriangleFilter.h"

#include "vtkCellData.h"
#include "vtkCellType.h"
#include "vtkGenericCell.h"
#include "vtkIdList.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkOrderedTriangulator.h"
#include "vtkPointData.h"
#include "vtkStructuredGrid.h"
#include "vtkStructuredPoints.h"
#include "vtkUnstructuredGrid.h"
#include "vtkRectilinearGrid.h"

vtkCxxRevisionMacro(vtkDataSetTriangleFilter, "1.27");
vtkStandardNewMacro(vtkDataSetTriangleFilter);

vtkDataSetTriangleFilter::vtkDataSetTriangleFilter()
{
  this->Triangulator = vtkOrderedTriangulator::New();
  this->Triangulator->PreSortedOff();
  this->Triangulator->UseTemplatesOn();
  this->TetrahedraOnly = 0;
}

vtkDataSetTriangleFilter::~vtkDataSetTriangleFilter()
{
  this->Triangulator->Delete();
  this->Triangulator = NULL;
}

int vtkDataSetTriangleFilter::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the input and ouptut
  vtkDataSet *input = vtkDataSet::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (input->IsA("vtkStructuredPoints") ||
      input->IsA("vtkStructuredGrid") ||
      input->IsA("vtkImageData") ||
      input->IsA("vtkRectilinearGrid"))
    {
    this->StructuredExecute(input, output);
    }
  else
    {
    this->UnstructuredExecute(input, output);
    }

  vtkDebugMacro(<<"Produced " << this->GetOutput()->GetNumberOfCells() << " cells");

  return 1;
}

void vtkDataSetTriangleFilter::StructuredExecute(vtkDataSet *input,
                                                 vtkUnstructuredGrid *output)
{
  int dimensions[3], i, j, k, l, m;
  vtkIdType newCellId, inId;
  vtkGenericCell *cell = vtkGenericCell::New();
  vtkCellData *inCD = input->GetCellData();
  vtkCellData *outCD = output->GetCellData();
  vtkPoints *cellPts = vtkPoints::New();
  vtkPoints *newPoints = vtkPoints::New();
  vtkIdList *cellPtIds = vtkIdList::New();
  int numSimplices, numPts, dim, type;
  vtkIdType pts[4], num;

  // Create an array of points. This does an explicit creation
  // of each point.
  num = input->GetNumberOfPoints();
  newPoints->SetNumberOfPoints(num);
  for (i = 0; i < num; ++i)
    {
    newPoints->SetPoint(i,input->GetPoint(i));
    }

  outCD->CopyAllocate(inCD,input->GetNumberOfCells()*5);
  output->Allocate(input->GetNumberOfCells()*5);

  if (input->IsA("vtkStructuredPoints"))
    {
    static_cast<vtkStructuredPoints*>(input)->GetDimensions(dimensions);
    }
  else if (input->IsA("vtkStructuredGrid"))
    {
    static_cast<vtkStructuredGrid*>(input)->GetDimensions(dimensions);
    }
  else if (input->IsA("vtkImageData"))
    {
    static_cast<vtkImageData*>(input)->GetDimensions(dimensions);
    }
  else if (input->IsA("vtkRectilinearGrid"))
    {
    static_cast<vtkRectilinearGrid*>(input)->GetDimensions(dimensions);
    }

  dimensions[0] = dimensions[0] - 1;
  dimensions[1] = dimensions[1] - 1;
  dimensions[2] = dimensions[2] - 1;

  vtkIdType numSlices = ( dimensions[2] > 0 ? dimensions[2] : 1 );
  int abort=0;
  for (k = 0; k < numSlices && !abort; k++)
    {
    this->UpdateProgress((double)k / numSlices);
    abort = this->GetAbortExecute();

    for (j = 0; j < dimensions[1]; j++)
      {
      for (i = 0; i < dimensions[0]; i++)
        {
        inId = i+(j+(k*dimensions[1]))*dimensions[0];
        input->GetCell(inId, cell);
        if ((i+j+k)%2 == 0)
          {
          cell->Triangulate(0, cellPtIds, cellPts);
          }
        else
          {
          cell->Triangulate(1, cellPtIds, cellPts);
          }

        dim = cell->GetCellDimension() + 1;

        numPts = cellPtIds->GetNumberOfIds();
        numSimplices = numPts / dim;
        type = 0;
        switch (dim)
          {
          case 1:
            type = VTK_VERTEX;    break;
          case 2:
            type = VTK_LINE;      break;
          case 3:
            type = VTK_TRIANGLE;  break;
          case 4:
            type = VTK_TETRA;     break;
          }
        if (!this->TetrahedraOnly || type == VTK_TETRA)
          {
          for (l = 0; l < numSimplices; l++ )
            {
            for (m = 0; m < dim; m++)
              {
              pts[m] = cellPtIds->GetId(dim*l+m);
              }
            // copy cell data
            newCellId = output->InsertNextCell(type, dim, pts);
            outCD->CopyData(inCD, inId, newCellId);
            }//for all simplices
          }
        }//i dimension
      }//j dimension
    }//k dimension

  // Update output
  output->SetPoints(newPoints);
  output->GetPointData()->PassData(input->GetPointData());
  output->Squeeze();

  cell->Delete();
  newPoints->Delete();
  cellPts->Delete();
  cellPtIds->Delete();
}

// 3D cells use the ordered triangulator. The ordered triangulator is used
// to create templates on the fly. Once the templates are created then they
// are used to produce the final triangulation.
//
void vtkDataSetTriangleFilter::UnstructuredExecute(vtkDataSet *dataSetInput,
                                                   vtkUnstructuredGrid *output)
{
  vtkPointSet *input = (vtkPointSet*) dataSetInput; //has to be
  vtkIdType numCells = input->GetNumberOfCells();
  vtkGenericCell *cell;
  vtkIdType newCellId, j;
  int k;
  vtkCellData *inCD=input->GetCellData();
  vtkCellData *outCD=output->GetCellData();
  vtkPoints *cellPts;
  vtkIdList *cellPtIds;
  vtkIdType ptId, numTets, ncells;
  int numPts, type;
  int numSimplices, dim;
  vtkIdType pts[4];
  double x[3];

  if (numCells == 0)
    {
    return;
    }

  cell = vtkGenericCell::New();
  cellPts = vtkPoints::New();
  cellPtIds = vtkIdList::New();

  // Create an array of points
  outCD->CopyAllocate(inCD,input->GetNumberOfCells()*5);
  output->Allocate(input->GetNumberOfCells()*5);

  // Points are passed through
  output->SetPoints(input->GetPoints());
  output->GetPointData()->PassData(input->GetPointData());

  int abort=0;
  vtkIdType updateTime = numCells/20 + 1;  // update roughly every 5%
  for (vtkIdType cellId=0; cellId < numCells && !abort; cellId++)
    {
    if ( !(cellId % updateTime) )
      {
      this->UpdateProgress((double)cellId / numCells);
      abort = this->GetAbortExecute();
      }

    input->GetCell(cellId, cell);
    dim = cell->GetCellDimension();

    if ( dim == 3 ) //use ordered triangulation
      {
      numPts = cell->GetNumberOfPoints();
      double *p, *pPtr=cell->GetParametricCoords();
      this->Triangulator->InitTriangulation(0.0,1.0, 0.0,1.0, 0.0,1.0, numPts);
      for (p=pPtr, j=0; j<numPts; j++, p+=3)
        {
        ptId = cell->PointIds->GetId(j);
        cell->Points->GetPoint(j, x);
        this->Triangulator->InsertPoint(ptId, x, p, 0);
        }//for all cell points
      if ( cell->IsPrimaryCell() ) //use templates if topology is fixed
        {
        int numEdges=cell->GetNumberOfEdges();
        this->Triangulator->TemplateTriangulate(cell->GetCellType(),
                                                numPts,numEdges);
        }
      else //use ordered triangulator
        {
        this->Triangulator->Triangulate();
        }

      ncells = output->GetNumberOfCells();
      numTets = this->Triangulator->AddTetras(0,output);

      for (j=0; j < numTets; j++)
        {
        outCD->CopyData(inCD, cellId, ncells+j);
        }
      }

    else if (!this->TetrahedraOnly) //2D or lower dimension
      {
      dim++;
      cell->Triangulate(0, cellPtIds, cellPts);
      numPts = cellPtIds->GetNumberOfIds();

      numSimplices = numPts / dim;
      type = 0;
      switch (dim)
        {
        case 1:
          type = VTK_VERTEX;    break;
        case 2:
          type = VTK_LINE;      break;
        case 3:
          type = VTK_TRIANGLE;  break;
        }

      for ( j=0; j < numSimplices; j++ )
        {
        for (k=0; k<dim; k++)
          {
          pts[k] = cellPtIds->GetId(dim*j+k);
          }
        // copy cell data
        newCellId = output->InsertNextCell(type, dim, pts);
        outCD->CopyData(inCD, cellId, newCellId);
        }
      } //if 2D or less cell
    } //for all cells

  // Update output
  output->Squeeze();

  cellPts->Delete();
  cellPtIds->Delete();
  cell->Delete();
}

int vtkDataSetTriangleFilter::FillInputPortInformation(int, vtkInformation *info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
  return 1;
}

void vtkDataSetTriangleFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "TetrahedraOnly: " << (this->TetrahedraOnly ? "On":"Off") << "\n";
}

<commit_msg>PERF: If all the cells in a ugrid are already simplices, just shallowcopy the input to the output..<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkDataSetTriangleFilter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkDataSetTriangleFilter.h"

#include "vtkCellData.h"
#include "vtkCellType.h"
#include "vtkGenericCell.h"
#include "vtkIdList.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkOrderedTriangulator.h"
#include "vtkPointData.h"
#include "vtkStructuredGrid.h"
#include "vtkStructuredPoints.h"
#include "vtkUnstructuredGrid.h"
#include "vtkRectilinearGrid.h"
#include "vtkUnsignedCharArray.h"

vtkCxxRevisionMacro(vtkDataSetTriangleFilter, "1.28");
vtkStandardNewMacro(vtkDataSetTriangleFilter);

vtkDataSetTriangleFilter::vtkDataSetTriangleFilter()
{
  this->Triangulator = vtkOrderedTriangulator::New();
  this->Triangulator->PreSortedOff();
  this->Triangulator->UseTemplatesOn();
  this->TetrahedraOnly = 0;
}

vtkDataSetTriangleFilter::~vtkDataSetTriangleFilter()
{
  this->Triangulator->Delete();
  this->Triangulator = NULL;
}

int vtkDataSetTriangleFilter::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the input and ouptut
  vtkDataSet *input = vtkDataSet::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (input->IsA("vtkStructuredPoints") ||
      input->IsA("vtkStructuredGrid") ||
      input->IsA("vtkImageData") ||
      input->IsA("vtkRectilinearGrid"))
    {
    this->StructuredExecute(input, output);
    }
  else
    {
    this->UnstructuredExecute(input, output);
    }

  vtkDebugMacro(<<"Produced " << this->GetOutput()->GetNumberOfCells() << " cells");

  return 1;
}

void vtkDataSetTriangleFilter::StructuredExecute(vtkDataSet *input,
                                                 vtkUnstructuredGrid *output)
{
  int dimensions[3], i, j, k, l, m;
  vtkIdType newCellId, inId;
  vtkGenericCell *cell = vtkGenericCell::New();
  vtkCellData *inCD = input->GetCellData();
  vtkCellData *outCD = output->GetCellData();
  vtkPoints *cellPts = vtkPoints::New();
  vtkPoints *newPoints = vtkPoints::New();
  vtkIdList *cellPtIds = vtkIdList::New();
  int numSimplices, numPts, dim, type;
  vtkIdType pts[4], num;

  // Create an array of points. This does an explicit creation
  // of each point.
  num = input->GetNumberOfPoints();
  newPoints->SetNumberOfPoints(num);
  for (i = 0; i < num; ++i)
    {
    newPoints->SetPoint(i,input->GetPoint(i));
    }

  outCD->CopyAllocate(inCD,input->GetNumberOfCells()*5);
  output->Allocate(input->GetNumberOfCells()*5);

  if (input->IsA("vtkStructuredPoints"))
    {
    static_cast<vtkStructuredPoints*>(input)->GetDimensions(dimensions);
    }
  else if (input->IsA("vtkStructuredGrid"))
    {
    static_cast<vtkStructuredGrid*>(input)->GetDimensions(dimensions);
    }
  else if (input->IsA("vtkImageData"))
    {
    static_cast<vtkImageData*>(input)->GetDimensions(dimensions);
    }
  else if (input->IsA("vtkRectilinearGrid"))
    {
    static_cast<vtkRectilinearGrid*>(input)->GetDimensions(dimensions);
    }

  dimensions[0] = dimensions[0] - 1;
  dimensions[1] = dimensions[1] - 1;
  dimensions[2] = dimensions[2] - 1;

  vtkIdType numSlices = ( dimensions[2] > 0 ? dimensions[2] : 1 );
  int abort=0;
  for (k = 0; k < numSlices && !abort; k++)
    {
    this->UpdateProgress((double)k / numSlices);
    abort = this->GetAbortExecute();

    for (j = 0; j < dimensions[1]; j++)
      {
      for (i = 0; i < dimensions[0]; i++)
        {
        inId = i+(j+(k*dimensions[1]))*dimensions[0];
        input->GetCell(inId, cell);
        if ((i+j+k)%2 == 0)
          {
          cell->Triangulate(0, cellPtIds, cellPts);
          }
        else
          {
          cell->Triangulate(1, cellPtIds, cellPts);
          }

        dim = cell->GetCellDimension() + 1;

        numPts = cellPtIds->GetNumberOfIds();
        numSimplices = numPts / dim;
        type = 0;
        switch (dim)
          {
          case 1:
            type = VTK_VERTEX;    break;
          case 2:
            type = VTK_LINE;      break;
          case 3:
            type = VTK_TRIANGLE;  break;
          case 4:
            type = VTK_TETRA;     break;
          }
        if (!this->TetrahedraOnly || type == VTK_TETRA)
          {
          for (l = 0; l < numSimplices; l++ )
            {
            for (m = 0; m < dim; m++)
              {
              pts[m] = cellPtIds->GetId(dim*l+m);
              }
            // copy cell data
            newCellId = output->InsertNextCell(type, dim, pts);
            outCD->CopyData(inCD, inId, newCellId);
            }//for all simplices
          }
        }//i dimension
      }//j dimension
    }//k dimension

  // Update output
  output->SetPoints(newPoints);
  output->GetPointData()->PassData(input->GetPointData());
  output->Squeeze();

  cell->Delete();
  newPoints->Delete();
  cellPts->Delete();
  cellPtIds->Delete();
}

// 3D cells use the ordered triangulator. The ordered triangulator is used
// to create templates on the fly. Once the templates are created then they
// are used to produce the final triangulation.
//
void vtkDataSetTriangleFilter::UnstructuredExecute(vtkDataSet *dataSetInput,
                                                   vtkUnstructuredGrid *output)
{
  vtkPointSet *input = (vtkPointSet*) dataSetInput; //has to be
  vtkIdType numCells = input->GetNumberOfCells();
  vtkGenericCell *cell;
  vtkIdType newCellId, j;
  int k;
  vtkCellData *inCD=input->GetCellData();
  vtkCellData *outCD=output->GetCellData();
  vtkPoints *cellPts;
  vtkIdList *cellPtIds;
  vtkIdType ptId, numTets, ncells;
  int numPts, type;
  int numSimplices, dim;
  vtkIdType pts[4];
  double x[3];

  if (numCells == 0)
    {
    return;
    }

  vtkUnstructuredGrid * inUgrid =
    vtkUnstructuredGrid::SafeDownCast(dataSetInput);
  if (inUgrid)
    {
    //avoid doing cell simplification if all cells are already simplices
    vtkUnsignedCharArray* cellTypes = inUgrid->GetCellTypesArray();
    if (cellTypes)
      {
      int allsimplices = 1;
      for (vtkIdType cellId = 0; cellId < cellTypes->GetSize() && allsimplices; cellId++)
        {
        switch (cellTypes->GetValue(cellId))
          {
          case VTK_TETRA:
            break;
          case VTK_VERTEX:
          case VTK_LINE:
          case VTK_TRIANGLE:
            if (this->TetrahedraOnly)
              {
              allsimplices = 0; //don't shallowcopy need to stip non tets
              }
            break;
          default:
            allsimplices = 0;
            break;
          }
        }
      if (allsimplices)
        {
        output->ShallowCopy(input);
        return;
        }
      }
    }

  cell = vtkGenericCell::New();
  cellPts = vtkPoints::New();
  cellPtIds = vtkIdList::New();

  // Create an array of points
  outCD->CopyAllocate(inCD,input->GetNumberOfCells()*5);
  output->Allocate(input->GetNumberOfCells()*5);

  // Points are passed through
  output->SetPoints(input->GetPoints());
  output->GetPointData()->PassData(input->GetPointData());

  int abort=0;
  vtkIdType updateTime = numCells/20 + 1;  // update roughly every 5%
  for (vtkIdType cellId=0; cellId < numCells && !abort; cellId++)
    {
    if ( !(cellId % updateTime) )
      {
      this->UpdateProgress((double)cellId / numCells);
      abort = this->GetAbortExecute();
      }

    input->GetCell(cellId, cell);
    dim = cell->GetCellDimension();

    if ( dim == 3 ) //use ordered triangulation
      {
      numPts = cell->GetNumberOfPoints();
      double *p, *pPtr=cell->GetParametricCoords();
      this->Triangulator->InitTriangulation(0.0,1.0, 0.0,1.0, 0.0,1.0, numPts);
      for (p=pPtr, j=0; j<numPts; j++, p+=3)
        {
        ptId = cell->PointIds->GetId(j);
        cell->Points->GetPoint(j, x);
        this->Triangulator->InsertPoint(ptId, x, p, 0);
        }//for all cell points
      if ( cell->IsPrimaryCell() ) //use templates if topology is fixed
        {
        int numEdges=cell->GetNumberOfEdges();
        this->Triangulator->TemplateTriangulate(cell->GetCellType(),
                                                numPts,numEdges);
        }
      else //use ordered triangulator
        {
        this->Triangulator->Triangulate();
        }

      ncells = output->GetNumberOfCells();
      numTets = this->Triangulator->AddTetras(0,output);

      for (j=0; j < numTets; j++)
        {
        outCD->CopyData(inCD, cellId, ncells+j);
        }
      }

    else if (!this->TetrahedraOnly) //2D or lower dimension
      {
      dim++;
      cell->Triangulate(0, cellPtIds, cellPts);
      numPts = cellPtIds->GetNumberOfIds();

      numSimplices = numPts / dim;
      type = 0;
      switch (dim)
        {
        case 1:
          type = VTK_VERTEX;    break;
        case 2:
          type = VTK_LINE;      break;
        case 3:
          type = VTK_TRIANGLE;  break;
        }

      for ( j=0; j < numSimplices; j++ )
        {
        for (k=0; k<dim; k++)
          {
          pts[k] = cellPtIds->GetId(dim*j+k);
          }
        // copy cell data
        newCellId = output->InsertNextCell(type, dim, pts);
        outCD->CopyData(inCD, cellId, newCellId);
        }
      } //if 2D or less cell
    } //for all cells

  // Update output
  output->Squeeze();

  cellPts->Delete();
  cellPtIds->Delete();
  cell->Delete();
}

int vtkDataSetTriangleFilter::FillInputPortInformation(int, vtkInformation *info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
  return 1;
}

void vtkDataSetTriangleFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "TetrahedraOnly: " << (this->TetrahedraOnly ? "On":"Off") << "\n";
}

<|endoftext|>