diff --git a/source/adios2/ADIOSMacros.h b/source/adios2/ADIOSMacros.h
index e482a8855a575f8ece7421562dc0ddb18f766f5e..2850171ef78e9cb36445144c3b1658d5eeb52349 100644
--- a/source/adios2/ADIOSMacros.h
+++ b/source/adios2/ADIOSMacros.h
@@ -8,6 +8,8 @@
 #ifndef ADIOS2_ADIOSMACROS_H
 #define ADIOS2_ADIOSMACROS_H
 
+#include <string>
+
 #include "adios2/ADIOSTypes.h"
 // The ADIOS_FOREACH_TYPE_1ARG macro assumes the given argument is a macro which
 // takes a single argument that is a type and then inserts the given MACRO for
@@ -51,6 +53,8 @@
     MACRO(unsigned int)                                                        \
     MACRO(long int)                                                            \
     MACRO(unsigned long int)                                                   \
+    MACRO(long long int)                                                       \
+    MACRO(unsigned long long int)                                              \
     MACRO(float)                                                               \
     MACRO(double)
 
@@ -64,4 +68,20 @@
     MACRO(float)                                                               \
     MACRO(double)
 
+#define ADIOS2_FOREACH_ATTRIBUTE_TYPE_1ARG(MACRO)                              \
+    MACRO(std::string)                                                         \
+    MACRO(char)                                                                \
+    MACRO(unsigned char)                                                       \
+    MACRO(short)                                                               \
+    MACRO(unsigned short)                                                      \
+    MACRO(int)                                                                 \
+    MACRO(unsigned int)                                                        \
+    MACRO(long int)                                                            \
+    MACRO(unsigned long int)                                                   \
+    MACRO(long long int)                                                       \
+    MACRO(unsigned long long int)                                              \
+    MACRO(float)                                                               \
+    MACRO(double)                                                              \
+    MACRO(long double)
+
 #endif /* ADIOS2_ADIOSMACROS_H */
diff --git a/source/adios2/CMakeLists.txt b/source/adios2/CMakeLists.txt
index 3bd8861811fcdb0cf4812ccd591e53c957331c4e..de3e5c2b4087496ae1696eba0eec46121e095a22 100644
--- a/source/adios2/CMakeLists.txt
+++ b/source/adios2/CMakeLists.txt
@@ -4,6 +4,8 @@
 #------------------------------------------------------------------------------#
   
 add_library(adios2
+  core/Attribute.cpp core/Attribute.tcc
+  core/AttributeBase.cpp
   core/ADIOS.cpp
   core/Engine.cpp
   core/IO.cpp core/IO.tcc
diff --git a/source/adios2/core/Attribute.cpp b/source/adios2/core/Attribute.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8e473101dcaec65e405c397f8e6122526d19a8f3
--- /dev/null
+++ b/source/adios2/core/Attribute.cpp
@@ -0,0 +1,17 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * Attribute.cpp : needed for template separation using Attribute.tcc
+ *
+ *  Created on: Aug 3, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include "Attribute.h"
+#include "Attribute.tcc"
+
+namespace adios2
+{
+
+} // end namespace adios2
diff --git a/source/adios2/core/Attribute.h b/source/adios2/core/Attribute.h
new file mode 100644
index 0000000000000000000000000000000000000000..bddd3c8087a9a22fc86b6a283215c9e8cb4eea9e
--- /dev/null
+++ b/source/adios2/core/Attribute.h
@@ -0,0 +1,48 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * Attribute.h : template class that defines typed attributes
+ *
+ *  Created on: Aug 1, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#ifndef ADIOS2_CORE_ATTRIBUTE_H_
+#define ADIOS2_CORE_ATTRIBUTE_H_
+
+#include "adios2/core/AttributeBase.h"
+
+namespace adios2
+{
+/** @brief Attributes provide complementary information to IO Variables*/
+template <class T>
+class Attribute : public AttributeBase
+{
+
+public:
+    const T *m_DataArray = nullptr;
+    T m_DataValue;
+
+    /**
+     * Data array constructor
+     * @param name
+     * @param data
+     * @param elements
+     */
+    Attribute<T>(const std::string &name, const T *data, const size_t elements);
+
+    /**
+     * Single value constructor
+     * @param name
+     * @param data
+     * @param elements
+     */
+    Attribute<T>(const std::string &name, const T &data);
+
+    ~Attribute<T>() = default;
+};
+
+} // end namespace adios2
+
+#endif /* ADIOS2_CORE_ATTRIBUTE_H_ */
diff --git a/source/adios2/core/Attribute.tcc b/source/adios2/core/Attribute.tcc
new file mode 100644
index 0000000000000000000000000000000000000000..6e771fc15591229787d44f7256aa9cef42419266
--- /dev/null
+++ b/source/adios2/core/Attribute.tcc
@@ -0,0 +1,43 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * Attribute.tcc
+ *
+ *  Created on: Aug 1, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#ifndef ADIOS2_CORE_ATTRIBUTE_TCC_
+#define ADIOS2_CORE_ATTRIBUTE_TCC_
+
+#include "Attribute.h"
+
+#include "adios2/ADIOSMacros.h"
+#include "adios2/helper/adiosFunctions.h" //GetType<T>
+
+namespace adios2
+{
+
+#define declare_type(T)                                                        \
+                                                                               \
+    template <>                                                                \
+    Attribute<T>::Attribute(const std::string &name, const T *array,           \
+                            const size_t elements)                             \
+    : AttributeBase(name, GetType<T>(), elements), m_DataArray(array),         \
+      m_DataValue()                                                            \
+    {                                                                          \
+    }                                                                          \
+                                                                               \
+    template <>                                                                \
+    Attribute<T>::Attribute(const std::string &name, const T &value)           \
+    : AttributeBase(name, GetType<T>(), 1), m_DataValue(value)                 \
+    {                                                                          \
+    }
+
+ADIOS2_FOREACH_ATTRIBUTE_TYPE_1ARG(declare_type)
+#undef declare_type
+
+} // end namespace adios2
+
+#endif /* ADIOS2_CORE_ATTRIBUTE_TCC_ */
diff --git a/source/adios2/core/AttributeBase.cpp b/source/adios2/core/AttributeBase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..498e7fbfc75a05549780daeb590bfedae204d407
--- /dev/null
+++ b/source/adios2/core/AttributeBase.cpp
@@ -0,0 +1,22 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * AttributeBase.cpp
+ *
+ *  Created on: Aug 1, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include "AttributeBase.h"
+
+namespace adios2
+{
+
+AttributeBase::AttributeBase(const std::string &name, const std::string type,
+                             const size_t elements)
+: m_Name(name), m_Type(type), m_Elements(elements)
+{
+}
+
+} // end namespace adios2
diff --git a/source/adios2/core/AttributeBase.h b/source/adios2/core/AttributeBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..a1a6b7c5ad7e8ca1ccef596154e2c4af8c0a5030
--- /dev/null
+++ b/source/adios2/core/AttributeBase.h
@@ -0,0 +1,46 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * AttributeBase.h : base class for Attribute<T> class, allows RTTI at read time
+ *
+ *  Created on: Aug 1, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#ifndef ADIOS2_CORE_ATTRIBUTEBASE_H_
+#define ADIOS2_CORE_ATTRIBUTEBASE_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <string>
+/// \endcond
+
+#include "adios2/ADIOSConfig.h"
+#include "adios2/ADIOSTypes.h"
+
+namespace adios2
+{
+
+class AttributeBase
+{
+
+public:
+    const std::string m_Name;
+    const std::string m_Type;
+    const size_t m_Elements;
+
+    /**
+     * Unique constructor used by Attribute<T> derived class
+     * @param name
+     * @param type
+     * @param elements
+     */
+    AttributeBase(const std::string &name, const std::string type,
+                  const size_t elements);
+
+    virtual ~AttributeBase() = default;
+};
+
+} // end namespace adios2
+
+#endif /* ADIOS2_CORE_ATTRIBUTEBASE_H_ */
diff --git a/source/adios2/core/IO.cpp b/source/adios2/core/IO.cpp
index 492aa0d84277b1c3e44d4ac85f1e6dae5daf71e6..1dee549c8f6ae855d818460b11cb5773a24c68fe 100644
--- a/source/adios2/core/IO.cpp
+++ b/source/adios2/core/IO.cpp
@@ -108,7 +108,7 @@ IO::DefineVariableCompound(const std::string &name, const size_t sizeOfVariable,
 
 VariableCompound &IO::GetVariableCompound(const std::string &name)
 {
-    return m_Compound.at(GetVariableIndex(name));
+    return m_Compound.at(GetMapIndex(name, m_Variables, "VariableCompound"));
 }
 
 std::string IO::GetVariableType(const std::string &name) const
@@ -281,30 +281,42 @@ std::shared_ptr<Engine> IO::Open(const std::string &name,
 }
 
 // PRIVATE Functions
-unsigned int IO::GetVariableIndex(const std::string &name) const
+unsigned int IO::GetMapIndex(const std::string &name, const DataMap &dataMap,
+                             const std::string hint) const
 {
+    auto itDataMap = dataMap.find(name);
+
     if (m_DebugMode)
     {
-        if (!VariableExists(name))
+        if (IsEnd(itDataMap, dataMap))
         {
-            throw std::invalid_argument(
-                "ERROR: variable " + m_Name +
-                " wasn't created with DefineVariable, in call to IO object " +
-                m_Name + " GetVariable\n");
+            throw std::invalid_argument("ERROR: " + hint + " " + m_Name +
+                                        " wasn't created with Define " + hint +
+                                        ", in call to IO object " + m_Name +
+                                        " Get" + hint + "\n");
         }
     }
-    auto itVariable = m_Variables.find(name);
-    return itVariable->second.second;
+    return itDataMap->second.second;
+}
+
+void IO::CheckAttributeCommon(const std::string &name) const
+{
+    auto itAttribute = m_Attributes.find(name);
+    if (!IsEnd(itAttribute, m_Attributes))
+    {
+        throw std::invalid_argument("ERROR: attribute " + name +
+                                    " exists in IO object " + m_Name +
+                                    ", in call to DefineAttribute\n");
+    }
 }
 
-bool IO::VariableExists(const std::string &name) const
+bool IO::IsEnd(DataMap::const_iterator itDataMap, const DataMap &dataMap) const
 {
-    bool exists = false;
-    if (m_Variables.count(name) == 1)
+    if (itDataMap == dataMap.end())
     {
-        exists = true;
+        return true;
     }
-    return exists;
+    return false;
 }
 
 void IO::CheckTransportType(const std::string type) const
@@ -321,11 +333,22 @@ void IO::CheckTransportType(const std::string type) const
 
 // Explicitly instantiate the necessary public template implementations
 #define define_template_instantiation(T)                                       \
-    template Variable<T> &IO::DefineVariable<T>(                               \
-        const std::string &, const Dims, const Dims, const Dims, const bool);  \
+    template Variable<T> &IO::DefineVariable<T>(const std::string &,           \
+                                                const Dims &, const Dims &,    \
+                                                const Dims &, const bool);     \
     template Variable<T> &IO::GetVariable<T>(const std::string &);
 
 ADIOS2_FOREACH_TYPE_1ARG(define_template_instantiation)
 #undef define_template_instatiation
 
+#define declare_template_instantiation(T)                                      \
+    template Attribute<T> &IO::DefineAttribute<T>(const std::string &,         \
+                                                  const T *, const size_t);    \
+    template Attribute<T> &IO::DefineAttribute<T>(const std::string &,         \
+                                                  const T &);                  \
+    template Attribute<T> &IO::GetAttribute(const std::string &);
+
+ADIOS2_FOREACH_ATTRIBUTE_TYPE_1ARG(declare_template_instantiation)
+#undef declare_template_instantiation
+
 } // end namespace adios
diff --git a/source/adios2/core/IO.h b/source/adios2/core/IO.h
index fbd8bb91cf29971356de8a8d471a1c45d658c733..f0a7b453633131f6077cf03b79505c7112e1dd65 100644
--- a/source/adios2/core/IO.h
+++ b/source/adios2/core/IO.h
@@ -24,12 +24,16 @@
 #include "adios2/ADIOSMPICommOnly.h"
 #include "adios2/ADIOSMacros.h"
 #include "adios2/ADIOSTypes.h"
+#include "adios2/core/Attribute.h"
 #include "adios2/core/Variable.h"
 #include "adios2/core/VariableCompound.h"
 
 namespace adios2
 {
 
+/** used for Variables and Attributes */
+using DataMap = std::map<std::string, std::pair<std::string, unsigned int>>;
+
 // forward declaration needed as IO is passed to Engine derived
 // classes
 class Engine;
@@ -134,8 +138,8 @@ public:
      * @return reference to Variable object
      */
     template <class T>
-    Variable<T> &DefineVariable(const std::string &name, const Dims shape = {},
-                                const Dims start = {}, const Dims count = {},
+    Variable<T> &DefineVariable(const std::string &name, const Dims &shape = {},
+                                const Dims &start = {}, const Dims &count = {},
                                 const bool constantShape = false);
 
     /**
@@ -151,11 +155,12 @@ public:
      * @return reference to Variable object
      */
     template <class T>
-    VariableCompound &
-    DefineVariableCompound(const std::string &name, const Dims shape = Dims{},
-                           const Dims start = Dims{}, const Dims count = Dims{},
-                           const bool constantDims = false);
-
+    VariableCompound &DefineVariableCompound(const std::string &name,
+                                             const Dims &shape = Dims{},
+                                             const Dims &start = Dims{},
+                                             const Dims &count = Dims{},
+                                             const bool constantShape = false);
+  
     VariableCompound &DefineVariableCompound(const std::string &name,
                                              const size_t sizeOfVariable,
                                              const Dims &shape = Dims{},
@@ -163,6 +168,26 @@ public:
                                              const Dims &count = Dims{},
                                              const bool constantDims = false);
 
+    /**
+     * Define attribute from contiguous data array owned by an application
+     * @param name must be unique for the IO object
+     * @param array pointer to user data
+     * @param elements number of data elements
+     * @return reference to internal Attribute
+     */
+    template <class T>
+    Attribute<T> &DefineAttribute(const std::string &name, const T *array,
+                                  const size_t elements);
+
+    /**
+     * Define attribute from a single variable making a copy
+     * @param name must be unique for the IO object
+     * @param value single data value
+     * @return reference to internal Attribute
+     */
+    template <class T>
+    Attribute<T> &DefineAttribute(const std::string &name, const T &value);
+
     /**
      * Removes an existing Variable previously created with DefineVariable or
      * DefineVariableCompound
@@ -189,6 +214,15 @@ public:
      */
     VariableCompound &GetVariableCompound(const std::string &name);
 
+    /**
+     * Gets an existing attribute of primitive type by name
+     * @param name of attribute to be retrieved
+     * @return reference to an existing attribute created with DefineAttribute
+     * throws an exception if Attribute is not found
+     */
+    template <class T>
+    Attribute<T> &GetAttribute(const std::string &name);
+
     /**
      * Get the type if variable (by name id) exists
      * @param name input id
@@ -248,7 +282,7 @@ private:
      *        pair.second = index in fixed size map (e.g. m_Int8, m_Double)
      * </pre>
      */
-    std::map<std::string, std::pair<std::string, unsigned int>> m_Variables;
+    DataMap m_Variables;
 
     /** Variable containers based on fixed-size type */
     std::map<unsigned int, Variable<char>> m_Char;
@@ -270,25 +304,63 @@ private:
     std::map<unsigned int, Variable<cldouble>> m_CLDouble;
     std::map<unsigned int, VariableCompound> m_Compound;
 
-    std::map<std::string, std::string> m_AttributesString;
-    std::map<std::string, double> m_AttributesNumeric;
-
-    std::set<std::string> m_EngineNames;
-
     /** Gets the internal reference to a variable map for type T
      *  This function is specialized in IO.tcc */
     template <class T>
     std::map<unsigned int, Variable<T>> &GetVariableMap();
 
-    /** Gets the internal index in variable map for an existing variable */
-    unsigned int GetVariableIndex(const std::string &name) const;
+    /**
+     * Map holding attribute identifiers
+     * <pre>
+     * key: unique attribute name,
+     * value: pair.first = type as string GetType<T> from
+     *                     helper/adiosTemplates.h
+     *        pair.second = index in fixed size map (e.g. m_Int8, m_Double)
+     * </pre>
+     */
+    DataMap m_Attributes;
+
+    std::map<unsigned int, Attribute<std::string>> m_StringA;
+    std::map<unsigned int, Attribute<char>> m_CharA;
+    std::map<unsigned int, Attribute<unsigned char>> m_UCharA;
+    std::map<unsigned int, Attribute<short>> m_ShortA;
+    std::map<unsigned int, Attribute<unsigned short>> m_UShortA;
+    std::map<unsigned int, Attribute<int>> m_IntA;
+    std::map<unsigned int, Attribute<unsigned int>> m_UIntA;
+    std::map<unsigned int, Attribute<long int>> m_LIntA;
+    std::map<unsigned int, Attribute<unsigned long int>> m_ULIntA;
+    std::map<unsigned int, Attribute<long long int>> m_LLIntA;
+    std::map<unsigned int, Attribute<unsigned long long int>> m_ULLIntA;
+    std::map<unsigned int, Attribute<float>> m_FloatA;
+    std::map<unsigned int, Attribute<double>> m_DoubleA;
+    std::map<unsigned int, Attribute<long double>> m_LDoubleA;
+
+    template <class T>
+    std::map<unsigned int, Attribute<T>> &GetAttributeMap();
 
     /**
-     * Checks if variable exists by checking its name
-     * @param name unique variable name to be checked against existing variables
-     * @return true: variable name exists, false: variable name doesn't exist
+     * Gets map index for Variables or Attributes
+     * @param name
+     * @param dataMap m_Variables or m_Attributes
+     * @param hint "Variable", "Attribute", or "VariableCompound"
+     * @return index in type map
      */
-    bool VariableExists(const std::string &name) const;
+    unsigned int GetMapIndex(const std::string &name, const DataMap &dataMap,
+                             const std::string hint) const;
+
+    /** Checks if attribute exists, called from DefineAttribute different
+     * signatures */
+    void CheckAttributeCommon(const std::string &name) const;
+
+    std::set<std::string> m_EngineNames;
+
+    /**
+     * Checks if iterator points to end. Used for Variables and Attributes.
+     * @param itDataMap iterator to be tested
+     * @param dataMap map
+     * @return true: itDataMap == dataMap.end(), false otherwise
+     */
+    bool IsEnd(DataMap::const_iterator itDataMap, const DataMap &dataMap) const;
 
     void CheckTransportType(const std::string type) const;
 };
@@ -296,14 +368,24 @@ private:
 // Explicit declaration of the public template methods
 #define declare_template_instantiation(T)                                      \
     extern template Variable<T> &IO::DefineVariable<T>(                        \
-        const std::string &name, const Dims, const Dims, const Dims,           \
-        const bool constantShape);                                             \
+        const std::string &, const Dims &, const Dims &, const Dims &,         \
+        const bool);                                                           \
     extern template Variable<T> &IO::GetVariable<T>(const std::string &name);
 
 ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
 #undef declare_template_instantiation
 
-} // end namespace adios
+#define declare_template_instantiation(T)                                      \
+    extern template Attribute<T> &IO::DefineAttribute<T>(                      \
+        const std::string &, const T *, const size_t);                         \
+    extern template Attribute<T> &IO::DefineAttribute<T>(const std::string &,  \
+                                                         const T &);           \
+    extern template Attribute<T> &IO::GetAttribute(const std::string &);
+
+ADIOS2_FOREACH_ATTRIBUTE_TYPE_1ARG(declare_template_instantiation)
+#undef declare_template_instantiation
+
+} // end namespace adios2
 
 #include "adios2/core/IO.inl"
 
diff --git a/source/adios2/core/IO.inl b/source/adios2/core/IO.inl
index 73c05a1b2a0e794720182a9e059297258e068f31..4a89c759c71952c545eb8f49184d37bc49880202 100644
--- a/source/adios2/core/IO.inl
+++ b/source/adios2/core/IO.inl
@@ -2,7 +2,8 @@
  * Distributed under the OSI-approved Apache License, Version 2.0.  See
  * accompanying file Copyright.txt for details.
  *
- * IO.inl inline template functions implementation of IO class
+ * IO.inl inline template functions implementation of IO class. VariableCompound
+ * can take any type so must be inlined as type is not known a priori.
  *
  *  Created on: May 15, 2017
  *      Author: William F Godoy godoywf@ornl.gov
@@ -21,8 +22,8 @@ namespace adios2
 
 template <class T>
 VariableCompound &IO::DefineVariableCompound(const std::string &name,
-                                             const Dims shape, const Dims start,
-                                             const Dims count,
+                                             const Dims &shape, const Dims &start,
+                                             const Dims &count,
                                              const bool constantDims)
 {
     return DefineVariableCompound(name, sizeof(T), shape, start, count,
diff --git a/source/adios2/core/IO.tcc b/source/adios2/core/IO.tcc
index 6f892ee6d1c38f9525029559514e96661ffd11b2..eb11fc87444b1b788368990f6da0faa35146b7d3 100644
--- a/source/adios2/core/IO.tcc
+++ b/source/adios2/core/IO.tcc
@@ -26,13 +26,14 @@ namespace adios2
 {
 
 template <class T>
-Variable<T> &IO::DefineVariable(const std::string &name, const Dims shape,
-                                const Dims start, const Dims count,
-                                const bool constantDims)
+Variable<T> &IO::DefineVariable(const std::string &name, const Dims &shape,
+                                const Dims &start, const Dims &count,
+                                const bool constantShape)
 {
     if (m_DebugMode)
     {
-        if (VariableExists(name))
+        auto itVariable = m_Variables.find(name);
+        if (!IsEnd(itVariable, m_Variables))
         {
             throw std::invalid_argument("ERROR: variable " + name +
                                         " exists in IO object " + m_Name +
@@ -41,7 +42,8 @@ Variable<T> &IO::DefineVariable(const std::string &name, const Dims shape,
     }
 
     auto &variableMap = GetVariableMap<T>();
-    const unsigned int size = variableMap.size();
+    const unsigned int size =
+        static_cast<const unsigned int>(variableMap.size());
     auto itVariablePair =
         variableMap.emplace(size, Variable<T>(name, shape, start, count,
                                               constantDims, m_DebugMode));
@@ -53,7 +55,53 @@ Variable<T> &IO::DefineVariable(const std::string &name, const Dims shape,
 template <class T>
 Variable<T> &IO::GetVariable(const std::string &name)
 {
-    return GetVariableMap<T>().at(GetVariableIndex(name));
+    return GetVariableMap<T>().at(GetMapIndex(name, m_Variables, "Variable"));
+}
+
+template <class T>
+Attribute<T> &IO::DefineAttribute(const std::string &name, const T &value)
+{
+    if (m_DebugMode)
+    {
+        CheckAttributeCommon(name);
+    }
+
+    auto &attributeMap = GetAttributeMap<T>();
+    const unsigned int size =
+        static_cast<const unsigned int>(attributeMap.size());
+
+    auto itAttributePair =
+        attributeMap.emplace(size, Attribute<T>(name, value));
+    m_Attributes.emplace(name, std::make_pair(GetType<T>(), size));
+
+    return itAttributePair.first->second;
+}
+
+template <class T>
+Attribute<T> &IO::DefineAttribute(const std::string &name, const T *array,
+                                  const size_t elements)
+{
+    if (m_DebugMode)
+    {
+        CheckAttributeCommon(name);
+    }
+
+    auto &attributeMap = GetAttributeMap<T>();
+    const unsigned int size =
+        static_cast<const unsigned int>(attributeMap.size());
+
+    auto itAttributePair =
+        attributeMap.emplace(size, Attribute<T>(name, array, elements));
+    m_Attributes.emplace(name, std::make_pair(GetType<T>(), size));
+
+    return itAttributePair.first->second;
+}
+
+template <class T>
+Attribute<T> &IO::GetAttribute(const std::string &name)
+{
+    return GetAttributeMap<T>().at(
+        GetMapIndex(name, m_Attributes, "Attribute"));
 }
 
 // PRIVATE
@@ -159,6 +207,91 @@ std::map<unsigned int, Variable<cldouble>> &IO::GetVariableMap()
     return m_CLDouble;
 }
 
-} // end namespace adios
+// attributes
+template <>
+std::map<unsigned int, Attribute<std::string>> &IO::GetAttributeMap()
+{
+    return m_StringA;
+}
+
+template <>
+std::map<unsigned int, Attribute<char>> &IO::GetAttributeMap()
+{
+    return m_CharA;
+}
+
+template <>
+std::map<unsigned int, Attribute<unsigned char>> &IO::GetAttributeMap()
+{
+    return m_UCharA;
+}
+
+template <>
+std::map<unsigned int, Attribute<short>> &IO::GetAttributeMap()
+{
+    return m_ShortA;
+}
+
+template <>
+std::map<unsigned int, Attribute<unsigned short>> &IO::GetAttributeMap()
+{
+    return m_UShortA;
+}
+
+template <>
+std::map<unsigned int, Attribute<int>> &IO::GetAttributeMap()
+{
+    return m_IntA;
+}
+
+template <>
+std::map<unsigned int, Attribute<unsigned int>> &IO::GetAttributeMap()
+{
+    return m_UIntA;
+}
+
+template <>
+std::map<unsigned int, Attribute<long int>> &IO::GetAttributeMap()
+{
+    return m_LIntA;
+}
+
+template <>
+std::map<unsigned int, Attribute<unsigned long int>> &IO::GetAttributeMap()
+{
+    return m_ULIntA;
+}
+
+template <>
+std::map<unsigned int, Attribute<long long int>> &IO::GetAttributeMap()
+{
+    return m_LLIntA;
+}
+
+template <>
+std::map<unsigned int, Attribute<unsigned long long int>> &IO::GetAttributeMap()
+{
+    return m_ULLIntA;
+}
+
+template <>
+std::map<unsigned int, Attribute<float>> &IO::GetAttributeMap()
+{
+    return m_FloatA;
+}
+
+template <>
+std::map<unsigned int, Attribute<double>> &IO::GetAttributeMap()
+{
+    return m_DoubleA;
+}
+
+template <>
+std::map<unsigned int, Attribute<long double>> &IO::GetAttributeMap()
+{
+    return m_LDoubleA;
+}
+
+} // end namespace adios2
 
 #endif /* ADIOS2_CORE_IO_TCC_ */
diff --git a/source/adios2/core/Variable.cpp b/source/adios2/core/Variable.cpp
index 55777209f8e5382653e6d185106d1eff596c8d94..86b5e3d165d79ef6da78cd90db00ca49e64ea6fd 100644
--- a/source/adios2/core/Variable.cpp
+++ b/source/adios2/core/Variable.cpp
@@ -2,7 +2,7 @@
  * Distributed under the OSI-approved Apache License, Version 2.0.  See
  * accompanying file Copyright.txt for details.
  *
- * Variable.cpp  needed for template separation using Variable.tcc
+ * Variable.cpp : needed for template separation using Variable.tcc
  *
  *  Created on: Jun 8, 2017
  *      Author: William F Godoy godoywf@ornl.gov
@@ -14,4 +14,4 @@
 namespace adios2
 {
 
-} // end namespace adios
+} // end namespace adios2
diff --git a/source/adios2/core/Variable.h b/source/adios2/core/Variable.h
index 8e9705fc166ab4284a733a3b3d34a2cd0958ab8a..dbf5ec2dc00f5754d098f8ef79c8cee44f971b3f 100644
--- a/source/adios2/core/Variable.h
+++ b/source/adios2/core/Variable.h
@@ -18,8 +18,6 @@
 #include <vector>
 /// \endcond
 
-#include "adios2/ADIOSMacros.h"
-#include "adios2/core/Transform.h"
 #include "adios2/core/VariableBase.h"
 
 namespace adios2
@@ -50,15 +48,15 @@ public:
      * @param constantShape
      * @param debugMode
      */
-    Variable<T>(const std::string &name, const Dims shape, const Dims start,
-                const Dims count, const bool constantDims,
+    Variable<T>(const std::string &name, const Dims &shape, const Dims &start,
+                const Dims &count, const bool constantShape,
                 const bool debugMode);
 
-    virtual ~Variable<T>() = default;
+    ~Variable<T>() = default;
 
     void ApplyTransforms() final;
 };
 
-} // end namespace adios
+} // end namespace adios2
 
 #endif /* ADIOS2_CORE_VARIABLE_H_ */
diff --git a/source/adios2/core/Variable.tcc b/source/adios2/core/Variable.tcc
index 9c1f888c9eee7fb4e82f92eb397c8fa0f68d6747..d6241f856adfd5512ea87ec53cc392e6f5d2a5f9 100644
--- a/source/adios2/core/Variable.tcc
+++ b/source/adios2/core/Variable.tcc
@@ -14,7 +14,7 @@
 #include "Variable.h"
 
 #include "adios2/ADIOSMacros.h"
-#include "adios2/helper/adiosFunctions.h" //GetType
+#include "adios2/helper/adiosFunctions.h" //GetType<T>
 
 namespace adios2
 {
@@ -22,9 +22,9 @@ namespace adios2
 #define declare_type(T)                                                        \
                                                                                \
     template <>                                                                \
-    Variable<T>::Variable(const std::string &name, const Dims shape,           \
-                          const Dims start, const Dims count,                  \
-                          const bool constantDims, const bool debugMode)       \
+    Variable<T>::Variable(const std::string &name, const Dims &shape,          \
+                          const Dims &start, const Dims &count,                \
+                          const bool constantShape, const bool debugMode)      \
     : VariableBase(name, GetType<T>(), sizeof(T), shape, start, count,         \
                    constantDims, debugMode)                                    \
     {                                                                          \
@@ -38,6 +38,6 @@ namespace adios2
 ADIOS2_FOREACH_TYPE_1ARG(declare_type)
 #undef declare_type
 
-} // end namespace adios
+} // end namespace adios2
 
 #endif /* ADIOS2_CORE_VARIABLE_TCC_ */
diff --git a/source/adios2/core/VariableBase.cpp b/source/adios2/core/VariableBase.cpp
index d98f572d15db6b399d008e6d5c4364cbbd29f91c..775944e0a775fb2f0ff635c36b50ec790cdf54f0 100644
--- a/source/adios2/core/VariableBase.cpp
+++ b/source/adios2/core/VariableBase.cpp
@@ -21,8 +21,8 @@ namespace adios2
 {
 
 VariableBase::VariableBase(const std::string &name, const std::string type,
-                           const size_t elementSize, const Dims shape,
-                           const Dims start, const Dims count,
+                           const size_t elementSize, const Dims &shape,
+                           const Dims &start, const Dims &count,
                            const bool constantDims, const bool debugMode)
 : m_Name(name), m_Type(type), m_ElementSize(elementSize), m_Shape(shape),
   m_Start(start), m_Count(count), m_ConstantDims(constantDims),
@@ -41,7 +41,7 @@ size_t VariableBase::TotalSize() const noexcept
     return GetTotalSize(m_Count);
 }
 
-void VariableBase::SetSelection(const Dims start, const Dims count)
+void VariableBase::SetSelection(const Dims &start, const Dims &count)
 {
     if (m_DebugMode)
     {
diff --git a/source/adios2/core/VariableBase.h b/source/adios2/core/VariableBase.h
index 61fc093dfd72f5860565edc4eb5da69d5ec72611..f169a3299d8251eda7f6d599e6ec2b042673c15d 100644
--- a/source/adios2/core/VariableBase.h
+++ b/source/adios2/core/VariableBase.h
@@ -63,8 +63,8 @@ public:
     unsigned int m_AvailableSteps = 1;
 
     VariableBase(const std::string &name, const std::string type,
-                 const size_t elementSize, const Dims shape, const Dims start,
-                 const Dims count, const bool constantShape,
+                 const size_t elementSize, const Dims &shape, const Dims &start,
+                 const Dims &count, const bool constantShape,
                  const bool debugMode);
 
     virtual ~VariableBase() = default;
@@ -82,7 +82,7 @@ public:
     size_t TotalSize() const noexcept;
 
     /** Set the local dimension and global offset of the variable */
-    void SetSelection(const Dims start, const Dims count);
+    void SetSelection(const Dims &start, const Dims &count);
 
     /** Overloaded version of SetSelection using a SelectionBoundingBox */
     void SetSelection(const SelectionBoundingBox &selection);
diff --git a/source/adios2/helper/adiosType.inl b/source/adios2/helper/adiosType.inl
index d0573ce5adf1ac073967415341a554962085e304..b81bb598183f5f11080ef293a61f3ed396366718 100644
--- a/source/adios2/helper/adiosType.inl
+++ b/source/adios2/helper/adiosType.inl
@@ -27,6 +27,13 @@ inline std::string GetType<void>() noexcept
 {
     return "unknown";
 }
+
+template <>
+inline std::string GetType<std::string>() noexcept
+{
+    return "string";
+}
+
 template <>
 inline std::string GetType<char>() noexcept
 {
diff --git a/testing/adios2/interface/CMakeLists.txt b/testing/adios2/interface/CMakeLists.txt
index e68ccfa6187ab17710e4bca93579ede6ded95079..c446f5eef939d5f86583f37b3085fc436be5bbbb 100644
--- a/testing/adios2/interface/CMakeLists.txt
+++ b/testing/adios2/interface/CMakeLists.txt
@@ -9,5 +9,9 @@ target_link_libraries(TestADIOSInterfaceWrite adios2 gtest gtest_main)
 add_executable(TestADIOSDefineVariable TestADIOSDefineVariable.cpp)
 target_link_libraries(TestADIOSDefineVariable adios2 gtest gtest_main)
 
+add_executable(TestADIOSDefineAttribute TestADIOSDefineAttribute.cpp)
+target_link_libraries(TestADIOSDefineAttribute adios2 gtest gtest_main)
+
 gtest_add_tests(TARGET TestADIOSInterfaceWrite)
-gtest_add_tests(TARGET TestADIOSDefineVariable)
\ No newline at end of file
+gtest_add_tests(TARGET TestADIOSDefineVariable)
+gtest_add_tests(TARGET TestADIOSDefineAttribute)
\ No newline at end of file
diff --git a/testing/adios2/interface/TestADIOSDefineAttribute.cpp b/testing/adios2/interface/TestADIOSDefineAttribute.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e31a439c625b5b9a054cb3e073438c064d44b864
--- /dev/null
+++ b/testing/adios2/interface/TestADIOSDefineAttribute.cpp
@@ -0,0 +1,591 @@
+#include <cstdint>
+
+#include <iostream>
+#include <stdexcept>
+
+#include <adios2.h>
+
+#include <gtest/gtest.h>
+
+class ADIOSDefineAttributeTest : public ::testing::Test
+{
+public:
+    ADIOSDefineAttributeTest() : adios(true), io(adios.DeclareIO("TestIO")) {}
+
+protected:
+    // virtual void SetUp() { }
+
+    // virtual void TearDown() { }
+
+    adios2::ADIOS adios;
+    adios2::IO &io;
+};
+
+TEST_F(ADIOSDefineAttributeTest, DefineAttributeNameException)
+{
+    auto &attributeString1 =
+        io.DefineAttribute<std::string>("attributeString", "-1");
+
+    EXPECT_THROW(auto &attributeString2 =
+                     io.DefineAttribute<std::string>("attributeString", "0"),
+                 std::invalid_argument);
+
+    EXPECT_THROW(auto &attributeString2 =
+                     io.GetAttribute<std::string>("NoExistingAttribute"),
+                 std::invalid_argument);
+
+    EXPECT_NO_THROW(auto &attributeString3 =
+                        io.GetAttribute<std::string>("attributeString"));
+}
+
+TEST_F(ADIOSDefineAttributeTest, DefineAttributeTypeByValue)
+{
+    // Define ADIOS global value
+    auto &attributeString =
+        io.DefineAttribute<std::string>("attributeString", "-1");
+    auto &attributeChar = io.DefineAttribute<char>("attributeChar", '0');
+    auto &attributeUChar =
+        io.DefineAttribute<unsigned char>("attributeUChar", '1');
+    auto &attributeShort = io.DefineAttribute<short>("attributeShort", 2);
+    auto &attributeUShort =
+        io.DefineAttribute<unsigned short>("attributeUShort", 3);
+    auto &attributeInt = io.DefineAttribute<int>("attributeInt", 4);
+    auto &attributeUInt = io.DefineAttribute<unsigned int>("attributeUInt", 5);
+    auto &attributeLInt = io.DefineAttribute<long int>("attributeLInt", 6);
+    auto &attributeULInt =
+        io.DefineAttribute<unsigned long int>("attributeULInt", 7);
+    auto &attributeLLInt =
+        io.DefineAttribute<long long int>("attributeLLInt", 8);
+    auto &attributeULLInt =
+        io.DefineAttribute<unsigned long long int>("attributeULLInt", 9);
+    auto &attributeFloat = io.DefineAttribute<float>("attributeFloat", 10);
+    auto &attributeDouble = io.DefineAttribute<double>("attributeDouble", 11);
+    auto &attributeLDouble =
+        io.DefineAttribute<long double>("attributeLDouble", 12);
+
+    // Verify the return type is as expected
+    ::testing::StaticAssertTypeEq<decltype(attributeString),
+                                  adios2::Attribute<std::string> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeChar),
+                                  adios2::Attribute<char> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeUChar),
+                                  adios2::Attribute<unsigned char> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeShort),
+                                  adios2::Attribute<short> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeUShort),
+                                  adios2::Attribute<unsigned short> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeInt),
+                                  adios2::Attribute<int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeUInt),
+                                  adios2::Attribute<unsigned int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeLInt),
+                                  adios2::Attribute<long int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeULInt),
+                                  adios2::Attribute<unsigned long int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeLLInt),
+                                  adios2::Attribute<long long int> &>();
+    ::testing::StaticAssertTypeEq<
+        decltype(attributeULLInt),
+        adios2::Attribute<unsigned long long int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeFloat),
+                                  adios2::Attribute<float> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeDouble),
+                                  adios2::Attribute<double> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeLDouble),
+                                  adios2::Attribute<long double> &>();
+
+    // Verify the members are correct
+    ASSERT_EQ(attributeString.m_DataArray, nullptr);
+    EXPECT_EQ(attributeString.m_Name, "attributeString");
+    EXPECT_EQ(attributeString.m_DataValue, "-1");
+    EXPECT_EQ(attributeString.m_Elements, 1);
+    EXPECT_EQ(attributeString.m_Type, "string");
+
+    ASSERT_EQ(attributeChar.m_DataArray, nullptr);
+    EXPECT_EQ(attributeChar.m_Name, "attributeChar");
+    EXPECT_EQ(attributeChar.m_DataValue, '0');
+    EXPECT_EQ(attributeChar.m_Elements, 1);
+    EXPECT_EQ(attributeChar.m_Type, "char");
+
+    ASSERT_EQ(attributeUChar.m_DataArray, nullptr);
+    EXPECT_EQ(attributeUChar.m_Name, "attributeUChar");
+    EXPECT_EQ(attributeUChar.m_DataValue, '1');
+    EXPECT_EQ(attributeUChar.m_Elements, 1);
+    EXPECT_EQ(attributeUChar.m_Type, "unsigned char");
+
+    ASSERT_EQ(attributeShort.m_DataArray, nullptr);
+    EXPECT_EQ(attributeShort.m_Name, "attributeShort");
+    EXPECT_EQ(attributeShort.m_DataValue, 2);
+    EXPECT_EQ(attributeShort.m_Elements, 1);
+    EXPECT_EQ(attributeShort.m_Type, "short");
+
+    ASSERT_EQ(attributeUShort.m_DataArray, nullptr);
+    EXPECT_EQ(attributeUShort.m_Name, "attributeUShort");
+    EXPECT_EQ(attributeUShort.m_DataValue, 3);
+    EXPECT_EQ(attributeUShort.m_Elements, 1);
+    EXPECT_EQ(attributeUShort.m_Type, "unsigned short");
+
+    ASSERT_EQ(attributeInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeInt.m_Name, "attributeInt");
+    EXPECT_EQ(attributeInt.m_DataValue, 4);
+    EXPECT_EQ(attributeInt.m_Elements, 1);
+    EXPECT_EQ(attributeInt.m_Type, "int");
+
+    ASSERT_EQ(attributeUInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeUInt.m_Name, "attributeUInt");
+    EXPECT_EQ(attributeUInt.m_DataValue, 5);
+    EXPECT_EQ(attributeUInt.m_Elements, 1);
+    EXPECT_EQ(attributeUInt.m_Type, "unsigned int");
+
+    ASSERT_EQ(attributeLInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeLInt.m_Name, "attributeLInt");
+    EXPECT_EQ(attributeLInt.m_DataValue, 6);
+    EXPECT_EQ(attributeLInt.m_Elements, 1);
+    EXPECT_EQ(attributeLInt.m_Type, "long int");
+
+    ASSERT_EQ(attributeULInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeULInt.m_Name, "attributeULInt");
+    EXPECT_EQ(attributeULInt.m_DataValue, 7);
+    EXPECT_EQ(attributeULInt.m_Elements, 1);
+    EXPECT_EQ(attributeULInt.m_Type, "unsigned long int");
+
+    ASSERT_EQ(attributeLLInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeLLInt.m_Name, "attributeLLInt");
+    EXPECT_EQ(attributeLLInt.m_DataValue, 8);
+    EXPECT_EQ(attributeLLInt.m_Elements, 1);
+    EXPECT_EQ(attributeLLInt.m_Type, "long long int");
+
+    ASSERT_EQ(attributeULLInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeULLInt.m_Name, "attributeULLInt");
+    EXPECT_EQ(attributeULLInt.m_DataValue, 9);
+    EXPECT_EQ(attributeULLInt.m_Elements, 1);
+    EXPECT_EQ(attributeULLInt.m_Type, "unsigned long long int");
+
+    ASSERT_EQ(attributeFloat.m_DataArray, nullptr);
+    EXPECT_EQ(attributeFloat.m_Name, "attributeFloat");
+    EXPECT_EQ(attributeFloat.m_DataValue, 10);
+    EXPECT_EQ(attributeFloat.m_Elements, 1);
+    EXPECT_EQ(attributeFloat.m_Type, "float");
+
+    ASSERT_EQ(attributeDouble.m_DataArray, nullptr);
+    EXPECT_EQ(attributeDouble.m_Name, "attributeDouble");
+    EXPECT_EQ(attributeDouble.m_DataValue, 11);
+    EXPECT_EQ(attributeDouble.m_Elements, 1);
+    EXPECT_EQ(attributeDouble.m_Type, "double");
+
+    ASSERT_EQ(attributeLDouble.m_DataArray, nullptr);
+    EXPECT_EQ(attributeLDouble.m_Name, "attributeLDouble");
+    EXPECT_EQ(attributeLDouble.m_DataValue, 12);
+    EXPECT_EQ(attributeLDouble.m_Elements, 1);
+    EXPECT_EQ(attributeLDouble.m_Type, "long double");
+}
+
+TEST_F(ADIOSDefineAttributeTest, DefineAttributeTypeByReference)
+{
+    // Define ADIOS global value
+    const std::vector<std::string> vString{"-1", "0", "+1"};
+    const std::vector<char> vChar = {0, 0 + 1, 0 + 2};
+    const std::vector<unsigned char> vUChar = {1, 1 + 1, 1 + 2};
+    const std::vector<short> vShort = {2, 2 + 1, 2 + 2};
+    const std::vector<unsigned short> vUShort = {3, 3 + 1, 3 + 2};
+    const std::vector<int> vInt = {4, 4 + 1, 4 + 2};
+    const std::vector<unsigned int> vUInt = {5, 5 + 1, 5 + 2};
+    const std::vector<long int> vLInt = {6, 6 + 1, 6 + 2};
+    const std::vector<unsigned long int> vULInt = {7, 7 + 1, 7 + 2};
+    const std::vector<long long int> vLLInt = {8, 8 + 1, 8 + 2};
+    const std::vector<unsigned long long int> vULLInt = {9, 9 + 1, 9 + 2};
+    const std::vector<float> vFloat = {10, 10 + 1, 10 + 2};
+    const std::vector<double> vDouble = {11, 11 + 1, 11 + 2};
+    const std::vector<long double> vLDouble = {12, 12 + 1, 12 + 2};
+
+    auto &attributeString =
+        io.DefineAttribute<std::string>("attributeString", vString.data(), 3);
+
+    auto &attributeChar =
+        io.DefineAttribute<char>("attributeChar", vChar.data(), 3);
+    auto &attributeUChar =
+        io.DefineAttribute<unsigned char>("attributeUChar", vUChar.data(), 3);
+    auto &attributeShort =
+        io.DefineAttribute<short>("attributeShort", vShort.data(), 3);
+    auto &attributeUShort = io.DefineAttribute<unsigned short>(
+        "attributeUShort", vUShort.data(), 3);
+    auto &attributeInt =
+        io.DefineAttribute<int>("attributeInt", vInt.data(), 3);
+    auto &attributeUInt =
+        io.DefineAttribute<unsigned int>("attributeUInt", vUInt.data(), 3);
+    auto &attributeLInt =
+        io.DefineAttribute<long int>("attributeLInt", vLInt.data(), 3);
+    auto &attributeULInt = io.DefineAttribute<unsigned long int>(
+        "attributeULInt", vULInt.data(), 3);
+    auto &attributeLLInt =
+        io.DefineAttribute<long long int>("attributeLLInt", vLLInt.data(), 3);
+    auto &attributeULLInt = io.DefineAttribute<unsigned long long int>(
+        "attributeULLInt", vULLInt.data(), 3);
+    auto &attributeFloat =
+        io.DefineAttribute<float>("attributeFloat", vFloat.data(), 3);
+    auto &attributeDouble =
+        io.DefineAttribute<double>("attributeDouble", vDouble.data(), 3);
+    auto &attributeLDouble =
+        io.DefineAttribute<long double>("attributeLDouble", vLDouble.data(), 3);
+
+    // Verify the return type is as expected
+    ::testing::StaticAssertTypeEq<decltype(attributeString),
+                                  adios2::Attribute<std::string> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeChar),
+                                  adios2::Attribute<char> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeUChar),
+                                  adios2::Attribute<unsigned char> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeShort),
+                                  adios2::Attribute<short> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeUShort),
+                                  adios2::Attribute<unsigned short> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeInt),
+                                  adios2::Attribute<int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeUInt),
+                                  adios2::Attribute<unsigned int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeLInt),
+                                  adios2::Attribute<long int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeULInt),
+                                  adios2::Attribute<unsigned long int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeLLInt),
+                                  adios2::Attribute<long long int> &>();
+    ::testing::StaticAssertTypeEq<
+        decltype(attributeULLInt),
+        adios2::Attribute<unsigned long long int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeFloat),
+                                  adios2::Attribute<float> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeDouble),
+                                  adios2::Attribute<double> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeLDouble),
+                                  adios2::Attribute<long double> &>();
+
+    // Verify the dimensions, name, and type are correct
+    ASSERT_NE(attributeString.m_DataArray, nullptr);
+    EXPECT_EQ(attributeString.m_DataArray[0], "-1");
+    EXPECT_EQ(attributeString.m_DataArray[1], "0");
+    EXPECT_EQ(attributeString.m_DataArray[2], "+1");
+    EXPECT_EQ(attributeString.m_Name, "attributeString");
+    ASSERT_EQ(attributeString.m_DataValue.empty(), true);
+    EXPECT_EQ(attributeString.m_Elements, 3);
+    EXPECT_EQ(attributeString.m_Type, "string");
+
+    ASSERT_NE(attributeChar.m_DataArray, nullptr);
+    EXPECT_EQ(attributeChar.m_DataArray[0], 0);
+    EXPECT_EQ(attributeChar.m_DataArray[1], 0 + 1);
+    EXPECT_EQ(attributeChar.m_DataArray[2], 0 + 2);
+    EXPECT_EQ(attributeChar.m_Name, "attributeChar");
+    EXPECT_EQ(attributeChar.m_Elements, 3);
+    EXPECT_EQ(attributeChar.m_Type, "char");
+
+    ASSERT_NE(attributeUChar.m_DataArray, nullptr);
+    EXPECT_EQ(attributeUChar.m_DataArray[0], 1);
+    EXPECT_EQ(attributeUChar.m_DataArray[1], 1 + 1);
+    EXPECT_EQ(attributeUChar.m_DataArray[2], 1 + 2);
+    EXPECT_EQ(attributeUChar.m_Name, "attributeUChar");
+    EXPECT_EQ(attributeUChar.m_Elements, 3);
+    EXPECT_EQ(attributeUChar.m_Type, "unsigned char");
+
+    ASSERT_NE(attributeShort.m_DataArray, nullptr);
+    EXPECT_EQ(attributeShort.m_DataArray[0], 2);
+    EXPECT_EQ(attributeShort.m_DataArray[1], 2 + 1);
+    EXPECT_EQ(attributeShort.m_DataArray[2], 2 + 2);
+    EXPECT_EQ(attributeShort.m_Name, "attributeShort");
+    EXPECT_EQ(attributeShort.m_Elements, 3);
+    EXPECT_EQ(attributeShort.m_Type, "short");
+
+    ASSERT_NE(attributeUShort.m_DataArray, nullptr);
+    EXPECT_EQ(attributeUShort.m_DataArray[0], 3);
+    EXPECT_EQ(attributeUShort.m_DataArray[1], 3 + 1);
+    EXPECT_EQ(attributeUShort.m_DataArray[2], 3 + 2);
+    EXPECT_EQ(attributeUShort.m_Name, "attributeUShort");
+    EXPECT_EQ(attributeUShort.m_Elements, 3);
+    EXPECT_EQ(attributeUShort.m_Type, "unsigned short");
+
+    ASSERT_NE(attributeInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeInt.m_DataArray[0], 4);
+    EXPECT_EQ(attributeInt.m_DataArray[1], 4 + 1);
+    EXPECT_EQ(attributeInt.m_DataArray[2], 4 + 2);
+    EXPECT_EQ(attributeInt.m_Name, "attributeInt");
+    EXPECT_EQ(attributeInt.m_Elements, 3);
+    EXPECT_EQ(attributeInt.m_Type, "int");
+
+    ASSERT_NE(attributeUInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeUInt.m_DataArray[0], 5);
+    EXPECT_EQ(attributeUInt.m_DataArray[1], 5 + 1);
+    EXPECT_EQ(attributeUInt.m_DataArray[2], 5 + 2);
+    EXPECT_EQ(attributeUInt.m_Name, "attributeUInt");
+    EXPECT_EQ(attributeUInt.m_Elements, 3);
+    EXPECT_EQ(attributeUInt.m_Type, "unsigned int");
+
+    ASSERT_NE(attributeLInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeLInt.m_DataArray[0], 6);
+    EXPECT_EQ(attributeLInt.m_DataArray[1], 6 + 1);
+    EXPECT_EQ(attributeLInt.m_DataArray[2], 6 + 2);
+    EXPECT_EQ(attributeLInt.m_Name, "attributeLInt");
+    EXPECT_EQ(attributeLInt.m_Elements, 3);
+    EXPECT_EQ(attributeLInt.m_Type, "long int");
+
+    ASSERT_NE(attributeULInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeULInt.m_DataArray[0], 7);
+    EXPECT_EQ(attributeULInt.m_DataArray[1], 7 + 1);
+    EXPECT_EQ(attributeULInt.m_DataArray[2], 7 + 2);
+    EXPECT_EQ(attributeULInt.m_Name, "attributeULInt");
+    EXPECT_EQ(attributeULInt.m_Elements, 3);
+    EXPECT_EQ(attributeULInt.m_Type, "unsigned long int");
+
+    ASSERT_NE(attributeLLInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeLLInt.m_DataArray[0], 8);
+    EXPECT_EQ(attributeLLInt.m_DataArray[1], 8 + 1);
+    EXPECT_EQ(attributeLLInt.m_DataArray[2], 8 + 2);
+    EXPECT_EQ(attributeLLInt.m_Name, "attributeLLInt");
+    EXPECT_EQ(attributeLLInt.m_Elements, 3);
+    EXPECT_EQ(attributeLLInt.m_Type, "long long int");
+
+    ASSERT_NE(attributeULLInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeULLInt.m_DataArray[0], 9);
+    EXPECT_EQ(attributeULLInt.m_DataArray[1], 9 + 1);
+    EXPECT_EQ(attributeULLInt.m_DataArray[2], 9 + 2);
+    EXPECT_EQ(attributeULLInt.m_Name, "attributeULLInt");
+    EXPECT_EQ(attributeULLInt.m_Elements, 3);
+    EXPECT_EQ(attributeULLInt.m_Type, "unsigned long long int");
+
+    ASSERT_NE(attributeFloat.m_DataArray, nullptr);
+    EXPECT_EQ(attributeFloat.m_DataArray[0], 10);
+    EXPECT_EQ(attributeFloat.m_DataArray[1], 10 + 1);
+    EXPECT_EQ(attributeFloat.m_DataArray[2], 10 + 2);
+    EXPECT_EQ(attributeFloat.m_Name, "attributeFloat");
+    EXPECT_EQ(attributeFloat.m_Elements, 3);
+    EXPECT_EQ(attributeFloat.m_Type, "float");
+
+    ASSERT_NE(attributeDouble.m_DataArray, nullptr);
+    EXPECT_EQ(attributeDouble.m_DataArray[0], 11);
+    EXPECT_EQ(attributeDouble.m_DataArray[1], 11 + 1);
+    EXPECT_EQ(attributeDouble.m_DataArray[2], 11 + 2);
+    EXPECT_EQ(attributeDouble.m_Name, "attributeDouble");
+    EXPECT_EQ(attributeDouble.m_Elements, 3);
+    EXPECT_EQ(attributeDouble.m_Type, "double");
+
+    ASSERT_NE(attributeLDouble.m_DataArray, nullptr);
+    EXPECT_EQ(attributeLDouble.m_DataArray[0], 12);
+    EXPECT_EQ(attributeLDouble.m_DataArray[1], 12 + 1);
+    EXPECT_EQ(attributeLDouble.m_DataArray[2], 12 + 2);
+    EXPECT_EQ(attributeLDouble.m_Name, "attributeLDouble");
+    EXPECT_EQ(attributeLDouble.m_Elements, 3);
+    EXPECT_EQ(attributeLDouble.m_Type, "long double");
+}
+
+TEST_F(ADIOSDefineAttributeTest, GetAttribute)
+{
+    // Define ADIOS global value
+    const std::vector<std::string> vString{"-1", "0", "+1"};
+    const std::vector<char> vChar = {0, 0 + 1, 0 + 2};
+    const std::vector<unsigned char> vUChar = {1, 1 + 1, 1 + 2};
+    const std::vector<short> vShort = {2, 2 + 1, 2 + 2};
+    const std::vector<unsigned short> vUShort = {3, 3 + 1, 3 + 2};
+    const std::vector<int> vInt = {4, 4 + 1, 4 + 2};
+    const std::vector<unsigned int> vUInt = {5, 5 + 1, 5 + 2};
+    const std::vector<long int> vLInt = {6, 6 + 1, 6 + 2};
+    const std::vector<unsigned long int> vULInt = {7, 7 + 1, 7 + 2};
+    const std::vector<long long int> vLLInt = {8, 8 + 1, 8 + 2};
+    const std::vector<unsigned long long int> vULLInt = {9, 9 + 1, 9 + 2};
+    const std::vector<float> vFloat = {10, 10 + 1, 10 + 2};
+    const std::vector<double> vDouble = {11, 11 + 1, 11 + 2};
+    const std::vector<long double> vLDouble = {12, 12 + 1, 12 + 2};
+
+    {
+        io.DefineAttribute<std::string>("attributeString", vString.data(), 3);
+        io.DefineAttribute<char>("attributeChar", vChar.data(), 3);
+        io.DefineAttribute<unsigned char>("attributeUChar", vUChar.data(), 3);
+        io.DefineAttribute<short>("attributeShort", vShort.data(), 3);
+        io.DefineAttribute<unsigned short>("attributeUShort", vUShort.data(),
+                                           3);
+        io.DefineAttribute<int>("attributeInt", vInt.data(), 3);
+        io.DefineAttribute<unsigned int>("attributeUInt", vUInt.data(), 3);
+        io.DefineAttribute<long int>("attributeLInt", vLInt.data(), 3);
+        io.DefineAttribute<unsigned long int>("attributeULInt", vULInt.data(),
+                                              3);
+        io.DefineAttribute<long long int>("attributeLLInt", vLLInt.data(), 3);
+        io.DefineAttribute<unsigned long long int>("attributeULLInt",
+                                                   vULLInt.data(), 3);
+        io.DefineAttribute<float>("attributeFloat", vFloat.data(), 3);
+        io.DefineAttribute<double>("attributeDouble", vDouble.data(), 3);
+        io.DefineAttribute<long double>("attributeLDouble", vLDouble.data(), 3);
+    }
+
+    auto &attributeString = io.GetAttribute<std::string>("attributeString");
+    auto &attributeChar = io.GetAttribute<char>("attributeChar");
+    auto &attributeUChar = io.GetAttribute<unsigned char>("attributeUChar");
+    auto &attributeShort = io.GetAttribute<short>("attributeShort");
+    auto &attributeUShort = io.GetAttribute<unsigned short>("attributeUShort");
+    auto &attributeInt = io.GetAttribute<int>("attributeInt");
+    auto &attributeUInt = io.GetAttribute<unsigned int>("attributeUInt");
+    auto &attributeLInt = io.GetAttribute<long int>("attributeLInt");
+    auto &attributeULInt = io.GetAttribute<unsigned long int>("attributeULInt");
+    auto &attributeLLInt = io.GetAttribute<long long int>("attributeLLInt");
+    auto &attributeULLInt =
+        io.GetAttribute<unsigned long long int>("attributeULLInt");
+    auto &attributeFloat = io.GetAttribute<float>("attributeFloat");
+    auto &attributeDouble = io.GetAttribute<double>("attributeDouble");
+    auto &attributeLDouble = io.GetAttribute<long double>("attributeLDouble");
+
+    // Verify the return type is as expected
+    ::testing::StaticAssertTypeEq<decltype(attributeString),
+                                  adios2::Attribute<std::string> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeChar),
+                                  adios2::Attribute<char> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeUChar),
+                                  adios2::Attribute<unsigned char> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeShort),
+                                  adios2::Attribute<short> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeUShort),
+                                  adios2::Attribute<unsigned short> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeInt),
+                                  adios2::Attribute<int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeUInt),
+                                  adios2::Attribute<unsigned int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeLInt),
+                                  adios2::Attribute<long int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeULInt),
+                                  adios2::Attribute<unsigned long int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeLLInt),
+                                  adios2::Attribute<long long int> &>();
+    ::testing::StaticAssertTypeEq<
+        decltype(attributeULLInt),
+        adios2::Attribute<unsigned long long int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeFloat),
+                                  adios2::Attribute<float> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeDouble),
+                                  adios2::Attribute<double> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeLDouble),
+                                  adios2::Attribute<long double> &>();
+
+    // Verify the dimensions, name, and type are correct
+    ASSERT_NE(attributeString.m_DataArray, nullptr);
+    EXPECT_EQ(attributeString.m_DataArray[0], "-1");
+    EXPECT_EQ(attributeString.m_DataArray[1], "0");
+    EXPECT_EQ(attributeString.m_DataArray[2], "+1");
+    EXPECT_EQ(attributeString.m_Name, "attributeString");
+    ASSERT_EQ(attributeString.m_DataValue.empty(), true);
+    EXPECT_EQ(attributeString.m_Elements, 3);
+    EXPECT_EQ(attributeString.m_Type, "string");
+
+    ASSERT_NE(attributeChar.m_DataArray, nullptr);
+    EXPECT_EQ(attributeChar.m_DataArray[0], 0);
+    EXPECT_EQ(attributeChar.m_DataArray[1], 0 + 1);
+    EXPECT_EQ(attributeChar.m_DataArray[2], 0 + 2);
+    EXPECT_EQ(attributeChar.m_Name, "attributeChar");
+    EXPECT_EQ(attributeChar.m_Elements, 3);
+    EXPECT_EQ(attributeChar.m_Type, "char");
+
+    ASSERT_NE(attributeUChar.m_DataArray, nullptr);
+    EXPECT_EQ(attributeUChar.m_DataArray[0], 1);
+    EXPECT_EQ(attributeUChar.m_DataArray[1], 1 + 1);
+    EXPECT_EQ(attributeUChar.m_DataArray[2], 1 + 2);
+    EXPECT_EQ(attributeUChar.m_Name, "attributeUChar");
+    EXPECT_EQ(attributeUChar.m_Elements, 3);
+    EXPECT_EQ(attributeUChar.m_Type, "unsigned char");
+
+    ASSERT_NE(attributeShort.m_DataArray, nullptr);
+    EXPECT_EQ(attributeShort.m_DataArray[0], 2);
+    EXPECT_EQ(attributeShort.m_DataArray[1], 2 + 1);
+    EXPECT_EQ(attributeShort.m_DataArray[2], 2 + 2);
+    EXPECT_EQ(attributeShort.m_Name, "attributeShort");
+    EXPECT_EQ(attributeShort.m_Elements, 3);
+    EXPECT_EQ(attributeShort.m_Type, "short");
+
+    ASSERT_NE(attributeUShort.m_DataArray, nullptr);
+    EXPECT_EQ(attributeUShort.m_DataArray[0], 3);
+    EXPECT_EQ(attributeUShort.m_DataArray[1], 3 + 1);
+    EXPECT_EQ(attributeUShort.m_DataArray[2], 3 + 2);
+    EXPECT_EQ(attributeUShort.m_Name, "attributeUShort");
+    EXPECT_EQ(attributeUShort.m_Elements, 3);
+    EXPECT_EQ(attributeUShort.m_Type, "unsigned short");
+
+    ASSERT_NE(attributeInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeInt.m_DataArray[0], 4);
+    EXPECT_EQ(attributeInt.m_DataArray[1], 4 + 1);
+    EXPECT_EQ(attributeInt.m_DataArray[2], 4 + 2);
+    EXPECT_EQ(attributeInt.m_Name, "attributeInt");
+    EXPECT_EQ(attributeInt.m_Elements, 3);
+    EXPECT_EQ(attributeInt.m_Type, "int");
+
+    ASSERT_NE(attributeUInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeUInt.m_DataArray[0], 5);
+    EXPECT_EQ(attributeUInt.m_DataArray[1], 5 + 1);
+    EXPECT_EQ(attributeUInt.m_DataArray[2], 5 + 2);
+    EXPECT_EQ(attributeUInt.m_Name, "attributeUInt");
+    EXPECT_EQ(attributeUInt.m_Elements, 3);
+    EXPECT_EQ(attributeUInt.m_Type, "unsigned int");
+
+    ASSERT_NE(attributeLInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeLInt.m_DataArray[0], 6);
+    EXPECT_EQ(attributeLInt.m_DataArray[1], 6 + 1);
+    EXPECT_EQ(attributeLInt.m_DataArray[2], 6 + 2);
+    EXPECT_EQ(attributeLInt.m_Name, "attributeLInt");
+    EXPECT_EQ(attributeLInt.m_Elements, 3);
+    EXPECT_EQ(attributeLInt.m_Type, "long int");
+
+    ASSERT_NE(attributeULInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeULInt.m_DataArray[0], 7);
+    EXPECT_EQ(attributeULInt.m_DataArray[1], 7 + 1);
+    EXPECT_EQ(attributeULInt.m_DataArray[2], 7 + 2);
+    EXPECT_EQ(attributeULInt.m_Name, "attributeULInt");
+    EXPECT_EQ(attributeULInt.m_Elements, 3);
+    EXPECT_EQ(attributeULInt.m_Type, "unsigned long int");
+
+    ASSERT_NE(attributeLLInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeLLInt.m_DataArray[0], 8);
+    EXPECT_EQ(attributeLLInt.m_DataArray[1], 8 + 1);
+    EXPECT_EQ(attributeLLInt.m_DataArray[2], 8 + 2);
+    EXPECT_EQ(attributeLLInt.m_Name, "attributeLLInt");
+    EXPECT_EQ(attributeLLInt.m_Elements, 3);
+    EXPECT_EQ(attributeLLInt.m_Type, "long long int");
+
+    ASSERT_NE(attributeULLInt.m_DataArray, nullptr);
+    EXPECT_EQ(attributeULLInt.m_DataArray[0], 9);
+    EXPECT_EQ(attributeULLInt.m_DataArray[1], 9 + 1);
+    EXPECT_EQ(attributeULLInt.m_DataArray[2], 9 + 2);
+    EXPECT_EQ(attributeULLInt.m_Name, "attributeULLInt");
+    EXPECT_EQ(attributeULLInt.m_Elements, 3);
+    EXPECT_EQ(attributeULLInt.m_Type, "unsigned long long int");
+
+    ASSERT_NE(attributeFloat.m_DataArray, nullptr);
+    EXPECT_EQ(attributeFloat.m_DataArray[0], 10);
+    EXPECT_EQ(attributeFloat.m_DataArray[1], 10 + 1);
+    EXPECT_EQ(attributeFloat.m_DataArray[2], 10 + 2);
+    EXPECT_EQ(attributeFloat.m_Name, "attributeFloat");
+    EXPECT_EQ(attributeFloat.m_Elements, 3);
+    EXPECT_EQ(attributeFloat.m_Type, "float");
+
+    ASSERT_NE(attributeDouble.m_DataArray, nullptr);
+    EXPECT_EQ(attributeDouble.m_DataArray[0], 11);
+    EXPECT_EQ(attributeDouble.m_DataArray[1], 11 + 1);
+    EXPECT_EQ(attributeDouble.m_DataArray[2], 11 + 2);
+    EXPECT_EQ(attributeDouble.m_Name, "attributeDouble");
+    EXPECT_EQ(attributeDouble.m_Elements, 3);
+    EXPECT_EQ(attributeDouble.m_Type, "double");
+
+    ASSERT_NE(attributeLDouble.m_DataArray, nullptr);
+    EXPECT_EQ(attributeLDouble.m_DataArray[0], 12);
+    EXPECT_EQ(attributeLDouble.m_DataArray[1], 12 + 1);
+    EXPECT_EQ(attributeLDouble.m_DataArray[2], 12 + 2);
+    EXPECT_EQ(attributeLDouble.m_Name, "attributeLDouble");
+    EXPECT_EQ(attributeLDouble.m_Elements, 3);
+    EXPECT_EQ(attributeLDouble.m_Type, "long double");
+}
+
+int main(int argc, char **argv)
+{
+#ifdef ADIOS2_HAVE_MPI
+    MPI_Init(nullptr, nullptr);
+#endif
+
+    ::testing::InitGoogleTest(&argc, argv);
+    int result = RUN_ALL_TESTS();
+
+#ifdef ADIOS2_HAVE_MPI
+    MPI_Finalize();
+#endif
+
+    return result;
+}