From 72f11b108ca85bd85f41857a4f4adf7452980d04 Mon Sep 17 00:00:00 2001
From: Behzad Safaei <iwia103h@alex1.nhr.fau.de>
Date: Wed, 5 Feb 2025 15:44:16 +0100
Subject: [PATCH] Enable device support in PairsAccessor (initial working
 version)

---
 runtime/math/MathTrait.h       | 633 +++++++++++++++++++++++++++++++++
 runtime/math/Vector3.hpp       |  43 +++
 runtime/pairs.hpp              |   4 +
 runtime/pairs_common.hpp       |  10 +
 src/pairs/code_gen/accessor.py | 369 +++++++++++++++++++
 src/pairs/code_gen/cgen.py     | 156 ++------
 src/pairs/ir/types.py          |   8 +-
 7 files changed, 1097 insertions(+), 126 deletions(-)
 create mode 100644 runtime/math/MathTrait.h
 create mode 100644 runtime/math/Vector3.hpp
 create mode 100644 src/pairs/code_gen/accessor.py

diff --git a/runtime/math/MathTrait.h b/runtime/math/MathTrait.h
new file mode 100644
index 0000000..44362c9
--- /dev/null
+++ b/runtime/math/MathTrait.h
@@ -0,0 +1,633 @@
+#pragma once
+
+//*************************************************************************************************
+// Includes
+//*************************************************************************************************
+
+#include <cstddef>
+
+namespace pairs {
+
+
+//=================================================================================================
+//
+//  MATHEMATICAL TRAIT
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*!\class MathTrait
+ * \brief Base template for the MathTrait class.
+ * \ingroup math
+ *
+ * \section mathtrait_general General
+ *
+ * The MathTrait class template offers the possibility to select the resulting data type
+ * of a generic mathematical operation. In case of operations between built-in data types,
+ * the MathTrait class defines the more significant data type as the resulting data type.
+ * For this selection, signed data types are given a higher significance. In case of
+ * operations involving user-defined data types, the MathTrait template specifies the
+ * resulting data type of this operation.\n
+ * Specifying the resulting data type for a specific operation is done by specializing
+ * the MathTrait template for this particular type combination. In case a certain type
+ * combination is not defined in a MathTrait specialization, the base template is selected,
+ * which defines no resulting types and therefore stops the compilation process. Each
+ * specialization defines the data types \a HighType that represents the high-order data
+ * type of the two given data types and \a LowType that represents the low-order data type.
+ * Additionally, each specialization defines the types \a AddType, \a SubType, \a MultType
+ * and \a DivType, that represent the type of the resulting data type of the corresponding
+ * mathematical operation. The following example shows the specialization for operations
+ * between the double and the integer type:
+
+   \code
+   template<>
+   struct MathTrait< double, int >
+   {
+      typedef double  HighType;
+      typedef int     LowType;
+      typedef double  AddType;
+      typedef double  SubType;
+      typedef double  MultType;
+      typedef double  DivType;
+   };
+   \endcode
+
+ * Per default, the MathTrait template provides specializations for the following built-in
+ * data types:
+ *
+ * <ul>
+ *    <li>integers</li>
+ *    <ul>
+ *       <li>unsigned char, signed char, char, wchar_t</li>
+ *       <li>unsigned short, short</li>
+ *       <li>unsigned int, int</li>
+ *       <li>unsigned long, long</li>
+ *       <li>std::size_t, std::ptrdiff_t (for certain 64-bit compilers)</li>
+ *    </ul>
+ *    <li>floating points</li>
+ *    <ul>
+ *       <li>float</li>
+ *       <li>double</li>
+ *       <li>long double</li>
+ *    </ul>
+ * </ul>
+ *
+ *
+ * \n \section specializations Creating custom specializations
+ *
+ * It is possible to specialize the MathTrait template for additional user-defined data types.
+ * However, it is possible that a specific mathematical operation is invalid for the particular
+ * type combination. In this case, the INVALID_NUMERICAL_TYPE can be used to fill the missing
+ * type definition. The INVALID_NUMERICAL_TYPE represents the resulting data type of an invalid
+ * numerical operation. It is left undefined to stop the compilation process in case it is
+ * instantiated. The following example shows the specialization of the MathTrait template for
+ * Matrix3 and Vector3. In this case, only the multiplication between the matrix and the vector
+ * is a valid numerical operation. Therefore for all other types the INVALID_NUMERICAL_TYPE is
+ * used.
+
+   \code
+   template< typename T1, typename T2 >
+   struct MathTrait< Matrix3<T1>, Vector3<T2> >
+   {
+      typedef INVALID_NUMERICAL_TYPE                          HighType;  // Invalid, no common high data type
+      typedef INVALID_NUMERICAL_TYPE                          LowType;   // Invalid, no common low data type
+      typedef INVALID_NUMERICAL_TYPE                          AddType;   // Invalid, cannot add a matrix and a vector
+      typedef INVALID_NUMERICAL_TYPE                          SubType;   // Invalid, cannot subtract a vector from a matrix
+      typedef Vector3< typename MathTrait<T1,T2>::MultType >  MultType;  // Multiplication between a matrix and a vector
+      typedef INVALID_NUMERICAL_TYPE                          DivType;   // Invalid, cannot divide a matrix by a vector
+   };
+   \endcode
+
+ * \n \section mathtrait_examples Examples
+ *
+ * The following example demonstrates the use of the MathTrait template, where depending on
+ * the two given data types the resulting data type is selected:
+
+   \code
+   template< typename T1, typename T2 >    // The two generic types
+   typename MathTrait<T1,T2>::HighType     // The resulting generic return type
+   add( T1 t1, T2 t2 )                     //
+   {                                       // The function 'add' returns the sum
+      return t1 + t2;                      // of the two given values
+   }                                       //
+   \endcode
+
+ * Additionally, the specializations of the MathTrait template enable arithmetic operations
+ * between any combination of the supported data types:
+
+   \code
+   typedef Vector3< Matrix3< float  > >  VectorOfMatrices;  // Vector of single-precision matrices
+   typedef Vector3< Vector3  < double > >  VectorOfVectors;   // Vector of double-precision vectors
+   typedef Vector3< double >                   VectorOfScalars;   // Vector of double-precision scalars
+
+   VectorOfMatrices vm;  // Setup of a vector of matrices
+   VectorOfVectors  vv;  // Setup of a vector of vectors
+
+   // Calculation of the scalar product between the two vectors. The resulting data type
+   // is a plain 3-dimensional vector of scalar values of type double.
+   VectorOfScalars res = vm * vv;
+   \endcode
+ */
+//*************************************************************************************************
+
+//strange but needed for compatibility reasons with visual studio compiler
+//backward compatibility to old PAIRS code
+template< typename T1, typename T2 >
+struct MathTrait
+{
+   using HighType = T1;
+   using LowType = T2;
+   using High = T1;
+   using Low = T2;
+};
+
+template< typename T>
+struct MathTrait< T, T >
+{
+   using HighType = T;
+   using LowType = T;
+   using High = T;
+   using Low = T;
+};
+
+
+//=================================================================================================
+//
+//  MATHTRAIT SPECIALIZATION MACRO
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \cond internal */
+/*!\brief Macro for the creation of MathTrait specializations for the built-in data types.
+ * \ingroup math
+ *
+ * This macro is used for the setup of the MathTrait specializations for the built-in data
+ * types.
+ */
+#define PAIRS_CREATE_MATHTRAIT_SPECIALIZATION(T1,T2,HIGH,LOW) \
+   template<> \
+   struct MathTrait< T1, T2 > \
+   { \
+      typedef HIGH  HighType; \
+      typedef LOW   LowType;  \
+      typedef HIGH  High;     \
+      typedef LOW   Low;      \
+      typedef HIGH  AddType;  \
+      typedef HIGH  SubType;  \
+      typedef HIGH  MultType; \
+      typedef HIGH  DivType;  \
+   }
+/*! \endcond */
+//*************************************************************************************************
+
+
+
+
+//=================================================================================================
+//
+//  UNSIGNED CHAR SPECIALIZATIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \cond internal */
+//                                  Type 1          Type 2          High type       Low type
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , unsigned char , unsigned char , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , char          , char          , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , signed char   , signed char   , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , wchar_t       , wchar_t       , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , unsigned short, unsigned short, unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , short         , short         , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , unsigned int  , unsigned int  , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , int           , int           , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , unsigned long , unsigned long , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , long          , long          , unsigned char  );
+#if defined(_WIN64)
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , std::size_t   , std::size_t   , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , std::ptrdiff_t, std::ptrdiff_t, unsigned char  );
+#endif
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , float         , float         , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , double        , double        , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned char , long double   , long double   , unsigned char  );
+/*! \endcond */
+//*************************************************************************************************
+
+
+
+
+//=================================================================================================
+//
+//  CHAR SPECIALIZATIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \cond internal */
+//                                  Type 1          Type 2          High type       Low type
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , unsigned char , char          , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , char          , char          , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , signed char   , signed char   , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , wchar_t       , wchar_t       , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , unsigned short, unsigned short, char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , short         , short         , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , unsigned int  , unsigned int  , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , int           , int           , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , unsigned long , unsigned long , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , long          , long          , char           );
+#if defined(_WIN64)
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , std::size_t   , std::size_t   , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , std::ptrdiff_t, std::ptrdiff_t, char           );
+#endif
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , float         , float         , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , double        , double        , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( char          , long double   , long double   , char           );
+/*! \endcond */
+//*************************************************************************************************
+
+
+
+
+//=================================================================================================
+//
+//  SIGNED CHAR SPECIALIZATIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \cond internal */
+//                                  Type 1          Type 2          High type       Low type
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , unsigned char , signed char   , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , char          , signed char   , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , signed char   , signed char   , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , wchar_t       , wchar_t       , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , unsigned short, unsigned short, signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , short         , short         , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , unsigned int  , unsigned int  , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , int           , int           , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , unsigned long , unsigned long , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , long          , long          , signed char    );
+#if defined(_WIN64)
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , std::size_t   , std::size_t   , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , std::ptrdiff_t, std::ptrdiff_t, signed char    );
+#endif
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , float         , float         , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , double        , double        , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( signed char   , long double   , long double   , signed char    );
+/*! \endcond */
+//*************************************************************************************************
+
+
+
+
+//=================================================================================================
+//
+//  WCHAR_T SPECIALIZATIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \cond internal */
+//                                  Type 1          Type 2          High type       Low type
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , unsigned char , wchar_t       , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , char          , wchar_t       , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , signed char   , wchar_t       , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , wchar_t       , wchar_t       , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , unsigned short, unsigned short, wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , short         , short         , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , unsigned int  , unsigned int  , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , int           , int           , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , unsigned long , unsigned long , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , long          , long          , wchar_t        );
+#if defined(_WIN64)
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , std::size_t   , std::size_t   , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , std::ptrdiff_t, std::ptrdiff_t, wchar_t        );
+#endif
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , float         , float         , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , double        , double        , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( wchar_t       , long double   , long double   , wchar_t        );
+/*! \endcond */
+//*************************************************************************************************
+
+
+
+
+//=================================================================================================
+//
+//  UNSIGNED SHORT SPECIALIZATIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \cond internal */
+//                                  Type 1          Type 2          High type       Low type
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, unsigned char , unsigned short, unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, char          , unsigned short, char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, signed char   , unsigned short, signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, wchar_t       , unsigned short, wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, unsigned short, unsigned short, unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, short         , short         , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, unsigned int  , unsigned int  , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, int           , int           , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, unsigned long , unsigned long , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, long          , long          , unsigned short );
+#if defined(_WIN64)
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, std::size_t   , std::size_t   , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, std::ptrdiff_t, std::ptrdiff_t, unsigned short );
+#endif
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, float         , float         , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, double        , double        , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned short, long double   , long double   , unsigned short );
+/*! \endcond */
+//*************************************************************************************************
+
+
+
+
+//=================================================================================================
+//
+//  SHORT SPECIALIZATIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \cond internal */
+//                                  Type 1          Type 2          High type       Low type
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , unsigned char , short         , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , char          , short         , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , signed char   , short         , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , wchar_t       , short         , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , unsigned short, short         , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , short         , short         , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , unsigned int  , unsigned int  , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , int           , int           , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , unsigned long , unsigned long , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , long          , long          , short          );
+#if defined(_WIN64)
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , std::size_t   , std::size_t   , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , std::ptrdiff_t, std::ptrdiff_t, short          );
+#endif
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , float         , float         , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , double        , double        , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( short         , long double   , long double   , short          );
+/*! \endcond */
+//*************************************************************************************************
+
+
+
+
+//=================================================================================================
+//
+//  UNSIGNED INT SPECIALIZATIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \cond internal */
+//                                  Type 1          Type 2          High type       Low type
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , unsigned char , unsigned int  , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , char          , unsigned int  , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , signed char   , unsigned int  , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , wchar_t       , unsigned int  , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , unsigned short, unsigned int  , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , short         , unsigned int  , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , unsigned int  , unsigned int  , unsigned int   );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , int           , int           , unsigned int   );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , unsigned long , unsigned long , unsigned int   );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , long          , long          , unsigned int   );
+#if defined(_WIN64)
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , std::size_t   , std::size_t   , unsigned int   );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , std::ptrdiff_t, std::ptrdiff_t, unsigned int   );
+#endif
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , float         , float         , unsigned int   );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , double        , double        , unsigned int   );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned int  , long double   , long double   , unsigned int   );
+/*! \endcond */
+//*************************************************************************************************
+
+
+
+
+//=================================================================================================
+//
+//  INT SPECIALIZATIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \cond internal */
+//                                  Type 1          Type 2          High type       Low type
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , unsigned char , int           , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , char          , int           , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , signed char   , int           , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , wchar_t       , int           , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , unsigned short, int           , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , short         , int           , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , unsigned int  , int           , unsigned int   );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , int           , int           , int            );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , unsigned long , unsigned long , int            );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , long          , long          , int            );
+#if defined(_WIN64)
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , std::size_t   , std::size_t   , int            );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , std::ptrdiff_t, std::ptrdiff_t, int            );
+#endif
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , float         , float         , int            );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , double        , double        , int            );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( int           , long double   , long double   , int            );
+/*! \endcond */
+//*************************************************************************************************
+
+
+
+
+//=================================================================================================
+//
+//  UNSIGNED LONG SPECIALIZATIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \cond internal */
+//                                  Type 1          Type 2          High type       Low type
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , unsigned char , unsigned long , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , char          , unsigned long , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , signed char   , unsigned long , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , wchar_t       , unsigned long , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , unsigned short, unsigned long , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , short         , unsigned long , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , unsigned int  , unsigned long , unsigned int   );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , int           , unsigned long , int            );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , unsigned long , unsigned long , unsigned long  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , long          , long          , unsigned long  );
+#if defined(_WIN64)
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , std::size_t   , std::size_t   , unsigned long  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , std::ptrdiff_t, std::ptrdiff_t, unsigned long  );
+#endif
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , float         , float         , unsigned long  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , double        , double        , unsigned long  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( unsigned long , long double   , long double   , unsigned long  );
+/*! \endcond */
+//*************************************************************************************************
+
+
+
+
+//=================================================================================================
+//
+//  LONG SPECIALIZATIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \cond internal */
+//                                  Type 1          Type 2          High type       Low type
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , unsigned char , long          , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , char          , long          , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , signed char   , long          , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , wchar_t       , long          , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , unsigned short, long          , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , short         , long          , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , unsigned int  , long          , unsigned int   );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , int           , long          , int            );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , unsigned long , long          , unsigned long  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , long          , long          , long           );
+#if defined(_WIN64)
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , std::size_t   , std::size_t   , long           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , std::ptrdiff_t, std::ptrdiff_t, long           );
+#endif
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , float         , float         , long           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , double        , double        , long           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long          , long double   , long double   , long           );
+/*! \endcond */
+//*************************************************************************************************
+
+
+
+
+//=================================================================================================
+//
+//  SIZE_T SPECIALIZATIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+#if defined(_WIN64)
+/*! \cond internal */
+//                                  Type 1          Type 2          High type       Low type
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( std::size_t   , unsigned char , std::size_t   , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( std::size_t   , char          , std::size_t   , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( std::size_t   , signed char   , std::size_t   , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( std::size_t   , wchar_t       , std::size_t   , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( std::size_t   , unsigned short, std::size_t   , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( std::size_t   , short         , std::size_t   , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( std::size_t   , unsigned int  , std::size_t   , unsigned int   );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( std::size_t   , int           , std::size_t   , int            );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( std::size_t   , unsigned long , std::size_t   , unsigned long  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( std::size_t   , long          , std::size_t   , long           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( std::size_t   , std::size_t   , std::size_t   , std::size_t    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( std::size_t   , float         , float         , std::size_t    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( std::size_t   , double        , double        , std::size_t    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( std::size_t   , long double   , long double   , std::size_t    );
+/*! \endcond */
+#endif
+//*************************************************************************************************
+
+
+
+
+//=================================================================================================
+//
+//  FLOAT SPECIALIZATIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \cond internal */
+//                                  Type 1          Type 2          High type       Low type
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , unsigned char , float         , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , char          , float         , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , signed char   , float         , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , wchar_t       , float         , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , unsigned short, float         , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , short         , float         , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , unsigned int  , float         , unsigned int   );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , int           , float         , int            );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , unsigned long , float         , unsigned long  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , long          , float         , long           );
+#if defined(_WIN64)
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , std::size_t   , float         , std::size_t    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , std::ptrdiff_t, float         , std::ptrdiff_t );
+#endif
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , float         , float         , float          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , double        , double        , float          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( float         , long double   , long double   , float          );
+/*! \endcond */
+//*************************************************************************************************
+
+
+
+
+//=================================================================================================
+//
+//  DOUBLE SPECIALIZATIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \cond internal */
+//                                  Type 1          Type 2          High type       Low type
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , unsigned char , double        , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , char          , double        , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , signed char   , double        , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , wchar_t       , double        , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , unsigned short, double        , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , short         , double        , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , unsigned int  , double        , unsigned int   );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , int           , double        , int            );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , unsigned long , double        , unsigned long  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , long          , double        , long           );
+#if defined(_WIN64)
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , std::size_t   , double        , std::size_t    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , std::ptrdiff_t, double        , std::ptrdiff_t );
+#endif
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , float         , double        , float          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , double        , double        , double         );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( double        , long double   , long double   , double         );
+/*! \endcond */
+//*************************************************************************************************
+
+
+
+
+//=================================================================================================
+//
+//  LONG DOUBLE SPECIALIZATIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \cond internal */
+//                                  Type 1          Type 2          High type       Low type
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , unsigned char , long double   , unsigned char  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , char          , long double   , char           );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , signed char   , long double   , signed char    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , wchar_t       , long double   , wchar_t        );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , unsigned short, long double   , unsigned short );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , short         , long double   , short          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , unsigned int  , long double   , unsigned int   );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , int           , long double   , int            );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , unsigned long , long double   , unsigned long  );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , long          , long double   , long           );
+#if defined(_WIN64)
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , std::size_t   , long double   , std::size_t    );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , std::ptrdiff_t, long double   , std::ptrdiff_t );
+#endif
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , float         , long double   , float          );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , double        , long double   , double         );
+PAIRS_CREATE_MATHTRAIT_SPECIALIZATION( long double   , long double   , long double   , long double    );
+/*! \endcond */
+//*************************************************************************************************
+
+#undef PAIRS_CREATE_MATHTRAIT_SPECIALIZATION
+
+}
diff --git a/runtime/math/Vector3.hpp b/runtime/math/Vector3.hpp
new file mode 100644
index 0000000..2e5b4f0
--- /dev/null
+++ b/runtime/math/Vector3.hpp
@@ -0,0 +1,43 @@
+#pragma once
+#include <iostream>
+
+#include "../pairs_common.hpp"
+#include "MathTrait.h"
+
+
+namespace pairs {
+
+#define HIGH typename MathTrait<Type,Other>::High
+
+template< typename Type >
+class Vector3 {
+public:
+   Vector3() = default;
+
+   // If the constructor is called from device, v_ is automatically allocated on 
+   // device because it's a static array embeded in the object itself 
+   PAIRS_ATTR_HOST_DEVICE Vector3( Type x, Type y, Type z ) {
+      v_[0] = x;
+      v_[1] = y;
+      v_[2] = z;
+   }
+
+   template< typename Other >
+   PAIRS_ATTR_HOST_DEVICE inline Vector3<HIGH> operator+( const Vector3<Other>& rhs ) const{
+      return Vector3<HIGH>( v_[0]+static_cast<Type>(rhs.v_[0]), v_[1]+static_cast<Type>(rhs.v_[1]), v_[2]+static_cast<Type>(rhs.v_[2]) );
+   }
+
+   PAIRS_ATTR_HOST_DEVICE Type& operator[]( int index ) { 
+      return v_[index]; 
+   }
+
+   PAIRS_ATTR_HOST_DEVICE const Type& operator[] ( int index ) const { 
+      return v_[index]; 
+   }
+
+private:
+   Type v_[3] = {Type(), Type(), Type()};
+};
+#undef HIGH
+
+}
diff --git a/runtime/pairs.hpp b/runtime/pairs.hpp
index 27892e4..cf1e65e 100644
--- a/runtime/pairs.hpp
+++ b/runtime/pairs.hpp
@@ -239,6 +239,10 @@ public:
 
     void copyPropertyToHost(Property &prop, action_t action, size_t size);
 
+    DeviceFlags* getPropFlags(){
+        return prop_flags;
+    }
+
     // Contact properties
     ContactProperty &getContactProperty(property_t id);
     ContactProperty &getContactPropertyByName(std::string name);
diff --git a/runtime/pairs_common.hpp b/runtime/pairs_common.hpp
index 23a03ba..73c9f7b 100644
--- a/runtime/pairs_common.hpp
+++ b/runtime/pairs_common.hpp
@@ -5,6 +5,16 @@
 
 namespace pairs {
 
+#ifdef PAIRS_TARGET_CUDA
+    #define PAIRS_ATTR_HOST __host__ 
+    #define PAIRS_ATTR_DEVICE __device__ 
+    #define PAIRS_ATTR_HOST_DEVICE __host__ __device__
+#else
+    #define PAIRS_ATTR_HOST
+    #define PAIRS_ATTR_DEVICE
+    #define PAIRS_ATTR_HOST_DEVICE
+#endif
+
 constexpr int FLAGS_INFINITE = 1 << 0 ;
 constexpr int FLAGS_GHOST    = 1 << 1 ;
 constexpr int FLAGS_FIXED    = 1 << 2 ;
diff --git a/src/pairs/code_gen/accessor.py b/src/pairs/code_gen/accessor.py
new file mode 100644
index 0000000..9996a6f
--- /dev/null
+++ b/src/pairs/code_gen/accessor.py
@@ -0,0 +1,369 @@
+from pairs.ir.types import Types
+
+class PairsAcessor:
+    def __init__(self, cgen):
+        self.sim = cgen.sim
+        self.target = cgen.target
+        self.print = cgen.print
+        self.debug = cgen.debug
+        self.host_device_attr = ""
+        self.host_attr = ""
+        
+    def generate(self):
+        self.print("")
+
+        if self.target.is_gpu():
+            self.host_device_attr = "__host__ __device__ "
+            self.host_attr = "__host__ "
+        self.print("#include \"runtime/math/Vector3.hpp\"")
+        # self.print("#include \"runtime/math/Quaternion.hpp\"")
+        # self.print("#include \"runtime/math/Matrix3.hpp\"")
+        self.print("")
+
+        self.print("class PairsAccessor {")
+        self.print("private:")
+        self.print.add_indent(4)
+        self.member_variables()
+        self.print.add_indent(-4)
+        self.print("public:")
+        self.print.add_indent(4)
+
+        if self.target.is_gpu():
+            self.update()
+
+        self.constructor()
+
+        for p in self.sim.properties:
+            if (p.type()==Types.Vector) or (Types.is_scalar(p.type())):
+                self.get_property(p)    
+                self.set_property(p)
+                if self.target.is_gpu():
+                        self.sync_property(p)
+
+        self.utility_funcs()
+            
+        self.print.add_indent(-4)
+        self.print("};")
+        self.print("")
+
+    def member_variables(self):
+        self.print("PairsSimulation *ps;")
+
+        if self.target.is_gpu():
+            self.print("int *nlocal_d;")
+            self.print("int *nghost_d;")
+            self.print("")
+
+            self.print("//Properties")
+            for p in self.sim.properties:
+                pname = p.name()
+                tkw = Types.c_keyword(self.sim, p.type())
+                self.print(f"{tkw} *{pname}_d;")
+
+            self.print("")
+            self.print("//Property flags")
+            for p in self.sim.properties:
+                pname = p.name()
+                tkw = Types.c_keyword(self.sim, Types.Boolean)
+                self.print(f"{tkw} *{pname}_device_flag_d;")
+                self.print(f"{tkw} {pname}_device_flag_h = false;")
+                self.print(f"{tkw} {pname}_host_flag = false;")
+
+        self.print("")
+
+    def update(self):
+        self.print(f"{self.host_attr}void update(){{")
+        self.print.add_indent(4)
+        self.print(f"cudaMemcpy(nlocal_d, &(ps->pobj->nlocal), sizeof(int), cudaMemcpyHostToDevice);")
+        self.print(f"cudaMemcpy(nghost_d, &(ps->pobj->nghost), sizeof(int), cudaMemcpyHostToDevice);")
+
+        for p in self.sim.properties:
+            pname = p.name()
+            self.print(f"{pname}_d = ps->pobj->{pname}_d;")
+
+        self.print.add_indent(-4)
+        self.print("}")
+        self.print("")
+
+
+    def constructor(self):
+        if self.target.is_gpu():
+            self.print(f"{self.host_attr}PairsAccessor(PairsSimulation *ps_): ps(ps_){{")
+            self.print.add_indent(4)
+
+            self.print(f"cudaMalloc(&nlocal_d, sizeof(int));")
+            self.print(f"cudaMalloc(&nghost_d, sizeof(int));")
+            self.print("this->update();")
+
+            for p in self.sim.properties:
+                pname = p.name()
+                tkw = Types.c_keyword(self.sim, Types.Boolean)
+                self.print(f"cudaMalloc(&{pname}_device_flag_d, sizeof({tkw}));")
+                self.print(f"cudaMemcpy({pname}_device_flag_d, &{pname}_device_flag_h, sizeof({tkw}), cudaMemcpyHostToDevice);")
+        
+            self.print.add_indent(-4)
+            self.print("}")
+        else:
+            self.print("PairsAccessor(PairsSimulation *ps_): ps(ps_){}")
+
+        self.print("")
+    
+    def ifdef_else(self, ifdef, func1, args1, func2, args2):
+        self.print.add_indent(4)
+        self.print(f"#ifdef {ifdef}")
+        func1(*args1)
+        self.print("#else")
+        func2(*args2)
+        self.print("#endif")
+        self.print.add_indent(-4)
+
+    def getter_body(self, prop, device=False):
+        self.print.add_indent(4)
+        pname = prop.name()
+        tkw = Types.c_accessor_keyword(self.sim, prop.type())
+        
+        if self.target.is_gpu() and device:
+            v = f"{pname}_d"
+        else:
+            v = f"ps->pobj->{pname}"
+
+        if Types.is_scalar(prop.type()):
+            self.print(f"return {v}[i];")
+        else:
+            nelems = Types.number_of_elements(self.sim, prop.type())
+            return_values = [f"{v}[i*{nelems} + {n}]" for n in range(nelems)] 
+            self.print(f"return {tkw}(" + ", ".join(rv for rv in return_values) + ");")
+        self.print.add_indent(-4)
+
+
+    def get_property(self, prop):
+        pname = prop.name()
+        tkw = Types.c_accessor_keyword(self.sim, prop.type())
+        splitname = pname.split('_')
+        funcname = ''.join(word.capitalize() for word in splitname)
+
+        self.print(f"{self.host_device_attr}{tkw} get{funcname}(const size_t i) const{{")
+
+        if self.target.is_gpu():
+            self.ifdef_else("__CUDA_ARCH__", self.getter_body, [prop, True], self.getter_body, [prop, False])
+        else:
+            self.getter_body(prop, False)
+
+        self.print("}")
+        self.print("")
+
+
+    def setter_body(self, prop, device=False):
+        self.print.add_indent(4)
+        pname = prop.name()
+        tkw = Types.c_accessor_keyword(self.sim, prop.type())
+
+        if self.target.is_gpu() and device:
+            v = f"{pname}_d"
+        else:
+            v = f"ps->pobj->{pname}"
+
+        if Types.is_scalar(prop.type()):
+            self.print(f"{v}[i] = value;")
+        else:
+            nelems = Types.number_of_elements(self.sim, prop.type())
+            set_values = [f"{v}[i*{nelems} + {n}] = value[{n}];" for n in range(nelems)] 
+            for sv in set_values:
+                self.print(sv)
+
+        if self.target.is_gpu():
+            flag = f"*{pname}_device_flag_d" if device else f"{pname}_host_flag"
+            self.print(f"{flag} = true;")
+
+        self.print.add_indent(-4)
+
+
+    def set_property(self, prop):
+        pname = prop.name()
+        tkw = Types.c_accessor_keyword(self.sim, prop.type())
+        splitname = pname.split('_')
+        funcname = ''.join(word.capitalize() for word in splitname)
+
+        self.print(f"{self.host_device_attr}void set{funcname}(const size_t i, const {tkw} &value){{")
+
+        if self.target.is_gpu():
+            self.ifdef_else("__CUDA_ARCH__", self.setter_body, [prop, True], self.setter_body, [prop, False])
+        else:
+            self.setter_body(prop, False)
+
+        self.print("}")
+        self.print("")
+
+    def sync_property(self, prop):
+        pname = prop.name()
+        pid = prop.id()
+        splitname = pname.split('_')
+        funcname = ''.join(word.capitalize() for word in splitname)
+
+        self.print(f"{self.host_attr}void sync{funcname}(){{")
+        self.print.add_indent(4)
+        self.print(f"{pname}_d = ps->pobj->{pname}_d;")
+        self.print(f"cudaMemcpy(&{pname}_device_flag_h, {pname}_device_flag_d, sizeof(bool), cudaMemcpyDeviceToHost);")
+        self.print("")
+        
+
+        #####################################################################################################################
+        #####################################################################################################################
+        # self.print(f"if (({pname}_host_flag && {pname}_device_flag_h) || ")
+        # self.print.add_indent(4)
+        # self.print(f"({pname}_host_flag && !ps->pairs_runtime->getPropFlags()->isHostFlagSet({pid})) ||")
+        # self.print(f"({pname}_device_flag_h && !ps->pairs_runtime->getPropFlags()->isDeviceFlagSet({pid}))){{")
+        # self.print(f"PAIRS_ERROR(\"OUT OF SYNC! Both host and device versions of {pname} are in a modified state.\\n\");")
+        # self.print("exit(-1);")
+        # self.print.add_indent(-4)
+        # self.print("}")
+        # self.print("")
+
+
+        self.print(f"if ({pname}_host_flag && {pname}_device_flag_h){{")
+        self.print.add_indent(4)
+        self.print(f"PAIRS_ERROR(\"OUT OF SYNC 1! Both host and device versions of {pname} are in a modified state.\\n\");")
+        self.print("exit(-1);")
+        self.print.add_indent(-4)
+        self.print("}")
+        self.print("")
+
+        self.print(f"if ({pname}_host_flag && !ps->pairs_runtime->getPropFlags()->isHostFlagSet({pid})){{")
+        self.print.add_indent(4)
+        self.print(f"PAIRS_ERROR(\"OUT OF SYNC 2! Both host and device versions of {pname} are in a modified state.\\n\");")
+        self.print("exit(-1);")
+        self.print.add_indent(-4)
+        self.print("}")
+        self.print("")
+
+        self.print(f"if ({pname}_device_flag_h && !ps->pairs_runtime->getPropFlags()->isDeviceFlagSet({pid})){{")
+        self.print.add_indent(4)
+        self.print(f"PAIRS_ERROR(\"OUT OF SYNC 3! Both host and device versions of {pname} are in a modified state.\\n\");")
+        self.print("exit(-1);")
+        self.print.add_indent(-4)
+        self.print("}")
+        self.print("")
+
+        #####################################################################################################################
+        #####################################################################################################################
+
+
+        self.print(f"if ({pname}_host_flag){{")
+        self.print.add_indent(4)
+        self.print(f"ps->pairs_runtime->getPropFlags()->setHostFlag({pid});")
+        self.print(f"ps->pairs_runtime->getPropFlags()->clearDeviceFlag({pid});")
+        self.print.add_indent(-4)
+        self.print("}")
+        
+        self.print(f"else if ({pname}_device_flag_h){{")
+        self.print.add_indent(4)
+        self.print(f"ps->pairs_runtime->getPropFlags()->setDeviceFlag({pid});")
+        self.print(f"ps->pairs_runtime->getPropFlags()->clearHostFlag({pid});")
+        self.print.add_indent(-4)
+        self.print("}")
+        self.print("")
+
+        nelems = Types.number_of_elements(self.sim, prop.type())
+        tkw = Types.c_keyword(self.sim, prop.type())
+
+        self.print(f"if (ps->pairs_runtime->getPropFlags()->isHostFlagSet({pid})) {{")
+        self.print.add_indent(4)
+
+        self.print(f"ps->pairs_runtime->copyPropertyToDevice({pid}, ReadOnly, (((ps->pobj->nlocal + ps->pobj->nghost) * {nelems}) * sizeof({tkw})));")
+        self.print.add_indent(-4)
+        self.print("}")
+
+        self.print(f"else if (ps->pairs_runtime->getPropFlags()->isDeviceFlagSet({pid})) {{")
+        self.print.add_indent(4)
+        self.print(f"ps->pairs_runtime->copyPropertyToHost({pid}, ReadOnly, (((ps->pobj->nlocal + ps->pobj->nghost) * {nelems}) * sizeof({tkw})));")
+        self.print.add_indent(-4)
+        self.print("}")
+        self.print("")
+
+        self.print(f"{pname}_host_flag = false;")
+        self.print(f"{pname}_device_flag_h = false;")
+        self.print(f"cudaMemcpy({pname}_device_flag_d, &{pname}_device_flag_h, sizeof(bool), cudaMemcpyHostToDevice);")
+
+        self.print.add_indent(-4)
+        self.print("}")
+        self.print("")
+
+    def utility_funcs(self):
+        if self.target.is_gpu():
+            self.print(f"{self.host_device_attr}int size() const {{")
+            self.print("    #ifdef __CUDA_ARCH__")
+            self.print("        return *nlocal_d + *nghost_d;")
+            self.print("    #else")
+            self.print("        return ps->pobj->nlocal + ps->pobj->nghost;")
+            self.print("    #endif")
+            self.print("}")
+            self.print("")
+        else:
+            self.print("int size() const {return ps->pobj->nlocal + ps->pobj->nghost;}")
+
+        if self.target.is_gpu():
+            self.print(f"{self.host_device_attr}int nlocal() const {{")
+            self.print("    #ifdef __CUDA_ARCH__")
+            self.print("        return *nlocal_d;")
+            self.print("    #else")
+            self.print("        return ps->pobj->nlocal;")
+            self.print("    #endif")
+            self.print("}")
+            self.print("")
+        else:
+            self.print("int nlocal() const {return ps->pobj->nlocal;}")
+
+        if self.target.is_gpu():
+            self.print(f"{self.host_device_attr}int nghost() const {{")
+            self.print("    #ifdef __CUDA_ARCH__")
+            self.print("        return *nghost_d;")
+            self.print("    #else")
+            self.print("        return ps->pobj->nghost;")
+            self.print("    #endif")
+            self.print("}")
+            self.print("")
+        else:
+            self.print("int nghost() const {return ps->pobj->nghost;}")
+
+
+        self.print(f"{self.host_device_attr}int getInvalidIdx(){{return -1;}}")
+        self.print("")
+
+        self.print(f"{self.host_device_attr}pairs::id_t getInvalidUid(){{return 0;}}")
+        self.print("")
+
+        self.print(f"{self.host_device_attr}int uidToIdx(pairs::id_t uid){{")
+        self.print("    int idx = getInvalidIdx();")
+        self.print("    for(int i=0; i<size(); ++i){")
+        self.print("        if (getUid(i) == uid){")
+        self.print("            idx = i;")
+        self.print("            break;")
+        self.print("        }")
+        self.print("    }")
+        self.print("    return idx;")
+        self.print("}")
+        self.print("")
+
+        self.print(f"{self.host_device_attr}int uidToIdxLocal(pairs::id_t uid){{")
+        self.print("    int idx = getInvalidIdx();")
+        self.print("    for(int i=0; i<nlocal(); ++i){")
+        self.print("        if (getUid(i) == uid){")
+        self.print("            idx = i;")
+        self.print("            break;")
+        self.print("        }")
+        self.print("    }")
+        self.print("    return idx;")
+        self.print("}")
+        self.print("")
+
+        self.print(f"{self.host_device_attr}int uidToIdxGhost(pairs::id_t uid){{")
+        self.print("    int idx = getInvalidIdx();")
+        self.print("    for(int i=nlocal(); i<size(); ++i){")
+        self.print("        if (getUid(i) == uid){")
+        self.print("            idx = i;")
+        self.print("            break;")
+        self.print("        }")
+        self.print("    }")
+        self.print("    return idx;")
+        self.print("}")
+        self.print("")
diff --git a/src/pairs/code_gen/cgen.py b/src/pairs/code_gen/cgen.py
index 766dcba..29e8b2f 100644
--- a/src/pairs/code_gen/cgen.py
+++ b/src/pairs/code_gen/cgen.py
@@ -33,6 +33,7 @@ from pairs.ir.vectors import Vector, VectorAccess, VectorOp, ZeroVector
 from pairs.sim.domain_partitioners import DomainPartitioners
 from pairs.sim.timestep import Timestep
 from pairs.code_gen.printer import Printer
+from pairs.code_gen.accessor import PairsAcessor
 
 
 class CGen:
@@ -61,7 +62,7 @@ class CGen:
             # Ideally this should never be called
             return "nullptr"
         
-        name = obj.name() if not device else f"d_{obj.name()}"
+        name = obj.name() if not device else f"{obj.name()}_d"
         t = obj.type()
         if not Types.is_scalar(t) and index is not None:
             name += f"_{index}"
@@ -197,102 +198,8 @@ class CGen:
         self.print.add_indent(-4)
         self.print("}")
         self.print("")
-
-    def generate_host_pairs_accessor_class(self):
-        self.print("#include <core/math/Vector3.h>")
-        self.print("#include <core/math/Quaternion.h>")
-        self.print("#include <core/math/Matrix3.h>")
-        self.print("")
-        self.print("class PairsAccessor {")
-        self.print("private:")
-        self.print("    std::shared_ptr<PairsSimulation> ps;")
-        self.print("public:")
-        self.print.add_indent(4)
-        self.print("PairsAccessor(const std::shared_ptr<PairsSimulation> &ps_): ps(ps_){}")
-        self.print("")
-        self.print("int size() const { return ps->pobj->nlocal + ps->pobj->nghost; }")
-        self.print("")
-
-        self.print("int nlocal() const { return ps->pobj->nlocal; }")
-        self.print("")
-
-        self.print("int nghost() const { return ps->pobj->nghost; }")
-        self.print("")
-
-        self.print("int getInvalidIdx(){return -1;}")
-        self.print("")
-
-        self.print("pairs::id_t getInvalidUid(){return 0;}")
-        self.print("")
-
-        self.print('''int uidToIdx(pairs::id_t uid){
-        int idx = getInvalidIdx();
-        for(int i=0; i<this->nlocal(); ++i){
-            if (getUid(i) == uid){
-                idx = i;
-                break;
-            }
-        }
-        return idx;''')
-        self.print("}")
-        self.print("")
-
-        self.print('''int uidToIdxGhost(pairs::id_t uid){
-        int idx = getInvalidIdx();
-        for(int i=this->nlocal(); i<this->size(); ++i){
-            if (getUid(i) == uid){
-                idx = i;
-                break;
-            }
-        }
-        return idx;''')
-        self.print("}")
-        self.print("")
-
-        for p in self.sim.properties:
-            ptr = p.name()
-
-            tkw = Types.walberla_keyword(self.sim, p.type())
-
-            splitname = ptr.split('_')
-            funcname = ''.join(word.capitalize() for word in splitname)
-            v = f"ps->pobj->{ptr}"
-            getSignature = f"{tkw} get{funcname}(const size_t i) const"
-            setSignature = f"void set{funcname}(const size_t i, {tkw} const &value)"
-
-            if Types.is_scalar(p.type()):
-                self.print(f"{getSignature} {{return {v}[i];}}")
-                self.print(f"{setSignature} {{{v}[i] = value;}}")
-                self.print("")
-
-            elif p.type()==Types.Vector:
-                self.print(f"{getSignature} {{return {tkw}({v}[i*3 + 0], {v}[i*3 + 1], {v}[i*3 + 2]);}}")
-                self.print(f"{setSignature} {{{v}[i*3 + 0] = value[0]; {v}[i*3 + 1] = value[1]; {v}[i*3 + 2] = value[2];}}")
-                self.print("")
-
-            elif p.type()==Types.Quaternion:
-                self.print(f"{getSignature} {{return {tkw}({v}[i*4 + 0], {v}[i*4 + 1], {v}[i*4 + 2], {v}[i*4 + 3]);}}")
-                self.print(f"{setSignature} {{{v}[i*4 + 0] = value[0]; {v}[i*4 + 1] = value[1]; {v}[i*4 + 2] = value[2]; {v}[i*4 + 3] = value[3];}}")
-                self.print("")
-
-            elif p.type()==Types.Matrix:
-                self.print(f"{getSignature} {{" \
-                           f"return {tkw}({v}[i*9 + 0], {v}[i*9 + 1], {v}[i*9 + 2], "\
-                                        f"{v}[i*9 + 3], {v}[i*9 + 4], {v}[i*9 + 5], "\
-                                        f"{v}[i*9 + 6], {v}[i*9 + 7], {v}[i*9 + 8]);}}")
-                self.print(f"{setSignature} {{" \
-                           f"{v}[i*9 + 0] = value[0]; {v}[i*9 + 1] = value[1]; {v}[i*9 + 2] = value[2]; "\
-                            f"{v}[i*9 + 3] = value[3]; {v}[i*9 + 4] = value[4]; {v}[i*9 + 5] = value[5]; "\
-                            f"{v}[i*9 + 6] = value[6]; {v}[i*9 + 7] = value[7]; {v}[i*9 + 8] = value[8];}}")
-                self.print("")
-            
-            
-        self.print.add_indent(-4)
-        self.print("};")
-        self.print("")
-
+        
     def generate_pairs_object_structure(self):
-
         self.print("")
         externkw = "" if self.sim._generate_whole_program else "extern "
         if self.target.is_gpu():
@@ -301,14 +208,14 @@ class CGen:
                     t = array.type()
                     tkw = Types.c_keyword(self.sim, t)
                     size = self.generate_expression(ScalarOp.inline(array.alloc_size()))
-                    self.print(f"{externkw}__constant__ {tkw} d_{array.name()}[{size}];")
+                    self.print(f"{externkw}__constant__ {tkw} {array.name()}_d[{size}];")
 
             for feature_prop in self.sim.feature_properties:
                 if feature_prop.device_flag:
                     t = feature_prop.type()
                     tkw = Types.c_keyword(self.sim, t)
                     size = feature_prop.array_size()
-                    self.print(f"{externkw}__constant__ {tkw} d_{feature_prop.name()}[{size}];")
+                    self.print(f"{externkw}__constant__ {tkw} {feature_prop.name()}_d[{size}];")
 
         self.print("")
         self.print("struct PairsObjects {")
@@ -330,7 +237,7 @@ class CGen:
                 if a.is_static():
                     continue
                 else:
-                    self.print(f"{tkw} *d_{ptr};")
+                    self.print(f"{tkw} *{ptr}_d;")
 
         self.print("// Properties")
         for p in self.sim.properties:
@@ -339,7 +246,7 @@ class CGen:
             self.print(f"{tkw} *{ptr};")
 
             if self.target.is_gpu() and p.device_flag:
-                self.print(f"{tkw} *d_{ptr};")
+                self.print(f"{tkw} *{ptr}_d;")
 
         self.print("// Contact properties")
         for cp in self.sim.contact_properties:
@@ -348,7 +255,7 @@ class CGen:
             self.print(f"{tkw} *{ptr};")
 
             if self.target.is_gpu() and cp.device_flag:
-                self.print(f"{tkw} *d_{ptr};")
+                self.print(f"{tkw} *{ptr}_d;")
 
         self.print("// Feature properties")
         for fp in self.sim.feature_properties:
@@ -423,14 +330,14 @@ class CGen:
                     t = array.type()
                     tkw = Types.c_keyword(self.sim, t)
                     size = self.generate_expression(ScalarOp.inline(array.alloc_size()))
-                    self.print(f"__constant__ {tkw} d_{array.name()}[{size}];")
+                    self.print(f"__constant__ {tkw} {array.name()}_d[{size}];")
 
             for feature_prop in self.sim.feature_properties:
                 if feature_prop.device_flag:
                     t = feature_prop.type()
                     tkw = Types.c_keyword(self.sim, t)
                     size = feature_prop.array_size()
-                    self.print(f"__constant__ {tkw} d_{feature_prop.name()}[{size}];")
+                    self.print(f"__constant__ {tkw} {feature_prop.name()}_d[{size}];")
 
         self.print("")
                     
@@ -509,9 +416,16 @@ class CGen:
         self.print("}")
         self.print("")
 
-        self.print("int rank(){")
-        self.print("    return pairs_runtime->getDomainPartitioner()->getRank();")
-        self.print("}")
+        self.print("int rank(){ return pairs_runtime->getDomainPartitioner()->getRank();}")
+        self.print("")
+
+        self.print("int size(){ return pobj->nlocal + pobj->nghost;}")
+        self.print("")
+
+        self.print("int nlocal(){ return pobj->nlocal;}")
+        self.print("")
+
+        self.print("int nghost(){ return pobj->nghost;}")
         self.print("")
 
         self.print("void setup_sim() {")
@@ -529,7 +443,7 @@ class CGen:
         self.print("}")
         self.print("")
 
-        self.print("void communicate(int timestep) {")
+        self.print("void communicate(int timestep = 0) {")
         self.print("    pobj->sim_timestep = timestep;")
         self.generate_statement(communicate_module.block)
         self.print("}")
@@ -555,9 +469,7 @@ class CGen:
         self.print.add_indent(-4)
         self.print("};")
 
-        if self.sim.partitioner()==DomainPartitioners.BlockForest:
-            self.generate_host_pairs_accessor_class()
-        # self.generate_host_pairs_accessor_class()
+        PairsAcessor(self).generate()
         
         self.print.end()
         self.generate_full_object_names = False
@@ -581,33 +493,33 @@ class CGen:
 
         for array in module.arrays():
             type_kw = Types.c_keyword(self.sim, array.type())
-            name = array.name() if not device_cond else f"d_{array.name()}"
+            name = array.name() if not device_cond else f"{array.name()}_d"
             if not array.is_static() or (array.is_static() and not device_cond):
                 self.print(f"{type_kw} *{array.name()} = pobj->{name};")
 
             if array in module.host_references():
-                self.print(f"{type_kw} *h_{array.name()} = pobj->{array.name()};")
+                self.print(f"{type_kw} *{array.name()}_h = pobj->{array.name()};")
 
 
         for prop in module.properties():
             type_kw = Types.c_keyword(self.sim, prop.type())
-            name = prop.name() if not device_cond else f"d_{prop.name()}"
+            name = prop.name() if not device_cond else f"{prop.name()}_d"
             self.print(f"{type_kw} *{prop.name()} = pobj->{name};")
 
             if prop in module.host_references():
-                self.print(f"{type_kw} *h_{prop.name()} = pobj->{prop.name()};")
+                self.print(f"{type_kw} *{prop.name()}_h = pobj->{prop.name()};")
 
         for contact_prop in module.contact_properties():
             type_kw = Types.c_keyword(self.sim, contact_prop.type())
-            name = contact_prop.name() if not device_cond else f"d_{contact_prop.name()}"
+            name = contact_prop.name() if not device_cond else f"{contact_prop.name()}_d"
             self.print(f"{type_kw} *{contact_prop.name()} = pobj->{name};")
 
             if contact_prop in module.host_references():
-                self.print(f"{type_kw} *h_{contact_prop.name()} = pobj->{contact_prop.name()};")
+                self.print(f"{type_kw} *{contact_prop.name()}_h = pobj->{contact_prop.name()};")
 
         for feature_prop in module.feature_properties():
             type_kw = Types.c_keyword(self.sim, feature_prop.type())
-            name = feature_prop.name() if not device_cond else f"d_{feature_prop.name()}"
+            name = feature_prop.name() if not device_cond else f"{feature_prop.name()}_d"
 
             if feature_prop.device_flag and device_cond:
                 # self.print(f"{type_kw} *{feature_prop.name()} = {self.generate_object_reference(feature_prop, device=device_cond)};")
@@ -616,7 +528,7 @@ class CGen:
                 self.print(f"{type_kw} *{feature_prop.name()} = pobj->{name};")
 
             if feature_prop in module.host_references():
-                self.print(f"{type_kw} *h_{feature_prop.name()} = pobj->{feature_prop.name()};")
+                self.print(f"{type_kw} *{feature_prop.name()}_h = pobj->{feature_prop.name()};")
 
     def generate_main(self, module):
         assert module.name=='main'
@@ -1018,11 +930,11 @@ class CGen:
             if ast_node.decl:
                 self.print(f"{tkw} *{array_name} = ({tkw} *) malloc({size});")
                 if self.target.is_gpu() and ast_node.array.device_flag:
-                    self.print(f"{tkw} *d_{array_name} = ({tkw} *) pairs::device_alloc({size});")
+                    self.print(f"{tkw} *{array_name}_d = ({tkw} *) pairs::device_alloc({size});")
             else:
                 self.print(f"{array_name} = ({tkw} *) malloc({size});")
                 if self.target.is_gpu() and ast_node.array.device_flag:
-                    self.print(f"d_{array_name} = ({tkw} *) pairs::device_alloc({size});")
+                    self.print(f"{array_name}_d = ({tkw} *) pairs::device_alloc({size});")
 
         if isinstance(ast_node, KernelLaunch):
             range_start = self.generate_expression(ScalarOp.inline(ast_node.min))
@@ -1274,14 +1186,14 @@ class CGen:
 
         if isinstance(ast_node, DeviceStaticRef):
             elem = self.generate_expression(ast_node.elem)
-            return f"d_{elem}"
+            return f"{elem}_d"
 
         if isinstance(ast_node, FeatureProperty):
             return self.generate_object_reference(ast_node)
 
         if isinstance(ast_node, HostRef):
             elem = self.generate_expression(ast_node.elem)
-            return f"h_{elem}"
+            return f"{elem}_h"
 
         if isinstance(ast_node, Iter):
             assert mem is False, "Iterator is not lvalue!"
diff --git a/src/pairs/ir/types.py b/src/pairs/ir/types.py
index e1b3b51..f4ab048 100644
--- a/src/pairs/ir/types.py
+++ b/src/pairs/ir/types.py
@@ -13,13 +13,13 @@ class Types:
     Matrix = 10
     Quaternion = 11
 
-    def walberla_keyword(sim, t):
+    def c_accessor_keyword(sim, t):
         real_kw = 'double' if sim.use_double_precision() else 'float'
         return (
             real_kw if t==Types.Real
-            else f'walberla::math::Vector3<{real_kw}>' if t==Types.Vector
-            else f'walberla::math::Matrix3<{real_kw}>' if t==Types.Matrix
-            else f'walberla::math::Quaternion<{real_kw}>' if t==Types.Quaternion
+            else f'pairs::Vector3<{real_kw}>' if t==Types.Vector
+            else f'pairs::Matrix3<{real_kw}>' if t==Types.Matrix
+            else f'pairs::Quaternion<{real_kw}>' if t==Types.Quaternion
             else 'float' if t == Types.Float
             else 'double' if t == Types.Double
             else 'int' if t == Types.Int32
-- 
GitLab