G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
paraview_example.cpp

This example file showcases many of the different ways you can export data from G+Smo in formats that can be imported in ParaView.

First a basic command line interface is set up so that the input and output files can be specified. Furthermore, the flag -b enables the export of Bezier patches, more details are provided later.

std::string input("surfaces/egg.xml");
std::string output("");
bool bezier=false;
gsCmdLine cmd("Tutorial on ParaView Output");
cmd.addPlainString("filename", "G+Smo input geometry file.", input);
cmd.addString("o", "output", "Base name of the output file", output);
cmd.addSwitch("b","bezier", "Output using Bezier elements", bezier);
try { cmd.getValues(argc,argv); } catch (int rv) { return rv; }

Next the contents of the provided file are parsed and a gsMultiPatch object is read or created using all gsGeometry objects of the file.

gsFileData<> fileData(input);
gsMultiPatch<> mPatch;
if(!fileData.has< gsGeometry<> >())
{
gsWarn << "Input file doesn't contain any geometry.\n";
return EXIT_FAILURE;
}
else if(fileData.has< gsMultiPatch<> >())
{
mPatch = * fileData.getFirst< gsMultiPatch<> >();
gsInfo << "Found a ";
}
else
{
std::vector<gsGeometry<>::uPtr> geo = fileData.getAll< gsGeometry<> >();
// Put all geometries in mPatch
for (index_t g = 0; g < geo.size(); ++g)
{
mPatch.addPatch(give(*geo[g]));
}
gsInfo << "Created a ";
}
gsInfo << mPatch << "\n";
memory::unique_ptr< gsGeometry > uPtr
Unique pointer for gsGeometry.
Definition gsGeometry.h:100
#define index_t
Definition gsConfig.h:32
#define gsWarn
Definition gsDebug.h:50
#define gsInfo
Definition gsDebug.h:43
S give(S &x)
Definition gsMemory.h:266

Output using gsWriteParaview

The first examples of writing data to ParaView formats are showcased in the following snippet. Here, the functions of the gsWriteParaview header are utilised. This contains many functions that can handle the output of many different G+Smo objects. Here a gsMultiPatch object is exported as well as its underlying gsMultiBasis plotted as colours over its physical domain. A gsMatrix containing the geometry's control points is created and exported, as an example of outputting a point set to ParaView. Lastly, gsWriteCsv ( although not contained in gsWriteParaview ) is used to export data for a line plot to ParaView, that could for example be some time dependent data or an evaluation over the edge of some geometry etc.

gsMultiBasis<> mBasis(mPatch);
gsWriteParaview(mPatch, output+"MultiPatch");
gsWriteParaview(mPatch, mBasis, output+"MultiBasis");
gsMatrix<> cPoints = mPatch.coefs().transpose();
gsWriteParaviewPoints(cPoints, output+"Points");
gsInfo << "Wrote " << output+"MultiPatch.pvd, " << output+"MultiPatch_*.vts, "<< output+"MultiBasis.pvd, "<< output+"MultiBasis_*.vts" << "\n\n";
// Fabricate some data to write to csv file and plot
gsMatrix<> lineData(1000, 2);
for (index_t i = 0; i < 1000; ++i)
{
lineData(i,0) = i/1000.0;
lineData(i,1) = std::sin(2*EIGEN_PI*i/1000.0) + 0.25*std::sin(8*EIGEN_PI*i/1000.0);
}
// Export to csv with headers
std::vector<std::string> headers = {"x", "f(x)"};
gsWriteCsv(output + "LineData.csv" ,lineData, headers);
void gsWriteCsv(std::string const &filename, const gsMatrix< T > &matrix, const std::vector< std::string > &headers=std::vector< std::string >())
Export a gsMatrix to a .csv (comma separated values) file.
Definition gsCsv.h:31
void gsWriteParaviewPoints(gsMatrix< T > const &X, gsMatrix< T > const &Y, std::string const &fn)
Export 2D Point set to Paraview file.
Definition gsWriteParaview.hpp:1383

Output via the expression evaluator

G+Smo's gsExprEvaluator is a valuable tool that allows to evaluate arbitrary mathematical expressions or solutions of PDEs that have been formulated using the gsExprAssembler. It can also be used in order to export these evaluations to ParaView as seen here, where the expressions for the measure meas(geoMap) of geometrical map and the outward surface normal usn(geoMap) of the geometry are exported.

gsExprEvaluator<> evaluator;
gsExprEvaluator<>::geometryMap geoMap = evaluator.getMap(mPatch);
evaluator.setIntegrationElements(mBasis);
evaluator.writeParaview( meas(geoMap), geoMap, output+"ExprEval");
evaluator.writeParaview(usn(geoMap), geoMap, output+"ExprEval");
gsInfo << "Wrote " << output+"ExprEval.pvd"<<","<<output+"ExprEval.vts\n\n";

Using gsParaviewCollection

The structure of a typical .pvd file is the following

<?xml version="1.0"?>
<VTKFile type="Collection" version="0.1">
<Collection>
<!-- Time = 0 -->
<DataSet timestep="0" name="Geometry" file="./hertz_pvd/hertz_t0.000000_patch0.vts"/>
<DataSet timestep="0" name="Mesh" file="./hertz_pvd/hertz_t0.000000_mesh1.vtp"/>
<!-- Time = 1 -->
<DataSet timestep="1" name="Geometry" file="./hertz_pvd/hertz_t1.000000_patch0.vts"/>
<DataSet timestep="1" name="Mesh" file="./hertz_pvd/hertz_t1.000000_mesh1.vtp"/>
</Collection>
</VTKFile>

As it is apparent a .pvd file is a collection of references to other files that contain the actual data. The gsParaviewCollection class follows the same logic, as it is used as a handler for exporting multiple fields over the same geometry (e.g. temperature and displacement) and across many time steps.

After the object is initialized and the options are set by the user, a new time step is created by passing a gsMultiPatch object to it. This is done for every time step, since the geometry might change over time ( e.g in structural problems ).

Next, the desired expressions are evaluated and exported using gsParaviewCollection::addField(), this can be some solution field or any other expression. After all desired data has been written gsParaviewCollection::saveTimeStep() must be called, so that all files are closed and properly referenced in the main .pvd file.

These steps can be repeated for all time instants of the solution process and finally gsParaviewCollection::save() must be called.

// Initialize the Paraview Collection with the desired filename of the .pvd file
// and the evaluator that will be used to evaluate the expressions (optionally)
gsParaviewCollection PVCollection(output + "PVCollection.pvd", &evaluator);
// Number of evaluation points per patch
PVCollection.options().setInt("numPoints", 1000);
// Number of decimal points in the output
PVCollection.options().setInt("precision", 5);
// Plot the element mesh and set it's resolution
PVCollection.options().setSwitch("plotElements", false);
PVCollection.options().setInt("plotElements.resolution", -1);
// Plot the control net
PVCollection.options().setSwitch("plotControlNet", false);
// Export the vtk files to a subfolder
PVCollection.options().setSwitch("makeSubfolder", true);
// Name of the subfolder
PVCollection.options().setString("subfolder", "");
// Export in base64 binary format
PVCollection.options().setSwitch("base64", false);
// Create a new timestep (e.g for the initial state of the problem)
// This initialises the appropriate files on disk
PVCollection.newTimeStep(&mPatch);
// Write the measure of the geometry to the files
PVCollection.addField( meas(geoMap), "Measure");
// Write the unit surface normal to the files
PVCollection.addField( usn(geoMap), "Surface normal");
// Save the timestep, so that all files are complete.
PVCollection.saveTimeStep();
// Give ellapsed time as seed for random numbers
std::srand(std::time(0));
// Perturb each patch of the multi patch with random numbers
// This simulates a deformation of the geometry that might
// be the result of a structural simulation
for (index_t p=0; p < mPatch.nPatches(); ++p)
{
mPatch.patch(p).coefs() += gsEigen::MatrixXd::Random(mPatch.patch(p).coefs().rows(), mPatch.patch(p).coefs().cols());
}
// Perform the same steps as before for the deformed geometry
PVCollection.newTimeStep(&mPatch);
PVCollection.addField( meas(geoMap), "Measure");
PVCollection.addField( usn(geoMap), "Surface normal");
PVCollection.saveTimeStep();
// Save the collection, so that the main .pvd file is completed.
PVCollection.save();
gsInfo << "Wrote " << output + "PVCollection.pvd and all files referenced therein."<< "\n\n";

Output of Bezier elements

A few years ago, rendering of rational Bezier cells has been introduced to ParaView. All previous methods of exporting data, rely on sampling the actual spline data at discrete points, and visualising these in ParaView. Althought the number of sampling points and thus the quality of the results is user-specified, higher sampling leads to long evaluation times.

With gsWriteParaviewBezier a Bezier extraction is performed on the geometry via gsMultiPatch::BezierOperator() and then each bezier element is written to ParaView's format. Thus the level of detail can be specified at render-time, so evaluation time is kept relatively low during the solution, and also the resulting files are significantly smaller.

if (bezier)
{
gsWriteParaviewBezier(mPatch, output+"Bezier");
gsInfo << "Wrote " << output+"Bezier" << ".vtu" << ", " << output+"Bezier" << ".pvd\n";
}
void gsWriteParaviewBezier(const gsMultiPatch< T > &mPatch, std::string const &filename, bool ctrlNet=false)
Export a multipatch Geometry (without scalar information) to paraview file using Bezier elements.
Definition gsWriteParaview.hpp:984

Annotated source file

Here is the full file examples/paraview_example.cpp. Clicking on a function or class name will lead you to its reference documentation.

#include <iostream>
#include <gismo.h>
using namespace gismo;
int main(int argc, char* argv[])
{
std::string input("surfaces/egg.xml");
std::string output("");
bool bezier=false;
gsCmdLine cmd("Tutorial on ParaView Output");
cmd.addPlainString("filename", "G+Smo input geometry file.", input);
cmd.addString("o", "output", "Base name of the output file", output);
cmd.addSwitch("b","bezier", "Output using Bezier elements", bezier);
try { cmd.getValues(argc,argv); } catch (int rv) { return rv; }
{
gsWarn << "The file cannot be found!\n";
return EXIT_FAILURE;
}
gsInfo << "Read file \"" << input << "\"\n";
gsFileData<> fileData(input);
if(!fileData.has< gsGeometry<> >())
{
gsWarn << "Input file doesn't contain any geometry.\n";
return EXIT_FAILURE;
}
else if(fileData.has< gsMultiPatch<> >())
{
mPatch = * fileData.getFirst< gsMultiPatch<> >();
gsInfo << "Found a ";
}
else
{
std::vector<gsGeometry<>::uPtr> geo = fileData.getAll< gsGeometry<> >();
// Put all geometries in mPatch
for (index_t g = 0; g < geo.size(); ++g)
{
mPatch.addPatch(give(*geo[g]));
}
gsInfo << "Created a ";
}
gsInfo << mPatch << "\n";
if ( output.empty() )
{
gsInfo << "Call program with option -o <basename> to write data to files\n";
return EXIT_SUCCESS;
}
gsMultiBasis<> mBasis(mPatch);
gsWriteParaview(mPatch, output+"MultiPatch");
gsWriteParaview(mPatch, mBasis, output+"MultiBasis");
gsMatrix<> cPoints = mPatch.coefs().transpose();
gsWriteParaviewPoints(cPoints, output+"Points");
gsInfo << "Wrote " << output+"MultiPatch.pvd, " << output+"MultiPatch_*.vts, "<< output+"MultiBasis.pvd, "<< output+"MultiBasis_*.vts" << "\n\n";
// Fabricate some data to write to csv file and plot
gsMatrix<> lineData(1000, 2);
for (index_t i = 0; i < 1000; ++i)
{
lineData(i,0) = i/1000.0;
lineData(i,1) = std::sin(2*EIGEN_PI*i/1000.0) + 0.25*std::sin(8*EIGEN_PI*i/1000.0);
}
// Export to csv with headers
std::vector<std::string> headers = {"x", "f(x)"};
gsWriteCsv(output + "LineData.csv" ,lineData, headers);
gsExprEvaluator<> evaluator;
gsExprEvaluator<>::geometryMap geoMap = evaluator.getMap(mPatch);
evaluator.setIntegrationElements(mBasis);
evaluator.writeParaview( meas(geoMap), geoMap, output+"ExprEval");
evaluator.writeParaview(usn(geoMap), geoMap, output+"ExprEval");
gsInfo << "Wrote " << output+"ExprEval.pvd"<<","<<output+"ExprEval.vts\n\n";
// Initialize the Paraview Collection with the desired filename of the .pvd file
// and the evaluator that will be used to evaluate the expressions (optionally)
gsParaviewCollection PVCollection(output + "PVCollection.pvd", &evaluator);
// Number of evaluation points per patch
PVCollection.options().setInt("numPoints", 1000);
// Number of decimal points in the output
PVCollection.options().setInt("precision", 5);
// Plot the element mesh and set it's resolution
PVCollection.options().setSwitch("plotElements", false);
PVCollection.options().setInt("plotElements.resolution", -1);
// Plot the control net
PVCollection.options().setSwitch("plotControlNet", false);
// Export the vtk files to a subfolder
PVCollection.options().setSwitch("makeSubfolder", true);
// Name of the subfolder
PVCollection.options().setString("subfolder", "");
// Export in base64 binary format
PVCollection.options().setSwitch("base64", false);
// Create a new timestep (e.g for the initial state of the problem)
// This initialises the appropriate files on disk
PVCollection.newTimeStep(&mPatch);
// Write the measure of the geometry to the files
PVCollection.addField( meas(geoMap), "Measure");
// Write the unit surface normal to the files
PVCollection.addField( usn(geoMap), "Surface normal");
// Save the timestep, so that all files are complete.
PVCollection.saveTimeStep();
// Give ellapsed time as seed for random numbers
std::srand(std::time(0));
// Perturb each patch of the multi patch with random numbers
// This simulates a deformation of the geometry that might
// be the result of a structural simulation
for (index_t p=0; p < mPatch.nPatches(); ++p)
{
mPatch.patch(p).coefs() += gsEigen::MatrixXd::Random(mPatch.patch(p).coefs().rows(), mPatch.patch(p).coefs().cols());
}
// Perform the same steps as before for the deformed geometry
PVCollection.newTimeStep(&mPatch);
PVCollection.addField( meas(geoMap), "Measure");
PVCollection.addField( usn(geoMap), "Surface normal");
PVCollection.saveTimeStep();
// Save the collection, so that the main .pvd file is completed.
PVCollection.save();
gsInfo << "Wrote " << output + "PVCollection.pvd and all files referenced therein."<< "\n\n";
if (bezier)
{
gsWriteParaviewBezier(mPatch, output+"Bezier");
gsInfo << "Wrote " << output+"Bezier" << ".vtu" << ", " << output+"Bezier" << ".pvd\n";
}
return EXIT_SUCCESS;
}
Class for command-line argument parsing.
Definition gsCmdLine.h:57
Generic evaluator of isogeometric expressions.
Definition gsExprEvaluator.h:39
void setIntegrationElements(const gsMultiBasis< T > &mesh)
Sets the domain of integration.
Definition gsExprEvaluator.h:110
void writeParaview(const expr::_expr< E > &expr, geometryMap G, std::string const &fn)
Creates a paraview file named fn containing valies of the.
Definition gsExprEvaluator.h:342
geometryMap getMap(const gsMultiPatch< T > &mp)
Registers mp as an isogeometric geometry map and return a handle to it.
Definition gsExprEvaluator.h:116
This class represents an XML data tree which can be read from or written to a (file) stream.
Definition gsFileData.h:34
static bool fileExists(const std::string &name)
Checks if the file exists.
Definition gsFileManager.cpp:62
Abstract base class representing a geometry map.
Definition gsGeometry.h:93
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
Holds a set of patch-wise bases and their topology information.
Definition gsMultiBasis.h:37
Container class for a set of geometry patches and their topology, that is, the interface connections ...
Definition gsMultiPatch.h:100
index_t addPatch(typename gsGeometry< T >::uPtr g)
Add a patch from a gsGeometry<T>::uPtr.
Definition gsMultiPatch.hpp:211
This class is used to create a Paraview .pvd (collection) file.
Definition gsParaviewCollection.h:77
Main header to be included by clients using the G+Smo library.
EIGEN_STRONG_INLINE meas_expr< T > meas(const gsGeometryMap< T > &G)
The measure of a geometry map.
Definition gsExpressions.h:4555
The G+Smo namespace, containing all definitions for the library.