Tutorial: My First VTFx

This tutorial shows how to write your own VTFx file from scratch.
This tutorial describes how to create a minimal VTFx file containing one database with a single cube, one state (i.e. time step) and one case.
Create and configure the File instance
Create the file instance and specify the output filename and the file settings for this file.
To keep it simple, just specify an application name and vendor name. See FileSettings
for other available settings.
// Create the VTFx file
// -------------------------------------------------------------------------
cee::PtrRef<cee::vtfx::File> file = new cee::vtfx::File;
// Create VTFx file settings struct
cee::vtfx::FileSettings fileSettings;
fileSettings.applicationName = "VTFx: VTFxMinimal";
fileSettings.vendorName = "My Company AS";
// Let the API create the VTFx file
const cee::Str fileName = "ExampleMinimal.vtfx";
if (!file->create(fileName, fileSettings))
{
return EXIT_FAILURE;
}
Create database and case
The database collects all data blocks (NodeBlock
,
ElementBlock
, GeometryBlock
, …) for a file.
The case represents one configuration of the visualization of a VTFx database. Several cases can use the same database
but with a different set of properties describing the actual visualization.
A cee::vtfx::File
can have several databases and cases, but for this simple example we will only create one
database (with id = 1) and one case (with id = 1) referencing the database. The database and case take the file instance
as a parameter upon construction.
// Create a single database (could have many)
cee::PtrRef<cee::vtfx::Database> database = new cee::vtfx::Database(file.get(), "Only Database", 1, cee::vtfx::Database::SIMULATION_TYPE_STRUCTURAL, cee::vtfx::Database::SOLUTION_TYPE_TRANSIENT, "Database description"); // database id 1
// Create a single case (could have many)
cee::PtrRef<cee::vtfx::Case> singleCase = new cee::vtfx::Case(file.get(), "Only Case", 1, 1); // case id 1 using database with id 1
Add nodes
The node block is a block that stores node coordinates. Node ids can also be specified, but for this simple tutorial, we will only be using node indexes.
Create the node block (with id = 1) with withNodeIds set to false.
This part is a cube so we add eight nodes.
The node coordinates can either be added as an array of cee::Vec3f
or as an interleaved
float array (x,y,z,x,y,z,x,y,z,…).
When done, we write this block to the database instance.
// Create the node block
cee::PtrRef<cee::vtfx::NodeBlock> nodeBlock = new cee::vtfx::NodeBlock(1, false); // node block id 1, not using node ids
// Set the node data (Note: The VTFx component expects interleaved node coordinates (xyzxyzxyz...))
const float NODES_PART[] =
{
0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f
};
std::vector<float> nodesPart(NODES_PART, NODES_PART + sizeof(NODES_PART) / sizeof(NODES_PART[0]));
if (!nodeBlock->setNodes(nodesPart))
{
return EXIT_FAILURE;
}
Add elements
An element block describes the connectivity table for the elements. The nodes in the table can be referred to by index or id.
First we create an element block (with id = 1). Since we created the node block above without
using ids, we will not reference nodes by ids so we set referNodesByIds in the constructor to false.
The node block used to define the elements is specified by
setNodeBlockId(1)
which is the node block id.
This tutorial only has one hexahedron element. An element is described by the nodes that define it.
For a single hexahedron element, it takes eight nodes.
(See ElementBlock::ElementType
or a full list of supported element types.)
// Create the element block
cee::PtrRef<cee::vtfx::ElementBlock> elementBlock = new cee::vtfx::ElementBlock(1, false, false); // element block id 1, not using element ids, referring nodes by index
elementBlock->setNodeBlockId(1); // Use node block with id = 1
// Set the element data
const int CONNECTS_PART[] =
{
0, 1, 2, 3, 4, 5, 6, 7
};
std::vector<int> elementNodes(CONNECTS_PART, CONNECTS_PART + sizeof(CONNECTS_PART) / sizeof(CONNECTS_PART[0]));
if (!elementBlock->addElements(cee::vtfx::ElementBlock::HEXAHEDRONS, elementNodes))
{
return EXIT_FAILURE;
}
// Write the element block
if (!database->writeBlock(elementBlock.get()))
{
return EXIT_FAILURE;
}
Add geometry
The geometry block bundles all elements contained in this geometry.
First, create the geometry block. Each database can - and must - have only one geometry block.
In the GeometryBlock
constructor, set number of geometries per state to 1. In most
cases, a single geometry containing all element blocks will fulfill your needs.
Add the elements to the geometry block by using the element block ids. For this file, there’s only one element block (with id = 1), itself containing a single element. Specify an id (for instance, id = 1) for the part that uses this element block. A part can only contain one element block.
You also need to add meta data about the geometry using a geometry info block.
Create the geometry info block and set the geometries per state to 1 (same as for the
GeometryBlock
above).
Add a meta data for a part specifying part id used in the geometry block and a part name.
// Create geometry block
cee::PtrRef<cee::vtfx::GeometryBlock> geoBlock = new cee::vtfx::GeometryBlock(1); // Only one geometry per state
size_t geoIndex = 0;
int partId = 1;
// Set to use element block with id 1
if (!geoBlock->addElementBlock(geoIndex, 1, partId)) // Element block with id = 1
{
return EXIT_FAILURE;
}
// Write the geometry block
if (!database->writeBlock(geoBlock.get()))
{
return EXIT_FAILURE;
}
// Create geometry info block
cee::PtrRef<cee::vtfx::GeometryInfoBlock> infoBlock = new cee::vtfx::GeometryInfoBlock(1); // Only one geometry per state
infoBlock->addPartInfo(geoIndex, partId, cee::Str("Only part"));
// Write the geometry info block
if (!database->writeBlock(infoBlock.get()))
{
return EXIT_FAILURE;
}
Add a state
Create a StateInfoBlock
containing the meta data of states. There must be only one
state info block in each database.
Add meta data for single state with id = 1 and give it a suitable name, reference value and define the reference value type.
// Create state info block
cee::PtrRef<cee::vtfx::StateInfoBlock> stepInfo = new cee::vtfx::StateInfoBlock;
if (!stepInfo->addStateInfo(1, "Only step", 42.0f, cee::vtfx::StateInfoBlock::TIME))
{
return EXIT_FAILURE;
}
// Write the state info block
if (!database->writeBlock(stepInfo.get()))
{
return EXIT_FAILURE;
}
Finally, close the file and it will be written to disk.
// Finally close the file
if (!file->close())
{
return EXIT_FAILURE;
}
If any error occurred when writing the file, a log message should have been created. Check the log for further information on what went wrong. See the Logging page for more information on how to set up logging.
See the complete source code here: