diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5b364d250b321b46dc3092ccf6e2c7562cc3860a..0294206175905f4c407b9926cbb15e8ebeb3f496 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -46,4 +46,5 @@ build_release_static:
 trigger_job:
   stage: trigger
   trigger:
-    project: tadah/tadah.mlip
\ No newline at end of file
+    project: tadah/tadah.mlip
+    branch: $CI_COMMIT_REF_NAME
\ No newline at end of file
diff --git a/include/tadah/mlip/dataset_readers/dataset_reader_selector.h b/include/tadah/mlip/dataset_readers/dataset_reader_selector.h
index 9c4808b416a9469d2b562883faa815a9f0b499bb..a09803ecc532770a28e191be52666ad02897b69a 100644
--- a/include/tadah/mlip/dataset_readers/dataset_reader_selector.h
+++ b/include/tadah/mlip/dataset_readers/dataset_reader_selector.h
@@ -15,11 +15,11 @@ public:
   /**
    * @brief Factory method to create specific DatasetReader objects.
    *
-   * @param type The type of the dataset reader to create.
+   * @param filepath File path to check the content.
    * @param db Reference to a StructureDB object to store parsed data.
    * @return A unique pointer to a DatasetReader object.
    */
-  static std::unique_ptr<DatasetReader> get_reader(const std::string& type, StructureDB& db);
+  static std::unique_ptr<DatasetReader> get_reader(const std::string& filepath, StructureDB& db);
 
   /**
    * @brief Determines the file type based on its content.
diff --git a/include/tadah/mlip/dataset_writers/castep_cell_writer.h b/include/tadah/mlip/dataset_writers/castep_cell_writer.h
new file mode 100644
index 0000000000000000000000000000000000000000..90b799c4c70c0be8ad1748098765c4d9f5d50157
--- /dev/null
+++ b/include/tadah/mlip/dataset_writers/castep_cell_writer.h
@@ -0,0 +1,23 @@
+#ifndef CASTEP_CELL_WRITER_H
+#define CASTEP_CELL_WRITER_H
+
+#include <tadah/mlip/structure.h>
+#include <tadah/mlip/structure_db.h>
+#include <tadah/mlip/dataset_writers/dataset_writer.h>
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <vector>
+#include <stdexcept>
+class CastepCellWriter : public DatasetWriter {
+public:
+  CastepCellWriter(StructureDB& db);
+
+  virtual void write_data(const std::string& filename, const size_t i) override;
+
+};
+
+#endif // CASTEP_CELL_WRITER_H
+
+
diff --git a/include/tadah/mlip/dataset_writers/dataset_writer.h b/include/tadah/mlip/dataset_writers/dataset_writer.h
new file mode 100644
index 0000000000000000000000000000000000000000..91ff858df6c7f77b083a654440ed371e224525be
--- /dev/null
+++ b/include/tadah/mlip/dataset_writers/dataset_writer.h
@@ -0,0 +1,23 @@
+#ifndef DATASET_WRITER_H
+#define DATASET_WRITER_H
+
+#include <tadah/mlip/structure_db.h>
+#include <string>
+#include <vector>
+
+class DatasetWriter {
+  public:
+    virtual ~DatasetWriter() = default;
+
+    virtual void write_data(const std::string& filename, const size_t i) = 0;
+
+    DatasetWriter(StructureDB& db) : stdb(db) {};
+
+    virtual void set_precision(const size_t _p) { p = _p; w = p+6; };
+
+  protected:
+    StructureDB& stdb;
+    double p = 10;  // output precision
+    double w = p+6;  // column width
+};
+#endif // DATASET_WRITER_H
diff --git a/include/tadah/mlip/dataset_writers/dataset_writer_selector.h b/include/tadah/mlip/dataset_writers/dataset_writer_selector.h
new file mode 100644
index 0000000000000000000000000000000000000000..7ea4f85e78bec210bd6ee9a92347e6899026734b
--- /dev/null
+++ b/include/tadah/mlip/dataset_writers/dataset_writer_selector.h
@@ -0,0 +1,15 @@
+#ifndef DATASET_WRITER_SELECTOR_H
+#define DATASET_WRITER_SELECTOR_H
+
+#include <tadah/mlip/structure_db.h>
+#include <tadah/mlip/dataset_writers/dataset_writer.h>
+#include <string>
+#include <memory>
+
+class DatasetWriterSelector {
+  public:
+    static std::unique_ptr<DatasetWriter> get_writer(const std::string& type, StructureDB& db);
+
+};
+
+#endif // DATASET_WRITER_SELECTOR_H
diff --git a/include/tadah/mlip/dataset_writers/lammps_structure_writer.h b/include/tadah/mlip/dataset_writers/lammps_structure_writer.h
new file mode 100644
index 0000000000000000000000000000000000000000..5ee539aea758bf972b33262af856c830ce241846
--- /dev/null
+++ b/include/tadah/mlip/dataset_writers/lammps_structure_writer.h
@@ -0,0 +1,21 @@
+#ifndef LAMMPS_STRUCTURE_WRITER_H
+#define LAMMPS_STRUCTURE_WRITER_H
+
+#include <tadah/mlip/structure.h>
+#include <tadah/mlip/structure_db.h>
+#include <tadah/mlip/dataset_writers/dataset_writer.h>
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <vector>
+#include <stdexcept>
+class LammpsStructureWriter : public DatasetWriter {
+public:
+  LammpsStructureWriter(StructureDB& db);
+
+  virtual void write_data(const std::string& filename, const size_t i) override;
+
+};
+
+#endif // LAMMPS_STRUCTURE_WRITER_H
diff --git a/include/tadah/mlip/dataset_writers/vasp_poscar_writer.h b/include/tadah/mlip/dataset_writers/vasp_poscar_writer.h
new file mode 100644
index 0000000000000000000000000000000000000000..abd58b8b38aa34b1330e0c22703ff4d24c0df9e4
--- /dev/null
+++ b/include/tadah/mlip/dataset_writers/vasp_poscar_writer.h
@@ -0,0 +1,21 @@
+#ifndef VASP_POSCAR_WRITER_H
+#define VASP_POSCAR_WRITER_H
+
+#include <tadah/mlip/structure.h>
+#include <tadah/mlip/structure_db.h>
+#include <tadah/mlip/dataset_writers/dataset_writer.h>
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <vector>
+#include <stdexcept>
+class VaspPoscarWriter : public DatasetWriter {
+public:
+  VaspPoscarWriter(StructureDB& db);
+
+  virtual void write_data(const std::string& filename, const size_t i) override;
+
+};
+
+#endif // VASP_POSCAR_WRITER_H
diff --git a/src/castep_cell_writer.cpp b/src/castep_cell_writer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..144da27ab7715efa0a652dfc27c88ad8745a2d94
--- /dev/null
+++ b/src/castep_cell_writer.cpp
@@ -0,0 +1,53 @@
+#include <tadah/mlip/structure.h>
+#include <tadah/mlip/structure_db.h>
+#include <tadah/mlip/dataset_writers/castep_cell_writer.h>
+
+CastepCellWriter::CastepCellWriter(StructureDB& db) : DatasetWriter(db) {}
+
+void CastepCellWriter::write_data(const std::string& filename, const size_t i) {
+
+  if (i >= stdb.size()) {
+    throw std::out_of_range("Index i is out of range.");
+  }
+    
+  std::ofstream file(filename);
+  if (!file.is_open()) {
+    throw std::runtime_error("Could not open the file: " + filename);
+  }
+
+  const Structure &st = stdb(i);
+
+  // write label
+  file << "# " << st.label << std::endl;
+
+  // write cell
+  file << "%BLOCK LATTICE_CART" << std::endl;
+  file << "ANG" << std::endl;
+  for (int i=0; i<3; ++i) {
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << st.cell(i,0);
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << st.cell(i,1);
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << st.cell(i,2);
+    file << std::endl;
+  }
+  file << "%ENDBLOCK LATTICE_CART" << std::endl;
+
+  file << std::endl;
+
+  file << "%BLOCK POSITIONS_ABS" << std::endl;
+  for (const auto &atom : st) {
+    file << std::right << std::fixed << std::setw(w)
+      << atom.symbol;
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << atom.position(0);
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << atom.position(1);
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << atom.position(2);
+    file << std::endl;
+  }
+  file << "%ENDBLOCK POSITIONS_ABS	" << std::endl;
+  file.close();
+}
diff --git a/src/dataset_writer_selector.cpp b/src/dataset_writer_selector.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c038bedb81b2a239201601371d1b15761a39933d
--- /dev/null
+++ b/src/dataset_writer_selector.cpp
@@ -0,0 +1,20 @@
+#include <tadah/mlip/dataset_writers/dataset_writer_selector.h>
+#include <tadah/mlip/dataset_writers/castep_cell_writer.h>
+#include <tadah/mlip/dataset_writers/vasp_poscar_writer.h>
+#include <tadah/mlip/dataset_writers/lammps_structure_writer.h>
+
+// Factory method implementation
+std::unique_ptr<DatasetWriter> DatasetWriterSelector::get_writer(const std::string& type, StructureDB& db) {
+
+  if (type == "CASTEP") {
+    return std::make_unique<CastepCellWriter>(db);
+  } else if (type == "VASP") {
+    return std::make_unique<VaspPoscarWriter>(db);
+  } else if (type == "LAMMPS") {
+    return std::make_unique<LammpsStructureWriter>(db);
+  } else {
+    std::cerr << "Unknown type! Returning nullptr." << std::endl;
+    return nullptr;
+  }
+
+}
diff --git a/src/lammps_structure_writer.cpp b/src/lammps_structure_writer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e634f3837cb870add5d88fb12e086c10472bbd5e
--- /dev/null
+++ b/src/lammps_structure_writer.cpp
@@ -0,0 +1,88 @@
+#include <tadah/mlip/structure.h>
+#include <tadah/mlip/structure_db.h>
+#include <tadah/mlip/dataset_writers/lammps_structure_writer.h>
+
+LammpsStructureWriter::LammpsStructureWriter(StructureDB& db) : DatasetWriter(db) {}
+
+void LammpsStructureWriter::write_data(const std::string& filename, const size_t i) {
+
+  if (i >= stdb.size()) {
+    throw std::out_of_range("Index i is out of range.");
+  }
+    
+  std::ofstream file(filename);
+  if (!file.is_open()) {
+    throw std::runtime_error("Could not open the file: " + filename);
+  }
+
+  const Structure &st = stdb(i);
+ 
+  // compute number of atoms for a given element
+  const auto &elements = st.get_unique_elements();
+  std::map<std::string, size_t> nelements;
+  std::map<std::string, size_t> type;
+  // Initialize the count for each element
+  for (const auto& element : elements) {
+    nelements[element.symbol] = 0;
+  }
+  // then count...
+  size_t t=0;
+  for (const auto &atom : st) {
+    nelements[atom.symbol]++; 
+    if (type.find(atom.symbol) == type.end()) {
+      type[atom.symbol] = ++t;
+    }
+  }
+
+  // BEGIN OF LAMMPS HEADER
+  file << st.label << std::endl;
+  file << std::endl;
+  file << st.natoms() << " atoms" << std::endl;
+  file << nelements.size() << " atom types" << std::endl;
+  file << std::endl;
+
+  // General triclinic box format
+  std::vector<std::string> abcvec = {"avec", "bvec", "cvec"};
+  for (int i=0; i<3; ++i) {
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << st.cell(i,0);
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << st.cell(i,1);
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << st.cell(i,2)
+      << "    " << abcvec[i];
+    file << std::endl;
+  }
+  file << "    0.0 0.0 0.0 abc origin" << std::endl;
+  // END LAMMPS HEADER
+
+  // BEGIN LAMMPS BODY
+  file << std::endl;
+  file << "Masses" << std::endl;
+  file << std::endl;
+  for (const auto &t: type) {
+    file << t.second << " " << PeriodicTable::get_mass(t.first) << "    # " << t.first << std::endl;
+  }
+
+  file << std::endl;
+  file << "Atoms # atomic" << std::endl;
+  file << std::endl;
+  // atomic: atom-ID [int, 1-Natoms]    atom-type [int, 1-Ntype]    x y z
+
+  size_t idx=1;
+  for (const auto &atom : st) {
+    file << std::right << std::fixed << std::setw(w) << idx;
+    file << std::right << std::fixed << std::setw(w) << type[atom.symbol];
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << atom.position(0);
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << atom.position(1);
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << atom.position(2);
+    file << std::endl;
+    idx++;
+  }
+  // END LAMMPS BODY
+  
+  file.close();
+}
diff --git a/src/vasp_poscar_writer.cpp b/src/vasp_poscar_writer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..33144181c9849ec4779e063c081dd39e8c3592f9
--- /dev/null
+++ b/src/vasp_poscar_writer.cpp
@@ -0,0 +1,79 @@
+#include <tadah/mlip/structure.h>
+#include <tadah/mlip/structure_db.h>
+#include <tadah/mlip/dataset_writers/vasp_poscar_writer.h>
+
+#include <fstream>
+
+VaspPoscarWriter::VaspPoscarWriter(StructureDB& db) : DatasetWriter(db) {}
+
+void VaspPoscarWriter::write_data(const std::string& filename, const size_t i) {
+
+  if (i >= stdb.size()) {
+    throw std::out_of_range("Index i is out of range.");
+  }
+    
+  std::ofstream file(filename);
+  if (!file.is_open()) {
+    throw std::runtime_error("Could not open the file: " + filename);
+  }
+
+  const Structure &st = stdb(i);
+
+  // write scaling factor
+  file << st.label << std::endl;
+  file << "1.0" << std::endl;
+
+  // write cell
+  for (int i=0; i<3; ++i) {
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << st.cell(i,0);
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << st.cell(i,1);
+    file << std::right << std::fixed << std::setw(w)
+      << std::setprecision(p) << st.cell(i,2);
+    file << std::endl;
+  }
+
+
+  // compute number of atoms for a given element
+  const auto &elements = st.get_unique_elements();
+  std::map<std::string, size_t> nelements;
+  // Initialize the count for each element
+  for (const auto& element : elements) {
+    nelements[element.symbol] = 0;
+  }
+  // then count...
+  for (const auto &atom : st) {
+    nelements[atom.symbol]++; 
+  }
+
+  // write elements
+  for (const auto& pair: nelements) {
+    file << pair.first << " ";
+  }
+  file << std::endl;
+
+  // write number of every elements
+  for (const auto& pair: nelements) {
+    file << pair.second << " ";
+  }
+  file << std::endl;
+
+  file << "Cartesian" << std::endl;
+
+  for (const auto& pair: nelements) {
+    for (const auto &atom : st) {
+      if (pair.first == atom.symbol) {
+        file << std::right << std::fixed << std::setw(w)
+          << std::setprecision(p) << atom.position(0);
+        file << std::right << std::fixed << std::setw(w)
+          << std::setprecision(p) << atom.position(1);
+        file << std::right << std::fixed << std::setw(w)
+          << std::setprecision(p) << atom.position(2);
+        file << std::endl;
+      }
+    }
+  }
+
+  file.close();
+}