diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 54e4e376a..90251e0f5 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -37,6 +37,7 @@ if(VTKm_ENABLE_EXAMPLES) add_subdirectory(cosmotools) add_subdirectory(demo) add_subdirectory(game_of_life) + add_subdirectory(heat_diffusion) add_subdirectory(hello_worklet) add_subdirectory(histogram) add_subdirectory(ising) diff --git a/examples/heat_diffusion/CMakeLists.txt b/examples/heat_diffusion/CMakeLists.txt new file mode 100644 index 000000000..b977d3be7 --- /dev/null +++ b/examples/heat_diffusion/CMakeLists.txt @@ -0,0 +1,63 @@ +##============================================================================ +## Copyright (c) Kitware, Inc. +## All rights reserved. +## See LICENSE.txt 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. +##============================================================================ +cmake_minimum_required(VERSION 3.13) + +project(Heat_Diffusion CXX) + +find_package(VTKm REQUIRED) + +vtkm_find_gl(OPTIONAL GL GLUT GLEW) +include(CTest) +enable_testing() + +add_library(Parameters parameters.cpp) + +add_library(InitalCondition InitalCondition.cpp) +target_link_libraries(InitalCondition PUBLIC vtkm_filter vtkm_io Parameters) + + + +add_executable(HeatDiffusionExample main.cxx) +target_link_libraries(HeatDiffusionExample PUBLIC InitalCondition Parameters vtkm_filter vtkm_io) + +vtkm_add_target_information(HeatDiffusionExample + DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS + DEVICE_SOURCES heat_diffusion.cxx Diffusion.cxx InitalCondition.cpp parameters.cpp) + +if(TARGET OpenGL::GL AND + TARGET GLUT::GLUT AND + TARGET GLEW::GLEW AND + TARGET vtkm_rendering ) + target_link_libraries(HeatDiffusionExample PUBLIC OpenGL::GL GLEW::GLEW GLUT::GLUT vtkm_rendering) + target_compile_definitions(HeatDiffusionExample PUBLIC -DANIMATE ) +else() + MESSAGE(STATUS "Either OpenGL::GL or GLUT::GLUT or GLEW::GLEW not found: animation disabled") +endif() + + +##file(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/Tests/test_*.cxx") +##foreach(file ${files}) +## string(REGEX REPLACE "(^.*/|\\.[^.]*$)" "" file_without_ext ${file}) +## add_executable(${file_without_ext} ${file}) +## target_link_libraries(${file_without_ext} PUBLIC vtkm_filter vtkm_io InitalCondition Parameters) +## vtkm_add_target_information(${file_without_ext} +## DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS +## DEVICE_SOURCES ${file}) +## add_test(${file_without_ext}_SERIAL ${file_without_ext} -d Serial) +## add_test(${file_without_ext}_OMP ${file_without_ext} -d OpenMP) +## add_test(${file_without_ext}_TBB ${file_without_ext} -d TBB) +## add_test(${file_without_ext}_CUDA ${file_without_ext} -d Cuda) +## configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/Tests/${file_without_ext}_data.data ${CMAKE_CURRENT_BINARY_DIR}/${file_without_ext}_data.data COPYONLY) +##endforeach() + +##add_test(perf_Serial HeatDiffusionExample -d Serial -p -s 20 -i 1) +##add_test(perf_OpenMP HeatDiffusionExample -d OpenMP -p -s 20 -i 1) +##add_test(perf_TBB HeatDiffusionExample -d TBB -p -s 20 -i 1) +##add_test(perf_CUDA HeatDiffusionExample -d CUDA -p -s 20 -i 1) diff --git a/examples/heat_diffusion/Diffusion.hpp b/examples/heat_diffusion/Diffusion.hpp new file mode 100644 index 000000000..e606742a6 --- /dev/null +++ b/examples/heat_diffusion/Diffusion.hpp @@ -0,0 +1,110 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt 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. +//============================================================================ + +#ifndef HEAT_DIFFUSION_DIFFUSION_HPP +#define HEAT_DIFFUSION_DIFFUSION_HPP +#define NEUMMAN 0 +#define DERICHLET 1 + +#include +#include + +struct UpdateHeat : public vtkm::worklet::WorkletPointNeighborhood +{ + using CountingHandle = vtkm::cont::ArrayHandleCounting; + + using ControlSignature = void(CellSetIn, + FieldInNeighborhood prevstate, + FieldIn condition, + FieldIn diffuseCoeff, + FieldOut state); + + using ExecutionSignature = void(_2, _3, _4, _5); + + template + VTKM_EXEC void operator()(const NeighIn& prevstate, + const vtkm::UInt8& condition, + const vtkm::Float32& diffuseCoeff, + vtkm::Float32& state) const + { + + auto current = prevstate.Get(0, 0, 0); + + if (condition == NEUMMAN) + { + state = diffuseCoeff * current + + (1 - diffuseCoeff) * (0.25f * (prevstate.Get(-1, 0, 0) + prevstate.Get(0, -1, 0) + + prevstate.Get(0, 1, 0) + prevstate.Get(1, 0, 0))); + } + else if (condition == DERICHLET) + { + state = current; + } + } +}; +namespace vtkm { +namespace filter { +class Diffusion : public vtkm::filter::FilterDataSet { +public: +// using SupportedTypes = vtkm::List; + + + template + VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet &input, + vtkm::filter::PolicyBase policy) const { + + vtkm::cont::ArrayHandle temperature; + vtkm::cont::ArrayHandle prevTemperature; + vtkm::cont::ArrayHandle condition; + vtkm::cont::ArrayHandle diffuse; + vtkm::cont::ArrayHandleiteration; + + const vtkm::cont::DynamicCellSet &cells = input.GetCellSet(); + + input.GetPointField("temperature").GetData().CopyTo(prevTemperature); + input.GetPointField("condition").GetData().CopyTo(condition); + input.GetPointField("diffuseCoeff").GetData().CopyTo(diffuse); + input.GetPointField("iteration").GetData().CopyTo(iteration); + + vtkm::cont::ArrayHandle *ptra = &prevTemperature, *ptrb = &temperature; + //Update the temperature + for (int i = 0; i < iteration.ReadPortal().Get(0); i++) + { + this->Invoke(UpdateHeat{}, + vtkm::filter::ApplyPolicyCellSet(cells, policy, *this), + *ptra, + condition, + diffuse, + *ptrb); + std::swap(ptra, ptrb); + } + + + vtkm::cont::DataSet output; + output.CopyStructure(input); + + output.AddField(vtkm::cont::make_FieldPoint("temperature", temperature)); + output.AddField(vtkm::cont::make_FieldPoint("condition", condition)); + output.AddField(vtkm::cont::make_FieldPoint("diffuseCoeff", diffuse)); + output.AddField(vtkm::cont::make_FieldPoint("iteration", iteration)); + + return output; + } + + + template + VTKM_CONT bool DoMapField(vtkm::cont::DataSet &, + const vtkm::cont::ArrayHandle &, + const vtkm::filter::FieldMetadata &, + vtkm::filter::PolicyBase) { return false; } +}; +} +} +#endif //HEAT_DIFFUSION_DIFFUSION_HPP diff --git a/examples/heat_diffusion/InitalCondition.cpp b/examples/heat_diffusion/InitalCondition.cpp new file mode 100644 index 000000000..ff89510e9 --- /dev/null +++ b/examples/heat_diffusion/InitalCondition.cpp @@ -0,0 +1,63 @@ +#include +#include +#include + +#include "InitalCondition.h" + +#define NEUMMAN 0 +#define DERICHLET 1 + +template +VTKM_EXEC void FillInitialCondition::operator()(const CoordType &coord, + vtkm::UInt8 &boundary, + vtkm::Float32 &temperature, + vtkm::Float32 &diffusion) const { + if (coord[0] == -2.0f || coord[0] == 2.0f || coord[1] == -2.0f || coord[1] == 2.0f) { + temperature = std::get<0>(parameters.temperature); + boundary = DERICHLET; + diffusion = parameters.diffuse_coeff; + } else { + + float dx = (float) coord[0] - 0.0f; + float dy = (float) coord[1] - 0.0f; + float distance = dx * dx + dy * dy; + + float rayon = (1.25f * 1.25f); + + if (distance - rayon < 0.1f && distance - rayon > -0.1f) { + temperature = std::get<0>(parameters.temperature); + boundary = DERICHLET; + diffusion = parameters.diffuse_coeff; + } else { + + temperature = std::get<1>(parameters.temperature); + boundary = NEUMMAN; + diffusion = parameters.diffuse_coeff; + } + } +} + +vtkm::cont::DataSet initial_condition(const Parameters ¶ms) { + vtkm::Id2 dimensions(params.dimension, params.dimension); + vtkm::cont::DataSet dataSet = vtkm::cont::DataSetBuilderUniform::Create(dimensions, + vtkm::Vec2f{-2.0f, -2.0f}, + vtkm::Vec2f{ + 4.0f / (float) (dimensions[0] - 1), + 4.0f / + (float) (dimensions[1] - 1)}); + + vtkm::cont::CoordinateSystem coords = dataSet.GetCoordinateSystem("coords"); + + vtkm::cont::ArrayHandle temperature; + vtkm::cont::ArrayHandle condition; + vtkm::cont::ArrayHandle diffuse; + + vtkm::cont::Invoker invoker; + invoker(FillInitialCondition{params}, coords, condition, temperature, diffuse); + + dataSet.AddField(vtkm::cont::make_FieldPoint("temperature", temperature)); + dataSet.AddField(vtkm::cont::make_FieldPoint("condition", condition)); + dataSet.AddField(vtkm::cont::make_FieldPoint("diffuseCoeff", diffuse)); + + return dataSet; +} diff --git a/examples/heat_diffusion/InitalCondition.h b/examples/heat_diffusion/InitalCondition.h new file mode 100644 index 000000000..41af2927b --- /dev/null +++ b/examples/heat_diffusion/InitalCondition.h @@ -0,0 +1,38 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt 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. +//============================================================================ + +#ifndef HEAT_DIFFUSION_INITALCONDITION_H +#define HEAT_DIFFUSION_INITALCONDITION_H + +#include + +#include "parameters.h" +struct FillInitialCondition : public vtkm::worklet::WorkletMapField +{ + + Parameters parameters; + + explicit FillInitialCondition(Parameters params) + : parameters(std::move(params)) + { + } + + using ControlSignature = void(FieldIn, FieldOut, FieldOut, FieldOut); + + using ExecutionSignature = void(_1, _2, _3, _4); + template + VTKM_EXEC void operator()(const CoordType& coord, + vtkm::UInt8& boundary, + vtkm::Float32& temperature, + vtkm::Float32& diffusion) const; +}; +vtkm::cont::DataSet initial_condition(const Parameters& params); + +#endif //HEAT_DIFFUSION_INITALCONDITION_H diff --git a/examples/heat_diffusion/main.cxx b/examples/heat_diffusion/main.cxx new file mode 100644 index 000000000..8503b818f --- /dev/null +++ b/examples/heat_diffusion/main.cxx @@ -0,0 +1,198 @@ +//============================================================================= +// +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt 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. +// +//============================================================================= + +#ifdef ANIMATE + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#endif +#include +#include +#include + +#include + +#include "Diffusion.hpp" +#include "InitalCondition.h" +#include "parameters.h" + +#include + +#ifdef ANIMATE + +void display_function(vtkm::cont::DataSet* global_ptr_data, vtkm::cont::DataSet newData, bool dim) +{ + vtkm::filter::Diffusion filter; + + newData = filter.Execute(*global_ptr_data); + *global_ptr_data = newData; + + vtkm::rendering::CanvasRayTracer canvas(800, 800); + vtkm::rendering::MapperRayTracer mapper; + + vtkm::rendering::Scene scene; + + if (!dim) + { + auto normal = vtkm::cont::make_ArrayHandleConstant(vtkm::Vec3f_32{ 0.f, 0.f, 1.f }, + newData.GetNumberOfPoints()); + newData.AddField(vtkm::cont::make_FieldPoint("normal", normal)); + + vtkm::filter::WarpScalar warp(0.05f); + + warp.SetUseCoordinateSystemAsField(true); + warp.SetScalarFactorField("temperature"); + warp.SetFieldsToPass("temperature"); + vtkm::cont::DataSet warpped = warp.Execute(newData); + + vtkm::cont::ArrayHandle warpped_points; + warpped.GetPointField("warpscalar").GetData().CopyTo(warpped_points); + + vtkm::rendering::Actor actor(warpped.GetCellSet(), + vtkm::cont::CoordinateSystem("warp", warpped_points), + warpped.GetPointField("temperature"), + vtkm::cont::ColorTable("Cool to warm")); + + scene.AddActor(actor); + } + else + { + vtkm::rendering::Actor actor(newData.GetCellSet(), + newData.GetCoordinateSystem(), + newData.GetPointField("temperature"), + vtkm::cont::ColorTable("Cool to Warm")); + + scene.AddActor(actor); + } + + vtkm::rendering::View3D view(scene, mapper, canvas); + + if (!dim) + { + view.GetCamera().SetLookAt(vtkm::Vec3f_32{ 0.f, 0.f, 3.0f }); + view.GetCamera().Azimuth(45.0); + view.GetCamera().Elevation(40.0); + } + + view.Paint(); + vtkm::cont::ArrayHandle color_buffer = view.GetCanvas().GetColorBuffer(); + const void* colorArray = + vtkm::cont::ArrayHandleBasic(color_buffer).GetReadPointer(); + glDrawPixels( + view.GetCanvas().GetWidth(), view.GetCanvas().GetHeight(), GL_RGBA, GL_FLOAT, colorArray); + glutSwapBuffers(); +} + +vtkm::cont::DataSet* global_ptr_data = nullptr; +vtkm::cont::DataSet newData; +bool dim; + +#endif + +int main(int argc, char* argv[]) +{ + + auto opts = vtkm::cont::InitializeOptions::DefaultAnyDevice; + vtkm::cont::InitializeResult config = vtkm::cont::Initialize(argc, argv, opts); + + vtkm::cont::DataSet data; + + Parameters params; + read_params(argc, argv, params); + + + if (params.create_matrix) + { + data = initial_condition(params); + std::cout << "Matrix size: " << params.dimension << "x" << params.dimension << std::endl; + std::cout << "Temperature outside: " << std::get<0>(params.temperature) << std::endl; + std::cout << "Temperature inside: " << std::get<1>(params.temperature) << std::endl; + std::cout << "Diffusion coefficient: " << params.diffuse_coeff << std::endl; + vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(config.Device); + } + else + { + vtkm::io::VTKDataSetReader reader(params.filename); + data = reader.ReadDataSet(); + } + +#ifndef ANIMATE + if (params.rendering_enable) + { + std::cout << "Animation is not available : performance is running " << std::endl; + params.rendering_enable = false; + } + +#endif + + if (params.rendering_enable) + { +#ifdef ANIMATE + global_ptr_data = &data; + std::vector ite; + ite.push_back(10); + + global_ptr_data->AddField( + vtkm::cont::make_FieldPoint("iteration", vtkm::cont::make_ArrayHandle(ite))); + + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); + glutInitWindowSize(800, 800); + glutCreateWindow("VTK-m Heat Diffusion"); + + GLenum err = glewInit(); + if (GLEW_OK != err) + { + std::cout << "glewInit failed\n"; + } + dim = params.twoD; + glutDisplayFunc([] { display_function(global_ptr_data, newData, dim); }); + + glutIdleFunc([]() { glutPostRedisplay(); }); + + glutMainLoop(); +#endif + } + else + { + vtkm::filter::Diffusion filter; + std::vector ite; + ite.push_back(params.iteration); + + data.AddField(vtkm::cont::make_FieldPoint("iteration", vtkm::cont::make_ArrayHandle(ite))); + vtkm::Float32 end, start; + vtkm::cont::Timer gTimer; + gTimer.Start(); + std::cout << "Number of iteration: " << params.iteration << std::endl; + + start = static_cast(gTimer.GetElapsedTime()); + data = filter.Execute(data); + end = static_cast(gTimer.GetElapsedTime()); + + std::cout << std::endl << "Execution time = " << end - start << std::endl; + double flop = ((float)params.dimension * (float)params.dimension * 8.f / (end - start)) * + (float)params.iteration; + std::cout << "MFlop = " << flop / 10e6 << std::endl; + } + + + return 0; +} diff --git a/examples/heat_diffusion/parameters.cpp b/examples/heat_diffusion/parameters.cpp new file mode 100644 index 000000000..40e599b3e --- /dev/null +++ b/examples/heat_diffusion/parameters.cpp @@ -0,0 +1,79 @@ +#include "parameters.h" + +#include +#include + +void display_param() +{ + std::cout << "\n\nParameters: " << std::endl; + std::cout << "\t\t-h or --help\t\t\t\t\t\tHelp\n" << std::endl; + std::cout << "\t\t-d [DEVICE]\t\t\tAny, Serial, OpenMP, TBB or Cuda\n" << std::endl; + std::cout << "\t\t-f [FILENAME]\t\t\tName of the file you want to treat\n" << std::endl; + std::cout << "\t\t-p \t\t\t\tEnable performance testing\n" << std::endl; + std::cout << "\t\t-t [TEMP_OUTSIDE] [TEMP_INSIDE]\tChange the temperature of the " + "dataset.\n\t\t\t\t\t\t\t\tDefault tempratures are 100 and 10\n" + << std::endl; + std::cout << "\t\t-s [DIMENSION]\t\t\tChange the size of the dataset.\n\t\t\t\t\t\t\t\tDefault " + "size is 2000*2000\n" + << std::endl; + std::cout << "\t\t-i [NB_ITERATION]\t\tChange the number of iteration for the " + "filter.\n\t\t\t\t\t\t\t\tDefault number of iteration is 100\n" + << std::endl; + std::cout << "\t\t-c [DIFF_COEFF]\t\t\tChange the diffusion coefficient of the dataset " + ".\n\t\t\t\t\t\t\t\tDefault coefficient of diffusion is 0.6\n" + << std::endl; + std::cout << "\t\t-2d\t\t\t\t 2D rendering, default is 3D" << std::endl; +} + +void read_params(int argc, char** argv, Parameters& params) +{ + int i = 0; + int tmpI; + + while (i < argc - 1) + { + ++i; + if (!strcmp("-h", argv[i]) || !strcmp("--help", argv[i])) + { + display_param(); + exit(EXIT_FAILURE); + } + if (!strcmp("-p", argv[i])) + { + params.rendering_enable = false; + continue; + } + if (!strcmp("-t", argv[i])) + { + std::get<0>(params.temperature) = strtof(argv[++i], nullptr); + std::get<1>(params.temperature) = strtof(argv[++i], nullptr); + continue; + } + if (!strcmp("-s", argv[i])) + { + tmpI = std::stoi(argv[i + 1], nullptr, 10); + if (tmpI > 9) + { + params.dimension = tmpI; + i++; + } + else + { + display_param(); + exit(EXIT_FAILURE); + } + } + if (!strcmp("-c", argv[i])) + { + params.diffuse_coeff = strtof(argv[++i], nullptr); + } + if (!strcmp("-i", argv[i])) + { + params.iteration = std::stoi(argv[++i], nullptr, 10); + } + if (!strcmp("-2d", argv[i])) + { + params.twoD = true; + } + } +} diff --git a/examples/heat_diffusion/parameters.h b/examples/heat_diffusion/parameters.h new file mode 100644 index 000000000..40c643416 --- /dev/null +++ b/examples/heat_diffusion/parameters.h @@ -0,0 +1,33 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt 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. +//============================================================================ + +#ifndef PARAMETERS_H +#define PARAMETERS_H + +#include +#include + +struct Parameters +{ + std::string filename; + std::tuple temperature = std::make_tuple(100.f, 10.f); + int dimension = 2000; + int iteration = 1000; + float diffuse_coeff = 0.6f; + bool rendering_enable = true; + bool create_matrix = true; + bool twoD = false; +}; + +void display_param(); + +void read_params(int argc, char** argv, Parameters& params); + +#endif