mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
ParaView-5.0.1: Added the source-tree to ThirdParty-dev and patched as described in the README file
Resolves bug-report http://bugs.openfoam.org/view.php?id=2098
This commit is contained in:
75
ParaView-5.0.1/Examples/BuildExamples.cmake
Normal file
75
ParaView-5.0.1/Examples/BuildExamples.cmake
Normal file
@ -0,0 +1,75 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# Builds the examples as a separate project using a custom target.
|
||||
# This is included in ParaView/CMakeLists.txt to build examples as a separate
|
||||
# project.
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Make sure it uses the same build configuration as ParaView.
|
||||
if (CMAKE_CONFIGURATION_TYPES)
|
||||
set(build_config_arg -C "${CMAKE_CFG_INTDIR}")
|
||||
else()
|
||||
set(build_config_arg)
|
||||
endif()
|
||||
|
||||
set (extra_params)
|
||||
foreach (flag CMAKE_C_FLAGS_DEBUG
|
||||
CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL
|
||||
CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_CXX_FLAGS_DEBUG
|
||||
CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL
|
||||
CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
if (${${flag}})
|
||||
set (extra_params ${extra_params}
|
||||
-D${flag}:STRING=${${flag}})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set (examples_dependencies
|
||||
vtkPVServerManagerApplication
|
||||
vtkPVServerManagerApplicationCS)
|
||||
if (PARAVIEW_BUILD_QT_GUI)
|
||||
list (APPEND examples_dependencies pqApplicationComponents)
|
||||
endif()
|
||||
|
||||
set(ENABLE_CATALYST OFF)
|
||||
if (PARAVIEW_ENABLE_PYTHON AND PARAVIEW_USE_MPI AND PARAVIEW_ENABLE_CATALYST AND NOT WIN32)
|
||||
list (APPEND examples_dependencies vtkPVPythonCatalyst)
|
||||
set (ENABLE_CATALYST ON)
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${ParaView_BINARY_DIR}/ParaViewExamples.done"
|
||||
COMMAND ${CMAKE_CTEST_COMMAND}
|
||||
ARGS ${build_config_arg}
|
||||
--build-and-test
|
||||
${ParaView_SOURCE_DIR}/Examples
|
||||
${ParaView_BINARY_DIR}/Examples/All
|
||||
--build-noclean
|
||||
--build-two-config
|
||||
--build-project ParaViewExamples
|
||||
--build-generator ${CMAKE_GENERATOR}
|
||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
||||
--build-options -DParaView_DIR:PATH=${ParaView_BINARY_DIR}
|
||||
-DPARAVIEW_QT_VERSION:STRING=${PARAVIEW_QT_VERSION}
|
||||
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
|
||||
-DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
|
||||
-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}
|
||||
-DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
|
||||
-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
|
||||
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY:PATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
|
||||
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
|
||||
-DBUILD_TESTING:BOOL=${BUILD_TESTING}
|
||||
-DPARAVIEW_TEST_OUTPUT_DIR:PATH=${PARAVIEW_TEST_OUTPUT_DIR}
|
||||
-DENABLE_CATALYST:BOOL=${ENABLE_CATALYST}
|
||||
${extra_params}
|
||||
--no-warn-unused-cli
|
||||
COMMAND ${CMAKE_COMMAND} -E touch
|
||||
"${ParaView_BINARY_DIR}/ParaViewExamples.done"
|
||||
COMMENT "Build examples as a separate project"
|
||||
DEPENDS ${examples_dependencies}
|
||||
)
|
||||
# Add custom target to ensure that the examples get built.
|
||||
add_custom_target(ParaViewExamples ALL DEPENDS
|
||||
"${ParaView_BINARY_DIR}/ParaViewExamples.done")
|
||||
51
ParaView-5.0.1/Examples/CMakeLists.txt
Normal file
51
ParaView-5.0.1/Examples/CMakeLists.txt
Normal file
@ -0,0 +1,51 @@
|
||||
cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)
|
||||
project(ParaViewExamples)
|
||||
|
||||
option(ENABLE_CATALYST "Enable Catalyst Examples" OFF)
|
||||
|
||||
set(paraview_components)
|
||||
if (ENABLE_CATALYST)
|
||||
list(APPEND paraview_components vtkPVPythonCatalyst)
|
||||
endif ()
|
||||
|
||||
if (paraview_components)
|
||||
list(INSERT paraview_components 0 COMPONENTS)
|
||||
endif ()
|
||||
find_package(ParaView REQUIRED ${paraview_components})
|
||||
include(${PARAVIEW_USE_FILE})
|
||||
|
||||
add_subdirectory(Plugins/Filter)
|
||||
add_subdirectory(Plugins/ParametricSource)
|
||||
add_subdirectory(Plugins/SMProxy)
|
||||
add_subdirectory(Plugins/Representation)
|
||||
add_subdirectory(Plugins/HiddenLinesRemoval)
|
||||
|
||||
if (ENABLE_CATALYST)
|
||||
add_subdirectory(Catalyst)
|
||||
endif ()
|
||||
|
||||
if (PARAVIEW_BUILD_QT_GUI)
|
||||
add_subdirectory(Plugins/Autostart)
|
||||
add_subdirectory(Plugins/DockWidget)
|
||||
add_subdirectory(Plugins/GUIToolBar)
|
||||
add_subdirectory(Plugins/PropertyWidgets)
|
||||
add_subdirectory(Plugins/Reader)
|
||||
add_subdirectory(Plugins/ReaderXMLOnly)
|
||||
add_subdirectory(Plugins/RenderPassViews)
|
||||
# TODO: update this plugin to use the pipeline controller instead.
|
||||
#add_subdirectory(Plugins/RepresentationBehavior)
|
||||
add_subdirectory(Plugins/SourceToolbar)
|
||||
add_subdirectory(Plugins/Writer)
|
||||
|
||||
add_subdirectory(CustomApplications/Clone1)
|
||||
add_subdirectory(CustomApplications/Clone2)
|
||||
add_subdirectory(CustomApplications/Demo0)
|
||||
add_subdirectory(CustomApplications/Demo1)
|
||||
add_subdirectory(CustomApplications/MultiServerClient)
|
||||
add_subdirectory(CustomApplications/Spreadsheet)
|
||||
add_subdirectory(CustomApplications/ParticlesViewer)
|
||||
endif()
|
||||
|
||||
if (TARGET vtkIOVisItBridge)
|
||||
# add_subdirectory(Plugins/VisItReader)
|
||||
endif ()
|
||||
40
ParaView-5.0.1/Examples/Catalyst/CFullExample/CMakeLists.txt
Normal file
40
ParaView-5.0.1/Examples/Catalyst/CFullExample/CMakeLists.txt
Normal file
@ -0,0 +1,40 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(CatalystCFullExample C)
|
||||
|
||||
set(USE_CATALYST ON CACHE BOOL "Link the simulator with Catalyst")
|
||||
if(USE_CATALYST)
|
||||
# we only need C++ compilers if we're building the Adaptor
|
||||
enable_language(CXX)
|
||||
find_package(ParaView 4.1 REQUIRED COMPONENTS vtkPVPythonCatalyst)
|
||||
include("${PARAVIEW_USE_FILE}")
|
||||
set(Adaptor_SRCS
|
||||
FEAdaptor.cxx
|
||||
)
|
||||
add_library(CFullExampleAdaptor ${Adaptor_SRCS})
|
||||
target_link_libraries(CFullExampleAdaptor vtkPVPythonCatalyst)
|
||||
add_definitions("-DUSE_CATALYST")
|
||||
if(NOT PARAVIEW_USE_MPI)
|
||||
message(SEND_ERROR "ParaView must be built with MPI enabled")
|
||||
endif()
|
||||
else()
|
||||
find_package(MPI REQUIRED)
|
||||
include_directories(${MPI_C_INCLUDE_PATH})
|
||||
endif()
|
||||
|
||||
add_executable(CFullExample FEDriver.c FEDataStructures.c)
|
||||
if(USE_CATALYST)
|
||||
target_link_libraries(CFullExample LINK_PRIVATE CFullExampleAdaptor)
|
||||
include(vtkModuleMacros)
|
||||
include(vtkMPI)
|
||||
vtk_mpi_link(CFullExample)
|
||||
else()
|
||||
target_link_libraries(CFullExample LINK_PRIVATE ${MPI_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_test(NAME CFullExampleTest COMMAND CFullExample ${CMAKE_CURRENT_SOURCE_DIR}/SampleScripts/feslicescript.py)
|
||||
set_tests_properties(CFullExampleTest PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
endif()
|
||||
152
ParaView-5.0.1/Examples/Catalyst/CFullExample/FEAdaptor.cxx
Normal file
152
ParaView-5.0.1/Examples/Catalyst/CFullExample/FEAdaptor.cxx
Normal file
@ -0,0 +1,152 @@
|
||||
#include <iostream>
|
||||
#include "FEAdaptor.h"
|
||||
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkCellType.h>
|
||||
#include <vtkCPDataDescription.h>
|
||||
#include <vtkCPInputDataDescription.h>
|
||||
#include <vtkCPProcessor.h>
|
||||
#include <vtkCPPythonScriptPipeline.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkFloatArray.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkPoints.h>
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
vtkCPProcessor* Processor = NULL;
|
||||
vtkUnstructuredGrid* VTKGrid;
|
||||
|
||||
void BuildVTKGrid(unsigned int numberOfPoints, double* pointsData,
|
||||
unsigned int numberOfCells, unsigned int* cellsData)
|
||||
{
|
||||
// create the points information
|
||||
vtkNew<vtkDoubleArray> pointArray;
|
||||
pointArray->SetNumberOfComponents(3);
|
||||
pointArray->SetArray(pointsData, static_cast<vtkIdType>(numberOfPoints*3), 1);
|
||||
vtkNew<vtkPoints> points;
|
||||
points->SetData(pointArray.GetPointer());
|
||||
VTKGrid->SetPoints(points.GetPointer());
|
||||
|
||||
// create the cells
|
||||
VTKGrid->Allocate(static_cast<vtkIdType>(numberOfCells*9));
|
||||
for(unsigned int cell=0;cell<numberOfCells;cell++)
|
||||
{
|
||||
unsigned int* cellPoints = cellsData+8*cell;
|
||||
vtkIdType tmp[8] = {cellPoints[0], cellPoints[1], cellPoints[2], cellPoints[3],
|
||||
cellPoints[4], cellPoints[5], cellPoints[6], cellPoints[7]};
|
||||
VTKGrid->InsertNextCell(VTK_HEXAHEDRON, 8, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateVTKAttributes(unsigned int numberOfPoints, double* velocityData,
|
||||
unsigned int numberOfCells, float* pressureData)
|
||||
{
|
||||
if(VTKGrid->GetPointData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// velocity array
|
||||
vtkNew<vtkDoubleArray> velocity;
|
||||
velocity->SetName("velocity");
|
||||
velocity->SetNumberOfComponents(3);
|
||||
velocity->SetNumberOfTuples(static_cast<vtkIdType>(numberOfPoints));
|
||||
VTKGrid->GetPointData()->AddArray(velocity.GetPointer());
|
||||
}
|
||||
if(VTKGrid->GetCellData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// pressure array
|
||||
vtkNew<vtkFloatArray> pressure;
|
||||
pressure->SetName("pressure");
|
||||
pressure->SetNumberOfComponents(1);
|
||||
VTKGrid->GetCellData()->AddArray(pressure.GetPointer());
|
||||
}
|
||||
vtkDoubleArray* velocity = vtkDoubleArray::SafeDownCast(
|
||||
VTKGrid->GetPointData()->GetArray("velocity"));
|
||||
// The velocity array is ordered as vx0,vx1,vx2,..,vy0,vy1,vy2,..,vz0,vz1,vz2,..
|
||||
// so we need to create a full copy of it with VTK's ordering of
|
||||
// vx0,vy0,vz0,vx1,vy1,vz1,..
|
||||
for(unsigned int i=0;i<numberOfPoints;i++)
|
||||
{
|
||||
double values[3] = {velocityData[i], velocityData[i+numberOfPoints],
|
||||
velocityData[i+2*numberOfPoints]};
|
||||
velocity->SetTupleValue(i, values);
|
||||
}
|
||||
|
||||
vtkFloatArray* pressure = vtkFloatArray::SafeDownCast(
|
||||
VTKGrid->GetCellData()->GetArray("pressure"));
|
||||
// The pressure array is a scalar array so we can reuse
|
||||
// memory as long as we ordered the points properly.
|
||||
pressure->SetArray(pressureData, static_cast<vtkIdType>(numberOfCells), 1);
|
||||
}
|
||||
|
||||
void BuildVTKDataStructures(unsigned int numberOfPoints, double* points, double* velocity,
|
||||
unsigned int numberOfCells, unsigned int* cells, float* pressure)
|
||||
{
|
||||
if(VTKGrid == NULL)
|
||||
{
|
||||
// The grid structure isn't changing so we only build it
|
||||
// the first time it's needed. If we needed the memory
|
||||
// we could delete it and rebuild as necessary.
|
||||
VTKGrid = vtkUnstructuredGrid::New();
|
||||
BuildVTKGrid(numberOfPoints, points, numberOfCells, cells);
|
||||
}
|
||||
UpdateVTKAttributes(numberOfPoints, velocity, numberOfCells, pressure);
|
||||
}
|
||||
}
|
||||
|
||||
void CatalystInitialize(int numScripts, char* scripts[])
|
||||
{
|
||||
if(Processor == NULL)
|
||||
{
|
||||
Processor = vtkCPProcessor::New();
|
||||
Processor->Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
Processor->RemoveAllPipelines();
|
||||
}
|
||||
for(int i=1;i<numScripts;i++)
|
||||
{
|
||||
vtkNew<vtkCPPythonScriptPipeline> pipeline;
|
||||
pipeline->Initialize(scripts[i]);
|
||||
Processor->AddPipeline(pipeline.GetPointer());
|
||||
}
|
||||
}
|
||||
|
||||
void CatalystFinalize()
|
||||
{
|
||||
if(Processor)
|
||||
{
|
||||
Processor->Delete();
|
||||
Processor = NULL;
|
||||
}
|
||||
if(VTKGrid)
|
||||
{
|
||||
VTKGrid->Delete();
|
||||
VTKGrid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CatalystCoProcess(unsigned int numberOfPoints, double* pointsData,
|
||||
unsigned int numberOfCells, unsigned int* cellsData,
|
||||
double* velocityData, float* pressureData, double time,
|
||||
unsigned int timeStep, int lastTimeStep)
|
||||
{
|
||||
vtkNew<vtkCPDataDescription> dataDescription;
|
||||
dataDescription->AddInput("input");
|
||||
dataDescription->SetTimeData(time, timeStep);
|
||||
if(lastTimeStep == true)
|
||||
{
|
||||
// assume that we want to all the pipelines to execute if it
|
||||
// is the last time step.
|
||||
dataDescription->ForceOutputOn();
|
||||
}
|
||||
if(Processor->RequestDataDescription(dataDescription.GetPointer()) != 0)
|
||||
{
|
||||
BuildVTKDataStructures(numberOfPoints, pointsData, velocityData,
|
||||
numberOfCells, cellsData, pressureData);
|
||||
dataDescription->GetInputDescriptionByName("input")->SetGrid(VTKGrid);
|
||||
Processor->CoProcess(dataDescription.GetPointer());
|
||||
}
|
||||
}
|
||||
19
ParaView-5.0.1/Examples/Catalyst/CFullExample/FEAdaptor.h
Normal file
19
ParaView-5.0.1/Examples/Catalyst/CFullExample/FEAdaptor.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef FEADAPTOR_HEADER
|
||||
#define FEADAPTOR_HEADER
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
void CatalystInitialize(int numScripts, char* scripts[]);
|
||||
|
||||
void CatalystFinalize();
|
||||
|
||||
void CatalystCoProcess(unsigned int numberOfPoints, double* pointsData,
|
||||
unsigned int numberOfCells, unsigned int* cellsDAta,
|
||||
double* velocityData, float* pressureData, double time,
|
||||
unsigned int timeStep, int lastTimeStep);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
137
ParaView-5.0.1/Examples/Catalyst/CFullExample/FEDataStructures.c
Normal file
137
ParaView-5.0.1/Examples/Catalyst/CFullExample/FEDataStructures.c
Normal file
@ -0,0 +1,137 @@
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <mpi.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void InitializeGrid(Grid* grid, const unsigned int numPoints[3], const double spacing[3] )
|
||||
{
|
||||
grid->NumberOfPoints = 0;
|
||||
grid->Points = 0;
|
||||
grid->NumberOfCells = 0;
|
||||
grid->Cells = 0;
|
||||
if(numPoints[0] == 0 || numPoints[1] == 0 || numPoints[2] == 0)
|
||||
{
|
||||
printf("Must have a non-zero amount of points in each direction.\n");
|
||||
}
|
||||
// in parallel, we do a simple partitioning in the x-direction.
|
||||
int mpiSize = 1;
|
||||
int mpiRank = 0;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
|
||||
|
||||
unsigned int startXPoint = mpiRank*numPoints[0]/mpiSize;
|
||||
unsigned int endXPoint = (mpiRank+1)*numPoints[0]/mpiSize;
|
||||
if(mpiSize != mpiRank+1)
|
||||
{
|
||||
endXPoint++;
|
||||
}
|
||||
|
||||
// create the points -- slowest in the x and fastest in the z directions
|
||||
if(grid->Points != 0)
|
||||
{
|
||||
free(grid->Points);
|
||||
}
|
||||
unsigned int numXPoints = endXPoint - startXPoint;
|
||||
grid->Points = (double*) malloc(3*sizeof(double)*numPoints[1]*numPoints[2]*numXPoints);
|
||||
unsigned int counter = 0;
|
||||
unsigned int i, j, k;
|
||||
for(i=startXPoint;i<endXPoint;i++)
|
||||
{
|
||||
for(j=0;j<numPoints[1];j++)
|
||||
{
|
||||
for(k=0;k<numPoints[2];k++)
|
||||
{
|
||||
grid->Points[counter] = i*spacing[0];
|
||||
grid->Points[counter+1] = j*spacing[1];
|
||||
grid->Points[counter+2] = k*spacing[2];
|
||||
counter += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
grid->NumberOfPoints = numPoints[1]*numPoints[2]*numXPoints;
|
||||
// create the hex cells
|
||||
if(grid->Cells != 0)
|
||||
{
|
||||
free(grid->Cells);
|
||||
}
|
||||
grid->Cells = (unsigned int*) malloc(8*sizeof(unsigned int)*(numPoints[1]-1)*(numPoints[2]-1)*(numXPoints-1));
|
||||
counter = 0;
|
||||
for(i=0;i<numXPoints-1;i++)
|
||||
{
|
||||
for(j=0;j<numPoints[1]-1;j++)
|
||||
{
|
||||
for(k=0;k<numPoints[2]-1;k++)
|
||||
{
|
||||
grid->Cells[counter] = i*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k;
|
||||
grid->Cells[counter+1] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k;
|
||||
grid->Cells[counter+2] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k;
|
||||
grid->Cells[counter+3] = i*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k;
|
||||
grid->Cells[counter+4] = i*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k+1;
|
||||
grid->Cells[counter+5] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k+1;
|
||||
grid->Cells[counter+6] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k+1;
|
||||
grid->Cells[counter+7] = i*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k+1;
|
||||
counter += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
grid->NumberOfCells = (numPoints[1]-1)*(numPoints[2]-1)*(numXPoints-1);
|
||||
}
|
||||
|
||||
void FinalizeGrid(Grid* grid)
|
||||
{
|
||||
if(grid->Points)
|
||||
{
|
||||
free(grid->Points);
|
||||
grid->Points = 0;
|
||||
}
|
||||
if(grid->Cells)
|
||||
{
|
||||
free(grid->Cells);
|
||||
grid->Cells = 0;
|
||||
}
|
||||
grid->NumberOfPoints = 0;
|
||||
grid->NumberOfCells = 0;
|
||||
}
|
||||
|
||||
void InitializeAttributes(Attributes* attributes, Grid* grid)
|
||||
{
|
||||
attributes->GridPtr = grid;
|
||||
attributes->Velocity = 0;
|
||||
attributes->Pressure = 0;
|
||||
}
|
||||
|
||||
void UpdateFields(Attributes* attributes, double time)
|
||||
{
|
||||
unsigned int numPoints = attributes->GridPtr->NumberOfPoints;
|
||||
if(attributes->Velocity != 0)
|
||||
{
|
||||
free(attributes->Velocity);
|
||||
}
|
||||
attributes->Velocity = (double*) malloc(sizeof(double)*numPoints*3);
|
||||
unsigned int i;
|
||||
for(i=0;i<numPoints;i++)
|
||||
{
|
||||
attributes->Velocity[i] = 0;
|
||||
attributes->Velocity[i+numPoints] = attributes->GridPtr->Points[i*3+1]*time;
|
||||
attributes->Velocity[i+2*numPoints] = 0;
|
||||
}
|
||||
unsigned int numCells = attributes->GridPtr->NumberOfCells;
|
||||
if(attributes->Pressure != 0)
|
||||
{
|
||||
free(attributes->Pressure);
|
||||
}
|
||||
attributes->Pressure = (float*) malloc(sizeof(float)*numCells);
|
||||
for(i=0;i<numCells;i++)
|
||||
{
|
||||
attributes->Pressure[i] = 0;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
#ifndef FEDATASTRUCTURES_HEADER
|
||||
#define FEDATASTRUCTURES_HEADER
|
||||
|
||||
typedef struct Grid
|
||||
{
|
||||
unsigned int NumberOfPoints;
|
||||
double* Points;
|
||||
unsigned int NumberOfCells;
|
||||
unsigned int* Cells;
|
||||
} Grid;
|
||||
|
||||
void InitializeGrid(Grid* grid, const unsigned int numPoints[3], const double spacing[3]);
|
||||
void FinalizeGrid(Grid*);
|
||||
|
||||
typedef struct Attributes
|
||||
{
|
||||
// A structure for generating and storing point and cell fields.
|
||||
// Velocity is stored at the points and pressure is stored
|
||||
// for the cells. The current velocity profile is for a
|
||||
// shearing flow with U(y,t) = y*t, V = 0 and W = 0.
|
||||
// Pressure is constant through the domain.
|
||||
double* Velocity;
|
||||
float* Pressure;
|
||||
Grid* GridPtr;
|
||||
} Attributes;
|
||||
|
||||
void InitializeAttributes(Attributes* attributes, Grid* grid);
|
||||
void FinalizeAttributes(Attributes* attributes);
|
||||
void UpdateFields(Attributes* attributes, double time);
|
||||
#endif
|
||||
61
ParaView-5.0.1/Examples/Catalyst/CFullExample/FEDriver.c
Normal file
61
ParaView-5.0.1/Examples/Catalyst/CFullExample/FEDriver.c
Normal file
@ -0,0 +1,61 @@
|
||||
#include "FEDataStructures.h"
|
||||
#include <mpi.h>
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
#include "FEAdaptor.h"
|
||||
#endif
|
||||
|
||||
// Example of a C adaptor for a simulation code
|
||||
// where the simulation code has a fixed topology
|
||||
// grid. We treat the grid as an unstructured
|
||||
// grid even though in the example provided it
|
||||
// would be best described as a vtkImageData.
|
||||
// Also, the points are stored in an inconsistent
|
||||
// manner with respect to the velocity vector.
|
||||
// This is purposefully done to demonstrate
|
||||
// the different approaches for getting data
|
||||
// into Catalyst. In this example we don't
|
||||
// use any of the Fortran/C API provided in
|
||||
// Catalyst. That is in CFullExample2.
|
||||
// Note that through configuration
|
||||
// that the driver can be run without linking
|
||||
// to Catalyst.
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
MPI_Init(&argc, &argv);
|
||||
Grid grid = (Grid) { .NumberOfPoints = 0, .Points = 0, .NumberOfCells = 0, .Cells = 0};
|
||||
unsigned int numPoints[3] = {70, 60, 44};
|
||||
double spacing[3] = {1, 1.1, 1.3};
|
||||
InitializeGrid(&grid, numPoints, spacing);
|
||||
Attributes attributes;
|
||||
InitializeAttributes(&attributes, &grid);
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
CatalystInitialize(argc, argv);
|
||||
#endif
|
||||
unsigned int numberOfTimeSteps = 100;
|
||||
unsigned int timeStep;
|
||||
for(timeStep=0;timeStep<numberOfTimeSteps;timeStep++)
|
||||
{
|
||||
// use a time step length of 0.1
|
||||
double time = timeStep * 0.1;
|
||||
UpdateFields(&attributes, time);
|
||||
#ifdef USE_CATALYST
|
||||
int lastTimeStep = 0;
|
||||
if(timeStep == numberOfTimeSteps-1)
|
||||
{
|
||||
lastTimeStep = 1;
|
||||
}
|
||||
CatalystCoProcess(grid.NumberOfPoints, grid.Points, grid.NumberOfCells, grid.Cells,
|
||||
attributes.Velocity, attributes.Pressure, time, timeStep, lastTimeStep);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
CatalystFinalize();
|
||||
#endif
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
|
||||
try: paraview.simple
|
||||
except: from paraview.simple import *
|
||||
|
||||
from paraview import coprocessing
|
||||
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Code generated from cpstate.py to create the CoProcessor.
|
||||
|
||||
|
||||
# ----------------------- CoProcessor definition -----------------------
|
||||
|
||||
def CreateCoProcessor():
|
||||
def _CreatePipeline(coprocessor, datadescription):
|
||||
class Pipeline:
|
||||
filename_3_pvtu = coprocessor.CreateProducer( datadescription, "input" )
|
||||
|
||||
Slice1 = Slice( guiName="Slice1", Crinkleslice=0, SliceOffsetValues=[0.0], Triangulatetheslice=1, SliceType="Plane" )
|
||||
Slice1.SliceType.Offset = 0.0
|
||||
Slice1.SliceType.Origin = [34.5, 32.45, 27.95]
|
||||
Slice1.SliceType.Normal = [1.0, 0.0, 0.0]
|
||||
|
||||
SetActiveSource(filename_3_pvtu)
|
||||
ParallelUnstructuredGridWriter1 = coprocessor.CreateWriter( XMLPUnstructuredGridWriter, "fullgrid_%t.pvtu", 100 )
|
||||
|
||||
SetActiveSource(Slice1)
|
||||
ParallelPolyDataWriter1 = coprocessor.CreateWriter( XMLPPolyDataWriter, "slice_%t.pvtp", 10 )
|
||||
|
||||
return Pipeline()
|
||||
|
||||
class CoProcessor(coprocessing.CoProcessor):
|
||||
def CreatePipeline(self, datadescription):
|
||||
self.Pipeline = _CreatePipeline(self, datadescription)
|
||||
|
||||
coprocessor = CoProcessor()
|
||||
freqs = {'input': [10, 100]}
|
||||
coprocessor.SetUpdateFrequencies(freqs)
|
||||
return coprocessor
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Global variables that will hold the pipeline for each timestep
|
||||
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
|
||||
# It will be automatically setup when coprocessor.UpdateProducers() is called the
|
||||
# first time.
|
||||
coprocessor = CreateCoProcessor()
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Enable Live-Visualizaton with ParaView
|
||||
coprocessor.EnableLiveVisualization(True)
|
||||
|
||||
|
||||
# ---------------------- Data Selection method ----------------------
|
||||
|
||||
def RequestDataDescription(datadescription):
|
||||
"Callback to populate the request for current timestep"
|
||||
global coprocessor
|
||||
if datadescription.GetForceOutput() == True:
|
||||
# We are just going to request all fields and meshes from the simulation
|
||||
# code/adaptor.
|
||||
for i in range(datadescription.GetNumberOfInputDescriptions()):
|
||||
datadescription.GetInputDescription(i).AllFieldsOn()
|
||||
datadescription.GetInputDescription(i).GenerateMeshOn()
|
||||
return
|
||||
|
||||
# setup requests for all inputs based on the requirements of the
|
||||
# pipeline.
|
||||
coprocessor.LoadRequestedData(datadescription)
|
||||
|
||||
# ------------------------ Processing method ------------------------
|
||||
|
||||
def DoCoProcessing(datadescription):
|
||||
"Callback to do co-processing for current timestep"
|
||||
global coprocessor
|
||||
|
||||
# Update the coprocessor by providing it the newly generated simulation data.
|
||||
# If the pipeline hasn't been setup yet, this will setup the pipeline.
|
||||
coprocessor.UpdateProducers(datadescription)
|
||||
|
||||
# Write output data, if appropriate.
|
||||
coprocessor.WriteData(datadescription);
|
||||
|
||||
# Write image capture (Last arg: rescale lookup table), if appropriate.
|
||||
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
|
||||
|
||||
# Live Visualization, if enabled.
|
||||
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)
|
||||
@ -0,0 +1,40 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(CatalystCFullExample2 C)
|
||||
|
||||
set(USE_CATALYST ON CACHE BOOL "Link the simulator with Catalyst")
|
||||
if(USE_CATALYST)
|
||||
# we only need C++ compilers if we're building the Adaptor
|
||||
enable_language(CXX)
|
||||
find_package(ParaView 4.1 REQUIRED COMPONENTS vtkPVPythonCatalyst)
|
||||
include("${PARAVIEW_USE_FILE}")
|
||||
set(Adaptor_SRCS
|
||||
FEAdaptor.cxx
|
||||
)
|
||||
add_library(CFullExample2Adaptor ${Adaptor_SRCS})
|
||||
target_link_libraries(CFullExample2Adaptor vtkPVPythonCatalyst)
|
||||
add_definitions("-DUSE_CATALYST")
|
||||
if(NOT PARAVIEW_USE_MPI)
|
||||
message(SEND_ERROR "ParaView must be built with MPI enabled")
|
||||
endif()
|
||||
else()
|
||||
find_package(MPI REQUIRED)
|
||||
include_directories(${MPI_C_INCLUDE_PATH})
|
||||
endif()
|
||||
|
||||
add_executable(CFullExample2 FEDriver.c FEDataStructures.c)
|
||||
if(USE_CATALYST)
|
||||
target_link_libraries(CFullExample2 LINK_PRIVATE CFullExample2Adaptor)
|
||||
include(vtkModuleMacros)
|
||||
include(vtkMPI)
|
||||
vtk_mpi_link(CFullExample2)
|
||||
else()
|
||||
target_link_libraries(CFullExample2 LINK_PRIVATE ${MPI_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_test(NAME CFullExample2Test COMMAND CFullExample2 ${CMAKE_CURRENT_SOURCE_DIR}/SampleScripts/feslicescript.py)
|
||||
set_tests_properties(CFullExample2Test PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
endif()
|
||||
135
ParaView-5.0.1/Examples/Catalyst/CFullExample2/FEAdaptor.cxx
Normal file
135
ParaView-5.0.1/Examples/Catalyst/CFullExample2/FEAdaptor.cxx
Normal file
@ -0,0 +1,135 @@
|
||||
#include <iostream>
|
||||
#include "FEAdaptor.h"
|
||||
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkCellType.h>
|
||||
#include <vtkCPAdaptorAPI.h>
|
||||
#include <vtkCPDataDescription.h>
|
||||
#include <vtkCPInputDataDescription.h>
|
||||
#include <vtkCPProcessor.h>
|
||||
#include <vtkCPPythonScriptPipeline.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkFloatArray.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkPoints.h>
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
vtkSmartPointer<vtkUnstructuredGrid> VTKGrid;
|
||||
|
||||
void BuildVTKGrid(unsigned int numberOfPoints, double* pointsData,
|
||||
unsigned int numberOfCells, unsigned int* cellsData)
|
||||
{
|
||||
// create the points information
|
||||
vtkNew<vtkDoubleArray> pointArray;
|
||||
pointArray->SetNumberOfComponents(3);
|
||||
pointArray->SetArray(pointsData, static_cast<vtkIdType>(numberOfPoints*3), 1);
|
||||
vtkNew<vtkPoints> points;
|
||||
points->SetData(pointArray.GetPointer());
|
||||
VTKGrid->SetPoints(points.GetPointer());
|
||||
|
||||
// create the cells
|
||||
VTKGrid->Allocate(static_cast<vtkIdType>(numberOfCells*9));
|
||||
for(unsigned int cell=0;cell<numberOfCells;cell++)
|
||||
{
|
||||
unsigned int* cellPoints = cellsData+8*cell;
|
||||
vtkIdType tmp[8] = {cellPoints[0], cellPoints[1], cellPoints[2], cellPoints[3],
|
||||
cellPoints[4], cellPoints[5], cellPoints[6], cellPoints[7]};
|
||||
VTKGrid->InsertNextCell(VTK_HEXAHEDRON, 8, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateVTKAttributes(unsigned int numberOfPoints, double* velocityData,
|
||||
unsigned int numberOfCells, float* pressureData)
|
||||
{
|
||||
if(VTKGrid->GetPointData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// velocity array
|
||||
vtkNew<vtkDoubleArray> velocity;
|
||||
velocity->SetName("velocity");
|
||||
velocity->SetNumberOfComponents(3);
|
||||
velocity->SetNumberOfTuples(static_cast<vtkIdType>(numberOfPoints));
|
||||
VTKGrid->GetPointData()->AddArray(velocity.GetPointer());
|
||||
}
|
||||
if(VTKGrid->GetCellData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// pressure array
|
||||
vtkNew<vtkFloatArray> pressure;
|
||||
pressure->SetName("pressure");
|
||||
pressure->SetNumberOfComponents(1);
|
||||
VTKGrid->GetCellData()->AddArray(pressure.GetPointer());
|
||||
}
|
||||
vtkDoubleArray* velocity = vtkDoubleArray::SafeDownCast(
|
||||
VTKGrid->GetPointData()->GetArray("velocity"));
|
||||
// The velocity array is ordered as vx0,vx1,vx2,..,vy0,vy1,vy2,..,vz0,vz1,vz2,..
|
||||
// so we need to create a full copy of it with VTK's ordering of
|
||||
// vx0,vy0,vz0,vx1,vy1,vz1,..
|
||||
for(unsigned int i=0;i<numberOfPoints;i++)
|
||||
{
|
||||
double values[3] = {velocityData[i], velocityData[i+numberOfPoints],
|
||||
velocityData[i+2*numberOfPoints]};
|
||||
velocity->SetTupleValue(i, values);
|
||||
}
|
||||
|
||||
vtkFloatArray* pressure = vtkFloatArray::SafeDownCast(
|
||||
VTKGrid->GetCellData()->GetArray("pressure"));
|
||||
// The pressure array is a scalar array so we can reuse
|
||||
// memory as long as we ordered the points properly.
|
||||
pressure->SetArray(pressureData, static_cast<vtkIdType>(numberOfCells), 1);
|
||||
}
|
||||
|
||||
void BuildVTKDataStructures(unsigned int numberOfPoints, double* points, double* velocity,
|
||||
unsigned int numberOfCells, unsigned int* cells, float* pressure)
|
||||
{
|
||||
if(VTKGrid == NULL)
|
||||
{
|
||||
// The grid structure isn't changing so we only build it
|
||||
// the first time it's needed. If we needed the memory
|
||||
// we could delete it and rebuild as necessary.
|
||||
VTKGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
|
||||
BuildVTKGrid(numberOfPoints, points, numberOfCells, cells);
|
||||
}
|
||||
UpdateVTKAttributes(numberOfPoints, velocity, numberOfCells, pressure);
|
||||
}
|
||||
}
|
||||
|
||||
void CatalystCoProcess(unsigned int numberOfPoints, double* pointsData,
|
||||
unsigned int numberOfCells, unsigned int* cellsData,
|
||||
double* velocityData, float* pressureData, double time,
|
||||
unsigned int timeStep, int lastTimeStep)
|
||||
{
|
||||
vtkCPProcessor* processor = vtkCPAdaptorAPI::GetCoProcessor();
|
||||
vtkCPDataDescription* dataDescription = vtkCPAdaptorAPI::GetCoProcessorData();
|
||||
if(processor == NULL || dataDescription == NULL)
|
||||
{
|
||||
cerr << "ERROR: Catalyst not properly initialized.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
dataDescription->AddInput("input");
|
||||
dataDescription->SetTimeData(time, timeStep);
|
||||
if(lastTimeStep == true)
|
||||
{
|
||||
// assume that we want to all the pipelines to execute if it
|
||||
// is the last time step.
|
||||
dataDescription->ForceOutputOn();
|
||||
}
|
||||
if(processor->RequestDataDescription(dataDescription) != 0)
|
||||
{
|
||||
BuildVTKDataStructures(numberOfPoints, pointsData, velocityData,
|
||||
numberOfCells, cellsData, pressureData);
|
||||
dataDescription->GetInputDescriptionByName("input")->SetGrid(VTKGrid);
|
||||
processor->CoProcess(dataDescription);
|
||||
}
|
||||
}
|
||||
|
||||
void CatalystFinalize()
|
||||
{ // Used to free grid if it was used
|
||||
if(VTKGrid)
|
||||
{
|
||||
VTKGrid = NULL;
|
||||
}
|
||||
}
|
||||
16
ParaView-5.0.1/Examples/Catalyst/CFullExample2/FEAdaptor.h
Normal file
16
ParaView-5.0.1/Examples/Catalyst/CFullExample2/FEAdaptor.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef FEADAPTOR_HEADER
|
||||
#define FEADAPTOR_HEADER
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
void CatalystCoProcess(unsigned int numberOfPoints, double* pointsData,
|
||||
unsigned int numberOfCells, unsigned int* cellsDAta,
|
||||
double* velocityData, float* pressureData, double time,
|
||||
unsigned int timeStep, int lastTimeStep);
|
||||
void CatalystFinalize();
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@ -0,0 +1,137 @@
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <mpi.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void InitializeGrid(Grid* grid, const unsigned int numPoints[3], const double spacing[3] )
|
||||
{
|
||||
grid->NumberOfPoints = 0;
|
||||
grid->Points = 0;
|
||||
grid->NumberOfCells = 0;
|
||||
grid->Cells = 0;
|
||||
if(numPoints[0] == 0 || numPoints[1] == 0 || numPoints[2] == 0)
|
||||
{
|
||||
printf("Must have a non-zero amount of points in each direction.\n");
|
||||
}
|
||||
// in parallel, we do a simple partitioning in the x-direction.
|
||||
int mpiSize = 1;
|
||||
int mpiRank = 0;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
|
||||
|
||||
unsigned int startXPoint = mpiRank*numPoints[0]/mpiSize;
|
||||
unsigned int endXPoint = (mpiRank+1)*numPoints[0]/mpiSize;
|
||||
if(mpiSize != mpiRank+1)
|
||||
{
|
||||
endXPoint++;
|
||||
}
|
||||
|
||||
// create the points -- slowest in the x and fastest in the z directions
|
||||
if(grid->Points != 0)
|
||||
{
|
||||
free(grid->Points);
|
||||
}
|
||||
unsigned int numXPoints = endXPoint - startXPoint;
|
||||
grid->Points = (double*) malloc(3*sizeof(double)*numPoints[1]*numPoints[2]*numXPoints);
|
||||
unsigned int counter = 0;
|
||||
unsigned int i, j, k;
|
||||
for(i=startXPoint;i<endXPoint;i++)
|
||||
{
|
||||
for(j=0;j<numPoints[1];j++)
|
||||
{
|
||||
for(k=0;k<numPoints[2];k++)
|
||||
{
|
||||
grid->Points[counter] = i*spacing[0];
|
||||
grid->Points[counter+1] = j*spacing[1];
|
||||
grid->Points[counter+2] = k*spacing[2];
|
||||
counter += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
grid->NumberOfPoints = numPoints[1]*numPoints[2]*numXPoints;
|
||||
// create the hex cells
|
||||
if(grid->Cells != 0)
|
||||
{
|
||||
free(grid->Cells);
|
||||
}
|
||||
grid->Cells = (unsigned int*) malloc(8*sizeof(unsigned int)*(numPoints[1]-1)*(numPoints[2]-1)*(numXPoints-1));
|
||||
counter = 0;
|
||||
for(i=0;i<numXPoints-1;i++)
|
||||
{
|
||||
for(j=0;j<numPoints[1]-1;j++)
|
||||
{
|
||||
for(k=0;k<numPoints[2]-1;k++)
|
||||
{
|
||||
grid->Cells[counter] = i*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k;
|
||||
grid->Cells[counter+1] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k;
|
||||
grid->Cells[counter+2] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k;
|
||||
grid->Cells[counter+3] = i*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k;
|
||||
grid->Cells[counter+4] = i*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k+1;
|
||||
grid->Cells[counter+5] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k+1;
|
||||
grid->Cells[counter+6] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k+1;
|
||||
grid->Cells[counter+7] = i*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k+1;
|
||||
counter += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
grid->NumberOfCells = (numPoints[1]-1)*(numPoints[2]-1)*(numXPoints-1);
|
||||
}
|
||||
|
||||
void FinalizeGrid(Grid* grid)
|
||||
{
|
||||
if(grid->Points)
|
||||
{
|
||||
free(grid->Points);
|
||||
grid->Points = 0;
|
||||
}
|
||||
if(grid->Cells)
|
||||
{
|
||||
free(grid->Cells);
|
||||
grid->Cells = 0;
|
||||
}
|
||||
grid->NumberOfPoints = 0;
|
||||
grid->NumberOfCells = 0;
|
||||
}
|
||||
|
||||
void InitializeAttributes(Attributes* attributes, Grid* grid)
|
||||
{
|
||||
attributes->GridPtr = grid;
|
||||
attributes->Velocity = 0;
|
||||
attributes->Pressure = 0;
|
||||
}
|
||||
|
||||
void UpdateFields(Attributes* attributes, double time)
|
||||
{
|
||||
unsigned int numPoints = attributes->GridPtr->NumberOfPoints;
|
||||
if(attributes->Velocity != 0)
|
||||
{
|
||||
free(attributes->Velocity);
|
||||
}
|
||||
attributes->Velocity = (double*) malloc(sizeof(double)*numPoints*3);
|
||||
unsigned int i;
|
||||
for(i=0;i<numPoints;i++)
|
||||
{
|
||||
attributes->Velocity[i] = 0;
|
||||
attributes->Velocity[i+numPoints] = attributes->GridPtr->Points[i*3+1]*time;
|
||||
attributes->Velocity[i+2*numPoints] = 0;
|
||||
}
|
||||
unsigned int numCells = attributes->GridPtr->NumberOfCells;
|
||||
if(attributes->Pressure != 0)
|
||||
{
|
||||
free(attributes->Pressure);
|
||||
}
|
||||
attributes->Pressure = (float*) malloc(sizeof(float)*numCells);
|
||||
for(i=0;i<numCells;i++)
|
||||
{
|
||||
attributes->Pressure[i] = 0;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
#ifndef FEDATASTRUCTURES_HEADER
|
||||
#define FEDATASTRUCTURES_HEADER
|
||||
|
||||
typedef struct Grid
|
||||
{
|
||||
unsigned int NumberOfPoints;
|
||||
double* Points;
|
||||
unsigned int NumberOfCells;
|
||||
unsigned int* Cells;
|
||||
} Grid;
|
||||
|
||||
void InitializeGrid(Grid* grid, const unsigned int numPoints[3], const double spacing[3]);
|
||||
void FinalizeGrid(Grid*);
|
||||
|
||||
typedef struct Attributes
|
||||
{
|
||||
// A structure for generating and storing point and cell fields.
|
||||
// Velocity is stored at the points and pressure is stored
|
||||
// for the cells. The current velocity profile is for a
|
||||
// shearing flow with U(y,t) = y*t, V = 0 and W = 0.
|
||||
// Pressure is constant through the domain.
|
||||
double* Velocity;
|
||||
float* Pressure;
|
||||
Grid* GridPtr;
|
||||
} Attributes;
|
||||
|
||||
void InitializeAttributes(Attributes* attributes, Grid* grid);
|
||||
void FinalizeAttributes(Attributes* attributes);
|
||||
void UpdateFields(Attributes* attributes, double time);
|
||||
#endif
|
||||
82
ParaView-5.0.1/Examples/Catalyst/CFullExample2/FEDriver.c
Normal file
82
ParaView-5.0.1/Examples/Catalyst/CFullExample2/FEDriver.c
Normal file
@ -0,0 +1,82 @@
|
||||
#include "FEDataStructures.h"
|
||||
#include <mpi.h>
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
#include "FEAdaptor.h"
|
||||
#include <CPythonAdaptorAPI.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
// Example of a C adaptor for a simulation code
|
||||
// where the simulation code has a fixed topology
|
||||
// grid. We treat the grid as an unstructured
|
||||
// grid even though in the example provided it
|
||||
// would be best described as a vtkImageData.
|
||||
// Also, the points are stored in an inconsistent
|
||||
// manner with respect to the velocity vector.
|
||||
// This is purposefully done to demonstrate
|
||||
// the different approaches for getting data
|
||||
// into Catalyst. In this example we use
|
||||
// some of the API in CPythonAdaptorAPI.h
|
||||
// to assist in setting the problem up.
|
||||
// CFullExample does essentially the same
|
||||
// thing but without using the existing
|
||||
// helper API. Note that through configuration
|
||||
// that the driver can be run without linking
|
||||
// to Catalyst.
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
MPI_Init(&argc, &argv);
|
||||
Grid grid = (Grid) { .NumberOfPoints = 0, .Points = 0, .NumberOfCells = 0, .Cells = 0};
|
||||
unsigned int numPoints[3] = {70, 60, 44};
|
||||
double spacing[3] = {1, 1.1, 1.3};
|
||||
InitializeGrid(&grid, numPoints, spacing);
|
||||
Attributes attributes;
|
||||
InitializeAttributes(&attributes, &grid);
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
int fileNameLength = 0;
|
||||
if(argc < 2)
|
||||
{
|
||||
printf("Must pass in a Catalyst script\n");
|
||||
MPI_Finalize();
|
||||
return 1;
|
||||
}
|
||||
fileNameLength = strlen(argv[1]);
|
||||
coprocessorinitializewithpython(argv[1], &fileNameLength);
|
||||
int i;
|
||||
for(i=2;i<argc;i++)
|
||||
{
|
||||
// Add in any other Python script pipelines that are passed in.
|
||||
fileNameLength = strlen(argv[i]);
|
||||
coprocessoraddpythonscript(argv[i], &fileNameLength);
|
||||
}
|
||||
#endif
|
||||
unsigned int numberOfTimeSteps = 100;
|
||||
unsigned int timeStep;
|
||||
for(timeStep=0;timeStep<numberOfTimeSteps;timeStep++)
|
||||
{
|
||||
// use a time step length of 0.1
|
||||
double time = timeStep * 0.1;
|
||||
UpdateFields(&attributes, time);
|
||||
#ifdef USE_CATALYST
|
||||
int lastTimeStep = 0;
|
||||
if(timeStep == numberOfTimeSteps-1)
|
||||
{
|
||||
lastTimeStep = 1;
|
||||
}
|
||||
CatalystCoProcess(grid.NumberOfPoints, grid.Points, grid.NumberOfCells, grid.Cells,
|
||||
attributes.Velocity, attributes.Pressure, time, timeStep, lastTimeStep);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
CatalystFinalize();
|
||||
coprocessorfinalize();
|
||||
#endif
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
|
||||
try: paraview.simple
|
||||
except: from paraview.simple import *
|
||||
|
||||
from paraview import coprocessing
|
||||
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Code generated from cpstate.py to create the CoProcessor.
|
||||
|
||||
|
||||
# ----------------------- CoProcessor definition -----------------------
|
||||
|
||||
def CreateCoProcessor():
|
||||
def _CreatePipeline(coprocessor, datadescription):
|
||||
class Pipeline:
|
||||
filename_3_pvtu = coprocessor.CreateProducer( datadescription, "input" )
|
||||
|
||||
Slice1 = Slice( guiName="Slice1", Crinkleslice=0, SliceOffsetValues=[0.0], Triangulatetheslice=1, SliceType="Plane" )
|
||||
Slice1.SliceType.Offset = 0.0
|
||||
Slice1.SliceType.Origin = [34.5, 32.45, 27.95]
|
||||
Slice1.SliceType.Normal = [1.0, 0.0, 0.0]
|
||||
|
||||
SetActiveSource(filename_3_pvtu)
|
||||
ParallelUnstructuredGridWriter1 = coprocessor.CreateWriter( XMLPUnstructuredGridWriter, "fullgrid_%t.pvtu", 100 )
|
||||
|
||||
SetActiveSource(Slice1)
|
||||
ParallelPolyDataWriter1 = coprocessor.CreateWriter( XMLPPolyDataWriter, "slice_%t.pvtp", 10 )
|
||||
|
||||
return Pipeline()
|
||||
|
||||
class CoProcessor(coprocessing.CoProcessor):
|
||||
def CreatePipeline(self, datadescription):
|
||||
self.Pipeline = _CreatePipeline(self, datadescription)
|
||||
|
||||
coprocessor = CoProcessor()
|
||||
freqs = {'input': [10, 100]}
|
||||
coprocessor.SetUpdateFrequencies(freqs)
|
||||
return coprocessor
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Global variables that will hold the pipeline for each timestep
|
||||
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
|
||||
# It will be automatically setup when coprocessor.UpdateProducers() is called the
|
||||
# first time.
|
||||
coprocessor = CreateCoProcessor()
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Enable Live-Visualizaton with ParaView
|
||||
coprocessor.EnableLiveVisualization(True)
|
||||
|
||||
|
||||
# ---------------------- Data Selection method ----------------------
|
||||
|
||||
def RequestDataDescription(datadescription):
|
||||
"Callback to populate the request for current timestep"
|
||||
global coprocessor
|
||||
if datadescription.GetForceOutput() == True:
|
||||
# We are just going to request all fields and meshes from the simulation
|
||||
# code/adaptor.
|
||||
for i in range(datadescription.GetNumberOfInputDescriptions()):
|
||||
datadescription.GetInputDescription(i).AllFieldsOn()
|
||||
datadescription.GetInputDescription(i).GenerateMeshOn()
|
||||
return
|
||||
|
||||
# setup requests for all inputs based on the requirements of the
|
||||
# pipeline.
|
||||
coprocessor.LoadRequestedData(datadescription)
|
||||
|
||||
# ------------------------ Processing method ------------------------
|
||||
|
||||
def DoCoProcessing(datadescription):
|
||||
"Callback to do co-processing for current timestep"
|
||||
global coprocessor
|
||||
|
||||
# Update the coprocessor by providing it the newly generated simulation data.
|
||||
# If the pipeline hasn't been setup yet, this will setup the pipeline.
|
||||
coprocessor.UpdateProducers(datadescription)
|
||||
|
||||
# Write output data, if appropriate.
|
||||
coprocessor.WriteData(datadescription);
|
||||
|
||||
# Write image capture (Last arg: rescale lookup table), if appropriate.
|
||||
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
|
||||
|
||||
# Live Visualization, if enabled.
|
||||
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)
|
||||
50
ParaView-5.0.1/Examples/Catalyst/CMakeLists.txt
Normal file
50
ParaView-5.0.1/Examples/Catalyst/CMakeLists.txt
Normal file
@ -0,0 +1,50 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(CatalystExamples CXX C)
|
||||
|
||||
set(USE_CATALYST ON CACHE BOOL "Link the simulator with Catalyst")
|
||||
if(USE_CATALYST)
|
||||
enable_language(CXX)
|
||||
find_package(ParaView 4.2 REQUIRED COMPONENTS vtkPVPythonCatalyst)
|
||||
include("${PARAVIEW_USE_FILE}")
|
||||
add_definitions("-DUSE_CATALYST")
|
||||
if(NOT PARAVIEW_USE_MPI)
|
||||
message(SEND_ERROR "ParaView must be built with MPI enabled")
|
||||
endif()
|
||||
else()
|
||||
find_package(MPI REQUIRED)
|
||||
include_directories(${MPI_C_INCLUDE_PATH})
|
||||
endif()
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
include(CTest)
|
||||
endif()
|
||||
|
||||
add_subdirectory(CxxOverlappingAMRExample)
|
||||
add_subdirectory(CxxNonOverlappingAMRExample)
|
||||
add_subdirectory(CFullExample2)
|
||||
add_subdirectory(CxxFullExample)
|
||||
add_subdirectory(CFullExample)
|
||||
add_subdirectory(CxxVTKPipelineExample)
|
||||
add_subdirectory(CxxImageDataExample)
|
||||
add_subdirectory(CxxMultiPieceExample)
|
||||
add_subdirectory(CxxPVSMPipelineExample)
|
||||
add_subdirectory(CxxMappedDataArrayExample)
|
||||
add_subdirectory(MPISubCommunicatorExample)
|
||||
add_subdirectory(PythonDolfinExample)
|
||||
add_subdirectory(CxxParticlePathExample)
|
||||
|
||||
set(BUILD_FORTRAN_EXAMPLES OFF CACHE BOOL "Build Fortran Catalyst Examples")
|
||||
if(BUILD_FORTRAN_EXAMPLES)
|
||||
# Theoretically, CheckFortran should not be needed, but
|
||||
# enable_language(OPTIONAL) fails with Ninja generator.
|
||||
include(CheckFortran)
|
||||
if(CMAKE_Fortran_COMPILER)
|
||||
enable_language(Fortran OPTIONAL)
|
||||
endif()
|
||||
if(CMAKE_Fortran_COMPILER_WORKS)
|
||||
add_subdirectory(Fortran90FullExample)
|
||||
add_subdirectory(FortranPoissonSolver)
|
||||
endif()
|
||||
endif()
|
||||
@ -0,0 +1,40 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(CatalystCxxFullExample)
|
||||
|
||||
set(USE_CATALYST ON CACHE BOOL "Link the simulator with Catalyst")
|
||||
if(USE_CATALYST)
|
||||
find_package(ParaView 4.1 REQUIRED COMPONENTS vtkPVPythonCatalyst)
|
||||
include("${PARAVIEW_USE_FILE}")
|
||||
set(Adaptor_SRCS
|
||||
FEAdaptor.cxx
|
||||
)
|
||||
add_library(CxxFullExampleAdaptor ${Adaptor_SRCS})
|
||||
target_link_libraries(CxxFullExampleAdaptor vtkPVPythonCatalyst vtkParallelMPI)
|
||||
add_definitions("-DUSE_CATALYST")
|
||||
if(NOT PARAVIEW_USE_MPI)
|
||||
message(SEND_ERROR "ParaView must be built with MPI enabled")
|
||||
endif()
|
||||
else()
|
||||
find_package(MPI REQUIRED)
|
||||
include_directories(${MPI_C_INCLUDE_PATH})
|
||||
endif()
|
||||
|
||||
add_executable(CxxFullExample FEDriver.cxx FEDataStructures.cxx)
|
||||
if(USE_CATALYST)
|
||||
target_link_libraries(CxxFullExample LINK_PRIVATE CxxFullExampleAdaptor)
|
||||
include(vtkModuleMacros)
|
||||
include(vtkMPI)
|
||||
vtk_mpi_link(CxxFullExample)
|
||||
else()
|
||||
target_link_libraries(CxxFullExample LINK_PRIVATE ${MPI_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_test(NAME CxxFullExampleTest COMMAND CxxFullExample ${CMAKE_CURRENT_SOURCE_DIR}/SampleScripts/feslicescript.py)
|
||||
set_tests_properties(CxxFullExampleTest PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
add_test(NAME CxxFullExampleCinemaTest COMMAND CxxFullExample ${CMAKE_CURRENT_SOURCE_DIR}/SampleScripts/feslicecinema.py)
|
||||
set_tests_properties(CxxFullExampleCinemaTest PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
endif()
|
||||
155
ParaView-5.0.1/Examples/Catalyst/CxxFullExample/FEAdaptor.cxx
Normal file
155
ParaView-5.0.1/Examples/Catalyst/CxxFullExample/FEAdaptor.cxx
Normal file
@ -0,0 +1,155 @@
|
||||
#include <iostream>
|
||||
#include "FEAdaptor.h"
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkCellType.h>
|
||||
#include <vtkCPDataDescription.h>
|
||||
#include <vtkCPInputDataDescription.h>
|
||||
#include <vtkCPProcessor.h>
|
||||
#include <vtkCPPythonScriptPipeline.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkFloatArray.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkPoints.h>
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
vtkCPProcessor* Processor = NULL;
|
||||
vtkUnstructuredGrid* VTKGrid;
|
||||
|
||||
void BuildVTKGrid(Grid& grid)
|
||||
{
|
||||
// create the points information
|
||||
vtkNew<vtkDoubleArray> pointArray;
|
||||
pointArray->SetNumberOfComponents(3);
|
||||
pointArray->SetArray(grid.GetPointsArray(), static_cast<vtkIdType>(grid.GetNumberOfPoints()*3), 1);
|
||||
vtkNew<vtkPoints> points;
|
||||
points->SetData(pointArray.GetPointer());
|
||||
VTKGrid->SetPoints(points.GetPointer());
|
||||
|
||||
// create the cells
|
||||
size_t numCells = grid.GetNumberOfCells();
|
||||
VTKGrid->Allocate(static_cast<vtkIdType>(numCells*9));
|
||||
for(size_t cell=0;cell<numCells;cell++)
|
||||
{
|
||||
unsigned int* cellPoints = grid.GetCellPoints(cell);
|
||||
vtkIdType tmp[8] = {cellPoints[0], cellPoints[1], cellPoints[2], cellPoints[3],
|
||||
cellPoints[4], cellPoints[5], cellPoints[6], cellPoints[7]};
|
||||
VTKGrid->InsertNextCell(VTK_HEXAHEDRON, 8, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateVTKAttributes(Grid& grid, Attributes& attributes)
|
||||
{
|
||||
if(VTKGrid->GetPointData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// velocity array
|
||||
vtkNew<vtkDoubleArray> velocity;
|
||||
velocity->SetName("velocity");
|
||||
velocity->SetNumberOfComponents(3);
|
||||
velocity->SetNumberOfTuples(static_cast<vtkIdType>(grid.GetNumberOfPoints()));
|
||||
VTKGrid->GetPointData()->AddArray(velocity.GetPointer());
|
||||
}
|
||||
if(VTKGrid->GetCellData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// pressure array
|
||||
vtkNew<vtkFloatArray> pressure;
|
||||
pressure->SetName("pressure");
|
||||
pressure->SetNumberOfComponents(1);
|
||||
VTKGrid->GetCellData()->AddArray(pressure.GetPointer());
|
||||
}
|
||||
vtkDoubleArray* velocity = vtkDoubleArray::SafeDownCast(
|
||||
VTKGrid->GetPointData()->GetArray("velocity"));
|
||||
// The velocity array is ordered as vx0,vx1,vx2,..,vy0,vy1,vy2,..,vz0,vz1,vz2,..
|
||||
// so we need to create a full copy of it with VTK's ordering of
|
||||
// vx0,vy0,vz0,vx1,vy1,vz1,..
|
||||
double* velocityData = attributes.GetVelocityArray();
|
||||
vtkIdType numTuples = velocity->GetNumberOfTuples();
|
||||
for(vtkIdType i=0;i<numTuples;i++)
|
||||
{
|
||||
double values[3] = {velocityData[i], velocityData[i+numTuples],
|
||||
velocityData[i+2*numTuples]};
|
||||
velocity->SetTupleValue(i, values);
|
||||
}
|
||||
|
||||
vtkFloatArray* pressure = vtkFloatArray::SafeDownCast(
|
||||
VTKGrid->GetCellData()->GetArray("pressure"));
|
||||
// The pressure array is a scalar array so we can reuse
|
||||
// memory as long as we ordered the points properly.
|
||||
float* pressureData = attributes.GetPressureArray();
|
||||
pressure->SetArray(pressureData, static_cast<vtkIdType>(grid.GetNumberOfCells()), 1);
|
||||
}
|
||||
|
||||
void BuildVTKDataStructures(Grid& grid, Attributes& attributes)
|
||||
{
|
||||
if(VTKGrid == NULL)
|
||||
{
|
||||
// The grid structure isn't changing so we only build it
|
||||
// the first time it's needed. If we needed the memory
|
||||
// we could delete it and rebuild as necessary.
|
||||
VTKGrid = vtkUnstructuredGrid::New();
|
||||
BuildVTKGrid(grid);
|
||||
}
|
||||
UpdateVTKAttributes(grid, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
|
||||
void Initialize(int numScripts, char* scripts[])
|
||||
{
|
||||
if(Processor == NULL)
|
||||
{
|
||||
Processor = vtkCPProcessor::New();
|
||||
Processor->Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
Processor->RemoveAllPipelines();
|
||||
}
|
||||
for(int i=1;i<numScripts;i++)
|
||||
{
|
||||
vtkNew<vtkCPPythonScriptPipeline> pipeline;
|
||||
pipeline->Initialize(scripts[i]);
|
||||
Processor->AddPipeline(pipeline.GetPointer());
|
||||
}
|
||||
}
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
if(Processor)
|
||||
{
|
||||
Processor->Delete();
|
||||
Processor = NULL;
|
||||
}
|
||||
if(VTKGrid)
|
||||
{
|
||||
VTKGrid->Delete();
|
||||
VTKGrid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep)
|
||||
{
|
||||
vtkNew<vtkCPDataDescription> dataDescription;
|
||||
dataDescription->AddInput("input");
|
||||
dataDescription->SetTimeData(time, timeStep);
|
||||
if(lastTimeStep == true)
|
||||
{
|
||||
// assume that we want to all the pipelines to execute if it
|
||||
// is the last time step.
|
||||
dataDescription->ForceOutputOn();
|
||||
}
|
||||
if(Processor->RequestDataDescription(dataDescription.GetPointer()) != 0)
|
||||
{
|
||||
BuildVTKDataStructures(grid, attributes);
|
||||
dataDescription->GetInputDescriptionByName("input")->SetGrid(VTKGrid);
|
||||
Processor->CoProcess(dataDescription.GetPointer());
|
||||
}
|
||||
}
|
||||
} // end of Catalyst namespace
|
||||
17
ParaView-5.0.1/Examples/Catalyst/CxxFullExample/FEAdaptor.h
Normal file
17
ParaView-5.0.1/Examples/Catalyst/CxxFullExample/FEAdaptor.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef FEADAPTOR_HEADER
|
||||
#define FEADAPTOR_HEADER
|
||||
|
||||
class Attributes;
|
||||
class Grid;
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
void Initialize(int numScripts, char* scripts[]);
|
||||
|
||||
void Finalize();
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,153 @@
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <mpi.h>
|
||||
#include <iostream>
|
||||
|
||||
Grid::Grid()
|
||||
{}
|
||||
|
||||
void Grid::Initialize(const unsigned int numPoints[3], const double spacing[3] )
|
||||
{
|
||||
if(numPoints[0] == 0 || numPoints[1] == 0 || numPoints[2] == 0)
|
||||
{
|
||||
std::cerr << "Must have a non-zero amount of points in each direction.\n";
|
||||
}
|
||||
// in parallel, we do a simple partitioning in the x-direction.
|
||||
int mpiSize = 1;
|
||||
int mpiRank = 0;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
|
||||
|
||||
unsigned int startXPoint = mpiRank*numPoints[0]/mpiSize;
|
||||
unsigned int endXPoint = (mpiRank+1)*numPoints[0]/mpiSize;
|
||||
if(mpiSize != mpiRank+1)
|
||||
{
|
||||
endXPoint++;
|
||||
}
|
||||
|
||||
// create the points -- slowest in the x and fastest in the z directions
|
||||
double coord[3] = {0,0,0};
|
||||
for(unsigned int i=startXPoint;i<endXPoint;i++)
|
||||
{
|
||||
coord[0] = i*spacing[0];
|
||||
for(unsigned int j=0;j<numPoints[1];j++)
|
||||
{
|
||||
coord[1] = j*spacing[1];
|
||||
for(unsigned int k=0;k<numPoints[2];k++)
|
||||
{
|
||||
coord[2] = k*spacing[2];
|
||||
// add the coordinate to the end of the vector
|
||||
std::copy(coord, coord+3, std::back_inserter(this->Points));
|
||||
}
|
||||
}
|
||||
}
|
||||
// create the hex cells
|
||||
unsigned int cellPoints[8];
|
||||
unsigned int numXPoints = endXPoint - startXPoint;
|
||||
for(unsigned int i=0;i<numXPoints-1;i++)
|
||||
{
|
||||
for(unsigned int j=0;j<numPoints[1]-1;j++)
|
||||
{
|
||||
for(unsigned int k=0;k<numPoints[2]-1;k++)
|
||||
{
|
||||
cellPoints[0] = i*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k;
|
||||
cellPoints[1] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k;
|
||||
cellPoints[2] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k;
|
||||
cellPoints[3] = i*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k;
|
||||
cellPoints[4] = i*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k+1;
|
||||
cellPoints[5] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k+1;
|
||||
cellPoints[6] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k+1;
|
||||
cellPoints[7] = i*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k+1;
|
||||
std::copy(cellPoints, cellPoints+8, std::back_inserter(this->Cells));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t Grid::GetNumberOfPoints()
|
||||
{
|
||||
return this->Points.size()/3;
|
||||
}
|
||||
|
||||
size_t Grid::GetNumberOfCells()
|
||||
{
|
||||
return this->Cells.size()/8;
|
||||
}
|
||||
|
||||
double* Grid::GetPointsArray()
|
||||
{
|
||||
if(this->Points.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &(this->Points[0]);
|
||||
}
|
||||
|
||||
double* Grid::GetPoint(size_t pointId)
|
||||
{
|
||||
if(pointId >= this->Points.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &(this->Points[pointId*3]);
|
||||
}
|
||||
|
||||
unsigned int* Grid::GetCellPoints(size_t cellId)
|
||||
{
|
||||
if(cellId >= this->Cells.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &(this->Cells[cellId*8]);
|
||||
}
|
||||
|
||||
Attributes::Attributes()
|
||||
{
|
||||
this->GridPtr = NULL;
|
||||
}
|
||||
|
||||
void Attributes::Initialize(Grid* grid)
|
||||
{
|
||||
this->GridPtr = grid;
|
||||
}
|
||||
|
||||
void Attributes::UpdateFields(double time)
|
||||
{
|
||||
size_t numPoints = this->GridPtr->GetNumberOfPoints();
|
||||
this->Velocity.resize(numPoints*3);
|
||||
for(size_t pt=0;pt<numPoints;pt++)
|
||||
{
|
||||
double* coord = this->GridPtr->GetPoint(pt);
|
||||
this->Velocity[pt] = coord[1]*time;
|
||||
}
|
||||
std::fill(this->Velocity.begin()+numPoints, this->Velocity.end(), 0.);
|
||||
size_t numCells = this->GridPtr->GetNumberOfCells();
|
||||
this->Pressure.resize(numCells);
|
||||
std::fill(this->Pressure.begin(), this->Pressure.end(), 1.);
|
||||
}
|
||||
|
||||
double* Attributes::GetVelocityArray()
|
||||
{
|
||||
if(this->Velocity.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &this->Velocity[0];
|
||||
}
|
||||
|
||||
float* Attributes::GetPressureArray()
|
||||
{
|
||||
if(this->Pressure.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &this->Pressure[0];
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
#ifndef FEDATASTRUCTURES_HEADER
|
||||
#define FEDATASTRUCTURES_HEADER
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
class Grid
|
||||
{
|
||||
public:
|
||||
Grid();
|
||||
void Initialize(const unsigned int numPoints[3], const double spacing[3]);
|
||||
size_t GetNumberOfPoints();
|
||||
size_t GetNumberOfCells();
|
||||
double* GetPointsArray();
|
||||
double* GetPoint(size_t pointId);
|
||||
unsigned int* GetCellPoints(size_t cellId);
|
||||
private:
|
||||
std::vector<double> Points;
|
||||
std::vector<unsigned int> Cells;
|
||||
};
|
||||
|
||||
class Attributes
|
||||
{
|
||||
// A class for generating and storing point and cell fields.
|
||||
// Velocity is stored at the points and pressure is stored
|
||||
// for the cells. The current velocity profile is for a
|
||||
// shearing flow with U(y,t) = y*t, V = 0 and W = 0.
|
||||
// Pressure is constant through the domain.
|
||||
public:
|
||||
Attributes();
|
||||
void Initialize(Grid* grid);
|
||||
void UpdateFields(double time);
|
||||
double* GetVelocityArray();
|
||||
float* GetPressureArray();
|
||||
|
||||
private:
|
||||
std::vector<double> Velocity;
|
||||
std::vector<float> Pressure;
|
||||
Grid* GridPtr;
|
||||
};
|
||||
#endif
|
||||
51
ParaView-5.0.1/Examples/Catalyst/CxxFullExample/FEDriver.cxx
Normal file
51
ParaView-5.0.1/Examples/Catalyst/CxxFullExample/FEDriver.cxx
Normal file
@ -0,0 +1,51 @@
|
||||
#include "FEDataStructures.h"
|
||||
#include <mpi.h>
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
#include "FEAdaptor.h"
|
||||
#endif
|
||||
|
||||
// Example of a C++ adaptor for a simulation code
|
||||
// where the simulation code has a fixed topology
|
||||
// grid. We treat the grid as an unstructured
|
||||
// grid even though in the example provided it
|
||||
// would be best described as a vtkImageData.
|
||||
// Also, the points are stored in an inconsistent
|
||||
// manner with respect to the velocity vector.
|
||||
// This is purposefully done to demonstrate
|
||||
// the different approaches for getting data
|
||||
// into Catalyst. Note that through configuration
|
||||
// that the driver can be run without linking
|
||||
// to Catalyst.
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
MPI_Init(&argc, &argv);
|
||||
Grid grid;
|
||||
unsigned int numPoints[3] = {70, 60, 44};
|
||||
double spacing[3] = {1, 1.1, 1.3};
|
||||
grid.Initialize(numPoints, spacing);
|
||||
Attributes attributes;
|
||||
attributes.Initialize(&grid);
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::Initialize(argc, argv);
|
||||
#endif
|
||||
unsigned int numberOfTimeSteps = 100;
|
||||
for(unsigned int timeStep=0;timeStep<numberOfTimeSteps;timeStep++)
|
||||
{
|
||||
// use a time step length of 0.1
|
||||
double time = timeStep * 0.1;
|
||||
attributes.UpdateFields(time);
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::CoProcess(grid, attributes, time, timeStep, timeStep == numberOfTimeSteps-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::Finalize();
|
||||
#endif
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,189 @@
|
||||
from paraview.simple import *
|
||||
|
||||
from paraview import coprocessing
|
||||
|
||||
# --------------------- Cinema exporter definition ---------------------
|
||||
|
||||
def CreateCinemaExporter(input, frequency):
|
||||
from paraview import simple
|
||||
from paraview import data_exploration as cinema
|
||||
|
||||
class FullAnalysis(object):
|
||||
def __init__(self):
|
||||
self.center_of_rotation = [34.5, 32.45, 27.95]
|
||||
self.rotation_axis = [0.0, 0.0, 1.0]
|
||||
self.distance = 500.0
|
||||
self.exporters = []
|
||||
self.analysis = cinema.AnalysisManager( 'cinema', "Cinema", "Test various cinema exporter.")
|
||||
self.analysis.begin()
|
||||
min = 0.0
|
||||
max = 642.0
|
||||
self.lut = simple.GetColorTransferFunction(
|
||||
"velocity",
|
||||
RGBPoints=[min, 0.23, 0.299, 0.754, (min+max)*0.5, 0.865, 0.865, 0.865, max, 0.706, 0.016, 0.15])
|
||||
# ==
|
||||
self.createSliceExporter()
|
||||
self.createComposite()
|
||||
self.createImageResampler()
|
||||
self.simple360()
|
||||
|
||||
def createSliceExporter(self):
|
||||
self.analysis.register_analysis(
|
||||
"slice", # id
|
||||
"Slice exploration", # title
|
||||
"Perform 10 slice along X", # description
|
||||
"{time}/{sliceColor}_{slicePosition}.jpg", # data structure
|
||||
cinema.SliceExplorer.get_data_type())
|
||||
nb_slices = 5
|
||||
colorByArray = { "velocity": { "lut": self.lut , "type": 'POINT_DATA'} }
|
||||
view = simple.CreateRenderView()
|
||||
|
||||
fng = self.analysis.get_file_name_generator("slice")
|
||||
exporter = cinema.SliceExplorer(fng, view, input, colorByArray, nb_slices)
|
||||
exporter.set_analysis(self.analysis)
|
||||
self.exporters.append(exporter)
|
||||
|
||||
def createComposite(self):
|
||||
try:
|
||||
simple.LoadDistributedPlugin("RGBZView", ns=globals())
|
||||
self.analysis.register_analysis(
|
||||
"composite",
|
||||
"Composite rendering",
|
||||
"Performing composite on contour",
|
||||
'{time}/{theta}/{phi}/{filename}', cinema.CompositeImageExporter.get_data_type())
|
||||
fng = self.analysis.get_file_name_generator("composite")
|
||||
|
||||
# Create pipeline to compose
|
||||
color_type = [('POINT_DATA', "velocity")]
|
||||
luts = { "velocity": self.lut }
|
||||
filters = [ input ]
|
||||
filters_description = [ {'name': 'catalyst'} ]
|
||||
color_by = [ color_type ]
|
||||
|
||||
# Data exploration ------------------------------------------------------------
|
||||
camera_handler = cinema.ThreeSixtyCameraHandler(fng, None, [ float(r) for r in range(0, 360, 72)], [ float(r) for r in range(-60, 61, 45)], self.center_of_rotation, self.rotation_axis, self.distance)
|
||||
exporter = cinema.CompositeImageExporter(fng, filters, color_by, luts, camera_handler, [400,400], filters_description, 0, 0)
|
||||
exporter.set_analysis(self.analysis)
|
||||
self.exporters.append(exporter)
|
||||
except:
|
||||
print "Skip RGBZView exporter"
|
||||
|
||||
def createImageResampler(self):
|
||||
self.analysis.register_analysis(
|
||||
"interactive-prober", # id
|
||||
"Interactive prober", # title
|
||||
"Sample data in image stack for line probing", # description
|
||||
"{time}/{field}/{slice}.{format}", # data structure
|
||||
cinema.ImageResampler.get_data_type())
|
||||
fng = self.analysis.get_file_name_generator("interactive-prober")
|
||||
arrays = { "velocity" : self.lut }
|
||||
exporter = cinema.ImageResampler(fng, input, [50,50,50], arrays)
|
||||
self.exporters.append(exporter)
|
||||
|
||||
def simple360(self):
|
||||
self.analysis.register_analysis(
|
||||
"360", # id
|
||||
"rotation", # title
|
||||
"Perform 15 contour", # description
|
||||
"{time}/{theta}_{phi}.jpg", # data structure
|
||||
cinema.ThreeSixtyImageStackExporter.get_data_type())
|
||||
fng = self.analysis.get_file_name_generator("360")
|
||||
arrayName = ('POINT_DATA', 'velocity')
|
||||
view = simple.CreateRenderView()
|
||||
|
||||
rep = simple.Show(input, view)
|
||||
rep.LookupTable = self.lut
|
||||
rep.ColorArrayName = arrayName
|
||||
|
||||
exporter = cinema.ThreeSixtyImageStackExporter(fng, view, self.center_of_rotation, self.distance, self.rotation_axis, [20,45])
|
||||
self.exporters.append(exporter)
|
||||
|
||||
def UpdatePipeline(self, time):
|
||||
if time % frequency != 0:
|
||||
return
|
||||
|
||||
# Do the exploration work
|
||||
for exporter in self.exporters:
|
||||
exporter.UpdatePipeline(time)
|
||||
|
||||
def Finalize(self):
|
||||
self.analysis.end()
|
||||
|
||||
return FullAnalysis()
|
||||
|
||||
# ----------------------- CoProcessor definition -----------------------
|
||||
|
||||
def CreateCoProcessor():
|
||||
def _CreatePipeline(coprocessor, datadescription):
|
||||
class Pipeline:
|
||||
filename_3_pvtu = coprocessor.CreateProducer( datadescription, "input" )
|
||||
|
||||
Slice1 = Slice( guiName="Slice1", Crinkleslice=0, SliceOffsetValues=[0.0], Triangulatetheslice=1, SliceType="Plane" )
|
||||
Slice1.SliceType.Offset = 0.0
|
||||
Slice1.SliceType.Origin = [34.5, 32.45, 27.95]
|
||||
Slice1.SliceType.Normal = [1.0, 0.0, 0.0]
|
||||
|
||||
ParallelPolyDataWriter1 = coprocessor.CreateWriter( XMLPPolyDataWriter, "slice_%t.pvtp", 10 )
|
||||
|
||||
# Add cinema exploration
|
||||
# coprocessor.RegisterExporter(CreateCinemaExporter(filename_3_pvtu, 2)) acbauer -- this should be the one to use
|
||||
CreateCinemaExporter(filename_3_pvtu, 2)
|
||||
|
||||
return Pipeline()
|
||||
|
||||
class CoProcessor(coprocessing.CoProcessor):
|
||||
def CreatePipeline(self, datadescription):
|
||||
self.Pipeline = _CreatePipeline(self, datadescription)
|
||||
|
||||
coprocessor = CoProcessor()
|
||||
freqs = {'input': [10, 100]}
|
||||
coprocessor.SetUpdateFrequencies(freqs)
|
||||
return coprocessor
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Global variables that will hold the pipeline for each timestep
|
||||
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
|
||||
# It will be automatically setup when coprocessor.UpdateProducers() is called the
|
||||
# first time.
|
||||
coprocessor = CreateCoProcessor()
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Enable Live-Visualizaton with ParaView
|
||||
coprocessor.EnableLiveVisualization(False)
|
||||
|
||||
|
||||
# ---------------------- Data Selection method ----------------------
|
||||
|
||||
def RequestDataDescription(datadescription):
|
||||
"Callback to populate the request for current timestep"
|
||||
global coprocessor
|
||||
if datadescription.GetForceOutput() == True:
|
||||
# We are just going to request all fields and meshes from the simulation
|
||||
# code/adaptor.
|
||||
for i in range(datadescription.GetNumberOfInputDescriptions()):
|
||||
datadescription.GetInputDescription(i).AllFieldsOn()
|
||||
datadescription.GetInputDescription(i).GenerateMeshOn()
|
||||
return
|
||||
|
||||
# setup requests for all inputs based on the requirements of the
|
||||
# pipeline.
|
||||
coprocessor.LoadRequestedData(datadescription)
|
||||
|
||||
# ------------------------ Processing method ------------------------
|
||||
|
||||
def DoCoProcessing(datadescription):
|
||||
"Callback to do co-processing for current timestep"
|
||||
global coprocessor
|
||||
|
||||
# Update the coprocessor by providing it the newly generated simulation data.
|
||||
# If the pipeline hasn't been setup yet, this will setup the pipeline.
|
||||
coprocessor.UpdateProducers(datadescription)
|
||||
|
||||
# Write output data, if appropriate.
|
||||
coprocessor.WriteData(datadescription);
|
||||
|
||||
# Write image capture (Last arg: rescale lookup table), if appropriate.
|
||||
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
|
||||
|
||||
# Live Visualization, if enabled.
|
||||
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)
|
||||
@ -0,0 +1,86 @@
|
||||
|
||||
try: paraview.simple
|
||||
except: from paraview.simple import *
|
||||
|
||||
from paraview import coprocessing
|
||||
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Code generated from cpstate.py to create the CoProcessor.
|
||||
|
||||
|
||||
# ----------------------- CoProcessor definition -----------------------
|
||||
|
||||
def CreateCoProcessor():
|
||||
def _CreatePipeline(coprocessor, datadescription):
|
||||
class Pipeline:
|
||||
filename_3_pvtu = coprocessor.CreateProducer( datadescription, "input" )
|
||||
|
||||
Slice1 = Slice( guiName="Slice1", Crinkleslice=0, SliceOffsetValues=[0.0], Triangulatetheslice=1, SliceType="Plane" )
|
||||
Slice1.SliceType.Offset = 0.0
|
||||
Slice1.SliceType.Origin = [34.5, 32.45, 27.95]
|
||||
Slice1.SliceType.Normal = [1.0, 0.0, 0.0]
|
||||
|
||||
ParallelPolyDataWriter1 = coprocessor.CreateWriter( XMLPPolyDataWriter, "slice_%t.pvtp", 10 )
|
||||
|
||||
SetActiveSource(filename_3_pvtu)
|
||||
ParallelUnstructuredGridWriter1 = coprocessor.CreateWriter( XMLPUnstructuredGridWriter, "fullgrid_%t.pvtu", 100 )
|
||||
|
||||
return Pipeline()
|
||||
|
||||
class CoProcessor(coprocessing.CoProcessor):
|
||||
def CreatePipeline(self, datadescription):
|
||||
self.Pipeline = _CreatePipeline(self, datadescription)
|
||||
|
||||
coprocessor = CoProcessor()
|
||||
freqs = {'input': [10, 100]}
|
||||
coprocessor.SetUpdateFrequencies(freqs)
|
||||
return coprocessor
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Global variables that will hold the pipeline for each timestep
|
||||
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
|
||||
# It will be automatically setup when coprocessor.UpdateProducers() is called the
|
||||
# first time.
|
||||
coprocessor = CreateCoProcessor()
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Enable Live-Visualizaton with ParaView
|
||||
coprocessor.EnableLiveVisualization(False)
|
||||
|
||||
|
||||
# ---------------------- Data Selection method ----------------------
|
||||
|
||||
def RequestDataDescription(datadescription):
|
||||
"Callback to populate the request for current timestep"
|
||||
global coprocessor
|
||||
if datadescription.GetForceOutput() == True:
|
||||
# We are just going to request all fields and meshes from the simulation
|
||||
# code/adaptor.
|
||||
for i in range(datadescription.GetNumberOfInputDescriptions()):
|
||||
datadescription.GetInputDescription(i).AllFieldsOn()
|
||||
datadescription.GetInputDescription(i).GenerateMeshOn()
|
||||
return
|
||||
|
||||
# setup requests for all inputs based on the requirements of the
|
||||
# pipeline.
|
||||
coprocessor.LoadRequestedData(datadescription)
|
||||
|
||||
# ------------------------ Processing method ------------------------
|
||||
|
||||
def DoCoProcessing(datadescription):
|
||||
"Callback to do co-processing for current timestep"
|
||||
global coprocessor
|
||||
|
||||
# Update the coprocessor by providing it the newly generated simulation data.
|
||||
# If the pipeline hasn't been setup yet, this will setup the pipeline.
|
||||
coprocessor.UpdateProducers(datadescription)
|
||||
|
||||
# Write output data, if appropriate.
|
||||
coprocessor.WriteData(datadescription);
|
||||
|
||||
# Write image capture (Last arg: rescale lookup table), if appropriate.
|
||||
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
|
||||
|
||||
# Live Visualization, if enabled.
|
||||
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)
|
||||
@ -0,0 +1,38 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(CatalystCxxImageDataExample)
|
||||
|
||||
set(USE_CATALYST ON CACHE BOOL "Link the simulator with Catalyst")
|
||||
if(USE_CATALYST)
|
||||
find_package(ParaView 4.1 REQUIRED COMPONENTS vtkPVPythonCatalyst)
|
||||
include("${PARAVIEW_USE_FILE}")
|
||||
set(Adaptor_SRCS
|
||||
FEAdaptor.cxx
|
||||
)
|
||||
add_library(CxxImageDataExampleAdaptor ${Adaptor_SRCS})
|
||||
target_link_libraries(CxxImageDataExampleAdaptor vtkPVPythonCatalyst)
|
||||
add_definitions("-DUSE_CATALYST")
|
||||
if(NOT PARAVIEW_USE_MPI)
|
||||
message(SEND_ERROR "ParaView must be built with MPI enabled")
|
||||
endif()
|
||||
else()
|
||||
find_package(MPI REQUIRED)
|
||||
include_directories(${MPI_CXX_INCLUDE_PATH})
|
||||
endif()
|
||||
|
||||
add_executable(CxxImageDataExample FEDriver.cxx FEDataStructures.cxx)
|
||||
if(USE_CATALYST)
|
||||
target_link_libraries(CxxImageDataExample LINK_PRIVATE CxxImageDataExampleAdaptor)
|
||||
include(vtkModuleMacros)
|
||||
include(vtkMPI)
|
||||
vtk_mpi_link(CxxImageDataExample)
|
||||
else()
|
||||
target_link_libraries(CxxImageDataExample LINK_PRIVATE ${MPI_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_test(NAME CxxImageDataExampleTest COMMAND CxxImageDataExample ${CMAKE_CURRENT_SOURCE_DIR}/SampleScripts/feslicescript.py)
|
||||
set_tests_properties(CxxImageDataExampleTest PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
endif()
|
||||
@ -0,0 +1,151 @@
|
||||
#include <iostream>
|
||||
#include "FEAdaptor.h"
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkCellType.h>
|
||||
#include <vtkCPDataDescription.h>
|
||||
#include <vtkCPInputDataDescription.h>
|
||||
#include <vtkCPProcessor.h>
|
||||
#include <vtkCPPythonScriptPipeline.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkFloatArray.h>
|
||||
#include <vtkImageData.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkPoints.h>
|
||||
#include <vtkPointData.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
vtkCPProcessor* Processor = NULL;
|
||||
vtkImageData* VTKGrid = NULL;
|
||||
|
||||
void BuildVTKGrid(Grid& grid)
|
||||
{
|
||||
// The grid structure isn't changing so we only build it
|
||||
// the first time it's needed. If we needed the memory
|
||||
// we could delete it and rebuild as necessary.
|
||||
if(VTKGrid == NULL)
|
||||
{
|
||||
VTKGrid = vtkImageData::New();
|
||||
int extent[6];
|
||||
for(int i=0;i<6;i++)
|
||||
{
|
||||
extent[i] = grid.GetExtent()[i];
|
||||
}
|
||||
VTKGrid->SetExtent(extent);
|
||||
VTKGrid->SetSpacing(grid.GetSpacing());
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateVTKAttributes(Grid& grid, Attributes& attributes)
|
||||
{
|
||||
if(VTKGrid->GetPointData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// velocity array
|
||||
vtkNew<vtkDoubleArray> velocity;
|
||||
velocity->SetName("velocity");
|
||||
velocity->SetNumberOfComponents(3);
|
||||
velocity->SetNumberOfTuples(static_cast<vtkIdType>(grid.GetNumberOfLocalPoints()));
|
||||
VTKGrid->GetPointData()->AddArray(velocity.GetPointer());
|
||||
}
|
||||
if(VTKGrid->GetCellData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// pressure array
|
||||
vtkNew<vtkFloatArray> pressure;
|
||||
pressure->SetName("pressure");
|
||||
pressure->SetNumberOfComponents(1);
|
||||
VTKGrid->GetCellData()->AddArray(pressure.GetPointer());
|
||||
}
|
||||
vtkDoubleArray* velocity = vtkDoubleArray::SafeDownCast(
|
||||
VTKGrid->GetPointData()->GetArray("velocity"));
|
||||
// The velocity array is ordered as vx0,vx1,vx2,..,vy0,vy1,vy2,..,vz0,vz1,vz2,..
|
||||
// so we need to create a full copy of it with VTK's ordering of
|
||||
// vx0,vy0,vz0,vx1,vy1,vz1,..
|
||||
double* velocityData = attributes.GetVelocityArray();
|
||||
vtkIdType numTuples = velocity->GetNumberOfTuples();
|
||||
for(vtkIdType i=0;i<numTuples;i++)
|
||||
{
|
||||
double values[3] = {velocityData[i], velocityData[i+numTuples],
|
||||
velocityData[i+2*numTuples]};
|
||||
velocity->SetTupleValue(i, values);
|
||||
}
|
||||
|
||||
vtkFloatArray* pressure = vtkFloatArray::SafeDownCast(
|
||||
VTKGrid->GetCellData()->GetArray("pressure"));
|
||||
// The pressure array is a scalar array so we can reuse
|
||||
// memory as long as we ordered the points properly.
|
||||
float* pressureData = attributes.GetPressureArray();
|
||||
pressure->SetArray(pressureData, static_cast<vtkIdType>(grid.GetNumberOfLocalCells()), 1);
|
||||
}
|
||||
|
||||
void BuildVTKDataStructures(Grid& grid, Attributes& attributes)
|
||||
{
|
||||
BuildVTKGrid(grid);
|
||||
UpdateVTKAttributes(grid, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
|
||||
void Initialize(int numScripts, char* scripts[])
|
||||
{
|
||||
if(Processor == NULL)
|
||||
{
|
||||
Processor = vtkCPProcessor::New();
|
||||
Processor->Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
Processor->RemoveAllPipelines();
|
||||
}
|
||||
for(int i=1;i<numScripts;i++)
|
||||
{
|
||||
vtkNew<vtkCPPythonScriptPipeline> pipeline;
|
||||
pipeline->Initialize(scripts[i]);
|
||||
Processor->AddPipeline(pipeline.GetPointer());
|
||||
}
|
||||
}
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
if(Processor)
|
||||
{
|
||||
Processor->Delete();
|
||||
Processor = NULL;
|
||||
}
|
||||
if(VTKGrid)
|
||||
{
|
||||
VTKGrid->Delete();
|
||||
VTKGrid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep)
|
||||
{
|
||||
vtkNew<vtkCPDataDescription> dataDescription;
|
||||
dataDescription->AddInput("input");
|
||||
dataDescription->SetTimeData(time, timeStep);
|
||||
if(lastTimeStep == true)
|
||||
{
|
||||
// assume that we want to all the pipelines to execute if it
|
||||
// is the last time step.
|
||||
dataDescription->ForceOutputOn();
|
||||
}
|
||||
if(Processor->RequestDataDescription(dataDescription.GetPointer()) != 0)
|
||||
{
|
||||
BuildVTKDataStructures(grid, attributes);
|
||||
dataDescription->GetInputDescriptionByName("input")->SetGrid(VTKGrid);
|
||||
int wholeExtent[6];
|
||||
for(int i=0;i<6;i++)
|
||||
{
|
||||
wholeExtent[i] = grid.GetNumPoints()[i];
|
||||
}
|
||||
|
||||
dataDescription->GetInputDescriptionByName("input")->SetWholeExtent(wholeExtent);
|
||||
Processor->CoProcess(dataDescription.GetPointer());
|
||||
}
|
||||
}
|
||||
} // end of Catalyst namespace
|
||||
@ -0,0 +1,17 @@
|
||||
#ifndef FEADAPTOR_HEADER
|
||||
#define FEADAPTOR_HEADER
|
||||
|
||||
class Attributes;
|
||||
class Grid;
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
void Initialize(int numScripts, char* scripts[]);
|
||||
|
||||
void Finalize();
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,122 @@
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <mpi.h>
|
||||
#include <assert.h>
|
||||
|
||||
Grid::Grid()
|
||||
{
|
||||
this->NumPoints[0] = this->NumPoints[1] = this->NumPoints[2] = 0;
|
||||
this->Spacing[0] = this->Spacing[1] = this->Spacing[2] = 0;
|
||||
}
|
||||
|
||||
void Grid::Initialize(const unsigned int numPoints[3], const double spacing[3] )
|
||||
{
|
||||
if(numPoints[0] == 0 || numPoints[1] == 0 || numPoints[2] == 0)
|
||||
{
|
||||
std::cerr << "Must have a non-zero amount of points in each direction.\n";
|
||||
}
|
||||
for(int i=0;i<3;i++)
|
||||
{
|
||||
this->NumPoints[i] = numPoints[i];
|
||||
this->Spacing[i] = spacing[i];
|
||||
}
|
||||
int mpiRank = 0, mpiSize = 1;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
|
||||
this->Extent[0] = mpiRank*numPoints[0]/mpiSize;
|
||||
this->Extent[1] = (mpiRank+1)*numPoints[0]/mpiSize;
|
||||
if(mpiSize != mpiRank+1)
|
||||
{
|
||||
this->Extent[1]++;
|
||||
}
|
||||
this->Extent[2] = this->Extent[4] = 0;
|
||||
this->Extent[3] = numPoints[1];
|
||||
this->Extent[5] = numPoints[2];
|
||||
}
|
||||
|
||||
unsigned int Grid::GetNumberOfLocalPoints()
|
||||
{
|
||||
return (this->Extent[1]-this->Extent[0]+1)*(this->Extent[3]-this->Extent[2]+1)*
|
||||
(this->Extent[5]-this->Extent[4]+1);
|
||||
}
|
||||
|
||||
unsigned int Grid::GetNumberOfLocalCells()
|
||||
{
|
||||
return (this->Extent[1]-this->Extent[0])*(this->Extent[3]-this->Extent[2])*
|
||||
(this->Extent[5]-this->Extent[4]);
|
||||
}
|
||||
|
||||
void Grid::GetLocalPoint(unsigned int pointId, double* point)
|
||||
{
|
||||
unsigned int logicalX = pointId%(this->Extent[1]-this->Extent[0]+1);
|
||||
assert(logicalX <= this->Extent[1]);
|
||||
point[0] = this->Spacing[0]*logicalX;
|
||||
unsigned int logicalY = pointId%((this->Extent[1]-this->Extent[0]+1)*(this->Extent[3]-this->Extent[2]+1));
|
||||
logicalY /= this->Extent[1]-this->Extent[0]+1;
|
||||
assert(logicalY <= this->Extent[3]);
|
||||
point[1] = this->Spacing[1]*logicalY;
|
||||
unsigned int logicalZ = pointId/((this->Extent[1]-this->Extent[0]+1)*
|
||||
(this->Extent[3]-this->Extent[2]+1));
|
||||
assert(logicalZ <= this->Extent[5]);
|
||||
point[2] = this->Spacing[2]*logicalZ;
|
||||
}
|
||||
|
||||
unsigned int* Grid::GetNumPoints()
|
||||
{
|
||||
return this->NumPoints;
|
||||
}
|
||||
|
||||
unsigned int* Grid::GetExtent()
|
||||
{
|
||||
return this->Extent;
|
||||
}
|
||||
|
||||
double* Grid::GetSpacing()
|
||||
{
|
||||
return this->Spacing;
|
||||
}
|
||||
|
||||
Attributes::Attributes()
|
||||
{
|
||||
this->GridPtr = NULL;
|
||||
}
|
||||
|
||||
void Attributes::Initialize(Grid* grid)
|
||||
{
|
||||
this->GridPtr = grid;
|
||||
}
|
||||
|
||||
void Attributes::UpdateFields(double time)
|
||||
{
|
||||
unsigned int numPoints = this->GridPtr->GetNumberOfLocalPoints();
|
||||
this->Velocity.resize(numPoints*3);
|
||||
for(unsigned int pt=0;pt<numPoints;pt++)
|
||||
{
|
||||
double coord[3];
|
||||
this->GridPtr->GetLocalPoint(pt, coord);
|
||||
this->Velocity[pt] = coord[1]*time;
|
||||
}
|
||||
std::fill(this->Velocity.begin()+numPoints, this->Velocity.end(), 0.);
|
||||
unsigned int numCells = this->GridPtr->GetNumberOfLocalCells();
|
||||
this->Pressure.resize(numCells);
|
||||
std::fill(this->Pressure.begin(), this->Pressure.end(), 1.);
|
||||
}
|
||||
|
||||
double* Attributes::GetVelocityArray()
|
||||
{
|
||||
if(this->Velocity.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &this->Velocity[0];
|
||||
}
|
||||
|
||||
float* Attributes::GetPressureArray()
|
||||
{
|
||||
if(this->Pressure.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &this->Pressure[0];
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
#ifndef FEDATASTRUCTURES_HEADER
|
||||
#define FEDATASTRUCTURES_HEADER
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
class Grid
|
||||
{
|
||||
public:
|
||||
Grid();
|
||||
void Initialize(const unsigned int numPoints[3], const double spacing[3]);
|
||||
unsigned int GetNumberOfLocalPoints();
|
||||
unsigned int GetNumberOfLocalCells();
|
||||
void GetLocalPoint(unsigned int pointId, double* point);
|
||||
unsigned int* GetNumPoints();
|
||||
unsigned int* GetExtent();
|
||||
double* GetSpacing();
|
||||
private:
|
||||
unsigned int NumPoints[3];
|
||||
unsigned int Extent[6];
|
||||
double Spacing[3];
|
||||
};
|
||||
|
||||
class Attributes
|
||||
{
|
||||
// A class for generating and storing point and cell fields.
|
||||
// Velocity is stored at the points and pressure is stored
|
||||
// for the cells. The current velocity profile is for a
|
||||
// shearing flow with U(y,t) = y*t, V = 0 and W = 0.
|
||||
// Pressure is constant through the domain.
|
||||
public:
|
||||
Attributes();
|
||||
void Initialize(Grid* grid);
|
||||
void UpdateFields(double time);
|
||||
double* GetVelocityArray();
|
||||
float* GetPressureArray();
|
||||
|
||||
private:
|
||||
std::vector<double> Velocity;
|
||||
std::vector<float> Pressure;
|
||||
Grid* GridPtr;
|
||||
};
|
||||
#endif
|
||||
@ -0,0 +1,51 @@
|
||||
#include "FEDataStructures.h"
|
||||
#include <mpi.h>
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
#include "FEAdaptor.h"
|
||||
#endif
|
||||
|
||||
// Example of a C++ adaptor for a simulation code
|
||||
// where the simulation code has a fixed topology
|
||||
// grid. We treat the grid as an unstructured
|
||||
// grid even though in the example provided it
|
||||
// would be best described as a vtkImageData.
|
||||
// Also, the points are stored in an inconsistent
|
||||
// manner with respect to the velocity vector.
|
||||
// This is purposefully done to demonstrate
|
||||
// the different approaches for getting data
|
||||
// into Catalyst. Note that through configuration
|
||||
// that the driver can be run without linking
|
||||
// to Catalyst.
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
MPI_Init(&argc, &argv);
|
||||
Grid grid;
|
||||
unsigned int numPoints[3] = {70, 60, 44};
|
||||
double spacing[3] = {1, 1.1, 1.3};
|
||||
grid.Initialize(numPoints, spacing);
|
||||
Attributes attributes;
|
||||
attributes.Initialize(&grid);
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::Initialize(argc, argv);
|
||||
#endif
|
||||
unsigned int numberOfTimeSteps = 100;
|
||||
for(unsigned int timeStep=0;timeStep<numberOfTimeSteps;timeStep++)
|
||||
{
|
||||
// use a time step length of 0.1
|
||||
double time = timeStep * 0.1;
|
||||
attributes.UpdateFields(time);
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::CoProcess(grid, attributes, time, timeStep, timeStep == numberOfTimeSteps-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::Finalize();
|
||||
#endif
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
try: paraview.simple
|
||||
except: from paraview.simple import *
|
||||
|
||||
from paraview import coprocessing
|
||||
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Code generated from cpstate.py to create the CoProcessor.
|
||||
|
||||
|
||||
# ----------------------- CoProcessor definition -----------------------
|
||||
|
||||
def CreateCoProcessor():
|
||||
def _CreatePipeline(coprocessor, datadescription):
|
||||
class Pipeline:
|
||||
filename_2_pvti = coprocessor.CreateProducer( datadescription, "input" )
|
||||
|
||||
ParallelImageDataWriter1 = coprocessor.CreateWriter( XMLPImageDataWriter, "fullgrid_%t.pvti", 100 )
|
||||
|
||||
SetActiveSource(filename_2_pvti)
|
||||
Slice1 = Slice( guiName="Slice1", Crinkleslice=0, SliceOffsetValues=[0.0], Triangulatetheslice=1, SliceType="Plane" )
|
||||
Slice1.SliceType.Offset = 0.0
|
||||
Slice1.SliceType.Origin = [9.0, 33.0, 28.6]
|
||||
Slice1.SliceType.Normal = [1.0, 0.0, 0.0]
|
||||
|
||||
ParallelPolyDataWriter1 = coprocessor.CreateWriter( XMLPPolyDataWriter, "slice_%t.pvtp", 10 )
|
||||
|
||||
return Pipeline()
|
||||
|
||||
class CoProcessor(coprocessing.CoProcessor):
|
||||
def CreatePipeline(self, datadescription):
|
||||
self.Pipeline = _CreatePipeline(self, datadescription)
|
||||
|
||||
coprocessor = CoProcessor()
|
||||
freqs = {'input': [10, 100]}
|
||||
coprocessor.SetUpdateFrequencies(freqs)
|
||||
return coprocessor
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Global variables that will hold the pipeline for each timestep
|
||||
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
|
||||
# It will be automatically setup when coprocessor.UpdateProducers() is called the
|
||||
# first time.
|
||||
coprocessor = CreateCoProcessor()
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Enable Live-Visualizaton with ParaView
|
||||
coprocessor.EnableLiveVisualization(False)
|
||||
|
||||
|
||||
# ---------------------- Data Selection method ----------------------
|
||||
|
||||
def RequestDataDescription(datadescription):
|
||||
"Callback to populate the request for current timestep"
|
||||
global coprocessor
|
||||
if datadescription.GetForceOutput() == True:
|
||||
# We are just going to request all fields and meshes from the simulation
|
||||
# code/adaptor.
|
||||
for i in range(datadescription.GetNumberOfInputDescriptions()):
|
||||
datadescription.GetInputDescription(i).AllFieldsOn()
|
||||
datadescription.GetInputDescription(i).GenerateMeshOn()
|
||||
return
|
||||
|
||||
# setup requests for all inputs based on the requirements of the
|
||||
# pipeline.
|
||||
coprocessor.LoadRequestedData(datadescription)
|
||||
|
||||
# ------------------------ Processing method ------------------------
|
||||
|
||||
def DoCoProcessing(datadescription):
|
||||
"Callback to do co-processing for current timestep"
|
||||
global coprocessor
|
||||
|
||||
# Update the coprocessor by providing it the newly generated simulation data.
|
||||
# If the pipeline hasn't been setup yet, this will setup the pipeline.
|
||||
coprocessor.UpdateProducers(datadescription)
|
||||
|
||||
# Write output data, if appropriate.
|
||||
coprocessor.WriteData(datadescription);
|
||||
|
||||
# Write image capture (Last arg: rescale lookup table), if appropriate.
|
||||
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
|
||||
|
||||
# Live Visualization, if enabled.
|
||||
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)
|
||||
@ -0,0 +1,38 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(CxxMappedDataArrayExample)
|
||||
|
||||
set(USE_CATALYST ON CACHE BOOL "Link the simulator with Catalyst")
|
||||
if(USE_CATALYST)
|
||||
find_package(ParaView 4.1 REQUIRED COMPONENTS vtkPVPythonCatalyst)
|
||||
include("${PARAVIEW_USE_FILE}")
|
||||
set(Adaptor_SRCS
|
||||
FEAdaptor.cxx
|
||||
)
|
||||
add_library(CxxMappedDataArrayExampleAdaptor ${Adaptor_SRCS})
|
||||
target_link_libraries(CxxMappedDataArrayExampleAdaptor vtkPVPythonCatalyst vtkParallelMPI)
|
||||
add_definitions("-DUSE_CATALYST")
|
||||
if(NOT PARAVIEW_USE_MPI)
|
||||
message(SEND_ERROR "ParaView must be built with MPI enabled")
|
||||
endif()
|
||||
else()
|
||||
find_package(MPI REQUIRED)
|
||||
include_directories(${MPI_C_INCLUDE_PATH})
|
||||
endif()
|
||||
|
||||
add_executable(CxxMappedDataArrayExample FEDriver.cxx FEDataStructures.cxx)
|
||||
if(USE_CATALYST)
|
||||
target_link_libraries(CxxMappedDataArrayExample LINK_PRIVATE CxxMappedDataArrayExampleAdaptor)
|
||||
include(vtkModuleMacros)
|
||||
include(vtkMPI)
|
||||
vtk_mpi_link(CxxMappedDataArrayExample)
|
||||
else()
|
||||
target_link_libraries(CxxMappedDataArrayExample LINK_PRIVATE ${MPI_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_test(NAME CxxMappedDataArrayExampleTest COMMAND CxxMappedDataArrayExample ${CMAKE_CURRENT_SOURCE_DIR}/SampleScripts/feslicescript.py)
|
||||
set_tests_properties(CxxMappedDataArrayExampleTest PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
endif()
|
||||
@ -0,0 +1,151 @@
|
||||
#include <iostream>
|
||||
#include "FEAdaptor.h"
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkCellType.h>
|
||||
#include <vtkCPDataDescription.h>
|
||||
#include <vtkCPInputDataDescription.h>
|
||||
#include <vtkCPProcessor.h>
|
||||
#include <vtkCPPythonScriptPipeline.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkFloatArray.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkPoints.h>
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
|
||||
#include "vtkCPMappedVectorArrayTemplate.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
vtkCPProcessor* Processor = NULL;
|
||||
vtkUnstructuredGrid* VTKGrid;
|
||||
|
||||
void BuildVTKGrid(Grid& grid)
|
||||
{
|
||||
// create the points information
|
||||
vtkCPMappedVectorArrayTemplate<double>* pointArray =
|
||||
vtkCPMappedVectorArrayTemplate<double>::New();
|
||||
|
||||
pointArray->SetVectorArray(grid.GetPointsArray(),static_cast<vtkIdType>(grid.GetNumberOfPoints()));
|
||||
vtkNew<vtkPoints> points;
|
||||
points->SetData(pointArray);
|
||||
pointArray->Delete();
|
||||
VTKGrid->SetPoints(points.GetPointer());
|
||||
|
||||
// create the cells
|
||||
size_t numCells = grid.GetNumberOfCells();
|
||||
VTKGrid->Allocate(static_cast<vtkIdType>(numCells*9));
|
||||
for(size_t cell=0;cell<numCells;cell++)
|
||||
{
|
||||
unsigned int* cellPoints = grid.GetCellPoints(cell);
|
||||
vtkIdType tmp[8] = {cellPoints[0], cellPoints[1], cellPoints[2], cellPoints[3],
|
||||
cellPoints[4], cellPoints[5], cellPoints[6], cellPoints[7]};
|
||||
VTKGrid->InsertNextCell(VTK_HEXAHEDRON, 8, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateVTKAttributes(Grid& grid, Attributes& attributes)
|
||||
{
|
||||
if(VTKGrid->GetPointData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// velocity array
|
||||
vtkCPMappedVectorArrayTemplate<double>* velocity =
|
||||
vtkCPMappedVectorArrayTemplate<double>::New();
|
||||
velocity->SetName("velocity");
|
||||
VTKGrid->GetPointData()->AddArray(velocity);
|
||||
velocity->Delete();
|
||||
}
|
||||
vtkCPMappedVectorArrayTemplate<double>* velocity =
|
||||
vtkCPMappedVectorArrayTemplate<double>::SafeDownCast(
|
||||
VTKGrid->GetPointData()->GetArray("velocity"));
|
||||
velocity->SetVectorArray(attributes.GetVelocityArray(),
|
||||
VTKGrid->GetNumberOfPoints());
|
||||
|
||||
if(VTKGrid->GetCellData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// pressure array
|
||||
vtkNew<vtkFloatArray> pressure;
|
||||
pressure->SetName("pressure");
|
||||
pressure->SetNumberOfComponents(1);
|
||||
VTKGrid->GetCellData()->AddArray(pressure.GetPointer());
|
||||
}
|
||||
vtkFloatArray* pressure = vtkFloatArray::SafeDownCast(
|
||||
VTKGrid->GetCellData()->GetArray("pressure"));
|
||||
// The pressure array is a scalar array so we can reuse
|
||||
// memory as long as we ordered the points properly.
|
||||
float* pressureData = attributes.GetPressureArray();
|
||||
pressure->SetArray(pressureData, static_cast<vtkIdType>(grid.GetNumberOfCells()), 1);
|
||||
}
|
||||
|
||||
void BuildVTKDataStructures(Grid& grid, Attributes& attributes)
|
||||
{
|
||||
if(VTKGrid == NULL)
|
||||
{
|
||||
// The grid structure isn't changing so we only build it
|
||||
// the first time it's needed. If we needed the memory
|
||||
// we could delete it and rebuild as necessary.
|
||||
VTKGrid = vtkUnstructuredGrid::New();
|
||||
BuildVTKGrid(grid);
|
||||
}
|
||||
UpdateVTKAttributes(grid, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
|
||||
void Initialize(int numScripts, char* scripts[])
|
||||
{
|
||||
if(Processor == NULL)
|
||||
{
|
||||
Processor = vtkCPProcessor::New();
|
||||
Processor->Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
Processor->RemoveAllPipelines();
|
||||
}
|
||||
for(int i=1;i<numScripts;i++)
|
||||
{
|
||||
vtkNew<vtkCPPythonScriptPipeline> pipeline;
|
||||
pipeline->Initialize(scripts[i]);
|
||||
Processor->AddPipeline(pipeline.GetPointer());
|
||||
}
|
||||
}
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
if(Processor)
|
||||
{
|
||||
Processor->Delete();
|
||||
Processor = NULL;
|
||||
}
|
||||
if(VTKGrid)
|
||||
{
|
||||
VTKGrid->Delete();
|
||||
VTKGrid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep)
|
||||
{
|
||||
vtkNew<vtkCPDataDescription> dataDescription;
|
||||
dataDescription->AddInput("input");
|
||||
dataDescription->SetTimeData(time, timeStep);
|
||||
if(lastTimeStep == true)
|
||||
{
|
||||
// assume that we want to all the pipelines to execute if it
|
||||
// is the last time step.
|
||||
dataDescription->ForceOutputOn();
|
||||
}
|
||||
if(Processor->RequestDataDescription(dataDescription.GetPointer()) != 0)
|
||||
{
|
||||
BuildVTKDataStructures(grid, attributes);
|
||||
dataDescription->GetInputDescriptionByName("input")->SetGrid(VTKGrid);
|
||||
Processor->CoProcess(dataDescription.GetPointer());
|
||||
}
|
||||
}
|
||||
} // end of Catalyst namespace
|
||||
@ -0,0 +1,17 @@
|
||||
#ifndef FEADAPTOR_HEADER
|
||||
#define FEADAPTOR_HEADER
|
||||
|
||||
class Attributes;
|
||||
class Grid;
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
void Initialize(int numScripts, char* scripts[]);
|
||||
|
||||
void Finalize();
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,162 @@
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <mpi.h>
|
||||
#include <iostream>
|
||||
|
||||
Grid::Grid()
|
||||
{}
|
||||
|
||||
void Grid::Initialize(const unsigned int numPoints[3], const double spacing[3] )
|
||||
{
|
||||
if(numPoints[0] == 0 || numPoints[1] == 0 || numPoints[2] == 0)
|
||||
{
|
||||
std::cerr << "Must have a non-zero amount of points in each direction.\n";
|
||||
}
|
||||
// in parallel, we do a simple partitioning in the x-direction.
|
||||
int mpiSize = 1;
|
||||
int mpiRank = 0;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
|
||||
|
||||
unsigned int startXPoint = mpiRank*numPoints[0]/mpiSize;
|
||||
unsigned int endXPoint = (mpiRank+1)*numPoints[0]/mpiSize;
|
||||
if(mpiSize != mpiRank+1)
|
||||
{
|
||||
endXPoint++;
|
||||
}
|
||||
|
||||
// create the points -- slowest in the x and fastest in the z directions
|
||||
// all of the x coordinates are stored first, then y coordinates and
|
||||
// finally z coordinates (e.g. x[0], x[1], ..., x[n-1], y[0], y[1], ...,
|
||||
// y[n-1], z[0], z[1], ..., z[n-1]) which is OPPOSITE of VTK's ordering.
|
||||
size_t numTotalPoints = (endXPoint-startXPoint)*numPoints[1]*numPoints[2];
|
||||
this->Points.resize(3*numTotalPoints);
|
||||
size_t counter = 0;
|
||||
for(unsigned int i=startXPoint;i<endXPoint;i++)
|
||||
{
|
||||
for(unsigned int j=0;j<numPoints[1];j++)
|
||||
{
|
||||
for(unsigned int k=0;k<numPoints[2];k++)
|
||||
{
|
||||
this->Points[counter] = i*spacing[0];
|
||||
this->Points[numTotalPoints+counter] = j*spacing[1];
|
||||
this->Points[2*numTotalPoints+counter] = k*spacing[2];
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create the hex cells
|
||||
unsigned int cellPoints[8];
|
||||
unsigned int numXPoints = endXPoint - startXPoint;
|
||||
for(unsigned int i=0;i<numXPoints-1;i++)
|
||||
{
|
||||
for(unsigned int j=0;j<numPoints[1]-1;j++)
|
||||
{
|
||||
for(unsigned int k=0;k<numPoints[2]-1;k++)
|
||||
{
|
||||
cellPoints[0] = i*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k;
|
||||
cellPoints[1] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k;
|
||||
cellPoints[2] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k;
|
||||
cellPoints[3] = i*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k;
|
||||
cellPoints[4] = i*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k+1;
|
||||
cellPoints[5] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k+1;
|
||||
cellPoints[6] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k+1;
|
||||
cellPoints[7] = i*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k+1;
|
||||
std::copy(cellPoints, cellPoints+8, std::back_inserter(this->Cells));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t Grid::GetNumberOfPoints()
|
||||
{
|
||||
return this->Points.size()/3;
|
||||
}
|
||||
|
||||
size_t Grid::GetNumberOfCells()
|
||||
{
|
||||
return this->Cells.size()/8;
|
||||
}
|
||||
|
||||
double* Grid::GetPointsArray()
|
||||
{
|
||||
if(this->Points.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &(this->Points[0]);
|
||||
}
|
||||
|
||||
bool Grid::GetPoint(size_t pointId, double coord[3])
|
||||
{
|
||||
if(pointId >= this->Points.size()/3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
coord[0] = this->Points[pointId];
|
||||
coord[1] = this->Points[pointId+this->GetNumberOfPoints()];
|
||||
coord[2] = this->Points[pointId+2*this->GetNumberOfPoints()];
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int* Grid::GetCellPoints(size_t cellId)
|
||||
{
|
||||
if(cellId >= this->Cells.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &(this->Cells[cellId*8]);
|
||||
}
|
||||
|
||||
Attributes::Attributes()
|
||||
{
|
||||
this->GridPtr = NULL;
|
||||
}
|
||||
|
||||
void Attributes::Initialize(Grid* grid)
|
||||
{
|
||||
this->GridPtr = grid;
|
||||
}
|
||||
|
||||
void Attributes::UpdateFields(double time)
|
||||
{
|
||||
size_t numPoints = this->GridPtr->GetNumberOfPoints();
|
||||
this->Velocity.resize(numPoints*3);
|
||||
double coord[3] = {0, 0, 0};
|
||||
for(size_t pt=0;pt<numPoints;pt++)
|
||||
{
|
||||
this->GridPtr->GetPoint(pt, coord);
|
||||
this->Velocity[pt] = coord[1]*time;
|
||||
}
|
||||
std::fill(this->Velocity.begin()+numPoints, this->Velocity.end(), 0.);
|
||||
size_t numCells = this->GridPtr->GetNumberOfCells();
|
||||
this->Pressure.resize(numCells);
|
||||
std::fill(this->Pressure.begin(), this->Pressure.end(), 1.);
|
||||
}
|
||||
|
||||
double* Attributes::GetVelocityArray()
|
||||
{
|
||||
if(this->Velocity.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &this->Velocity[0];
|
||||
}
|
||||
|
||||
float* Attributes::GetPressureArray()
|
||||
{
|
||||
if(this->Pressure.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &this->Pressure[0];
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
#ifndef FEDATASTRUCTURES_HEADER
|
||||
#define FEDATASTRUCTURES_HEADER
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
class Grid
|
||||
{
|
||||
public:
|
||||
Grid();
|
||||
void Initialize(const unsigned int numPoints[3], const double spacing[3]);
|
||||
size_t GetNumberOfPoints();
|
||||
size_t GetNumberOfCells();
|
||||
double* GetPointsArray();
|
||||
bool GetPoint(size_t pointId, double coord[3]);
|
||||
unsigned int* GetCellPoints(size_t cellId);
|
||||
private:
|
||||
std::vector<double> Points;
|
||||
std::vector<unsigned int> Cells;
|
||||
};
|
||||
|
||||
class Attributes
|
||||
{
|
||||
// A class for generating and storing point and cell fields.
|
||||
// Velocity is stored at the points and pressure is stored
|
||||
// for the cells. The current velocity profile is for a
|
||||
// shearing flow with U(y,t) = y*t, V = 0 and W = 0.
|
||||
// Pressure is constant through the domain.
|
||||
public:
|
||||
Attributes();
|
||||
void Initialize(Grid* grid);
|
||||
void UpdateFields(double time);
|
||||
double* GetVelocityArray();
|
||||
float* GetPressureArray();
|
||||
|
||||
private:
|
||||
std::vector<double> Velocity;
|
||||
std::vector<float> Pressure;
|
||||
Grid* GridPtr;
|
||||
};
|
||||
#endif
|
||||
@ -0,0 +1,51 @@
|
||||
#include "FEDataStructures.h"
|
||||
#include <mpi.h>
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
#include "FEAdaptor.h"
|
||||
#endif
|
||||
|
||||
// Example of a C++ adaptor for a simulation code
|
||||
// where the simulation code has a fixed topology
|
||||
// grid. We treat the grid as an unstructured
|
||||
// grid even though in the example provided it
|
||||
// would be best described as a vtkImageData.
|
||||
// Also, the points are stored in an inconsistent
|
||||
// manner with respect to the velocity vector.
|
||||
// This is purposefully done to demonstrate
|
||||
// the different approaches for getting data
|
||||
// into Catalyst. Note that through configuration
|
||||
// that the driver can be run without linking
|
||||
// to Catalyst.
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
MPI_Init(&argc, &argv);
|
||||
Grid grid;
|
||||
unsigned int numPoints[3] = {70, 60, 44};
|
||||
double spacing[3] = {1, 1.1, 1.3};
|
||||
grid.Initialize(numPoints, spacing);
|
||||
Attributes attributes;
|
||||
attributes.Initialize(&grid);
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::Initialize(argc, argv);
|
||||
#endif
|
||||
unsigned int numberOfTimeSteps = 100;
|
||||
for(unsigned int timeStep=0;timeStep<numberOfTimeSteps;timeStep++)
|
||||
{
|
||||
// use a time step length of 0.1
|
||||
double time = timeStep * 0.1;
|
||||
attributes.UpdateFields(time);
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::CoProcess(grid, attributes, time, timeStep, timeStep == numberOfTimeSteps-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::Finalize();
|
||||
#endif
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
|
||||
try: paraview.simple
|
||||
except: from paraview.simple import *
|
||||
|
||||
from paraview import coprocessing
|
||||
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Code generated from cpstate.py to create the CoProcessor.
|
||||
|
||||
|
||||
# ----------------------- CoProcessor definition -----------------------
|
||||
|
||||
def CreateCoProcessor():
|
||||
def _CreatePipeline(coprocessor, datadescription):
|
||||
class Pipeline:
|
||||
filename_3_pvtu = coprocessor.CreateProducer( datadescription, "input" )
|
||||
|
||||
Slice1 = Slice( guiName="Slice1", Crinkleslice=0, SliceOffsetValues=[0.0], Triangulatetheslice=1, SliceType="Plane" )
|
||||
Slice1.SliceType.Offset = 0.0
|
||||
Slice1.SliceType.Origin = [34.5, 32.45, 27.95]
|
||||
Slice1.SliceType.Normal = [1.0, 0.0, 0.0]
|
||||
|
||||
ParallelPolyDataWriter1 = coprocessor.CreateWriter( XMLPPolyDataWriter, "slice_%t.pvtp", 10 )
|
||||
|
||||
SetActiveSource(filename_3_pvtu)
|
||||
ParallelUnstructuredGridWriter1 = coprocessor.CreateWriter( XMLPUnstructuredGridWriter, "fullgrid_%t.pvtu", 100 )
|
||||
|
||||
return Pipeline()
|
||||
|
||||
class CoProcessor(coprocessing.CoProcessor):
|
||||
def CreatePipeline(self, datadescription):
|
||||
self.Pipeline = _CreatePipeline(self, datadescription)
|
||||
|
||||
coprocessor = CoProcessor()
|
||||
freqs = {'input': [10, 100]}
|
||||
coprocessor.SetUpdateFrequencies(freqs)
|
||||
return coprocessor
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Global variables that will hold the pipeline for each timestep
|
||||
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
|
||||
# It will be automatically setup when coprocessor.UpdateProducers() is called the
|
||||
# first time.
|
||||
coprocessor = CreateCoProcessor()
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Enable Live-Visualizaton with ParaView
|
||||
coprocessor.EnableLiveVisualization(False)
|
||||
|
||||
|
||||
# ---------------------- Data Selection method ----------------------
|
||||
|
||||
def RequestDataDescription(datadescription):
|
||||
"Callback to populate the request for current timestep"
|
||||
global coprocessor
|
||||
if datadescription.GetForceOutput() == True:
|
||||
# We are just going to request all fields and meshes from the simulation
|
||||
# code/adaptor.
|
||||
for i in range(datadescription.GetNumberOfInputDescriptions()):
|
||||
datadescription.GetInputDescription(i).AllFieldsOn()
|
||||
datadescription.GetInputDescription(i).GenerateMeshOn()
|
||||
return
|
||||
|
||||
# setup requests for all inputs based on the requirements of the
|
||||
# pipeline.
|
||||
coprocessor.LoadRequestedData(datadescription)
|
||||
|
||||
# ------------------------ Processing method ------------------------
|
||||
|
||||
def DoCoProcessing(datadescription):
|
||||
"Callback to do co-processing for current timestep"
|
||||
global coprocessor
|
||||
|
||||
# Update the coprocessor by providing it the newly generated simulation data.
|
||||
# If the pipeline hasn't been setup yet, this will setup the pipeline.
|
||||
coprocessor.UpdateProducers(datadescription)
|
||||
|
||||
# Write output data, if appropriate.
|
||||
coprocessor.WriteData(datadescription);
|
||||
|
||||
# Write image capture (Last arg: rescale lookup table), if appropriate.
|
||||
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
|
||||
|
||||
# Live Visualization, if enabled.
|
||||
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)
|
||||
@ -0,0 +1,120 @@
|
||||
/*=========================================================================
|
||||
|
||||
Program: Visualization Toolkit
|
||||
Module: vtkCPMappedVectorArrayTemplate.h
|
||||
|
||||
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
||||
All rights reserved.
|
||||
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE. See the above copyright notice for more information.
|
||||
|
||||
=========================================================================*/
|
||||
|
||||
// .NAME vtkCPMappedVectorArrayTemplate - Map native data arrays into
|
||||
// the vtkDataArray interface.
|
||||
//
|
||||
// .SECTION Description
|
||||
// Map native simulation code data arrays into the vtkDataArray interface.
|
||||
// This is based on the vtkCPExodusIIResultsArrayTemplate.h class in VTK.
|
||||
|
||||
#ifndef vtkCPMappedVectorArrayTemplate_h
|
||||
#define vtkCPMappedVectorArrayTemplate_h
|
||||
|
||||
#include "vtkMappedDataArray.h"
|
||||
|
||||
#include "vtkTypeTemplate.h" // For templated vtkObject API
|
||||
#include "vtkObjectFactory.h" // for vtkStandardNewMacro
|
||||
|
||||
template <class Scalar>
|
||||
class vtkCPMappedVectorArrayTemplate:
|
||||
public vtkTypeTemplate<vtkCPMappedVectorArrayTemplate<Scalar>,
|
||||
vtkMappedDataArray<Scalar> >
|
||||
{
|
||||
public:
|
||||
vtkMappedDataArrayNewInstanceMacro(
|
||||
vtkCPMappedVectorArrayTemplate<Scalar>)
|
||||
static vtkCPMappedVectorArrayTemplate *New();
|
||||
virtual void PrintSelf(ostream &os, vtkIndent indent);
|
||||
|
||||
// Description:
|
||||
// Set the raw scalar arrays for the coordinate set. This class takes
|
||||
// ownership of the arrays and deletes them with delete[].
|
||||
void SetVectorArray(Scalar *array, vtkIdType numPoints);
|
||||
|
||||
// Reimplemented virtuals -- see superclasses for descriptions:
|
||||
void Initialize();
|
||||
void GetTuples(vtkIdList *ptIds, vtkAbstractArray *output);
|
||||
void GetTuples(vtkIdType p1, vtkIdType p2, vtkAbstractArray *output);
|
||||
void Squeeze();
|
||||
vtkArrayIterator *NewIterator();
|
||||
vtkIdType LookupValue(vtkVariant value);
|
||||
void LookupValue(vtkVariant value, vtkIdList *ids);
|
||||
vtkVariant GetVariantValue(vtkIdType idx);
|
||||
void ClearLookup();
|
||||
double* GetTuple(vtkIdType i);
|
||||
void GetTuple(vtkIdType i, double *tuple);
|
||||
vtkIdType LookupTypedValue(Scalar value);
|
||||
void LookupTypedValue(Scalar value, vtkIdList *ids);
|
||||
Scalar GetValue(vtkIdType idx);
|
||||
Scalar& GetValueReference(vtkIdType idx);
|
||||
void GetTupleValue(vtkIdType idx, Scalar *t);
|
||||
|
||||
// Description:
|
||||
// This container is read only -- this method does nothing but print a
|
||||
// warning.
|
||||
int Allocate(vtkIdType sz, vtkIdType ext);
|
||||
int Resize(vtkIdType numTuples);
|
||||
void SetNumberOfTuples(vtkIdType number);
|
||||
void SetTuple(vtkIdType i, vtkIdType j, vtkAbstractArray *source);
|
||||
void SetTuple(vtkIdType i, const float *source);
|
||||
void SetTuple(vtkIdType i, const double *source);
|
||||
void InsertTuple(vtkIdType i, vtkIdType j, vtkAbstractArray *source);
|
||||
void InsertTuple(vtkIdType i, const float *source);
|
||||
void InsertTuple(vtkIdType i, const double *source);
|
||||
void InsertTuples(vtkIdList *dstIds, vtkIdList *srcIds,
|
||||
vtkAbstractArray *source);
|
||||
void InsertTuples(vtkIdType dstStart, vtkIdType n, vtkIdType srcStart,
|
||||
vtkAbstractArray* source);
|
||||
vtkIdType InsertNextTuple(vtkIdType j, vtkAbstractArray *source);
|
||||
vtkIdType InsertNextTuple(const float *source);
|
||||
vtkIdType InsertNextTuple(const double *source);
|
||||
void DeepCopy(vtkAbstractArray *aa);
|
||||
void DeepCopy(vtkDataArray *da);
|
||||
void InterpolateTuple(vtkIdType i, vtkIdList *ptIndices,
|
||||
vtkAbstractArray* source, double* weights);
|
||||
void InterpolateTuple(vtkIdType i, vtkIdType id1, vtkAbstractArray *source1,
|
||||
vtkIdType id2, vtkAbstractArray *source2, double t);
|
||||
void SetVariantValue(vtkIdType idx, vtkVariant value);
|
||||
void InsertVariantValue(vtkIdType idx, vtkVariant value);
|
||||
void RemoveTuple(vtkIdType id);
|
||||
void RemoveFirstTuple();
|
||||
void RemoveLastTuple();
|
||||
void SetTupleValue(vtkIdType i, const Scalar *t);
|
||||
void InsertTupleValue(vtkIdType i, const Scalar *t);
|
||||
vtkIdType InsertNextTupleValue(const Scalar *t);
|
||||
void SetValue(vtkIdType idx, Scalar value);
|
||||
vtkIdType InsertNextValue(Scalar v);
|
||||
void InsertValue(vtkIdType idx, Scalar v);
|
||||
|
||||
protected:
|
||||
vtkCPMappedVectorArrayTemplate();
|
||||
~vtkCPMappedVectorArrayTemplate();
|
||||
|
||||
Scalar *Array;
|
||||
|
||||
private:
|
||||
vtkCPMappedVectorArrayTemplate(
|
||||
const vtkCPMappedVectorArrayTemplate &); // Not implemented.
|
||||
void operator=(
|
||||
const vtkCPMappedVectorArrayTemplate &); // Not implemented.
|
||||
|
||||
vtkIdType Lookup(const Scalar &val, vtkIdType startIndex);
|
||||
double TempDoubleArray[3];
|
||||
};
|
||||
|
||||
#include "vtkCPMappedVectorArrayTemplate.txx"
|
||||
|
||||
#endif //vtkCPMappedVectorArrayTemplate_h
|
||||
@ -0,0 +1,499 @@
|
||||
/*=========================================================================
|
||||
|
||||
Program: Visualization Toolkit
|
||||
Module: vtkCPMappedVectorArrayTemplate.txx
|
||||
|
||||
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
||||
All rights reserved.
|
||||
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE. See the above copyright notice for more information.
|
||||
|
||||
=========================================================================*/
|
||||
|
||||
#include "vtkCPMappedVectorArrayTemplate.h"
|
||||
|
||||
#include "vtkIdList.h"
|
||||
#include "vtkObjectFactory.h"
|
||||
#include "vtkVariant.h"
|
||||
#include "vtkVariantCast.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Can't use vtkStandardNewMacro with a template.
|
||||
template <class Scalar> vtkCPMappedVectorArrayTemplate<Scalar> *
|
||||
vtkCPMappedVectorArrayTemplate<Scalar>::New()
|
||||
{
|
||||
VTK_STANDARD_NEW_BODY(vtkCPMappedVectorArrayTemplate<Scalar>)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::PrintSelf(ostream &os, vtkIndent indent)
|
||||
{
|
||||
this->vtkCPMappedVectorArrayTemplate<Scalar>::Superclass::PrintSelf(
|
||||
os, indent);
|
||||
os << indent << "Array: " << this->Array << std::endl;
|
||||
os << indent << "TempDoubleArray: " << this->TempDoubleArray << std::endl;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::Initialize()
|
||||
{
|
||||
this->Array = NULL;
|
||||
this->MaxId = -1;
|
||||
this->Size = 0;
|
||||
this->NumberOfComponents = 3;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::GetTuples(vtkIdList *ptIds, vtkAbstractArray *output)
|
||||
{
|
||||
vtkDataArray *outArray = vtkDataArray::FastDownCast(output);
|
||||
if (!outArray)
|
||||
{
|
||||
vtkWarningMacro(<<"Input is not a vtkDataArray");
|
||||
return;
|
||||
}
|
||||
|
||||
vtkIdType numTuples = ptIds->GetNumberOfIds();
|
||||
|
||||
outArray->SetNumberOfComponents(this->NumberOfComponents);
|
||||
outArray->SetNumberOfTuples(numTuples);
|
||||
|
||||
const vtkIdType numPoints = ptIds->GetNumberOfIds();
|
||||
for (vtkIdType i = 0; i < numPoints; ++i)
|
||||
{
|
||||
outArray->SetTuple(i, this->GetTuple(ptIds->GetId(i)));
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::GetTuples(vtkIdType p1, vtkIdType p2, vtkAbstractArray *output)
|
||||
{
|
||||
vtkDataArray *da = vtkDataArray::FastDownCast(output);
|
||||
if (!da)
|
||||
{
|
||||
vtkErrorMacro(<<"Input is not a vtkDataArray");
|
||||
return;
|
||||
}
|
||||
|
||||
if (da->GetNumberOfComponents() != this->GetNumberOfComponents())
|
||||
{
|
||||
vtkErrorMacro(<<"Incorrect number of components in input array.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (vtkIdType daTupleId = 0; p1 <= p2; ++p1)
|
||||
{
|
||||
da->SetTuple(daTupleId++, this->GetTuple(p1));
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::Squeeze()
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> vtkArrayIterator*
|
||||
vtkCPMappedVectorArrayTemplate<Scalar>::NewIterator()
|
||||
{
|
||||
vtkErrorMacro(<<"Not implemented.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> vtkIdType vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::LookupValue(vtkVariant value)
|
||||
{
|
||||
bool valid = true;
|
||||
Scalar val = vtkVariantCast<Scalar>(value, &valid);
|
||||
if (valid)
|
||||
{
|
||||
return this->Lookup(val, 0);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::LookupValue(vtkVariant value, vtkIdList *ids)
|
||||
{
|
||||
bool valid = true;
|
||||
Scalar val = vtkVariantCast<Scalar>(value, &valid);
|
||||
ids->Reset();
|
||||
if (valid)
|
||||
{
|
||||
vtkIdType index = 0;
|
||||
while ((index = this->Lookup(val, index)) >= 0)
|
||||
{
|
||||
ids->InsertNextId(index++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> vtkVariant vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::GetVariantValue(vtkIdType idx)
|
||||
{
|
||||
return vtkVariant(this->GetValueReference(idx));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::ClearLookup()
|
||||
{
|
||||
// no-op, no fast lookup implemented.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> double* vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::GetTuple(vtkIdType i)
|
||||
{
|
||||
this->GetTuple(i, this->TempDoubleArray);
|
||||
return this->TempDoubleArray;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::GetTuple(vtkIdType i, double *tuple)
|
||||
{
|
||||
tuple[0] = static_cast<double>(this->Array[i]);
|
||||
tuple[1] = static_cast<double>(this->Array[i+this->GetNumberOfTuples()]);
|
||||
tuple[2] = static_cast<double>(this->Array[i+2*this->GetNumberOfTuples()]);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> vtkIdType vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::LookupTypedValue(Scalar value)
|
||||
{
|
||||
return this->Lookup(value, 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::LookupTypedValue(Scalar value, vtkIdList *ids)
|
||||
{
|
||||
ids->Reset();
|
||||
vtkIdType index = 0;
|
||||
while ((index = this->Lookup(value, index)) >= 0)
|
||||
{
|
||||
ids->InsertNextId(index++);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> Scalar vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::GetValue(vtkIdType idx)
|
||||
{
|
||||
return this->GetValueReference(idx);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> Scalar& vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::GetValueReference(vtkIdType idx)
|
||||
{
|
||||
const vtkIdType tuple = idx / this->NumberOfComponents;
|
||||
const vtkIdType comp = idx % this->NumberOfComponents;
|
||||
switch (comp)
|
||||
{
|
||||
case 0:
|
||||
return this->Array[tuple];
|
||||
case 1:
|
||||
return this->Array[tuple+this->GetNumberOfTuples()];
|
||||
case 2:
|
||||
return this->Array[tuple+2*this->GetNumberOfTuples()];
|
||||
default:
|
||||
vtkErrorMacro(<< "Invalid number of components.");
|
||||
static Scalar dummy(0);
|
||||
return dummy;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::GetTupleValue(vtkIdType tupleId, Scalar *tuple)
|
||||
{
|
||||
tuple[0] = this->Array[tupleId];
|
||||
tuple[1] = this->Array[tupleId+this->GetNumberOfTuples()];
|
||||
tuple[2] = this->Array[tupleId+2*this->GetNumberOfTuples()];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> int vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::Allocate(vtkIdType, vtkIdType)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> int vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::Resize(vtkIdType)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::SetNumberOfTuples(vtkIdType)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::SetTuple(vtkIdType, vtkIdType, vtkAbstractArray *)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::SetTuple(vtkIdType, const float *)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::SetTuple(vtkIdType, const double *)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InsertTuple(vtkIdType, vtkIdType, vtkAbstractArray *)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InsertTuple(vtkIdType, const float *)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InsertTuple(vtkIdType, const double *)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InsertTuples(vtkIdList *, vtkIdList *, vtkAbstractArray *)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InsertTuples(vtkIdType, vtkIdType, vtkIdType, vtkAbstractArray *)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> vtkIdType vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InsertNextTuple(vtkIdType, vtkAbstractArray *)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> vtkIdType vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InsertNextTuple(const float *)
|
||||
{
|
||||
|
||||
vtkErrorMacro("Read only container.")
|
||||
return -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> vtkIdType vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InsertNextTuple(const double *)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::DeepCopy(vtkAbstractArray *)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::DeepCopy(vtkDataArray *)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InterpolateTuple(vtkIdType, vtkIdList *, vtkAbstractArray *, double *)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InterpolateTuple(vtkIdType, vtkIdType, vtkAbstractArray*, vtkIdType,
|
||||
vtkAbstractArray*, double)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::SetVariantValue(vtkIdType, vtkVariant)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InsertVariantValue(vtkIdType, vtkVariant)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::RemoveTuple(vtkIdType)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::RemoveFirstTuple()
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::RemoveLastTuple()
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::SetTupleValue(vtkIdType, const Scalar*)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InsertTupleValue(vtkIdType, const Scalar*)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> vtkIdType vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InsertNextTupleValue(const Scalar *)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::SetValue(vtkIdType, Scalar)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> vtkIdType vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InsertNextValue(Scalar)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::InsertValue(vtkIdType, Scalar)
|
||||
{
|
||||
vtkErrorMacro("Read only container.")
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::vtkCPMappedVectorArrayTemplate()
|
||||
: Array(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::~vtkCPMappedVectorArrayTemplate()
|
||||
{ }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> void vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::SetVectorArray(Scalar *array, vtkIdType numPoints)
|
||||
{
|
||||
Initialize();
|
||||
this->Array = array;
|
||||
this->NumberOfComponents = 3;
|
||||
this->Size = this->NumberOfComponents * numPoints;
|
||||
this->MaxId = this->Size - 1;
|
||||
this->Modified();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class Scalar> vtkIdType vtkCPMappedVectorArrayTemplate<Scalar>
|
||||
::Lookup(const Scalar &val, vtkIdType index)
|
||||
{
|
||||
while (index <= this->MaxId)
|
||||
{
|
||||
if (this->GetValueReference(index++) == val)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(CatalystCxxMultiPieceExample)
|
||||
|
||||
set(USE_CATALYST ON CACHE BOOL "Link the simulator with Catalyst")
|
||||
if(USE_CATALYST)
|
||||
find_package(ParaView 4.1 REQUIRED COMPONENTS vtkPVPythonCatalyst)
|
||||
include("${PARAVIEW_USE_FILE}")
|
||||
set(Adaptor_SRCS
|
||||
FEAdaptor.cxx
|
||||
)
|
||||
add_library(CxxMultiPieceExampleAdaptor ${Adaptor_SRCS})
|
||||
target_link_libraries(CxxMultiPieceExampleAdaptor vtkPVPythonCatalyst)
|
||||
add_definitions("-DUSE_CATALYST")
|
||||
if(NOT PARAVIEW_USE_MPI)
|
||||
message(SEND_ERROR "ParaView must be built with MPI enabled")
|
||||
endif()
|
||||
else()
|
||||
find_package(MPI REQUIRED)
|
||||
include_directories(${MPI_CXX_INCLUDE_PATH})
|
||||
endif()
|
||||
|
||||
add_executable(CxxMultiPieceExample FEDriver.cxx FEDataStructures.cxx)
|
||||
if(USE_CATALYST)
|
||||
target_link_libraries(CxxMultiPieceExample LINK_PRIVATE CxxMultiPieceExampleAdaptor)
|
||||
include(vtkModuleMacros)
|
||||
include(vtkMPI)
|
||||
vtk_mpi_link(CxxMultiPieceExample)
|
||||
else()
|
||||
target_link_libraries(CxxMultiPieceExample LINK_PRIVATE ${MPI_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_test(NAME CxxMultiPieceExampleTest COMMAND CxxMultiPieceExample ${CMAKE_CURRENT_SOURCE_DIR}/SampleScripts/feslicescript.py)
|
||||
set_tests_properties(CxxMultiPieceExampleTest PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
endif()
|
||||
@ -0,0 +1,182 @@
|
||||
#include <iostream>
|
||||
#include "FEAdaptor.h"
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkCellType.h>
|
||||
#include <vtkCommunicator.h>
|
||||
#include <vtkCPDataDescription.h>
|
||||
#include <vtkCPInputDataDescription.h>
|
||||
#include <vtkCPProcessor.h>
|
||||
#include <vtkCPPythonScriptPipeline.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkFloatArray.h>
|
||||
#include <vtkImageData.h>
|
||||
#include <vtkMultiBlockDataSet.h>
|
||||
#include <vtkMultiPieceDataSet.h>
|
||||
#include <vtkMultiProcessController.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkPoints.h>
|
||||
#include <vtkPointData.h>
|
||||
|
||||
#include <mpi.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
vtkCPProcessor* Processor = NULL;
|
||||
vtkMultiBlockDataSet* VTKGrid;
|
||||
|
||||
void BuildVTKGrid(Grid& grid)
|
||||
{
|
||||
vtkNew<vtkImageData> imageData;
|
||||
imageData->SetSpacing(grid.GetSpacing());
|
||||
imageData->SetOrigin(0, 0, 0); // Not necessary for (0,0,0)
|
||||
unsigned int* extents = grid.GetExtents();
|
||||
int extents2[6];
|
||||
for(int i=0;i<6;i++)
|
||||
{
|
||||
extents2[i] = static_cast<int>(extents[i]);
|
||||
}
|
||||
imageData->SetExtent(extents2);
|
||||
int mpiSize = 1;
|
||||
int mpiRank = 0;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
|
||||
vtkNew<vtkMultiPieceDataSet> multiPiece;
|
||||
multiPiece->SetNumberOfPieces(mpiSize);
|
||||
multiPiece->SetPiece(mpiRank, imageData.GetPointer());
|
||||
VTKGrid->SetNumberOfBlocks(1);
|
||||
VTKGrid->SetBlock(0, multiPiece.GetPointer());
|
||||
}
|
||||
|
||||
void UpdateVTKAttributes(Grid& grid, Attributes& attributes)
|
||||
{
|
||||
int mpiRank = 0;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
|
||||
vtkMultiPieceDataSet* multiPiece = vtkMultiPieceDataSet::SafeDownCast(
|
||||
VTKGrid->GetBlock(0));
|
||||
vtkDataSet* dataSet = vtkDataSet::SafeDownCast(multiPiece->GetPiece(mpiRank));
|
||||
if(dataSet->GetPointData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// velocity array
|
||||
vtkNew<vtkDoubleArray> velocity;
|
||||
velocity->SetName("velocity");
|
||||
velocity->SetNumberOfComponents(3);
|
||||
velocity->SetNumberOfTuples(static_cast<vtkIdType>(grid.GetNumberOfLocalPoints()));
|
||||
dataSet->GetPointData()->AddArray(velocity.GetPointer());
|
||||
}
|
||||
if(dataSet->GetCellData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// pressure array
|
||||
vtkNew<vtkFloatArray> pressure;
|
||||
pressure->SetName("pressure");
|
||||
pressure->SetNumberOfComponents(1);
|
||||
dataSet->GetCellData()->AddArray(pressure.GetPointer());
|
||||
}
|
||||
vtkDoubleArray* velocity = vtkDoubleArray::SafeDownCast(
|
||||
dataSet->GetPointData()->GetArray("velocity"));
|
||||
// The velocity array is ordered as vx0,vx1,vx2,..,vy0,vy1,vy2,..,vz0,vz1,vz2,..
|
||||
// so we need to create a full copy of it with VTK's ordering of
|
||||
// vx0,vy0,vz0,vx1,vy1,vz1,..
|
||||
double* velocityData = attributes.GetVelocityArray();
|
||||
vtkIdType numTuples = velocity->GetNumberOfTuples();
|
||||
for(vtkIdType i=0;i<numTuples;i++)
|
||||
{
|
||||
double values[3] = {velocityData[i], velocityData[i+numTuples],
|
||||
velocityData[i+2*numTuples]};
|
||||
velocity->SetTupleValue(i, values);
|
||||
}
|
||||
|
||||
vtkFloatArray* pressure = vtkFloatArray::SafeDownCast(
|
||||
dataSet->GetCellData()->GetArray("pressure"));
|
||||
// The pressure array is a scalar array so we can reuse
|
||||
// memory as long as we ordered the points properly.
|
||||
float* pressureData = attributes.GetPressureArray();
|
||||
pressure->SetArray(pressureData, static_cast<vtkIdType>(grid.GetNumberOfLocalCells()), 1);
|
||||
}
|
||||
|
||||
void BuildVTKDataStructures(Grid& grid, Attributes& attributes)
|
||||
{
|
||||
if(VTKGrid == NULL)
|
||||
{
|
||||
// The grid structure isn't changing so we only build it
|
||||
// the first time it's needed. If we needed the memory
|
||||
// we could delete it and rebuild as necessary.
|
||||
VTKGrid = vtkMultiBlockDataSet::New();
|
||||
BuildVTKGrid(grid);
|
||||
}
|
||||
UpdateVTKAttributes(grid, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
|
||||
void Initialize(int numScripts, char* scripts[])
|
||||
{
|
||||
if(Processor == NULL)
|
||||
{
|
||||
Processor = vtkCPProcessor::New();
|
||||
Processor->Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
Processor->RemoveAllPipelines();
|
||||
}
|
||||
for(int i=1;i<numScripts;i++)
|
||||
{
|
||||
vtkNew<vtkCPPythonScriptPipeline> pipeline;
|
||||
pipeline->Initialize(scripts[i]);
|
||||
Processor->AddPipeline(pipeline.GetPointer());
|
||||
}
|
||||
}
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
if(Processor)
|
||||
{
|
||||
Processor->Delete();
|
||||
Processor = NULL;
|
||||
}
|
||||
if(VTKGrid)
|
||||
{
|
||||
VTKGrid->Delete();
|
||||
VTKGrid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep)
|
||||
{
|
||||
vtkNew<vtkCPDataDescription> dataDescription;
|
||||
dataDescription->AddInput("input");
|
||||
dataDescription->SetTimeData(time, timeStep);
|
||||
if(lastTimeStep == true)
|
||||
{
|
||||
// assume that we want to all the pipelines to execute if it
|
||||
// is the last time step.
|
||||
dataDescription->ForceOutputOn();
|
||||
}
|
||||
if(Processor->RequestDataDescription(dataDescription.GetPointer()) != 0)
|
||||
{
|
||||
BuildVTKDataStructures(grid, attributes);
|
||||
dataDescription->GetInputDescriptionByName("input")->SetGrid(VTKGrid);
|
||||
|
||||
// figure out the whole extent of the grid
|
||||
unsigned int* extent = grid.GetExtents();
|
||||
int wholeExtent[6], tmp[6];
|
||||
for(int i=0;i<3;i++)
|
||||
{
|
||||
wholeExtent[i*2] = - static_cast<int>(extent[i*2]); // negate for parallel communication
|
||||
wholeExtent[i*2+1] = static_cast<int>(extent[i*2+1]);
|
||||
}
|
||||
vtkMultiProcessController::GetGlobalController()->AllReduce(wholeExtent, tmp, 6, vtkCommunicator::MAX_OP);
|
||||
for(int i=0;i<3;i++)
|
||||
{
|
||||
tmp[i*2] = -tmp[i*2];
|
||||
}
|
||||
dataDescription->GetInputDescriptionByName("input")->SetWholeExtent(tmp);
|
||||
Processor->CoProcess(dataDescription.GetPointer());
|
||||
}
|
||||
}
|
||||
} // end of Catalyst namespace
|
||||
@ -0,0 +1,17 @@
|
||||
#ifndef FEADAPTOR_HEADER
|
||||
#define FEADAPTOR_HEADER
|
||||
|
||||
class Attributes;
|
||||
class Grid;
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
void Initialize(int numScripts, char* scripts[]);
|
||||
|
||||
void Finalize();
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,118 @@
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <mpi.h>
|
||||
#include <iostream>
|
||||
|
||||
Grid::Grid()
|
||||
{}
|
||||
|
||||
void Grid::Initialize(const unsigned int numPoints[3], const double spacing[3] )
|
||||
{
|
||||
if(numPoints[0] == 0 || numPoints[1] == 0 || numPoints[2] == 0)
|
||||
{
|
||||
std::cerr << "Must have a non-zero amount of points in each direction.\n";
|
||||
}
|
||||
for(int i=0;i<3;i++)
|
||||
{
|
||||
this->Extents[i*2] = 0;
|
||||
this->Extents[i*2+1] = numPoints[i];
|
||||
this->Spacing[i] = spacing[i];
|
||||
}
|
||||
|
||||
// in parallel, we do a simple partitioning in the x-direction.
|
||||
int mpiSize = 1;
|
||||
int mpiRank = 0;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
|
||||
|
||||
this->Extents[0] = mpiRank*numPoints[0]/mpiSize;
|
||||
this->Extents[1] = (mpiRank+1)*numPoints[0]/mpiSize;
|
||||
}
|
||||
|
||||
unsigned int Grid::GetNumberOfLocalPoints()
|
||||
{
|
||||
return (this->Extents[1]-this->Extents[0]+1) *
|
||||
(this->Extents[3]-this->Extents[2]+1) *
|
||||
(this->Extents[5]-this->Extents[4]+1);
|
||||
}
|
||||
|
||||
unsigned int Grid::GetNumberOfLocalCells()
|
||||
{
|
||||
return (this->Extents[1]-this->Extents[0]) *
|
||||
(this->Extents[3]-this->Extents[2]) *
|
||||
(this->Extents[5]-this->Extents[4]);
|
||||
}
|
||||
|
||||
void Grid::GetPoint(unsigned int logicalLocalCoords[3], double coord[3])
|
||||
{
|
||||
coord[0] = (this->Extents[0]+logicalLocalCoords[0])*this->Spacing[0];
|
||||
coord[1] = logicalLocalCoords[1]*this->Spacing[1];
|
||||
coord[2] = logicalLocalCoords[2]*this->Spacing[2];
|
||||
}
|
||||
|
||||
double* Grid::GetSpacing()
|
||||
{
|
||||
return this->Spacing;
|
||||
}
|
||||
|
||||
unsigned int* Grid::GetExtents()
|
||||
{
|
||||
return this->Extents;
|
||||
}
|
||||
|
||||
Attributes::Attributes()
|
||||
{
|
||||
this->GridPtr = NULL;
|
||||
}
|
||||
|
||||
void Attributes::Initialize(Grid* grid)
|
||||
{
|
||||
this->GridPtr = grid;
|
||||
}
|
||||
|
||||
void Attributes::UpdateFields(double time)
|
||||
{
|
||||
size_t numPoints = this->GridPtr->GetNumberOfLocalPoints();
|
||||
this->Velocity.resize(numPoints*3);
|
||||
unsigned int* extents = this->GridPtr->GetExtents();
|
||||
unsigned int logicalLocalCoords[3];
|
||||
size_t pt = 0;
|
||||
for(unsigned int k=0;k<extents[5]-extents[4]+1;k++)
|
||||
{
|
||||
logicalLocalCoords[2] = k;
|
||||
for(unsigned int j=0;j<extents[3]-extents[2]+1;j++)
|
||||
{
|
||||
logicalLocalCoords[1] = j;
|
||||
for(unsigned int i=0;i<extents[1]-extents[0]+1;i++)
|
||||
{
|
||||
logicalLocalCoords[0] = i;
|
||||
double coord[3];
|
||||
this->GridPtr->GetPoint(logicalLocalCoords, coord);
|
||||
this->Velocity[pt] = coord[1]*time;
|
||||
pt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::fill(this->Velocity.begin()+numPoints, this->Velocity.end(), 0.);
|
||||
size_t numCells = this->GridPtr->GetNumberOfLocalCells();
|
||||
this->Pressure.resize(numCells);
|
||||
std::fill(this->Pressure.begin(), this->Pressure.end(), 1.);
|
||||
}
|
||||
|
||||
double* Attributes::GetVelocityArray()
|
||||
{
|
||||
if(this->Velocity.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &this->Velocity[0];
|
||||
}
|
||||
|
||||
float* Attributes::GetPressureArray()
|
||||
{
|
||||
if(this->Pressure.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &this->Pressure[0];
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
#ifndef FEDATASTRUCTURES_HEADER
|
||||
#define FEDATASTRUCTURES_HEADER
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
class Grid
|
||||
{
|
||||
public:
|
||||
Grid();
|
||||
void Initialize(const unsigned int numGlobalPoints[3], const double spacing[3]);
|
||||
unsigned int GetNumberOfLocalPoints();
|
||||
unsigned int GetNumberOfLocalCells();
|
||||
void GetPoint(unsigned int logicalLocalCoords[3], double coord[3]);
|
||||
double* GetSpacing();
|
||||
unsigned int* GetExtents();
|
||||
private:
|
||||
unsigned int Extents[6];
|
||||
double Spacing[3];
|
||||
};
|
||||
|
||||
class Attributes
|
||||
{
|
||||
// A class for generating and storing point and cell fields.
|
||||
// Velocity is stored at the points and pressure is stored
|
||||
// for the cells. The current velocity profile is for a
|
||||
// shearing flow with U(y,t) = y*t, V = 0 and W = 0.
|
||||
// Pressure is constant through the domain.
|
||||
public:
|
||||
Attributes();
|
||||
void Initialize(Grid* grid);
|
||||
void UpdateFields(double time);
|
||||
double* GetVelocityArray();
|
||||
float* GetPressureArray();
|
||||
|
||||
private:
|
||||
std::vector<double> Velocity;
|
||||
std::vector<float> Pressure;
|
||||
Grid* GridPtr;
|
||||
};
|
||||
#endif
|
||||
@ -0,0 +1,54 @@
|
||||
#include <algorithm>
|
||||
#include "FEDataStructures.h"
|
||||
#include <iostream>
|
||||
#include <mpi.h>
|
||||
#include <vector>
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
#include "FEAdaptor.h"
|
||||
#endif
|
||||
|
||||
// Example of a C++ adaptor for a simulation code
|
||||
// where the simulation code has a fixed topology
|
||||
// grid. We treat the grid as a partitioned
|
||||
// regular grid. This is stored as a set of
|
||||
// vtkImageDatas in a vtkMultiPieceDataSet.
|
||||
// Also, the points are stored in an inconsistent
|
||||
// manner with respect to the velocity vector.
|
||||
// This is purposefully done to demonstrate
|
||||
// the different approaches for getting data
|
||||
// into Catalyst. Note that through configuration
|
||||
// that the driver can be run without linking
|
||||
// to Catalyst.
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
MPI_Init(&argc, &argv);
|
||||
Grid grid;
|
||||
unsigned int numPoints[3] = {70, 60, 44};
|
||||
double spacing[3] = {1, 1.1, 1.3};
|
||||
grid.Initialize(numPoints, spacing);
|
||||
Attributes attributes;
|
||||
attributes.Initialize(&grid);
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::Initialize(argc, argv);
|
||||
#endif
|
||||
unsigned int numberOfTimeSteps = 100;
|
||||
for(unsigned int timeStep=0;timeStep<numberOfTimeSteps;timeStep++)
|
||||
{
|
||||
// use a time step length of 0.1
|
||||
double time = timeStep * 0.1;
|
||||
attributes.UpdateFields(time);
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::CoProcess(grid, attributes, time, timeStep, timeStep == numberOfTimeSteps-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::Finalize();
|
||||
#endif
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
try: paraview.simple
|
||||
except: from paraview.simple import *
|
||||
|
||||
from paraview import coprocessing
|
||||
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Code generated from cpstate.py to create the CoProcessor.
|
||||
|
||||
|
||||
# ----------------------- CoProcessor definition -----------------------
|
||||
|
||||
def CreateCoProcessor():
|
||||
def _CreatePipeline(coprocessor, datadescription):
|
||||
class Pipeline:
|
||||
filename_18_vtm = coprocessor.CreateProducer( datadescription, "input" )
|
||||
|
||||
ParallelMultiBlockDataSetWriter1 = coprocessor.CreateWriter( XMLMultiBlockDataWriter, "fullgrid_%t.vtm", 100 )
|
||||
|
||||
SetActiveSource(filename_18_vtm)
|
||||
Slice1 = Slice( guiName="Slice1", Crinkleslice=0, SliceOffsetValues=[0.0], Triangulatetheslice=1, SliceType="Plane" )
|
||||
Slice1.SliceType.Offset = 0.0
|
||||
Slice1.SliceType.Origin = [35.0, 33.0, 28.6]
|
||||
Slice1.SliceType.Normal = [1.0, 0.0, 0.0]
|
||||
|
||||
ParallelMultiBlockDataSetWriter2 = coprocessor.CreateWriter( XMLMultiBlockDataWriter, "slice_%t.vtm", 10 )
|
||||
|
||||
return Pipeline()
|
||||
|
||||
class CoProcessor(coprocessing.CoProcessor):
|
||||
def CreatePipeline(self, datadescription):
|
||||
self.Pipeline = _CreatePipeline(self, datadescription)
|
||||
|
||||
coprocessor = CoProcessor()
|
||||
freqs = {'input': [10, 100]}
|
||||
coprocessor.SetUpdateFrequencies(freqs)
|
||||
return coprocessor
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Global variables that will hold the pipeline for each timestep
|
||||
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
|
||||
# It will be automatically setup when coprocessor.UpdateProducers() is called the
|
||||
# first time.
|
||||
coprocessor = CreateCoProcessor()
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Enable Live-Visualizaton with ParaView
|
||||
coprocessor.EnableLiveVisualization(False)
|
||||
|
||||
|
||||
# ---------------------- Data Selection method ----------------------
|
||||
|
||||
def RequestDataDescription(datadescription):
|
||||
"Callback to populate the request for current timestep"
|
||||
global coprocessor
|
||||
if datadescription.GetForceOutput() == True:
|
||||
# We are just going to request all fields and meshes from the simulation
|
||||
# code/adaptor.
|
||||
for i in range(datadescription.GetNumberOfInputDescriptions()):
|
||||
datadescription.GetInputDescription(i).AllFieldsOn()
|
||||
datadescription.GetInputDescription(i).GenerateMeshOn()
|
||||
return
|
||||
|
||||
# setup requests for all inputs based on the requirements of the
|
||||
# pipeline.
|
||||
coprocessor.LoadRequestedData(datadescription)
|
||||
|
||||
# ------------------------ Processing method ------------------------
|
||||
|
||||
def DoCoProcessing(datadescription):
|
||||
"Callback to do co-processing for current timestep"
|
||||
global coprocessor
|
||||
|
||||
# Update the coprocessor by providing it the newly generated simulation data.
|
||||
# If the pipeline hasn't been setup yet, this will setup the pipeline.
|
||||
coprocessor.UpdateProducers(datadescription)
|
||||
|
||||
# Write output data, if appropriate.
|
||||
coprocessor.WriteData(datadescription);
|
||||
|
||||
# Write image capture (Last arg: rescale lookup table), if appropriate.
|
||||
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
|
||||
|
||||
# Live Visualization, if enabled.
|
||||
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)
|
||||
@ -0,0 +1,22 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(CatalystCxxNonOverlappingAMRExample)
|
||||
|
||||
find_package(ParaView 4.1 REQUIRED COMPONENTS vtkPVPythonCatalyst)
|
||||
include("${PARAVIEW_USE_FILE}")
|
||||
set(Adaptor_SRCS
|
||||
FEAdaptor.cxx
|
||||
)
|
||||
add_library(CxxNonOverlappingAMRExampleAdaptor ${Adaptor_SRCS})
|
||||
target_link_libraries(CxxNonOverlappingAMRExampleAdaptor vtkPVPythonCatalyst)
|
||||
add_definitions("-DUSE_CATALYST")
|
||||
|
||||
add_executable(CxxNonOverlappingAMRExample FEDriver.cxx)
|
||||
target_link_libraries(CxxNonOverlappingAMRExample CxxNonOverlappingAMRExampleAdaptor)
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_test(NAME CxxNonOverlappingAMRExampleTest COMMAND CxxNonOverlappingAMRExample ${CMAKE_CURRENT_SOURCE_DIR}/SampleScripts/feslicescript.py)
|
||||
set_tests_properties(CxxNonOverlappingAMRExampleTest PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
endif()
|
||||
@ -0,0 +1,121 @@
|
||||
#include <iostream>
|
||||
#include "FEAdaptor.h"
|
||||
|
||||
#include <vtkCompositeDataIterator.h>
|
||||
#include <vtkCPDataDescription.h>
|
||||
#include <vtkCPInputDataDescription.h>
|
||||
#include <vtkCPProcessor.h>
|
||||
#include <vtkCPPythonScriptPipeline.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkNonOverlappingAMR.h>
|
||||
#include <vtkUniformGrid.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
vtkCPProcessor* Processor = NULL;
|
||||
vtkNonOverlappingAMR* VTKGrid;
|
||||
|
||||
void BuildVTKGrid()
|
||||
{
|
||||
if(VTKGrid == NULL)
|
||||
{
|
||||
// The grid structure isn't changing so we only build it
|
||||
// the first time it's needed. If we needed the memory
|
||||
// we could delete it and rebuild as necessary.
|
||||
VTKGrid = vtkNonOverlappingAMR::New();
|
||||
}
|
||||
|
||||
// Note that all of the vtkUniformGrids in the vtkNonOverlappingAMR
|
||||
// grid can use independent spacing, origin and extents. This is
|
||||
// shown in the mid-level grids in that they don't share an
|
||||
// origin. The highest level grid and lowest level grid do share
|
||||
// the same origin of (0,0,0) and thus need to have appropriate
|
||||
// extents and spacings as well.
|
||||
int numberOfLevels = 3;
|
||||
int blocksPerLevel[3] = {1, 2, 1};
|
||||
VTKGrid->Initialize(numberOfLevels, blocksPerLevel);
|
||||
|
||||
// the highest level grid
|
||||
vtkNew<vtkUniformGrid> level0Grid;
|
||||
level0Grid->SetSpacing(4, 4, 4);
|
||||
level0Grid->SetOrigin(0, 0, 0);
|
||||
level0Grid->SetExtent(0, 10, 0, 20, 0, 20);
|
||||
VTKGrid->SetDataSet(0, 0, level0Grid.GetPointer());
|
||||
|
||||
// the first mid-level grid
|
||||
vtkNew<vtkUniformGrid> level1Grid0;
|
||||
level1Grid0->SetSpacing(2, 2, 2);
|
||||
level1Grid0->SetOrigin(40, 0, 0);
|
||||
level1Grid0->SetExtent(0, 8, 0, 20, 0, 40);
|
||||
VTKGrid->SetDataSet(1, 0, level1Grid0.GetPointer());
|
||||
|
||||
// the second mid-level grid
|
||||
vtkNew<vtkUniformGrid> level1Grid1;
|
||||
level1Grid1->SetSpacing(2, 2, 2);
|
||||
level1Grid1->SetOrigin(40, 40, 0);
|
||||
level1Grid1->SetExtent(0, 40, 0, 20, 0, 40);
|
||||
VTKGrid->SetDataSet(1, 1, level1Grid1.GetPointer());
|
||||
|
||||
// the lowest level grid
|
||||
vtkNew<vtkUniformGrid> level2Grid;
|
||||
level2Grid->SetSpacing(1, 1, 2);
|
||||
level2Grid->SetOrigin(0, 0, 0);
|
||||
level2Grid->SetExtent(56, 120, 0, 40, 0, 40);
|
||||
VTKGrid->SetDataSet(2, 0, level2Grid.GetPointer());
|
||||
}
|
||||
}
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
void Initialize(int numScripts, char* scripts[])
|
||||
{
|
||||
if(Processor == NULL)
|
||||
{
|
||||
Processor = vtkCPProcessor::New();
|
||||
Processor->Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
Processor->RemoveAllPipelines();
|
||||
}
|
||||
for(int i=1;i<numScripts;i++)
|
||||
{
|
||||
vtkNew<vtkCPPythonScriptPipeline> pipeline;
|
||||
pipeline->Initialize(scripts[i]);
|
||||
Processor->AddPipeline(pipeline.GetPointer());
|
||||
}
|
||||
}
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
if(Processor)
|
||||
{
|
||||
Processor->Delete();
|
||||
Processor = NULL;
|
||||
}
|
||||
if(VTKGrid)
|
||||
{
|
||||
VTKGrid->Delete();
|
||||
VTKGrid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CoProcess(double time, unsigned int timeStep, bool lastTimeStep)
|
||||
{
|
||||
vtkNew<vtkCPDataDescription> dataDescription;
|
||||
dataDescription->AddInput("input");
|
||||
dataDescription->SetTimeData(time, timeStep);
|
||||
if(lastTimeStep == true)
|
||||
{
|
||||
// assume that we want to all the pipelines to execute if it
|
||||
// is the last time step.
|
||||
dataDescription->ForceOutputOn();
|
||||
}
|
||||
if(Processor->RequestDataDescription(dataDescription.GetPointer()) != 0)
|
||||
{
|
||||
BuildVTKGrid();
|
||||
dataDescription->GetInputDescriptionByName("input")->SetGrid(VTKGrid);
|
||||
Processor->CoProcess(dataDescription.GetPointer());
|
||||
}
|
||||
}
|
||||
} // end of Catalyst namespace
|
||||
@ -0,0 +1,13 @@
|
||||
#ifndef FEADAPTOR_HEADER
|
||||
#define FEADAPTOR_HEADER
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
void Initialize(int numScripts, char* scripts[]);
|
||||
|
||||
void Finalize();
|
||||
|
||||
void CoProcess(double time, unsigned int timeStep, bool lastTimeStep);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,25 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "FEAdaptor.h"
|
||||
|
||||
// Example of a C++ adaptor for a simulation code
|
||||
// where the simulation code has a fixed topology
|
||||
// grid. The grid in this case is a vtkNonOverlappingAMR
|
||||
// data set without any attributes specified
|
||||
// over the grid.
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
FEAdaptor::Initialize(argc, argv);
|
||||
unsigned int numberOfTimeSteps = 100;
|
||||
for(unsigned int timeStep=0;timeStep<numberOfTimeSteps;timeStep++)
|
||||
{
|
||||
// use a time step length of 0.1
|
||||
double time = timeStep * 0.1;
|
||||
FEAdaptor::CoProcess(time, timeStep, timeStep == numberOfTimeSteps-1);
|
||||
}
|
||||
FEAdaptor::Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
|
||||
try: paraview.simple
|
||||
except: from paraview.simple import *
|
||||
|
||||
from paraview import coprocessing
|
||||
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Code generated from cpstate.py to create the CoProcessor.
|
||||
|
||||
|
||||
# ----------------------- CoProcessor definition -----------------------
|
||||
|
||||
def CreateCoProcessor():
|
||||
def _CreatePipeline(coprocessor, datadescription):
|
||||
class Pipeline:
|
||||
filename_4_vthb = coprocessor.CreateProducer( datadescription, "input" )
|
||||
|
||||
Slice1 = Slice( guiName="Slice1", Crinkleslice=0, SliceOffsetValues=[0.0], Triangulatetheslice=1, SliceType="Plane" )
|
||||
Slice1.SliceType.Offset = 0.0
|
||||
Slice1.SliceType.Origin = [20.0, 40.0, 40.0]
|
||||
Slice1.SliceType.Normal = [1.0, 0.0, 0.0]
|
||||
|
||||
ParallelMultiBlockDataSetWriter1 = coprocessor.CreateWriter( XMLMultiBlockDataWriter, "slice_%t.vtm", 10 )
|
||||
|
||||
return Pipeline()
|
||||
|
||||
class CoProcessor(coprocessing.CoProcessor):
|
||||
def CreatePipeline(self, datadescription):
|
||||
self.Pipeline = _CreatePipeline(self, datadescription)
|
||||
|
||||
coprocessor = CoProcessor()
|
||||
freqs = {'input': [10]}
|
||||
coprocessor.SetUpdateFrequencies(freqs)
|
||||
return coprocessor
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Global variables that will hold the pipeline for each timestep
|
||||
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
|
||||
# It will be automatically setup when coprocessor.UpdateProducers() is called the
|
||||
# first time.
|
||||
coprocessor = CreateCoProcessor()
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Enable Live-Visualizaton with ParaView
|
||||
coprocessor.EnableLiveVisualization(False)
|
||||
|
||||
|
||||
# ---------------------- Data Selection method ----------------------
|
||||
|
||||
def RequestDataDescription(datadescription):
|
||||
"Callback to populate the request for current timestep"
|
||||
global coprocessor
|
||||
if datadescription.GetForceOutput() == True:
|
||||
# We are just going to request all fields and meshes from the simulation
|
||||
# code/adaptor.
|
||||
for i in range(datadescription.GetNumberOfInputDescriptions()):
|
||||
datadescription.GetInputDescription(i).AllFieldsOn()
|
||||
datadescription.GetInputDescription(i).GenerateMeshOn()
|
||||
return
|
||||
|
||||
# setup requests for all inputs based on the requirements of the
|
||||
# pipeline.
|
||||
coprocessor.LoadRequestedData(datadescription)
|
||||
|
||||
# ------------------------ Processing method ------------------------
|
||||
|
||||
def DoCoProcessing(datadescription):
|
||||
"Callback to do co-processing for current timestep"
|
||||
global coprocessor
|
||||
|
||||
# Update the coprocessor by providing it the newly generated simulation data.
|
||||
# If the pipeline hasn't been setup yet, this will setup the pipeline.
|
||||
coprocessor.UpdateProducers(datadescription)
|
||||
|
||||
# Write output data, if appropriate.
|
||||
coprocessor.WriteData(datadescription);
|
||||
|
||||
# Write image capture (Last arg: rescale lookup table), if appropriate.
|
||||
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
|
||||
|
||||
# Live Visualization, if enabled.
|
||||
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)
|
||||
@ -0,0 +1,22 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(CatalystCxxOverlappingAMRExample)
|
||||
|
||||
find_package(ParaView 4.1 REQUIRED COMPONENTS vtkPVPythonCatalyst)
|
||||
include("${PARAVIEW_USE_FILE}")
|
||||
set(Adaptor_SRCS
|
||||
FEAdaptor.cxx
|
||||
)
|
||||
add_library(CxxOverlappingAMRExampleAdaptor ${Adaptor_SRCS})
|
||||
target_link_libraries(CxxOverlappingAMRExampleAdaptor vtkPVPythonCatalyst)
|
||||
|
||||
add_executable(CxxOverlappingAMRExample FEDriver.cxx)
|
||||
target_link_libraries(CxxOverlappingAMRExample CxxOverlappingAMRExampleAdaptor)
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_test(NAME CxxOverlappingAMRExampleTest COMMAND CxxOverlappingAMRExample
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SampleScripts/feslicescript.py)
|
||||
set_tests_properties(CxxOverlappingAMRExampleTest PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
endif()
|
||||
@ -0,0 +1,131 @@
|
||||
#include <iostream>
|
||||
#include "FEAdaptor.h"
|
||||
|
||||
#include <vtkAMRBox.h>
|
||||
#include <vtkCompositeDataIterator.h>
|
||||
#include <vtkCPDataDescription.h>
|
||||
#include <vtkCPInputDataDescription.h>
|
||||
#include <vtkCPProcessor.h>
|
||||
#include <vtkCPPythonScriptPipeline.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkOverlappingAMR.h>
|
||||
#include <vtkUniformGrid.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
vtkCPProcessor* Processor = NULL;
|
||||
vtkOverlappingAMR* VTKGrid;
|
||||
|
||||
void BuildVTKGrid()
|
||||
{
|
||||
if(VTKGrid == NULL)
|
||||
{
|
||||
// The grid structure isn't changing so we only build it
|
||||
// the first time it's needed. If we needed the memory
|
||||
// we could delete it and rebuild as necessary.
|
||||
VTKGrid = vtkOverlappingAMR::New();
|
||||
BuildVTKGrid();
|
||||
}
|
||||
|
||||
int numberOfLevels = 3;
|
||||
int blocksPerLevel[3] = {1, 1, 1};
|
||||
VTKGrid->Initialize(numberOfLevels, blocksPerLevel);
|
||||
VTKGrid->SetGridDescription(VTK_XYZ_GRID);
|
||||
double origin[] = {0,0,0};
|
||||
double level0Spacing[] = {4, 4, 4};
|
||||
double level1Spacing[] = {2, 2, 2};
|
||||
double level2Spacing[] = {1, 1, 1};
|
||||
VTKGrid->SetOrigin(origin);
|
||||
int level0Dims[] = {25, 25, 25};
|
||||
vtkAMRBox level0Box(origin, level0Dims, level0Spacing, origin, VTK_XYZ_GRID);
|
||||
int level1Dims[] = {20, 20, 20};
|
||||
vtkAMRBox level1Box(origin, level1Dims, level1Spacing, origin, VTK_XYZ_GRID);
|
||||
int level2Dims[] = {10, 10, 10};
|
||||
vtkAMRBox level2Box(origin, level2Dims, level2Spacing, origin, VTK_XYZ_GRID);
|
||||
VTKGrid->SetSpacing(0, level0Spacing);
|
||||
VTKGrid->SetAMRBox(0, 0, level0Box);
|
||||
|
||||
VTKGrid->SetSpacing(1, level1Spacing);
|
||||
VTKGrid->SetAMRBox(1, 0, level1Box);
|
||||
|
||||
VTKGrid->SetSpacing(2, level2Spacing);
|
||||
VTKGrid->SetAMRBox(2, 0, level2Box);
|
||||
|
||||
VTKGrid->GenerateParentChildInformation();
|
||||
|
||||
// the highest level grid
|
||||
vtkNew<vtkUniformGrid> level0Grid;
|
||||
level0Grid->SetSpacing(level0Spacing);
|
||||
level0Grid->SetOrigin(0, 0, 0);
|
||||
level0Grid->SetExtent(0, 25, 0, 25, 0, 25);
|
||||
VTKGrid->SetDataSet(0, 0, level0Grid.GetPointer());
|
||||
|
||||
// the mid-level grid
|
||||
vtkNew<vtkUniformGrid> level1Grid0;
|
||||
level1Grid0->SetSpacing(level1Spacing);
|
||||
level1Grid0->SetExtent(0, 20, 0, 20, 0, 20);
|
||||
VTKGrid->SetDataSet(1, 0, level1Grid0.GetPointer());
|
||||
|
||||
// the lowest level grid
|
||||
vtkNew<vtkUniformGrid> level2Grid;
|
||||
level2Grid->SetSpacing(level2Spacing);
|
||||
level2Grid->SetExtent(0, 10, 0, 10, 0, 10);
|
||||
VTKGrid->SetDataSet(2, 0, level2Grid.GetPointer());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
void Initialize(int numScripts, char* scripts[])
|
||||
{
|
||||
if(Processor == NULL)
|
||||
{
|
||||
Processor = vtkCPProcessor::New();
|
||||
Processor->Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
Processor->RemoveAllPipelines();
|
||||
}
|
||||
for(int i=1;i<numScripts;i++)
|
||||
{
|
||||
vtkNew<vtkCPPythonScriptPipeline> pipeline;
|
||||
pipeline->Initialize(scripts[i]);
|
||||
Processor->AddPipeline(pipeline.GetPointer());
|
||||
}
|
||||
}
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
if(Processor)
|
||||
{
|
||||
Processor->Delete();
|
||||
Processor = NULL;
|
||||
}
|
||||
if(VTKGrid)
|
||||
{
|
||||
VTKGrid->Delete();
|
||||
VTKGrid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CoProcess(double time, unsigned int timeStep, bool lastTimeStep)
|
||||
{
|
||||
vtkNew<vtkCPDataDescription> dataDescription;
|
||||
dataDescription->AddInput("input");
|
||||
dataDescription->SetTimeData(time, timeStep);
|
||||
if(lastTimeStep == true)
|
||||
{
|
||||
// assume that we want to all the pipelines to execute if it
|
||||
// is the last time step.
|
||||
dataDescription->ForceOutputOn();
|
||||
}
|
||||
if(Processor->RequestDataDescription(dataDescription.GetPointer()) != 0)
|
||||
{
|
||||
BuildVTKGrid();
|
||||
dataDescription->GetInputDescriptionByName("input")->SetGrid(VTKGrid);
|
||||
Processor->CoProcess(dataDescription.GetPointer());
|
||||
}
|
||||
}
|
||||
} // end of Catalyst namespace
|
||||
@ -0,0 +1,13 @@
|
||||
#ifndef FEADAPTOR_HEADER
|
||||
#define FEADAPTOR_HEADER
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
void Initialize(int numScripts, char* scripts[]);
|
||||
|
||||
void Finalize();
|
||||
|
||||
void CoProcess(double time, unsigned int timeStep, bool lastTimeStep);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,25 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "FEAdaptor.h"
|
||||
|
||||
// Example of a C++ adaptor for a simulation code
|
||||
// where the simulation code has a fixed topology
|
||||
// grid. The grid in this case is a vtkOverlappingAMR
|
||||
// data set without any attributes specified
|
||||
// over the grid.
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
FEAdaptor::Initialize(argc, argv);
|
||||
unsigned int numberOfTimeSteps = 100;
|
||||
for(unsigned int timeStep=0;timeStep<numberOfTimeSteps;timeStep++)
|
||||
{
|
||||
// use a time step length of 0.1
|
||||
double time = timeStep * 0.1;
|
||||
FEAdaptor::CoProcess(time, timeStep, timeStep == numberOfTimeSteps-1);
|
||||
}
|
||||
FEAdaptor::Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
|
||||
try: paraview.simple
|
||||
except: from paraview.simple import *
|
||||
|
||||
from paraview import coprocessing
|
||||
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Code generated from cpstate.py to create the CoProcessor.
|
||||
|
||||
|
||||
# ----------------------- CoProcessor definition -----------------------
|
||||
|
||||
def CreateCoProcessor():
|
||||
def _CreatePipeline(coprocessor, datadescription):
|
||||
class Pipeline:
|
||||
filename_10_vthb = coprocessor.CreateProducer( datadescription, "input" )
|
||||
|
||||
Slice1 = Slice( guiName="Slice1", Crinkleslice=0, SliceOffsetValues=[0.0], Triangulatetheslice=1, SliceType="Plane" )
|
||||
Slice1.SliceType.Offset = 0.0
|
||||
Slice1.SliceType.Origin = [1.9627925694422252, 50.0, 50.0]
|
||||
Slice1.SliceType.Normal = [1.0, 0.0, 0.0]
|
||||
|
||||
ParallelMultiBlockDataSetWriter1 = coprocessor.CreateWriter( XMLMultiBlockDataWriter, "filename_%t.vtm", 10 )
|
||||
|
||||
return Pipeline()
|
||||
|
||||
class CoProcessor(coprocessing.CoProcessor):
|
||||
def CreatePipeline(self, datadescription):
|
||||
self.Pipeline = _CreatePipeline(self, datadescription)
|
||||
|
||||
coprocessor = CoProcessor()
|
||||
freqs = {'input': [10]}
|
||||
coprocessor.SetUpdateFrequencies(freqs)
|
||||
return coprocessor
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Global variables that will hold the pipeline for each timestep
|
||||
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
|
||||
# It will be automatically setup when coprocessor.UpdateProducers() is called the
|
||||
# first time.
|
||||
coprocessor = CreateCoProcessor()
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Enable Live-Visualizaton with ParaView
|
||||
coprocessor.EnableLiveVisualization(False)
|
||||
|
||||
|
||||
# ---------------------- Data Selection method ----------------------
|
||||
|
||||
def RequestDataDescription(datadescription):
|
||||
"Callback to populate the request for current timestep"
|
||||
global coprocessor
|
||||
if datadescription.GetForceOutput() == True:
|
||||
# We are just going to request all fields and meshes from the simulation
|
||||
# code/adaptor.
|
||||
for i in range(datadescription.GetNumberOfInputDescriptions()):
|
||||
datadescription.GetInputDescription(i).AllFieldsOn()
|
||||
datadescription.GetInputDescription(i).GenerateMeshOn()
|
||||
return
|
||||
|
||||
# setup requests for all inputs based on the requirements of the
|
||||
# pipeline.
|
||||
coprocessor.LoadRequestedData(datadescription)
|
||||
|
||||
# ------------------------ Processing method ------------------------
|
||||
|
||||
def DoCoProcessing(datadescription):
|
||||
"Callback to do co-processing for current timestep"
|
||||
global coprocessor
|
||||
|
||||
# Update the coprocessor by providing it the newly generated simulation data.
|
||||
# If the pipeline hasn't been setup yet, this will setup the pipeline.
|
||||
coprocessor.UpdateProducers(datadescription)
|
||||
|
||||
# Write output data, if appropriate.
|
||||
coprocessor.WriteData(datadescription);
|
||||
|
||||
# Write image capture (Last arg: rescale lookup table), if appropriate.
|
||||
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
|
||||
|
||||
# Live Visualization, if enabled.
|
||||
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)
|
||||
@ -0,0 +1,41 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(CatalystCxxPVSMPipelineExample)
|
||||
|
||||
set(USE_CATALYST ON CACHE BOOL "Link the simulator with Catalyst")
|
||||
if(USE_CATALYST)
|
||||
# We have a C++ pipeline so we don't need to link with Python
|
||||
# or vtkPVPythonCatalyst since vtkPVCatalyst is sufficient.
|
||||
find_package(ParaView 4.1 REQUIRED COMPONENTS vtkPVCatalyst vtkPVVTKExtensionsDefault)
|
||||
include("${PARAVIEW_USE_FILE}")
|
||||
set(Adaptor_SRCS
|
||||
FEAdaptor.cxx
|
||||
vtkCPPVSMPipeline.cxx
|
||||
)
|
||||
add_library(CxxPVSMPipelineExampleAdaptor ${Adaptor_SRCS})
|
||||
target_link_libraries(CxxPVSMPipelineExampleAdaptor vtkPVCatalyst vtkPVVTKExtensionsDefault)
|
||||
add_definitions("-DUSE_CATALYST")
|
||||
if(NOT PARAVIEW_USE_MPI)
|
||||
message(SEND_ERROR "ParaView must be built with MPI enabled")
|
||||
endif()
|
||||
else()
|
||||
find_package(MPI REQUIRED)
|
||||
include_directories(${MPI_CXX_INCLUDE_PATH})
|
||||
endif()
|
||||
|
||||
add_executable(CxxPVSMPipelineExample FEDriver.cxx FEDataStructures.cxx)
|
||||
if(USE_CATALYST)
|
||||
target_link_libraries(CxxPVSMPipelineExample LINK_PRIVATE CxxPVSMPipelineExampleAdaptor)
|
||||
include(vtkModuleMacros)
|
||||
include(vtkMPI)
|
||||
vtk_mpi_link(CxxPVSMPipelineExample)
|
||||
else()
|
||||
target_link_libraries(CxxPVSMPipelineExample LINK_PRIVATE ${MPI_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_test(NAME CxxPVSMPipelineExampleTest COMMAND CxxPVSMPipelineExample 5 output)
|
||||
set_tests_properties(CxxPVSMPipelineExampleTest PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
endif()
|
||||
@ -0,0 +1,149 @@
|
||||
#include <iostream>
|
||||
#include "FEAdaptor.h"
|
||||
#include "FEDataStructures.h"
|
||||
#include "vtkCPPVSMPipeline.h"
|
||||
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkCellType.h>
|
||||
#include <vtkCPDataDescription.h>
|
||||
#include <vtkCPInputDataDescription.h>
|
||||
#include <vtkCPProcessor.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkFloatArray.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkPoints.h>
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
#include <vtkSMSession.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
vtkCPProcessor* Processor = NULL;
|
||||
vtkUnstructuredGrid* VTKGrid;
|
||||
|
||||
void BuildVTKGrid(Grid& grid)
|
||||
{
|
||||
// create the points information
|
||||
vtkNew<vtkDoubleArray> pointArray;
|
||||
pointArray->SetNumberOfComponents(3);
|
||||
pointArray->SetArray(grid.GetPointsArray(), static_cast<vtkIdType>(grid.GetNumberOfPoints()*3), 1);
|
||||
vtkNew<vtkPoints> points;
|
||||
points->SetData(pointArray.GetPointer());
|
||||
VTKGrid->SetPoints(points.GetPointer());
|
||||
|
||||
// create the cells
|
||||
size_t numCells = grid.GetNumberOfCells();
|
||||
VTKGrid->Allocate(static_cast<vtkIdType>(numCells*9));
|
||||
for(size_t cell=0;cell<numCells;cell++)
|
||||
{
|
||||
unsigned int* cellPoints = grid.GetCellPoints(cell);
|
||||
vtkIdType tmp[8] = {cellPoints[0], cellPoints[1], cellPoints[2], cellPoints[3],
|
||||
cellPoints[4], cellPoints[5], cellPoints[6], cellPoints[7]};
|
||||
VTKGrid->InsertNextCell(VTK_HEXAHEDRON, 8, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateVTKAttributes(Grid& grid, Attributes& attributes)
|
||||
{
|
||||
if(VTKGrid->GetPointData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// velocity array
|
||||
vtkNew<vtkDoubleArray> velocity;
|
||||
velocity->SetName("velocity");
|
||||
velocity->SetNumberOfComponents(3);
|
||||
velocity->SetNumberOfTuples(static_cast<vtkIdType>(grid.GetNumberOfPoints()));
|
||||
VTKGrid->GetPointData()->AddArray(velocity.GetPointer());
|
||||
}
|
||||
if(VTKGrid->GetCellData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// pressure array
|
||||
vtkNew<vtkFloatArray> pressure;
|
||||
pressure->SetName("pressure");
|
||||
pressure->SetNumberOfComponents(1);
|
||||
VTKGrid->GetCellData()->AddArray(pressure.GetPointer());
|
||||
}
|
||||
vtkDoubleArray* velocity = vtkDoubleArray::SafeDownCast(
|
||||
VTKGrid->GetPointData()->GetArray("velocity"));
|
||||
// The velocity array is ordered as vx0,vx1,vx2,..,vy0,vy1,vy2,..,vz0,vz1,vz2,..
|
||||
// so we need to create a full copy of it with VTK's ordering of
|
||||
// vx0,vy0,vz0,vx1,vy1,vz1,..
|
||||
double* velocityData = attributes.GetVelocityArray();
|
||||
vtkIdType numTuples = velocity->GetNumberOfTuples();
|
||||
for(vtkIdType i=0;i<numTuples;i++)
|
||||
{
|
||||
double values[3] = {velocityData[i], velocityData[i+numTuples],
|
||||
velocityData[i+2*numTuples]};
|
||||
velocity->SetTupleValue(i, values);
|
||||
}
|
||||
|
||||
vtkFloatArray* pressure = vtkFloatArray::SafeDownCast(
|
||||
VTKGrid->GetCellData()->GetArray("pressure"));
|
||||
// The pressure array is a scalar array so we can reuse
|
||||
// memory as long as we ordered the points properly.
|
||||
float* pressureData = attributes.GetPressureArray();
|
||||
pressure->SetArray(pressureData, static_cast<vtkIdType>(grid.GetNumberOfCells()), 1);
|
||||
}
|
||||
|
||||
void BuildVTKDataStructures(Grid& grid, Attributes& attributes)
|
||||
{
|
||||
if(VTKGrid == NULL)
|
||||
{
|
||||
// The grid structure isn't changing so we only build it
|
||||
// the first time it's needed. If we needed the memory
|
||||
// we could delete it and rebuild as necessary.
|
||||
VTKGrid = vtkUnstructuredGrid::New();
|
||||
BuildVTKGrid(grid);
|
||||
}
|
||||
UpdateVTKAttributes(grid, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
void Initialize(int outputFrequency, std::string fileName)
|
||||
{
|
||||
if(Processor == NULL)
|
||||
{
|
||||
Processor = vtkCPProcessor::New();
|
||||
Processor->Initialize();
|
||||
}
|
||||
vtkSMSession::ConnectToSelf();
|
||||
vtkNew<vtkCPPVSMPipeline> pipeline;
|
||||
pipeline->Initialize(outputFrequency, fileName);
|
||||
Processor->AddPipeline(pipeline.GetPointer());
|
||||
}
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
if(Processor)
|
||||
{
|
||||
Processor->Delete();
|
||||
Processor = NULL;
|
||||
}
|
||||
if(VTKGrid)
|
||||
{
|
||||
VTKGrid->Delete();
|
||||
VTKGrid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep)
|
||||
{
|
||||
vtkNew<vtkCPDataDescription> dataDescription;
|
||||
dataDescription->AddInput("input");
|
||||
dataDescription->SetTimeData(time, timeStep);
|
||||
if(lastTimeStep == true)
|
||||
{
|
||||
// assume that we want to all the pipelines to execute if it
|
||||
// is the last time step.
|
||||
dataDescription->ForceOutputOn();
|
||||
}
|
||||
if(Processor->RequestDataDescription(dataDescription.GetPointer()) != 0)
|
||||
{
|
||||
BuildVTKDataStructures(grid, attributes);
|
||||
dataDescription->GetInputDescriptionByName("input")->SetGrid(VTKGrid);
|
||||
Processor->CoProcess(dataDescription.GetPointer());
|
||||
}
|
||||
}
|
||||
} // end of Catalyst namespace
|
||||
@ -0,0 +1,19 @@
|
||||
#ifndef FEADAPTOR_HEADER
|
||||
#define FEADAPTOR_HEADER
|
||||
|
||||
#include <string>
|
||||
|
||||
class Attributes;
|
||||
class Grid;
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
void Initialize(int outputFrequency, std::string fileName);
|
||||
|
||||
void Finalize();
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,153 @@
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <mpi.h>
|
||||
#include <iostream>
|
||||
|
||||
Grid::Grid()
|
||||
{}
|
||||
|
||||
void Grid::Initialize(const unsigned int numPoints[3], const double spacing[3] )
|
||||
{
|
||||
if(numPoints[0] == 0 || numPoints[1] == 0 || numPoints[2] == 0)
|
||||
{
|
||||
std::cerr << "Must have a non-zero amount of points in each direction.\n";
|
||||
}
|
||||
// in parallel, we do a simple partitioning in the x-direction.
|
||||
int mpiSize = 1;
|
||||
int mpiRank = 0;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
|
||||
|
||||
unsigned int startXPoint = mpiRank*numPoints[0]/mpiSize;
|
||||
unsigned int endXPoint = (mpiRank+1)*numPoints[0]/mpiSize;
|
||||
if(mpiSize != mpiRank+1)
|
||||
{
|
||||
endXPoint++;
|
||||
}
|
||||
|
||||
// create the points -- slowest in the x and fastest in the z directions
|
||||
double coord[3] = {0,0,0};
|
||||
for(unsigned int i=startXPoint;i<endXPoint;i++)
|
||||
{
|
||||
coord[0] = i*spacing[0];
|
||||
for(unsigned int j=0;j<numPoints[1];j++)
|
||||
{
|
||||
coord[1] = j*spacing[1];
|
||||
for(unsigned int k=0;k<numPoints[2];k++)
|
||||
{
|
||||
coord[2] = k*spacing[2];
|
||||
// add the coordinate to the end of the vector
|
||||
std::copy(coord, coord+3, std::back_inserter(this->Points));
|
||||
}
|
||||
}
|
||||
}
|
||||
// create the hex cells
|
||||
unsigned int cellPoints[8];
|
||||
unsigned int numXPoints = endXPoint - startXPoint;
|
||||
for(unsigned int i=0;i<numXPoints-1;i++)
|
||||
{
|
||||
for(unsigned int j=0;j<numPoints[1]-1;j++)
|
||||
{
|
||||
for(unsigned int k=0;k<numPoints[2]-1;k++)
|
||||
{
|
||||
cellPoints[0] = i*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k;
|
||||
cellPoints[1] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k;
|
||||
cellPoints[2] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k;
|
||||
cellPoints[3] = i*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k;
|
||||
cellPoints[4] = i*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k+1;
|
||||
cellPoints[5] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k+1;
|
||||
cellPoints[6] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k+1;
|
||||
cellPoints[7] = i*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k+1;
|
||||
std::copy(cellPoints, cellPoints+8, std::back_inserter(this->Cells));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t Grid::GetNumberOfPoints()
|
||||
{
|
||||
return this->Points.size()/3;
|
||||
}
|
||||
|
||||
size_t Grid::GetNumberOfCells()
|
||||
{
|
||||
return this->Cells.size()/8;
|
||||
}
|
||||
|
||||
double* Grid::GetPointsArray()
|
||||
{
|
||||
if(this->Points.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &(this->Points[0]);
|
||||
}
|
||||
|
||||
double* Grid::GetPoint(size_t pointId)
|
||||
{
|
||||
if(pointId >= this->Points.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &(this->Points[pointId*3]);
|
||||
}
|
||||
|
||||
unsigned int* Grid::GetCellPoints(size_t cellId)
|
||||
{
|
||||
if(cellId >= this->Cells.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &(this->Cells[cellId*8]);
|
||||
}
|
||||
|
||||
Attributes::Attributes()
|
||||
{
|
||||
this->GridPtr = NULL;
|
||||
}
|
||||
|
||||
void Attributes::Initialize(Grid* grid)
|
||||
{
|
||||
this->GridPtr = grid;
|
||||
}
|
||||
|
||||
void Attributes::UpdateFields(double time)
|
||||
{
|
||||
size_t numPoints = this->GridPtr->GetNumberOfPoints();
|
||||
this->Velocity.resize(numPoints*3);
|
||||
for(size_t pt=0;pt<numPoints;pt++)
|
||||
{
|
||||
double* coord = this->GridPtr->GetPoint(pt);
|
||||
this->Velocity[pt] = coord[1]*time;
|
||||
}
|
||||
std::fill(this->Velocity.begin()+numPoints, this->Velocity.end(), 0.);
|
||||
size_t numCells = this->GridPtr->GetNumberOfCells();
|
||||
this->Pressure.resize(numCells);
|
||||
std::fill(this->Pressure.begin(), this->Pressure.end(), 1.);
|
||||
}
|
||||
|
||||
double* Attributes::GetVelocityArray()
|
||||
{
|
||||
if(this->Velocity.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &this->Velocity[0];
|
||||
}
|
||||
|
||||
float* Attributes::GetPressureArray()
|
||||
{
|
||||
if(this->Pressure.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &this->Pressure[0];
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
#ifndef FEDATASTRUCTURES_HEADER
|
||||
#define FEDATASTRUCTURES_HEADER
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
class Grid
|
||||
{
|
||||
public:
|
||||
Grid();
|
||||
void Initialize(const unsigned int numPoints[3], const double spacing[3]);
|
||||
size_t GetNumberOfPoints();
|
||||
size_t GetNumberOfCells();
|
||||
double* GetPointsArray();
|
||||
double* GetPoint(size_t pointId);
|
||||
unsigned int* GetCellPoints(size_t cellId);
|
||||
private:
|
||||
std::vector<double> Points;
|
||||
std::vector<unsigned int> Cells;
|
||||
};
|
||||
|
||||
class Attributes
|
||||
{
|
||||
// A class for generating and storing point and cell fields.
|
||||
// Velocity is stored at the points and pressure is stored
|
||||
// for the cells. The current velocity profile is for a
|
||||
// shearing flow with U(y,t) = y*t, V = 0 and W = 0.
|
||||
// Pressure is constant through the domain.
|
||||
public:
|
||||
Attributes();
|
||||
void Initialize(Grid* grid);
|
||||
void UpdateFields(double time);
|
||||
double* GetVelocityArray();
|
||||
float* GetPressureArray();
|
||||
|
||||
private:
|
||||
std::vector<double> Velocity;
|
||||
std::vector<float> Pressure;
|
||||
Grid* GridPtr;
|
||||
};
|
||||
#endif
|
||||
@ -0,0 +1,74 @@
|
||||
#include "FEDataStructures.h"
|
||||
#include <mpi.h>
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
#include <cstdlib>
|
||||
#include "FEAdaptor.h"
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
// Example of a C++ adaptor for a simulation code
|
||||
// where we use a hard-coded ParaView server-manager
|
||||
// C++ pipeline. The simulation code has a fixed topology
|
||||
// grid. We treat the grid as an unstructured
|
||||
// grid even though in the example provided it
|
||||
// would be best described as a vtkImageData.
|
||||
// Also, the points are stored in an inconsistent
|
||||
// manner with respect to the velocity vector.
|
||||
// This is purposefully done to demonstrate
|
||||
// the different approaches for getting data
|
||||
// into Catalyst. The hard-coded C++ pipeline
|
||||
// uses a slice filter to cut 4 planes through
|
||||
// the domain.
|
||||
// Note that through configuration
|
||||
// that the driver can be run without linking
|
||||
// to Catalyst.
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
MPI_Init(&argc, &argv);
|
||||
Grid grid;
|
||||
unsigned int numPoints[3] = {70, 60, 44};
|
||||
double spacing[3] = {1, 1.1, 1.3};
|
||||
grid.Initialize(numPoints, spacing);
|
||||
Attributes attributes;
|
||||
attributes.Initialize(&grid);
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
bool doCoProcessing = false;
|
||||
if(argc == 3)
|
||||
{
|
||||
doCoProcessing = true;
|
||||
// pass in the number of time steps and base file name.
|
||||
FEAdaptor::Initialize(atoi(argv[1]), argv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "To run with Catalyst you must pass in the output frequency and the base file name.\n";
|
||||
}
|
||||
#endif
|
||||
unsigned int numberOfTimeSteps = 15;
|
||||
for(unsigned int timeStep=0;timeStep<numberOfTimeSteps;timeStep++)
|
||||
{
|
||||
// use a time step length of 0.1
|
||||
double time = timeStep * 0.1;
|
||||
attributes.UpdateFields(time);
|
||||
#ifdef USE_CATALYST
|
||||
if(doCoProcessing)
|
||||
{
|
||||
FEAdaptor::CoProcess(grid, attributes, time, timeStep,
|
||||
timeStep == numberOfTimeSteps-1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
if(doCoProcessing)
|
||||
{
|
||||
FEAdaptor::Finalize();
|
||||
}
|
||||
#endif
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,163 @@
|
||||
#include "vtkCPPVSMPipeline.h"
|
||||
|
||||
#include <vtkCommunicator.h>
|
||||
#include <vtkCPDataDescription.h>
|
||||
#include <vtkCPInputDataDescription.h>
|
||||
#include <vtkMultiProcessController.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkObjectFactory.h>
|
||||
#include <vtkPVTrivialProducer.h>
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkSMDoubleVectorProperty.h>
|
||||
#include <vtkSMInputProperty.h>
|
||||
#include <vtkSMSourceProxy.h>
|
||||
#include <vtkSMSessionProxyManager.h>
|
||||
#include <vtkSMProxyManager.h>
|
||||
#include <vtkSMStringVectorProperty.h>
|
||||
#include <vtkSMWriterProxy.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
vtkStandardNewMacro(vtkCPPVSMPipeline);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
vtkCPPVSMPipeline::vtkCPPVSMPipeline()
|
||||
{
|
||||
this->OutputFrequency = 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
vtkCPPVSMPipeline::~vtkCPPVSMPipeline()
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void vtkCPPVSMPipeline::Initialize(int outputFrequency, std::string& fileName)
|
||||
{
|
||||
this->OutputFrequency = outputFrequency;
|
||||
this->FileName = fileName;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int vtkCPPVSMPipeline::RequestDataDescription(
|
||||
vtkCPDataDescription* dataDescription)
|
||||
{
|
||||
if(!dataDescription)
|
||||
{
|
||||
vtkWarningMacro("dataDescription is NULL.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(this->FileName.empty())
|
||||
{
|
||||
vtkWarningMacro("No output file name given to output results to.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(dataDescription->GetForceOutput() == true ||
|
||||
(this->OutputFrequency != 0 &&
|
||||
dataDescription->GetTimeStep() % this->OutputFrequency == 0) )
|
||||
{
|
||||
dataDescription->GetInputDescriptionByName("input")->AllFieldsOn();
|
||||
dataDescription->GetInputDescriptionByName("input")->GenerateMeshOn();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int vtkCPPVSMPipeline::CoProcess(
|
||||
vtkCPDataDescription* dataDescription)
|
||||
{
|
||||
if(!dataDescription)
|
||||
{
|
||||
vtkWarningMacro("DataDescription is NULL");
|
||||
return 0;
|
||||
}
|
||||
vtkUnstructuredGrid* grid = vtkUnstructuredGrid::SafeDownCast(
|
||||
dataDescription->GetInputDescriptionByName("input")->GetGrid());
|
||||
if(grid == NULL)
|
||||
{
|
||||
vtkWarningMacro("DataDescription is missing input unstructured grid.");
|
||||
return 0;
|
||||
}
|
||||
if(this->RequestDataDescription(dataDescription) == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
vtkSMProxyManager* proxyManager = vtkSMProxyManager::GetProxyManager();
|
||||
vtkSMSessionProxyManager* sessionProxyManager =
|
||||
proxyManager->GetActiveSessionProxyManager();
|
||||
|
||||
// Create a vtkPVTrivialProducer and set its output
|
||||
// to be the input grid.
|
||||
vtkSmartPointer<vtkSMSourceProxy> producer;
|
||||
producer.TakeReference(
|
||||
vtkSMSourceProxy::SafeDownCast(
|
||||
sessionProxyManager->NewProxy("sources", "PVTrivialProducer")));
|
||||
producer->UpdateVTKObjects();
|
||||
vtkObjectBase* clientSideObject = producer->GetClientSideObject();
|
||||
vtkPVTrivialProducer* realProducer =
|
||||
vtkPVTrivialProducer::SafeDownCast(clientSideObject);
|
||||
realProducer->SetOutput(grid);
|
||||
|
||||
// Create a slice filter and set the cut type to plane
|
||||
vtkSmartPointer<vtkSMSourceProxy> slice;
|
||||
slice.TakeReference(
|
||||
vtkSMSourceProxy::SafeDownCast(sessionProxyManager->NewProxy("filters", "Cut")));
|
||||
vtkSMInputProperty* sliceInputConnection =
|
||||
vtkSMInputProperty::SafeDownCast(slice->GetProperty("Input"));
|
||||
|
||||
vtkSMProxyProperty* cutType =
|
||||
vtkSMProxyProperty::SafeDownCast(slice->GetProperty("CutFunction"));
|
||||
vtkSmartPointer<vtkSMProxy> cutPlane;
|
||||
cutPlane.TakeReference(
|
||||
sessionProxyManager->NewProxy("implicit_functions", "Plane"));
|
||||
cutPlane->UpdatePropertyInformation();
|
||||
cutPlane->UpdateVTKObjects();
|
||||
cutType->SetProxy(0, cutPlane);
|
||||
cutType->UpdateAllInputs();
|
||||
|
||||
// We set 4 offsets, i.e. 4 parallel cut planes for the slice filter
|
||||
vtkSMDoubleVectorProperty* offsets =
|
||||
vtkSMDoubleVectorProperty::SafeDownCast(slice->GetProperty("ContourValues"));
|
||||
offsets->SetElements4(1, 11, 21, 31);
|
||||
|
||||
producer->UpdateVTKObjects();
|
||||
sliceInputConnection->SetInputConnection(0, producer, 0);
|
||||
slice->UpdatePropertyInformation();
|
||||
slice->UpdateVTKObjects();
|
||||
|
||||
// Finally, create the parallel poly data writer, set the
|
||||
// filename and then update the pipeline.
|
||||
vtkSmartPointer<vtkSMWriterProxy> writer;
|
||||
writer.TakeReference(
|
||||
vtkSMWriterProxy::SafeDownCast(sessionProxyManager->NewProxy("writers", "XMLPPolyDataWriter")));
|
||||
vtkSMInputProperty* writerInputConnection =
|
||||
vtkSMInputProperty::SafeDownCast(writer->GetProperty("Input"));
|
||||
writerInputConnection->SetInputConnection(0, slice, 0);
|
||||
vtkSMStringVectorProperty* fileName =
|
||||
vtkSMStringVectorProperty::SafeDownCast(writer->GetProperty("FileName"));
|
||||
|
||||
std::ostringstream o;
|
||||
o << dataDescription->GetTimeStep();
|
||||
std::string name = this->FileName + o.str() + ".pvtp";
|
||||
|
||||
fileName->SetElement(0, name.c_str());
|
||||
writer->UpdatePropertyInformation();
|
||||
writer->UpdateVTKObjects();
|
||||
writer->UpdatePipeline();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void vtkCPPVSMPipeline::PrintSelf(ostream& os, vtkIndent indent)
|
||||
{
|
||||
this->Superclass::PrintSelf(os, indent);
|
||||
os << indent << "OutputFrequency: " << this->OutputFrequency << "\n";
|
||||
os << indent << "FileName: " << this->FileName << "\n";
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
#ifndef VTKCPPVSMPIPELINE_H
|
||||
#define VTKCPPVSMPIPELINE_H
|
||||
|
||||
#include <vtkCPPipeline.h>
|
||||
#include <string>
|
||||
|
||||
class vtkCPDataDescription;
|
||||
class vtkCPPythonHelper;
|
||||
|
||||
class vtkCPPVSMPipeline : public vtkCPPipeline
|
||||
{
|
||||
public:
|
||||
static vtkCPPVSMPipeline* New();
|
||||
vtkTypeMacro(vtkCPPVSMPipeline,vtkCPPipeline);
|
||||
virtual void PrintSelf(ostream& os, vtkIndent indent);
|
||||
|
||||
virtual void Initialize(int outputFrequency, std::string& fileName);
|
||||
|
||||
virtual int RequestDataDescription(vtkCPDataDescription* dataDescription);
|
||||
|
||||
virtual int CoProcess(vtkCPDataDescription* dataDescription);
|
||||
|
||||
protected:
|
||||
vtkCPPVSMPipeline();
|
||||
virtual ~vtkCPPVSMPipeline();
|
||||
|
||||
private:
|
||||
vtkCPPVSMPipeline(const vtkCPPVSMPipeline&); // Not implemented
|
||||
void operator=(const vtkCPPVSMPipeline&); // Not implemented
|
||||
|
||||
int OutputFrequency;
|
||||
std::string FileName;
|
||||
};
|
||||
#endif
|
||||
@ -0,0 +1,58 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(CatalystCxxParticlePathExample)
|
||||
|
||||
set(USE_CATALYST ON CACHE BOOL "Link the simulator with Catalyst")
|
||||
if(USE_CATALYST)
|
||||
# we need 5.0 for the proper in situ particle path filter
|
||||
find_package(ParaView 5.0 REQUIRED COMPONENTS vtkPVPythonCatalyst)
|
||||
include("${PARAVIEW_USE_FILE}")
|
||||
set(Adaptor_SRCS
|
||||
FEAdaptor.cxx
|
||||
)
|
||||
add_library(CxxParticlePathExampleAdaptor ${Adaptor_SRCS})
|
||||
target_link_libraries(CxxParticlePathExampleAdaptor vtkPVPythonCatalyst vtkParallelMPI)
|
||||
add_definitions("-DUSE_CATALYST")
|
||||
if(NOT PARAVIEW_USE_MPI)
|
||||
message(SEND_ERROR "ParaView must be built with MPI enabled")
|
||||
endif()
|
||||
else()
|
||||
find_package(MPI REQUIRED)
|
||||
include_directories(${MPI_C_INCLUDE_PATH})
|
||||
endif()
|
||||
|
||||
add_executable(CxxParticlePathExample FEDriver.cxx FEDataStructures.cxx)
|
||||
if(USE_CATALYST)
|
||||
target_link_libraries(CxxParticlePathExample LINK_PRIVATE CxxParticlePathExampleAdaptor)
|
||||
include(vtkModuleMacros)
|
||||
include(vtkMPI)
|
||||
vtk_mpi_link(CxxParticlePathExample)
|
||||
else()
|
||||
target_link_libraries(CxxParticlePathExample LINK_PRIVATE ${MPI_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
include(CTest)
|
||||
|
||||
if(PARAVIEW_TEST_OUTPUT_DIR)
|
||||
set(TEST_OUTPUT_DIR ${PARAVIEW_TEST_OUTPUT_DIR})
|
||||
else(PARAVIEW_TEST_OUTPUT_DIR)
|
||||
set(TEST_OUTPUT_DIR "${CMAKE_BINARY_DIR}/Testing/Temporary")
|
||||
endif(PARAVIEW_TEST_OUTPUT_DIR)
|
||||
|
||||
add_test(NAME CxxParticlePathExampleTest
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DCOPROCESSING_TEST_DRIVER:FILEPATH=$<TARGET_FILE:CxxParticlePathExample>
|
||||
-DCOPROCESSING_TEST_DIR:PATH=${TEST_OUTPUT_DIR}
|
||||
-DCOPROCESSING_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}
|
||||
-DPVBATCH:FILEPATH=$<TARGET_FILE:pvbatch>
|
||||
-DMPIEXEC:FILEPATH=${MPIEXEC}
|
||||
-DMPIEXEC_NUMPROC_FLAG:STRING=${MPIEXEC_NUMPROC_FLAG}
|
||||
-DMPIEXEC_NUMPROCS=4
|
||||
-DMPIEXEC_PREFLAGS:STRING=${MPIEXEC_PREFLAGS}
|
||||
-DVTK_MPI_POSTFLAGS:STRING=${VTK_MPI_POSTFLAGS}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/ParticlePathTesting.cmake)
|
||||
set_tests_properties(CxxParticlePathExampleTest PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
|
||||
endif (BUILD_TESTING)
|
||||
@ -0,0 +1,142 @@
|
||||
#include <iostream>
|
||||
#include "FEAdaptor.h"
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkCellType.h>
|
||||
#include <vtkCPDataDescription.h>
|
||||
#include <vtkCPInputDataDescription.h>
|
||||
#include <vtkCPProcessor.h>
|
||||
#include <vtkCPPythonScriptPipeline.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkFloatArray.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkPoints.h>
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
vtkCPProcessor* Processor = NULL;
|
||||
|
||||
void BuildVTKGrid(Grid& grid, vtkUnstructuredGrid* vtkgrid)
|
||||
{
|
||||
// create the points information
|
||||
vtkNew<vtkDoubleArray> pointArray;
|
||||
pointArray->SetNumberOfComponents(3);
|
||||
pointArray->SetArray(grid.GetPointsArray(), static_cast<vtkIdType>(grid.GetNumberOfPoints()*3), 1);
|
||||
vtkNew<vtkPoints> points;
|
||||
points->SetData(pointArray.GetPointer());
|
||||
vtkgrid->SetPoints(points.GetPointer());
|
||||
|
||||
// create the cells
|
||||
size_t numCells = grid.GetNumberOfCells();
|
||||
vtkgrid->Allocate(static_cast<vtkIdType>(numCells*9));
|
||||
for(size_t cell=0;cell<numCells;cell++)
|
||||
{
|
||||
unsigned int* cellPoints = grid.GetCellPoints(cell);
|
||||
vtkIdType tmp[8] = {cellPoints[0], cellPoints[1], cellPoints[2], cellPoints[3],
|
||||
cellPoints[4], cellPoints[5], cellPoints[6], cellPoints[7]};
|
||||
vtkgrid->InsertNextCell(VTK_HEXAHEDRON, 8, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateVTKAttributes(Grid& grid, Attributes& attributes, vtkUnstructuredGrid* vtkgrid)
|
||||
{
|
||||
if(vtkgrid->GetPointData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// velocity array
|
||||
vtkNew<vtkDoubleArray> velocity;
|
||||
velocity->SetName("velocity");
|
||||
velocity->SetNumberOfComponents(3);
|
||||
velocity->SetNumberOfTuples(static_cast<vtkIdType>(grid.GetNumberOfPoints()));
|
||||
vtkgrid->GetPointData()->AddArray(velocity.GetPointer());
|
||||
}
|
||||
if(vtkgrid->GetCellData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// pressure array
|
||||
vtkNew<vtkFloatArray> pressure;
|
||||
pressure->SetName("pressure");
|
||||
pressure->SetNumberOfComponents(1);
|
||||
vtkgrid->GetCellData()->AddArray(pressure.GetPointer());
|
||||
}
|
||||
vtkDoubleArray* velocity = vtkDoubleArray::SafeDownCast(
|
||||
vtkgrid->GetPointData()->GetArray("velocity"));
|
||||
// The velocity array is ordered as vx0,vx1,vx2,..,vy0,vy1,vy2,..,vz0,vz1,vz2,..
|
||||
// so we need to create a full copy of it with VTK's ordering of
|
||||
// vx0,vy0,vz0,vx1,vy1,vz1,..
|
||||
double* velocityData = attributes.GetVelocityArray();
|
||||
vtkIdType numTuples = velocity->GetNumberOfTuples();
|
||||
for(vtkIdType i=0;i<numTuples;i++)
|
||||
{
|
||||
double values[3] = {velocityData[i], velocityData[i+numTuples],
|
||||
velocityData[i+2*numTuples]};
|
||||
velocity->SetTupleValue(i, values);
|
||||
}
|
||||
|
||||
vtkFloatArray* pressure = vtkFloatArray::SafeDownCast(
|
||||
vtkgrid->GetCellData()->GetArray("pressure"));
|
||||
// The pressure array is a scalar array so we can reuse
|
||||
// memory as long as we ordered the points properly.
|
||||
float* pressureData = attributes.GetPressureArray();
|
||||
pressure->SetArray(pressureData, static_cast<vtkIdType>(grid.GetNumberOfCells()), 1);
|
||||
}
|
||||
|
||||
void BuildVTKDataStructures(Grid& grid, Attributes& attributes, vtkUnstructuredGrid* vtkgrid)
|
||||
{
|
||||
BuildVTKGrid(grid, vtkgrid);
|
||||
UpdateVTKAttributes(grid, attributes, vtkgrid);
|
||||
}
|
||||
}
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
void Initialize(std::vector<std::string>& scripts)
|
||||
{
|
||||
if(Processor == NULL)
|
||||
{
|
||||
Processor = vtkCPProcessor::New();
|
||||
Processor->Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
Processor->RemoveAllPipelines();
|
||||
}
|
||||
for(std::vector<std::string>::iterator it=scripts.begin();it!=scripts.end();it++)
|
||||
{
|
||||
vtkNew<vtkCPPythonScriptPipeline> pipeline;
|
||||
pipeline->Initialize(it->c_str());
|
||||
Processor->AddPipeline(pipeline.GetPointer());
|
||||
}
|
||||
}
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
if(Processor)
|
||||
{
|
||||
Processor->Delete();
|
||||
Processor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep)
|
||||
{
|
||||
vtkNew<vtkCPDataDescription> dataDescription;
|
||||
dataDescription->AddInput("input");
|
||||
dataDescription->SetTimeData(time, timeStep);
|
||||
if(lastTimeStep == true)
|
||||
{
|
||||
// assume that we want to all the pipelines to execute if it
|
||||
// is the last time step.
|
||||
dataDescription->ForceOutputOn();
|
||||
}
|
||||
if(Processor->RequestDataDescription(dataDescription.GetPointer()) != 0)
|
||||
{
|
||||
vtkNew<vtkUnstructuredGrid> vtkgrid;
|
||||
BuildVTKDataStructures(grid, attributes, vtkgrid.GetPointer());
|
||||
dataDescription->GetInputDescriptionByName("input")->SetGrid(vtkgrid.GetPointer());
|
||||
Processor->CoProcess(dataDescription.GetPointer());
|
||||
}
|
||||
}
|
||||
} // end of Catalyst namespace
|
||||
@ -0,0 +1,20 @@
|
||||
#ifndef FEADAPTOR_HEADER
|
||||
#define FEADAPTOR_HEADER
|
||||
|
||||
class Attributes;
|
||||
class Grid;
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
void Initialize(std::vector<std::string>& scripts);
|
||||
|
||||
void Finalize();
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,154 @@
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <mpi.h>
|
||||
#include <iostream>
|
||||
|
||||
Grid::Grid()
|
||||
{}
|
||||
|
||||
void Grid::Initialize(const unsigned int numPoints[3], const double spacing[3] )
|
||||
{
|
||||
if(numPoints[0] == 0 || numPoints[1] == 0 || numPoints[2] == 0)
|
||||
{
|
||||
std::cerr << "Must have a non-zero amount of points in each direction.\n";
|
||||
}
|
||||
// in parallel, we do a simple partitioning in the x-direction.
|
||||
int mpiSize = 1;
|
||||
int mpiRank = 0;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
|
||||
|
||||
unsigned int startXPoint = mpiRank*numPoints[0]/mpiSize;
|
||||
unsigned int endXPoint = (mpiRank+1)*numPoints[0]/mpiSize;
|
||||
if(mpiSize != mpiRank+1)
|
||||
{
|
||||
endXPoint++;
|
||||
}
|
||||
|
||||
// create the points -- slowest in the x and fastest in the z directions
|
||||
double coord[3] = {0,0,0};
|
||||
for(unsigned int i=startXPoint;i<endXPoint;i++)
|
||||
{
|
||||
coord[0] = i*spacing[0];
|
||||
for(unsigned int j=0;j<numPoints[1];j++)
|
||||
{
|
||||
coord[1] = j*spacing[1];
|
||||
for(unsigned int k=0;k<numPoints[2];k++)
|
||||
{
|
||||
coord[2] = k*spacing[2];
|
||||
// add the coordinate to the end of the vector
|
||||
std::copy(coord, coord+3, std::back_inserter(this->Points));
|
||||
}
|
||||
}
|
||||
}
|
||||
// create the hex cells
|
||||
unsigned int cellPoints[8];
|
||||
unsigned int numXPoints = endXPoint - startXPoint;
|
||||
for(unsigned int i=0;i<numXPoints-1;i++)
|
||||
{
|
||||
for(unsigned int j=0;j<numPoints[1]-1;j++)
|
||||
{
|
||||
for(unsigned int k=0;k<numPoints[2]-1;k++)
|
||||
{
|
||||
cellPoints[0] = i*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k;
|
||||
cellPoints[1] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k;
|
||||
cellPoints[2] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k;
|
||||
cellPoints[3] = i*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k;
|
||||
cellPoints[4] = i*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k+1;
|
||||
cellPoints[5] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k+1;
|
||||
cellPoints[6] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k+1;
|
||||
cellPoints[7] = i*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k+1;
|
||||
std::copy(cellPoints, cellPoints+8, std::back_inserter(this->Cells));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t Grid::GetNumberOfPoints()
|
||||
{
|
||||
return this->Points.size()/3;
|
||||
}
|
||||
|
||||
size_t Grid::GetNumberOfCells()
|
||||
{
|
||||
return this->Cells.size()/8;
|
||||
}
|
||||
|
||||
double* Grid::GetPointsArray()
|
||||
{
|
||||
if(this->Points.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &(this->Points[0]);
|
||||
}
|
||||
|
||||
double* Grid::GetPoint(size_t pointId)
|
||||
{
|
||||
if(pointId >= this->Points.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &(this->Points[pointId*3]);
|
||||
}
|
||||
|
||||
unsigned int* Grid::GetCellPoints(size_t cellId)
|
||||
{
|
||||
if(cellId >= this->Cells.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &(this->Cells[cellId*8]);
|
||||
}
|
||||
|
||||
Attributes::Attributes()
|
||||
{
|
||||
this->GridPtr = NULL;
|
||||
}
|
||||
|
||||
void Attributes::Initialize(Grid* grid)
|
||||
{
|
||||
this->GridPtr = grid;
|
||||
}
|
||||
|
||||
void Attributes::UpdateFields(double time)
|
||||
{
|
||||
size_t numPoints = this->GridPtr->GetNumberOfPoints();
|
||||
this->Velocity.resize(numPoints*3);
|
||||
for(size_t pt=0;pt<numPoints;pt++)
|
||||
{
|
||||
double* coord = this->GridPtr->GetPoint(pt);
|
||||
this->Velocity[pt] = coord[1]*time;
|
||||
//this->Velocity[pt] = time;
|
||||
}
|
||||
std::fill(this->Velocity.begin()+numPoints, this->Velocity.end(), 0.);
|
||||
size_t numCells = this->GridPtr->GetNumberOfCells();
|
||||
this->Pressure.resize(numCells);
|
||||
std::fill(this->Pressure.begin(), this->Pressure.end(), 1.);
|
||||
}
|
||||
|
||||
double* Attributes::GetVelocityArray()
|
||||
{
|
||||
if(this->Velocity.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &this->Velocity[0];
|
||||
}
|
||||
|
||||
float* Attributes::GetPressureArray()
|
||||
{
|
||||
if(this->Pressure.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &this->Pressure[0];
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
#ifndef FEDATASTRUCTURES_HEADER
|
||||
#define FEDATASTRUCTURES_HEADER
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
class Grid
|
||||
{
|
||||
public:
|
||||
Grid();
|
||||
void Initialize(const unsigned int numPoints[3], const double spacing[3]);
|
||||
size_t GetNumberOfPoints();
|
||||
size_t GetNumberOfCells();
|
||||
double* GetPointsArray();
|
||||
double* GetPoint(size_t pointId);
|
||||
unsigned int* GetCellPoints(size_t cellId);
|
||||
private:
|
||||
std::vector<double> Points;
|
||||
std::vector<unsigned int> Cells;
|
||||
};
|
||||
|
||||
class Attributes
|
||||
{
|
||||
// A class for generating and storing point and cell fields.
|
||||
// Velocity is stored at the points and pressure is stored
|
||||
// for the cells. The current velocity profile is for a
|
||||
// shearing flow with U(y,t) = y*t, V = 0 and W = 0.
|
||||
// Pressure is constant through the domain.
|
||||
public:
|
||||
Attributes();
|
||||
void Initialize(Grid* grid);
|
||||
void UpdateFields(double time);
|
||||
double* GetVelocityArray();
|
||||
float* GetPressureArray();
|
||||
|
||||
private:
|
||||
std::vector<double> Velocity;
|
||||
std::vector<float> Pressure;
|
||||
Grid* GridPtr;
|
||||
};
|
||||
#endif
|
||||
@ -0,0 +1,81 @@
|
||||
#include "FEDataStructures.h"
|
||||
#include <mpi.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
#include "FEAdaptor.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <cstring>
|
||||
|
||||
// Example of a C++ adaptor for a simulation code
|
||||
// where the simulation code has a fixed topology
|
||||
// grid. We treat the grid as an unstructured
|
||||
// grid even though in the example provided it
|
||||
// would be best described as a vtkImageData.
|
||||
// Also, the points are stored in an inconsistent
|
||||
// manner with respect to the velocity vector.
|
||||
// This is purposefully done to demonstrate
|
||||
// the different approaches for getting data
|
||||
// into Catalyst. The simulation can be run
|
||||
// from a restarted time step with the
|
||||
// -- restart <time step> command line argument.
|
||||
// All other arguments are considered to be input
|
||||
// script. Note that through configuration
|
||||
// that the driver can be run without linking
|
||||
// to Catalyst.
|
||||
#include <unistd.h>
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
MPI_Init(&argc, &argv);
|
||||
|
||||
Grid grid;
|
||||
unsigned int numPoints[3] = {70, 60, 44};
|
||||
double spacing[3] = {1, 1.1, 1.3};
|
||||
grid.Initialize(numPoints, spacing);
|
||||
Attributes attributes;
|
||||
attributes.Initialize(&grid);
|
||||
|
||||
// we are doing a restarted simulation
|
||||
unsigned int startTimeStep = 0;
|
||||
|
||||
std::vector<std::string> scripts;
|
||||
for(int i=1;i<argc;i++)
|
||||
{
|
||||
if(strcmp(argv[i], "--restart") == 0)
|
||||
{
|
||||
if(i+1 < argc)
|
||||
{
|
||||
startTimeStep = static_cast<unsigned int>(atoi(argv[2]));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scripts.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::Initialize(scripts);
|
||||
#endif
|
||||
unsigned int numberOfTimeSteps = 50;
|
||||
for(unsigned int timeStep=startTimeStep;timeStep<=startTimeStep+numberOfTimeSteps;timeStep++)
|
||||
{
|
||||
// use a time step length of 0.018
|
||||
double time = timeStep * 0.018;
|
||||
attributes.UpdateFields(time);
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::CoProcess(grid, attributes, time, timeStep, timeStep == numberOfTimeSteps+startTimeStep);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
FEAdaptor::Finalize();
|
||||
#endif
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
# CoProcessing test expects the following arguments to be passed to cmake using
|
||||
# -DFoo=BAR arguments.
|
||||
|
||||
# COPROCESSING_TEST_DRIVER -- path to CxxParticlePathExample
|
||||
# COPROCESSING_TEST_DIR -- path to temporary dir
|
||||
# COPROCESSING_SOURCE_DIR -- path to where the source code with the python scripts are
|
||||
# PVBATCH
|
||||
# MPIEXEC
|
||||
# MPIEXEC_NUMPROC_FLAG
|
||||
# MPIEXEC_NUMPROCS
|
||||
# MPIEXEC_PREFLAGS
|
||||
# VTK_MPI_POSTFLAGS
|
||||
|
||||
# remove result files generated by the test
|
||||
file(REMOVE "${COPROCESSING_TEST_DIR}/particles*vtp" )
|
||||
|
||||
if(NOT EXISTS "${COPROCESSING_TEST_DRIVER}")
|
||||
message(FATAL_ERROR "'${COPROCESSING_TEST_DRIVER}' does not exist")
|
||||
endif()
|
||||
|
||||
message("Executing :
|
||||
${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_NUMPROCS} ${MPIEXEC_PREFLAGS}
|
||||
\"${COPROCESSING_TEST_DRIVER}\"
|
||||
\"${COPROCESSING_SOURCE_DIR}/SampleScripts/particlepath.py\"")
|
||||
execute_process(COMMAND
|
||||
${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_NUMPROCS} ${MPIEXEC_PREFLAGS}
|
||||
"${COPROCESSING_TEST_DRIVER}"
|
||||
"${COPROCESSING_SOURCE_DIR}/SampleScripts/particlepath.py"
|
||||
WORKING_DIRECTORY ${COPROCESSING_TEST_DIR}
|
||||
RESULT_VARIABLE rv)
|
||||
|
||||
if(NOT rv EQUAL 0)
|
||||
message(FATAL_ERROR "Test executable return value was ${rv}")
|
||||
endif()
|
||||
|
||||
# below is the restarted "simulation"
|
||||
message("Executing (restart):
|
||||
${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_NUMPROCS} ${MPIEXEC_PREFLAGS}
|
||||
\"${COPROCESSING_TEST_DRIVER}\" --restart 50
|
||||
\"${COPROCESSING_SOURCE_DIR}/SampleScripts/particlepath.py\"")
|
||||
execute_process(COMMAND
|
||||
${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_NUMPROCS} ${MPIEXEC_PREFLAGS}
|
||||
"${COPROCESSING_TEST_DRIVER}" --restart 50
|
||||
"${COPROCESSING_SOURCE_DIR}/SampleScripts/particlepath.py"
|
||||
WORKING_DIRECTORY ${COPROCESSING_TEST_DIR}
|
||||
RESULT_VARIABLE rv)
|
||||
|
||||
if(NOT rv EQUAL 0)
|
||||
message(FATAL_ERROR "Test executable (restart) return value was ${rv}")
|
||||
endif()
|
||||
|
||||
message("Executing :
|
||||
${PVBATCH} ${COPROCESSING_SOURCE_DIR}/TestScripts/verifyparticlepath.py ${COPROCESSING_TEST_DIR}")
|
||||
|
||||
execute_process(COMMAND "${PVBATCH}" "${COPROCESSING_SOURCE_DIR}/TestScripts/verifyparticlepath.py" "${COPROCESSING_TEST_DIR}"
|
||||
RESULT_VARIABLE rv
|
||||
WORKING_DIRECTORY ${COPROCESSING_TEST_DIR})
|
||||
|
||||
if(NOT rv EQUAL 0)
|
||||
message(FATAL_ERROR "verifyparticlepath.py failed.")
|
||||
endif()
|
||||
@ -0,0 +1,131 @@
|
||||
from paraview.simple import *
|
||||
from paraview import coprocessing
|
||||
|
||||
outputfrequency = 1
|
||||
reinjectionfrequency = 70
|
||||
|
||||
# ----------------------- CoProcessor definition -----------------------
|
||||
|
||||
def CreateCoProcessor():
|
||||
def _CreatePipeline(coprocessor, datadescription):
|
||||
class Pipeline:
|
||||
# state file generated using paraview version 4.4.0-117-ge0a3d77
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# setup the data processing pipelines
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
#### disable automatic camera reset on 'Show'
|
||||
paraview.simple._DisableFirstRenderCameraReset()
|
||||
|
||||
# create a new 'Line' for seed sources
|
||||
line1 = Line()
|
||||
line1.Point1 = [1., 1., 30.]
|
||||
line1.Point2 = [1., 64., 30.]
|
||||
|
||||
# create a producer from a simulation input
|
||||
fullgrid_99pvtu = coprocessor.CreateProducer(datadescription, 'input')
|
||||
|
||||
# create a new 'ParticlePath'
|
||||
# disable resetting the cache so that the particle path filter works in situ
|
||||
# and only updates from previously computed information.
|
||||
particlePath1 = InSituParticlePath(Input=fullgrid_99pvtu, SeedSource=line1, DisableResetCache=1)
|
||||
particlePath1.SelectInputVectors = ['POINTS', 'velocity']
|
||||
# don't save particle locations from previous time steps. they can take
|
||||
# up a surprising amount of memory for long running simulations.
|
||||
particlePath1.ClearCache = 1
|
||||
|
||||
# if we're starting from a restarted simulation, the following are
|
||||
# used to specify the time step for the restarted simulation and
|
||||
# the input for the previously advected particles to continue
|
||||
# advecting them
|
||||
if datadescription.GetTimeStep() != 0:
|
||||
restartparticles = XMLPartitionedPolydataReader(FileName='particles_50.pvtp')
|
||||
particlePath1.RestartSource = restartparticles
|
||||
particlePath1.FirstTimeStep = datadescription.GetTimeStep()
|
||||
particlePath1.RestartedSimulation = 1
|
||||
|
||||
# create a new 'Parallel PolyData Writer'
|
||||
parallelPolyDataWriter1 = servermanager.writers.XMLPPolyDataWriter(Input=particlePath1)
|
||||
|
||||
# register the writer with coprocessor
|
||||
# and provide it with information such as the filename to use,
|
||||
# how frequently to write the data, etc.
|
||||
coprocessor.RegisterWriter(parallelPolyDataWriter1, filename='particles_%t.pvtp', freq=outputfrequency)
|
||||
|
||||
return Pipeline()
|
||||
|
||||
class CoProcessor(coprocessing.CoProcessor):
|
||||
def CreatePipeline(self, datadescription):
|
||||
self.Pipeline = _CreatePipeline(self, datadescription)
|
||||
|
||||
coprocessor = CoProcessor()
|
||||
# these are the frequencies at which the coprocessor updates. for
|
||||
# particle paths this is done every time step
|
||||
freqs = {'input': [1]}
|
||||
coprocessor.SetUpdateFrequencies(freqs)
|
||||
return coprocessor
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Global variables that will hold the pipeline for each timestep
|
||||
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
|
||||
# It will be automatically setup when coprocessor.UpdateProducers() is called the
|
||||
# first time.
|
||||
coprocessor = CreateCoProcessor()
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Enable Live-Visualizaton with ParaView
|
||||
coprocessor.EnableLiveVisualization(False, 1)
|
||||
|
||||
# ---------------------- Data Selection method ----------------------
|
||||
|
||||
def RequestDataDescription(datadescription):
|
||||
"Callback to populate the request for current timestep"
|
||||
global coprocessor
|
||||
if datadescription.GetForceOutput() == True:
|
||||
# We are just going to request all fields and meshes from the simulation
|
||||
# code/adaptor.
|
||||
for i in range(datadescription.GetNumberOfInputDescriptions()):
|
||||
datadescription.GetInputDescription(i).AllFieldsOn()
|
||||
datadescription.GetInputDescription(i).GenerateMeshOn()
|
||||
return
|
||||
|
||||
# setup requests for all inputs based on the requirements of the
|
||||
# pipeline.
|
||||
coprocessor.LoadRequestedData(datadescription)
|
||||
|
||||
# ------------------------ Processing method ------------------------
|
||||
|
||||
def DoCoProcessing(datadescription):
|
||||
"Callback to do co-processing for current timestep"
|
||||
global coprocessor
|
||||
|
||||
# Update the coprocessor by providing it the newly generated simulation data.
|
||||
# If the pipeline hasn't been setup yet, this will setup the pipeline.
|
||||
#if not coprocessor.__PipelineCreated:
|
||||
coprocessor.UpdateProducers(datadescription)
|
||||
|
||||
# tell the particle path filter how far to integrate in time (i.e. our current time)
|
||||
coprocessor.Pipeline.particlePath1.TerminationTime = datadescription.GetTime()
|
||||
|
||||
# specify reinjection frequency manually so that reinjection
|
||||
# occurs based on the simulation time step to avoid restart issues since
|
||||
# the particle path filter only knows how many time steps
|
||||
# it has been updated. this is the same when the simulation has not been
|
||||
# restarted.
|
||||
timestep = datadescription.GetTimeStep()
|
||||
if timestep % reinjectionfrequency == 0:
|
||||
coprocessor.Pipeline.particlePath1.ForceReinjectionEveryNSteps = 1
|
||||
else:
|
||||
coprocessor.Pipeline.particlePath1.ForceReinjectionEveryNSteps = timestep+1
|
||||
|
||||
coprocessor.Pipeline.particlePath1.UpdatePipeline()
|
||||
|
||||
# Write output data, if appropriate.
|
||||
coprocessor.WriteData(datadescription);
|
||||
|
||||
# Write image capture (Last arg: rescale lookup table), if appropriate.
|
||||
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
|
||||
|
||||
# Live Visualization, if enabled.
|
||||
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)
|
||||
@ -0,0 +1,91 @@
|
||||
import sys
|
||||
|
||||
print 'running the test script with args', sys.argv
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print 'need to pass in the test directory location'
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# the velocity is [y*t, 0, 0] and the time step length is 0.018
|
||||
# the beginning x-location for the seeds is 1
|
||||
# the y location for the seeds are [1, 11.5, 22, 32.5, 43, 53.5, 64]
|
||||
# the z location for the seeds is 30
|
||||
# the analytical locations of the initially injected seeds are 1+y*time*time/2
|
||||
# the seeds are reinjected at time step 70 (time 1.26) and their
|
||||
# analytical locations are 1+y*(time*time-1.26*1.26)/2
|
||||
|
||||
# in parallel when seeds are migrated to different processes there
|
||||
# is a slight loss of accuracy due to using a first order time
|
||||
# integration method instead of vtkRungeKutta4.cxx.
|
||||
|
||||
from paraview.simple import *
|
||||
r = XMLPartitionedPolydataReader(FileName=sys.argv[1]+'/particles_40.pvtp')
|
||||
r.UpdatePipeline()
|
||||
bounds = r.GetDataInformation().DataInformation.GetBounds()
|
||||
if bounds[0] < 1.25 or bounds[0] > 1.27 or \
|
||||
bounds[1] < 17.5 or bounds[1] > 17.7 or \
|
||||
bounds[2] < .9 or bounds[2] > 1.1 or \
|
||||
bounds[3] < 63.9 or bounds[3] > 64.1 or \
|
||||
bounds[4] < 29.9 or bounds[4] > 30.1 or \
|
||||
bounds[5] < 29.9 or bounds[5] > 30.1:
|
||||
print 'Time step 40: wrong particle bounds', bounds
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
g = Glyph()
|
||||
g.GlyphMode = 'All Points'
|
||||
g.GlyphType = '2D Glyph'
|
||||
g.GlyphType.GlyphType = 'Vertex'
|
||||
|
||||
t = Threshold()
|
||||
t.Scalars = ['POINTS', 'ParticleAge']
|
||||
t.ThresholdRange = [0.71, 0.73]
|
||||
t.UpdatePipeline()
|
||||
|
||||
grid = servermanager.Fetch(t)
|
||||
if grid.GetNumberOfPoints() != 7:
|
||||
print 'Time step 40: wrong number of points', grid.GetNumberOfPoints()
|
||||
sys.exit(1)
|
||||
|
||||
r.FileName = sys.argv[1]+'/particles_80.pvtp'
|
||||
|
||||
# threshold to get the seeds that were originally injected only
|
||||
t.ThresholdRange = [1.43, 1.45]
|
||||
t.UpdatePipeline()
|
||||
bounds = t.GetDataInformation().DataInformation.GetBounds()
|
||||
if bounds[0] < 2. or bounds[0] > 2.1 or \
|
||||
bounds[1] < 67.3 or bounds[1] > 67.4 or \
|
||||
bounds[2] < .9 or bounds[2] > 1.1 or \
|
||||
bounds[3] < 63.9 or bounds[3] > 64.1 or \
|
||||
bounds[4] < 29.9 or bounds[4] > 30.1 or \
|
||||
bounds[5] < 29.9 or bounds[5] > 30.1:
|
||||
print 'Time step 80: wrong particle bounds for initial injected particles', bounds
|
||||
sys.exit(1)
|
||||
|
||||
grid = servermanager.Fetch(t)
|
||||
if grid.GetNumberOfPoints() != 7:
|
||||
print 'Time step 80: wrong number of points for initial injected particles', grid.GetNumberOfPoints()
|
||||
sys.exit(1)
|
||||
|
||||
# threshold to get the seeds that were injected at time step 70
|
||||
t.Scalars = ['POINTS', 'InjectionStepId']
|
||||
t.ThresholdRange = [69, 71]
|
||||
t.UpdatePipeline()
|
||||
|
||||
bounds = t.GetDataInformation().DataInformation.GetBounds()
|
||||
if bounds[0] < 1.23 or bounds[0] > 1.25 or \
|
||||
bounds[1] < 16.5 or bounds[1] > 16.7 or \
|
||||
bounds[2] < .9 or bounds[2] > 1.1 or \
|
||||
bounds[3] < 63.9 or bounds[3] > 64.1 or \
|
||||
bounds[4] < 29.9 or bounds[4] > 30.1 or \
|
||||
bounds[5] < 29.9 or bounds[5] > 30.1:
|
||||
print 'Time step 80: wrong particle bounds for reinjected particles', bounds
|
||||
sys.exit(1)
|
||||
|
||||
grid = servermanager.Fetch(t)
|
||||
if grid.GetNumberOfPoints() != 7:
|
||||
print 'Time step 80: wrong number of points for reinjected particles', grid.GetNumberOfPoints()
|
||||
sys.exit(1)
|
||||
|
||||
print 'test passed'
|
||||
@ -0,0 +1,42 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(CatalystCxxVTKPipelineExample)
|
||||
|
||||
set(USE_CATALYST ON CACHE BOOL "Link the simulator with Catalyst")
|
||||
if(USE_CATALYST)
|
||||
# We have a C++ pipeline so we don't need to link with Python
|
||||
# or vtkPVPythonCatalyst since vtkPVCatalyst is sufficient.
|
||||
find_package(ParaView 4.1 REQUIRED COMPONENTS vtkPVCatalyst vtkPVVTKExtensionsDefault vtkPVClientServerCoreCore)
|
||||
include("${PARAVIEW_USE_FILE}")
|
||||
set(Adaptor_SRCS
|
||||
FEAdaptor.cxx
|
||||
vtkCPVTKPipeline.cxx
|
||||
)
|
||||
add_library(CxxVTKPipelineExampleAdaptor ${Adaptor_SRCS})
|
||||
target_link_libraries(CxxVTKPipelineExampleAdaptor vtkPVCatalyst vtkPVVTKExtensionsDefault vtkPVClientServerCoreCore)
|
||||
add_definitions("-DUSE_CATALYST")
|
||||
if(NOT PARAVIEW_USE_MPI)
|
||||
message(SEND_ERROR "ParaView must be built with MPI enabled")
|
||||
endif()
|
||||
else()
|
||||
find_package(MPI REQUIRED)
|
||||
include_directories(${MPI_CXX_INCLUDE_PATH})
|
||||
endif()
|
||||
|
||||
|
||||
add_executable(CxxVTKPipelineExample FEDriver.cxx FEDataStructures.cxx)
|
||||
if(USE_CATALYST)
|
||||
target_link_libraries(CxxVTKPipelineExample LINK_PRIVATE CxxVTKPipelineExampleAdaptor)
|
||||
include(vtkModuleMacros)
|
||||
include(vtkMPI)
|
||||
vtk_mpi_link(CxxVTKPipelineExample)
|
||||
else()
|
||||
target_link_libraries(CxxVTKPipelineExample LINK_PRIVATE ${MPI_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_test(NAME CxxVTKPipelineExampleTest COMMAND CxxVTKPipelineExample 10 output)
|
||||
set_tests_properties(CxxVTKPipelineExampleTest PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
endif()
|
||||
@ -0,0 +1,147 @@
|
||||
#include <iostream>
|
||||
#include "FEAdaptor.h"
|
||||
#include "FEDataStructures.h"
|
||||
#include "vtkCPVTKPipeline.h"
|
||||
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkCellType.h>
|
||||
#include <vtkCPDataDescription.h>
|
||||
#include <vtkCPInputDataDescription.h>
|
||||
#include <vtkCPProcessor.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkFloatArray.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkPoints.h>
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
vtkCPProcessor* Processor = NULL;
|
||||
vtkUnstructuredGrid* VTKGrid;
|
||||
|
||||
void BuildVTKGrid(Grid& grid)
|
||||
{
|
||||
// create the points information
|
||||
vtkNew<vtkDoubleArray> pointArray;
|
||||
pointArray->SetNumberOfComponents(3);
|
||||
pointArray->SetArray(grid.GetPointsArray(), static_cast<vtkIdType>(grid.GetNumberOfPoints()*3), 1);
|
||||
vtkNew<vtkPoints> points;
|
||||
points->SetData(pointArray.GetPointer());
|
||||
VTKGrid->SetPoints(points.GetPointer());
|
||||
|
||||
// create the cells
|
||||
size_t numCells = grid.GetNumberOfCells();
|
||||
VTKGrid->Allocate(static_cast<vtkIdType>(numCells*9));
|
||||
for(size_t cell=0;cell<numCells;cell++)
|
||||
{
|
||||
unsigned int* cellPoints = grid.GetCellPoints(cell);
|
||||
vtkIdType tmp[8] = {cellPoints[0], cellPoints[1], cellPoints[2], cellPoints[3],
|
||||
cellPoints[4], cellPoints[5], cellPoints[6], cellPoints[7]};
|
||||
VTKGrid->InsertNextCell(VTK_HEXAHEDRON, 8, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateVTKAttributes(Grid& grid, Attributes& attributes)
|
||||
{
|
||||
if(VTKGrid->GetPointData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// velocity array
|
||||
vtkNew<vtkDoubleArray> velocity;
|
||||
velocity->SetName("velocity");
|
||||
velocity->SetNumberOfComponents(3);
|
||||
velocity->SetNumberOfTuples(static_cast<vtkIdType>(grid.GetNumberOfPoints()));
|
||||
VTKGrid->GetPointData()->AddArray(velocity.GetPointer());
|
||||
}
|
||||
if(VTKGrid->GetCellData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// pressure array
|
||||
vtkNew<vtkFloatArray> pressure;
|
||||
pressure->SetName("pressure");
|
||||
pressure->SetNumberOfComponents(1);
|
||||
VTKGrid->GetCellData()->AddArray(pressure.GetPointer());
|
||||
}
|
||||
vtkDoubleArray* velocity = vtkDoubleArray::SafeDownCast(
|
||||
VTKGrid->GetPointData()->GetArray("velocity"));
|
||||
// The velocity array is ordered as vx0,vx1,vx2,..,vy0,vy1,vy2,..,vz0,vz1,vz2,..
|
||||
// so we need to create a full copy of it with VTK's ordering of
|
||||
// vx0,vy0,vz0,vx1,vy1,vz1,..
|
||||
double* velocityData = attributes.GetVelocityArray();
|
||||
vtkIdType numTuples = velocity->GetNumberOfTuples();
|
||||
for(vtkIdType i=0;i<numTuples;i++)
|
||||
{
|
||||
double values[3] = {velocityData[i], velocityData[i+numTuples],
|
||||
velocityData[i+2*numTuples]};
|
||||
velocity->SetTupleValue(i, values);
|
||||
}
|
||||
|
||||
vtkFloatArray* pressure = vtkFloatArray::SafeDownCast(
|
||||
VTKGrid->GetCellData()->GetArray("pressure"));
|
||||
// The pressure array is a scalar array so we can reuse
|
||||
// memory as long as we ordered the points properly.
|
||||
float* pressureData = attributes.GetPressureArray();
|
||||
pressure->SetArray(pressureData, static_cast<vtkIdType>(grid.GetNumberOfCells()), 1);
|
||||
}
|
||||
|
||||
void BuildVTKDataStructures(Grid& grid, Attributes& attributes)
|
||||
{
|
||||
if(VTKGrid == NULL)
|
||||
{
|
||||
// The grid structure isn't changing so we only build it
|
||||
// the first time it's needed. If we needed the memory
|
||||
// we could delete it and rebuild as necessary.
|
||||
VTKGrid = vtkUnstructuredGrid::New();
|
||||
BuildVTKGrid(grid);
|
||||
}
|
||||
UpdateVTKAttributes(grid, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
void Initialize(int outputFrequency, std::string fileName)
|
||||
{
|
||||
if(Processor == NULL)
|
||||
{
|
||||
Processor = vtkCPProcessor::New();
|
||||
Processor->Initialize();
|
||||
}
|
||||
vtkNew<vtkCPVTKPipeline> pipeline;
|
||||
pipeline->Initialize(outputFrequency, fileName);
|
||||
Processor->AddPipeline(pipeline.GetPointer());
|
||||
}
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
if(Processor)
|
||||
{
|
||||
Processor->Delete();
|
||||
Processor = NULL;
|
||||
}
|
||||
if(VTKGrid)
|
||||
{
|
||||
VTKGrid->Delete();
|
||||
VTKGrid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep)
|
||||
{
|
||||
vtkNew<vtkCPDataDescription> dataDescription;
|
||||
dataDescription->AddInput("input");
|
||||
dataDescription->SetTimeData(time, timeStep);
|
||||
if(lastTimeStep == true)
|
||||
{
|
||||
// assume that we want to all the pipelines to execute if it
|
||||
// is the last time step.
|
||||
dataDescription->ForceOutputOn();
|
||||
}
|
||||
if(Processor->RequestDataDescription(dataDescription.GetPointer()) != 0)
|
||||
{
|
||||
BuildVTKDataStructures(grid, attributes);
|
||||
dataDescription->GetInputDescriptionByName("input")->SetGrid(VTKGrid);
|
||||
Processor->CoProcess(dataDescription.GetPointer());
|
||||
}
|
||||
}
|
||||
} // end of Catalyst namespace
|
||||
@ -0,0 +1,19 @@
|
||||
#ifndef FEADAPTOR_HEADER
|
||||
#define FEADAPTOR_HEADER
|
||||
|
||||
#include <string>
|
||||
|
||||
class Attributes;
|
||||
class Grid;
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
void Initialize(int outputFrequency, std::string fileName);
|
||||
|
||||
void Finalize();
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,153 @@
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <mpi.h>
|
||||
#include <iostream>
|
||||
|
||||
Grid::Grid()
|
||||
{}
|
||||
|
||||
void Grid::Initialize(const unsigned int numPoints[3], const double spacing[3] )
|
||||
{
|
||||
if(numPoints[0] == 0 || numPoints[1] == 0 || numPoints[2] == 0)
|
||||
{
|
||||
std::cerr << "Must have a non-zero amount of points in each direction.\n";
|
||||
}
|
||||
// in parallel, we do a simple partitioning in the x-direction.
|
||||
int mpiSize = 1;
|
||||
int mpiRank = 0;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
|
||||
|
||||
unsigned int startXPoint = mpiRank*numPoints[0]/mpiSize;
|
||||
unsigned int endXPoint = (mpiRank+1)*numPoints[0]/mpiSize;
|
||||
if(mpiSize != mpiRank+1)
|
||||
{
|
||||
endXPoint++;
|
||||
}
|
||||
|
||||
// create the points -- slowest in the x and fastest in the z directions
|
||||
double coord[3] = {0,0,0};
|
||||
for(unsigned int i=startXPoint;i<endXPoint;i++)
|
||||
{
|
||||
coord[0] = i*spacing[0];
|
||||
for(unsigned int j=0;j<numPoints[1];j++)
|
||||
{
|
||||
coord[1] = j*spacing[1];
|
||||
for(unsigned int k=0;k<numPoints[2];k++)
|
||||
{
|
||||
coord[2] = k*spacing[2];
|
||||
// add the coordinate to the end of the vector
|
||||
std::copy(coord, coord+3, std::back_inserter(this->Points));
|
||||
}
|
||||
}
|
||||
}
|
||||
// create the hex cells
|
||||
unsigned int cellPoints[8];
|
||||
unsigned int numXPoints = endXPoint - startXPoint;
|
||||
for(unsigned int i=0;i<numXPoints-1;i++)
|
||||
{
|
||||
for(unsigned int j=0;j<numPoints[1]-1;j++)
|
||||
{
|
||||
for(unsigned int k=0;k<numPoints[2]-1;k++)
|
||||
{
|
||||
cellPoints[0] = i*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k;
|
||||
cellPoints[1] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k;
|
||||
cellPoints[2] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k;
|
||||
cellPoints[3] = i*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k;
|
||||
cellPoints[4] = i*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k+1;
|
||||
cellPoints[5] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
j*numPoints[2] + k+1;
|
||||
cellPoints[6] = (i+1)*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k+1;
|
||||
cellPoints[7] = i*numPoints[1]*numPoints[2] +
|
||||
(j+1)*numPoints[2] + k+1;
|
||||
std::copy(cellPoints, cellPoints+8, std::back_inserter(this->Cells));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t Grid::GetNumberOfPoints()
|
||||
{
|
||||
return this->Points.size()/3;
|
||||
}
|
||||
|
||||
size_t Grid::GetNumberOfCells()
|
||||
{
|
||||
return this->Cells.size()/8;
|
||||
}
|
||||
|
||||
double* Grid::GetPointsArray()
|
||||
{
|
||||
if(this->Points.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &(this->Points[0]);
|
||||
}
|
||||
|
||||
double* Grid::GetPoint(size_t pointId)
|
||||
{
|
||||
if(pointId >= this->Points.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &(this->Points[pointId*3]);
|
||||
}
|
||||
|
||||
unsigned int* Grid::GetCellPoints(size_t cellId)
|
||||
{
|
||||
if(cellId >= this->Cells.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &(this->Cells[cellId*8]);
|
||||
}
|
||||
|
||||
Attributes::Attributes()
|
||||
{
|
||||
this->GridPtr = NULL;
|
||||
}
|
||||
|
||||
void Attributes::Initialize(Grid* grid)
|
||||
{
|
||||
this->GridPtr = grid;
|
||||
}
|
||||
|
||||
void Attributes::UpdateFields(double time)
|
||||
{
|
||||
size_t numPoints = this->GridPtr->GetNumberOfPoints();
|
||||
this->Velocity.resize(numPoints*3);
|
||||
for(size_t pt=0;pt<numPoints;pt++)
|
||||
{
|
||||
double* coord = this->GridPtr->GetPoint(pt);
|
||||
this->Velocity[pt] = coord[1]*time;
|
||||
}
|
||||
std::fill(this->Velocity.begin()+numPoints, this->Velocity.end(), 0.);
|
||||
size_t numCells = this->GridPtr->GetNumberOfCells();
|
||||
this->Pressure.resize(numCells);
|
||||
std::fill(this->Pressure.begin(), this->Pressure.end(), 1.);
|
||||
}
|
||||
|
||||
double* Attributes::GetVelocityArray()
|
||||
{
|
||||
if(this->Velocity.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &this->Velocity[0];
|
||||
}
|
||||
|
||||
float* Attributes::GetPressureArray()
|
||||
{
|
||||
if(this->Pressure.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &this->Pressure[0];
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
#ifndef FEDATASTRUCTURES_HEADER
|
||||
#define FEDATASTRUCTURES_HEADER
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
class Grid
|
||||
{
|
||||
public:
|
||||
Grid();
|
||||
void Initialize(const unsigned int numPoints[3], const double spacing[3]);
|
||||
size_t GetNumberOfPoints();
|
||||
size_t GetNumberOfCells();
|
||||
double* GetPointsArray();
|
||||
double* GetPoint(size_t pointId);
|
||||
unsigned int* GetCellPoints(size_t cellId);
|
||||
private:
|
||||
std::vector<double> Points;
|
||||
std::vector<unsigned int> Cells;
|
||||
};
|
||||
|
||||
class Attributes
|
||||
{
|
||||
// A class for generating and storing point and cell fields.
|
||||
// Velocity is stored at the points and pressure is stored
|
||||
// for the cells. The current velocity profile is for a
|
||||
// shearing flow with U(y,t) = y*t, V = 0 and W = 0.
|
||||
// Pressure is constant through the domain.
|
||||
public:
|
||||
Attributes();
|
||||
void Initialize(Grid* grid);
|
||||
void UpdateFields(double time);
|
||||
double* GetVelocityArray();
|
||||
float* GetPressureArray();
|
||||
|
||||
private:
|
||||
std::vector<double> Velocity;
|
||||
std::vector<float> Pressure;
|
||||
Grid* GridPtr;
|
||||
};
|
||||
#endif
|
||||
@ -0,0 +1,76 @@
|
||||
#include "FEDataStructures.h"
|
||||
#include <mpi.h>
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
#include <cstdlib>
|
||||
#include "FEAdaptor.h"
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
// Example of a C++ adaptor for a simulation code
|
||||
// where we use a hard-coded VTK C++ pipeline.
|
||||
// The simulation code has a fixed topology
|
||||
// grid. We treat the grid as an unstructured
|
||||
// grid even though in the example provided it
|
||||
// would be best described as a vtkImageData.
|
||||
// Also, the points are stored in an inconsistent
|
||||
// manner with respect to the velocity vector.
|
||||
// This is purposefully done to demonstrate
|
||||
// the different approaches for getting data
|
||||
// into Catalyst. The hard-coded C++ pipeline
|
||||
// computes the velocity magnitude from a velocity
|
||||
// vector and then uses a threshold filter to keep the
|
||||
// portion of the domain where velocity magnitude
|
||||
// is within the 10% of the maximum velocity.
|
||||
// Note that through configuration
|
||||
// that the driver can be run without linking
|
||||
// to Catalyst.
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
MPI_Init(&argc, &argv);
|
||||
Grid grid;
|
||||
unsigned int numPoints[3] = {70, 60, 44};
|
||||
double spacing[3] = {1, 1.1, 1.3};
|
||||
grid.Initialize(numPoints, spacing);
|
||||
Attributes attributes;
|
||||
attributes.Initialize(&grid);
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
bool doCoProcessing = false;
|
||||
if(argc == 3)
|
||||
{
|
||||
doCoProcessing = true;
|
||||
// pass in the number of time steps and base file name.
|
||||
FEAdaptor::Initialize(atoi(argv[1]), argv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "To run with Catalyst you must pass in the output frequency and the base file name.\n";
|
||||
}
|
||||
#endif
|
||||
unsigned int numberOfTimeSteps = 100;
|
||||
for(unsigned int timeStep=0;timeStep<numberOfTimeSteps;timeStep++)
|
||||
{
|
||||
// use a time step length of 0.1
|
||||
double time = timeStep * 0.1;
|
||||
attributes.UpdateFields(time);
|
||||
#ifdef USE_CATALYST
|
||||
if(doCoProcessing)
|
||||
{
|
||||
FEAdaptor::CoProcess(grid, attributes, time, timeStep,
|
||||
timeStep == numberOfTimeSteps-1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
if(doCoProcessing)
|
||||
{
|
||||
FEAdaptor::Finalize();
|
||||
}
|
||||
#endif
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,137 @@
|
||||
#include "vtkCPVTKPipeline.h"
|
||||
|
||||
#include <vtkCommunicator.h>
|
||||
#include <vtkCompleteArrays.h>
|
||||
#include <vtkCPDataDescription.h>
|
||||
#include <vtkDataArray.h>
|
||||
#include <vtkCPInputDataDescription.h>
|
||||
#include <vtkMultiProcessController.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkObjectFactory.h>
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkPVArrayCalculator.h>
|
||||
#include <vtkPVTrivialProducer.h>
|
||||
#include <vtkSMProxyManager.h>
|
||||
#include <vtkThreshold.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
#include <vtkXMLPUnstructuredGridWriter.h>
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
vtkStandardNewMacro(vtkCPVTKPipeline);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
vtkCPVTKPipeline::vtkCPVTKPipeline()
|
||||
{
|
||||
this->OutputFrequency = 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
vtkCPVTKPipeline::~vtkCPVTKPipeline()
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void vtkCPVTKPipeline::Initialize(int outputFrequency, std::string& fileName)
|
||||
{
|
||||
this->OutputFrequency = outputFrequency;
|
||||
this->FileName = fileName;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int vtkCPVTKPipeline::RequestDataDescription(
|
||||
vtkCPDataDescription* dataDescription)
|
||||
{
|
||||
if(!dataDescription)
|
||||
{
|
||||
vtkWarningMacro("dataDescription is NULL.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(this->FileName.empty())
|
||||
{
|
||||
vtkWarningMacro("No output file name given to output results to.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(dataDescription->GetForceOutput() == true ||
|
||||
(this->OutputFrequency != 0 && dataDescription->GetTimeStep() % this->OutputFrequency == 0) )
|
||||
{
|
||||
dataDescription->GetInputDescriptionByName("input")->AllFieldsOn();
|
||||
dataDescription->GetInputDescriptionByName("input")->GenerateMeshOn();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int vtkCPVTKPipeline::CoProcess(
|
||||
vtkCPDataDescription* dataDescription)
|
||||
{
|
||||
if(!dataDescription)
|
||||
{
|
||||
vtkWarningMacro("DataDescription is NULL");
|
||||
return 0;
|
||||
}
|
||||
vtkUnstructuredGrid* grid = vtkUnstructuredGrid::SafeDownCast(
|
||||
dataDescription->GetInputDescriptionByName("input")->GetGrid());
|
||||
if(grid == NULL)
|
||||
{
|
||||
vtkWarningMacro("DataDescription is missing input unstructured grid.");
|
||||
return 0;
|
||||
}
|
||||
if(this->RequestDataDescription(dataDescription) == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
vtkNew<vtkPVTrivialProducer> producer;
|
||||
producer->SetOutput(grid);
|
||||
|
||||
vtkNew<vtkPVArrayCalculator> calculator;
|
||||
calculator->SetInputConnection(producer->GetOutputPort());
|
||||
calculator->SetAttributeMode(1);
|
||||
calculator->SetResultArrayName("velocity magnitude");
|
||||
calculator->SetFunction("mag(velocity)");
|
||||
|
||||
// update now so that we can get the global data bounds of
|
||||
// the velocity magnitude for thresholding
|
||||
calculator->Update();
|
||||
double range[2];
|
||||
vtkUnstructuredGrid::SafeDownCast(calculator->GetOutput())->GetPointData()
|
||||
->GetArray("velocity magnitude")->GetRange(range, 0);
|
||||
double globalRange[2];
|
||||
vtkMultiProcessController::GetGlobalController()->AllReduce(
|
||||
range+1, globalRange+1, 1, vtkCommunicator::MAX_OP);
|
||||
|
||||
vtkNew<vtkThreshold> threshold;
|
||||
threshold->SetInputConnection(calculator->GetOutputPort());
|
||||
threshold->SetInputArrayToProcess(
|
||||
0, 0, 0, "vtkDataObject::FIELD_ASSOCIATION_POINTS", "velocity magnitude");
|
||||
threshold->ThresholdBetween(0.9*globalRange[1], globalRange[1]);
|
||||
|
||||
// If process 0 doesn't have any points or cells, the writer may
|
||||
// have problems in parallel so we use completeArrays to fill in
|
||||
// the missing information.
|
||||
vtkNew<vtkCompleteArrays> completeArrays;
|
||||
completeArrays->SetInputConnection(threshold->GetOutputPort());
|
||||
|
||||
vtkNew<vtkXMLPUnstructuredGridWriter> writer;
|
||||
writer->SetInputConnection(completeArrays->GetOutputPort());
|
||||
std::ostringstream o;
|
||||
o << dataDescription->GetTimeStep();
|
||||
std::string name = this->FileName + o.str() + ".pvtu";
|
||||
writer->SetFileName(name.c_str());
|
||||
writer->Update();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void vtkCPVTKPipeline::PrintSelf(ostream& os, vtkIndent indent)
|
||||
{
|
||||
this->Superclass::PrintSelf(os, indent);
|
||||
os << indent << "OutputFrequency: " << this->OutputFrequency << "\n";
|
||||
os << indent << "FileName: " << this->FileName << "\n";
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
#ifndef VTKCPVTKPIPELINE_H
|
||||
#define VTKCPVTKPIPELINE_H
|
||||
|
||||
#include <vtkCPPipeline.h>
|
||||
#include <string>
|
||||
|
||||
class vtkCPDataDescription;
|
||||
class vtkCPPythonHelper;
|
||||
|
||||
class vtkCPVTKPipeline : public vtkCPPipeline
|
||||
{
|
||||
public:
|
||||
static vtkCPVTKPipeline* New();
|
||||
vtkTypeMacro(vtkCPVTKPipeline,vtkCPPipeline);
|
||||
virtual void PrintSelf(ostream& os, vtkIndent indent);
|
||||
|
||||
virtual void Initialize(int outputFrequency, std::string& fileName);
|
||||
|
||||
virtual int RequestDataDescription(vtkCPDataDescription* dataDescription);
|
||||
|
||||
virtual int CoProcess(vtkCPDataDescription* dataDescription);
|
||||
|
||||
protected:
|
||||
vtkCPVTKPipeline();
|
||||
virtual ~vtkCPVTKPipeline();
|
||||
|
||||
private:
|
||||
vtkCPVTKPipeline(const vtkCPVTKPipeline&); // Not implemented
|
||||
void operator=(const vtkCPVTKPipeline&); // Not implemented
|
||||
|
||||
int OutputFrequency;
|
||||
std::string FileName;
|
||||
};
|
||||
#endif
|
||||
@ -0,0 +1,26 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
project(CatalystFortran90FullExample CXX Fortran)
|
||||
|
||||
find_package(ParaView 4.1 REQUIRED COMPONENTS vtkPVPythonCatalyst)
|
||||
|
||||
include(${PARAVIEW_USE_FILE})
|
||||
if(NOT PARAVIEW_USE_MPI)
|
||||
message(SEND_ERROR "ParaView must be built with MPI enabled")
|
||||
endif()
|
||||
if(NOT MPI_Fortran_LIBRARIES)
|
||||
find_package(MPI)
|
||||
endif()
|
||||
|
||||
add_executable(Fortran90FullExample FEDriver.f90 FEFortranAdaptor.f90 FECxxAdaptor.cxx)
|
||||
target_link_libraries(Fortran90FullExample vtkPVPythonCatalyst ${MPI_Fortran_LIBRARIES})
|
||||
set_target_properties(Fortran90FullExample PROPERTIES
|
||||
LINKER_LANGUAGE Fortran)
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/SampleScripts/coproc.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
include(CTest)
|
||||
add_test(NAME Fortran90FullExampleTest COMMAND Fortran90FullExample)
|
||||
set_tests_properties(Fortran90FullExampleTest PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
endif()
|
||||
@ -0,0 +1,67 @@
|
||||
// Adaptor for getting Fortran simulation code into ParaView CoProcessor.
|
||||
|
||||
// CoProcessor specific headers
|
||||
#include "vtkCPDataDescription.h"
|
||||
#include "vtkCPInputDataDescription.h"
|
||||
#include "vtkCPProcessor.h"
|
||||
#include "vtkCPPythonScriptPipeline.h"
|
||||
#include "vtkSmartPointer.h"
|
||||
#include "vtkDoubleArray.h"
|
||||
#include "vtkPointData.h"
|
||||
#include "vtkImageData.h"
|
||||
|
||||
// Fortran specific header
|
||||
#include "vtkCPPythonAdaptorAPI.h"
|
||||
|
||||
|
||||
// These will be called from the Fortran "glue" code"
|
||||
// Completely dependent on data layout, structured vs. unstructured, etc.
|
||||
// since VTK/ParaView uses different internal layouts for each.
|
||||
|
||||
// Creates the data container for the CoProcessor.
|
||||
extern "C" void createcpimagedata_(int* nxstart, int* nxend, int* nx,
|
||||
int* ny, int* nz)
|
||||
{
|
||||
if (!vtkCPPythonAdaptorAPI::GetCoProcessorData())
|
||||
{
|
||||
vtkGenericWarningMacro("Unable to access CoProcessorData.");
|
||||
return;
|
||||
}
|
||||
|
||||
// The simulation grid is a 3-dimensional topologically and geometrically
|
||||
// regular grid. In VTK/ParaView, this is considered an image data set.
|
||||
vtkSmartPointer<vtkImageData> grid = vtkSmartPointer<vtkImageData>::New();
|
||||
|
||||
grid->SetExtent(*nxstart-1, *nxend-1, 0, *ny-1, 0, *nz-1);
|
||||
|
||||
// Name should be consistent between here, Fortran and Python client script.
|
||||
vtkCPPythonAdaptorAPI::GetCoProcessorData()->GetInputDescriptionByName("input")->SetGrid(grid);
|
||||
vtkCPPythonAdaptorAPI::GetCoProcessorData()->GetInputDescriptionByName("input")->SetWholeExtent(0, *nx-1, 0, *ny-1, 0, *nz-1);
|
||||
}
|
||||
|
||||
// Add field(s) to the data container.
|
||||
// Separate from above because this will be dynamic, grid is static.
|
||||
// By hand name mangling for fortran.
|
||||
extern "C" void addfield_(double* scalars, char* name)
|
||||
{
|
||||
vtkCPInputDataDescription* idd =
|
||||
vtkCPPythonAdaptorAPI::GetCoProcessorData()->GetInputDescriptionByName("input");
|
||||
|
||||
vtkImageData* Image = vtkImageData::SafeDownCast(idd->GetGrid());
|
||||
|
||||
if (!Image)
|
||||
{
|
||||
vtkGenericWarningMacro("No adaptor grid to attach field data to.");
|
||||
return;
|
||||
}
|
||||
|
||||
// field name must match that in the fortran code.
|
||||
if (idd->IsFieldNeeded(name))
|
||||
{
|
||||
vtkSmartPointer<vtkDoubleArray> field = vtkSmartPointer<vtkDoubleArray>::New();
|
||||
field->SetNumberOfComponents(2);
|
||||
field->SetName(name);
|
||||
field->SetArray(scalars, 2*Image->GetNumberOfPoints(), 1);
|
||||
Image->GetPointData()->AddArray(field);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
! A Fortran Catalyst example. Note that coproc.py
|
||||
! must be in the directory where the example
|
||||
! is run from.
|
||||
! Thanks to Lucas Pettey for helping create the example.
|
||||
|
||||
PROGRAM coproc
|
||||
use tcp
|
||||
implicit none
|
||||
include 'mpif.h'
|
||||
integer,parameter :: nx=100,ny=100,nz=100,ntime=10
|
||||
integer :: i,j,k,time,nxstart,nxend
|
||||
real :: max
|
||||
complex(kind=8), allocatable :: psi01(:,:,:)
|
||||
integer :: numtasks,rank,ierr
|
||||
|
||||
call mpi_init(ierr)
|
||||
call mpi_comm_size(MPI_COMM_WORLD, numtasks, ierr)
|
||||
call mpi_comm_rank(MPI_COMM_WORLD, rank, ierr)
|
||||
|
||||
call coprocessorinitializewithpython("coproc.py",9)
|
||||
|
||||
! partition in the x-direction only
|
||||
nxstart=rank*nx/numtasks+1
|
||||
nxend=(rank+1)*nx/numtasks
|
||||
if(numtasks .ne. rank+1) then
|
||||
nxend=nxend+1
|
||||
endif
|
||||
|
||||
allocate(psi01(nxend-nxstart+1,ny,nz))
|
||||
! set initial values
|
||||
max=sqrt(real(nx)**2+real(ny)**2+real(nz)**2)
|
||||
do k=1,nz
|
||||
do j=1,ny
|
||||
do i=1,nxend-nxstart+1
|
||||
psi01(i,j,k)=CMPLX(max-sqrt(real(i-50)**2+real(j-50)**2+real(k-50)**2),&
|
||||
real(1+j+k))/max*100.0
|
||||
enddo
|
||||
enddo
|
||||
enddo
|
||||
|
||||
do time=1,ntime
|
||||
do k=1,nz
|
||||
do j=1,ny
|
||||
do i=1,nxend-nxstart+1
|
||||
psi01(i,j,k)=CMPLX(real(0.30),0.0)+psi01(i,j,k)
|
||||
end do
|
||||
end do
|
||||
end do
|
||||
call testcoprocessor(nxstart,nxend,nx,ny,nz,time,dble(time),psi01)
|
||||
enddo
|
||||
deallocate(psi01)
|
||||
|
||||
call coprocessorfinalize()
|
||||
call mpi_finalize(ierr)
|
||||
|
||||
end program coproc
|
||||
@ -0,0 +1,32 @@
|
||||
module tcp
|
||||
use iso_c_binding
|
||||
implicit none
|
||||
public
|
||||
interface tcp_adaptor
|
||||
module procedure testcoprocessor
|
||||
end interface
|
||||
contains
|
||||
|
||||
subroutine testcoprocessor(nxstart,nxend,nx,ny,nz,step,time,psi01)
|
||||
use iso_c_binding
|
||||
implicit none
|
||||
integer, intent(in) :: nxstart,nxend,nx,ny,nz,step
|
||||
real(kind=8), intent(in) :: time
|
||||
complex(kind=8), dimension(:,:,:), intent (in) :: psi01
|
||||
integer :: flag
|
||||
call requestdatadescription(step,time,flag)
|
||||
if (flag .ne. 0) then
|
||||
call needtocreategrid(flag)
|
||||
if (flag .ne. 0) then
|
||||
call createcpimagedata(nxstart,nxend,nx,nz,nz)
|
||||
end if
|
||||
! adding //char(0) appends the C++ terminating character
|
||||
! to the Fortran array
|
||||
call addfield(psi01,"psi01"//char(0))
|
||||
call coprocess()
|
||||
end if
|
||||
|
||||
return
|
||||
|
||||
end subroutine
|
||||
end module tcp
|
||||
@ -0,0 +1,83 @@
|
||||
|
||||
try: paraview.simple
|
||||
except: from paraview.simple import *
|
||||
|
||||
from paraview import coprocessing
|
||||
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Code generated from cpstate.py to create the CoProcessor.
|
||||
|
||||
|
||||
# ----------------------- CoProcessor definition -----------------------
|
||||
|
||||
def CreateCoProcessor():
|
||||
def _CreatePipeline(coprocessor, datadescription):
|
||||
class Pipeline:
|
||||
filename_6_pvti = coprocessor.CreateProducer( datadescription, "input" )
|
||||
|
||||
Slice1 = Slice( guiName="Slice1", Crinkleslice=0, SliceOffsetValues=[0.0], Triangulatetheslice=1, SliceType="Plane" )
|
||||
Slice1.SliceType.Offset = 0.0
|
||||
Slice1.SliceType.Origin = [49.5, 49.5, 49.5]
|
||||
Slice1.SliceType.Normal = [1.0, 0.0, 0.0]
|
||||
|
||||
ParallelPolyDataWriter1 = coprocessor.CreateWriter( XMLPPolyDataWriter, "slice_%t.pvtp", 10 )
|
||||
|
||||
return Pipeline()
|
||||
|
||||
class CoProcessor(coprocessing.CoProcessor):
|
||||
def CreatePipeline(self, datadescription):
|
||||
self.Pipeline = _CreatePipeline(self, datadescription)
|
||||
|
||||
coprocessor = CoProcessor()
|
||||
freqs = {'input': [10]}
|
||||
coprocessor.SetUpdateFrequencies(freqs)
|
||||
return coprocessor
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Global variables that will hold the pipeline for each timestep
|
||||
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
|
||||
# It will be automatically setup when coprocessor.UpdateProducers() is called the
|
||||
# first time.
|
||||
coprocessor = CreateCoProcessor()
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Enable Live-Visualizaton with ParaView
|
||||
coprocessor.EnableLiveVisualization(False)
|
||||
|
||||
|
||||
# ---------------------- Data Selection method ----------------------
|
||||
|
||||
def RequestDataDescription(datadescription):
|
||||
"Callback to populate the request for current timestep"
|
||||
global coprocessor
|
||||
if datadescription.GetForceOutput() == True:
|
||||
# We are just going to request all fields and meshes from the simulation
|
||||
# code/adaptor.
|
||||
for i in range(datadescription.GetNumberOfInputDescriptions()):
|
||||
datadescription.GetInputDescription(i).AllFieldsOn()
|
||||
datadescription.GetInputDescription(i).GenerateMeshOn()
|
||||
return
|
||||
|
||||
# setup requests for all inputs based on the requirements of the
|
||||
# pipeline.
|
||||
coprocessor.LoadRequestedData(datadescription)
|
||||
|
||||
# ------------------------ Processing method ------------------------
|
||||
|
||||
def DoCoProcessing(datadescription):
|
||||
"Callback to do co-processing for current timestep"
|
||||
global coprocessor
|
||||
|
||||
# Update the coprocessor by providing it the newly generated simulation data.
|
||||
# If the pipeline hasn't been setup yet, this will setup the pipeline.
|
||||
coprocessor.UpdateProducers(datadescription)
|
||||
|
||||
# Write output data, if appropriate.
|
||||
coprocessor.WriteData(datadescription);
|
||||
|
||||
# Write image capture (Last arg: rescale lookup table), if appropriate.
|
||||
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
|
||||
|
||||
# Live Visualization, if enabled.
|
||||
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)
|
||||
114
ParaView-5.0.1/Examples/Catalyst/FortranPoissonSolver/Box.F90
Normal file
114
ParaView-5.0.1/Examples/Catalyst/FortranPoissonSolver/Box.F90
Normal file
@ -0,0 +1,114 @@
|
||||
module Box
|
||||
implicit none
|
||||
public :: getownedbox, getlocalbox
|
||||
|
||||
contains
|
||||
|
||||
! this gives a partitioning of an extent based on its inputs.
|
||||
! the partitioning will overlap (e.g. 0 to 10 partitioned into
|
||||
! 2 pieces would result in 0-5 and 5-10). arguments are:
|
||||
! piece: which piece to get the partition for (between 1 and numpieces)
|
||||
! numpieces: the number of pieces that the extent is partitioned into
|
||||
! globalbox: the extent where the values are ordered by
|
||||
! {max x index, max y index, max z index}
|
||||
! box: the returned local extent where the values are ordered by
|
||||
! {min x index, max x index, min y index, max y index, min z index, max z index}
|
||||
subroutine getlocalbox(piece, numpieces, dimensions, box)
|
||||
implicit none
|
||||
integer, intent(in) :: piece, numpieces, dimensions(3)
|
||||
integer, intent(inout) :: box(6)
|
||||
integer :: numpiecesinfirsthalf, splitaxis, mid, cnt
|
||||
integer :: numpieceslocal, piecelocal, i, size(3)
|
||||
|
||||
do i=1, 3
|
||||
box((i-1)*2+1) = 1
|
||||
box(2*i) = dimensions(i)
|
||||
enddo
|
||||
|
||||
if (piece .gt. numpieces .or. piece .lt. 0) return
|
||||
! keep splitting until we have only one piece.
|
||||
! piece and numpieces will always be relative to the current box.
|
||||
cnt = 0
|
||||
numpieceslocal = numpieces
|
||||
piecelocal = piece-1
|
||||
do while (numpieceslocal .gt. 1)
|
||||
size(1) = box(2) - box(1)
|
||||
size(2) = box(4) - box(3)
|
||||
size(3) = box(6) - box(5)
|
||||
! choose what axis to split on based on the SplitMode
|
||||
! if the user has requested x, y, or z slabs then try to
|
||||
! honor that request. If that axis is already split as
|
||||
! far as it can go, then drop to block mode.
|
||||
! choose the biggest axis
|
||||
if (size(3) .ge. size(2) .and. size(3) .ge. size(1) .and. size(3)/2 .ge. 1) then
|
||||
splitaxis = 3
|
||||
else if (size(2) .ge. size(1) .and. size(2)/2 .ge. 1) then
|
||||
splitaxis = 2
|
||||
else if (size(1)/2 .ge. 1) then
|
||||
splitaxis = 1
|
||||
else
|
||||
splitaxis = -1
|
||||
endif
|
||||
|
||||
if (splitaxis .eq. -1) then
|
||||
! can not split any more.
|
||||
if (piecelocal .eq. 0) then
|
||||
! just return the remaining piece
|
||||
numpieceslocal = 1
|
||||
else
|
||||
! the rest must be empty
|
||||
return
|
||||
endif
|
||||
else ! (splitaxis .eq. -1)
|
||||
! split the chosen axis into two pieces.
|
||||
numpiecesinfirsthalf = (numpieceslocal / 2)
|
||||
mid = size(splitaxis)
|
||||
mid = (mid * numpiecesinfirsthalf) / numpieceslocal + box((splitaxis-1)*2+1)
|
||||
if (piecelocal .lt. numpiecesinfirsthalf) then
|
||||
! piece is in the first half
|
||||
! set boxent to the first half of the previous value.
|
||||
box((splitaxis-1)*2+2) = mid
|
||||
! piece must adjust.
|
||||
numpieceslocal = numpiecesinfirsthalf
|
||||
else
|
||||
! piece is in the second half.
|
||||
! set the boxent to be the second half. (two halves share points)
|
||||
box((splitaxis-1)*2+1) = mid
|
||||
! piece must adjust
|
||||
numpieceslocal = numpieceslocal - numpiecesinfirsthalf
|
||||
piecelocal = piecelocal - numpiecesinfirsthalf
|
||||
endif
|
||||
endif
|
||||
end do
|
||||
return
|
||||
end subroutine getlocalbox
|
||||
|
||||
! box is only locally owned on the minimum side of that
|
||||
! is at the domain boundary
|
||||
subroutine getownedbox(piece, numpieces, dimensions, ownedbox)
|
||||
implicit none
|
||||
integer, intent(in) :: dimensions(3), piece, numpieces
|
||||
integer, intent(out) :: ownedbox(6)
|
||||
integer :: i, localbox(6)
|
||||
|
||||
call getlocalbox(piece, numpieces, dimensions, localbox)
|
||||
|
||||
do i=1, 3
|
||||
! minimums
|
||||
if(localbox((i-1)*2+1) .eq. 1) then
|
||||
ownedbox((i-1)*2+1) = 1
|
||||
else
|
||||
if(localbox((i-1)*2+1) .ne. dimensions(i)) then
|
||||
ownedbox((i-1)*2+1) = localbox((i-1)*2+1)+1
|
||||
else
|
||||
! this happens when the domain has a single point in this direction
|
||||
ownedbox((i-1)*2+1) = 1
|
||||
endif
|
||||
endif
|
||||
! maximums
|
||||
ownedbox(i*2) = localbox(i*2)
|
||||
end do
|
||||
|
||||
end subroutine getownedbox
|
||||
|
||||
end module Box
|
||||
@ -0,0 +1,43 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
project(CatalystFortranPoissonSolver CXX Fortran)
|
||||
|
||||
set(SOURCES
|
||||
FEDriver.F90
|
||||
Box.F90
|
||||
SparseMatrix.F90
|
||||
ConjugateGradient.F90
|
||||
PoissonDiscretization.F90
|
||||
)
|
||||
|
||||
set(USE_CATALYST ON CACHE BOOL "Link the simulator with Catalyst")
|
||||
if(USE_CATALYST)
|
||||
find_package(ParaView 4.1 REQUIRED COMPONENTS vtkPVPythonCatalyst)
|
||||
include("${PARAVIEW_USE_FILE}")
|
||||
# we don't create a separate library for the adaptor here
|
||||
# since FEFortranAdaptor.F90 depends on Box.F90
|
||||
list(APPEND SOURCES FEFortranAdaptor.F90 FECxxAdaptor.cxx)
|
||||
add_definitions("-DUSE_CATALYST")
|
||||
if(NOT PARAVIEW_USE_MPI)
|
||||
message(SEND_ERROR "ParaView must be built with MPI enabled")
|
||||
endif()
|
||||
else()
|
||||
find_package(MPI REQUIRED)
|
||||
include_directories(${MPI_Fortran_INCLUDE_PATH})
|
||||
endif()
|
||||
|
||||
add_executable(FortranPoissonSolver ${SOURCES})
|
||||
target_link_libraries(FortranPoissonSolver ${MPI_Fortran_LIBRARIES})
|
||||
if(USE_CATALYST)
|
||||
target_link_libraries(FortranPoissonSolver vtkPVPythonCatalyst vtkParallelMPI)
|
||||
endif()
|
||||
set_target_properties(FortranPoissonSolver PROPERTIES
|
||||
LINKER_LANGUAGE Fortran)
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/SampleScripts/coproc.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
include(CTest)
|
||||
add_test(NAME FortranPoissonSolverTest COMMAND FortranPoissonSolver coproc.py)
|
||||
set_tests_properties(FortranPoissonSolverTest PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
endif()
|
||||
@ -0,0 +1,67 @@
|
||||
module ConjugateGradient
|
||||
use SparseMatrix
|
||||
#ifdef USE_CATALYST
|
||||
use CoProcessor
|
||||
#endif
|
||||
implicit none
|
||||
private :: dotproduct
|
||||
public :: solve
|
||||
|
||||
contains
|
||||
|
||||
real(kind=8) function dotproduct(sm, a, b)
|
||||
type(SparseMatrixData), intent(inout) :: sm
|
||||
integer :: i
|
||||
real(kind=8), intent(in) :: a(:), b(:)
|
||||
real(kind=8) :: value
|
||||
|
||||
value = 0.d0
|
||||
do i=1, sm%globalsize
|
||||
value = value + a(i)*b(i)
|
||||
enddo
|
||||
dotproduct = value
|
||||
end function dotproduct
|
||||
|
||||
subroutine solve(dimensions, sm, x, rhs)
|
||||
type(SparseMatrixData), intent(inout) :: sm
|
||||
integer, intent(in) :: dimensions(3)
|
||||
real(kind=8), intent(in) :: rhs(:)
|
||||
real(kind=8), intent(inout) :: x(:)
|
||||
integer :: k, i
|
||||
real(kind=8) :: alpha, beta, rdotproduct, rnewdotproduct, sqrtorigresid
|
||||
real(kind=8), DIMENSION(:), allocatable :: r(:), p(:), ap(:)
|
||||
|
||||
allocate(r(sm%globalsize), p(sm%globalsize), ap(sm%globalsize))
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
x(:) = 0.d0
|
||||
call runcoprocessor(dimensions, 0, 0.d0, x)
|
||||
#endif
|
||||
|
||||
r(:) = rhs(:)
|
||||
p(:) = rhs(:)
|
||||
k = 1
|
||||
rdotproduct = dotproduct(sm, r, r)
|
||||
sqrtorigresid = sqrt(rdotproduct)
|
||||
do while(k .le. sm%globalsize .and. sqrt(rdotproduct) .gt. sqrtorigresid*0.000001d0)
|
||||
call matvec(sm, p, ap)
|
||||
alpha = rdotproduct/dotproduct(sm, ap, p)
|
||||
x(:) = x(:) + alpha*p(:)
|
||||
r(:) = r(:) - alpha*ap(:)
|
||||
rnewdotproduct = dotproduct(sm, r, r)
|
||||
beta = rnewdotproduct/rdotproduct
|
||||
p(:) = r(:) + beta*p(:)
|
||||
rdotproduct = rnewdotproduct
|
||||
!write(*,*) 'on iteration ', k, sqrtorigresid, sqrt(rdotproduct), alpha
|
||||
#ifdef USE_CATALYST
|
||||
call runcoprocessor(dimensions, k, k*1.d0, x)
|
||||
#endif
|
||||
k = k+1
|
||||
end do
|
||||
|
||||
deallocate(r, p, ap)
|
||||
|
||||
end subroutine solve
|
||||
|
||||
|
||||
end module ConjugateGradient
|
||||
@ -0,0 +1,66 @@
|
||||
// Adaptor for getting Fortran simulation code into ParaView Catalyst.
|
||||
|
||||
// CoProcessor specific headers
|
||||
#include "vtkCPDataDescription.h"
|
||||
#include "vtkCPInputDataDescription.h"
|
||||
#include "vtkCPProcessor.h"
|
||||
#include "vtkSmartPointer.h"
|
||||
#include "vtkDoubleArray.h"
|
||||
#include "vtkPointData.h"
|
||||
#include "vtkImageData.h"
|
||||
|
||||
// Fortran specific header
|
||||
#include "vtkCPPythonAdaptorAPI.h"
|
||||
|
||||
// These will be called from the Fortran "glue" code"
|
||||
// Completely dependent on data layout, structured vs. unstructured, etc.
|
||||
// since VTK/ParaView uses different internal layouts for each.
|
||||
|
||||
// Creates the data container for the CoProcessor.
|
||||
extern "C" void createcpimagedata_(int* dimensions, int* extent)
|
||||
{
|
||||
if (!vtkCPPythonAdaptorAPI::GetCoProcessorData())
|
||||
{
|
||||
vtkGenericWarningMacro("Unable to access CoProcessorData.");
|
||||
return;
|
||||
}
|
||||
|
||||
// The simulation grid is a 3-dimensional topologically and geometrically
|
||||
// regular grid. In VTK/ParaView, this is considered an image data set.
|
||||
vtkSmartPointer<vtkImageData> grid = vtkSmartPointer<vtkImageData>::New();
|
||||
|
||||
grid->SetExtent(extent[0]-1, extent[1]-1, extent[2]-1,
|
||||
extent[3]-1, extent[4]-1, extent[5]-1);
|
||||
grid->SetSpacing(1./(dimensions[0]-1), 1./(dimensions[1]-1), 1./(dimensions[2]-1));
|
||||
|
||||
// Name should be consistent between here, Fortran and Python client script.
|
||||
vtkCPPythonAdaptorAPI::GetCoProcessorData()->GetInputDescriptionByName("input")->SetGrid(grid);
|
||||
vtkCPPythonAdaptorAPI::GetCoProcessorData()->GetInputDescriptionByName("input")->SetWholeExtent(
|
||||
0, dimensions[0]-1, 0, dimensions[1]-1, 0, dimensions[2]-1);
|
||||
}
|
||||
|
||||
// Add field(s) to the data container.
|
||||
// Separate from above because this will be dynamic, grid is static.
|
||||
// By hand name mangling for fortran.
|
||||
extern "C" void addfield_(double* scalars, char* name)
|
||||
{
|
||||
vtkCPInputDataDescription* idd =
|
||||
vtkCPPythonAdaptorAPI::GetCoProcessorData()->GetInputDescriptionByName("input");
|
||||
|
||||
vtkImageData* image = vtkImageData::SafeDownCast(idd->GetGrid());
|
||||
|
||||
if (!image)
|
||||
{
|
||||
vtkGenericWarningMacro("No adaptor grid to attach field data to.");
|
||||
return;
|
||||
}
|
||||
|
||||
// field name must match that in the fortran code.
|
||||
if (idd->IsFieldNeeded(name))
|
||||
{
|
||||
vtkSmartPointer<vtkDoubleArray> field = vtkSmartPointer<vtkDoubleArray>::New();
|
||||
field->SetName(name);
|
||||
field->SetArray(scalars, image->GetNumberOfPoints(), 1);
|
||||
image->GetPointData()->AddArray(field);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
PROGRAM coproc
|
||||
#ifdef USE_CATALYST
|
||||
use CoProcessor ! ParaView Catalyst adaptor
|
||||
#endif
|
||||
use SparseMatrix ! contains initialize() and finalize()
|
||||
use PoissonDiscretization ! contains fillmatrixandrhs()
|
||||
use ConjugateGradient ! contains solve()
|
||||
use Box ! contains getownedbox()
|
||||
implicit none
|
||||
include 'mpif.h'
|
||||
integer :: numtasks,rank,ierr,allocatestatus
|
||||
integer :: dimensions(3), ownedbox(6)
|
||||
type(SparseMatrixData) :: sm
|
||||
real(kind=8), DIMENSION(:), allocatable :: x, rhs
|
||||
|
||||
call mpi_init(ierr)
|
||||
call mpi_comm_size(MPI_COMM_WORLD, numtasks, ierr)
|
||||
call mpi_comm_rank(MPI_COMM_WORLD, rank, ierr)
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
call initializecoprocessor()
|
||||
#endif
|
||||
|
||||
dimensions(1) = 10
|
||||
dimensions(2) = 10
|
||||
dimensions(3) = 10
|
||||
|
||||
! given a piece between 1 and numtasks, compute the nodes that
|
||||
! are owned by this process (ownedbox)
|
||||
call getownedbox(rank+1, numtasks, dimensions, ownedbox)
|
||||
|
||||
call initialize(sm, ownedbox, dimensions)
|
||||
|
||||
! each process has a full copy of the solution and the RHS to keep things simple
|
||||
allocate(x(dimensions(1)*dimensions(2)*dimensions(3)), rhs(dimensions(1)*dimensions(2)*dimensions(3)), STAT = allocatestatus)
|
||||
if (allocatestatus /= 0) STOP "*** FEDriver.F90: Not enough memory for arrays ***"
|
||||
|
||||
call fillmatrixandrhs(sm, rhs, ownedbox, dimensions)
|
||||
|
||||
call solve(dimensions, sm, x, rhs)
|
||||
|
||||
#ifdef USE_CATALYST
|
||||
call finalizecoprocessor()
|
||||
#endif
|
||||
|
||||
deallocate(x, rhs)
|
||||
|
||||
call finalize(sm)
|
||||
|
||||
call mpi_finalize(ierr)
|
||||
|
||||
write(*,*) 'Finished on rank', rank, 'of', numtasks
|
||||
|
||||
end program coproc
|
||||
@ -0,0 +1,86 @@
|
||||
module CoProcessor
|
||||
implicit none
|
||||
public initializecoprocessor, runcoprocessor, finalizecoprocessor
|
||||
|
||||
contains
|
||||
|
||||
subroutine initializecoprocessor()
|
||||
implicit none
|
||||
integer :: ilen, i
|
||||
character(len=200) :: arg
|
||||
|
||||
call coprocessorinitialize()
|
||||
do i=1, iargc()
|
||||
call getarg(i, arg)
|
||||
ilen = len_trim(arg)
|
||||
arg(ilen+1:) = char(0)
|
||||
call coprocessoraddpythonscript(arg, ilen)
|
||||
enddo
|
||||
end subroutine initializecoprocessor
|
||||
|
||||
subroutine runcoprocessor(dimensions, step, time, x)
|
||||
use iso_c_binding
|
||||
implicit none
|
||||
integer, intent(in) :: dimensions(3), step
|
||||
real(kind=8), dimension(:), intent(in) :: x
|
||||
real(kind=8), intent(in) :: time
|
||||
integer :: flag, extent(6)
|
||||
real(kind=8), DIMENSION(:), allocatable :: xcp(:)
|
||||
|
||||
call requestdatadescription(step,time,flag)
|
||||
if (flag .ne. 0) then
|
||||
call needtocreategrid(flag)
|
||||
call getvtkextent(dimensions, extent)
|
||||
|
||||
if (flag .ne. 0) then
|
||||
call createcpimagedata(dimensions, extent)
|
||||
end if
|
||||
! x is the array with global values, we need just this process's
|
||||
! values for Catalyst which will be put in xcp
|
||||
allocate(xcp((extent(2)-extent(1)+1)*(extent(4)-extent(3)+1)*(extent(6)-extent(5)+1)))
|
||||
call getlocalfield(dimensions, extent, x, xcp)
|
||||
|
||||
! adding //char(0) appends the C++ terminating character
|
||||
! to the Fortran array
|
||||
call addfield(xcp,"solution"//char(0))
|
||||
call coprocess()
|
||||
deallocate(xcp)
|
||||
end if
|
||||
end subroutine runcoprocessor
|
||||
|
||||
subroutine finalizecoprocessor()
|
||||
call coprocessorfinalize()
|
||||
end subroutine finalizecoprocessor
|
||||
|
||||
! helper methods
|
||||
subroutine getvtkextent(dimensions, extent)
|
||||
use Box
|
||||
implicit none
|
||||
include 'mpif.h'
|
||||
integer, intent(in) :: dimensions(3)
|
||||
integer, intent(out) :: extent(6)
|
||||
integer :: numtasks, rank, ierr
|
||||
|
||||
call mpi_comm_size(MPI_COMM_WORLD, numtasks, ierr)
|
||||
call mpi_comm_rank(MPI_COMM_WORLD, rank, ierr)
|
||||
call getlocalbox(rank+1, numtasks, dimensions, extent)
|
||||
end subroutine getvtkextent
|
||||
|
||||
subroutine getlocalfield(dimensions, extent, x, xcp)
|
||||
implicit none
|
||||
integer :: i, j, k, counter
|
||||
integer, intent(in) :: dimensions(3), extent(6)
|
||||
real(kind=8), dimension(:), intent(in) :: x
|
||||
real(kind=8), dimension(:), intent(out) :: xcp
|
||||
counter = 1
|
||||
do k=extent(5), extent(6)
|
||||
do j=extent(3), extent(4)
|
||||
do i=extent(1), extent(2)
|
||||
xcp(counter) = x(i+(j-1)*dimensions(1)+(k-1)*dimensions(1)*dimensions(2))
|
||||
counter = counter + 1
|
||||
enddo
|
||||
enddo
|
||||
enddo
|
||||
end subroutine getlocalfield
|
||||
|
||||
end module CoProcessor
|
||||
@ -0,0 +1,127 @@
|
||||
module PoissonDiscretization
|
||||
implicit none
|
||||
public :: fillmatrixandrhs
|
||||
|
||||
contains
|
||||
subroutine fillmatrixandrhs(sm, rhs, ownedbox, dimensions)
|
||||
use SparseMatrix
|
||||
implicit none
|
||||
real(kind=8), intent(out) :: rhs(:)
|
||||
type(SparseMatrixData), intent(inout) :: sm
|
||||
integer, intent(in) :: ownedbox(6), dimensions(3)
|
||||
integer :: i,j,k
|
||||
real(kind=8) :: dxsqinverse, dysqinverse, dzsqinverse, value
|
||||
logical :: negativex, negativey, negativez, positivex, positivey, positivez, interior
|
||||
integer :: numx, numy, numz, row
|
||||
|
||||
! construct the matrix
|
||||
numx = ownedbox(2)-ownedbox(1)+1
|
||||
if(numx < 1) numx = 1
|
||||
numy = ownedbox(4)-ownedbox(3)+1
|
||||
if(numy < 1) numy = 1
|
||||
numz = ownedbox(6)-ownedbox(5)+1
|
||||
|
||||
rhs(:) = 0.0
|
||||
|
||||
dxsqinverse = 1.d0/((dimensions(1)-1)*(dimensions(1)-1))
|
||||
dysqinverse = 1.d0/((dimensions(2)-1)*(dimensions(2)-1))
|
||||
dzsqinverse = 1.d0/((dimensions(3)-1)*(dimensions(3)-1))
|
||||
|
||||
do k=1, numz
|
||||
negativez = .TRUE.
|
||||
if(k .eq. 1 .and. ownedbox(5) .eq. 1) negativez = .FALSE.
|
||||
positivez = .TRUE.
|
||||
if(k .eq. numz .and. ownedbox(6) .eq. dimensions(3)) positivez = .FALSE.
|
||||
do j=1, numy
|
||||
negativey = .TRUE.
|
||||
if(j .eq. 1 .and. ownedbox(3) .eq. 1) negativey = .FALSE.
|
||||
positivey = .TRUE.
|
||||
if(j .eq. numy .and. ownedbox(4) .eq. dimensions(2)) positivey = .FALSE.
|
||||
do i=1, numx
|
||||
negativex = .TRUE.
|
||||
if(i .eq. 1 .and. ownedbox(1) .eq. 1) negativex = .FALSE.
|
||||
positivex = .TRUE.
|
||||
if(i .eq. numx .and. ownedbox(2) .eq. dimensions(1)) positivex = .FALSE.
|
||||
interior = negativex .and. negativey .and. negativez .and. positivex .and. positivey .and. positivez
|
||||
row = i+ownedbox(1)-1+(j+ownedbox(3)-2)*dimensions(1)+(k+ownedbox(5)-2)*dimensions(1)*dimensions(2)
|
||||
if(.NOT. interior) then
|
||||
call insert(sm, row, row, 1.d0)
|
||||
if(.NOT. positivez) rhs(row) = 1.d0
|
||||
else
|
||||
call insert(sm, row, row-1, dxsqinverse)
|
||||
call insert(sm, row, row+1, dxsqinverse)
|
||||
call insert(sm, row, row-dimensions(1), dysqinverse)
|
||||
call insert(sm, row, row+dimensions(1), dysqinverse)
|
||||
call insert(sm, row, row-dimensions(1)*dimensions(2), dzsqinverse)
|
||||
call insert(sm, row, row+dimensions(1)*dimensions(2), dzsqinverse)
|
||||
call insert(sm, row, row, -2.d0*dxsqinverse-2.d0*dysqinverse-2.d0*dzsqinverse)
|
||||
endif
|
||||
end do
|
||||
end do
|
||||
end do
|
||||
|
||||
! now we need to diagonalize the matrix based on boundary conditions
|
||||
! do the non-homogeneous bcs on the z=1 plane first
|
||||
if(ownedbox(5) .le. dimensions(3)-1 .and. ownedbox(6) .ge. dimensions(3)-1) then
|
||||
do i=ownedbox(1), ownedbox(2)
|
||||
do j=ownedbox(3), ownedbox(4)
|
||||
row = i+(j-1)*dimensions(1)+dimensions(1)*dimensions(2)*(dimensions(3)-2)
|
||||
call get(sm, row, row+dimensions(1)*dimensions(2), value)
|
||||
rhs(row) = rhs(row) - value*1.d0
|
||||
call insert(sm, row, row+dimensions(1)*dimensions(2), 0.d0)
|
||||
enddo
|
||||
enddo
|
||||
endif
|
||||
! the homogeneous bcs
|
||||
! the z=0 plane
|
||||
if(ownedbox(5) .le. 2 .and. ownedbox(6) .ge. 2) then
|
||||
do i=ownedbox(1), ownedbox(2)
|
||||
do j=ownedbox(3), ownedbox(4)
|
||||
row = i+(j-1)*dimensions(1)+dimensions(1)*dimensions(2)
|
||||
call insert(sm, row, row-dimensions(1)*dimensions(2), 0.d0)
|
||||
enddo
|
||||
enddo
|
||||
endif
|
||||
! the x=0 plane
|
||||
if(ownedbox(1) .le. 2 .and. ownedbox(2) .ge. 2) then
|
||||
do i=ownedbox(3), ownedbox(4)
|
||||
do j=ownedbox(5), ownedbox(6)
|
||||
row = 2+(i-1)*dimensions(1)+(j-1)*dimensions(1)*dimensions(2)
|
||||
call insert(sm, row, row-1, 0.d0)
|
||||
enddo
|
||||
enddo
|
||||
endif
|
||||
! the x=1 plane
|
||||
if(ownedbox(1) .le. dimensions(1)-1 .and. ownedbox(2) .ge. dimensions(1)-1) then
|
||||
do i=ownedbox(3), ownedbox(4)
|
||||
do j=ownedbox(5), ownedbox(6)
|
||||
row = dimensions(1)-1+(i-1)*dimensions(1)+(j-1)*dimensions(1)*dimensions(2)
|
||||
call insert(sm, row, row+1, 0.d0)
|
||||
enddo
|
||||
enddo
|
||||
endif
|
||||
! the y=0 plane
|
||||
if(ownedbox(3) .le. 2 .and. ownedbox(4) .ge. 2) then
|
||||
do i=ownedbox(1), ownedbox(2)
|
||||
do j=ownedbox(5), ownedbox(6)
|
||||
row = i+dimensions(1)+(j-1)*dimensions(1)*dimensions(2)
|
||||
call insert(sm, row, row-dimensions(1), 0.d0)
|
||||
enddo
|
||||
enddo
|
||||
endif
|
||||
! the y=1 plane
|
||||
if(ownedbox(3) .le. dimensions(2)-1 .and. ownedbox(4) .ge. dimensions(2)-1) then
|
||||
do i=ownedbox(1), ownedbox(2)
|
||||
do j=ownedbox(5), ownedbox(6)
|
||||
row = i+dimensions(1)*(dimensions(2)-2)+(j-1)*dimensions(1)*dimensions(2)
|
||||
call insert(sm, row, row+dimensions(1), 0.d0)
|
||||
enddo
|
||||
enddo
|
||||
endif
|
||||
|
||||
! now do an mpi_allreduce on the rhs
|
||||
call allreducevector(sm%globalsize, rhs)
|
||||
|
||||
end subroutine fillmatrixandrhs
|
||||
|
||||
end module PoissonDiscretization
|
||||
@ -0,0 +1,83 @@
|
||||
|
||||
try: paraview.simple
|
||||
except: from paraview.simple import *
|
||||
|
||||
from paraview import coprocessing
|
||||
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Code generated from cpstate.py to create the CoProcessor.
|
||||
|
||||
|
||||
# ----------------------- CoProcessor definition -----------------------
|
||||
|
||||
def CreateCoProcessor():
|
||||
def _CreatePipeline(coprocessor, datadescription):
|
||||
class Pipeline:
|
||||
filename_6_pvti = coprocessor.CreateProducer( datadescription, "input" )
|
||||
|
||||
Slice1 = Slice( guiName="Slice1", Crinkleslice=0, SliceOffsetValues=[0.0], Triangulatetheslice=1, SliceType="Plane" )
|
||||
Slice1.SliceType.Offset = 0.0
|
||||
Slice1.SliceType.Origin = [49.5, 49.5, 49.5]
|
||||
Slice1.SliceType.Normal = [1.0, 0.0, 0.0]
|
||||
|
||||
ParallelPolyDataWriter1 = coprocessor.CreateWriter( XMLPPolyDataWriter, "slice_%t.pvtp", 10 )
|
||||
|
||||
return Pipeline()
|
||||
|
||||
class CoProcessor(coprocessing.CoProcessor):
|
||||
def CreatePipeline(self, datadescription):
|
||||
self.Pipeline = _CreatePipeline(self, datadescription)
|
||||
|
||||
coprocessor = CoProcessor()
|
||||
freqs = {'input': [10]}
|
||||
coprocessor.SetUpdateFrequencies(freqs)
|
||||
return coprocessor
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Global variables that will hold the pipeline for each timestep
|
||||
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
|
||||
# It will be automatically setup when coprocessor.UpdateProducers() is called the
|
||||
# first time.
|
||||
coprocessor = CreateCoProcessor()
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Enable Live-Visualizaton with ParaView
|
||||
coprocessor.EnableLiveVisualization(False)
|
||||
|
||||
|
||||
# ---------------------- Data Selection method ----------------------
|
||||
|
||||
def RequestDataDescription(datadescription):
|
||||
"Callback to populate the request for current timestep"
|
||||
global coprocessor
|
||||
if datadescription.GetForceOutput() == True:
|
||||
# We are just going to request all fields and meshes from the simulation
|
||||
# code/adaptor.
|
||||
for i in range(datadescription.GetNumberOfInputDescriptions()):
|
||||
datadescription.GetInputDescription(i).AllFieldsOn()
|
||||
datadescription.GetInputDescription(i).GenerateMeshOn()
|
||||
return
|
||||
|
||||
# setup requests for all inputs based on the requirements of the
|
||||
# pipeline.
|
||||
coprocessor.LoadRequestedData(datadescription)
|
||||
|
||||
# ------------------------ Processing method ------------------------
|
||||
|
||||
def DoCoProcessing(datadescription):
|
||||
"Callback to do co-processing for current timestep"
|
||||
global coprocessor
|
||||
|
||||
# Update the coprocessor by providing it the newly generated simulation data.
|
||||
# If the pipeline hasn't been setup yet, this will setup the pipeline.
|
||||
coprocessor.UpdateProducers(datadescription)
|
||||
|
||||
# Write output data, if appropriate.
|
||||
coprocessor.WriteData(datadescription);
|
||||
|
||||
# Write image capture (Last arg: rescale lookup table), if appropriate.
|
||||
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
|
||||
|
||||
# Live Visualization, if enabled.
|
||||
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)
|
||||
@ -0,0 +1,177 @@
|
||||
module SparseMatrix
|
||||
! this uses the MKL sparse matrix storage scheme. it assumes we have a
|
||||
! node-based partitioning of the grid.
|
||||
implicit none
|
||||
public :: initialize, insert, finalize, allreducevector, matvec
|
||||
|
||||
type SparseMatrixData
|
||||
real(kind=8), DIMENSION(:), allocatable :: values
|
||||
integer, DIMENSION(:), allocatable :: columns, rowindices, mapping
|
||||
integer :: globalsize
|
||||
end type SparseMatrixData
|
||||
|
||||
contains
|
||||
subroutine initialize(sm, ownedbox, dimensions)
|
||||
type(SparseMatrixData), intent(inout) :: sm
|
||||
integer, intent(in) :: ownedbox(6), dimensions(3)
|
||||
integer :: numpoints, i, j, k, numx, numy, numz, counter, rowcounter, globalindex
|
||||
logical :: negativey, positivey, negativez, positivez
|
||||
integer :: allocatestatus
|
||||
|
||||
numpoints = 1
|
||||
numx = ownedbox(2)-ownedbox(1)+1
|
||||
if(numx < 1) numx = 1
|
||||
numy = ownedbox(4)-ownedbox(3)+1
|
||||
if(numy < 1) numy = 1
|
||||
numz = ownedbox(6)-ownedbox(5)+1
|
||||
if(numz < 1) numz = 1
|
||||
numpoints = numx*numy*numz
|
||||
|
||||
! over-allocate both values and columns
|
||||
allocate(sm%rowindices(numpoints+1), sm%columns(7*numpoints), sm%values(7*numpoints), STAT = allocatestatus)
|
||||
if (allocatestatus /= 0) STOP "*** SparseMatrix.F90: Not enough memory for arrays ***"
|
||||
|
||||
sm%values(:) = 0.d0
|
||||
sm%columns(:) = -1
|
||||
|
||||
! a mapping from the global row index to the local row index
|
||||
sm%globalsize = dimensions(1)*dimensions(2)*dimensions(3)
|
||||
allocate(sm%mapping(sm%globalsize))
|
||||
sm%mapping(:) = -1 ! initialize with bad values
|
||||
|
||||
rowcounter = 1
|
||||
counter = 1
|
||||
do k=1, numz
|
||||
negativez = .TRUE.
|
||||
if(k .eq. 1 .and. ownedbox(5) .eq. 1) negativez = .FALSE.
|
||||
positivez = .TRUE.
|
||||
if(k .eq. numz .and. ownedbox(6) .eq. dimensions(3)) positivez = .FALSE.
|
||||
do j=1, numy
|
||||
negativey = .TRUE.
|
||||
if(j .eq. 1 .and. ownedbox(3) .eq. 1) negativey = .FALSE.
|
||||
positivey = .TRUE.
|
||||
if(j .eq. numy .and. ownedbox(4) .eq. dimensions(2)) positivey = .FALSE.
|
||||
do i=1, numx
|
||||
globalindex = (ownedbox(5)+k-2)*dimensions(1)*dimensions(2)+(ownedbox(3)+j-2)*dimensions(1)+ownedbox(1)+i-1
|
||||
sm%rowindices(rowcounter) = counter
|
||||
sm%mapping(globalindex) = rowcounter
|
||||
rowcounter = rowcounter + 1
|
||||
if(negativez) then
|
||||
sm%columns(counter) = globalindex-dimensions(1)*dimensions(2)
|
||||
counter = counter + 1
|
||||
endif
|
||||
if(negativey) then
|
||||
sm%columns(counter) = globalindex-dimensions(1)
|
||||
counter = counter + 1
|
||||
endif
|
||||
if(i .ne. 1 .or. ownedbox(1) .ne. 1) then
|
||||
sm%columns(counter) = globalindex-1
|
||||
counter = counter + 1
|
||||
endif
|
||||
sm%columns(counter) = globalindex
|
||||
counter = counter + 1
|
||||
if(i .ne. numx .or. ownedbox(2) .ne. dimensions(1)) then
|
||||
sm%columns(counter) = globalindex+1
|
||||
counter = counter + 1
|
||||
endif
|
||||
if(positivey) then
|
||||
sm%columns(counter) = globalindex+dimensions(1)
|
||||
counter = counter + 1
|
||||
endif
|
||||
if(positivez) then
|
||||
sm%columns(counter) = globalindex+dimensions(1)*dimensions(2)
|
||||
counter = counter + 1
|
||||
endif
|
||||
end do
|
||||
end do
|
||||
end do
|
||||
! the final value for ending the row
|
||||
sm%rowindices(rowcounter) = counter
|
||||
end subroutine initialize
|
||||
|
||||
subroutine finalize(sm)
|
||||
type(SparseMatrixData), intent(inout) :: sm
|
||||
if(allocated(sm%values)) deallocate(sm%values)
|
||||
if(allocated(sm%columns)) deallocate(sm%columns)
|
||||
if(allocated(sm%rowindices)) deallocate(sm%rowindices)
|
||||
if(allocated(sm%mapping)) deallocate(sm%mapping)
|
||||
end subroutine finalize
|
||||
|
||||
subroutine insert(sm, row, column, value)
|
||||
type(SparseMatrixData), intent(inout) :: sm
|
||||
integer, intent(in) :: row, column
|
||||
real(kind=8), intent(in) :: value
|
||||
integer :: i, rowindex
|
||||
|
||||
rowindex = sm%mapping(row)
|
||||
|
||||
do i=sm%rowindices(rowindex), sm%rowindices(rowindex+1)-1
|
||||
if(sm%columns(i) .eq. column) then
|
||||
sm%values(i) = value
|
||||
return
|
||||
endif
|
||||
end do
|
||||
|
||||
write(*,*) 'SparseMatrix: bad indices for insert() ', row, column
|
||||
end subroutine insert
|
||||
|
||||
subroutine get(sm, row, column, value)
|
||||
type(SparseMatrixData), intent(in) :: sm
|
||||
integer, intent(in) :: row, column
|
||||
real(kind=8), intent(out) :: value
|
||||
integer :: i, rowindex
|
||||
|
||||
rowindex = sm%mapping(row)
|
||||
|
||||
do i=sm%rowindices(rowindex), sm%rowindices(rowindex+1)-1
|
||||
if(sm%columns(i) .eq. column) then
|
||||
value = sm%values(i)
|
||||
return
|
||||
endif
|
||||
end do
|
||||
write(*,*) 'SparseMatrix: bad indices for get() ', row, column
|
||||
end subroutine get
|
||||
|
||||
subroutine matvec(sm, x, b)
|
||||
!Ax=b
|
||||
type(SparseMatrixData), intent(inout) :: sm
|
||||
real(kind=8), intent(in) :: x(:)
|
||||
real(kind=8), intent(out) :: b(:)
|
||||
integer :: i, j
|
||||
|
||||
do i=1, sm%globalsize
|
||||
b(i) = 0.d0
|
||||
if(sm%mapping(i) .gt. 0) then
|
||||
do j=sm%rowindices(sm%mapping(i)), sm%rowindices(sm%mapping(i)+1)-1
|
||||
b(i) = b(i) + sm%values(j)*x(sm%columns(j))
|
||||
end do
|
||||
endif
|
||||
end do
|
||||
|
||||
call allreducevector(sm%globalsize, b)
|
||||
end subroutine matvec
|
||||
|
||||
subroutine allreducevector(globalsize, vec)
|
||||
implicit none
|
||||
include 'mpif.h'
|
||||
integer, intent(in) :: globalsize
|
||||
real(kind=8), intent(inout) :: vec(:)
|
||||
real(kind=8), DIMENSION(:), allocatable :: temp
|
||||
integer :: ierr, i, numtasks, allocatestatus
|
||||
|
||||
call mpi_comm_size(MPI_COMM_WORLD, numtasks, ierr)
|
||||
if(numtasks .eq. 1) then
|
||||
return
|
||||
endif
|
||||
|
||||
allocate(temp(globalsize), STAT = allocatestatus)
|
||||
if (allocatestatus /= 0) STOP "*** SparseMatrix.F90: Not enough memory for temp array ***"
|
||||
do i=1, globalsize
|
||||
temp(i) = vec(i)
|
||||
enddo
|
||||
call mpi_allreduce(temp, vec, globalsize, MPI_DOUBLE_PRECISION, MPI_SUM, MPI_COMM_WORLD, ierr)
|
||||
deallocate(temp)
|
||||
|
||||
end subroutine allreducevector
|
||||
|
||||
end module SparseMatrix
|
||||
27
ParaView-5.0.1/Examples/Catalyst/LICENSE.md
Normal file
27
ParaView-5.0.1/Examples/Catalyst/LICENSE.md
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2013, Kitware Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the name of Kitware Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@ -0,0 +1,23 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(CatalystMPISubCommunicatorExample)
|
||||
|
||||
find_package(ParaView 4.2 REQUIRED COMPONENTS vtkPVPythonCatalyst)
|
||||
include("${PARAVIEW_USE_FILE}")
|
||||
if(NOT PARAVIEW_USE_MPI)
|
||||
message(SEND_ERROR "ParaView must be built with MPI enabled")
|
||||
endif()
|
||||
|
||||
add_executable(MPISubCommunicatorExample FEDriver.cxx FEDataStructures.cxx FEAdaptor.cxx)
|
||||
target_link_libraries(MPISubCommunicatorExample LINK_PRIVATE vtkPVPythonCatalyst vtkParallelMPI)
|
||||
include(vtkModuleMacros)
|
||||
include(vtkMPI)
|
||||
vtk_mpi_link(MPISubCommunicatorExample)
|
||||
|
||||
option(BUILD_TESTING "Build Testing" OFF)
|
||||
# Setup testing.
|
||||
if (BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_test(NAME MPISubCommunicatorExampleTest COMMAND MPISubCommunicatorExample
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SampleScripts/feslicescript.py)
|
||||
set_tests_properties(MPISubCommunicatorExampleTest PROPERTIES LABELS "PARAVIEW;CATALYST")
|
||||
endif()
|
||||
@ -0,0 +1,164 @@
|
||||
#include <iostream>
|
||||
#include "FEAdaptor.h"
|
||||
#include "FEDataStructures.h"
|
||||
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkCellType.h>
|
||||
#include <vtkCPDataDescription.h>
|
||||
#include <vtkCPInputDataDescription.h>
|
||||
#include <vtkCPProcessor.h>
|
||||
#include <vtkCPPythonScriptPipeline.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkFloatArray.h>
|
||||
#include <vtkMPI.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkPoints.h>
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
vtkCPProcessor* Processor = NULL;
|
||||
vtkUnstructuredGrid* VTKGrid;
|
||||
vtkMPICommunicatorOpaqueComm* Comm = NULL;
|
||||
|
||||
void BuildVTKGrid(Grid& grid)
|
||||
{
|
||||
// create the points information
|
||||
vtkNew<vtkDoubleArray> pointArray;
|
||||
pointArray->SetNumberOfComponents(3);
|
||||
pointArray->SetArray(grid.GetPointsArray(), static_cast<vtkIdType>(grid.GetNumberOfPoints()*3), 1);
|
||||
vtkNew<vtkPoints> points;
|
||||
points->SetData(pointArray.GetPointer());
|
||||
VTKGrid->SetPoints(points.GetPointer());
|
||||
|
||||
// create the cells
|
||||
size_t numCells = grid.GetNumberOfCells();
|
||||
VTKGrid->Allocate(static_cast<vtkIdType>(numCells*9));
|
||||
for(size_t cell=0;cell<numCells;cell++)
|
||||
{
|
||||
unsigned int* cellPoints = grid.GetCellPoints(cell);
|
||||
vtkIdType tmp[8] = {cellPoints[0], cellPoints[1], cellPoints[2], cellPoints[3],
|
||||
cellPoints[4], cellPoints[5], cellPoints[6], cellPoints[7]};
|
||||
VTKGrid->InsertNextCell(VTK_HEXAHEDRON, 8, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateVTKAttributes(Grid& grid, Attributes& attributes)
|
||||
{
|
||||
if(VTKGrid->GetPointData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// velocity array
|
||||
vtkNew<vtkDoubleArray> velocity;
|
||||
velocity->SetName("velocity");
|
||||
velocity->SetNumberOfComponents(3);
|
||||
velocity->SetNumberOfTuples(static_cast<vtkIdType>(grid.GetNumberOfPoints()));
|
||||
VTKGrid->GetPointData()->AddArray(velocity.GetPointer());
|
||||
}
|
||||
if(VTKGrid->GetCellData()->GetNumberOfArrays() == 0)
|
||||
{
|
||||
// pressure array
|
||||
vtkNew<vtkFloatArray> pressure;
|
||||
pressure->SetName("pressure");
|
||||
pressure->SetNumberOfComponents(1);
|
||||
VTKGrid->GetCellData()->AddArray(pressure.GetPointer());
|
||||
}
|
||||
vtkDoubleArray* velocity = vtkDoubleArray::SafeDownCast(
|
||||
VTKGrid->GetPointData()->GetArray("velocity"));
|
||||
// The velocity array is ordered as vx0,vx1,vx2,..,vy0,vy1,vy2,..,vz0,vz1,vz2,..
|
||||
// so we need to create a full copy of it with VTK's ordering of
|
||||
// vx0,vy0,vz0,vx1,vy1,vz1,..
|
||||
double* velocityData = attributes.GetVelocityArray();
|
||||
vtkIdType numTuples = velocity->GetNumberOfTuples();
|
||||
for(vtkIdType i=0;i<numTuples;i++)
|
||||
{
|
||||
double values[3] = {velocityData[i], velocityData[i+numTuples],
|
||||
velocityData[i+2*numTuples]};
|
||||
velocity->SetTupleValue(i, values);
|
||||
}
|
||||
|
||||
vtkFloatArray* pressure = vtkFloatArray::SafeDownCast(
|
||||
VTKGrid->GetCellData()->GetArray("pressure"));
|
||||
// The pressure array is a scalar array so we can reuse
|
||||
// memory as long as we ordered the points properly.
|
||||
float* pressureData = attributes.GetPressureArray();
|
||||
pressure->SetArray(pressureData, static_cast<vtkIdType>(grid.GetNumberOfCells()), 1);
|
||||
}
|
||||
|
||||
void BuildVTKDataStructures(Grid& grid, Attributes& attributes)
|
||||
{
|
||||
if(VTKGrid == NULL)
|
||||
{
|
||||
// The grid structure isn't changing so we only build it
|
||||
// the first time it's needed. If we needed the memory
|
||||
// we could delete it and rebuild as necessary.
|
||||
VTKGrid = vtkUnstructuredGrid::New();
|
||||
BuildVTKGrid(grid);
|
||||
}
|
||||
UpdateVTKAttributes(grid, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
namespace FEAdaptor
|
||||
{
|
||||
|
||||
void Initialize(int numScripts, char* scripts[], MPI_Comm* handle)
|
||||
{
|
||||
if(Processor == NULL)
|
||||
{
|
||||
Processor = vtkCPProcessor::New();
|
||||
Comm = new vtkMPICommunicatorOpaqueComm(handle);
|
||||
Processor->Initialize(*Comm);
|
||||
}
|
||||
else
|
||||
{
|
||||
Processor->RemoveAllPipelines();
|
||||
}
|
||||
for(int i=1;i<numScripts;i++)
|
||||
{
|
||||
vtkNew<vtkCPPythonScriptPipeline> pipeline;
|
||||
pipeline->Initialize(scripts[i]);
|
||||
Processor->AddPipeline(pipeline.GetPointer());
|
||||
}
|
||||
}
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
if(Processor)
|
||||
{
|
||||
Processor->Finalize();
|
||||
Processor->Delete();
|
||||
Processor = NULL;
|
||||
}
|
||||
if(VTKGrid)
|
||||
{
|
||||
VTKGrid->Delete();
|
||||
VTKGrid = NULL;
|
||||
}
|
||||
if(Comm)
|
||||
{
|
||||
delete Comm;
|
||||
Comm = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CoProcess(Grid& grid, Attributes& attributes, double time,
|
||||
unsigned int timeStep, bool lastTimeStep)
|
||||
{
|
||||
vtkNew<vtkCPDataDescription> dataDescription;
|
||||
dataDescription->AddInput("input");
|
||||
dataDescription->SetTimeData(time, timeStep);
|
||||
if(lastTimeStep == true)
|
||||
{
|
||||
// assume that we want to all the pipelines to execute if it
|
||||
// is the last time step.
|
||||
dataDescription->ForceOutputOn();
|
||||
}
|
||||
if(Processor->RequestDataDescription(dataDescription.GetPointer()) != 0)
|
||||
{
|
||||
BuildVTKDataStructures(grid, attributes);
|
||||
dataDescription->GetInputDescriptionByName("input")->SetGrid(VTKGrid);
|
||||
Processor->CoProcess(dataDescription.GetPointer());
|
||||
}
|
||||
}
|
||||
} // end of Catalyst namespace
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user