Math¶
mutomMath adds geometry, meshes, event containers, images,
transforms, and algorithms to Core. The primary
namespace is uLib; a handful of lower-level image APIs live in
uLib::Abstract.
Geometry and transforms¶
The library's common geometry values are Eigen-compatible aliases declared in
uLib/Math/Geometry.h: HPoint3f,
HVector3f, HMatrix3f, HLine3f,
HPlane3f, and their d (double precision) variants.
Geometry, LinearGeometry,
CylindricalGeometry, SphericalGeometry, and
ToroidalGeometry describe coordinate systems.
AffineTransform stores a matrix transform as an editable Core
object. TRS stores position, rotation, and scale; the
TransformModifier algorithm applies transforms to compatible
objects. ClosestApproach provides line/line closest-approach
calculations.
#include <Math/Dense.h>
#include <Math/Transform.h>
uLib::HLine3f ray;
ray.origin = uLib::HPoint3f{1.0f, 2.0f, 3.0f};
ray.direction = uLib::HVector3f{0.0f, 0.0f, 1.0f};
uLib::TRS pose;
pose.Position.Set({10.0f, 0.0f, 0.0f});
pose.Rotation.Set({0.0f, 0.0f, 0.5f}); // Euler angles, in radians
Scene objects, meshes, and point data¶
All of these are uLib::Object descendants and can be placed in
an ObjectsContext.
| Class | Use |
|---|---|
ContainerBox, Assembly |
Structural/grouping objects for a scene or data hierarchy. |
Cylinder |
Editable cylindrical domain object. |
PointSet |
Point coordinates with scalar/vector point attributes. |
Polydata |
General polygonal data and attributes. |
TriangleMesh, QuadMesh, TessellatedMesh |
Surface meshes with triangle, quad, or generic tessellated topology. |
StructuredData, Structured2DGrid, Structured4DGrid, StructuredGrid |
Regular-grid data, geometry, and point/cell arrays. |
MultiVoxImage |
Named collection of voxel images. |
#include <Core/ObjectsContext.h>
#include <Math/ContainerBox.h>
#include <Math/PointSet.h>
uLib::ObjectsContext context;
auto *group = context.CreateObject<uLib::ContainerBox>("measurements");
auto *points = context.CreateObject<uLib::PointSet>("hits");
group->AddObject(points);
points->Add(0.0, 0.0);
points->Add(1.0, 0.0);
points->Add(1.0, 1.0);
PointSet, meshes, and grids use Core properties where they need
to participate in synchronization. Use their public data APIs for bulk
coordinates and attributes, then call the documented update method when the
specific type requires one.
Images, voxels, and ray tracing¶
Abstract::VoxImage is the common image-object base.
VoxImage<Voxel> is the templated voxel volume, while
VoxChannel represents one channel and MultiVoxImage
groups several images. Voxel is supplied for the supported
voxel payloads.
VoxRaytracer intersects a ray with a voxel image. Its result
contains RayData::Element entries, each reporting the traversed
voxel and segment information. VoxImageFilter and the
VoxFilterAlgorithm* classes provide reusable filtering pipelines:
linear, median, threshold, trimmed, bilateral, Gaussian, and custom filters.
#include <Math/VoxImage.h>
#include <Math/VoxRaytracer.h>
uLib::VoxImage<uLib::Voxel> image{uLib::Vector3i{64, 64, 64}};
image.SetSpacing({2.0f, 2.0f, 2.0f});
uLib::VoxRaytracer tracer{image};
const auto path = tracer.TraceLine(ray);
for (const auto &element : path.Data()) {
// element.vox_id identifies a crossed voxel; element.L is its segment length.
}
The precise image construction calls vary by voxel payload and version.
The catalog links to the owning headers; the
VoxImageTest and VoxRaytracerTest test targets are
also useful executable references.
Voxels on the GPU¶
Abstract::VoxImage carries a PreferredDevice
property -- Host, or Device for the voxel block to
be kept in GPU memory so an algorithm or a Python recipe working there reads
it without a copy. It needs no CUDA toolkit (device memory is the driver's
job) and it never claims a move it did not make:
GetDataLocation() says where the voxels are and why.
image.SetPreferredDevice(uLib::MemoryDevice::VRAM);
uLib::DeviceArrayView view;
if (image.GetDeviceArray(view)) {
// view.data is a device pointer to the first voxel's Value, one every
// view.stride bytes -- what a kernel, numba or CuPy is pointed at.
}
A scene to open: assets/examples/math/02_images_on_the_gpu.gcx,
written by src/Math/examples/02_images_on_the_gpu.cpp. The whole
mechanism is in
Data on the GPU.
Histograms and event tables¶
HistogramAxis describes one binned axis and
Histogram stores the resulting counts. EventTable
is a tabular, serializable event-data object. They are appropriate when data
has a natural analytical representation rather than a scene topology.
#include <Math/Histogram.h>
uLib::HistogramAxis axis{"energy", 100, 0.0, 10.0};
uLib::Histogram histogram{{axis}};
histogram.Fill({4.2});
histogram.Fill({4.2}, 0.5);
Scalar, vector, and tensor fields¶
Math/Field.h defines a field as a domain and a function that
gives every point of the domain a value. The domain,
FieldDomain<D>, is an axis-aligned box of any dimension
D, sampled on Dims nodes per axis (both ends
included, first axis fastest). The value type picks the specialization:
| Template | Value | Concrete, registered classes |
|---|---|---|
ScalarField<D> |
double |
ScalarField1d, ScalarField2d, ScalarField3d |
VectorField<D, N = D> |
Eigen::Matrix<double, N, 1> |
VectorField2d, VectorField3d |
TensorField<D, R = D, C = R> |
Eigen::Matrix<double, R, C> |
TensorField2d, TensorField3d |
Every field is also an Algorithm and a
uLib::Function (Core/FunctionObject.h), which maps a
point to a value. It has these ports:
| Port | Direction | Carries |
|---|---|---|
Function |
in | What the field computes: a uLib::Function (a CallableFunction, a Geant MagneticField or ElectricField, or another field), or a Recipe whose function named by FunctionName (default evaluate) is called with each point. |
Points |
in (stream) | The points to map: a stream of FieldSample items, such as a FieldSampleSet, another field, or a buffer. If nothing is connected, the field maps its domain grid. |
Results |
out | A FieldSampleSet that each run fills. |
Samples |
out (stream) | The field itself, as a push stream of FieldSample (point and value). |
What the field computes is resolved in order: the Function port,
then a std::function installed with SetFunction(),
then multilinear interpolation between the field's own samples.
Run() maps every input point, pushes each sample to the output
stream, and adds it to Results. When a consumer reads the
Samples stream while nothing is running, the field maps the next
BatchSize points on demand, because the field is its own
StreamActivator. A chain of fields therefore pulls points through
one batch at a time. When the function source, the domain, or the points
change, the output stream restarts for its next reader.
The domain is three properties (DomainMin, DomainMax,
DomainDims). Samples are cached from the function, or set
directly with SetSamples() or SetSample().
Bake() replaces the function with its samples. Saving a field
writes its domain, its samples, and its settings. The port wires are saved by
the scene document.
Differential operators use central differences:
Gradient and Laplacian for scalar fields;
Jacobian, Divergence, and Curl for
vector fields; and Trace, Determinant, and
Divergence for tensor fields.
AbstractField is the dimension-independent interface. It passes
coordinates and values as flat std::vector<double>, with
tensor components in row-major order.
#include <Math/Field.h>
uLib::VectorField3d wind;
wind.SetDomain(uLib::Vector3d(-1, -1, -1), uLib::Vector3d(1, 1, 1),
uLib::Vector3i(21, 21, 21));
wind.SetFunction([](const uLib::Vector3d &p) {
return uLib::Vector3d(-p.y(), p.x(), 0.1 * p.z());
});
double div = wind.Divergence(uLib::Vector3d(0.2, 0.1, 0.0)); // 0.1
uLib::Vector3d curl = wind.Curl(uLib::Vector3d::Zero()); // (0, 0, 2)
// Or drive the field with a Geant field, and map a set of points through it.
uLib::Geant::MagneticField b("dipole");
b.FieldValue.Set(uLib::Vector3d(0, 0, 1.5));
uLib::VectorField3d map;
map.SetFunctionSource(&b);
uLib::FieldSampleSet probes, results;
probes.AddPoint({0.0, 0.0, 100.0});
map.SetPoints(&probes);
map.SetResults(&results);
map.Run(); // results.At(0).value == {0, 0, 1.5}
Vtk::Field (Vtk/Math/vtkField.h) draws any field.
It samples the field into a vtkImageData. The
Field.Backend display property selects the representation for
the field's rank:
| Field | Backends |
|---|---|
| Scalar | Surface, Volume, Isosurface, Points |
| Vector | Topology (vtkVectorFieldTopology: critical points and separatrices), Glyphs, Streamlines, Magnitude |
| Tensor | Ellipsoids, Boxes (vtkTensorGlyph), Norm |
A scene to open in gcompose:
assets/examples/math/01_vector_fields.gcx, written by
src/Math/examples/01_vector_fields.cpp. It contains a cellular flow
sampled in C++, and a dipole field whose Function port is a Recipe
with a probe line wired to its Points port. Select a field and
change Display > Field > Backend. Run main to map the probes.
Statistical helpers¶
The accumulator types in Accumulator.h support running
statistics:
| Type | Purpose |
|---|---|
Accumulator_Mean |
Mean and standard aggregation. |
Accumulator_ABTrim |
Alpha/beta trimmed aggregation. |
Accumulator_ABClip |
Alpha/beta clipping aggregation. |
They are deliberately small value types, suitable for numeric algorithms and
filters without requiring an ObjectsContext.
Math class catalog¶
See the complete Math catalog for every installed Math public class, grouped by header family. The streaming guide shows how Math objects participate in Core algorithms and data pipelines.