<commit_before>#pragma once

#include "units.h"
#include "core.h"
#include "particle.h"
#include "tensor.h"
#include <Eigen/Geometry>
#include <iostream>
#include <cereal/types/base_class.hpp>

/** @brief Faunus main namespace */
namespace Faunus {

struct Random;

/**
 * @brief Simulation geometries and related operations.
 *
 * Other parts of Faunus use directly only Chameleon geometry which serves as an interface. Based on the provided
 * configuration, Chameleon initializes an appropriate concrete implementation, which it encapsulates.
 *
 * To add a new geometry implementation, a class derived from GeometryImplementation is created. Geometry::Variant
 * enum type is extended and an initialization within Chameleon::makeGeometry() is provided. In order to make
 * geometry constructable from a json configuration, the map Chameleon::names is extended. When performance is
 * an issue, inlineable implementation of vdist and boundary can be added into respective methods of Chameleon.
 *
 * All geometry implementation shall be covered by unit tests.
 *
 */
namespace Geometry {
typedef std::function<void(Point &)> BoundaryFunction;
typedef std::function<Point(const Point &, const Point &)> DistanceFunction;

//! Geometry variant used for Chameleon.
enum Variant { CUBOID = 0, SPHERE, CYLINDER, SLIT, HEXAGONAL, OCTAHEDRON, HYPERSPHERE2D };

//! Various methods of volume scaling, @see GeometryBase::setVolume.
enum VolumeMethod { ISOTROPIC, ISOCHORIC, XY, Z };

enum Coordinates { ORTHOGONAL, ORTHOHEXAGONAL, TRUNC_OCTAHEDRAL, NON3D };
enum Boundary { FIXED, PERIODIC };

/**
 * @brief A structure containing a type of boundary condition in each direction.
 *
 * A stub. It can be extended to fully json-configurable boundary conditions.
 */
struct BoundaryCondition {
    typedef Eigen::Matrix<Boundary, 3, 1> BoundaryXYZ;
    // typedef std::pair<std::string, BoundaryXYZ> BoundaryName;
    // static const std::map<std::string, BoundaryXYZ> names; //!< boundary names

    Coordinates coordinates;
    BoundaryXYZ direction;

    template <class Archive> void serialize(Archive &archive) {
        archive(coordinates, direction);
    } //!< Cereal serialisation

    BoundaryCondition(Coordinates coordinates = ORTHOGONAL, BoundaryXYZ boundary = {FIXED, FIXED, FIXED})
        : coordinates(coordinates), direction(boundary){};
};

/**
 * @brief An interface for all geometries.
 */
struct GeometryBase {
    virtual Point setVolume(double, VolumeMethod = ISOTROPIC) = 0; //!< Set volume
    virtual double getVolume(int = 3) const = 0;                   //!< Get volume
    virtual void boundary(Point &) const = 0;                      //!< Apply boundary conditions
    virtual bool collision(const Point &) const = 0;               //!< Overlap with boundaries
    virtual void randompos(Point &, Random &) const = 0;           //!< Generate random position
    virtual Point vdist(const Point &, const Point &) const = 0;   //!< (Minimum) distance between two points
    virtual Point getLength() const = 0;                           //!< Side lengths
    virtual ~GeometryBase();
    virtual void to_json(json &j) const = 0;
    virtual void from_json(const json &j) = 0;

    inline BoundaryFunction getBoundaryFunc() const {
        return [this](Point &i) { boundary(i); };
    } //!< returns lambda to boundary()

    inline DistanceFunction getDistanceFunc() const {
        return [this](const Point &i, const Point &j) { return vdist(i, j); };
    } //!< returns lambda to vdist()

  protected:
    template <typename T = double> inline int anint(T x) const {
        return int(x > 0.0 ? x + 0.5 : x - 0.5);
    } //!< Round to int

}; //!< Base class for all geometries

/**
 * @brief A base class for various geometries implementations.
 */
class GeometryImplementation : public GeometryBase {
  public:
    BoundaryCondition boundary_conditions;

    virtual ~GeometryImplementation();

    //! A unique pointer to a copy of self. To be used in copy constructors.
    virtual std::unique_ptr<GeometryImplementation> clone() const = 0;

    //! Cereal serialisation
    template <class Archive> void serialize(Archive &archive) { archive(boundary_conditions); }
};

/**
 * @brief The cuboid geometry with periodic boundary conditions possibly applied in all three directions.
 */
class Cuboid : public GeometryImplementation {
  protected:
    Point box, box_half, box_inv;

  public:
    Point getLength() const override;
    double getVolume(int dim = 3) const final; // finalized to help the compiler with inlining
    void setLength(const Point &len);          // todo shall be protected
    Point setVolume(double volume, VolumeMethod method = ISOTROPIC) override;
    Point vdist(const Point &a, const Point &b) const override;
    void boundary(Point &a) const override;
    bool collision(const Point &a) const override;
    void randompos(Point &m, Random &rand) const override;
    void from_json(const json &j) override;
    void to_json(json &j) const override;
    Cuboid(const Point &p);
    Cuboid(double x, double y, double z);
    Cuboid(double x = 0.0);

    std::unique_ptr<GeometryImplementation> clone() const override {
        return std::make_unique<Cuboid>(*this);
    }; //!< A unique pointer to a copy of self.

    //! Cereal serialisation
    template <class Archive> void serialize(Archive &archive) {
        archive(cereal::base_class<GeometryImplementation>(this), box);
    }
};

/**
 * @brief A legacy class for the cuboid geometry with periodic boundary conditions only in xy directions.
 *
 * @deprecated Shall be replaced by Cuboid with a proper periodic boundary set on initialization.
 */
class Slit : public Cuboid {
    using Tbase = Cuboid;

  public:
    Slit(const Point &p);
    Slit(double x, double y, double z);
    Slit(double x = 0.0);

    std::unique_ptr<GeometryImplementation> clone() const override {
        return std::make_unique<Slit>(*this);
    }; //!< A unique pointer to a copy of itself.
};

/**
 * @brief The spherical geometry where no periodic boundary condition could be applied.
 */
class Sphere : public GeometryImplementation {
  protected:
    double radius;

  public:
    Point getLength() const override;
    double getVolume(int dim = 3) const override;
    Point setVolume(double volume, VolumeMethod method = ISOTROPIC) override;
    Point vdist(const Point &a, const Point &b) const override;
    void boundary(Point &a) const override;
    bool collision(const Point &a) const override;
    void randompos(Point &m, Random &rand) const override;
    void from_json(const json &j) override;
    void to_json(json &j) const override;
    Sphere(double radius = 0.0);

    std::unique_ptr<GeometryImplementation> clone() const override {
        return std::make_unique<Sphere>(*this);
    }; //!< A unique pointer to a copy of self.

    //! Cereal serialisation
    template <class Archive> void serialize(Archive &archive) {
        archive(cereal::base_class<GeometryImplementation>(this), radius);
    }
};

class Hypersphere2d : public Sphere {
  public:<commit_msg>Add inline Geometry::Sphere::sqdist()<commit_after>#pragma once

#include "units.h"
#include "core.h"
#include "particle.h"
#include "tensor.h"
#include <Eigen/Geometry>
#include <iostream>
#include <cereal/types/base_class.hpp>

/** @brief Faunus main namespace */
namespace Faunus {

struct Random;

/**
 * @brief Simulation geometries and related operations.
 *
 * Other parts of Faunus use directly only Chameleon geometry which serves as an interface. Based on the provided
 * configuration, Chameleon initializes an appropriate concrete implementation, which it encapsulates.
 *
 * To add a new geometry implementation, a class derived from GeometryImplementation is created. Geometry::Variant
 * enum type is extended and an initialization within Chameleon::makeGeometry() is provided. In order to make
 * geometry constructable from a json configuration, the map Chameleon::names is extended. When performance is
 * an issue, inlineable implementation of vdist and boundary can be added into respective methods of Chameleon.
 *
 * All geometry implementation shall be covered by unit tests.
 *
 */
namespace Geometry {
typedef std::function<void(Point &)> BoundaryFunction;
typedef std::function<Point(const Point &, const Point &)> DistanceFunction;

//! Geometry variant used for Chameleon.
enum Variant { CUBOID = 0, SPHERE, CYLINDER, SLIT, HEXAGONAL, OCTAHEDRON, HYPERSPHERE2D };

//! Various methods of volume scaling, @see GeometryBase::setVolume.
enum VolumeMethod { ISOTROPIC, ISOCHORIC, XY, Z };

enum Coordinates { ORTHOGONAL, ORTHOHEXAGONAL, TRUNC_OCTAHEDRAL, NON3D };
enum Boundary { FIXED, PERIODIC };

/**
 * @brief A structure containing a type of boundary condition in each direction.
 *
 * A stub. It can be extended to fully json-configurable boundary conditions.
 */
struct BoundaryCondition {
    typedef Eigen::Matrix<Boundary, 3, 1> BoundaryXYZ;
    // typedef std::pair<std::string, BoundaryXYZ> BoundaryName;
    // static const std::map<std::string, BoundaryXYZ> names; //!< boundary names

    Coordinates coordinates;
    BoundaryXYZ direction;

    template <class Archive> void serialize(Archive &archive) {
        archive(coordinates, direction);
    } //!< Cereal serialisation

    BoundaryCondition(Coordinates coordinates = ORTHOGONAL, BoundaryXYZ boundary = {FIXED, FIXED, FIXED})
        : coordinates(coordinates), direction(boundary){};
};

/**
 * @brief An interface for all geometries.
 */
struct GeometryBase {
    virtual Point setVolume(double, VolumeMethod = ISOTROPIC) = 0; //!< Set volume
    virtual double getVolume(int = 3) const = 0;                   //!< Get volume
    virtual void boundary(Point &) const = 0;                      //!< Apply boundary conditions
    virtual bool collision(const Point &) const = 0;               //!< Overlap with boundaries
    virtual void randompos(Point &, Random &) const = 0;           //!< Generate random position
    virtual Point vdist(const Point &, const Point &) const = 0;   //!< (Minimum) distance between two points
    virtual Point getLength() const = 0;                           //!< Side lengths
    virtual ~GeometryBase();
    virtual void to_json(json &j) const = 0;
    virtual void from_json(const json &j) = 0;

    inline BoundaryFunction getBoundaryFunc() const {
        return [this](Point &i) { boundary(i); };
    } //!< returns lambda to boundary()

    inline DistanceFunction getDistanceFunc() const {
        return [this](const Point &i, const Point &j) { return vdist(i, j); };
    } //!< returns lambda to vdist()

  protected:
    template <typename T = double> inline int anint(T x) const {
        return int(x > 0.0 ? x + 0.5 : x - 0.5);
    } //!< Round to int

}; //!< Base class for all geometries

/**
 * @brief A base class for various geometries implementations.
 */
class GeometryImplementation : public GeometryBase {
  public:
    BoundaryCondition boundary_conditions;

    virtual ~GeometryImplementation();

    //! A unique pointer to a copy of self. To be used in copy constructors.
    virtual std::unique_ptr<GeometryImplementation> clone() const = 0;

    //! Cereal serialisation
    template <class Archive> void serialize(Archive &archive) { archive(boundary_conditions); }
};

/**
 * @brief The cuboid geometry with periodic boundary conditions possibly applied in all three directions.
 */
class Cuboid : public GeometryImplementation {
  protected:
    Point box, box_half, box_inv;

  public:
    Point getLength() const override;
    double getVolume(int dim = 3) const final; // finalized to help the compiler with inlining
    void setLength(const Point &len);          // todo shall be protected
    Point setVolume(double volume, VolumeMethod method = ISOTROPIC) override;
    Point vdist(const Point &a, const Point &b) const override;
    void boundary(Point &a) const override;
    bool collision(const Point &a) const override;
    void randompos(Point &m, Random &rand) const override;
    void from_json(const json &j) override;
    void to_json(json &j) const override;
    Cuboid(const Point &p);
    Cuboid(double x, double y, double z);
    Cuboid(double x = 0.0);

    std::unique_ptr<GeometryImplementation> clone() const override {
        return std::make_unique<Cuboid>(*this);
    }; //!< A unique pointer to a copy of self.

    //! Cereal serialisation
    template <class Archive> void serialize(Archive &archive) {
        archive(cereal::base_class<GeometryImplementation>(this), box);
    }
};

/**
 * @brief A legacy class for the cuboid geometry with periodic boundary conditions only in xy directions.
 *
 * @deprecated Shall be replaced by Cuboid with a proper periodic boundary set on initialization.
 */
class Slit : public Cuboid {
    using Tbase = Cuboid;

  public:
    Slit(const Point &p);
    Slit(double x, double y, double z);
    Slit(double x = 0.0);

    std::unique_ptr<GeometryImplementation> clone() const override {
        return std::make_unique<Slit>(*this);
    }; //!< A unique pointer to a copy of itself.
};

/**
 * @brief The spherical geometry where no periodic boundary condition could be applied.
 */
class Sphere : public GeometryImplementation {
  protected:
    double radius;

  public:
    Point getLength() const override;
    double getVolume(int dim = 3) const override;
    Point setVolume(double volume, VolumeMethod method = ISOTROPIC) override;
    Point vdist(const Point &a, const Point &b) const override;
    double sqdist(const Point &a, const Point &b) const { return (a - b).squaredNorm(); };
    void boundary(Point &a) const override;
    bool collision(const Point &a) const override;
    void randompos(Point &m, Random &rand) const override;
    void from_json(const json &j) override;
    void to_json(json &j) const override;
    Sphere(double radius = 0.0);

    std::unique_ptr<GeometryImplementation> clone() const override {
        return std::make_unique<Sphere>(*this);
    }; //!< A unique pointer to a copy of self.

    //! Cereal serialisation
    template <class Archive> void serialize(Archive &archive) {
        archive(cereal::base_class<GeometryImplementation>(this), radius);
    }
};

class Hypersphere2d : public Sphere {
  public:
{'fraction_non_alphanumeric': 0.10086092251697347, 'fraction_numerical': 0.004339609435150837, 'mean_word_length': 3.6465040650406504, 'pattern_counts': {'":': 0, '<': 79, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1624162', 'n_tokens_mistral': 4137, 'n_tokens_neox': 3923, 'n_words': 1458}