diff --git a/.gitattributes b/.gitattributes index c9d57724b..278350448 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,6 +8,7 @@ data/** filter=lfs diff=lfs merge=lfs -text /**/data/** filter=lfs diff=lfs merge=lfs -text +/**/images/** filter=lfs diff=lfs merge=lfs -text *.cmake whitespace=tab-in-indent *.md whitespace=tab-in-indent whitespace=-blank-at-eol conflict-marker-size=79 -whitespace diff --git a/CMake/FindSphinx.cmake b/CMake/FindSphinx.cmake new file mode 100644 index 000000000..57a54a1d2 --- /dev/null +++ b/CMake/FindSphinx.cmake @@ -0,0 +1,395 @@ +# This find module originally created by Jeroen Koekkoek. +# Copyright (c) 2023, Jeroen Koekkoek +# +# This file is covered by a BSD 3-Clause License. +# See https://github.com/k0ekk0ek/cmake-sphinx/blob/master/LICENSE for details. + +include(FindPackageHandleStandardArgs) + +macro(_Sphinx_find_executable _exe) + string(TOUPPER "${_exe}" _uc) + # sphinx-(build|quickstart)-3 x.x.x + # FIXME: This works on Fedora (and probably most other UNIX like targets). + # Windows targets and PIP installs might need some work. + find_program( + SPHINX_${_uc}_EXECUTABLE + NAMES "sphinx-${_exe}-3" "sphinx-${_exe}" "sphinx-${_exe}.exe") + mark_as_advanced(SPHINX_${_uc}_EXECUTABLE) + + if(SPHINX_${_uc}_EXECUTABLE) + execute_process( + COMMAND "${SPHINX_${_uc}_EXECUTABLE}" --version + RESULT_VARIABLE _result + OUTPUT_VARIABLE _output + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(_result EQUAL 0 AND _output MATCHES " v?([0-9]+\\.[0-9]+\\.[0-9]+)$") + set(SPHINX_${_uc}_VERSION "${CMAKE_MATCH_1}") + endif() + + if(NOT TARGET Sphinx::${_exe}) + add_executable(Sphinx::${_exe} IMPORTED GLOBAL) + set_target_properties(Sphinx::${_exe} PROPERTIES + IMPORTED_LOCATION "${SPHINX_${_uc}_EXECUTABLE}") + endif() + set(Sphinx_${_exe}_FOUND TRUE) + else() + set(Sphinx_${_exe}_FOUND FALSE) + endif() + unset(_uc) +endmacro() + +macro(_Sphinx_find_module _name _module) + string(TOUPPER "${_name}" _Sphinx_uc) + if(SPHINX_PYTHON_EXECUTABLE) + execute_process( + COMMAND ${SPHINX_PYTHON_EXECUTABLE} -m ${_module} --version + RESULT_VARIABLE _result + OUTPUT_VARIABLE _output + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) + if(_result EQUAL 0) + if(_output MATCHES " v?([0-9]+\\.[0-9]+\\.[0-9]+)$") + set(SPHINX_${_Sphinx_uc}_VERSION "${CMAKE_MATCH_1}") + endif() + + if(NOT TARGET Sphinx::${_name}) + set(SPHINX_${_Sphinx_uc}_EXECUTABLE "${SPHINX_PYTHON_EXECUTABLE} -m ${_module}") + add_executable(Sphinx::${_name} IMPORTED GLOBAL) + set_target_properties(Sphinx::${_name} PROPERTIES + IMPORTED_LOCATION "${SPHINX_PYTHON_EXECUTABLE}") + endif() + set(Sphinx_${_name}_ARGS -m ${_module}) + set(Sphinx_${_name}_FOUND TRUE) + else() + set(Sphinx_${_name}_FOUND FALSE) + endif() + else() + set(Sphinx_${_name}_FOUND FALSE) + endif() + unset(_Sphinx_uc) +endmacro() + +macro(_Sphinx_find_extension _ext) + if(SPHINX_PYTHON_EXECUTABLE) + execute_process( + COMMAND ${SPHINX_PYTHON_EXECUTABLE} -c "import ${_ext}" + RESULT_VARIABLE _result) + if(_result EQUAL 0) + set(Sphinx_${_ext}_FOUND TRUE) + else() + set(Sphinx_${_ext}_FOUND FALSE) + endif() + endif() +endmacro() + +# +# Find sphinx-build and sphinx-quickstart. +# + +# Find sphinx-build shim. +_Sphinx_find_executable(build) + +if(SPHINX_BUILD_EXECUTABLE) + # Find sphinx-quickstart shim. + _Sphinx_find_executable(quickstart) + + # Locate Python executable + if(CMAKE_HOST_WIN32) + # script-build on Windows located under (when PIP is used): + # C:/Program Files/PythonXX/Scripts + # C:/Users/username/AppData/Roaming/Python/PythonXX/Sripts + # + # Python modules are installed under: + # C:/Program Files/PythonXX/Lib + # C:/Users/username/AppData/Roaming/Python/PythonXX/site-packages + # + # To verify a given module is installed, use the Python base directory + # and test if either Lib/module.py or site-packages/module.py exists. + get_filename_component(_Sphinx_directory "${SPHINX_BUILD_EXECUTABLE}" DIRECTORY) + get_filename_component(_Sphinx_directory "${_Sphinx_directory}" DIRECTORY) + if(EXISTS "${_Sphinx_directory}/python.exe") + set(SPHINX_PYTHON_EXECUTABLE "${_Sphinx_directory}/python.exe") + endif() + unset(_Sphinx_directory) + else() + file(READ "${SPHINX_BUILD_EXECUTABLE}" _Sphinx_script) + if(_Sphinx_script MATCHES "^#!([^\n]+)") + string(STRIP "${CMAKE_MATCH_1}" _Sphinx_shebang) + if(EXISTS "${_Sphinx_shebang}") + set(SPHINX_PYTHON_EXECUTABLE "${_Sphinx_shebang}") + endif() + endif() + unset(_Sphinx_script) + unset(_Sphinx_shebang) + endif() +endif() + +if(NOT SPHINX_PYTHON_EXECUTABLE) + # Python executable cannot be extracted from shim shebang or path if e.g. + # virtual environments are used, fallback to find package. Assume the + # correct installation is found, the setup is probably broken in more ways + # than one otherwise. + find_package(Python3 QUIET COMPONENTS Interpreter) + if(TARGET Python3::Interpreter) + set(SPHINX_PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) + # Revert to "python -m sphinx" if shim cannot be found. + if(NOT SPHINX_BUILD_EXECUTABLE) + _Sphinx_find_module(build sphinx) + _Sphinx_find_module(quickstart sphinx.cmd.quickstart) + endif() + endif() +endif() + +# +# Verify components are available. +# +if(SPHINX_BUILD_VERSION) + # Breathe is required for Exhale + if("exhale" IN_LIST Sphinx_FIND_COMPONENTS AND NOT + "breathe" IN_LIST Sphinx_FIND_COMPONENTS) + list(APPEND Sphinx_FIND_COMPONENTS "breathe") + endif() + + foreach(_Sphinx_component IN LISTS Sphinx_FIND_COMPONENTS) + if(_Sphinx_component STREQUAL "build") + # Do nothing, sphinx-build is always required. + continue() + elseif(_Sphinx_component STREQUAL "quickstart") + # Do nothing, sphinx-quickstart is optional, but looked up by default. + continue() + endif() + _Sphinx_find_extension(${_Sphinx_component}) + endforeach() + unset(_Sphinx_component) + + # + # Verify both executables are part of the Sphinx distribution. + # + if(SPHINX_QUICKSTART_VERSION AND NOT SPHINX_BUILD_VERSION STREQUAL SPHINX_QUICKSTART_VERSION) + message(FATAL_ERROR "Versions for sphinx-build (${SPHINX_BUILD_VERSION}) " + "and sphinx-quickstart (${SPHINX_QUICKSTART_VERSION}) " + "do not match") + endif() +endif() + +find_package_handle_standard_args( + Sphinx + VERSION_VAR SPHINX_BUILD_VERSION + REQUIRED_VARS SPHINX_BUILD_EXECUTABLE SPHINX_BUILD_VERSION + HANDLE_COMPONENTS) + +# Generate a conf.py template file using sphinx-quickstart. +# +# sphinx-quickstart allows for quiet operation and a lot of settings can be +# specified as command line arguments, therefore its not required to parse the +# generated conf.py. +function(_Sphinx_generate_confpy _target _cachedir) + if(NOT TARGET Sphinx::quickstart) + message(FATAL_ERROR "sphinx-quickstart is not available, needed by" + "sphinx_add_docs for target ${_target}") + endif() + + if(NOT DEFINED SPHINX_PROJECT) + set(SPHINX_PROJECT ${PROJECT_NAME}) + endif() + + if(NOT DEFINED SPHINX_AUTHOR) + set(SPHINX_AUTHOR "${SPHINX_PROJECT} committers") + endif() + + if(NOT DEFINED SPHINX_COPYRIGHT) + string(TIMESTAMP "%Y, ${SPHINX_AUTHOR}" SPHINX_COPYRIGHT) + endif() + + if(NOT DEFINED SPHINX_VERSION) + set(SPHINX_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") + endif() + + if(NOT DEFINED SPHINX_RELEASE) + set(SPHINX_RELEASE "${PROJECT_VERSION}") + endif() + + if(NOT DEFINED SPHINX_LANGUAGE) + set(SPHINX_LANGUAGE "en") + endif() + + if(NOT DEFINED SPHINX_MASTER) + set(SPHINX_MASTER "index") + endif() + + set(_known_exts autodoc doctest intersphinx todo coverage imgmath mathjax + ifconfig viewcode githubpages) + + if(DEFINED SPHINX_EXTENSIONS) + foreach(_ext ${SPHINX_EXTENSIONS}) + set(_is_known_ext FALSE) + foreach(_known_ext ${_known_exsts}) + if(_ext STREQUAL _known_ext) + set(_opts "${opts} --ext-${_ext}") + set(_is_known_ext TRUE) + break() + endif() + endforeach() + if(NOT _is_known_ext) + if(_exts) + set(_exts "${_exts},${_ext}") + else() + set(_exts "${_ext}") + endif() + endif() + endforeach() + endif() + + if(_exts) + set(_exts "--extensions=${_exts}") + endif() + + set(_templatedir "${CMAKE_CURRENT_BINARY_DIR}/${_target}.template") + file(MAKE_DIRECTORY "${_templatedir}") + string(REPLACE " " ";" _Sphinx_executable ${SPHINX_QUICKSTART_EXECUTABLE}) + execute_process( + COMMAND ${_Sphinx_executable} + -q --no-makefile --no-batchfile + -p "${SPHINX_PROJECT}" + -a "${SPHINX_AUTHOR}" + -v "${SPHINX_VERSION}" + -r "${SPHINX_RELEASE}" + -l "${SPHINX_LANGUAGE}" + --master "${SPHINX_MASTER}" + ${_opts} ${_exts} "${_templatedir}" + RESULT_VARIABLE _result + OUTPUT_QUIET) + unset(_Sphinx_executable) + + if(_result EQUAL 0 AND EXISTS "${_templatedir}/conf.py") + file(COPY "${_templatedir}/conf.py" DESTINATION "${_cachedir}") + endif() + + file(REMOVE_RECURSE "${_templatedir}") + + if(NOT _result EQUAL 0 OR NOT EXISTS "${_cachedir}/conf.py") + message(FATAL_ERROR "Sphinx configuration file not generated for " + "target ${_target}") + endif() +endfunction() + +function(sphinx_add_docs _target) + set(_opts) + set(_single_opts BUILDER OUTPUT_DIRECTORY SOURCE_DIRECTORY) + set(_multi_opts BREATHE_PROJECTS) + cmake_parse_arguments(_args "${_opts}" "${_single_opts}" "${_multi_opts}" ${ARGN}) + + unset(SPHINX_BREATHE_PROJECTS) + + if(NOT _args_BUILDER) + message(FATAL_ERROR "Sphinx builder not specified for target ${_target}") + elseif(NOT _args_SOURCE_DIRECTORY) + message(FATAL_ERROR "Sphinx source directory not specified for target ${_target}") + else() + if(NOT IS_ABSOLUTE "${_args_SOURCE_DIRECTORY}") + get_filename_component(_sourcedir "${_args_SOURCE_DIRECTORY}" ABSOLUTE) + else() + set(_sourcedir "${_args_SOURCE_DIRECTORY}") + endif() + if(NOT IS_DIRECTORY "${_sourcedir}") + message(FATAL_ERROR "Sphinx source directory '${_sourcedir}' for" + "target ${_target} does not exist") + endif() + endif() + + set(_builder "${_args_BUILDER}") + if(_args_OUTPUT_DIRECTORY) + set(_outputdir "${_args_OUTPUT_DIRECTORY}") + else() + set(_outputdir "${CMAKE_CURRENT_BINARY_DIR}/${_target}") + endif() + + + if(_args_BREATHE_PROJECTS) + if(NOT Sphinx_breathe_FOUND) + message(FATAL_ERROR "Sphinx extension 'breathe' is not available. Needed" + "by sphinx_add_docs for target ${_target}") + endif() + list(APPEND SPHINX_EXTENSIONS breathe) + + foreach(_doxygen_target ${_args_BREATHE_PROJECTS}) + if(TARGET ${_doxygen_target}) + list(APPEND _depends ${_doxygen_target}) + + # Doxygen targets are supported. Verify that a Doxyfile exists. + get_target_property(_dir ${_doxygen_target} BINARY_DIR) + set(_doxyfile "${_dir}/Doxyfile.${_doxygen_target}") + if(NOT EXISTS "${_doxyfile}") + message(FATAL_ERROR "Target ${_doxygen_target} is not a Doxygen" + "target, needed by sphinx_add_docs for target" + "${_target}") + endif() + + # Read the Doxyfile, verify XML generation is enabled and retrieve the + # output directory. + file(READ "${_doxyfile}" _contents) + if(NOT _contents MATCHES "GENERATE_XML *= *YES") + message(FATAL_ERROR "Doxygen target ${_doxygen_target} does not" + "generate XML, needed by sphinx_add_docs for" + "target ${_target}") + elseif(_contents MATCHES "OUTPUT_DIRECTORY *= *([^ ][^\n]*)") + string(STRIP "${CMAKE_MATCH_1}" _dir) + set(_name "${_doxygen_target}") + set(_dir "${_dir}/xml") + else() + message(FATAL_ERROR "Cannot parse Doxyfile generated by Doxygen" + "target ${_doxygen_target}, needed by" + "sphinx_add_docs for target ${_target}") + endif() + elseif(_doxygen_target MATCHES "([^: ]+) *: *(.*)") + set(_name "${CMAKE_MATCH_1}") + string(STRIP "${CMAKE_MATCH_2}" _dir) + endif() + + if(_name AND _dir) + if(_breathe_projects) + set(_breathe_projects "${_breathe_projects}, \"${_name}\": \"${_dir}\"") + else() + set(_breathe_projects "\"${_name}\": \"${_dir}\"") + endif() + if(NOT _breathe_default_project) + set(_breathe_default_project "${_name}") + endif() + endif() + endforeach() + endif() + + set(_cachedir "${CMAKE_CURRENT_BINARY_DIR}/${_target}.cache") + file(MAKE_DIRECTORY "${_cachedir}") + if(EXISTS "${_sourcedir}/_static") + file(COPY "${_sourcedir}/_static" DESTINATION "${_cachedir}") + endif() + if(EXISTS "${_sourcedir}/_templates") + file(COPY "${_sourcedir}/_templates" DESTINATION "${_cachedir}") + endif() + + if(EXISTS "${_sourcedir}/conf.py") + configure_file("${_sourcedir}/conf.py" "${_cachedir}/conf.py" @ONLY) + else() + _Sphinx_generate_confpy(${_target} "${_cachedir}") + endif() + + if(_breathe_projects) + file(APPEND "${_cachedir}/conf.py" + "\nbreathe_projects = { ${_breathe_projects} }" + "\nbreathe_default_project = '${_breathe_default_project}'") + endif() + + string(REPLACE " " ";" _Sphinx_executable ${SPHINX_BUILD_EXECUTABLE}) + add_custom_target( + ${_target} ALL + COMMAND ${_Sphinx_executable} + -b ${_builder} + -d "${CMAKE_CURRENT_BINARY_DIR}/${_target}.cache/_doctrees" + -c "${CMAKE_CURRENT_BINARY_DIR}/${_target}.cache" + "${_sourcedir}" + "${_outputdir}" + COMMENT "Building ${_target} Sphinx document" + DEPENDS ${_depends}) + unset(_Sphinx_executable) +endfunction() diff --git a/CMake/VTKmModules.cmake b/CMake/VTKmModules.cmake index 6bf7cc69a..bff5811d1 100644 --- a/CMake/VTKmModules.cmake +++ b/CMake/VTKmModules.cmake @@ -221,7 +221,7 @@ function(_vtkm_module_parse_module_file module_file name_var) # Parse module file as arguments to a function set(options NO_TESTING) - set(oneValueArgs NAME) + set(oneValueArgs NAME TESTING_DIR) set(multiValueArgs GROUPS DEPENDS PRIVATE_DEPENDS OPTIONAL_DEPENDS TEST_DEPENDS TEST_OPTIONAL_DEPENDS) cmake_parse_arguments(_vtkm_module @@ -592,10 +592,16 @@ function(_vtkm_modules_try_build_tests target_module) endif() endforeach() + vtkm_module_get_property(testing_subdir ${target_module} TESTING_DIR) + if(NOT testing_subdir) + set(testing_subdir "testing") + endif() + vtkm_module_get_property(src_directory ${target_module} DIRECTORY) file(RELATIVE_PATH rel_directory "${VTKm_SOURCE_DIR}" "${src_directory}") set(vtkm_module_current_test ${target_module}) - add_subdirectory("${src_directory}/testing" "${VTKm_BINARY_DIR}/${rel_directory}/testing") + add_subdirectory("${src_directory}/${testing_subdir}" + "${VTKm_BINARY_DIR}/${rel_directory}/${testing_subdir}") set(vtkm_module_current_test) endfunction() diff --git a/CMake/doxyfile.in b/CMake/doxyfile.in index b2e890922..d8f8f1b4e 100644 --- a/CMake/doxyfile.in +++ b/CMake/doxyfile.in @@ -294,7 +294,7 @@ MAN_LINKS = NO # configuration options related to the XML output #--------------------------------------------------------------------------- -GENERATE_XML = NO +GENERATE_XML = YES XML_OUTPUT = xml diff --git a/CMakeLists.txt b/CMakeLists.txt index d0d76b79a..51bd48faa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,6 +119,14 @@ mark_as_advanced(VTKm_ENABLE_TESTING_LIBRARY) cmake_dependent_option(VTKm_ENABLE_ANARI "Enable ANARI interop support" OFF "VTKm_ENABLE_RENDERING" OFF) +# If you are building Doxygen, you also have the option to build the User's Guide with Sphinx +cmake_dependent_option(VTKm_ENABLE_USERS_GUIDE + "Build User's Guide with Sphinx" + ON + "VTKm_ENABLE_DOCUMENTATION" + OFF + ) + # We may want to make finer controls on whether libraries/modules get built. # VTK uses the concept of groups for its modules vtkm_option(VTKm_BUILD_ALL_LIBRARIES @@ -306,28 +314,6 @@ include(CheckTypeSize) check_type_size(long VTKm_SIZE_LONG BUILTIN_TYPES_ONLY) check_type_size("long long" VTKm_SIZE_LONG_LONG BUILTIN_TYPES_ONLY) -#----------------------------------------------------------------------------- -# Add subdirectories -add_subdirectory(vtkmstd) - -#----------------------------------------------------------------------------- -# Process modules -vtkm_modules_scan( - SCAN_DIRECTORIES vtkm benchmarking - PROVIDED_MODULES all_modules - ) -vtkm_modules_build( - PROVIDED_MODULES ${all_modules} - WANT_BY_DEFAULT ${VTKm_BUILD_ALL_LIBRARIES} - WANT_BY_DEFAULT_REASON "VTKm_BUILD_ALL_LIBRARIES is `${VTKm_BUILD_ALL_LIBRARIES}`" - ) - -#----------------------------------------------------------------------------- -# Build documentation -if (VTKm_ENABLE_DOCUMENTATION) - include(VTKmBuildDocumentation) -endif() - #----------------------------------------------------------------------------- # Ready files for find_package include(CMakePackageConfigHelpers) @@ -349,6 +335,28 @@ write_basic_package_version_file( VERSION ${VTKm_VERSION} COMPATIBILITY ExactVersion ) +#----------------------------------------------------------------------------- +# Add subdirectories +add_subdirectory(vtkmstd) + +#----------------------------------------------------------------------------- +# Process modules +vtkm_modules_scan( + SCAN_DIRECTORIES vtkm benchmarking docs + PROVIDED_MODULES all_modules + ) +vtkm_modules_build( + PROVIDED_MODULES ${all_modules} + WANT_BY_DEFAULT ${VTKm_BUILD_ALL_LIBRARIES} + WANT_BY_DEFAULT_REASON "VTKm_BUILD_ALL_LIBRARIES is `${VTKm_BUILD_ALL_LIBRARIES}`" + ) + +#----------------------------------------------------------------------------- +# Build documentation +if (VTKm_ENABLE_DOCUMENTATION) + include(VTKmBuildDocumentation) +endif() + #----------------------------------------------------------------------------- # Create makefile/package files for projects not using CMake diff --git a/LICENSE.txt b/LICENSE.txt index 0fbe20498..2675cc7e5 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -32,7 +32,7 @@ met: 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 +"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 AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, @@ -48,6 +48,7 @@ The following files and directories come from third parties. Check the contents of these for details on the specifics of their respective licenses. - - - - - - - - - - - - - - - - - - - - - - - - do not remove this line +CMake/FindSphinx.cmake CMake/FindTBB.cmake Utilities vtkm/cont/tbb/internal/parallel_sort.h diff --git a/docs/Modules.md b/docs/Modules.md index ae1dcf593..9bf785e10 100644 --- a/docs/Modules.md +++ b/docs/Modules.md @@ -102,6 +102,8 @@ arguments for that option. The following options can be defined in a named `testing`, which will build any necessary testing executables and add ctest tests. If this option is given, no tests are added. (Note, modules generally should have tests.) + * `TESTING_DIR`: Specify the name of the testing subdirectory. If not + provided, `testing` is used. A `vtkm.module` file may also have comments. Everything between a `#` and the end of the line will be ignored. diff --git a/docs/changelog/users-guide.md b/docs/changelog/users-guide.md new file mode 100644 index 000000000..d7b2fdbc2 --- /dev/null +++ b/docs/changelog/users-guide.md @@ -0,0 +1,15 @@ +# Added VTK-m's user guide into the source code + +The VTK-m User's Guide is being transitioned into the VTK-m source code. +The implementation of the guide is being converted from LaTeX to +ReStructuredText text to be built by Sphinx. There are several goals of +this change. + +1. Integrate the documentation into the source code better to better + keep the code up to date. +2. Move the documentation over to Sphinx so that it can be posted online + and be more easily linked. +3. Incoporate Doxygen into the guide to keep the documentation + consistent. +4. Build the user guide examples as part of the VTK-m CI to catch + compatibility changes quickly. diff --git a/docs/users-guide/CMakeLists.txt b/docs/users-guide/CMakeLists.txt new file mode 100644 index 000000000..0bfa47578 --- /dev/null +++ b/docs/users-guide/CMakeLists.txt @@ -0,0 +1,46 @@ +##============================================================================ +## 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. +##============================================================================ + +# This module is always loaded so that the example code is compiled as part +# of the test build. However, we only really want to build the document if +# VTKm_ENABLE_USERS_GUIDE is set. +if (NOT VTKm_ENABLE_USERS_GUIDE) + return() +endif() + +set(sphinx_docs + index.rst + ) + +find_package(Sphinx) +if (NOT Sphinx_FOUND) + message(FATAL_ERROR + "Could not find Sphinx to build User's Guide. If you want to compile Doxygen without the User's Guide, turn off VTKm_ENABLE_USERS_GUIDE.") +endif() + +# Configuration used in conf.py. +set(doxygen_xml_output_dir "${VTKm_BINARY_DIR}/docs/doxygen/xml") +set(example_directory "${CMAKE_CURRENT_SOURCE_DIR}/examples") + +sphinx_add_docs(VTKmUsersGuideHTML + BUILDER html + SOURCE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html + CONF_FILE conf.py + ) +add_dependencies(VTKmUsersGuideHTML VTKmDoxygenDocs) + +sphinx_add_docs(VTKmUsersGuideLaTeX + BUILDER latex + SOURCE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/latex + CONF_FILE conf.py + ) +add_dependencies(VTKmUsersGuideLaTeX VTKmDoxygenDocs) diff --git a/docs/users-guide/README.md b/docs/users-guide/README.md new file mode 100644 index 000000000..6941cfc0e --- /dev/null +++ b/docs/users-guide/README.md @@ -0,0 +1,278 @@ +# VTK-m User's Guide Source + +This directory contains the source for building the VTK-m User's Guide. The +document is written for the [Sphinx](https://www.sphinx-doc.org/en/master/) +document generator. + + +## Building the documentation + +To build the document, you will need the following installed on your +system. + + * [Doxygen] - Processes source code to pull out documentation. + * [Sphinx] - Processes [reStructuredText] to build HTML and LaTeX + formatted documents. + * [RTD Theme] - We use the Sphinx Read the Docs theme for formatting the + generated HTML. The build will fail without this installed. + * [Sphinx CMake Domain] Sphinx does not support documenting CMake + elements out of the box. This extension provides that support. + * [Breathe] - Forms a bridge betweein Doxygen and Sphinx to allow the + Sphinx reStructuredTest to include documentation extracted by Doxygen. + +To enable document generation, you first must turn on the CMake option +`VTKm_ENABLE_DOCUMENTATION`, which turns on the Doxygen documentation. With +that on, you can then turn on the `VTKm_ENABLE_USERS_GUIDE` CMake option. + +The documentation will be built into HTML format in the +`docs/users-guide/html` directory in the build. It will also build LaTeX +files in `docs/users-guide/latex`. It will come with a `Makefile` that can +be used to generate a pdf form (given the proper LaTeX compiler). + + +## Features of the documents + +The VTK-m User's Guide is built as a standard [Sphinx] project. However, +there are some features that writers should be aware of. + +### Writing credit + +Kenneth Moreland is the main author of this document. If you have made a +contribution, you can credit yourself in the `Contributors` section of +[acknowledgements.rst]. + +### Provided substitutions + +The Sphinx configuration provides some convenient substitutions that can be +used throughout the document. + + * `|VTKm|` This should be used whenever `VTK-m` is referenced. The + substitution contains formatting for the word. + +### Expanded directives + +This reStructuredText is build with some extended directives. + +#### Info boxes + +Two new "admonition" boxes are supported: `didyouknow` and `commonerrors`. +It is encouraged to use these boxes to highlight interesting features or +common gotchas. These are use like other tip boxes. + +``` restructuredtext +.. didyouknow:: + In this guide we periodically use these **Did you know?** boxes to + provide additional information related to the topic at hand. + +.. commonerrors:: + **Common Errors** blocks are used to highlight some of the common + problems or complications you might encounter when dealing with the + topic of discussion. +``` + +### Section references + +It is desired for the VTK-m User's Guide to be available both online as web +pages and as a self-contained document (e.g. pdf). One issue is that +traditional paper documents work best with numbered references to parts, +chapters, and sections whereas html documents prefer descriptive links. + +To service both, this document has extensions to automatically provide +references to document parts. Three roles are created: `:partref:`, +`:chapref:`, and `:secref:` to create cross references to parts, chapters, +and sections, respectively. They each take a label, and Sphinx is +configured with numfig and autosection labels. These labels take the form +: where <file> is the name of the file containing the section +(without the `.rst` extension) and <title> is the full name of the section. + +Here are examples of cross references. + +``` restructuredtext +:partref:`part-getting-started:Getting Started` + +:chapref:`introduction:Introduction` + +:secref:`introduction:How to Use This Guide` +``` + +### Example code + +The VTK-m User's Guide has numerous code examples. These code examples are +pulled from source files that are compiled and run as part of VTK-m's +regression tests. Although these "tests" are not meant to be thorough +regression tests like the others, they ensure that the documentation stays +up to date and correct. + +Examples are added to the `examples` directory more or less like any other +unit test in VTK-m (except by convention we start the name with +`GuideExample`). Each of these files can then be scanned to find excerpts +to include as an example in the guide. + +#### Marking examples in the code + +A simple text scanner goes through the example code looking for lines +containing a comment starting with 4 slashes, `////`. Any such line will +not be included in the example. + +An example can be started with `//// BEGIN-EXAMPLE` and ended with +`//// END-EXAMPLE`. Each of these must be given the name of the example. + +``` cpp + //// + //// BEGIN-EXAMPLE EquilateralTriangle + //// + vtkm::Vec<vtkm::Vec2f_32, 3> equilateralTriangle = { { 0.0f, 0.0f }, + { 1.0f, 0.0f }, + { 0.5f, 0.8660254f } }; + //// + //// END-EXAMPLE EquilateralTriangle + //// +``` + +#### Loading examples in the documentation + +An example can be loaded into the VTK-m User's Guide using the extended +reStructuredText `load-example` directive. The directive takes the name of +the example as its argument. `load-example` should also be given the +`:file:` and `:caption:` options. + +``` restructuredtext +.. load-example:: EquilateralTriangle + :file: GuideExampleCoreDataTypes.cxx + :caption: Defining a triangle in the plane. +``` + +The following options are supported. + + * `:file:` The filename of the file containing the named example. The + filename is relative to the `examples` directory. + * `:caption:` The caption used for the example. + * `:nolinenos:` Turn off line numbering. By default, line numbers are + shown, but they are suppressed with this option. + +#### Referencing examples + +The example is registered as a `code-block` the named registered as the +example named prepended with `ex:`. This name can then be referenced with +the `:ref:` and `:numref:` roles as with figures, sections, and other cross +references. + +The `:numref:` role is particularly useful for referencing each example. +Using `:numref:` with just the name will be replaced with a link titled +"Example #" with "#" being the number of the example. + +``` restructuredtext +:numref:`ex:EquilateralTriangle` shows how the :class:`Vec` class can be used to +store several points in the same structure. +``` + +The `:numref:` role also supports custom text with number substitution as +described in the [Sphinx +documentation](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-numref) + +``` restructuredtext +:numref:`Example %s representes an equilateral triangle<ex:EquilateralTriangle>` +using the :class:`Vec` class. +``` + +#### Pausing and resuming capture + +Sometimes it is useful to insert code in the compiled test that is not +included as part of the example. This is useful to, for example, insert a +check for values, which can verify that the code is working correctly but +is not necessary for the example. + +When a `//// PAUSE-EXAMPLE` is inserted into the code, the following lines +will not be captured until the line `//// RESUME-EXAMPLE` is encountered. + +``` cpp + range.Include(2.0); // range is now [0.5 .. 2] + bool b5 = range.Contains(0.5); // b3 is true + bool b6 = range.Contains(0.6); // b4 is true + + range.Include(vtkm::Range(-1, 1)); // range is now [-1 .. 2] + //// PAUSE-EXAMPLE + VTKM_TEST_ASSERT(test_equal(range, vtkm::Range(-1, 2)), "Bad range"); + //// RESUME-EXAMPLE +``` + +#### Referencing a specific line + +You apply a label to a specific line in the code by adding a `//// LABEL` +comment right before it. The `LABEL` needs a text string used to reference +the line. + +``` cpp +//// +//// BEGIN-EXAMPLE VecCExample +//// +//// LABEL index-to-ijk +VTKM_EXEC vtkm::VecCConst<vtkm::IdComponent> HexagonIndexToIJK(vtkm::IdComponent index) +{ + static const vtkm::IdComponent HexagonIndexToIJKTable[8][3] = { + { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 }, + { 0, 0, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 0, 1, 1 } + }; + + return vtkm::make_VecC(HexagonIndexToIJKTable[index], 3); +} + +//// LABEL ijk-to-index +VTKM_EXEC vtkm::IdComponent HexagonIJKToIndex(vtkm::VecCConst<vtkm::IdComponent> ijk) +{ + static const vtkm::IdComponent HexagonIJKToIndexTable[2][2][2] = { + { + // i=0 + { 0, 4 }, // j=0 + { 3, 7 }, // j=1 + }, + { + // i=1 + { 1, 5 }, // j=0 + { 2, 6 }, // j=1 + } + }; + + return HexagonIJKToIndexTable[ijk[0]][ijk[1]][ijk[2]]; +} +//// +//// END-EXAMPLE VecCExample +//// +``` + +This line can be referenced in the text using the extended reStructuredText +`:exlineref:` role. The role takes references of the form +"example-name:line-label". If given just this reference, the link text is +"Example #, line #". + +``` restructuredtext +A function to convert a 3D index to a flat index starts on +:exlineref:`VecCExample:ijk-to-index`. +``` + +`:exlineref:` also accepts a formatting string like the `:numref:` builtin +role. `%s` and `{line}` will be replaced with the line number. +`:exlineref:` also follows the [`:numref:` +convention](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-numref) +of replacing `{number}` and `{name}` with the example number and caption, +respectively. + +``` restructuredtext +You can convert a flat index to a 3D index (shown starting on +:exlineref:`line {line} in Example {number}<VecCExample:index-to-ijk>`) and +the inverse function (:exlineref:`line %s<VecCExample:ijk-to-index>`). +``` + +### Ingesting Doxygen + +The VTK-m User's Guide is built with [Breathe], which allows it to pull in +Doxygen documentation. Use [Breathe's +directives](https://breathe.readthedocs.io/en/latest/directives.html#directives) +to include the doxygen documentation. + +[Sphinx]: https://www.sphinx-doc.org/en/master/ +[Doxygen]: https://www.doxygen.nl/ +[RTD Theme]: https://sphinx-themes.org/sample-sites/sphinx-rtd-theme/ +[Sphinx CMake Domain]: https://github.com/scikit-build/moderncmakedomain +[Breathe]: https://www.breathe-doc.org/ +[reStructuredText]: https://docutils.sourceforge.io/rst.html diff --git a/docs/users-guide/_ext/extract_examples/__init__.py b/docs/users-guide/_ext/extract_examples/__init__.py new file mode 100644 index 000000000..03c1c00ca --- /dev/null +++ b/docs/users-guide/_ext/extract_examples/__init__.py @@ -0,0 +1,139 @@ +##============================================================================= +## +## 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. +## +##============================================================================= + +from extract_examples import find_examples +import sphinx_tools + +import docutils.nodes +import docutils.parsers.rst.directives + +import sphinx.util.docutils + +import re + +class LoadExampleDirective(sphinx.util.docutils.SphinxDirective): + has_content = False + required_arguments = 1 + option_spec = { + 'file': docutils.parsers.rst.directives.unchanged, + 'nolinenos': docutils.parsers.rst.directives.flag, + 'caption': docutils.parsers.rst.directives.unchanged_required, + 'language': docutils.parsers.rst.directives.unchanged, + 'command-comment': docutils.parsers.rst.directives.unchanged, + } + + def run(self): + reparse = sphinx_tools.ReparseNodes() + source_file = self.state.document.current_source + source_line = self.lineno + example_name = self.arguments[0] + + filename = None + if 'file' in self.options: + filename = self.options.get('file') + if self.config.example_directory: + filename = self.config.example_directory + '/' + filename + else: + print('WARNING %s:%d: Example `%s` loaded without filename.' % + (source_file, source_line, example_name)) + + if 'language' in self.options: + language = self.options.get('language') + else: + language = self.config.example_language + + reparse.add_line('.. code-block:: %s' % language, source_file, source_line) + reparse.add_line(' :name: ex:%s' % example_name, source_file, source_line) + if 'nolinenos' not in self.options: + reparse.add_line(' :linenos:', source_file, source_line) + if 'caption' in self.options: + reparse.add_line(' :caption: %s' % self.options.get('caption'), + source_file, source_line) + reparse.add_line('', source_file, source_line) + + try: + if 'command-comment' in self.options: + command_comment = self.options.get('command-comment') + else: + command_comment = self.config.example_command_comment + example = find_examples.get_example(example_name, + filename=filename, + command_comment=command_comment) + for line in example.lines: + reparse.add_line(' %s' % line.code, example.sourcefile, line.lineno) + except Exception as e: + error = self.state_machine.reporter.error( + str(e), + docutils.nodes.literal_block(self.block_text, self.block_text), + lineno=self.lineno, + ) + return [error] + + reparse.add_line('', source_file, source_line) + return reparse.get_nodes(self) + +def exlineref_role(name, rawtext, text, lineno, inliner, options = {}, content = []): + match = re.fullmatch(r'(.*)<(.*)>', text, re.DOTALL) + if match: + pattern = match.group(1) + ref = match.group(2) + else: + pattern = 'Example {number}, line {line}' + ref = text + + match = re.fullmatch(r'(.*):([^:]*)', ref) + if not match: + message = inliner.reporter.error( + 'References for :exlineref: must be of the form example-name:label-name.;' + ' `%s` is invalid.' % ref, line=lineno) + problematic = inliner.problematic(rawtext, rawtext, message) + return [problematic, message] + examplename = match.group(1) + linelabel = match.group(2) + # Strip optional `ex:` prefix. + match = re.fullmatch(r'ex:(.*)', examplename) + if match: + examplename = group(1) + + try: + example = find_examples.get_example(examplename) + if linelabel not in example.labels: + raise Exception( + 'Label `%s` not in example `%s`' % (linelabel, examplename)) + lineno = example.labels[linelabel] + except Exception as e: + message = inliner.reporter.error(str(e), line=lineno) + problematic = inliner.problematic(rawtext, rawtext, message) + return [problematic, message] + + pattern = re.sub(r'%s', str(lineno), pattern, 1, re.DOTALL) + pattern = pattern.format(line=lineno, number='{number}', name='{name}') + if (pattern.find('{number}') >=0) or (pattern.find('{name}') >= 0): + return sphinx_tools.role_reparse( + ':numref:`%s <ex:%s>`' % (pattern, examplename), lineno, inliner) + else: + return sphinx_tools.role_reparse( + ':ref:`%s <ex:%s>`' % (pattern, examplename), lineno, inliner) + +def setup(app): + app.add_config_value('example_directory', + default=None, + rebuild='env', + types=[str]) + app.add_config_value('example_command_comment', + default='####', + rebuild='env') + app.add_config_value('example_language', + default='', + rebuild='env') + app.add_directive('load-example', LoadExampleDirective) + app.add_role('exlineref', exlineref_role) diff --git a/docs/users-guide/_ext/extract_examples/find_examples.py b/docs/users-guide/_ext/extract_examples/find_examples.py new file mode 100644 index 000000000..91fec3837 --- /dev/null +++ b/docs/users-guide/_ext/extract_examples/find_examples.py @@ -0,0 +1,160 @@ +##============================================================================= +## +## 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. +## +##============================================================================= + +import re + +class SourceLine: + '''Class to hold lines to include as example along with line numbers.''' + def __init__(self, code, lineno): + self.code = code + self.lineno = lineno + +class Example: + '''Class to hold an extracted example. + The `name` field contains the name of the example. The `lines` field + contains an array of `SourceLine` objects containing the contents.''' + def __init__(self, name, sourcefile, startline): + self.name = name + self.sourcefile = sourcefile + self.startline = startline + self.lines = [] + self.labels = {} + + def add_line(self, code, lineno): + self.lines.append(SourceLine(code, lineno)) + +class ReadError(Exception): + '''This class is thrown as an exception if a read error occurs.''' + def __init__(self, message, filename, lineno, line): + super().__init__('%s:%s: %s\n%s' % (filename, lineno, message, line)) + +loaded_examples = {} +loaded_files = [] + +def read_file(filename, command_comment='////', verbose=False): + '''Reads a source file and finds examples declared by special command + comments. This method returns an array of `Example` objects.''' + + if verbose: + print('Reading file %s' % filename) + + lines = open(filename, 'r').readlines() + + examples = [] + active_examples = {} + lineno = 0 + paused = False + for line in lines: + lineno += 1 + index = line.find(command_comment) + if index >= 0: + command = line[(index + len(command_comment)):].split() + if len(command) < 1: + pass + elif command[0] == 'BEGIN-EXAMPLE': + if len(command) != 2: + raise ReadError('BEGIN-EXAMPLE requires exactly one argument.', + filename, + lineno, + line) + example_name = command[1] + if verbose: + print('Extracting example `%s`' % example_name) + if example_name in active_examples: + raise ReadError('Example %s declared within itself.' % example_name, + filename, + lineno, + line) + active_examples[example_name] = Example(example_name, filename, lineno) + elif command[0] == 'END-EXAMPLE': + if len(command) != 2: + raise ReadError('END-EXAMPLE requires exactly one argument.', + filename, + lineno, + line) + example_name = command[1] + if example_name not in active_examples: + raise ReadError('Example %s ended before it began.' % example_name, + filename, + lineno, + line) + examples.append(active_examples[example_name]) + del active_examples[example_name] + elif command[0] == 'PAUSE-EXAMPLE': + if paused: + raise ReadError('Example iteratively paused.', + filename, lineno, line) + paused = True + elif command[0] == 'RESUME-EXAMPLE': + if not paused: + raise ReadError('Example resumed without being paused.', + filename, lineno, line) + paused = False + elif command[0] == 'LABEL': + if len(command) != 2: + raise ReadError('LABEL requires exactly one argument.', + filename, + lineno, + line) + label = command[1] + for name in active_examples: + nextline = len(active_examples[name].lines) + 1 + active_examples[name].labels[label] = nextline + else: + raise ReadError('Command %s not recognized.' % command[0], + filename, + lineno, + line) + else: + # Line not a command. Add it to any active examples. + if not paused: + for name in active_examples: + active_examples[name].add_line(line.rstrip(), lineno) + + if active_examples: + raise ReadError( + 'Unterminated example: %s' % next(iter(active_examples.keys())), + filename, + lineno, + line) + + return examples + +def load_file(filename, command_comment='////', verbose=False): + '''Loads the examples in the given file. The examples a placed in the + `loaded_examples` dictionary, which is indexed by example name. If the + file was previously loaded, nothing happens.''' + if filename not in loaded_files: + examples = read_file(filename, command_comment, verbose) + for example in examples: + name = example.name + if name in loaded_examples: + raise Exception('Example named %s found in both %s:%d and %s:%d.' % + (name, example.sourcefile, example.startline, + loaded_examples[name].sourcefile, + loaded_examples[name].startline)) + loaded_examples[name] = example + loaded_files.append(filename) + +def get_example(name, filename=None, command_comment='////', verbose=False): + '''Returns an `Example` object containing the named example. If a filename + is provided, that file is first scanned for examples (if it has not already + been scanned for examples).''' + if filename: + load_file(filename, command_comment, verbose) + if name not in loaded_examples: + raise Exception('No example named %s found.' % name) + example = loaded_examples[name] + if filename and filename != example.sourcefile: + print('WARNING: Example %s was expected in file %s but found in %s' % + (name, filename, example.sourcefile)) + return example diff --git a/docs/users-guide/_ext/fullref.py b/docs/users-guide/_ext/fullref.py new file mode 100644 index 000000000..d3e236240 --- /dev/null +++ b/docs/users-guide/_ext/fullref.py @@ -0,0 +1,37 @@ +##============================================================================= +## +## 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. +## +##============================================================================= + +import docutils.nodes + +import sphinx_tools + +def fullref_role(reftype, name, rawtext, text, lineno, inliner, options, content): + return sphinx_tools.role_reparse( + ':numref:`%s {number} ({name})<%s>`' % (reftype, text), + lineno, inliner) + +def partref_role(name, rawtext, text, lineno, inliner, options = {}, content = []): + return fullref_role( + 'Part', name, rawtext, text, lineno, inliner, options, content) + +def chapref_role(name, rawtext, text, lineno, inliner, options = {}, content = []): + return fullref_role( + 'Chapter', name, rawtext, text, lineno, inliner, options, content) + +def secref_role(name, rawtext, text, lineno, inliner, options = {}, content = []): + return fullref_role( + 'Section', name, rawtext, text, lineno, inliner, options, content) + +def setup(app): + app.add_role('partref', partref_role) + app.add_role('chapref', chapref_role) + app.add_role('secref', secref_role) diff --git a/docs/users-guide/_ext/infoboxes.py b/docs/users-guide/_ext/infoboxes.py new file mode 100644 index 000000000..0e4d9ef31 --- /dev/null +++ b/docs/users-guide/_ext/infoboxes.py @@ -0,0 +1,69 @@ +##============================================================================= +## +## 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. +## +##============================================================================= + +import docutils.nodes +import docutils.parsers.rst + +import sphinx.util.docutils + +class didyouknownode(docutils.nodes.Admonition, docutils.nodes.Element): + pass + +class commonerrorsnode(docutils.nodes.Admonition, docutils.nodes.Element): + pass + +def visit_didyouknow_node(self, node): + self.visit_admonition(node) + +def visit_commonerrors_node(self, node): + self.visit_admonition(node) + +def depart_didyouknow_node(self, node): + self.depart_admonition(node) + +def depart_commonerrors_node(self, node): + self.depart_admonition(node) + +class didyouknowdirective(sphinx.util.docutils.SphinxDirective): + has_content = True + def run(self): + admonitionnode = didyouknownode('\n'.join(self.content)) + admonitionnode += docutils.nodes.title('Did You Know?', 'Did You Know?') + admonitionnode['classes'] += ['tip'] + self.state.nested_parse(self.content, self.content_offset, admonitionnode) + + return [admonitionnode] + +class commonerrorsdirective(sphinx.util.docutils.SphinxDirective): + has_content = True + def run(self): + admonitionnode = commonerrorsnode('\n'.join(self.content)) + admonitionnode += docutils.nodes.title('Common Errors', 'Common Errors') + admonitionnode['classes'] += ['error'] + self.state.nested_parse(self.content, self.content_offset, admonitionnode) + + return [admonitionnode] + +def setup(app): + app.add_node(didyouknownode, + html=(visit_didyouknow_node, depart_didyouknow_node), + latex=(visit_didyouknow_node, depart_didyouknow_node), + text=(visit_didyouknow_node, depart_didyouknow_node), + ) + app.add_directive('didyouknow', didyouknowdirective) + + app.add_node(commonerrorsnode, + html=(visit_commonerrors_node, depart_commonerrors_node), + latex=(visit_commonerrors_node, depart_commonerrors_node), + text=(visit_commonerrors_node, depart_commonerrors_node), + ) + app.add_directive('commonerrors', commonerrorsdirective) diff --git a/docs/users-guide/_ext/sphinx_tools.py b/docs/users-guide/_ext/sphinx_tools.py new file mode 100644 index 000000000..f03224fc2 --- /dev/null +++ b/docs/users-guide/_ext/sphinx_tools.py @@ -0,0 +1,109 @@ +##============================================================================= +## +## 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. +## +##============================================================================= + +def role_reparse(rawtext, lineno, inliner): + '''Reparses inline code for a role. + + It is often the case that a role for reStructuredText can be defined using + other existing functionality. Rather than try to implement the node building + for such extensions from scratch, it is much easier to substitute the text + with something and instruct the parser to parse that. + + Unfortunately, Sphinx currently does not provide the ability to do such a + "reparse" while implementing a role. This method is a hacked version of the + `parse` method of `docutils.parsers.rst.states.Inliner`. (This code might + break if the internals of that class change.) + + To use this method, create a role implementation function as normal, modify + the text/rawText to the form that implements the functionality, and call + this method with the new text as well as the passed in line number and + inliner object. + + Note that if the parsing of the text breaks, the error messages may be + confusing because they could refer to items that are not being directly + used in the reStructuredText document. + ''' + remaining = rawtext + processed = [] + unprocessed = [] + messages = [] + while remaining: + match = inliner.patterns.initial.search(remaining) + if match: + groups = match.groupdict() + method = inliner.dispatch[groups['start'] or groups['backquote'] + or groups['refend'] or groups['fnend']] + before, inlines, remaining, sysmessages = method(inliner, match, lineno) + unprocessed.append(before) + messages += sysmessages + if inlines: + processed += inliner.implicit_inline(''.join(unprocessed), lineno) + processed += inlines + unprocessed = [] + else: + break + remaining = ''.join(unprocessed) + remaining + if remaining: + processed += inliner.implicit_inline(remaining, lineno) + return processed, messages + +import docutils.nodes +import docutils.statemachine +import sphinx.util.nodes + +class ReparseNodes: + '''This class is used within directive classes to implement a directive by + creating new reStructuredText code. This new code is fed back to the parser + and the resulting nodes can be returned as the implementation of the + directive. + + To use this class, construct an object. Then use the ``add_line`` method to + add lines one at a time. When finished, use the ``get_nodes`` function to + get the nodes that should be returned from the directives ``run`` method. + Here is a simple example:: + + import sphinx.util.docutils + + class Foo(sphinx.util.docutils.SphinxDirective): + def run(self): + reparse = ReparseNodes() + reparse.add_line('.. note::', 'fakefile.rst', 1) + reparse.add_line(' This box added in directive.', 'fakefile.rst', 2) + reparse.add_line('', 'fakefile.rst', 3) + reparse.add_line('This text also added in directive.', 'fakefile.rst', 3) + return reparse.get_nodes(self) + + def setup(app): + app.add_directive('foo', Foo) + + Note that if you want the reparse to base its file location on the location + of your directive (which is a good idea), you can get the name of the file + containing the directive call with ``self.state.document.current_source`` + and get the line to directive starts at with ``self.lineno``. + + The implementation of this class suggested from + https://stackoverflow.com/questions/34350844/how-to-add-rst-format-in-nodes-for-directive + ''' + def __init__(self): + self.source = docutils.statemachine.ViewList() + + def add_line(self, sourceline, filename, linenumber): + self.source.append(sourceline, filename, linenumber) + + def get_nodes(self, directive): + node = docutils.nodes.section() + node.document = directive.state.document + + sphinx.util.nodes.nested_parse_with_titles(directive.state, + self.source, + node) + return node.children diff --git a/docs/users-guide/acknowledgements.rst b/docs/users-guide/acknowledgements.rst new file mode 100644 index 000000000..01ab7ba45 --- /dev/null +++ b/docs/users-guide/acknowledgements.rst @@ -0,0 +1,94 @@ +============================== +Acknowledgements +============================== + +------------------------------ +Contributors +------------------------------ + +.. todo:: Make sure contribution section cross references are correct. + +This book includes contributions from the VTK-m community including the +VTK-m development team and the user community. +We would like to thank the following people for their significant +contributions to this text: + +.. NOTE: Also make sure that the contribution list is updated in index.rst + +**Vicente Bolea**, **Nickolas Davis**, **Matthew Letter**, and **Nick Thompson** for their help keeping the user's guide up to date with the |VTKm| source code. + +**Sujin Philip**, **Robert Maynard**, **James Kress**, **Abhishek Yenpure**, **Mark Kim**, and **Hank Childs** for their descriptions of numerous filters. + +.. Sujin Philip: Surface normals, normals in Marching Cubes +.. Robert Maynard: Gradient, warp scalars, warp vectors, histogram, extract structured +.. James Kress: Point transform +.. Abhishek Yenpure: Point merge +.. Mark Kim: ZFP compression +.. Hank Childs: Mesh Quality Metrics + +**Allison Vacanti** for her documentation of.. + +.. several |VTKm| features in the `Extract Component Arrays`_ and `SwizzleArrays`_ sections as well as select filters. + +.. Allie Vacanti filters: Surface normals. + +**David Pugmire** for his documentation of.. + +.. partitioned data sets (Section \ref{sec:DataSets:PartitionedDataSet}) and select filters. + +.. Dave Pugmire filters: Streamlines, point transform, coordinate system transforms, add ghost cells, remove ghost cells. + +**Abhishek Yenpure** and **Li-Ta Lo** for their documentation of locator structures.. + +.. (Chapter~\ref{chap:Locators}). + +.. Abhishek Yenpure: General cell locators and BoundingIntervalHierarchy +.. Li-Ta Lo: General point locators and uniform grid point locator, particle density + +**Li-Ta Lo** for his documentation of random array handles and particle +density filters. + +.. ArrayHandleRandomUniformBits. + +**James Kress** for his documentation on |VTKm|'s testing classes. + +**Manish Mathai** for his documentation of rendering features.. + +.. (Chapter~\ref{chap:Rendering}). + + +------------------------------ +Funding +------------------------------ + +.. |LogoSpacing| image:: images/LogoSpacing.png +.. |DOELogo| image:: images/DOELogo.png +.. |ORNLLogo| image:: images/ORNLLogo.png +.. |LANLLogo| image:: images/LANLLogo.png +.. |SandiaLogo| image:: images/SandiaLogo.png +.. |KitwareLogo| image:: images/KitwareLogo.png + +.. centered:: |DOELogo| + |LogoSpacing| + |ORNLLogo| + |LogoSpacing| + |LANLLogo| + |LogoSpacing| + |SandiaLogo| + |LogoSpacing| + |KitwareLogo| + +|LogoSpacing| + +This project has been funded in whole or in part with Federal funds from the Department of Energy, including from Oak Ridge National Laboratory, Los Alamos National Laboratory, and Sandia National Laboratories. + +This manuscript has been authored in part by UT-Battelle, LLC, under contract DE-AC05-00OR22725 with the US Department of Energy (DOE). +The US government retains and the publisher, by accepting the article for publication, acknowledges that the US government retains a nonexclusive, paid-up, irrevocable, worldwide license to publish or reproduce the published form of this manuscript, or allow others to do so, for US government purposes. + +Sandia National Laboratories is a multimission laboratory managed and operated by National Technology and Engineering Solutions of Sandia LLC, a wholly owned subsidiary of Honeywell International Inc. for the U.S. Department of Energy's National Nuclear Security Administration under contract DE-NA0003525. + +This research was supported by the Exascale Computing Project (17-SC-20-SC), a joint project of the U.S. +Department of Energy's Office of Science and National Nuclear Security Administration, responsible for delivering a capable exascale ecosystem, including software, applications, and hardware technology, to support the nation's exascale computing imperative. + +This material is based upon work supported by the U.S. +Department of Energy, Office of Science, Office of Advanced Scientific Computing Research, Scientific Discovery through Advanced Computing (SciDAC) program. diff --git a/docs/users-guide/base-types.rst b/docs/users-guide/base-types.rst new file mode 100644 index 000000000..c3b9b9151 --- /dev/null +++ b/docs/users-guide/base-types.rst @@ -0,0 +1,227 @@ +============================== +Base Types +============================== + +It is common for a framework to define its own types. +Even the C++ standard template library defines its own base types like :type:`std::size_t` and :type:`std::pair`. +|VTKm| is no exception. + +In fact |VTKm| provides a great many base types. +It is the general coding standard of |VTKm| to not directly use the base C types like ``int`` and ``float`` and instead to use types declared in |VTKm|. +The rational is to precisely declare the representation of each variable to prevent future trouble. + +Consider that you are programming something and you need to declare an integer variable. +You would declare this variable as ``int``, right? +Well, maybe. +In C++, the declaration ``int`` does not simply mean "an integer." +``int`` means something much more specific than that. +If you were to look up the C++11 standard, you would find that ``int`` is an integer represented in 32 bits with a two's complement signed representation. +In fact, a C++ compiler has no less than 8 standard integer types. + +.. + \footnote{% + I intentionally use the phrase ``no less than'' for our pedantic readers. + One could argue that \textcode{char} and \textcode{bool} are treated distinctly by the compiler even if their representations match either \textcode{signed char} or \textcode{unsigned char}. + Furthermore, many modern C++ compilers have extensions for less universally accepted types like 128-bit integers. + } + +So, ``int`` is nowhere near as general as the code might make it seem, and treating it as such could lead to trouble. +For example, consider the MPI standard, which, back in the 1990's, implicitly selected ``int`` for its indexing needs. +Fast forward to today where there is a need to reference buffers with more than 2 billion elements, but the standard is stuck with a data type that cannot represent sizes that big. +(To be fair, it is *possible* to represent buffers this large in MPI, but it is extraordinarily awkward to do so. + +Consequently, we feel that with |VTKm| it is best to declare the intention of a variable with its declaration, which should help both prevent errors and future proof code. +All the types presented in this chapter are declared in :file:`vtkm/Types.h`, which is typically included either directly or indirectly by all source using |VTKm|. + +------------------------------ +Floating Point Types +------------------------------ + +|VTKm| declares 2 types to hold floating point numbers: :type:`vtkm::Float32` and :type:`vtkm::Float64`. +These, of course, represent floating point numbers with 32-bits and 64-bits of precision, respectively. +These should be used when the precision of a floating point number is predetermined. + +.. doxygentypedef:: vtkm::Float32 + +.. doxygentypedef:: vtkm::Float64 + +When the precision of a floating point number is not predetermined, operations usually have to be overloaded or templated to work with multiple precisions. +In cases where a precision must be set, but no particular precision is specified, :type:`vtkm::FloatDefault` should be used. + +.. doxygentypedef:: vtkm::FloatDefault + +:type:`vtkm::FloatDefault` will be set to either :type:`vtkm::Float32` or :type:`vtkm::Float64` depending on whether the CMake option :cmake:variable:`VTKm_USE_DOUBLE_PRECISION` was set when |VTKm| was compiled, as discussed in :secref:`building:Configuring |VTKm|`. +Using :type:`vtkm::FloatDefault` makes it easier for users to trade off precision and speed. + + +------------------------------ +Integer Types +------------------------------ + +The most common use of an integer in |VTKm| is to index arrays. +For this purpose, the :type:`vtkm::Id` type should be used. +(The width of :type:`vtkm::Id` is determined by the :cmake:variable:`VTKm_USE_64BIT_IDS` CMake option.) + +.. doxygentypedef:: vtkm::Id + +|VTKm| also has a secondary index type named :type:`vtkm::IdComponent`, which is smaller and typically used for indexing groups of components within a thread. +For example, if you had an array of 3D points, you would use :type:`vtkm::Id` to reference each point, and you would use :type:`vtkm::IdComponent` to reference the respective :math:`x`, :math:`y`, and :math:`z` components. + +.. doxygentypedef:: vtkm::IdComponent + +.. index:: std::size_t, size_t +.. didyouknow:: + The |VTKm| index types, :type:`vtkm::Id` and :type:`vtkm::IdComponent` use signed integers. + This breaks with the convention of other common index types like the C++ standard template library :type:`std::size_t`, which use unsigned integers. + Unsigned integers make sense for indices as a valid index is always 0 or greater. + However, doing things like iterating in a for loop backward, representing relative indices, and representing invalid values is much easier with signed integers. + Thus, |VTKm| chooses to use a signed integer for indexing. + +|VTKm| also has types to declare an integer of a specific width and sign. +The types :type:`vtkm::Int8`, :type:`vtkm::Int16`, :type:`vtkm::Int32`, and :type:`vtkm::Int64` specify signed integers of 1, 2, 4, and 8 bytes, respectively. +Likewise, the types :type:`vtkm::UInt8`, :type:`vtkm::UInt16`, :type:`vtkm::UInt32`, and :type:`vtkm::UInt64` specify unsigned integers of 1, 2, 4, and 8 bytes, respectively. + +.. doxygentypedef:: vtkm::Int8 + +.. doxygentypedef:: vtkm::UInt8 + +.. doxygentypedef:: vtkm::Int16 + +.. doxygentypedef:: vtkm::UInt16 + +.. doxygentypedef:: vtkm::Int32 + +.. doxygentypedef:: vtkm::UInt32 + +.. doxygentypedef:: vtkm::Int64 + +.. doxygentypedef:: vtkm::UInt64 + + +------------------------------ +Vector Types +------------------------------ + +Visualization algorithms also often require operations on short vectors. +Arrays indexed in up to three dimensions are common. +Data are often defined in 2-space and 3-space, and transformations are typically done in homogeneous coordinates of length 4. +To simplify these types of operations, |VTKm| provides a collection of base types to represent these short vectors, which are collectively referred to as ``Vec`` types. + +:type:`vtkm::Vec2f`, :type:`vtkm::Vec3f`, and :type:`vtkm::Vec4f` specify floating point vectors of 2, 3, and 4 components, respectively. +The precision of the floating point numbers follows that of :type:`vtkm::FloatDefault` (which, as documented in :secref:`base-types:Floating Point Types`, is specified by the :cmake:variable:`VTKm_USE_DOUBLE_PRECISION` compile option). +Components of these and other ``Vec`` types can be references through the ``[ ]`` operator, much like a C array. +A ``Vec`` also supports basic arithmetic operators so that it can be used much like its scalar-value counterparts. + +.. doxygentypedef:: vtkm::Vec2f + +.. doxygentypedef:: vtkm::Vec3f + +.. doxygentypedef:: vtkm::Vec4f + +.. load-example:: SimpleVectorTypes + :file: GuideExampleCoreDataTypes.cxx + :caption: Simple use of ``Vec`` objects.} + +You can also specify the precision for each of these vector types by appending the bit size of each component. +For example, :type:`vtkm::Vec3f_32` and :type:`vtkm::Vec3f_64` represent 3-component floating point vectors with each component being 32 bits and 64 bits respectively. +Note that the precision number refers to the precision of each component, not the vector as a whole. +So :type:`vtkm::Vec3f_32` contains 3 32-bit (4-byte) floating point components, which means the entire :type:`vtkm::Vec3f_32` requires 96 bits (12 bytes). + +.. doxygentypedef:: vtkm::Vec2f_32 + +.. doxygentypedef:: vtkm::Vec2f_64 + +.. doxygentypedef:: vtkm::Vec3f_32 + +.. doxygentypedef:: vtkm::Vec3f_64 + +.. doxygentypedef:: vtkm::Vec4f_32 + +.. doxygentypedef:: vtkm::Vec4f_64 + +To help with indexing 2-, 3-, and 4- dimensional arrays, |VTKm| provides the types :type:`vtkm::Id2`, :type:`vtkm::Id3`, and :type:`vtkm::Id4`, which are \textidentifier{Vec}s of type :type:`vtkm::Id`. +Likewise, |VTKm| provides :type:`vtkm::IdComponent2`, :type:`vtkm::IdComponent3`, and :type:`vtkm::IdComponent4`. + +.. doxygentypedef:: vtkm::Id2 + +.. doxygentypedef:: vtkm::Id3 + +.. doxygentypedef:: vtkm::Id4 + +.. doxygentypedef:: vtkm::IdComponent2 + +.. doxygentypedef:: vtkm::IdComponent3 + +.. doxygentypedef:: vtkm::IdComponent4 + +|VTKm| also provides types for \textidentifier{Vec}s of integers of all varieties described in Section \ref{sec:IntegerTypes}. +:type:`vtkm::Vec2i`, :type:`vtkm::Vec3i`, and :type:`vtkm::Vec4i` are vectors of signed integers whereas :type:`vtkm::Vec2ui`, :type:`vtkm::Vec3ui`, and :type:`vtkm::Vec4ui` are vectors of unsigned integers. +All of these sport components of a width equal to :type:`vtkm::Id`. + +.. doxygentypedef:: vtkm::Vec2i + +.. doxygentypedef:: vtkm::Vec3i + +.. doxygentypedef:: vtkm::Vec4i + +.. doxygentypedef:: vtkm::Vec2ui + +.. doxygentypedef:: vtkm::Vec3ui + +.. doxygentypedef:: vtkm::Vec4ui + +The width can be specified by appending the desired number of bits in the same way as the floating point \textidentifier{Vec}s. +For example, :type:`vtkm::Vec4ui_8` is a \textidentifier{Vec} of 4 unsigned bytes. + +.. doxygentypedef:: vtkm::Vec2i_8 + +.. doxygentypedef:: vtkm::Vec2ui_8 + +.. doxygentypedef:: vtkm::Vec2i_16 + +.. doxygentypedef:: vtkm::Vec2ui_16 + +.. doxygentypedef:: vtkm::Vec2i_32 + +.. doxygentypedef:: vtkm::Vec2ui_32 + +.. doxygentypedef:: vtkm::Vec2i_64 + +.. doxygentypedef:: vtkm::Vec2ui_64 + +.. doxygentypedef:: vtkm::Vec3i_8 + +.. doxygentypedef:: vtkm::Vec3ui_8 + +.. doxygentypedef:: vtkm::Vec3i_16 + +.. doxygentypedef:: vtkm::Vec3ui_16 + +.. doxygentypedef:: vtkm::Vec3i_32 + +.. doxygentypedef:: vtkm::Vec3ui_32 + +.. doxygentypedef:: vtkm::Vec3i_64 + +.. doxygentypedef:: vtkm::Vec3ui_64 + +.. doxygentypedef:: vtkm::Vec4i_8 + +.. doxygentypedef:: vtkm::Vec4ui_8 + +.. doxygentypedef:: vtkm::Vec4i_16 + +.. doxygentypedef:: vtkm::Vec4ui_16 + +.. doxygentypedef:: vtkm::Vec4i_32 + +.. doxygentypedef:: vtkm::Vec4ui_32 + +.. doxygentypedef:: vtkm::Vec4i_64 + +.. doxygentypedef:: vtkm::Vec4ui_64 + +These types really just scratch the surface of the ``Vec`` types available in |VTKm| and the things that can be done with them. +See ``:chapref:`advanced-types:Advanced Types` `` for more information on ``Vec`` types and what can be done with them. + +.. todo:: Update chapter reference. diff --git a/docs/users-guide/building.rst b/docs/users-guide/building.rst new file mode 100644 index 000000000..a3a9ac339 --- /dev/null +++ b/docs/users-guide/building.rst @@ -0,0 +1,399 @@ +============================== +Building and Installing |VTKm| +============================== + +Before we begin describing how to develop with |VTKm|, we have a brief overview of how to build |VTKm|, optionally install it on your system, and start your own programs that use |VTKm|. + + +------------------------------ +Getting |VTKm| +------------------------------ + +|VTKm| is an open source software product where the code is made freely available. +To get the latest released version of |VTKm|, go to the |VTKm| releases page: + + https://gitlab.kitware.com/vtk/vtk-m/-/releases + +From there with your favorite browser you may download the source code from any of the recent |VTKm| releases in a variety of different archive files such as zip or tar gzip. + +For access to the most recent work, the |VTKm| development team provides public anonymous read access to their main source code repository. +The main |VTKm| repository on a GitLab instance hosted at Kitware, Inc. +The repository can be browsed from its project web page: + + https://gitlab.kitware.com/vtk/vtk-m + +We leave access to the :index:`git` hosted repository as an exercise for the user. +Those interested in :command:`git` access for the purpose of contributing to |VTKm| should consult the `CONTRIBUTING <https://gitlab.kitware.com/vtk/vtk-m/blob/master/CONTRIBUTING.md>`_ guidelines documented in the source code. + +.. %% \index{git|(} + +.. %% The source code in the |VTKm| repository is access through the \textfilename{git} version control tool. +.. %% If you have not used \textfilename{git} before, there are several resources available to help you get familiar with it. +.. %% Github has a nice setup guide (\url{https://help.github.com/articles/set-up-git}) to help you get up and running quickly. +.. %% For more complete documentation, we recommend the \emph{Pro Git} book (\url{https://git-scm.com/book}). + +.. %% To get a copy of the |VTKm| repository, issue a git clone command. + +.. %% \begin{blankexample}{Cloning the main |VTKm| git repository.} +.. %% git clone https://gitlab.kitware.com/vtk/vtk-m.git +.. %% \end{blankexample} + +.. %% The git clone command will create a copy of all the source code to your local machine. +.. %% As time passes and you want to get an update of changes in the repository, you can do that with the git pull command. + +.. %% \begin{blankexample}{Updating a git repository with the pull command.} +.. %% git pull +.. %% \end{blankexample} + +.. %% \begin{didyouknow} +.. %% The proceeding examples for using git are based on the \textfilename{git} command line tool, which is particularly prevalent on Unix-based and Mac systems. +.. %% There also exist several GUI tools for accessing git repositories. +.. %% These tools each have their own interface and they can be quite different. +.. %% However, they all should have roughly equivalent commands named ``clone'' to download a repository given a url and ``pull'' to update an existing repository. +.. %% \end{didyouknow} + +.. %% \index{git|)} + + +------------------------------ +Configuring |VTKm| +------------------------------ + +.. index:: + single: CMake + pair: CMake; configuration + +|VTKm| uses a cross-platform configuration tool named CMake to simplify the configuration and building across many supported platforms. +CMake is available from many package distribution systems and can also be downloaded for many platforms from http://cmake.org. + +Most distributions of CMake come with a convenient GUI application (:command:`cmake-gui`) that allows you to browse all of the available configuration variables and run the configuration. +Many distributions also come with an alternative terminal-based version (:command:`ccmake`), which is helpful when accessing remote systems where creating GUI windows is difficult. + +One helpful feature of CMake is that it allows you to establish a build directory separate from the source directory, and the |VTKm| project requires that separation. +Thus, when you run CMake for the first time, you want to set the build directory to a new empty directory and the source to the downloaded or cloned files. +The following example shows the steps for the case where the |VTKm| source is cloned from the git repository. +(If you extracted files from an archive downloaded from the |VTKm| web page, the instructions are the same from the second line down.) + +.. code-block:: bash + :caption: Running CMake on downloaded |VTKm| source (Unix commands). + :name: ex:RunningCMake + + tar xvzf ~/Downloads/vtk-m-v2.1.0.tar.gz + mkdir vtkm-build + cd vtkm-build + cmake-gui ../vtk-m-v2.1.0 + +.. _fig:CMakeGUI: +.. figure:: images/CMakeGUIBoth.png + :width: 100% + :align: center + + The CMake GUI configuring the |VTKm| project. + At left is the initial blank configuration. + At right is the state after a configure pass. + +The first time the CMake GUI runs, it initially comes up blank as shown at left in :numref:`fig:CMakeGUI`. +Verify that the source and build directories are correct (located at the top of the GUI) and then click the :guilabel:`Configure` button near the bottom. +The first time you run configure, CMake brings up a dialog box asking what generator you want for the project. +This allows you to select what build system or IDE to use (e.g. make, ninja, Visual Studio). +Once you click :guilabel:`Finish`, CMake will perform its first configuration. +Don't worry if CMake gives an error about an error in this first configuration process. + +.. commonerrors:: + Most options in CMake can be reconfigured at any time, but not the compiler and build system used. + These must be set the first time configure is run and cannot be subsequently changed. + If you want to change the compiler or the project file types, you will need to delete everything in the build directory and start over. + +After the first configuration, the CMake GUI will provide several configuration options as shown in :numref:`fig:CMakeGUI` on the right. +You now have a chance to modify the configuration of |VTKm|, which allows you to modify both the behavior of the compiled |VTKm| code as well as find components on your system. +Using the CMake GUI is usually an iterative process where you set configuration options and re-run :guilabel:`Configure`. +Each time you configure, CMake might find new options, which are shown in red in the GUI. + +It is often the case during this iterative configuration process that configuration errors occur. +This can occur after a new option is enabled but CMake does not automatically find the necessary libraries to make that feature possible. +For example, to enable TBB support, you may have to first enable building TBB, configure for TBB support, and then tell CMake where the TBB include directories and libraries are. + +Once you have set all desired configuration variables and resolved any CMake errors, click the :guilabel:`Generate` button. This will create the build files (such as makefiles or project files depending on the generator chosen at the beginning). You can then close the CMake GUI. + +There are a great number of configuration parameters available when running CMake on |VTKm|. +The following list contains the most common configuration parameters. + +.. cmake:variable:: BUILD_SHARED_LIBS + + Determines whether static or shared libraries are built. + +.. cmake:variable:: CMAKE_BUILD_TYPE + + Selects groups of compiler options from categories like :index:`Debug` and :index:`Release`. + Debug builds are, obviously, easier to debug, but they run *much* slower than Release builds. + Use Release builds whenever releasing production software or doing performance tests. + +.. cmake:variable:: CMAKE_INSTALL_PREFIX + + The root directory to place files when building the install target. + +.. cmake:variable:: VTKm_ENABLE_EXAMPLES + + The |VTKm| repository comes with an \textfilename{examples} directory. + This macro determines whether they are built. + +.. cmake:variable:: VTKm_ENABLE_BENCHMARKS + + If on, the |VTKm| build includes several benchmark programs. + The benchmarks are regression tests for performance. + +.. cmake:variable:: VTKm_ENABLE_CUDA + + Determines whether |VTKm| is built to run on :index:`CUDA` GPU devices. + +.. index:: kokkos +.. cmake:variable:: VTKm_ENABLE_KOKKOS + + Determines whether |VTKm| is built using the `Kokkos <https://kokkos.github.io/kokkos-core-wiki/>`_ portable library. + Kokkos, can be configured to support several backends that |VTKm| can leverage. + +.. cmake:variable:: VTKm_ENABLE_MPI + + Determines whether |VTKm| is built with :index:`MPI` suppoert for running on distributed memory clusters. + +.. cmake:variable:: VTKm_ENABLE_OPENMP + + Determines whether |VTKm| is built to run on multi-core devices using :index:`OpenMP` pragmas provided by the C++ compiler. + +.. cmake:variable:: VTKm_ENABLE_RENDERING + + Determines whether to build the rendering library. + +.. index:: see: Intel Threading Building Blocks; TBB +.. index:: TBB +.. cmake:variable:: VTKm_ENABLE_TBB + + Determines whether |VTKm| is built to run on multi-core x86 devices using the Intel Threading Building Blocks library. + +.. cmake:variable:: VTKm_ENABLE_TESTING + + If on, the |VTKm| build includes building many test programs. + The |VTKm| source includes hundreds of regression tests to ensure quality during development. + +.. cmake:variable:: VTKm_ENABLE_TUTORIALS + + If on, several small example programes used for the |VTKm| tutorial are built. + +.. cmake:variable:: VTKm_USE_64BIT_IDS + + If on, then |VTKm| will be compiled to use 64-bit integers to index arrays and other lists. + If off, then |VTKm| will use 32-bit integers. + 32-bit integers take less memory but could cause failures on larger data. + +.. cmake:variable:: VTKm_USE_DOUBLE_PRECISION + + If on, then |VTKm| will use double precision (64-bit) floating point numbers for calculations where the precision type is not otherwise specified. + If off, then single precision (32-bit) floating point numbers are used. + Regardless of this setting, |VTKm|'s templates will accept either type. + + +------------------------------ +Building |VTKm| +------------------------------ + +Once CMake successfully configures |VTKm| and generates the files for the build system, you are ready to build |VTKm|. +As stated earlier, CMake supports generating configuration files for several different types of build tools. +Make and ninja are common build tools, but CMake also supports building project files for several different types of integrated development environments such as Microsoft Visual Studio and Apple XCode. + +The |VTKm| libraries and test files are compiled when the default build is invoked. +For example, if a :file:`Makefile` was generated, the build is invoked by calling \textfilename{make} in the build directory. +Expanding on :numref:`ex:RunningCMake` + +.. code-block:: bash + :caption: Using :command:`make` to build |VTKm|. + :name: ex:RunningMake + + tar xvzf ~/Downloads/vtk-m-v2.1.0.tar.gz + mkdir vtkm-build + cd vtkm-build + cmake-gui ../vtk-m-v2.1.0 + make -j + make install + +.. didyouknow:: + :file:`Makefile` and other project files generated by CMake support parallel builds, which run multiple compile steps simultaneously. + On computers that have multiple processing cores (as do almost all modern computers), this can significantly speed up the overall compile. + Some build systems require a special flag to engage parallel compiles. + For example, :command:`make` requires the ``-j`` flag to start parallel builds as demonstrated in :numref:`ex:RunningMake`. + +.. didyouknow:: + :numref:`ex:RunningMake` assumes that a make build system was generated, which is the default on most system. + However, CMake supports many more build systems, which use different commands to run the build. + If you are not sure what the appropriate build command is, you can run ``cmake --build`` to allow CMake to start the build using whatever build system is being used. + +.. commonerrors:: + CMake allows you to switch between several types of builds including default, Debug, and Release. + Programs and libraries compiled as release builds can run *much* faster than those from other types of builds. + Thus, it is important to perform Release builds of all software released for production or where runtime is a concern. + Some integrated development environments such as Microsoft Visual Studio allow you to specify the different build types within the build system. + But for other build programs, like :command:`make`, you have to specify the build type in the :cmake:variable:`CMAKE_BUILD_TYPE` CMake configuration variable, which is described in :secref:`building:Configuring |VTKm|`. + +CMake creates several build "targets" that specify the group of things to build. +The default target builds all of |VTKm|'s libraries as well as tests, examples, and benchmarks if enabled. +The ``test`` target executes each of the |VTKm| regression tests and verifies they complete successfully on the system. +The ``install`` target copies the subset of files required to use |VTKm| to a common installation directory. +The ``install`` target may need to be run as an administrator user if the installation directory is a system directory. + +.. didyouknow:: + |VTKm| contains a significant amount of regression tests. + If you are not concerned with testing a build on a given system, you can turn off building the testing, benchmarks, and examples using the CMake configuration variables described in :secref:`building:Configuring |VTKm|`. + This can shorten the |VTKm| compile time. + + +------------------------------ +Linking to |VTKm| +------------------------------ + +Ultimately, the value of |VTKm| is the ability to link it into external projects that you write. +The header files and libraries installed with |VTKm| are typical, and thus you can link |VTKm| into a software project using any type of build system. +However, |VTKm| comes with several CMake configuration files that simplify linking |VTKm| into another project that is also managed by CMake. +Thus, the documentation in this section is specifically for finding and configuring |VTKm| for CMake projects. + +.. index:: + pair: CMake; VTK-m package + +|VTKm| can be configured from an external project using the :cmake:command:`find_package` CMake function. +The behavior and use of this function is well described in the CMake documentation. +The first argument to :cmake:command:`find_package` is the name of the package, which in this case is ``VTKm``. +CMake configures this package by looking for a file named :file:`VTKmConfig.cmake`, which will be located in the :file:`lib/cmake/vtkm-<\VTKm version>` directory of the install or build of |VTKm|. +The configurable CMake variable :cmake:variable:`CMAKE_PREFIX_PATH` can be set to the build or install directory, the :cmake:envvar:`CMAKE_PREFIX_PATH` environment variable can likewise be set, or \cmakevar{VTKm_DIR} can be set to the directory that contains this file. + +.. code-block:: cmake + :caption: Loading |VTKm| configuration from an external CMake project. + + find_package(VTKm REQUIRED) + +.. didyouknow:: + The CMake :cmake:command:`find_package` function also supports several features not discussed here including specifying a minimum or exact version of |VTKm| and turning off some of the status messages. + See the CMake documentation for more details. + +.. index:: + triple: CMake ; VTK-m package ; libraries + +When you load the |VTKm| package in CMake, several libraries are defined. +Projects building with |VTKm| components should link against one or more of these libraries as appropriate, typically with the :cmake:command:`target_link_libraries` command. + +.. code-block:: cmake + :caption: Linking |VTKm| code into an external program. + + find_package(VTKm REQUIRED) + + add_executable(myprog myprog.cxx) + target_link_libraries(myprog vtkm::filter) + +Several library targets are provided, but most projects will need to link in one or more of the following. + +.. + Note that I am documenting the VTK-m targets as CMake variables. This is + because the Sphinx extension for the CMake domain that I am using currently + does not support documenting targets. + +.. cmake:variable:: vtkm::cont + + Contains the base objects used to control |VTKm|. + +.. cmake:variable:: vtkm::filter + + Contains |VTKm|'s pre-built filters. + Applications that are looking to use VTK-m filters will need to link to this library. + The filters are further broken up into several smaller library packages (such as :cmake:variable:`vtkm::filter_contour`, :cmake:variable`vtkm::filter_flow`, :cmake:variable:`vtkm::filter_field_transform`, and many more. + :cmake:variable:`vtkm::filter` is actually a meta library that links all of these filter libraries to a CMake target. + +.. cmake:variable:: vtkm::io + + Contains |VTKm|'s facilities for interacting with files. + For example, reading and writing png, NetBPM, and VTK files. + +.. cmake:variable:: vtkm::rendering + + Contains |VTKm|'s rendering components. + This library is only available if :cmake:variable:`VTKm_ENABLE_RENDERING` is set to true. + +.. cmake:variable:: vtkm::source + + Contains |VTKm|'s pre-built dataset generators suchas Wavelet, Tangle, and Oscillator. + Most applications will not need to link to this library. + +.. didyouknow:: + The "libraries" made available in the |VTKm| do more than add a library to the linker line. + These libraries are actually defined as external targets that establish several compiler flags, like include file directories. + Many CMake packages require you to set up other target options to compile correctly, but for |VTKm| it is sufficient to simply link against the library. + +.. commonerrors:: + Because the |VTKm| CMake libraries do more than set the link line, correcting the link libraries can do more than fix link problems. + For example, if you are getting compile errors about not finding |VTKm| header files, then you probably need to link to one of |VTKm|'s libraries to fix the problem rather than try to add the include directories yourself. + +.. index:: + triple: CMake; VTK-m package; variables + +The following is a list of all the CMake variables defined when the \textcode{find_package} function completes. + +.. cmake:variable:: VTKm_FOUND + + Set to true if the |VTKm| CMake package is successfully loaded. + If :cmake:command:`find_package` was not called with the ``REQUIRED`` option, then this variable should be checked before attempting to use |VTKm|. + +.. cmake:variable:: VTKm_VERSION + + The version number of the loaded |VTKm| package. + This is in the form "major.minor". + +.. cmake:variable:: VTKm_VERSION_FULL + + The extended version number of the |VTKm| package including patch and in-between-release information. + This is in the form "major.minor.patch[.gitsha1]" where "gitsha" is only included if the source code is in between releases. + +.. cmake:variable:: VTKm_VERSION_MAJOR + + The major |VTKm| version number. + +.. cmake:variable:: VTKm_VERSION_MINOR + + The minor |VTKm| version number. + +.. cmake:variable:: VTKm_VERSION_PATCH + + The patch |VTKm| version number. + +.. cmake:variable:: VTKm_ENABLE_CUDA + + Set to true if |VTKm| was compiled for CUDA. + +.. cmake:variable:: VTKm_ENABLE_Kokkos + + Set to true if |VTKm| was compiled with Kokkos. + +.. cmake:variable:: VTKm_ENABLE_OPENMP + + Set to true if |VTKm| was compiled for OpenMP. + +.. cmake:variable:: VTKm_ENABLE_TBB + + Set to true if |VTKm| was compiled for TBB. + +.. cmake:variable:: VTKm_ENABLE_RENDERING + + Set to true if the |VTKm| rendering library was compiled. + +.. cmake:variable:: VTKm_ENABLE_MPI + + Set to true if |VTKm| was compiled with MPI support. + +These package variables can be used to query whether optional components are supported before they are used in your CMake configuration. + +.. code-block:: cmake + :caption: Using an optional component of |VTKm|. + + find_package(VTKm REQUIRED) + + if (NOT VTKm::ENABLE::RENDERING) + message(FATAL_ERROR "VTK-m must be built with rendering on.") + endif() + + add_executable(myprog myprog.cxx) + target_link_libraries(myprog vtkm::cont vtkm::rendering) diff --git a/docs/users-guide/conf.py b/docs/users-guide/conf.py new file mode 100644 index 000000000..b35efeb38 --- /dev/null +++ b/docs/users-guide/conf.py @@ -0,0 +1,102 @@ +##============================================================================ +## 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. +##============================================================================ + +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = "The VTK-m User's Guide" +copyright = 'Kitware Inc., National Technology & Engineering Solutions of Sandia LLC, UT-Battelle LLC, Los Alamos National Security LLC' +author = 'Kenneth Moreland' +version = '@VTKm_VERSION_FULL@' +release = '@VTKm_VERSION_FULL@' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +# We provide some custom extensions in the _ext directory +import sys +sys.path.append('@CMAKE_CURRENT_SOURCE_DIR@/_ext') + +extensions = [ + 'sphinx.ext.autosectionlabel', + 'sphinx.ext.mathjax', + 'sphinx.ext.todo', + + # Extension available from https://breathe.readthedocs.io/en/stable/ + 'breathe', + + # Extension available from https://sphinx-themes.org/sample-sites/sphinx-rtd-theme/ + # Can be installed with `pip install sphinx-rtd-theme` + 'sphinx_rtd_theme', + + # Extension available from https://github.com/scikit-build/moderncmakedomain + # Can be installed with `pip install sphinxcontrib-moderncmakedomain` + 'sphinxcontrib.moderncmakedomain', + + # Extensions included in the _ext directory. + 'extract_examples', + 'fullref', + 'infoboxes', +] +# Note: there are some custom extensions at the bottom of this file. + +todo_include_todos = True + +numfig = True +autosectionlabel_prefix_document = True + +#templates_path = ['_templates'] +exclude_patterns = ['CMakeFiles', '*.cmake', '.DS_Store'] + +primary_domain = 'cpp' +highlight_language = 'cpp' + +numfig = True +numfig_format = { + 'figure': 'Figure %s', + 'table': 'Table %s', + 'code-block': 'Example %s', + 'section': '%s', +} + +today_fmt = '%B %d, %Y' + +rst_prolog = ''' +.. |VTKm| replace:: VTK‑m +.. |report-year| replace:: 2023 +.. |report-number| replace:: ORNL/TM-2023/2863 +''' + +breathe_projects = { 'vtkm': '@doxygen_xml_output_dir@' } +breathe_default_project = 'vtkm' + +example_directory = '@example_directory@' +example_command_comment = '////' +example_language = 'cpp' + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +#html_theme = 'alabaster' +#html_theme = 'sphinxdoc' +#html_theme = 'bizstyle' +#html_theme = 'classic' +html_theme = 'sphinx_rtd_theme' +#html_static_path = ['_static'] + + +# -- Options for LaTeX output ------------------------------------------------- + +latex_toplevel_sectioning = 'part' diff --git a/docs/users-guide/examples/.clang-format b/docs/users-guide/examples/.clang-format new file mode 100644 index 000000000..c4430b8e6 --- /dev/null +++ b/docs/users-guide/examples/.clang-format @@ -0,0 +1,17 @@ +--- +# This configuration requires clang-format 3.8 or higher. +BasedOnStyle: Mozilla +AlignAfterOpenBracket: Align +AlignOperands: false +AlwaysBreakAfterReturnType: None +AlwaysBreakAfterDefinitionReturnType: None +BreakBeforeBraces: Allman +BinPackArguments: false +BinPackParameters: false +ColumnLimit: 89 +MaxEmptyLinesToKeep: 4 +Standard: Cpp11 +# This requires clang-format 4.0 (at least). +#FixNamespaceComments: true +ReflowComments: false +... diff --git a/docs/users-guide/examples/CMakeLists.txt b/docs/users-guide/examples/CMakeLists.txt new file mode 100644 index 000000000..c6375e843 --- /dev/null +++ b/docs/users-guide/examples/CMakeLists.txt @@ -0,0 +1,51 @@ +##============================================================================ +## 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. +##============================================================================ + +set(examples + GuideExampleCoreDataTypes.cxx + ) + +vtkm_unit_tests( + SOURCES ${examples} + ) + +# Special example that is an encapsulated program +# VTKm examples expects vtkm libraries to be namespaced with the prefix vtkm::. +# However as the examples are also built as just another part of the VTK-m code +# those prefix are not added to the targets (This happens during the +# installation). To workaround this issue here, we create IMPORTED libs linking +# to the vtkm libraries used by the examples with expected the vtkm:: prefix. +vtkm_module_get_list(module_list) +foreach(tgt IN LISTS module_list) + if(TARGET ${tgt}) + # The reason of creating this phony IMPORTED libraries instead of making + # ALIAS libraries is that ALIAS libraries are GLOBAL whereas IMPORTED are + # local at the directory level where they are created. We do not want these + # phony targets to be visible outside of the example directory. + vtkm_target_mangle(tgt_name_mangled ${tgt}) + add_library("vtkm::${tgt_name_mangled}" INTERFACE IMPORTED) + target_link_libraries("vtkm::${tgt_name_mangled}" INTERFACE ${tgt}) + endif() +endforeach() +add_library(vtkm::filter INTERFACE IMPORTED) +target_link_libraries(vtkm::filter INTERFACE vtkm_filter) + +#add the directory that contains the VTK-m config file to the cmake +#path so that our examples can find VTK-m +set(CMAKE_PREFIX_PATH ${VTKm_BINARY_DIR}/${VTKm_INSTALL_CONFIG_DIR}) + +include(VTKmQuickStart.cmake) +set_target_properties(VTKmQuickStart + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${VTKm_EXECUTABLE_OUTPUT_PATH} + ) +add_test(NAME VTKmQuickStart + COMMAND VTKmQuickStart ${VTKm_SOURCE_DIR}/data/data/unstructured/cow.vtk + ) diff --git a/docs/users-guide/examples/GuideExampleCoreDataTypes.cxx b/docs/users-guide/examples/GuideExampleCoreDataTypes.cxx new file mode 100644 index 000000000..a98960b44 --- /dev/null +++ b/docs/users-guide/examples/GuideExampleCoreDataTypes.cxx @@ -0,0 +1,329 @@ +//============================================================================ +// 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. +//============================================================================ + +#include <vtkm/Range.h> +#include <vtkm/Types.h> +#include <vtkm/VecVariable.h> + +#include <vtkm/testing/Testing.h> + +namespace +{ + +void SimpleVectorTypes() +{ + //// + //// BEGIN-EXAMPLE SimpleVectorTypes + //// + vtkm::Vec2f A(1); // A is (1, 1) + A[1] = 3; // A is (1, 3) now + vtkm::Vec2f B = { 4, 5 }; // B is (4, 5) + vtkm::Vec2f C = A + B; // C is (5, 8) + vtkm::FloatDefault manhattanDistance = C[0] + C[1]; + //// + //// END-EXAMPLE SimpleVectorTypes + //// + + VTKM_TEST_ASSERT(test_equal(A, vtkm::make_Vec(1, 3))); + VTKM_TEST_ASSERT(test_equal(B, vtkm::make_Vec(4, 5))); + VTKM_TEST_ASSERT(test_equal(C, vtkm::make_Vec(5, 8))); + VTKM_TEST_ASSERT(test_equal(manhattanDistance, 13)); +} + +void CreatingVectorTypes() +{ + //// + //// BEGIN-EXAMPLE CreatingVectorTypes + //// + vtkm::Vec3f_32 A{ 1 }; // A is (1, 1, 1) + A[1] = 2; // A is now (1, 2, 1) + vtkm::Vec3f_32 B{ 1, 2, 3 }; // B is (1, 2, 3) + vtkm::Vec3f_32 C = vtkm::make_Vec(3, 4, 5); // C is (3, 4, 5) + // Longer Vecs specified with template. + vtkm::Vec<vtkm::Float32, 5> D{ 1 }; // D is (1, 1, 1, 1, 1) + vtkm::Vec<vtkm::Float32, 5> E{ 1, 2, 3, 4, 5 }; // E is (1, 2, 3, 4, 5) + vtkm::Vec<vtkm::Float32, 5> F = { 6, 7, 8, 9, 10 }; // F is (6, 7, 8, 9, 10) + auto G = vtkm::make_Vec(1, 3, 5, 7, 9); // G is (1, 3, 5, 7, 9) + //// + //// END-EXAMPLE CreatingVectorTypes + //// + + VTKM_TEST_ASSERT((A[0] == 1) && (A[1] == 2) && (A[2] == 1), + "A is different than expected."); + VTKM_TEST_ASSERT((B[0] == 1) && (B[1] == 2) && (B[2] == 3), + "B is different than expected."); + VTKM_TEST_ASSERT((C[0] == 3) && (C[1] == 4) && (C[2] == 5), + "C is different than expected."); + VTKM_TEST_ASSERT((D[0] == 1) && (D[1] == 1) && (D[2] == 1) && (D[3] == 1) && + (D[4] == 1), + "D is different than expected."); + VTKM_TEST_ASSERT((E[0] == 1) && (E[1] == 2) && (E[2] == 3) && (E[3] == 4) && + (E[4] == 5), + "E is different than expected."); + VTKM_TEST_ASSERT((F[0] == 6) && (F[1] == 7) && (F[2] == 8) && (F[3] == 9) && + (F[4] == 10), + "F is different than expected."); + VTKM_TEST_ASSERT((G[0] == 1) && (G[1] == 3) && (G[2] == 5) && (G[3] == 7) && + (G[4] == 9), + "F is different than expected."); +} + +void VectorOperations() +{ + //// + //// BEGIN-EXAMPLE VectorOperations + //// + vtkm::Vec3f_32 A{ 1, 2, 3 }; + vtkm::Vec3f_32 B{ 4, 5, 6.5 }; + vtkm::Vec3f_32 C = A + B; // C is (5, 7, 9.5) + vtkm::Vec3f_32 D = 2.0f * C; // D is (10, 14, 19) + vtkm::Float32 s = vtkm::Dot(A, B); // s is 33.5 + bool b1 = (A == B); // b1 is false + bool b2 = (A == vtkm::make_Vec(1, 2, 3)); // b2 is true + + vtkm::Vec<vtkm::Float32, 5> E{ 1, 2.5, 3, 4, 5 }; // E is (1, 2, 3, 4, 5) + vtkm::Vec<vtkm::Float32, 5> F{ 6, 7, 8.5, 9, 10.5 }; // F is (6, 7, 8, 9, 10) + vtkm::Vec<vtkm::Float32, 5> G = E + F; // G is (7, 9.5, 11.5, 13, 15.5) + bool b3 = (E == F); // b3 is false + bool b4 = (G == vtkm::make_Vec(7.f, 9.5f, 11.5f, 13.f, 15.5f)); // b4 is true + //// + //// END-EXAMPLE VectorOperations + //// + + VTKM_TEST_ASSERT(test_equal(C, vtkm::Vec3f_32(5, 7, 9.5)), "C is wrong"); + VTKM_TEST_ASSERT(test_equal(D, vtkm::Vec3f_32(10, 14, 19)), "D is wrong"); + VTKM_TEST_ASSERT(test_equal(s, 33.5), "s is wrong"); + VTKM_TEST_ASSERT(!b1, "b1 is wrong"); + VTKM_TEST_ASSERT(b2, "b2 is wrong"); + VTKM_TEST_ASSERT(!b3, "b3 is wrong"); + VTKM_TEST_ASSERT(b4, "b4 is wrong"); +} + +void EquilateralTriangle() +{ + //// + //// BEGIN-EXAMPLE EquilateralTriangle + //// + vtkm::Vec<vtkm::Vec2f_32, 3> equilateralTriangle = { { 0.0f, 0.0f }, + { 1.0f, 0.0f }, + { 0.5f, 0.8660254f } }; + //// + //// END-EXAMPLE EquilateralTriangle + //// + + vtkm::Float32 edgeLengthSqr = 1.0; + vtkm::Vec<vtkm::Vec2f_32, 3> edges(equilateralTriangle[1] - equilateralTriangle[0], + equilateralTriangle[2] - equilateralTriangle[0], + equilateralTriangle[2] - equilateralTriangle[1]); + VTKM_TEST_ASSERT(test_equal(vtkm::Dot(edges[0], edges[0]), edgeLengthSqr), + "Bad edge length."); + VTKM_TEST_ASSERT(test_equal(vtkm::Dot(edges[1], edges[1]), edgeLengthSqr), + "Bad edge length."); + VTKM_TEST_ASSERT(test_equal(vtkm::Dot(edges[2], edges[2]), edgeLengthSqr), + "Bad edge length."); +} + +//// +//// BEGIN-EXAMPLE VecCExample +//// +VTKM_EXEC vtkm::VecCConst<vtkm::IdComponent> HexagonIndexToIJK(vtkm::IdComponent index) +{ + static const vtkm::IdComponent HexagonIndexToIJKTable[8][3] = { + { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 }, + { 0, 0, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 0, 1, 1 } + }; + + return vtkm::make_VecC(HexagonIndexToIJKTable[index], 3); +} + +VTKM_EXEC vtkm::IdComponent HexagonIJKToIndex(vtkm::VecCConst<vtkm::IdComponent> ijk) +{ + static const vtkm::IdComponent HexagonIJKToIndexTable[2][2][2] = { { + // i=0 + { 0, 4 }, // j=0 + { 3, 7 }, // j=1 + }, + { + // i=1 + { 1, 5 }, // j=0 + { 2, 6 }, // j=1 + } }; + + return HexagonIJKToIndexTable[ijk[0]][ijk[1]][ijk[2]]; +} +//// +//// END-EXAMPLE VecCExample +//// + +//// +//// BEGIN-EXAMPLE VecVariableExample +//// +vtkm::VecVariable<vtkm::IdComponent, 4> HexagonShortestPath(vtkm::IdComponent startPoint, + vtkm::IdComponent endPoint) +{ + vtkm::VecCConst<vtkm::IdComponent> startIJK = HexagonIndexToIJK(startPoint); + vtkm::VecCConst<vtkm::IdComponent> endIJK = HexagonIndexToIJK(endPoint); + + vtkm::IdComponent3 currentIJK; + startIJK.CopyInto(currentIJK); + + vtkm::VecVariable<vtkm::IdComponent, 4> path; + path.Append(startPoint); + for (vtkm::IdComponent dimension = 0; dimension < 3; dimension++) + { + if (currentIJK[dimension] != endIJK[dimension]) + { + currentIJK[dimension] = endIJK[dimension]; + path.Append(HexagonIJKToIndex(currentIJK)); + } + } + + return path; +} +//// +//// END-EXAMPLE VecVariableExample +//// + +void UsingVecCAndVecVariable() +{ + vtkm::VecVariable<vtkm::IdComponent, 4> path; + + path = HexagonShortestPath(2, 2); + VTKM_TEST_ASSERT(test_equal(path, vtkm::Vec<vtkm::IdComponent, 1>(2)), "Bad path"); + + path = HexagonShortestPath(0, 7); + VTKM_TEST_ASSERT(test_equal(path, vtkm::IdComponent3(0, 3, 7)), "Bad path"); + + path = HexagonShortestPath(5, 3); + VTKM_TEST_ASSERT(test_equal(path, vtkm::IdComponent4(5, 4, 7, 3)), "Bad path"); +} + +void UsingRange() +{ + //// + //// BEGIN-EXAMPLE UsingRange + //// + vtkm::Range range; // default constructor is empty range + bool b1 = range.IsNonEmpty(); // b1 is false + + range.Include(0.5); // range now is [0.5 .. 0.5] + bool b2 = range.IsNonEmpty(); // b2 is true + bool b3 = range.Contains(0.5); // b3 is true + bool b4 = range.Contains(0.6); // b4 is false + + range.Include(2.0); // range is now [0.5 .. 2] + bool b5 = range.Contains(0.5); // b3 is true + bool b6 = range.Contains(0.6); // b4 is true + + range.Include(vtkm::Range(-1, 1)); // range is now [-1 .. 2] + //// PAUSE-EXAMPLE + VTKM_TEST_ASSERT(test_equal(range, vtkm::Range(-1, 2)), "Bad range"); + //// RESUME-EXAMPLE + + range.Include(vtkm::Range(3, 4)); // range is now [-1 .. 4] + //// PAUSE-EXAMPLE + VTKM_TEST_ASSERT(test_equal(range, vtkm::Range(-1, 4)), "Bad range"); + //// RESUME-EXAMPLE + + vtkm::Float64 lower = range.Min; // lower is -1 + vtkm::Float64 upper = range.Max; // upper is 4 + vtkm::Float64 length = range.Length(); // length is 5 + vtkm::Float64 center = range.Center(); // center is 1.5 + //// + //// END-EXAMPLE UsingRange + //// + + VTKM_TEST_ASSERT(!b1, "Bad non empty."); + VTKM_TEST_ASSERT(b2, "Bad non empty."); + VTKM_TEST_ASSERT(b3, "Bad contains."); + VTKM_TEST_ASSERT(!b4, "Bad contains."); + VTKM_TEST_ASSERT(b5, "Bad contains."); + VTKM_TEST_ASSERT(b6, "Bad contains."); + + VTKM_TEST_ASSERT(test_equal(lower, -1), "Bad lower"); + VTKM_TEST_ASSERT(test_equal(upper, 4), "Bad upper"); + VTKM_TEST_ASSERT(test_equal(length, 5), "Bad length"); + VTKM_TEST_ASSERT(test_equal(center, 1.5), "Bad center"); +} + +void UsingBounds() +{ + //// + //// BEGIN-EXAMPLE UsingBounds + //// + vtkm::Bounds bounds; // default constructor makes empty + bool b1 = bounds.IsNonEmpty(); // b1 is false + + bounds.Include(vtkm::make_Vec(0.5, 2.0, 0.0)); // bounds contains only + // the point [0.5, 2, 0] + bool b2 = bounds.IsNonEmpty(); // b2 is true + bool b3 = bounds.Contains(vtkm::make_Vec(0.5, 2.0, 0.0)); // b3 is true + bool b4 = bounds.Contains(vtkm::make_Vec(1, 1, 1)); // b4 is false + bool b5 = bounds.Contains(vtkm::make_Vec(0, 0, 0)); // b5 is false + + bounds.Include(vtkm::make_Vec(4, -1, 2)); // bounds is region [0.5 .. 4] in X, + // [-1 .. 2] in Y, + // and [0 .. 2] in Z + //// PAUSE-EXAMPLE + VTKM_TEST_ASSERT(test_equal(bounds, vtkm::Bounds(0.5, 4, -1, 2, 0, 2)), ""); + //// RESUME-EXAMPLE + bool b6 = bounds.Contains(vtkm::make_Vec(0.5, 2.0, 0.0)); // b6 is true + bool b7 = bounds.Contains(vtkm::make_Vec(1, 1, 1)); // b7 is true + bool b8 = bounds.Contains(vtkm::make_Vec(0, 0, 0)); // b8 is false + + vtkm::Bounds otherBounds(vtkm::make_Vec(0, 0, 0), vtkm::make_Vec(3, 3, 3)); + // otherBounds is region [0 .. 3] in X, Y, and Z + bounds.Include(otherBounds); // bounds is now region [0 .. 4] in X, + // [-1 .. 3] in Y, + // and [0 .. 3] in Z + //// PAUSE-EXAMPLE + VTKM_TEST_ASSERT(test_equal(bounds, vtkm::Bounds(0, 4, -1, 3, 0, 3)), ""); + //// RESUME-EXAMPLE + + vtkm::Vec3f_64 lower(bounds.X.Min, bounds.Y.Min, bounds.Z.Min); + // lower is [0, -1, 0] + vtkm::Vec3f_64 upper(bounds.X.Max, bounds.Y.Max, bounds.Z.Max); + // upper is [4, 3, 3] + + vtkm::Vec3f_64 center = bounds.Center(); // center is [2, 1, 1.5] + //// + //// END-EXAMPLE UsingBounds + //// + + VTKM_TEST_ASSERT(!b1, "Bad non empty."); + VTKM_TEST_ASSERT(b2, "Bad non empty."); + VTKM_TEST_ASSERT(b3, "Bad contains."); + VTKM_TEST_ASSERT(!b4, "Bad contains."); + VTKM_TEST_ASSERT(!b5, "Bad contains."); + VTKM_TEST_ASSERT(b6, "Bad contains."); + VTKM_TEST_ASSERT(b7, "Bad contains."); + VTKM_TEST_ASSERT(!b8, "Bad contains."); + VTKM_TEST_ASSERT(test_equal(lower, vtkm::make_Vec(0, -1, 0)), ""); + VTKM_TEST_ASSERT(test_equal(upper, vtkm::make_Vec(4, 3, 3)), ""); + VTKM_TEST_ASSERT(test_equal(center, vtkm::make_Vec(2.0, 1.0, 1.5)), ""); +} + +void Test() +{ + SimpleVectorTypes(); + CreatingVectorTypes(); + VectorOperations(); + EquilateralTriangle(); + UsingVecCAndVecVariable(); + UsingRange(); + UsingBounds(); +} + +} // anonymous namespace + +int GuideExampleCoreDataTypes(int argc, char* argv[]) +{ + return vtkm::testing::Testing::Run(Test, argc, argv); +} diff --git a/docs/users-guide/examples/VTKmQuickStart.cmake b/docs/users-guide/examples/VTKmQuickStart.cmake new file mode 100644 index 000000000..7c680f097 --- /dev/null +++ b/docs/users-guide/examples/VTKmQuickStart.cmake @@ -0,0 +1,25 @@ +##============================================================================= +## +## 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. +## +##============================================================================= + +#### +#### BEGIN-EXAMPLE QuickStartCMakeLists.txt +#### +cmake_minimum_required(VERSION 3.13) +project(VTKmQuickStart CXX) + +find_package(VTKm REQUIRED) + +add_executable(VTKmQuickStart VTKmQuickStart.cxx) +target_link_libraries(VTKmQuickStart vtkm::filter vtkm::rendering) +#### +#### END-EXAMPLE QuickStartCMakeLists.txt +#### diff --git a/docs/users-guide/examples/VTKmQuickStart.cxx b/docs/users-guide/examples/VTKmQuickStart.cxx new file mode 100644 index 000000000..2b1f9ddcf --- /dev/null +++ b/docs/users-guide/examples/VTKmQuickStart.cxx @@ -0,0 +1,100 @@ +//============================================================================= +// +// 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. +// +//============================================================================= + +//// +//// BEGIN-EXAMPLE VTKmQuickStart +//// +#include <vtkm/cont/Initialize.h> + +#include <vtkm/io/VTKDataSetReader.h> + +#include <vtkm/filter/mesh_info/MeshQuality.h> + +#include <vtkm/rendering/Actor.h> +#include <vtkm/rendering/CanvasRayTracer.h> +#include <vtkm/rendering/MapperRayTracer.h> +#include <vtkm/rendering/Scene.h> +#include <vtkm/rendering/View3D.h> + +//// +//// BEGIN-EXAMPLE VTKmQuickStartInitialize +//// +int main(int argc, char* argv[]) +{ + vtkm::cont::Initialize(argc, argv); + //// + //// END-EXAMPLE VTKmQuickStartInitialize + //// + + if (argc != 2) + { + std::cerr << "USAGE: " << argv[0] << " <file.vtk>" << std::endl; + return 1; + } + + // Read in a file specified in the first command line argument. + //// + //// BEGIN-EXAMPLE VTKmQuickStartReadFile + //// + vtkm::io::VTKDataSetReader reader(argv[1]); + vtkm::cont::DataSet inData = reader.ReadDataSet(); + //// + //// END-EXAMPLE VTKmQuickStartReadFile + //// + //// PAUSE-EXAMPLE + inData.PrintSummary(std::cout); + //// RESUME-EXAMPLE + + // Run the data through the elevation filter. + //// + //// BEGIN-EXAMPLE VTKmQuickStartFilter + //// + vtkm::filter::mesh_info::MeshQuality cellArea( + vtkm::filter::mesh_info::CellMetric::Area); + vtkm::cont::DataSet outData = cellArea.Execute(inData); + //// + //// END-EXAMPLE VTKmQuickStartFilter + //// + + // Render an image and write it out to a file. + //// + //// BEGIN-EXAMPLE VTKmQuickStartRender + //// + //// LABEL scene-start + vtkm::rendering::Actor actor( + outData.GetCellSet(), outData.GetCoordinateSystem(), outData.GetField("area")); + + vtkm::rendering::Scene scene; + //// LABEL scene-end + scene.AddActor(actor); + + vtkm::rendering::MapperRayTracer mapper; + + vtkm::rendering::CanvasRayTracer canvas(1280, 1024); + + //// LABEL view + vtkm::rendering::View3D view(scene, mapper, canvas); + + //// LABEL paint + view.Paint(); + + //// LABEL save + view.SaveAs("image.png"); + //// + //// END-EXAMPLE VTKmQuickStartRender + //// + + return 0; +} +//// +//// END-EXAMPLE VTKmQuickStart +//// diff --git a/docs/users-guide/genindex.rst b/docs/users-guide/genindex.rst new file mode 100644 index 000000000..62def08a7 --- /dev/null +++ b/docs/users-guide/genindex.rst @@ -0,0 +1,7 @@ +============================== +Index +============================== + +.. + This is placeholder to put the geneated index in the table of context. + https://stackoverflow.com/questions/36235578/how-can-i-include-the-genindex-in-a-sphinx-toc diff --git a/docs/users-guide/images/CMakeGUI.png b/docs/users-guide/images/CMakeGUI.png new file mode 100644 index 000000000..be694d334 --- /dev/null +++ b/docs/users-guide/images/CMakeGUI.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9c8577c28da9c422e9c1b3eb4e2b86502237b4e28de7f89d9fde4daac551e35a +size 45824 diff --git a/docs/users-guide/images/CMakeGUIBlank.png b/docs/users-guide/images/CMakeGUIBlank.png new file mode 100644 index 000000000..2adfefdfa --- /dev/null +++ b/docs/users-guide/images/CMakeGUIBlank.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:569d90224e67af812d99bf597cab96b06bd75b0f6e49b31a44db6d0dd2fcf9d8 +size 17473 diff --git a/docs/users-guide/images/CMakeGUIBoth.png b/docs/users-guide/images/CMakeGUIBoth.png new file mode 100644 index 000000000..e7690461e --- /dev/null +++ b/docs/users-guide/images/CMakeGUIBoth.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:09869e65d5b2e9c8e5f4b6ade05a07ccdca2d631afc4dba71182bd488d4af3b1 +size 59566 diff --git a/docs/users-guide/images/DOELogo.pdf b/docs/users-guide/images/DOELogo.pdf new file mode 100644 index 000000000..4fd70443d --- /dev/null +++ b/docs/users-guide/images/DOELogo.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:94c519604ede743c346bbbe6ad327afd994cfc66dd2a7044fac54a99be72c683 +size 765497 diff --git a/docs/users-guide/images/DOELogo.png b/docs/users-guide/images/DOELogo.png new file mode 100644 index 000000000..f9b98895d --- /dev/null +++ b/docs/users-guide/images/DOELogo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fe656884ba6a65c9241fe4ac1fdf0342f1ff0616efc14e745d417ccdd151c9fc +size 17966 diff --git a/docs/users-guide/images/KitwareLogo-large.png b/docs/users-guide/images/KitwareLogo-large.png new file mode 100644 index 000000000..a9da65e3c --- /dev/null +++ b/docs/users-guide/images/KitwareLogo-large.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:abce0e365bdd079734931ff8cb50dc9e8a0b99fa58e5f7c28b7ccfd1fd36a48d +size 134860 diff --git a/docs/users-guide/images/KitwareLogo.png b/docs/users-guide/images/KitwareLogo.png new file mode 100644 index 000000000..7d2c295fd --- /dev/null +++ b/docs/users-guide/images/KitwareLogo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d9933aa10a88c653b9306ef79f9082e7fbb33065668b44aa7b46f677dd93f74 +size 18581 diff --git a/docs/users-guide/images/LANLLogo-large.png b/docs/users-guide/images/LANLLogo-large.png new file mode 100644 index 000000000..d8e912ea6 --- /dev/null +++ b/docs/users-guide/images/LANLLogo-large.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ba8be9278d541b02ac603f0b6f68bbc2d1b34f6e9aba82881200d09c919f74c +size 42684 diff --git a/docs/users-guide/images/LANLLogo.png b/docs/users-guide/images/LANLLogo.png new file mode 100644 index 000000000..b16933051 --- /dev/null +++ b/docs/users-guide/images/LANLLogo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89d1e524f9bfcdbb950cfe96c23e13c207dbbde6ee45d2aab773ebf020e99ba8 +size 13394 diff --git a/docs/users-guide/images/LogoSpacing.png b/docs/users-guide/images/LogoSpacing.png new file mode 100644 index 000000000..173015ff0 --- /dev/null +++ b/docs/users-guide/images/LogoSpacing.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b6613cc596bfe2558c7cb491c8c0bd63e5bb4cace59b5c1b90beed43ffb81fe3 +size 1397 diff --git a/docs/users-guide/images/MCCompareCuda.pdf b/docs/users-guide/images/MCCompareCuda.pdf new file mode 100644 index 000000000..6a4035ffb --- /dev/null +++ b/docs/users-guide/images/MCCompareCuda.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e6919ed64154fb791fa9f7f6a7841314effcea456fed0427946c294416a95abf +size 89920 diff --git a/docs/users-guide/images/MCCompareCuda.png b/docs/users-guide/images/MCCompareCuda.png new file mode 100644 index 000000000..b9e1d7474 --- /dev/null +++ b/docs/users-guide/images/MCCompareCuda.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e426c1c2360cd131799eb949a1c4b52752bd5eb64f69b701301b1a3e11711a6c +size 171944 diff --git a/docs/users-guide/images/MCCompareVTKm.pdf b/docs/users-guide/images/MCCompareVTKm.pdf new file mode 100644 index 000000000..d1adb9bde --- /dev/null +++ b/docs/users-guide/images/MCCompareVTKm.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5f98d23244b645f4301b6717394cd3a95c3ec60d980081b1519006cdab75cee6 +size 54147 diff --git a/docs/users-guide/images/MCCompareVTKm.png b/docs/users-guide/images/MCCompareVTKm.png new file mode 100644 index 000000000..2311f1f38 --- /dev/null +++ b/docs/users-guide/images/MCCompareVTKm.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f2dc062c33b7767c08d45d177a573af1ff13ccd2d41a87ccd2b6538336763781 +size 108739 diff --git a/docs/users-guide/images/ORNLLogo-large.png b/docs/users-guide/images/ORNLLogo-large.png new file mode 100644 index 000000000..b1bee7c4a --- /dev/null +++ b/docs/users-guide/images/ORNLLogo-large.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cee96e1f16e817b823768d525ff8b9faa388b2054fa0a9f7e2688134cc473fde +size 77653 diff --git a/docs/users-guide/images/ORNLLogo.png b/docs/users-guide/images/ORNLLogo.png new file mode 100644 index 000000000..03162ee95 --- /dev/null +++ b/docs/users-guide/images/ORNLLogo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c5af23e99d2f3eadafcd8d7f3f907dfb21c9e6533eff73870c38d561527ff273 +size 15328 diff --git a/docs/users-guide/images/SandiaLogo.pdf b/docs/users-guide/images/SandiaLogo.pdf new file mode 100644 index 000000000..2ea8f28ca --- /dev/null +++ b/docs/users-guide/images/SandiaLogo.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:10669565c1f742c0b9e916d6f73d614b721e78752496a88fe5ef9ca579c7f6a9 +size 806559 diff --git a/docs/users-guide/images/SandiaLogo.png b/docs/users-guide/images/SandiaLogo.png new file mode 100644 index 000000000..d22dfa3e5 --- /dev/null +++ b/docs/users-guide/images/SandiaLogo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2e63593dcf59541ebedacaeb86680bb334e93089ba17dcda80e9602ce4a6fe2b +size 7759 diff --git a/docs/users-guide/index.rst b/docs/users-guide/index.rst new file mode 100644 index 000000000..6e481ee1c --- /dev/null +++ b/docs/users-guide/index.rst @@ -0,0 +1,56 @@ +.. title page + +============================== +The VTK-m User's Guide +============================== + +.. todo:: Hide TODOs for release documentation. + +| **The VTK-m User's Guide** +| Version |version| + +Kenneth Moreland + +with special contributions from +Vicente Bolea, +Hank Childs, +Nickolas Davis, +Mark Kim, +James Kress, +Matthew Letter, +Li-Ta Lo, +Robert Maynard, +Sujin Philip, +David Pugmire, +Nick Thompson, +Allison Vacanti, +Abhishek Yenpure, +and the |VTKm| community + +Moreland, K. (|report-year|). *The VTK-m User's Guide*, Tech report |report-number|, Oak Ridge National Laboratory. + +.. centered:: Join the VTK-m Community at http://m.vtk.org. + +.. todo:: The centered directive is deprecated (https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-centered). Figure out how to add rst-class to center. + +.. toctree:: + :numbered: + :maxdepth: 2 + :caption: VTK-m User's Guide + + part-getting-started.rst + part-using.rst + part-developing.rst + part-advanced.rst + part-core.rst + part-appendix.rst + + + +.. + Indices and tables + ================== + + * :ref:`genindex` + * :ref:`modindex` + * :ref:`search` diff --git a/docs/users-guide/introduction.rst b/docs/users-guide/introduction.rst new file mode 100644 index 000000000..d36188836 --- /dev/null +++ b/docs/users-guide/introduction.rst @@ -0,0 +1,86 @@ +============================== +Introduction +============================== + +High-performance computing relies on ever finer threading. +Advances in processor technology include ever greater numbers of cores, hyperthreading, accelerators with integrated blocks of cores, and special vectorized instructions, all of which require more software parallelism to achieve peak performance. +Traditional visualization solutions cannot support this extreme level of concurrency. +Extreme scale systems require a new programming model and a fundamental change in how we design algorithms. +To address these issues we created |VTKm|: the visualization toolkit for multi-/many-core architectures. + +|VTKm| supports a number of algorithms and the ability to design further algorithms through a top-down design with an emphasis on extreme parallelism. +|VTKm| also provides support for finding and building links across topologies, making it possible to perform operations that determine manifold surfaces, interpolate generated values, and find adjacencies. +Although |VTKm| provides a simplified high-level interface for programming, its template-based code removes the overhead of abstraction. + +.. |MCCompareCuda| image:: images/MCCompareCuda.png + :width: 75px +.. |MCCompareVTKm| image:: images/MCCompareVTKm.png + :width: 75px + +.. table:: Comparison of Marching Cubes implementations. + :name: MCCompare + :widths: auto + :align: center + + +-----------------+-----------------+ + | CUDA SDK | |VTKm| | + +-----------------+-----------------+ + | 431 LOC | 265 LOC | + +-----------------+-----------------+ + | |MCCompareCuda| | |MCCompareVTKm| | + +-----------------+-----------------+ + +|VTKm| simplifies the development of parallel scientific visualization algorithms by providing a framework of supporting functionality that allows developers to focus on visualization operations. +Consider the listings in :numref:`MCCompare` that compares the size of the implementation for the Marching Cubes algorithm in |VTKm| with the equivalent reference implementation in the CUDA software development kit. +Because |VTKm| internally manages the parallel distribution of work and data, the |VTKm| implementation is shorter and easier to maintain. +Additionally, |VTKm| provides data abstractions not provided by other libraries that make code written in |VTKm| more versatile. + +------------------------------ +How to Use This Guide +------------------------------ + +This user's guide is organized into 5 parts to help guide novice to advanced users and to provide a convenient reference. +:partref:`part-getting-started:Getting Started` provides a brief overview of using |VTKm|. +This part provides instructions on building |VTKm| and some simple examples of using |VTKm|. +Users new to |VTKm| are well served to read through Part :partref:`part-getting-started:Getting Started` first to become acquainted with the basic concepts. + +The remaining parts, which provide detailed documentation of increasing complexity, have chapters that do not need to be read in detail. +Readers will likely find it useful to skip to specific topics of interest. + +:partref:`part-using:Using |VTKm|` dives deeper into the |VTKm| library. +It provides much more detail on the concepts introduced in :partref:`part-getting-started:Getting Started` and introduces new topics helpful to people who use |VTKm|'s existing algorithms. + +:partref:`part-developing:Developing Algorithms` documents how to use |VTKm|'s framework to develop new or custom visualization algorithms. +In this part we dive into the inner workings of filters and introduce the concept of a *worklet*, which is the base unit used to write a device-portable algorithm in |VTKm|. +:partref:`part-developing:Developing Algorithms` also documents many supporting functions that are helpful in implementing visualization algorithms. + +:partref:`part-advanced:Advanced Development` explores in more detail how |VTKm| manages memory and devices. +This information describes how to adapt |VTKm| to custom data structures and new devices. + +:partref:`part-core:Core Development` exposes the inner workings of |VTKm|. +These concepts allow you to design new algorithmic structures not already available in |VTKm|. + +.. ------------------------------ +.. Conventions Used in This Guide +.. ------------------------------ +.. +.. When documenting the |VTKm| API, the following conventions are used. +.. \begin{itemize} +.. \item Filenames are printed in a \textfilename{sans serif font}. +.. \item C++ code is printed in a \textcode{monospace font}. +.. \item Macros and namespaces from |VTKm| are printed in \textnamespace{red}. +.. \item Identifiers from |VTKm| are printed in \textidentifier{blue}. +.. \item Signatures, described in Chapter \ref{chap:SimpleWorklets}, and the +.. tags used in them are printed in \textsignature{green}. +.. \end{itemize} +.. +.. This guide provides actual code samples throughout its discussions to +.. demonstrate their use. These examples are all valid code that can be +.. compiled and used although it is often the case that code snippets are +.. provided. In such cases, the code must be placed in a larger context. + +.. didyouknow:: + In this guide we periodically use these **Did you know?** boxes to provide additional information related to the topic at hand. + +.. commonerrors:: + **Common Errors** blocks are used to highlight some of the common problems or complications you might encounter when dealing with the topic of discussion. diff --git a/docs/users-guide/license.rst b/docs/users-guide/license.rst new file mode 100644 index 000000000..567c3cae6 --- /dev/null +++ b/docs/users-guide/license.rst @@ -0,0 +1,9 @@ +============================== +License +============================== + +.. include:: ../../LICENSE.txt + :start-line: 3 + :end-before: ============================== + +All product names mentioned herein are the trademarks of their respective owners. diff --git a/docs/users-guide/part-advanced.rst b/docs/users-guide/part-advanced.rst new file mode 100644 index 000000000..9017faab1 --- /dev/null +++ b/docs/users-guide/part-advanced.rst @@ -0,0 +1,3 @@ +============================== +Advanced Development +============================== diff --git a/docs/users-guide/part-appendix.rst b/docs/users-guide/part-appendix.rst new file mode 100644 index 000000000..599492c10 --- /dev/null +++ b/docs/users-guide/part-appendix.rst @@ -0,0 +1,12 @@ +============================== +Appendix +============================== + +.. todolist:: + +.. toctree:: + :maxdepth: 2 + + acknowledgements.rst + license.rst + genindex.rst diff --git a/docs/users-guide/part-core.rst b/docs/users-guide/part-core.rst new file mode 100644 index 000000000..36707a592 --- /dev/null +++ b/docs/users-guide/part-core.rst @@ -0,0 +1,3 @@ +============================== +Core Development +============================== diff --git a/docs/users-guide/part-developing.rst b/docs/users-guide/part-developing.rst new file mode 100644 index 000000000..4a1a0dc5b --- /dev/null +++ b/docs/users-guide/part-developing.rst @@ -0,0 +1,3 @@ +============================== +Developing Algorithms +============================== diff --git a/docs/users-guide/part-getting-started.rst b/docs/users-guide/part-getting-started.rst new file mode 100644 index 000000000..ee1549885 --- /dev/null +++ b/docs/users-guide/part-getting-started.rst @@ -0,0 +1,10 @@ +============================== +Getting Started +============================== + +.. toctree:: + :maxdepth: 2 + + introduction.rst + building.rst + quick-start.rst diff --git a/docs/users-guide/part-using.rst b/docs/users-guide/part-using.rst new file mode 100644 index 000000000..91f3bfe65 --- /dev/null +++ b/docs/users-guide/part-using.rst @@ -0,0 +1,8 @@ +============================== +Using |VTKm| +============================== + +.. toctree:: + :maxdepth: 2 + + base-types.rst diff --git a/docs/users-guide/quick-start.rst b/docs/users-guide/quick-start.rst new file mode 100644 index 000000000..1d3858ac6 --- /dev/null +++ b/docs/users-guide/quick-start.rst @@ -0,0 +1,173 @@ +============================== +Quick Start +============================== + +In this chapter we go through the steps to create a simple program that uses |VTKm|. +This "hello world" example presents only the bare minimum of features available. +The remainder of this book documents dives into much greater detail. + +We will call the example program we are building :file:`VTKmQuickStart`. +It will demonstrate reading data from a file, processing the data with a filter, and rendering an image of the data. +Readers who are less interested in an explanation and are more interested in browsing some code can skip to :secref:`quick-start:The Full Example`. + +------------------------------ +Initialize +------------------------------ + +.. index:: initialization + +The first step to using |VTKm| is to initialize the library. +Although initializing |VTKm| is *optional*, it is recommend to allow |VTKm| to configure devices and logging. +Initialization is done by calling the :func:`vtkm::cont::Initialize` function. +The ``Initialize`` function is defined in the :file:`vtkm/cont/Initialize.h` header file. + +``Initialize`` takes the ``argc`` and ``argv`` arguments that are passed to the ``main`` function of your program, find any command line arguments relevant to |VTKm|, and remove them from the list to make further command line argument processing easier. + +.. load-example:: VTKmQuickStartInitialize + :file: VTKmQuickStart.cxx + :caption: Initializing |VTKm|. + +.. todo:: Uncomment and add cross reference. + +.. + ``Initialize`` has many options to customize command line argument processing. + See Chapter \ref{chap:Initialization} for more details. + +.. didyouknow:: + Don't have access to ``argc`` and ``argv``? + No problem. + You can call :func:`vtkm::cont::Initialize` with no arguments. + + +------------------------------ +Reading a File +------------------------------ + +.. index:: + single: file I/O ; read + single: read file + +|VTKm| comes with a simple I/O library that can read and write files in VTK legacy format. +These files have a :file:`.vtk` extension. + +VTK legacy files can be read using the :class:`vtkm::io::VTKDataSetReader` object, which is declared in the :file:`vtkm/io/VTKDataSetReader.h` header file. +The object is constructed with a string specifying the filename (which for this example we will get from the command line). +The data is then read in by calling the :member:`vtkm::io::VTKDataSetReader::ReadDataSet` method. + +.. load-example:: VTKmQuickStartReadFile + :file: VTKmQuickStart.cxx + :caption: Reading data from a VTK legacy file. + +.. todo:: Uncomment and cross reference. + +.. + The ``ReadDataSet`` method returns the data in a :class:`vtkm::cont::DataSet` object. + The structure and features of a ``DataSet`` object is described in Chapter \ref{chap:DataSet}. + For the purposes of this quick start, we will treat ``DataSet`` as a mostly opaque object that gets passed to and from operations in |VTKm|. + + More information about |VTKm|'s file readers and writers can be found in Chapter \ref{chap:FileIO}. + + +------------------------------ +Running a Filter +------------------------------ + +.. index:: filter + +Algorithms in |VTKm| are encapsulated in units called *filters*. +A filter takes in a ``DataSet``, processes it, and returns a new ``DataSet``. +The returned ``DataSet`` often, but not always, contains data inherited from the source data. + +.. todo:: Fix cross reference to Running Filters. + +|VTKm| comes with many filters, which are documented in Chapter \ref{chap:RunningFilters}. +For this example, we will demonstrate the use of the :class:`vtkm::filter::MeshQuality` filter, which is defined in the :file:`vtkm/filter/MeshQuality.h` header file. +The ``MeshQuality`` filter will compute for each cell in the input data will compute a quantity representing some metric of the cell's shape. +Several metrics are available, and in this example we will find the area of each cell. + +.. todo:: Fix cross reference to MeshQuality. + +Like all filters, ``MeshQuality`` contains an ``Execute`` method that takes an input ``DataSet`` and produces an output ``DataSet``. +It also has several methods used to set up the parameters of the execution. +Section \ref{sec:MeshQuality} provides details on all the options of ``MeshQuality``. +Suffice it to say that in this example we instruct the filter to find the area of each cell, which it will output to a field named ``area``. + +.. load-example:: VTKmQuickStartFilter + :file: VTKmQuickStart.cxx + :caption: Running a filter. + + +------------------------------ +Rendering an Image +------------------------------ + +.. index:: rendering + +Although it is possible to leverage external rendering systems, |VTKm| comes with its own self-contained image rendering algorithms. +These rendering classes are completely implemented with the parallel features provided by |VTKm|, so using rendering in |VTKm| does not require any complex library dependencies. + +.. todo:: Fix cross reference to rendering chapter. + +Even a simple rendering scene requires setting up several parameters to establish what is to be featured in the image including what data should be rendered, how that data should be represented, where objects should be placed in space, and the qualities of the image to generate. +Consequently, setting up rendering in |VTKm| involves many steps. +Chapter \ref{chap:Rendering} goes into much detail on the ways in which a rendering scene is specified. +For now, we just briefly present some boilerplate to achieve a simple rendering. + +.. load-example:: VTKmQuickStartRender + :file: VTKmQuickStart.cxx + :caption: Rendering data. + +.. index:: + single: scene + single: actor + +The first step in setting up a render is to create a *scene*. +A scene comprises some number of *actors*, which represent some data to be rendered in some location in space. +In our case we only have one ``DataSet`` to render, so we simply create a single actor and add it to a scene as shown in :exlineref:`Example {number} lines {line}<VTKmQuickStartRender:scene-start>` :exlineref:`-- %s<VTKmQuickStartRender:scene-end>`. + +.. index:: + single: view + single: mapper + single: canvas + +The second step in setting up a render is to create a *view*. +The view comprises the aforementioned scene, a *mapper*, which describes how the data are to be rendered, and a *canvas*, which holds the image buffer and other rendering context. +The view is created in :exlineref:`VTKmQuickStartRender:view`. +The image generation is then performed by calling :member:`vtkm::rendering::View::Paint` on the view object (:exlineref:`VTKmQuickStartRender:paint`). +However, the rendering done by |VTKm|'s rendering classes is performed offscreen, which means that the result does not appear on your computer's monitor. +The easiest way to see the image is to save it to an image file using the :member:`vtkm::rendering::View::SaveAs` method (:exlineref:`VTKmQuickStartRender:save`). + + +------------------------------ +The Full Example +------------------------------ + +Putting together the examples from the previous sections, here is a complete program for reading, processing, and rendering data with |VTKm|. + +.. load-example:: VTKmQuickStart + :file: VTKmQuickStart.cxx + :caption: Simple example of using |VTKm|. + + +------------------------------ +Build Configuration +------------------------------ + +.. index:: CMakeLists.txt + +Now that we have the program listed in :numref:`ex:VTKmQuickStart`, we still need to compile it with the appropriate compilers and flags. +By far the easiest way to compile |VTKm| code is to use CMake. +CMake commands that can be used to link code to |VTKm| are discussed in :secref:`building:Linking to |VTKm|`. +The following example provides a minimal :file:`CMakeLists.txt` required to build this program. + +.. load-example:: QuickStartCMakeLists.txt + :file: VTKmQuickStart.cmake + :caption: :file:`CMakeLists.txt` to build a program using |VTKm|. + :language: cmake + :command-comment: #### + +The first two lines contain boilerplate for any :file:`CMakeLists.txt` file. +They all should declare the minimum CMake version required (for backward compatibility) and have a :cmake:command:`project` command to declare which languages are used. + +The remainder of the commands find the |VTKm| library, declare the program begin compiled, and link the program to the |VTKm| library. +These steps are described in detail in :secref:`building:Linking to |VTKm|`. diff --git a/docs/users-guide/vtkm.module b/docs/users-guide/vtkm.module new file mode 100644 index 000000000..43a7cb7f0 --- /dev/null +++ b/docs/users-guide/vtkm.module @@ -0,0 +1,10 @@ +NAME + UsersGuide +GROUPS + Core +TESTING_DIR + examples +TEST_DEPENDS + vtkm_cont + vtkm_filter_mesh_info + vtkm_rendering diff --git a/vtkm/Types.h b/vtkm/Types.h index 281770e07..8ec4944c7 100644 --- a/vtkm/Types.h +++ b/vtkm/Types.h @@ -151,16 +151,42 @@ namespace vtkm //***************************************************************************** // Typedefs for basic types. //***************************************************************************** + +/// Base type to use for 32-bit floating-point numbers. +/// using Float32 = float; + +/// Base type to use for 64-bit floating-point numbers. +/// using Float64 = double; + +/// Base type to use for 8-bit signed integer numbers. +/// using Int8 = int8_t; + +/// Base type to use for 8-bit unsigned integer numbers. +/// using UInt8 = uint8_t; + +/// Base type to use for 16-bit signed integer numbers. +/// using Int16 = int16_t; + +/// Base type to use for 16-bit unsigned integer numbers. +/// using UInt16 = uint16_t; + +/// Base type to use for 32-bit signed integer numbers. +/// using Int32 = int32_t; + +/// Base type to use for 32-bit unsigned integer numbers. +/// using UInt32 = uint32_t; -/// Represents a component ID (index of component in a vector). The number +/// \brief Base type to use to index small lists. +/// +/// This type represents a component ID (index of component in a vector). The number /// of components, being a value fixed at compile time, is generally assumed /// to be quite small. However, we are currently using a 32-bit width /// integer because modern processors tend to access them more efficiently @@ -172,19 +198,31 @@ using IdComponent = vtkm::Int32; using WordTypeDefault = vtkm::UInt32; //In this order so that we exactly match the logic that exists in VTK -#if VTKM_SIZE_LONG_LONG == 8 +#if (VTKM_SIZE_LONG_LONG == 8) || defined(VTKM_DOXYGEN_ONLY) +/// Base type to use for 64-bit signed integer numbers. +/// using Int64 = signed long long; +/// Base type to use for 64-bit signed integer numbers. +/// using UInt64 = unsigned long long; #define VTKM_UNUSED_INT_TYPE long #elif VTKM_SIZE_LONG == 8 +/// Base type to use for 64-bit signed integer numbers. +/// using Int64 = signed long; +/// Base type to use for 64-bit unsigned integer numbers. +/// using UInt64 = unsigned long; #define VTKM_UNUSED_INT_TYPE long long #else #error Could not find a 64-bit integer. #endif -/// Represents an ID (index into arrays). +/// \brief Base type to use to index arrays. +/// +/// This type represents an ID (index into arrays). It should be used whenever +/// indexing data that could grow arbitrarily large. +/// #ifdef VTKM_USE_64BIT_IDS using Id = vtkm::Int64; #else