├── .clang-format ├── .github └── workflows │ └── build.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake ├── Catch2.cmake ├── nanobind.cmake ├── python.cmake └── sanitizer-cmake.cmake ├── data ├── test_2.2_ascii.msh ├── test_2.2_bin.msh ├── test_4.1_ascii.msh └── test_4.1_bin.msh ├── examples └── msh_inspect.cpp ├── include └── mshio │ ├── MshSpec.h │ ├── MshSpecExt.h │ ├── exception.h │ └── mshio.h ├── pyproject.toml ├── python ├── mshio │ └── __init__.py └── pymshio.cpp ├── setup.py ├── src ├── element_utils.cpp ├── element_utils.h ├── io_utils.cpp ├── io_utils.h ├── load_msh.cpp ├── load_msh_curves.cpp ├── load_msh_curves.h ├── load_msh_data.cpp ├── load_msh_data.h ├── load_msh_elements.cpp ├── load_msh_elements.h ├── load_msh_entities.cpp ├── load_msh_entities.h ├── load_msh_format.cpp ├── load_msh_format.h ├── load_msh_nanospline_format.h ├── load_msh_nodes.cpp ├── load_msh_nodes.h ├── load_msh_patches.cpp ├── load_msh_patches.h ├── load_msh_physical_groups.cpp ├── load_msh_physical_groups.h ├── load_msh_post_process.cpp ├── load_msh_post_process.h ├── save_msh.cpp ├── save_msh_curves.cpp ├── save_msh_curves.h ├── save_msh_data.cpp ├── save_msh_data.h ├── save_msh_elements.cpp ├── save_msh_elements.h ├── save_msh_entities.cpp ├── save_msh_entities.h ├── save_msh_format.cpp ├── save_msh_format.h ├── save_msh_nanospline_format.h ├── save_msh_nodes.cpp ├── save_msh_nodes.h ├── save_msh_patches.cpp ├── save_msh_patches.h ├── save_msh_physical_groups.cpp ├── save_msh_physical_groups.h └── validate_spec.cpp └── tests ├── test_io.cpp └── test_main.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | # Docs: 2 | # http://clang.llvm.org/docs/ClangFormatStyleOptions.html 3 | 4 | # The style used for all options not specifically set in the configuration. 5 | # Available options: LLVM, Google, Chromium, Mozilla, WebKit 6 | BasedOnStyle: Google 7 | 8 | # The extra indent or outdent of access modifiers, e.g. public:. 9 | AccessModifierOffset: -4 10 | 11 | # If true, horizontally aligns arguments after an open bracket. 12 | # This applies to round brackets (parentheses), angle brackets and square brackets. This will result in formattings like code someLongFunction(argument1, argument2); endcode 13 | AlignAfterOpenBracket: DontAlign 14 | 15 | # If true, aligns escaped newlines as far left as possible. Otherwise puts them into the right-most column. 16 | AlignEscapedNewlinesLeft: Left 17 | 18 | # If true, horizontally align operands of binary and ternary expressions. 19 | AlignOperands: true 20 | 21 | # If true, aligns trailing comments. 22 | AlignTrailingComments: false 23 | 24 | # Allow putting all parameters of a function declaration onto the next line even if BinPackParameters is false. 25 | AllowAllParametersOfDeclarationOnNextLine: true 26 | 27 | # Allows contracting simple braced statements to a single line. 28 | # E.g., this allows if (a) { return; } to be put on a single line. 29 | # Shayan: I set it to false. I think if you want to create a single line block, 30 | # might as well just not create the block in the first place. 31 | AllowShortBlocksOnASingleLine: false 32 | 33 | # If true, short case labels will be contracted to a single line. 34 | AllowShortCaseLabelsOnASingleLine: true 35 | 36 | # Dependent on the value, int f() { return 0; } can be put on a single line. 37 | # SFS_None (in configuration: None) Never merge functions into a single line. 38 | # SFS_Inline (in configuration: Inline) Only merge functions defined inside a class. 39 | # SFS_Empty (in configuration: Empty) Only merge empty functions. 40 | # SFS_All (in configuration: All) Merge all functions fitting on a single line. 41 | AllowShortFunctionsOnASingleLine: Inline 42 | 43 | # If true, if (a) return; can be put on a single line. 44 | # Lagrange convention: 45 | # if( condition ) do something; -> YES 46 | # if( condition ) 47 | # do something; -> DON'T 48 | AllowShortIfStatementsOnASingleLine: true 49 | 50 | # If true, while (true) continue; can be put on a single line. 51 | # Lagrange convention: 52 | # while( condition ) do something; -> YES 53 | # while( condition ) 54 | # do something; -> DON'T 55 | AllowShortLoopsOnASingleLine: true 56 | 57 | # The function definition return type breaking style to use. This option is deprecated and is 58 | # retained for backwards compatibility. 59 | # AlwaysBreakAfterDefinitionReturnType: false 60 | 61 | # If true, always break before multiline string literals. 62 | AlwaysBreakBeforeMultilineStrings: false 63 | 64 | # If true, always break after the template<...> of a template declaration. 65 | AlwaysBreakTemplateDeclarations: true 66 | 67 | # If false, a function call's arguments will either be all on the same line or will have one line each. 68 | BinPackArguments: false 69 | 70 | # If false, a function call's arguments will either be all 71 | # on the same line or will have one line each. 72 | BinPackParameters: false 73 | 74 | # The way to wrap binary operators. 75 | # BOS_None (in configuration: None) Break after operators. 76 | # BOS_NonAssignment (in configuration: NonAssignment) Break before operators that aren't assignments. 77 | # BOS_All (in configuration: All) Break before operators. 78 | #BreakBeforeBinaryOperators: None 79 | 80 | # The brace breaking style to use. 81 | # BS_Attach (in configuration: Attach) Always attach braces to surrounding context. 82 | # BS_Linux (in configuration: Linux) Like Attach, but break before braces on function, namespace and class definitions. 83 | # BS_Stroustrup (in configuration: Stroustrup) Like Attach, but break before function definitions, and `else`. 84 | # BS_Allman (in configuration: Allman) Always break before braces. 85 | # BS_GNU (in configuration: GNU) Always break before braces and add an extra level of indentation to braces of control statements, not to those of class, function or other definitions. 86 | BraceWrapping: 87 | AfterClass: true 88 | AfterControlStatement: false 89 | AfterEnum: false 90 | AfterFunction: true 91 | AfterNamespace: false 92 | AfterObjCDeclaration: false 93 | AfterStruct: true 94 | AfterUnion: false 95 | BeforeCatch: false 96 | BeforeElse: false 97 | IndentBraces: false 98 | SplitEmptyFunction: false 99 | BreakBeforeBraces: Custom 100 | 101 | # If true, ternary operators will be placed after line breaks. 102 | BreakBeforeTernaryOperators: true 103 | 104 | # Always break constructor initializers before commas and align the commas with the colon. 105 | BreakConstructorInitializersBeforeComma: true 106 | 107 | # The column limit. 108 | # A column limit of 0 means that there is no column limit. In this case, clang-format will respect the input's line breaking decisions within statements unless they contradict other rules. 109 | ColumnLimit: 100 110 | 111 | # A regular expression that describes comments with special meaning, which should not be split into lines or otherwise changed. 112 | CommentPragmas: "\/*(.*)*\/" 113 | 114 | # If the constructor initializers don't fit on a line, put each initializer on its own line. 115 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 116 | 117 | # The number of characters to use for indentation of constructor initializer lists. 118 | ConstructorInitializerIndentWidth: 4 119 | 120 | # Indent width for line continuations. 121 | # A little more than normal indent 122 | ContinuationIndentWidth: 4 123 | 124 | # If true, format braced lists as best suited for C++11 braced lists. 125 | # Important differences: - No spaces inside the braced list. - No line break before the closing brace. - Indentation with the continuation indent, not with the block indent. 126 | # Fundamentally, C++11 braced lists are formatted exactly like function calls would be formatted in their place. If the braced list follows a name (e.g. a type or variable name), clang-format formats as if the {} were the parentheses of a function call with that name. If there is no name, a zero-length name is assumed. 127 | Cpp11BracedListStyle: true 128 | 129 | # If true, analyze the formatted file for the most common alignment of & and *. Point 130 | #DerivePointerAlignment: false 131 | 132 | # Disables formatting at all. 133 | #DisableFormat: false 134 | 135 | # If true, clang-format detects whether function calls and definitions are formatted with one parameter per line. 136 | # Each call can be bin-packed, one-per-line or inconclusive. If it is inconclusive, e.g. completely on one line, but a decision needs to be made, clang-format analyzes whether there are other bin-packed cases in the input file and act accordingly. 137 | # NOTE: This is an experimental flag, that might go away or be renamed. Do not use this in config files, etc. Use at your own risk. 138 | #ExperimentalAutoDetectBinPacking: false 139 | 140 | # If true, clang-format adds missing namespace end comments and fixes invalid existing ones. 141 | FixNamespaceComments: true 142 | 143 | # A vector of macros that should be interpreted as foreach loops instead of as function calls. 144 | # These are expected to be macros of the form: code FOREACH(, ...) endcode 145 | # For example: BOOST_FOREACH. 146 | #ForEachMacros (std::vector) 147 | 148 | # Dependent on the value, multiple #include blocks can be sorted as one and divided based on category. 149 | IncludeBlocks: Preserve 150 | 151 | # Indent case labels one level from the switch statement. 152 | # When false, use the same indentation level as for the switch statement. Switch statement body is always indented one level more than case labels. 153 | IndentCaseLabels: false 154 | 155 | # The number of columns to use for indentation. 156 | IndentWidth: 4 157 | 158 | # Indent if a function definition or declaration is wrapped after the type. 159 | #IndentWrappedFunctionNames: false 160 | 161 | # If true, empty lines at the start of blocks are kept. 162 | #KeepEmptyLinesAtTheStartOfBlocks: false 163 | 164 | # Language, this format style is targeted at. 165 | # LK_None (in configuration: None) Do not use. 166 | # LK_Cpp (in configuration: Cpp) Should be used for C, C++, ObjectiveC, ObjectiveC++. 167 | # LK_Java (in configuration: Java) Should be used for Java. 168 | # LK_JavaScript (in configuration: JavaScript) Should be used for JavaScript. 169 | # LK_Proto (in configuration: Proto) Should be used for Protocol Buffers (https://developers.google.com/protocol-buffers/). 170 | Language: Cpp 171 | 172 | # The maximum number of consecutive empty lines to keep. 173 | MaxEmptyLinesToKeep: 2 174 | 175 | # The indentation used for namespaces. 176 | # NI_None (in configuration: None) Don't indent in namespaces. 177 | # NI_Inner (in configuration: Inner) Indent only in inner namespaces (nested in other namespaces). 178 | # NI_All (in configuration: All) Indent in all namespaces. 179 | NamespaceIndentation: None 180 | 181 | # The number of characters to use for indentation of ObjC blocks. 182 | #ObjCBlockIndentWidth: 4 183 | 184 | # Add a space after @property in Objective-C, i.e. use \@property (readonly) instead of \@property(readonly). 185 | #ObjCSpaceAfterProperty: false 186 | 187 | # Add a space in front of an Objective-C protocol list, i.e. use Foo instead of Foo. 188 | #ObjCSpaceBeforeProtocolList: false 189 | 190 | # The penalty for breaking a function call after `call(`. 191 | #PenaltyBreakBeforeFirstCallParameter (unsigned) 192 | 193 | # The penalty for each line break introduced inside a comment. 194 | #PenaltyBreakComment (unsigned) 195 | 196 | # The penalty for breaking before the first <<. 197 | #PenaltyBreakFirstLessLess (unsigned) 198 | 199 | # The penalty for each line break introduced inside a string literal. 200 | #PenaltyBreakString (unsigned) 201 | 202 | # The penalty for each character outside of the column limit. 203 | #PenaltyExcessCharacter (unsigned) 204 | 205 | # Penalty for putting the return type of a function onto its own line. 206 | #PenaltyReturnTypeOnItsOwnLine (unsigned) 207 | 208 | # If true, analyze the formatted file for the most common alignment of & and *. PointerAlignment is then used only as fallback. 209 | PointerAlignment: Middle 210 | 211 | # If true, clang-format will attempt to re-flow comments. 212 | ReflowComments: true 213 | 214 | # Add a space before parantheses 215 | # if (condition) -> tick 216 | # if(condition) -> cross 217 | SpaceBeforeParens: ControlStatements 218 | 219 | # If true, a space may be inserted after C style casts. 220 | SpaceAfterCStyleCast: false 221 | 222 | # If false, spaces will be removed before assignment operators. 223 | #SpaceBeforeAssignmentOperators: true 224 | 225 | # If true, spaces may be inserted into `()`. 226 | SpaceInEmptyParentheses: false 227 | 228 | # The number of spaces before trailing line comments (// - comments). 229 | # This does not affect trailing block comments (/**/ - comments) as those commonly have different usage patterns and a number of special cases. 230 | SpacesBeforeTrailingComments: 1 231 | 232 | # If true, spaces will be inserted after `<` and before `>` in template argument lists 233 | SpacesInAngles: false 234 | 235 | # If true, spaces may be inserted into C style casts. 236 | SpacesInCStyleCastParentheses: false 237 | 238 | # If true, spaces are inserted inside container literals (e.g. ObjC and Javascript array and dict literals). 239 | SpacesInContainerLiterals: false 240 | 241 | # If true, spaces will be inserted after `(` and before `)`. 242 | SpacesInParentheses: false 243 | 244 | # If true, spaces will be inserted after `[` and before `]`. 245 | SpacesInSquareBrackets: false 246 | 247 | # Format compatible with this standard, e.g. use A > instead of A> for LS_Cpp03. 248 | # LS_Cpp03 (in configuration: Cpp03) Use C++03-compatible syntax. 249 | # LS_Cpp11 (in configuration: Cpp11) Use features of C++11 (e.g. A> instead of A >). 250 | # LS_Auto (in configuration: Auto) Automatic detection based on the input. 251 | Standard: Cpp11 252 | 253 | # The number of columns used for tab stops. 254 | TabWidth: 4 255 | 256 | # The way to use tab characters in the resulting file. 257 | # UT_Never (in configuration: Never) Never use tab. 258 | # UT_ForIndentation (in configuration: ForIndentation) Use tabs only for indentation. 259 | # UT_Always (in configuration: Always) Use tabs whenever we need to fill whitespace that spans at least from one tab stop to the next one. 260 | UseTab: Never 261 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build and test 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | build-Ubuntu: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v1 10 | 11 | - name: build and run 12 | run: | 13 | mkdir build 14 | cd build 15 | cmake .. -DCMAKE_BUILD_TYPE=Release -DMSHIO_BUILD_TESTS=On -DMSHIO_BUILD_EXAMPLES=On 16 | make -j 17 | ctest 18 | 19 | build-MacOS: 20 | runs-on: macos-latest 21 | steps: 22 | - uses: actions/checkout@v1 23 | 24 | - name: build and run 25 | run: | 26 | mkdir build 27 | cd build 28 | cmake .. -DCMAKE_BUILD_TYPE=Release -DMSHIO_BUILD_TESTS=On -DMSHIO_BUILD_EXAMPLES=On 29 | make -j 30 | ctest 31 | 32 | build-Windows: 33 | runs-on: windows-latest 34 | steps: 35 | - uses: actions/checkout@v1 36 | 37 | - name: build and run 38 | run: | 39 | mkdir build 40 | cd build 41 | cmake .. -DCMAKE_GENERATOR_PLATFORM=x64 -DMSHIO_BUILD_TESTS=On -DMSHIO_BUILD_EXAMPLES=On 42 | cmake --build . --config Release 43 | ctest 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build*/ 2 | _skbuild/ 3 | *.egg-info/ 4 | __pycache__/ 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ============================================================================ 2 | # This file will generate the cmake target `MshIO::MshIO`. 3 | # 4 | # To add MshIO as a dependency: 5 | # 6 | # add_subdirectory(MshIO) 7 | # target_link_libraries(your_target mshio::mshio) 8 | # 9 | # ============================================================================ 10 | 11 | cmake_minimum_required(VERSION 3.11) 12 | set(CMAKE_CXX_STANDARD 14) 13 | 14 | project(MshIO) 15 | 16 | option(MSHIO_BUILD_TESTS "Build unit tests" OFF) 17 | option(MSHIO_BUILD_EXAMPLES "Build examples" OFF) 18 | option(MSHIO_EXT_NANOSPLINE "Enable nanospline extension" OFF) 19 | option(MSHIO_PYTHON "Build python binding" OFF) 20 | 21 | include(FetchContent) 22 | 23 | file(GLOB INC_FILES "${PROJECT_SOURCE_DIR}/include/mshio/*.h") 24 | file(GLOB SRC_FILES "${PROJECT_SOURCE_DIR}/src/*.cpp") 25 | 26 | add_library(mshio STATIC ${SRC_FILES}) 27 | target_include_directories(mshio PUBLIC 28 | "$" 29 | "$") 30 | 31 | add_library(mshio::mshio ALIAS mshio) 32 | 33 | 34 | if (MSHIO_EXT_NANOSPLINE) 35 | target_compile_definitions(mshio PUBLIC -DMSHIO_EXT_NANOSPLINE) 36 | endif() 37 | 38 | 39 | if (MSHIO_PYTHON) 40 | include(cmake/nanobind.cmake) 41 | set(PY_SRC_FILE "${PROJECT_SOURCE_DIR}/python/pymshio.cpp") 42 | nanobind_add_module(pymshio NB_STATIC ${PY_SRC_FILE}) 43 | target_link_libraries(pymshio PUBLIC mshio::mshio) 44 | install(TARGETS pymshio LIBRARY DESTINATION .) 45 | add_library(mshio::pymshio ALIAS pymshio) 46 | endif() 47 | 48 | 49 | if (MSHIO_BUILD_EXAMPLES) 50 | add_executable(msh_inspect ${PROJECT_SOURCE_DIR}/examples/msh_inspect.cpp) 51 | target_link_libraries(msh_inspect PRIVATE mshio::mshio) 52 | endif() 53 | 54 | 55 | if (MSHIO_BUILD_TESTS) 56 | include(CTest) 57 | enable_testing() 58 | include(cmake/Catch2.cmake) 59 | include(cmake/sanitizer-cmake.cmake) 60 | 61 | file(GLOB TEST_FILES "${PROJECT_SOURCE_DIR}/tests/*.cpp") 62 | add_executable(test_MshIO ${TEST_FILES}) 63 | target_link_libraries(test_MshIO mshio::mshio Catch2::Catch2) 64 | target_compile_definitions(test_MshIO PRIVATE 65 | MSHIO_DATA_DIR="${PROJECT_SOURCE_DIR}/data") 66 | catch_discover_tests(test_MshIO) 67 | 68 | if(NOT MSVC) 69 | target_compile_options(test_MshIO PRIVATE -Wconversion -Wall -Werror) 70 | else() 71 | target_compile_options(test_MshIO PRIVATE "/MP") 72 | endif() 73 | 74 | if (SANITIZE_ADDRESS OR 75 | SANITIZE_LINK_STATIC OR 76 | SANITIZE_MEMORY OR 77 | SANITIZE_THREAD OR 78 | SANITIZE_UNDEFINED) 79 | add_sanitizers(test_MshIO) 80 | endif() 81 | endif() 82 | 83 | 84 | if (NOT MSHIO_PYTHON) 85 | include(GNUInstallDirs) 86 | install(TARGETS mshio 87 | EXPORT mshio_target 88 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 89 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 90 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) 91 | install(DIRECTORY include/ DESTINATION include 92 | FILES_MATCHING PATTERN "*.h") 93 | install(EXPORT mshio_target DESTINATION cmake) 94 | endif() 95 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MshIO 2 | 3 | MshIO is a tiny library written with modern C++. It is created by Qingnan Zhou 4 | as a coding exercise. It supports reading and writing [MSH format] with both 5 | ASCII and binary encodings for both version 2.2 and version 4.1. 6 | 7 | ![build and test](https://github.com/qnzhou/MshIO/workflows/build%20and%20test/badge.svg) 8 | 9 | ## Build 10 | 11 | ```sh 12 | # Build C++ library 13 | mkdir build 14 | cd build 15 | cmake .. 16 | make 17 | 18 | # Build python 19 | pip install git+https://github.com/qnzhou/MshIO.git 20 | ``` 21 | 22 | ## Usage 23 | 24 | In C++: 25 | ```c++ 26 | #include 27 | 28 | mshio::MshSpec spec = mshio::load_msh("input.msh"); 29 | 30 | mshio::save_msh("output.msh", spec); 31 | ``` 32 | 33 | or in Python 34 | ```python 35 | import mshio 36 | 37 | spec = mshio.load_msh("input.msh") 38 | mshio.save_msh("output.msh", spec) 39 | ``` 40 | 41 | ## `MshSpec` data structure 42 | 43 | `MshSpec` ([code](../main/include/MshIO/MshSpec.h)) is a data structure 44 | that maps almost verbatim to the information stored in a MSH file. Currently, 45 | the following sections are supported: 46 | 47 | | Section name | Description | 48 | | ------------------: | ---------------------------------------------------------------------------- | 49 | | [Mesh format] | Format header. | 50 | | [Nodes] | 3D coordinates of nodes and (optionally) their parameterization coordinates. | 51 | | [Elements] | A list of elements grouped by blocks. | 52 | | [Entities] | The boundary representation (BRep) of the model. | 53 | | [Physical groups] | Metadata defined on elements. | 54 | | [Node data] | Scalar/vector/tensor fields defined on nodes. | 55 | | [Element data] | Scalar/vector/tensor fields defined on elements. | 56 | | [Element-node data] | Scalar/vector/tensor fields defined over each node of each element. | 57 | 58 | The follow sections are supported by MSH format, but not yet supported by MshIO 59 | (contribution welcomed): 60 | * Partitioned entities 61 | * Periodic 62 | * Ghost elements 63 | * Parametrizations 64 | * Interpolation scheme 65 | 66 | All fields will be populated by `mshio::load_msh()` method, and all fields 67 | should be set up correctly before calling `mshio::save_msh()` method. The helper 68 | method `mshio::validate_spec(spec)` can be used to check if a given `spec` is 69 | valid. 70 | 71 | ### Mesh format 72 | 73 | Mesh format section is the header of MSH file. It contains information about 74 | the MSH version used, whether the file is binary and data size. This section is 75 | required. 76 | 77 | ```c++ 78 | auto& format = spec.mesh_format; 79 | format.version = "4.1"; // Only version "2.2" and "4.1" are supported. 80 | format.file_type = 1; // 0: ASCII, 1: binary. 81 | format.data_size = sizeof(size_t); // Size of data, defined as sizeof(size_t) = 8. 82 | ``` 83 | 84 | ### Nodes 85 | 86 | Nodes are grouped into node blocks in MSH format. Each node has a unique "tag", 87 | and the tag is used for referring to this node in other sections. All tags are 88 | positive. Ideally, tags should be ordered consecutively from 1 to N (the number 89 | of nodes), but it does not have to be so. It is up to the client application to 90 | maintain a mapping from tag to nodes. 91 | 92 | ```c++ 93 | auto& nodes = spec.nodes; 94 | nodes.num_entity_blocksl = 1; // Number of node blocks. 95 | nodes.num_nodes = 3; // Total number of nodes. 96 | nodes.min_node_tag = 1; 97 | nodes.max_node_tag = 3; 98 | nodes.entity_blocks = {...}; // A std::vector of node blocks. 99 | ``` 100 | 101 | #### Node block 102 | 103 | A node block is simply a group of nodes. 104 | 105 | ```c++ 106 | auto& block = nodes.entity_blocks[k]; 107 | block.entity_dim = 2; // The dimension of the entity. 108 | block.entity_tag = 1; // The entity these nodes belongs to. 109 | block.parametric = 0; // 0: non-parametric, 1: parametric. 110 | block.num_nodes_in_block = 3; // The number of nodes in block. 111 | block.tags = {...}; // A std::vector of unique, positive node tags. 112 | block.data = {...}; // A std::vector of coordinates (x,y,z,,,,...) 113 | ``` 114 | 115 | When `block.parametric` is `1`, `block.data` contains the parametric coordinates 116 | in addition to the XYZ coordinates. The dimension of the parametric coordinates 117 | is defined by `block.entity_dim` variable. 118 | 119 | ### Elements 120 | 121 | Elements are grouped into element blocks. Each element has a unique positive 122 | "tag". Ideally, tags should be ordered consecutively from 1 to M (the number of 123 | elements), but it does not have not be so. It is up to the client application 124 | to maintain a mapping from tag to elements. 125 | 126 | ```c++ 127 | auto& elements = spec.elements; 128 | elements.num_entity_blocks = 1; // Number of element blocks. 129 | elements.num_elements = 12; // Total number of elmeents. 130 | elements.min_element_tag = 1; 131 | elements.max_element_tag = 12; 132 | elements.entity_blocks = {...}; // A std::vector of element blocks. 133 | ``` 134 | 135 | #### Element block 136 | 137 | An element block is a set of elements of the same type: 138 | 139 | ```c++ 140 | auto& block = elements.entity_blocks[k]; 141 | block.entity_dim = 2; // The dimension of the elements. 142 | block.entity_tag = 1; // The entity these elements belongs to. 143 | block.element_type = 2; // See element type table below. 144 | block.num_elements_in_block = 12; // The number of elements in this block. 145 | block.data = {...}; // See more detail below. 146 | ``` 147 | 148 | #### Element types 149 | 150 | MSH format supports a large set of finite element types. Element types 151 | determines the dimension of the element as well as the number of nodes that make 152 | up the element. 153 | 154 | ```c++ 155 | int element_type = ...; // Element type is encoded as an int. 156 | 157 | // To look up the number of nodes for this element type: 158 | size_t n = nodes_per_element(element_type); 159 | 160 | // To look up the dimension of the element: 161 | int dim = get_element_dim(element_type); 162 | ``` 163 | 164 | See all supported element types [here](#Supported-element-types). 165 | 166 | 167 | #### Element data 168 | 169 | The element data is a flattened `std::vector` of `size_t`. It follows the 170 | convention below: 171 | 172 | ``` 173 | element_tag node_tag ... node_tag 174 | element_tag node_tag ... node_tag 175 | ... 176 | ``` 177 | 178 | i.e. Each element entry consists of an element tag followed by `n` node tags, 179 | where `n` is the number of nodes corresponding determined by the element type. 180 | See the [supported element types](#Supported-element-types) table. 181 | 182 | ### Entities 183 | 184 | Entities make up the boundary representation of the mesh model. Nodes and 185 | elements belong to specific entities. The four types of entities are points, 186 | lines, surfaces and volumes. Higher order entities are bounded by lower ones 187 | (e.g. volumes are bounded by surfaces). Entities also contain bounding box and 188 | physical group information. 189 | 190 | ```c++ 191 | auto& entities = spec.entities; 192 | auto& point_entities = entities.points; 193 | auto& curve_entities = entities.curves; 194 | auto& surface_entities = entities.surfaces; 195 | auto& volume_entities = entities.volumes; 196 | 197 | // look up the physical groups of an element block 198 | auto& block = elements.entity_blocks[i]; 199 | assert(block.entity_dim == 2); // surface entity (0 for point, 1 for curve...) 200 | auto surface_entity = std::find_if(surface_entities.begin(), 201 | surface_entities.end(), [&](const mshio::SurfaceEntity& s) { 202 | return s.tag == block.entity_tag; 203 | }); 204 | assert(surface_entity != surface_entities.end()); 205 | auto& physical_groups = surface_entity->physical_group_tags; 206 | ``` 207 | 208 | ### Physical groups 209 | 210 | Physical groups are used to tag elements with arbitrary metadata (e.g. 211 | "boundary", "steel", etc.). Physical groups have an `int` tag, `int` dimension, 212 | and `string` name. The name may be empty. 213 | 214 | ```c++ 215 | auto& physical_groups = spec.physical_groups; 216 | auto& pg = physical_groups[k]; 217 | 218 | pg.dim = 0; 219 | pg.tag = 1; 220 | pg.name = "My Physical Group"; 221 | ``` 222 | 223 | ### Post-processing data 224 | 225 | One of main advantage of MSH format is its support for storing post-processing 226 | data along with the mesh. There are 3 types of post-processing data: node data, 227 | element data and element-node data. Each type of post-processing data consists 228 | of a header and a `std::vector` of entries. 229 | 230 | ```c++ 231 | auto& node_data = spec.node_data[k]; 232 | auto& element_data = spec.element_data[k]; 233 | auto& element_node_data = spec.element_node_data[k]; 234 | ``` 235 | 236 | #### Data header 237 | 238 | Data header consists of arrays of `string`, `double` and `int` tags. Some tags 239 | has pre-defined meaning: 240 | 241 | ```c++ 242 | auto& header = node_data.header; 243 | header.string_tags = {...}; // [field_name, , ...] 244 | header.real_tags = {...}; // [