diff --git a/include/scalfmm/meta/utils.hpp b/include/scalfmm/meta/utils.hpp
index 64ef4cf1537626843794dc3666595f111faad593..1c11fea7e359002f601a4e3c45e60a76583efd0a 100644
--- a/include/scalfmm/meta/utils.hpp
+++ b/include/scalfmm/meta/utils.hpp
@@ -209,7 +209,7 @@ namespace scalfmm::meta
     };
 
     /**
-     * @brief
+     * @brief return the size of the tuple
      *
      * @tparam T
      */
@@ -335,6 +335,24 @@ namespace scalfmm::meta
     {
     };
 
+    /**
+     * @brief contains the size of a patricle type without the vatiables
+     *
+     *  use particle_size_without_variables<ParticleType>::size ;
+     * @tparam PositionType
+     * @tparam PositionDim
+     * @tparam InputsType
+     * @tparam NInputs
+     * @tparam OutputsType
+     * @tparam MOutputs
+     * @tparam Variables
+     */
+    template<typename ParticleType>
+    struct particle_size_without_variables
+    {
+        static constexpr size_t size = ParticleType::dimension + ParticleType::inputs_size + ParticleType::outputs_size;
+    };
+
     /**
      * @brief
      *
diff --git a/include/scalfmm/tools/fma_loader.hpp b/include/scalfmm/tools/fma_loader.hpp
index 6021822b1a0af9494da72d394c66d65ee1fdc339..9957b745cf1d0e3c9ef3dc4ebf07a25e7cd233c7 100644
--- a/include/scalfmm/tools/fma_loader.hpp
+++ b/include/scalfmm/tools/fma_loader.hpp
@@ -730,10 +730,10 @@ namespace scalfmm::io
             }
             std::cout << std::endl << std::flush;
         }
-        template<typename IntType1, typename IntType2>
-        auto writeHeader(const FReal* centerOfBox, const FReal& boxWidth, const IntType1& nbParticles,
-                         const IntType2& dataType, const IntType2& nbDataPerRecord, const IntType2& dimension,
-                         const IntType2& nb_input_values) -> void
+        < template<typename IntType1, typename IntType2>
+          auto writeHeader(const FReal* centerOfBox, const FReal& boxWidth, const IntType1& nbParticles,
+                           const IntType2& dataType, const IntType2& nbDataPerRecord, const IntType2& dimension,
+                           const IntType2& nb_input_values) -> void
         {
             std::array<unsigned int, 4> typeFReal = {
               static_cast<unsigned int>(dataType), static_cast<unsigned int>(nbDataPerRecord),
@@ -916,8 +916,8 @@ namespace scalfmm::io
          * @tparam ContainerType
          * @tparam PointType
          * @tparam ValueType
-         * @param values
-         * @param number_particles
+         * @param values the contnaire of particles
+         * @param number_particles.  number of particles to write
          * @param center
          * @param box_width
          */
@@ -938,6 +938,8 @@ namespace scalfmm::io
             using particles_t = std::array<data_type, nb_elt_per_par>;
             std::vector<particles_t> particles(number_particles);
 
+            std::cout << " WRONG \n";
+
 #pragma omp parallel for shared(particles)
             for(auto it_p = std::begin(values); it_p < std::end(values); ++it_p)
             {
@@ -955,6 +957,89 @@ namespace scalfmm::io
                               nb_elt_per_par, dimension, nb_input_per_par);
             this->writeArrayOfReal(particles.data()->data(), nb_elt_per_par, number_particles);
         }
+        /**
+         * @brief
+         *
+         *  writeDataFrom write all data from the std::vector of particles in fma format
+         *
+         *  How to get automatically double from container
+         *
+         * @tparam ContainerType
+         * @tparam PointType
+         * @tparam ValueType
+         * @param values the vector of particles
+         * @param center the center of the box
+         * @param box_width th width of the box
+         */
+        template<class ParticleType, class PointType, typename ValueType>
+        auto writeDataFrom(std::vector<ParticleType>& values, const PointType& center, const ValueType box_width)
+          -> void
+        {
+            // get the number of elements per particles in the container build with tuples.
+            using particle_type = ParticleType;
+            static constexpr std::size_t dimension = particle_type::dimension_size;
+            static constexpr std::size_t outputs_size = particle_type::outputs_size;
+            static constexpr std::size_t inputs_size = particle_type::inputs_size;
+            constexpr std::size_t nb_elt_per_par = scalfmm::meta ::particle_size_without_variables<particle_type>::size;
+            ///  @todo check for different input and output types (double versus complexe)
+            using data_type = typename particle_type::outputs_value_type;
+            using particles_t = std::array<data_type, nb_elt_per_par>;
+            // Not good output_values are put in input_values
+            constexpr std::size_t nb_input_per_par = particle_type::inputs_size;
+
+            auto number_particles = values.size();
+            // if constexpr(nb_elt_per_par < scalfmm::meta ::tuple_size_v<particle_type>)
+            if constexpr(sizeof(particle_type) > nb_elt_per_par * sizeof(ValueType))
+            //
+            {
+                // std::cout << " I have variables\n";
+                std::vector<particles_t> particles(number_particles);
+#pragma omp parallel for shared(particles, values)
+                for(std::size_t i = 0; i < values.size(); ++i)
+                {
+                    particle_type& p = values[i];
+                    particles_t& a = particles[i];
+                    int k{0};
+
+                    for(auto e: p.position())
+                    {
+                        a[k++] = e;
+                    }
+                    for(auto& e: p.inputs())
+                    {
+                        a[k++] = e;
+                    }
+                    for(auto& e: p.outputs())
+                    {
+                        a[k++] = e;
+                    }
+                }
+                //  write the particles
+                // Here we need to separate input from output variables - no tools yet
+                this->writeHeader(center, box_width, number_particles, static_cast<std::size_t>(sizeof(data_type)),
+                                  nb_elt_per_par, dimension, nb_input_per_par);
+                this->writeArrayOfReal(particles.data()->data(), nb_elt_per_par, number_particles);
+            }
+            else
+            {
+                // std::cout << nb_elt_per_par << " . " << scalfmm::meta ::tuple_size_v<particle_type> << std::endl;
+                this->writeHeader(center, box_width, number_particles, static_cast<std::size_t>(sizeof(data_type)),
+                                  nb_elt_per_par, dimension, nb_input_per_par);
+                // std::cout << " " << &(values[0].position()[0]) << "  " << values.data() << std::endl;
+                auto ptr_data = &(values[0].position()[0]);
+                // int k{0};
+                // for(int i = 0; i < 3; ++i)
+                // {
+                //     std::cout << i << " part " << values[i] << " array ";
+                //     for(int j = 0; j < nb_elt_per_par; ++j, ++k)
+                //     {
+                //         std::cout << ptr_data[k] << " ";
+                //     }
+                //     std::cout << std::endl;
+                // }
+                this->writeArrayOfReal(ptr_data, nb_elt_per_par, number_particles);
+            }
+        }
 
       protected:
         /**