No Matches
Exporting data

In this tutorial, we will create an exporter for the following XYZ format: The 1st line: the number of atoms in the file. The 2nd line: arbitraty header line. Next lines contain information on atoms in the following format (coordinates are in angstroms): element_symbol x-coordinate y-coordinate z-coordinate.

Example of the format:

C -6.644 9.967 5.557
C -7.934 9.831 4.773
C -7.934 10.816 3.617
C -8.098 8.407 4.266
N -7.404 9.603 7.84
C -6.46 9.161 6.834
C -5.09 9.488 7.383
O -5.008 10.375 8.245
H -8.382 9.481 7.521
H -7.182 10.599 8.021
This class is the main interface.
Definition: SAMSON.hpp:66

Note: SAMSON already has an XYZ Exporter which is installed by default, that's why we are actually going to read files with a exyz extension, even though the contents will still correspond to the xyz format.

The source code for an Extension created in this tutorial can be found at https://github.com/1A-OneAngstrom/SAMSON-Developer-Tutorials.

Generating an Extension

We will start by creating a new SAMSON Extension called EXYZ thanks to the SAMSON Extension generator (please, refer to the SAMSON Extension generator tutorial for a reminder on how to use it):

The SAMSON Extension generator generates an exporter class (derived from the SBIFileExporter class) and a GUI class that implements the user interface of the exporter and is derived from the SBGFileExporter class.

Exporting into a file

In SAMSON, an exporter is created by programming three functions in the exporter class:

Let's open the SEEXYZExporter.cpp file and implement these functions.

Modify the getExtension function to return the extension of the exporter (exyz) as follows:

std::string SEEXYZExporter::getExtension() const {
return std::string("exyz");

Modify the getFilter function to return the filter of the exporter as follows (it should be in the Qt format):

std::string SEEXYZExporter::getFilter() const {
return std::string("EXYZ format (*.exyz)");

We now have to code the exportToFile function to export atoms into a exyz file. To achieve this, we are going to use fstream to create and write into a file, the SAMSON class to get atoms from the active document, and several structural classes. For that, include the following headers in the file:

#include <fstream>
#include "SAMSON.hpp"
#include "SBStructuralModel.hpp"
#include "SBAtom.hpp"

Let's now code inside the exportToFile function:

bool SEEXYZExporter::exportToFile(const SBNodeIndexer& nodeIndexer, const std::string& fileName, const std::unordered_map<std::string, SBValue>* parameters)
This class describes a node indexer.
Definition: SBDDataGraphNodeIndexer.hpp:21

First, we find all atoms in the nodes that were passed to the exportToFile function:

// retrieve all atoms
SBNodeIndexer atomIndexer;
SB_FOR(SBNode* node, nodeIndexer) node->getNodes(atomIndexer, SBNode::IsType(SBNode::Atom));
A macro to easily write for loops involving containers.
Definition: SBCContainerFor.hpp:83
This node predicate compares the node type with a given type.
Definition: SBDDataGraphNode.hpp:512
This class is the base class to describe a node in the data graph.
Definition: SBDDataGraphNode.hpp:33
@ Atom
Definition: SBDDataGraphNode.hpp:67

Recall that SBNode::IsType(SBNode::Atom) is a predicate, passed to the getNodes function, that returns true for nodes that are atoms.

If the user saves data via File > Save or File > Save as... it will export all atoms from the active document, if the user saves data via File > Save selection as... it will export all atoms from the selection in the active document.

Then, we create the file and write its header:

// create file
ofstream file;
// write the header
file << atomIndexer.size() << std::endl; // number of atoms
file << "SAMSON Export" << std::endl;
unsigned int size() const
Returns the number of indexed objects.
Definition: SBCContainerIndexer.hpp:481

In this tutorial, for simplicity we do not check for errors during the creation and writing of the file.

And we then write the description of each atom to the file:

// write atoms
for (unsigned int i = 0; i < atomIndexer.size(); i++) {
SBAtom* currentAtom = static_cast<SBAtom*>(atomIndexer[i]);
SBPosition3 const& currentAtomPosition = currentAtom->getPosition();
file << SAMSON::getElementSymbol(currentAtom->getElementType())
<< " " << SBQuantity::angstrom(currentAtomPosition.v[0]).getValue()
<< " " << SBQuantity::angstrom(currentAtomPosition.v[1]).getValue()
<< " " << SBQuantity::angstrom(currentAtomPosition.v[2]).getValue() << "\n";
static std::string getElementSymbol(SBMElement::Type element)
Returns the symbol of the periodic table element corresponding to a given type.
Definition: SAMSON.cpp:830
SBDQuantityType< SBDQuantityUnitType< SBUnitSystemSI, -10, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 > > angstrom
The angstrom type.
Definition: SBDQuantity.hpp:81
Quantity v[3]
The components of the physical vector.
Definition: SBDTypePhysicalVector3.hpp:768
This class describes an atom in a structural model.
Definition: SBMStructuralModelNodeAtom.hpp:34
SBPosition3 const & getPosition() const
Returns the atom's position.
Definition: SBMStructuralModelNodeAtom.cpp:330
virtual SBElement::Type getElementType() const
Returns the atom's element type.
Definition: SBMStructuralModelNodeAtom.cpp:1768

Finally, we close the file and we signal that everything went fine (at least we believe so, since we didn’t test for errors in this tutorial):

// close the file
return true;

That is it. You can now export into exyz format.

If you want for the Exporter to get some parameters/options from the user, please check out to the Importer tutorial: Getting parameters, if not then you can simply disable the options window by replacing the constructor and destructor of SEEXYZExporter as follows:

SEEXYZExporter::SEEXYZExporter() {
// remove the options window
propertyDialog = nullptr;
SEEXYZExporter::~SEEXYZExporter() {