Ponca  aa50bfdf187919869239c5b44b748842569114c1
Point Cloud Analysis library
Loading...
Searching...
No Matches
Fitting Module: User Manual
[Go back to user manual]
[Go to concept page]

Introduction

The fitting module is dedicated to the smooth fitting of point clouds and extraction of useful geometric properties. Figure 1(a) shows a typical example in 2D: we reconstruct a potential function (shown in fake colors) from a few 2D points equipped with normals; then the 0-isoline of this potential gives us an implicit curve (in orange) from which we can readily extract further properties like curvature. A great benefit of this implicit technique [6] is that it works in arbitrary dimensions: Figures 1(b-c) show how we reconstruct an implicit 3D surface with the same approach, starting from a 3D point cloud. Working with meshes then simply consists of only considering their vertices.

Figure 1: (a) An implicit 2D curve fit to a 2D point cloud. (b) A 3D point cloud shown with splats. (c) An implicit 3D surface reconstructed from (b).

This is just the tip of the iceberg though, as we also provide methods for dealing with points equipped with non-oriented normals [4], techniques to analyze points clouds in scale-space to discover salient structures [10], methods to compute multi-scale principal curvatures [11] and methods to compute surface variation using a plane instead of a sphere for the fitting [12].

Design choices and programing techniques

The goal of this module is to provide lightweight, fast and generic algorithms for 3d point cloud processing. We mostly focus on local regression techniques, which are core components of surface reconstruction techniques [2] [6], geometric descriptors [10] [8] or shape analysis techniques [7]. Most of these techniques share similar computation, and can be combined in several ways. For instance, NormalDerivativesCurvatureEstimator estimates curvature values by analyzing the spatial derivatives of a normal field, and can be combined with any normal estimation technique.

In order to ease the association of multiple computational components, the library is based on the Curiously Recurring Template Pattern (CRTP). In contrast with polymorphism, this method allows to combine multiple short computations without adding runtime overhead (both in terms of memory footprint and execution time). Instead, the combination of the computational components is performed and optimized when compiling the program, and thus require more memory and time for this stage.

Because of some properties of the C++ language, our classes does not inherit from a Base interface defining the API, but rather follows concepts, as described in Fitting module: Concepts.

Fitting primitives and compute neighborhood properties

The fitting module provides a unified API to perform computations (e.g. fit a Primitive, compute geometrical properties such as Curvatures) over the neighborhood of a given point. The type of computation is controlled by a type (called Fit in the example below) defined by the user by combining computational components offered in this module. Given an object of type Fit, the client code will always looks as follows:

Fit fit; // Create the user-defined fitting procedure
fit.setWeightFunc(WeightFunc(t)); // Set a weighting function to weight neighbors
fit.init(p); // Set the evaluation position
for(auto& it = vecs.begin(); it != vecs.end(); it++)
fit.addNeighbor(*it); // Traverse neighborhood
fit.finalize(); // Finalize computations

Once computations are done, the Fit object provides both getters to the neighborhood properties (e.g. estimated curvature), and procedures (e.g. projection operator onto the fitted primitive):

cout << "Estimated mean curvature: " << fit.kMean() << "\n"
<< "The initial point " << p.transpose() << "\n"
<< "Is projected at " << fit.project(p).transpose() << endl;

The Spatial Partitioning module provides data-structures to collect neighborhood in point clouds.

Fitting techniques overview

We provide various approaches to approximate, analyze or characterize the geometric properties of local neighborhoods. In most situations, all these tools are based on the estimation of a geometric Primitive approximating the neighborhood, on top of which we provide more advanced computations. The table below summarizes the Primitives available in the library, as well as the associated fitting techniques:

Primitive Required Input Fitting techniques
Barycenter Points only MeanPosition (nD)
Normal Vector Oriented points MeanNormal (nD, co-dimension 1)
Covariance Matrix Points only CovarianceFitBase (nD)
Line Points only CovarianceLineFitImpl (nD)
Plane Points only CovariancePlaneFitImpl (nD)
Plane Oriented points MeanPlaneFitImpl (nD, co-dimension 1)
MongePatch Points only MongePatch (3D)
AlgebraicSphere Points only SphereFitImpl (nD) [6]
AlgebraicSphere Oriented points OrientedSphereFitImpl (nD) [6]
AlgebraicSphere Non-oriented points UnorientedSphereFitImpl (nD) [4]

See section Computational objets, basket and CRTP for more details on how these primitives can be extended for more advanced computation.

Structure of the documentation

In the following, we focus on a basic use of the module, and detail how to:

We also show detail all the available tools for geometrical property estimation (see Section Computational objets, basket and CRTP), with a specific focus on curvature (see Section Computing Curvatures). The last section details how to use this module on CUDA kernels (see Section Cuda).

First Steps

Include directives

The Fitting module defines operators that rely on no data structure and work both with CUDA and C++. These core operators implement atomic scientific contributions that are agnostic of the host application. If you want to use the Fitting module, just include its header:

#include "Ponca/Fitting"

Data Samples

The first step needed to use Ponca is to define how samples are represented inside the module. A strength of Ponca is to define all these structures at compile time to generate optimized code for fast evaluation at runtime.

The class Ponca::Concept::PointConcept defines the interface that has to be implemented to represent a sample. Observe that there is no need for data conversion: all you need to do is to indicate how to access existing data (see the example Ponca data-structure binding).

As an example, let's fit a AlgebraicSphere onto points equipped with normals using Ponca::OrientedSphereFit. To this end, we must define a structure (denoted PointPositionNormal in the example below) containing a normal vector and its associated accessors. Depending on the fitting procedure we will use, we may need to define a MatrixType type. This is for instance required for Computing Curvatures. This leads to the following class:

// Point with position and normal vector
template<typename _Scalar, int _Dim>
class PointPositionNormal
{
public:
enum {Dim = _Dim};
typedef _Scalar Scalar;
typedef Eigen::Matrix<Scalar, Dim, 1> VectorType;
typedef Eigen::Matrix<Scalar, Dim, Dim> MatrixType;
PONCA_MULTIARCH inline PointPositionNormal(
const VectorType &pos = VectorType::Zero(),
const VectorType& normal = VectorType::Zero() )
: m_pos(pos), m_normal(normal) {}
PONCA_MULTIARCH inline const VectorType& pos() const { return m_pos; }
PONCA_MULTIARCH inline const VectorType& normal() const { return m_normal; }
PONCA_MULTIARCH inline VectorType& pos() { return m_pos; }
PONCA_MULTIARCH inline VectorType& normal() { return m_normal; }
private:
VectorType m_pos, m_normal;
};
Note
The macro PONCA_MULTIARCH is optional and required only for Cuda support.

PointPositionNormal needs to be specialized for any scalar type or dimension (you may also use a non-template class directly):

typedef PointPositionNormal<Scalar, Dim> Point;

Definition of the Fitting object

Two template classes must be specialized to configure computations.

  1. The first step consists in specifying a weighting function: it defines how neighbor samples will contribute to the fit, as illustrated in Figure 2(a) in 2D. In this example, we choose a weight based on the Euclidean distance using Ponca::DistWeightFunc, remapped through a bisquare kernel defined in Ponca::SmoothWeightKernel:
    using WeightFunc = DistWeightFunc<Point, SmoothWeightKernel<Scalar> >;
  2. The second step identifies a complete fitting procedure through the specialization of a Ponca::Basket. In our example, we want to apply an Ponca::OrientedSphereFit to input data points, which outputs an Ponca::AlgebraicSphere by default. This leads to the following specialization:
    using Sphere = Basket<Point, WeightFunc, OrientedSphereFit>;

Fitting Process

At this point, most of the hard job has already been performed. All we have to do now is to provide an instance of the weight function, where \(t\) refers to the neighborhood size, and initiate the fit at an arbitrary position \(\mathbf{p}\).

Fit fit1;
fit1.setWeightFunc(WeightFunc(analysisScale));
fit1.init(fitInitPos);
for(auto it = vectorPoints.begin(); it != vectorPoints.end(); ++it)
fit1.addNeighbor(*it);
fit1.finalize();

Then neighbors are added sequentially: in this example, we traverse a simple array, and samples outside of the neighborhood are automatically ignored by the weighting function. Once all neighbors have been incorporated, the fit is performed and results stored in the specialized Basket object. STL-like iterators can be used directly for the fit by calling

Fit fit2;
fit2.setWeightFunc(WeightFunc(analysisScale));
fit2.init(fitInitPos);
fit2.compute(vectorPoints);

Spatial structures can be used to accelerate spatial queries. Consider for instance using the KdTree class with range queries:

Fit fit3;
fit3.setWeightFunc(WeightFunc(analysisScale));
fit3.init(fitInitPos);
fit3.computeWithIds( tree.range_neighbors(fitInitPos, analysisScale), vectorPoints );
Note
Currently, users need to ensure consistency between the query and the fit location/scale. This is expected to be fixed in the upcoming releases.

In these examples, fit1, fit2 and fit3 should perform exactly the same computations, as long a the neighborhood remains the same between the three calls.

Check fitting status

After calling finalize or compute, it is recommended to test the return state of the Fit object before using it:

FIT_RESULT eResult = fit.compute(vecs.begin(), vecs.end()); // or eResult = fit.finalize();
if(eResult == STABLE) // or fit.isStable()
//do your things...
FIT_RESULT
Enum corresponding to the state of a fitting method (and what the finalize function returns)
Definition: enums.h:15
@ STABLE
The fitting is stable and ready to use.
Definition: enums.h:17

Some methods require multiple fitting passes, e.g. MongePatch. This is directly handled by the compute method. If you don't use it, you need to check if eResults == NEED_ANOTHER_PASS and repeat the addNeighbor()/finalize() steps. Don't forget to call startNewPass() at each iteration.

Warning
You should avoid data of low magnitude (i.e., 1 should be a significant value) to get good results; thus rescaling might be necessary.

Basic Outputs

Figure 2. (a) Fitting a 2D point cloud of positions and normals at a point p (in red) requires to define a weight function of size t (in green). (b) This results in an implicit scalar field (in fake colors), from which parameters of a local spherical surface can be extracted: an offset tau, a normal eta and a curvature kappa.

Now that you have performed fitting, you may use its outputs in a number of ways (see Figure 2(b) for an illustration in 2D).

You may directly access generic properties of the fitted Primitive:

cout << "Value of the scalar field at the initial point: " << p.transpose()
<< " is equal to " << fit.potential(p) << endl;
cout << "Its gradient is equal to: " << fit.primitiveGradient(p).transpose() << endl;

This generates the following output:

Value of the scalar field at the initial point: 0 0 0 is equal to -0.501162
Its gradient is equal to: 0.00016028 0.000178782 -0.000384989

You may rather access properties of the fitted sphere (the 0-isosurface of the fitted scalar field), as defined in AlgebraicSphere :

cout << "Center: [" << fit.center().transpose() << "] ; radius: " << fit.radius() << endl;
cout << "The initial point " << p.transpose() << endl
<< "Is projected at " << fit.project(p).transpose() << endl;

You will obtain:

Center: [-0.000160652 -0.000179197 0.000385884] ; radius: 1.00232
The initial point 0 0 0
Is projected at 0.353911 0.394765 -0.850088

Advanced usage

Computing derivatives

Starting from v1.0, Ponca provides BasketDiff, a class to extend an existing Basket with differentiation tools. Given a specialized type TestPlane that performs covariance plane fitting (using Ponca::CovariancePlaneFit), and defined as follows:

using TestPlane = Basket<Point, WeightFunc, CovariancePlaneFit>;

BasketDiff allows to extend this type to compute its derivatives in space and/or scale:

using PlaneScaleDiff = BasketDiff<TestPlane, FitScaleDer, CovariancePlaneDer>;
using PlaneSpaceDiff = BasketDiff<TestPlane, FitSpaceDer, CovariancePlaneDer>;
using PlaneScaleSpaceDiff = BasketDiff<TestPlane, FitScaleSpaceDer, CovariancePlaneDer>;

Computational objets, basket and CRTP

In addition to Primitive fitting, Ponca allows to compute geometrical properties of the input samples. This is done by aggregating multiple tool classes in the Basket, for instance to compute the Growing Least Squares descriptor [10] (see GLSParam) from multiple sphere fitting techniques:

typedef Basket<Point, WeightSmoothFunc, OrientedSphereFit, GLSParam> FitSmoothOriented;
typedef Basket<Point, WeightConstantFunc, OrientedSphereFit, GLSParam> FitConstantOriented;
typedef Basket<Point, WeightSmoothFunc, UnorientedSphereFit, GLSParam> FitSmoothUnoriented;
typedef Basket<Point, WeightConstantFunc, UnorientedSphereFit, GLSParam> FitConstantUnoriented;

From a technical point of view, the Basket class combines its template parameters (here Ponca::OrientedSphereFit and GLSParam) following the CRTP rules, ie. to form an object of the type GLSParam<Ponca::OrientedSphereFit<DataPoint, _WFunctor,T>>, that aggregates the computations provided in each class of the hierarchy.

In practice, Ponca uses these mechanisms under the hood in order to combine atomic computations and minimize code duplication. For instance, Ponca::OrientedSphereFit is defined as an assembly of several computations classes:

51template < class DataPoint, class _WFunctor, typename T>
53OrientedSphereFitImpl<DataPoint, _WFunctor,
54 MeanPosition<DataPoint, _WFunctor,
55 MeanNormal<DataPoint, _WFunctor,
56 AlgebraicSphere<DataPoint, _WFunctor,T>>>>;
OrientedSphereFitImpl< DataPoint, _WFunctor, MeanPosition< DataPoint, _WFunctor, MeanNormal< DataPoint, _WFunctor, AlgebraicSphere< DataPoint, _WFunctor, T > > > > OrientedSphereFit
Helper alias for Oriented Sphere fitting on 3D points using OrientedSphereFitImpl [OrientedSphereFit ...

Here, the class MeanPosition computes the mean position of the input points. It is also used in Ponca::CovariancePlaneFit:

86 template < class DataPoint, class _WFunctor, typename T>
87 using CovariancePlaneFit =
88 CovariancePlaneFitImpl<DataPoint, _WFunctor,
89 CovarianceFitBase<DataPoint, _WFunctor,
90 MeanPosition<DataPoint, _WFunctor,
91 Plane<DataPoint, _WFunctor,T>>>>;
CovariancePlaneFitImpl< DataPoint, _WFunctor, CovarianceFitBase< DataPoint, _WFunctor, MeanPosition< DataPoint, _WFunctor, Plane< DataPoint, _WFunctor, T > > > > CovariancePlaneFit
Helper alias for Plane fitting on 3D points using CovariancePlaneFitImpl [CovariancePlaneFit Definiti...

and Ponca::MeanPlaneFit, among others.

55 template < class DataPoint, class _WFunctor, typename T>
56 using MeanPlaneFit =
57 MeanPlaneFitImpl<DataPoint, _WFunctor,
58 MeanNormal<DataPoint, _WFunctor,
59 MeanPosition<DataPoint, _WFunctor,
60 Plane<DataPoint, _WFunctor,T>>>>;
MeanPlaneFitImpl< DataPoint, _WFunctor, MeanNormal< DataPoint, _WFunctor, MeanPosition< DataPoint, _WFunctor, Plane< DataPoint, _WFunctor, T > > > > MeanPlaneFit
Helper alias for Plane fitting on points using MeanPlaneFitImpl [MeanPlaneFit Definition].
Definition: meanPlaneFit.h:60

Computational objets capabilities and requirements

Aggregating small computational objects allows to minimize code duplication, but also to easily combine different techniques. For instance, GLSDer can be used independently of the fitting technique, e.g. Ponca::OrientedSphereFit or Ponca::UnorientedSphereFit, as long as the fitted Primitive is an AlgebraicSphere.

In order to detect if the computational objects are correctly combined, Ponca provides a compile-time equirement/capability system: each computational objects check if the other classes of the CRTP provides the required computations. For instance, in the GLSParam class, we define the following enum:

46protected:
47 enum
48 {
49 Check = Base::PROVIDES_ALGEBRAIC_SPHERE,
50 PROVIDES_GLS_PARAMETRIZATION
51 };

Base is a type defined from the CRTP and that represents the inherited classes. If Base does not define PROVIDES_ALGEBRAIC_SPHERE, this line generates an error when compiling the program. For instance, compiling the type

typedef Basket<Point, WeightSmoothFunc, GLSParam> FitSmoothOriented;

generates the following error:

Building CXX object /xxxxx/wrongType.cpp.o
In file included from /xxxxx/wrongType.cpp:19:
/xxxxx/ponca/Ponca/src/Fitting/gls.h:51:23: error: no member named 'PROVIDES_ALGEBRAIC_SPHERE' in 'Ponca::PrimitiveBase<PointPositionNormal<float, 3>, Ponca::DistWeightFunc<PointPositionNormal<float, 3>, Ponca::SmoothWeightKernel<float> >, void>'
Check = Base::PROVIDES_ALGEBRAIC_SPHERE,
~~~~~~^
This Source Code Form is subject to the terms of the Mozilla Public License, v.

The capability PROVIDES_GLS_PARAMETRIZATION tells that GLSParam provides the GLS parameterization [10], and other components can access the related information.

Note
There is currently no formal description of the API provided by each capability. This will be fixed in upcoming releases. These relations are currently implicitly defined (and used), but not documented. For instance, a tool with the capability PROVIDES_PRINCIPAL_CURVATURES provides the following methods: kmin(), kmax(), kminDirection(), kmaxDirection(), kMean(), GaussianCurvature(), see CurvatureEstimatorBase.

In order to ease tools combinations, each class declare a set of required and provided capabilities, as listed in the two following table:

Fit/Tool (used in Basket) Requires Provides
MeanPosition PROVIDES_MEAN_POSITION
MeanNormal PROVIDES_MEAN_NORMAL
PrimitiveBase PROVIDES_PRIMITIVE_BASE
DryFit PROVIDES_PRIMITIVE_BASE
Plane PROVIDES_PRIMITIVE_BASE PROVIDES_PLANE
Ponca::MeanPlaneFitImpl PROVIDES_MEAN_POSITION,PROVIDES_MEAN_NORMAL,PROVIDES_PLANE
CovarianceFitBase PROVIDES_MEAN_POSITION PROVIDES_POSITION_COVARIANCE
Ponca::CovarianceLineFitImpl PROVIDES_LINE,PROVIDES_POSITION_COVARIANCE
Ponca::CovariancePlaneFitImpl PROVIDES_PLANE,PROVIDES_POSITION_COVARIANCE PROVIDES_TANGENT_PLANE_BASIS
MongePatch PROVIDES_TANGENT_PLANE_BASIS,PROVIDES_PLANE
AlgebraicSphere PROVIDES_PRIMITIVE_BASE PROVIDES_ALGEBRAIC_SPHERE
Ponca::SphereFitImpl PROVIDES_ALGEBRAIC_SPHERE
Ponca::OrientedSphereFitImpl PROVIDES_ALGEBRAIC_SPHERE,PROVIDES_MEAN_NORMAL,PROVIDES_MEAN_POSITION
Ponca::UnorientedSphereFitImpl PROVIDES_ALGEBRAIC_SPHERE,PROVIDES_MEAN_POSITION
GLSParam PROVIDES_ALGEBRAIC_SPHERE PROVIDES_GLS_PARAMETRIZATION
Fit/Tool (used in BasketDiff) Requires Provides
PrimitiveDer PROVIDES_PRIMITIVE_BASE PROVIDES_PRIMITIVE_DERIVATIVE
CovarianceFitDer PROVIDES_PRIMITIVE_DERIVATIVE,PROVIDES_MEAN_POSITION_DERIVATIVE,PROVIDES_POSITION_COVARIANCE PROVIDES_POSITION_COVARIANCE_DERIVATIVE
Ponca::CovariancePlaneDerImpl PROVIDES_PLANE,PROVIDES_POSITION_COVARIANCE_DERIVATIVE PROVIDES_COVARIANCE_PLANE_DERIVATIVE,PROVIDES_NORMAL_DERIVATIVE
Ponca::OrientedSphereDerImpl PROVIDES_ALGEBRAIC_SPHERE,PROVIDES_MEAN_POSITION_DERIVATIVE,PROVIDES_PRIMITIVE_DERIVATIVE PROVIDES_ALGEBRAIC_SPHERE_DERIVATIVE,PROVIDES_NORMAL_DERIVATIVE
MlsSphereFitDer PROVIDES_PRIMITIVE_DERIVATIVE,PROVIDES_ALGEBRAIC_SPHERE_DERIVATIVE PROVIDES_NORMAL_DERIVATIVE
GLSDer PROVIDES_GLS_PARAMETRIZATION,PROVIDES_PRIMITIVE_DERIVATIVE,PROVIDES_ALGEBRAIC_SPHERE_DERIVATIVE PROVIDES_GLS_DERIVATIVE,PROVIDES_GLS_GEOM_VAR
CurvatureEstimatorBase PROVIDES_PRINCIPAL_CURVATURES
NormalDerivativesCurvatureEstimator PROVIDES_NORMAL_DERIVATIVE,PROVIDES_PRINCIPAL_CURVATURES
NormalCovarianceCurvatureEstimator PROVIDES_PRINCIPAL_CURVATURES
ProjectedNormalCovarianceCurvatureEstimator PROVIDES_PLANE
Note
In its current version, the requirement/capability system offer limited protection over the combination of tools providing the same capabilities. Indeed, it is possible to build ill-formed combinations where two computations attempt to save their results at the same place, e.g. when using two fitting technique for the same primitive:
typedef Basket<Point, WeightConstantFunc, Plane,
MeanNormal, MeanPosition, MeanPlaneFitImpl,
CovarianceFitBase, CovariancePlaneFitImpl> Hybrid1; //test conflict detection in one direction
This case is not detected at compile time, but rather dynamically when calling finalize(), which can now return CONFLICT_ERROR_FOUND. Internally, this is implemented by checking if the primitive is already valid (ie. it has been computed already) when finalizing the computation. This limitation is expected to be resolved in upcoming releases.

Sharing computations between fits

In most cases, only one primitive is included in the Basket, and it is recommended to use the helper classes provided by Ponca for fitting, e.g. Ponca::CovariancePlaneFitImpl, Ponca::OrientedSphereFitImpl. Starting from version 1.0.0, Ponca allows to combine multiple primitives. In order to share intermediate computation results, it is recommended to explicitly define the computational arrangement, e.g.:

// Create an hybrid structure fitting a plane and a sphere at the same time
using Hybrid = Basket<Point, WeightFunc,
AlgebraicSphere, Plane, // primitives
MeanNormal, MeanPosition, // shared computation
OrientedSphereFitImpl, // sphere fitting
CovarianceFitBase, CovariancePlaneFitImpl>; // plane fitting

Computing Curvatures

Ponca offers several ways to compute curvatures, some of which are reviewed and compared by Lejemble et al. in [8] and listed in the table below:

Estimator Name Estimated quantities Usage Speed Robustness
Distance to PCA plane [5] Mean curvature Basket<P,W,CovariancePlaneFit> // method potential() +++ -
Surface Variation [12] Mean curvature Basket<P,W,CovariancePlaneFit> // method surfaceVariation() +++ -
Growing Least Squares [10] Mean curvature Basket<P,W,OrientedSphereFit,GLSParam> // method kappa() ++ + +
Point Set Surfaces (PSS) [2] Curvature Tensor Basket<P,W,CovariancePlaneFit,CovariancePlaneSpaceDer,NormalDerivativesCurvatureEstimator> +++ +
Algebraic Point Set Surfaces (APSS) [6] Curvature Tensor Basket<P,W,OrientedSphereFit,OrientedSphereSpaceDer,NormalDerivativesCurvatureEstimator> ++ + +
Algebraic Shape Operator (ASO) [8] Curvature Tensor Basket<P,W,OrientedSphereFit,OrientedSphereSpaceDer,MlsSphereFitDer,NormalDerivativesCurvatureEstimator> + + + +
Figure 3. Example of mean curvature (GLSParam::kappa) computed at a fine (left) and a coarse (right) scale, and rendered with a simple color map (orange for concavities, blue for convexities).

Cuda

Ponca can be used directly on GPU, thanks to several mechanisms:

  • Eigen Cuda capabilities, see Eigen documentation for more details. You need to use a consistent Eigen::Index on both CPU and GPU if you plan to transfer memory between the computing units. That's why we recommend to set the following preprocessor variable when compiling your project:
    -DEIGEN_DEFAULT_DENSE_INDEX_TYPE=int
    You might also need to define the --expt-relaxed-constexpr preprocessor option for NVCC. Example of working cmake file (see Screen Space Curvature using Cuda/C++):
    enable_language(CUDA)
    add_executable(ponca_ssgls "ponca_ssgls.cu")
    target_compile_options(ponca_ssgls PRIVATE --expt-relaxed-constexpr)
  • Automatic CPU/GPU compilation qualifiers. We use the macro
    PONCA_MULTIARCH void function();
    to use the same code for C++ and CUDA. It has no effect when the code is compiled with GCC or Clang, but it will force the compilation for both host and device architectures when compiling with nvcc. A similar macro system is provided for mathematical functions, to switch between STL and CUDA versions.

Check the C++/Cuda and Python/Cuda (using PyCuda) examples for more details and how-to.


[Go to concept page]
[Go back to user manual]