Program Listing for File raytracer.h

Return to documentation for file (framework/mesh/raytrace/raytracer.h)

// SPDX-FileCopyrightText: 2024 The OpenSn Authors <https://open-sn.github.io/opensn/>
// SPDX-License-Identifier: MIT

#pragma once

#include "framework/mesh/mesh.h"
#include "framework/mesh/cell/cell.h"
#include "framework/data_types/vector3.h"

namespace opensn
{

class Cell;
class MeshContinuum;

/// Data structure to hold output info from the raytracer.
struct RayTracerOutputInformation
{
  double distance_to_surface = 0.0;
  Vector3 pos_f;
  unsigned int destination_face_index = 0;
  uint64_t destination_face_neighbor = 0;
  bool particle_lost = false;
  std::string lost_particle_info;
};

/// Raytracer object.
class RayTracer
{
private:
  const std::shared_ptr<MeshContinuum> reference_grid_;
  std::vector<double> cell_sizes_;
  double epsilon_nudge_ = 1.0e-8;
  double backward_tolerance_ = 1.0e-10;
  double extension_distance_ = 1.0e5;
  bool perform_concavity_checks_ = true;

public:
  explicit RayTracer(const std::shared_ptr<MeshContinuum> grid,
                     std::vector<double> cell_sizes,
                     bool perform_concavity_checks = true)
    : reference_grid_(grid),
      cell_sizes_(std::move(cell_sizes)),
      perform_concavity_checks_(perform_concavity_checks)
  {
  }

private:
  const std::shared_ptr<MeshContinuum> Grid() const;

  void SetTolerancesFromCellSize(double cell_size)
  {
    epsilon_nudge_ = cell_size * 1.0e-2;
    backward_tolerance_ = cell_size * 1.0e-10;
    extension_distance_ = 3.0 * cell_size;
  }

public:
  /**
   * Traces a ray with an initial position either within the cell or on the cell surface, and with a
   * direction vector pointing inward toward the cell. If the ray-trace fails the particle will be
   * marked as lost.
   */
  RayTracerOutputInformation
  TraceRay(const Cell& cell, Vector3& pos_i, Vector3& omega_i, int function_depth = 0);

  /// Traces a ray with an initial position, presumed to be outside the cell, to an incident face.
  RayTracerOutputInformation
  TraceIncidentRay(const Cell& cell, const Vector3& pos_i, const Vector3& omega_i);

private:
  /// Performs raytracing within a 1D-slab.
  void TraceSlab(const Cell& cell,
                 Vector3& pos_i,
                 Vector3& omega_i,
                 bool& intersection_found,
                 bool& backward_tolerance_hit,
                 RayTracerOutputInformation& oi);

  /// Performs raytracing within a 2D Polygon.
  void TracePolygon(const Cell& cell,
                    Vector3& pos_i,
                    Vector3& omega_i,
                    bool& intersection_found,
                    bool& backward_tolerance_hit,
                    RayTracerOutputInformation& oi);

  /// Performs raytracing within a 3D Polyhedron.
  void TracePolyhedron(const Cell& cell,
                       Vector3& pos_i,
                       Vector3& omega_i,
                       bool& intersection_found,
                       bool& backward_tolerance_hit,
                       RayTracerOutputInformation& oi);
};

/**
 * Computes the intersection of a line with a plane.
 *
 * The first step of this algorithm is to compute v0 and v1. These
 * are vectors from the plane's reference point to each of the line-points,
 * respectively.
 * We then take the dot-products of these
 * vectors with the plane normal.
 * We then say that the vectors have a positive sense if the dot-product
 * is positive and a negative sense if the dot-product is negative.
 * If the senses are not equal then the line intersects the plane.
 *
 * Since the face normal is a normalized vector the dot-product of v0 or v1
 * will give the projection of the relevant vector along the normal to the
 * plane. We can use this projection to compute a weight associated with
 * each vector. This also then allows us to compute the intersection point.
 *
 * \param plane_normal The normal associated with the plane
 * \param plane_point The reference point for the plane
 * \param line_point_0 The line's initial point
 * \param line_point_1 The line's destination point
 * \param intersection_point The point to be populated with the intersection
 *                           point
 * \param weights The weights associated with this intersection
 *
 * \return Returns true if the line intersects the plane and false otherwise.
 */
bool CheckPlaneLineIntersect(const Vector3& plane_normal,
                             const Vector3& plane_point,
                             const Vector3& line_point_0,
                             const Vector3& line_point_1,
                             Vector3& intersection_point,
                             std::pair<double, double>* weights = nullptr);

/**
 * Given a strip defined by two points (v0,v1) and a normal, n, (meaning infinite in the direction
 * defined by (v1-v0).cross(n), this function determines if a line, defined from p0 to p1,
 * intersects it. If it does then `true` is returned and `intersection_point` contains the point of
 * intersection. If it does not then `false` is returned and `intersection_point` remains unchanged.
 */
bool CheckLineIntersectStrip(const Vector3& strip_point0,
                             const Vector3& strip_point1,
                             const Vector3& strip_normal,
                             const Vector3& line_point0,
                             const Vector3& line_point1,
                             Vector3& intersection_point,
                             double* distance_to_intersection = nullptr);

/// Given a triangle defined by three points, computes whether a line intersects this triangle.
bool CheckLineIntersectTriangle2(const Vector3& tri_point0,
                                 const Vector3& tri_point1,
                                 const Vector3& tri_point2,
                                 const Vector3& ray_posi,
                                 const Vector3& ray_dir,
                                 Vector3& intersection_point,
                                 double* distance_to_intersection = nullptr);

/// Check whether a point lies in a triangle.
bool CheckPointInTriangle(
  const Vector3& v0, const Vector3& v1, const Vector3& v2, const Vector3& n, const Vector3& point);

/**
 * This functions checks the intersection of a plane with a tetrahedron.
 * The equation of a plane is
 *      nx(x-x0) + ny(y-y0) + nz(z-z0) = 0
 * Where the plane normal is (nx,ny,nz) and the plane point is (x0,y0,z0).
 * If we form a dot product between the normal and a vector (x-x0,y-y0,z-z0) then sign of the result
 * gives the sense to the surface. Therefore, if we encounter differing senses then the plane is
 * indeed intersecting.
 */
bool CheckPlaneTetIntersect(const Vector3& plane_normal,
                            const Vector3& plane_point,
                            const std::vector<Vector3>& tet_points);

/// Populates segment lengths along a ray. Sorted along the direction.
void PopulateRaySegmentLengths(const std::shared_ptr<MeshContinuum> grid,
                               const Cell& cell,
                               const Vector3& line_point0,
                               const Vector3& line_point1,
                               const Vector3& omega,
                               std::vector<double>& segment_lengths);

} // namespace opensn