From 34327298dd5823309d6346050c71224afb3dd237 Mon Sep 17 00:00:00 2001 From: Moritz Date: Mon, 16 Aug 2021 21:18:30 +0200 Subject: [PATCH 01/26] Refactor: Moved validation of segment header keywords --- include/detail/parse_rules.hpp | 98 +++++++++++++++------------------- 1 file changed, 43 insertions(+), 55 deletions(-) diff --git a/include/detail/parse_rules.hpp b/include/detail/parse_rules.hpp index 7100bc4..e5fba5a 100644 --- a/include/detail/parse_rules.hpp +++ b/include/detail/parse_rules.hpp @@ -397,8 +397,17 @@ namespace parse template< typename Input > static void apply( const Input& in, ovf_file & file, ovf_segment & segment ) { + // Check if all required keywords were present std::vector missing_keywords(0); + std::vector wrong_keywords(0); + + if( std::string(segment.meshtype) != "rectangular" && std::string(segment.meshtype) != "irregular") + { + throw tao::pegtl::parse_error( fmt::format( + "Invalid meshtype: \"{}\"", segment.meshtype), in ); + } + if( !file._state->found_title ) missing_keywords.push_back("title"); if( !file._state->found_meshunit ) @@ -444,13 +453,35 @@ namespace parse missing_keywords.push_back("ynodes"); if( !file._state->found_znodes ) missing_keywords.push_back("znodes"); + } else { + if( file._state->found_xbase ) + wrong_keywords.push_back("xbase"); + if( file._state->found_ybase ) + wrong_keywords.push_back("ybase"); + if( file._state->found_zbase ) + wrong_keywords.push_back("zbase"); + if( file._state->found_xstepsize ) + wrong_keywords.push_back("xstepsize"); + if( file._state->found_ystepsize ) + wrong_keywords.push_back("ystepsize"); + if( file._state->found_zstepsize ) + wrong_keywords.push_back("zstepsize"); + if( file._state->found_xnodes ) + wrong_keywords.push_back("xnodes"); + if( file._state->found_ynodes ) + wrong_keywords.push_back("ynodes"); + if( file._state->found_znodes ) + wrong_keywords.push_back("znodes"); } - else if( std::string(segment.meshtype) == "irregular" ) + + if( std::string(segment.meshtype) == "irregular" ) { segment.N = segment.pointcount; - if( !file._state->found_pointcount ) missing_keywords.push_back("pointcount"); + } else { + if( file._state->found_pointcount ) + wrong_keywords.push_back("pointcount"); } if( missing_keywords.size() > 0 ) @@ -460,6 +491,15 @@ namespace parse message += fmt::format( ", \"{}\"", missing_keywords[i] ); throw tao::pegtl::parse_error( message, in ); } + + if( wrong_keywords.size() > 0 ) + { + std::string message = fmt::format( "Wrong keywords for meshtype \"{}\": \"{}\"", segment.meshtype, wrong_keywords[0] ); + for( int i=1; i < wrong_keywords.size(); ++i ) + message += fmt::format( ", \"{}\"", wrong_keywords[i] ); + throw tao::pegtl::parse_error( message, in ); + } + } }; @@ -565,108 +605,56 @@ namespace parse { std::string meshtype = f._state->value; std::transform(meshtype.begin(), meshtype.end(), meshtype.begin(), ::tolower); - if( std::string(segment.meshtype) == "" ) - { - if( meshtype != "rectangular" && meshtype != "irregular" ) - throw tao::pegtl::parse_error( fmt::format( - "Invalid meshtype: \"{}\"", meshtype), in ); - segment.meshtype = strdup(meshtype.c_str()); - } - else if( std::string(segment.meshtype) != meshtype ) - { - throw tao::pegtl::parse_error( fmt::format( - "meshtype \"{}\" was specified, but due to other parameters specified before, \"{}\" was expected!", - meshtype, segment.meshtype), in ); - } + segment.meshtype = strdup(meshtype.c_str()); f._state->found_meshtype = true; } else if( f._state->keyword == "xbase" ) { - if( std::string(segment.meshtype) != "rectangular" ) - throw tao::pegtl::parse_error( fmt::format( - "xbase is only for rectangular meshes! Mesh type is \"{}\"", segment.meshtype), in ); - segment.meshtype = strdup("rectangular"); segment.origin[0] = std::stof(f._state->value.c_str()); f._state->found_xbase = true; } else if( f._state->keyword == "ybase" ) { - if( std::string(segment.meshtype) != "rectangular" ) - throw tao::pegtl::parse_error( fmt::format( - "ybase is only for rectangular meshes! Mesh type is \"{}\"", segment.meshtype), in ); - segment.meshtype = strdup("rectangular"); segment.origin[1] = std::stof(f._state->value.c_str()); f._state->found_ybase = true; } else if( f._state->keyword == "zbase" ) { - if( std::string(segment.meshtype) != "rectangular" ) - throw tao::pegtl::parse_error( fmt::format( - "zbase is only for rectangular meshes! Mesh type is \"{}\"", segment.meshtype), in ); - segment.meshtype = strdup("rectangular"); segment.origin[2] = std::stof(f._state->value.c_str()); f._state->found_zbase = true; } else if( f._state->keyword == "xstepsize" ) { - if( std::string(segment.meshtype) != "rectangular" ) - throw tao::pegtl::parse_error( fmt::format( - "xstepsize is only for rectangular meshes! Mesh type is \"{}\"", segment.meshtype), in ); - segment.meshtype = strdup("rectangular"); segment.step_size[0] = std::stof(f._state->value.c_str()); f._state->found_xstepsize = true; } else if( f._state->keyword == "ystepsize" ) { - if( std::string(segment.meshtype) != "rectangular" ) - throw tao::pegtl::parse_error( fmt::format( - "ystepsize is only for rectangular meshes! Mesh type is \"{}\"", segment.meshtype), in ); - segment.meshtype = strdup("rectangular"); segment.step_size[1] = std::stof(f._state->value.c_str()); f._state->found_ystepsize = true; } else if( f._state->keyword == "zstepsize" ) { - if( std::string(segment.meshtype) != "rectangular" ) - throw tao::pegtl::parse_error( fmt::format( - "zstepsize is only for rectangular meshes! Mesh type is \"{}\"", segment.meshtype), in ); - segment.meshtype = strdup("rectangular"); segment.step_size[2] = std::stof(f._state->value.c_str()); f._state->found_zstepsize = true; } else if( f._state->keyword == "xnodes" ) { - if( std::string(segment.meshtype) != "rectangular" ) - throw tao::pegtl::parse_error( fmt::format( - "xnodes is only for rectangular meshes! Mesh type is \"{}\"", segment.meshtype), in ); - segment.meshtype = strdup("rectangular"); segment.n_cells[0] = std::stoi(f._state->value.c_str()); f._state->found_xnodes = true; } else if( f._state->keyword == "ynodes" ) { - if( std::string(segment.meshtype) != "rectangular" ) - throw tao::pegtl::parse_error( fmt::format( - "ynodes is only for rectangular meshes! Mesh type is \"{}\"", segment.meshtype), in ); - segment.meshtype = strdup("rectangular"); segment.n_cells[1] = std::stoi(f._state->value.c_str()); f._state->found_ynodes = true; } else if( f._state->keyword == "znodes" ) { - if( std::string(segment.meshtype) != "rectangular" ) - throw tao::pegtl::parse_error( fmt::format( - "znodes is only for rectangular meshes! Mesh type is \"{}\"", segment.meshtype), in ); - segment.meshtype = strdup("rectangular"); segment.n_cells[2] = std::stoi(f._state->value.c_str()); f._state->found_znodes = true; } else if( f._state->keyword == "pointcount" ) { - if( std::string(segment.meshtype) != "" && std::string(segment.meshtype) != "irregular" ) - throw tao::pegtl::parse_error( fmt::format( - "pointcount is only for irregular meshes! Mesh type is \"{}\"", segment.meshtype), in ); - segment.meshtype = strdup("irregular"); segment.pointcount = std::stoi(f._state->value.c_str()); f._state->found_pointcount = true; } From 6fef06f1acd45ca2fdc759a73e9534391b2d90e4 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 12:35:14 +0200 Subject: [PATCH 02/26] Moved parser_state into its own header --- include/detail/parse_rules.hpp | 49 +------------------------- include/detail/pegtl_defines.hpp | 59 ++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 48 deletions(-) create mode 100644 include/detail/pegtl_defines.hpp diff --git a/include/detail/parse_rules.hpp b/include/detail/parse_rules.hpp index e5fba5a..832c345 100644 --- a/include/detail/parse_rules.hpp +++ b/include/detail/parse_rules.hpp @@ -3,6 +3,7 @@ #define LIBOVF_DETAIL_PARSE_RULES_H #include "ovf.h" +#include "pegtl_defines.hpp" #include #include @@ -10,54 +11,6 @@ #include -struct parser_state -{ - // For the segment strings - std::vector file_contents{}; - - // for reading data blocks - int current_column = 0; - int current_line = 0; - - std::string keyword="", value=""; - - // Whether certain keywords were found in parsing - bool found_title = false; - bool found_meshunit = false; - bool found_valuedim = false; - bool found_valueunits = false; - bool found_valuelabels = false; - bool found_xmin = false; - bool found_ymin = false; - bool found_zmin = false; - bool found_xmax = false; - bool found_ymax = false; - bool found_zmax = false; - bool found_meshtype = false; - bool found_xbase = false; - bool found_ybase = false; - bool found_zbase = false; - bool found_xstepsize = false; - bool found_ystepsize = false; - bool found_zstepsize = false; - bool found_xnodes = false; - bool found_ynodes = false; - bool found_znodes = false; - bool found_pointcount = false; - - /* - messages, e.g. in case a function returned OVF_ERROR. - message_out will be filled and returned by ovf_latest_message, while message_latest - will be filled by other functions and cleared by ovf_latest_message. - */ - std::string message_out="", message_latest=""; - - int max_data_index=0; - int tmp_idx=0; - std::array tmp_vec3 = std::array{0,0,0}; - - std::ios::pos_type n_segments_pos = 0; -}; namespace ovf { diff --git a/include/detail/pegtl_defines.hpp b/include/detail/pegtl_defines.hpp new file mode 100644 index 0000000..116699f --- /dev/null +++ b/include/detail/pegtl_defines.hpp @@ -0,0 +1,59 @@ +#pragma once +#ifndef LIBOVF_DETAIL_PEGTL_DEFINES_H +#define LIBOVF_DETAIL_PEGTL_DEFINES_H + +#include +#include +#include +#include + +struct parser_state +{ + // For the segment strings + std::vector file_contents{}; + + // for reading data blocks + int current_column = 0; + int current_line = 0; + + std::string keyword="", value=""; + + // Whether certain keywords were found in parsing + bool found_title = false; + bool found_meshunit = false; + bool found_valuedim = false; + bool found_valueunits = false; + bool found_valuelabels = false; + bool found_xmin = false; + bool found_ymin = false; + bool found_zmin = false; + bool found_xmax = false; + bool found_ymax = false; + bool found_zmax = false; + bool found_meshtype = false; + bool found_xbase = false; + bool found_ybase = false; + bool found_zbase = false; + bool found_xstepsize = false; + bool found_ystepsize = false; + bool found_zstepsize = false; + bool found_xnodes = false; + bool found_ynodes = false; + bool found_znodes = false; + bool found_pointcount = false; + + /* + messages, e.g. in case a function returned OVF_ERROR. + message_out will be filled and returned by ovf_latest_message, while message_latest + will be filled by other functions and cleared by ovf_latest_message. + */ + std::string message_out="", message_latest=""; + + int max_data_index=0; + int tmp_idx=0; + std::array tmp_vec3 = std::array{0,0,0}; + + std::ios::pos_type n_segments_pos = 0; +}; + +#endif \ No newline at end of file From b582197743528844f28ddfa3895587252e8f621a Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 12:43:35 +0200 Subject: [PATCH 03/26] Added keywords header file --- include/detail/keywords.hpp | 430 ++++++++++++++++++++++++++++++++++++ 1 file changed, 430 insertions(+) create mode 100644 include/detail/keywords.hpp diff --git a/include/detail/keywords.hpp b/include/detail/keywords.hpp new file mode 100644 index 0000000..a452b9e --- /dev/null +++ b/include/detail/keywords.hpp @@ -0,0 +1,430 @@ +#pragma once +#ifndef LIBOVF_DETAIL_KEYWORDS_H +#define LIBOVF_DETAIL_KEYWORDS_H + +#include "ovf.h" +#include "pegtl_defines.hpp" + +#include +#include + +#include +#include + +#include + + +namespace ovf { +namespace detail +{ + +namespace keywords +{ + namespace pegtl = tao::pegtl; + + template< typename Rule > + struct kw_action + : pegtl::nothing< Rule > + { }; + + ////// title + struct title : TAO_PEGTL_ISTRING("title") + { }; + + struct title_value : pegtl::until + { }; + + template<> + struct kw_action< title_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.title = strdup(in.string().c_str()); + f._state->found_title = true; + } + }; + + ////// valuedim + struct valuedim : TAO_PEGTL_ISTRING("valuedim") + { }; + + struct valuedim_value : pegtl::until + { }; + + template<> + struct kw_action< valuedim_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.valuedim = std::stoi(in.string()); + f._state->found_valuedim = true; + } + }; + + ////// valueunits + struct valueunits : TAO_PEGTL_ISTRING("valueunits") + { }; + + struct valueunits_value : pegtl::until + { }; + + template<> + struct kw_action< valueunits_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.valueunits = strdup(in.string().c_str()); + f._state->found_valueunits = true; + } + }; + + ////// valuelabels + struct valuelabels : TAO_PEGTL_ISTRING("valuelabels") + { }; + + struct valuelabels_value : pegtl::until + { }; + + template<> + struct kw_action< valuelabels_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.valuelabels = strdup(in.string().c_str()); + f._state->found_valuelabels = true; + } + }; + + ////// meshtype + struct meshtype : TAO_PEGTL_ISTRING("meshtype") + { }; + + struct meshtype_value : pegtl::until + { }; + + template<> + struct kw_action< meshtype_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.meshtype = strdup(in.string().c_str()); + f._state->found_meshtype = true; + } + }; + + ////// meshunit + struct meshunit : TAO_PEGTL_ISTRING("meshunit") + { }; + + struct meshunit_value : pegtl::until + { }; + + template<> + struct kw_action< meshunit_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.meshunit = std::stoi(in.string()); + f._state->found_meshunit = true; + } + }; + + ////// pointcount + struct pointcount : TAO_PEGTL_ISTRING("pointcount") + { }; + + struct pointcount_value : pegtl::until + { }; + + template<> + struct kw_action< pointcount_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.pointcount = std::stoi(in.string()); + f._state->found_pointcount = true; + } + }; + + ////// xnodes + struct xnodes : TAO_PEGTL_ISTRING("xnodes") + { }; + + struct xnodes_value : pegtl::until + { }; + + template<> + struct kw_action< xnodes_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.n_cells[0] = std::stoi(in.string()); + f._state->found_xnodes = true; + } + }; + + ////// ynodes + struct ynodes : TAO_PEGTL_ISTRING("ynodes") + { }; + + struct ynodes_value : pegtl::until + { }; + + template<> + struct kw_action< ynodes_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.n_cells[1] = std::stoi(in.string()); + f._state->found_ynodes = true; + } + }; + + ////// znodes + struct znodes : TAO_PEGTL_ISTRING("znodes") + { }; + + struct znodes_value : pegtl::until + { }; + + template<> + struct kw_action< znodes_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.n_cells[2] = std::stoi(in.string()); + f._state->found_znodes = true; + } + }; + + ////// xstepsize + struct xstepsize : TAO_PEGTL_ISTRING("xstepsize") + { }; + + struct xstepsize_value : pegtl::until + { }; + + template<> + struct kw_action< xstepsize_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.step_size[0] = std::stof(in.string()); + f._state->found_xstepsize = true; + } + }; + + ////// ystepsize + struct ystepsize : TAO_PEGTL_ISTRING("ystepsize") + { }; + + struct ystepsize_value : pegtl::until + { }; + + template<> + struct kw_action< ystepsize_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.step_size[1] = std::stof(in.string()); + f._state->found_ystepsize = true; + } + }; + + ////// zstepsize + struct zstepsize : TAO_PEGTL_ISTRING("zstepsize") + { }; + + struct zstepsize_value : pegtl::until + { }; + + template<> + struct kw_action< zstepsize_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.step_size[2] = std::stof(in.string()); + f._state->found_zstepsize = true; + } + }; + + ////// xmin + struct xmin : TAO_PEGTL_ISTRING("xmin") + { }; + + struct xmin_value : pegtl::until + { }; + + template<> + struct kw_action< xmin_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bounds_min[0] = std::stof(in.string()); + f._state->found_xmin = true; + } + }; + + ////// ymin + struct ymin : TAO_PEGTL_ISTRING("ymin") + { }; + + struct ymin_value : pegtl::until + { }; + + template<> + struct kw_action< ymin_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bounds_min[1] = std::stof(in.string()); + f._state->found_ymin = true; + } + }; + + ////// zmin + struct zmin : TAO_PEGTL_ISTRING("zmin") + { }; + + struct zmin_value : pegtl::until + { }; + + template<> + struct kw_action< zmin_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bounds_min[2] = std::stof(in.string()); + f._state->found_zmin = true; + } + }; + + ////// xmax + struct xmax : TAO_PEGTL_ISTRING("xmax") + { }; + + struct xmax_value : pegtl::until + { }; + + template<> + struct kw_action< xmax_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bounds_max[0] = std::stof(in.string()); + f._state->found_xmax = true; + } + }; + + ////// ymax + struct ymax : TAO_PEGTL_ISTRING("ymax") + { }; + + struct ymax_value : pegtl::until + { }; + + template<> + struct kw_action< ymax_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bounds_max[1] = std::stof(in.string()); + f._state->found_ymax = true; + } + }; + + ////// zmax + struct zmax : TAO_PEGTL_ISTRING("zmax") + { }; + + struct zmax_value : pegtl::until + { }; + + template<> + struct kw_action< zmax_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bounds_max[2] = std::stof(in.string()); + f._state->found_zmax = true; + } + }; + + ////// xbase + struct xbase : TAO_PEGTL_ISTRING("xbase") + { }; + + struct xbase_value : pegtl::until + { }; + + template<> + struct kw_action< xbase_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.origin[0] = std::stof(in.string()); + f._state->found_xbase = true; + } + }; + + ////// ybase + struct ybase : TAO_PEGTL_ISTRING("ybase") + { }; + + struct ybase_value : pegtl::until + { }; + + template<> + struct kw_action< ybase_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.origin[1] = std::stof(in.string()); + f._state->found_ybase = true; + } + }; + + ////// zbase + struct zbase : TAO_PEGTL_ISTRING("zbase") + { }; + + struct zbase_value : pegtl::until + { }; + + template<> + struct kw_action< zbase_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.origin[2] = std::stof(in.string()); + f._state->found_zbase = true; + } + }; + +} +} +} + +#endif \ No newline at end of file From f4fcb5dcc6570af3dc2ca892c505886ebc5b773c Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 14:19:25 +0200 Subject: [PATCH 04/26] Use pegtl keywords rules to parse segment headers. Improved pegtl rules for keywords. --- include/detail/keywords.hpp | 61 ++++---- include/detail/parse_rules.hpp | 247 +++++-------------------------- include/detail/pegtl_defines.hpp | 71 +++++++++ 3 files changed, 142 insertions(+), 237 deletions(-) diff --git a/include/detail/keywords.hpp b/include/detail/keywords.hpp index a452b9e..e421fec 100644 --- a/include/detail/keywords.hpp +++ b/include/detail/keywords.hpp @@ -1,7 +1,6 @@ #pragma once #ifndef LIBOVF_DETAIL_KEYWORDS_H #define LIBOVF_DETAIL_KEYWORDS_H - #include "ovf.h" #include "pegtl_defines.hpp" @@ -14,7 +13,8 @@ #include -namespace ovf { +namespace ovf +{ namespace detail { @@ -27,11 +27,15 @@ namespace keywords : pegtl::nothing< Rule > { }; + struct end_kw_value : pegtl::at< pegtl::sor> > {}; + struct standard_kw_value : pegtl::until< end_kw_value > {}; + struct numeric_kw_value : pegtl::seq, end_kw_value > {}; + ////// title struct title : TAO_PEGTL_ISTRING("title") { }; - struct title_value : pegtl::until + struct title_value : standard_kw_value { }; template<> @@ -45,11 +49,18 @@ namespace keywords } }; + ////// desc + struct desc : TAO_PEGTL_ISTRING("desc") + { }; + + struct desc_value : standard_kw_value + { }; + ////// valuedim struct valuedim : TAO_PEGTL_ISTRING("valuedim") { }; - struct valuedim_value : pegtl::until + struct valuedim_value : standard_kw_value { }; template<> @@ -67,7 +78,7 @@ namespace keywords struct valueunits : TAO_PEGTL_ISTRING("valueunits") { }; - struct valueunits_value : pegtl::until + struct valueunits_value : standard_kw_value { }; template<> @@ -85,7 +96,7 @@ namespace keywords struct valuelabels : TAO_PEGTL_ISTRING("valuelabels") { }; - struct valuelabels_value : pegtl::until + struct valuelabels_value : standard_kw_value { }; template<> @@ -103,7 +114,7 @@ namespace keywords struct meshtype : TAO_PEGTL_ISTRING("meshtype") { }; - struct meshtype_value : pegtl::until + struct meshtype_value : pegtl::sor< TAO_PEGTL_ISTRING("rectangular"), TAO_PEGTL_ISTRING("irregular")> // Only 'rectangular' or 'irregular' allowed { }; template<> @@ -121,7 +132,7 @@ namespace keywords struct meshunit : TAO_PEGTL_ISTRING("meshunit") { }; - struct meshunit_value : pegtl::until + struct meshunit_value : standard_kw_value { }; template<> @@ -130,7 +141,7 @@ namespace keywords template< typename Input > static void apply( const Input& in, ovf_file & f, ovf_segment & segment) { - segment.meshunit = std::stoi(in.string()); + segment.meshunit = strdup(in.string().c_str()); f._state->found_meshunit = true; } }; @@ -139,7 +150,7 @@ namespace keywords struct pointcount : TAO_PEGTL_ISTRING("pointcount") { }; - struct pointcount_value : pegtl::until + struct pointcount_value : numeric_kw_value { }; template<> @@ -157,7 +168,7 @@ namespace keywords struct xnodes : TAO_PEGTL_ISTRING("xnodes") { }; - struct xnodes_value : pegtl::until + struct xnodes_value : numeric_kw_value { }; template<> @@ -175,7 +186,7 @@ namespace keywords struct ynodes : TAO_PEGTL_ISTRING("ynodes") { }; - struct ynodes_value : pegtl::until + struct ynodes_value : numeric_kw_value { }; template<> @@ -193,7 +204,7 @@ namespace keywords struct znodes : TAO_PEGTL_ISTRING("znodes") { }; - struct znodes_value : pegtl::until + struct znodes_value : numeric_kw_value { }; template<> @@ -211,7 +222,7 @@ namespace keywords struct xstepsize : TAO_PEGTL_ISTRING("xstepsize") { }; - struct xstepsize_value : pegtl::until + struct xstepsize_value : numeric_kw_value { }; template<> @@ -229,7 +240,7 @@ namespace keywords struct ystepsize : TAO_PEGTL_ISTRING("ystepsize") { }; - struct ystepsize_value : pegtl::until + struct ystepsize_value : numeric_kw_value { }; template<> @@ -247,7 +258,7 @@ namespace keywords struct zstepsize : TAO_PEGTL_ISTRING("zstepsize") { }; - struct zstepsize_value : pegtl::until + struct zstepsize_value : numeric_kw_value { }; template<> @@ -265,7 +276,7 @@ namespace keywords struct xmin : TAO_PEGTL_ISTRING("xmin") { }; - struct xmin_value : pegtl::until + struct xmin_value : numeric_kw_value { }; template<> @@ -283,7 +294,7 @@ namespace keywords struct ymin : TAO_PEGTL_ISTRING("ymin") { }; - struct ymin_value : pegtl::until + struct ymin_value : numeric_kw_value { }; template<> @@ -301,7 +312,7 @@ namespace keywords struct zmin : TAO_PEGTL_ISTRING("zmin") { }; - struct zmin_value : pegtl::until + struct zmin_value : numeric_kw_value { }; template<> @@ -319,7 +330,7 @@ namespace keywords struct xmax : TAO_PEGTL_ISTRING("xmax") { }; - struct xmax_value : pegtl::until + struct xmax_value : numeric_kw_value { }; template<> @@ -337,7 +348,7 @@ namespace keywords struct ymax : TAO_PEGTL_ISTRING("ymax") { }; - struct ymax_value : pegtl::until + struct ymax_value : numeric_kw_value { }; template<> @@ -355,7 +366,7 @@ namespace keywords struct zmax : TAO_PEGTL_ISTRING("zmax") { }; - struct zmax_value : pegtl::until + struct zmax_value : numeric_kw_value { }; template<> @@ -373,7 +384,7 @@ namespace keywords struct xbase : TAO_PEGTL_ISTRING("xbase") { }; - struct xbase_value : pegtl::until + struct xbase_value : numeric_kw_value { }; template<> @@ -391,7 +402,7 @@ namespace keywords struct ybase : TAO_PEGTL_ISTRING("ybase") { }; - struct ybase_value : pegtl::until + struct ybase_value : numeric_kw_value { }; template<> @@ -409,7 +420,7 @@ namespace keywords struct zbase : TAO_PEGTL_ISTRING("zbase") { }; - struct zbase_value : pegtl::until + struct zbase_value : numeric_kw_value { }; template<> diff --git a/include/detail/parse_rules.hpp b/include/detail/parse_rules.hpp index 832c345..38f1b70 100644 --- a/include/detail/parse_rules.hpp +++ b/include/detail/parse_rules.hpp @@ -3,6 +3,7 @@ #define LIBOVF_DETAIL_PARSE_RULES_H #include "ovf.h" +#include "keywords.hpp" #include "pegtl_defines.hpp" #include @@ -156,49 +157,6 @@ namespace parse ////////////////////////////////////////////// - struct opt_plus_minus - : pegtl::opt< pegtl::one< '+', '-' > > - {}; - - struct inf - : pegtl::seq< - pegtl::istring< 'i', 'n', 'f' >, - pegtl::opt< pegtl::istring< 'i', 'n', 'i', 't', 'y' > > > - {}; - - struct nan - : pegtl::seq< - pegtl::istring< 'n', 'a', 'n' >, - pegtl::opt< pegtl::one< '(' >, - pegtl::plus< pegtl::alnum >, - pegtl::one< ')' > > > - {}; - - template< typename D > - struct basic_number - : pegtl::if_then_else< - pegtl::one< '.' >, - pegtl::plus< D >, - pegtl::seq< - pegtl::plus< D >, - pegtl::opt< pegtl::one< '.' > >, - pegtl::star< D > - > - > - {}; - - struct exponent - : pegtl::seq< - opt_plus_minus, - pegtl::plus< pegtl::digit > > - {}; - - struct decimal_number - : pegtl::seq< - basic_number< pegtl::digit >, - pegtl::opt< pegtl::one< 'e', 'E' >, exponent > > - {}; - struct hexadecimal_number // TODO: is this actually hexadecimal?? : pegtl::seq< pegtl::one< '0' >, @@ -269,22 +227,45 @@ namespace parse ////////////////////////////////////////////// - struct keyword - : pegtl::until< pegtl::at, - pegtl::if_must, pegtl::any> >//, pegtl::not_at> > - {}; - - struct value : pegtl::seq< pegtl::until> > {}; - - struct keyword_value_line + template + struct keyword_value_pair : pegtl::seq< prefix, - pegtl::pad< keyword, pegtl::blank >, + pegtl::pad< kw, pegtl::blank >, TAO_PEGTL_ISTRING(":"), - pegtl::pad< value, pegtl::blank >, + pegtl::pad< val, pegtl::blank >, + pegtl::until>, finish_line > {}; + struct keyword_value_line + : pegtl::sor< + keyword_value_pair< keywords::title, keywords::title_value >, + keyword_value_pair< keywords::desc, keywords::desc_value >, + keyword_value_pair< keywords::valuedim, keywords::valuedim_value >, + keyword_value_pair< keywords::valueunits, keywords::valueunits_value >, + keyword_value_pair< keywords::valuelabels, keywords::valuelabels_value >, + keyword_value_pair< keywords::meshtype, keywords::meshtype_value >, + keyword_value_pair< keywords::meshunit, keywords::meshunit_value >, + keyword_value_pair< keywords::pointcount, keywords::pointcount_value >, + keyword_value_pair< keywords::xnodes, keywords::xnodes_value >, + keyword_value_pair< keywords::ynodes, keywords::ynodes_value >, + keyword_value_pair< keywords::znodes, keywords::znodes_value >, + keyword_value_pair< keywords::xstepsize, keywords::xstepsize_value >, + keyword_value_pair< keywords::ystepsize, keywords::ystepsize_value >, + keyword_value_pair< keywords::zstepsize, keywords::zstepsize_value >, + keyword_value_pair< keywords::xmin, keywords::xmin_value >, + keyword_value_pair< keywords::ymin, keywords::ymin_value >, + keyword_value_pair< keywords::zmin, keywords::zmin_value >, + keyword_value_pair< keywords::xmax, keywords::xmax_value >, + keyword_value_pair< keywords::ymax, keywords::ymax_value >, + keyword_value_pair< keywords::zmax, keywords::zmax_value >, + keyword_value_pair< keywords::xbase, keywords::xbase_value >, + keyword_value_pair< keywords::ybase, keywords::ybase_value >, + keyword_value_pair< keywords::zbase, keywords::zbase_value > + > + {}; + // struct header : pegtl::seq< @@ -340,8 +321,7 @@ namespace parse // Class template for user-defined actions that does nothing by default. template< typename Rule > - struct ovf_segment_header_action - : pegtl::nothing< Rule > + struct ovf_segment_header_action : keywords::kw_action {}; template<> @@ -468,163 +448,6 @@ namespace parse } }; - //////////////////////////////////////////////////////////////////////////////////////////// - - template<> - struct ovf_segment_header_action< keyword > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment ) - { - f._state->keyword = in.string(); - std::transform(f._state->keyword.begin(), f._state->keyword.end(),f._state->keyword.begin(), ::tolower); - } - }; - - template<> - struct ovf_segment_header_action< value > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment ) - { - f._state->value = in.string(); - } - }; - - template<> - struct ovf_segment_header_action< keyword_value_line > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment ) - { - if( f._state->keyword == "title" ) - { - segment.title = strdup(f._state->value.c_str()); - f._state->found_title = true; - } - else if( f._state->keyword == "desc" ) - segment.comment = strdup(f._state->value.c_str()); - else if( f._state->keyword == "meshunit" ) - { - segment.meshunit = strdup(f._state->value.c_str()); - f._state->found_meshunit = true; - } - else if( f._state->keyword == "valuedim" ) - { - segment.valuedim = std::stoi(f._state->value.c_str()); - f._state->found_valuedim = true; - } - else if( f._state->keyword == "valueunits" ) - { - segment.valueunits = strdup(f._state->value.c_str()); - f._state->found_valueunits = true; - } - else if( f._state->keyword == "valuelabels" ) - { - segment.valuelabels = strdup(f._state->value.c_str()); - f._state->found_valuelabels = true; - } - else if( f._state->keyword == "xmin" ) - { - segment.bounds_min[0] = std::stof(f._state->value.c_str()); - f._state->found_xmin = true; - } - else if( f._state->keyword == "ymin" ) - { - segment.bounds_min[1] = std::stof(f._state->value.c_str()); - f._state->found_ymin = true; - } - else if( f._state->keyword == "zmin" ) - { - segment.bounds_min[2] = std::stof(f._state->value.c_str()); - f._state->found_zmin = true; - } - else if( f._state->keyword == "xmax" ) - { - segment.bounds_max[0] = std::stof(f._state->value.c_str()); - f._state->found_xmax = true; - } - else if( f._state->keyword == "ymax" ) - { - segment.bounds_max[1] = std::stof(f._state->value.c_str()); - f._state->found_ymax = true; - } - else if( f._state->keyword == "zmax" ) - { - segment.bounds_max[2] = std::stof(f._state->value.c_str()); - f._state->found_zmax = true; - } - else if( f._state->keyword == "meshtype" ) - { - std::string meshtype = f._state->value; - std::transform(meshtype.begin(), meshtype.end(), meshtype.begin(), ::tolower); - segment.meshtype = strdup(meshtype.c_str()); - f._state->found_meshtype = true; - } - else if( f._state->keyword == "xbase" ) - { - segment.origin[0] = std::stof(f._state->value.c_str()); - f._state->found_xbase = true; - } - else if( f._state->keyword == "ybase" ) - { - segment.origin[1] = std::stof(f._state->value.c_str()); - f._state->found_ybase = true; - } - else if( f._state->keyword == "zbase" ) - { - segment.origin[2] = std::stof(f._state->value.c_str()); - f._state->found_zbase = true; - } - else if( f._state->keyword == "xstepsize" ) - { - segment.step_size[0] = std::stof(f._state->value.c_str()); - f._state->found_xstepsize = true; - } - else if( f._state->keyword == "ystepsize" ) - { - segment.step_size[1] = std::stof(f._state->value.c_str()); - f._state->found_ystepsize = true; - } - else if( f._state->keyword == "zstepsize" ) - { - segment.step_size[2] = std::stof(f._state->value.c_str()); - f._state->found_zstepsize = true; - } - else if( f._state->keyword == "xnodes" ) - { - segment.n_cells[0] = std::stoi(f._state->value.c_str()); - f._state->found_xnodes = true; - } - else if( f._state->keyword == "ynodes" ) - { - segment.n_cells[1] = std::stoi(f._state->value.c_str()); - f._state->found_ynodes = true; - } - else if( f._state->keyword == "znodes" ) - { - segment.n_cells[2] = std::stoi(f._state->value.c_str()); - f._state->found_znodes = true; - } - else if( f._state->keyword == "pointcount" ) - { - segment.pointcount = std::stoi(f._state->value.c_str()); - f._state->found_pointcount = true; - } - else - { - // UNKNOWN KEYWORD - throw tao::pegtl::parse_error( fmt::format( - "unknown keyword \"{}\": \"{}\"", f._state->keyword, f._state->value), in ); - } - - f._state->keyword = ""; - f._state->value = ""; - } - }; - - //////////////////////////////////////////////////////////////////////////////////////////// - struct data_text : pegtl::seq< begin, TAO_PEGTL_ISTRING("Data Text"), pegtl::eol, diff --git a/include/detail/pegtl_defines.hpp b/include/detail/pegtl_defines.hpp index 116699f..25e249b 100644 --- a/include/detail/pegtl_defines.hpp +++ b/include/detail/pegtl_defines.hpp @@ -6,6 +6,7 @@ #include #include #include +#include struct parser_state { @@ -56,4 +57,74 @@ struct parser_state std::ios::pos_type n_segments_pos = 0; }; +namespace ovf +{ +namespace detail +{ +namespace parse +{ + + namespace pegtl = tao::pegtl; + + struct opt_plus_minus + : pegtl::opt< pegtl::one< '+', '-' > > + {}; + + struct inf + : pegtl::seq< + pegtl::istring< 'i', 'n', 'f' >, + pegtl::opt< pegtl::istring< 'i', 'n', 'i', 't', 'y' > > > + {}; + + struct nan + : pegtl::seq< + pegtl::istring< 'n', 'a', 'n' >, + pegtl::opt< pegtl::one< '(' >, + pegtl::plus< pegtl::alnum >, + pegtl::one< ')' > > > + {}; + + template< typename D > + struct basic_number + : pegtl::if_then_else< + pegtl::one< '.' >, + pegtl::plus< D >, + pegtl::seq< + pegtl::plus< D >, + pegtl::opt< pegtl::one< '.' > >, + pegtl::star< D > + > + > + {}; + + struct exponent + : pegtl::seq< + opt_plus_minus, + pegtl::plus< pegtl::digit > > + {}; + + struct decimal_number + : pegtl::seq< + basic_number< pegtl::digit >, + pegtl::opt< pegtl::one< 'e', 'E' >, exponent > > + {}; + + struct hexadecimal_number // TODO: is this actually hexadecimal?? + : pegtl::seq< + pegtl::one< '0' >, + pegtl::one< 'x', 'X' >, + basic_number< pegtl::xdigit >, + pegtl::opt< pegtl::one< 'p', 'P' >, exponent > > + {}; + + struct float_value + : pegtl::seq< + opt_plus_minus, + decimal_number > + {}; + +} +} +} + #endif \ No newline at end of file From fcee71d1b0abac4b459841187290062ee5d996ae Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 16:01:47 +0200 Subject: [PATCH 05/26] Implemented atomistic keywords --- include/detail/atomistic_keywords.hpp | 352 ++++++++++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 include/detail/atomistic_keywords.hpp diff --git a/include/detail/atomistic_keywords.hpp b/include/detail/atomistic_keywords.hpp new file mode 100644 index 0000000..a384c5a --- /dev/null +++ b/include/detail/atomistic_keywords.hpp @@ -0,0 +1,352 @@ +#pragma once +#ifndef LIBOVF_DETAIL_ATOMISTIC_KEYWORDS_H +#define LIBOVF_DETAIL_ATOMISTIC_KEYWORDS_H +#include "keywords.hpp" + +namespace ovf +{ +namespace detail +{ +namespace keywords +{ + ////// bravaisa + // x + struct bravaisa_value_x : pegtl::pad + { }; + + template<> + struct kw_action< bravaisa_value_x > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bravaisa[0] = std::stof(in.string()); + } + }; + + // y + struct bravaisa_value_y : pegtl::pad + { }; + + template<> + struct kw_action< bravaisa_value_y > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bravaisa[1] = std::stof(in.string()); + } + }; + + // z + struct bravaisa_value_z : pegtl::pad + { }; + + template<> + struct kw_action< bravaisa_value_z > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bravaisa[2] = std::stof(in.string()); + } + }; + + struct bravaisa_value : pegtl::seq + { }; + + template<> + struct kw_action< bravaisa_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + f._state->found_bravaisa = true; + } + }; + + struct bravaisa : TAO_PEGTL_ISTRING("bravaisa") + { }; + + ////// bravaisb + // x + struct bravaisb_value_x : pegtl::pad + { }; + + template<> + struct kw_action< bravaisb_value_x > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bravaisb[0] = std::stof(in.string()); + } + }; + + // y + struct bravaisb_value_y : pegtl::pad + { }; + + template<> + struct kw_action< bravaisb_value_y > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bravaisb[1] = std::stof(in.string()); + } + }; + + // z + struct bravaisb_value_z : pegtl::pad + { }; + + template<> + struct kw_action< bravaisb_value_z > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bravaisb[2] = std::stof(in.string()); + } + }; + + struct bravaisb_value : pegtl::seq + { }; + + template<> + struct kw_action< bravaisb_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + f._state->found_bravaisb = true; + } + }; + + struct bravaisb : TAO_PEGTL_ISTRING("bravaisb") + { }; + + ////// bravaisc + // x + struct bravaisc_value_x : pegtl::pad + { }; + + template<> + struct kw_action< bravaisc_value_x > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bravaisc[0] = std::stof(in.string()); + } + }; + + // y + struct bravaisc_value_y : pegtl::pad + { }; + + template<> + struct kw_action< bravaisc_value_y > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bravaisc[1] = std::stof(in.string()); + } + }; + + // z + struct bravaisc_value_z : pegtl::pad + { }; + + template<> + struct kw_action< bravaisc_value_z > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bravaisc[2] = std::stof(in.string()); + } + }; + + struct bravaisc_value : pegtl::seq + { }; + + template<> + struct kw_action< bravaisc_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + f._state->found_bravaisc = true; + } + }; + + struct bravaisc : TAO_PEGTL_ISTRING("bravaisc") + { }; + + + ////// ncellpoints + struct ncellpoints : TAO_PEGTL_ISTRING("ncellpoints") + { }; + + struct ncellpoints_value : numeric_kw_value + { }; + + template<> + struct kw_action< ncellpoints_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.ncellpoints = std::stoi(in.string()); + f._state->found_ncellpoints = true; + segment.basis = new float[3 * segment.ncellpoints]; + } + }; + + ////// anodes + struct anodes : TAO_PEGTL_ISTRING("anodes") + { }; + + struct anodes_value : numeric_kw_value + { }; + + template<> + struct kw_action< anodes_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.anodes = std::stoi(in.string()); + f._state->found_anodes = true; + } + }; + + ////// bnodes + struct bnodes : TAO_PEGTL_ISTRING("bnodes") + { }; + + struct bnodes_value : numeric_kw_value + { }; + + template<> + struct kw_action< bnodes_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.bnodes = std::stoi(in.string()); + f._state->found_bnodes = true; + } + }; + + ////// cnodes + struct cnodes : TAO_PEGTL_ISTRING("cnodes") + { }; + + struct cnodes_value : numeric_kw_value + { }; + + template<> + struct kw_action< cnodes_value > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.cnodes = std::stoi(in.string()); + f._state->found_cnodes = true; + } + }; + + ////// basis + struct basis : TAO_PEGTL_ISTRING("basis") + { }; + + struct cur_basis_line_value_x : pegtl::pad + { }; + + struct cur_basis_line_value_y : pegtl::pad + { }; + + struct cur_basis_line_value_z : pegtl::pad + { }; + + struct basis_value_line : pegtl::seq< pegtl::string<'#'>, cur_basis_line_value_x, cur_basis_line_value_y, cur_basis_line_value_z, pegtl::eol > + { }; + + struct basis_value : pegtl::seq< pegtl::eol, pegtl::plus< basis_value_line > > + { + }; + + template<> + struct kw_action< cur_basis_line_value_x > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + if( !f._state->found_ncellpoints ) // Need to make sure that the basis array is already allocated + { + throw std::exception("ncellpoints must be specified before the basis!"); + } + segment.basis[3 * f._state->_cur_basis_line + 0] = std::stof(in.string()); + } + }; + + template<> + struct kw_action< cur_basis_line_value_y > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + if( !f._state->found_ncellpoints ) // Need to make sure that the basis array is already allocated + { + throw std::exception("ncellpoints must be specified before the basis!"); + } + segment.basis[3*f._state->_cur_basis_line + 1] = std::stof(in.string()); + } + }; + + template<> + struct kw_action< cur_basis_line_value_z > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + if( !f._state->found_ncellpoints ) // Need to make sure that the basis array is already allocated + { + throw std::exception("ncellpoints must be specified before the basis!"); + } + segment.basis[3* f._state->_cur_basis_line + 2] = std::stof(in.string()); + } + }; + + template<> + struct kw_action< basis_value_line > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + f._state->_cur_basis_line++; + } + }; + + template<> + struct kw_action + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + f._state->found_basis = true; + if( segment.ncellpoints != f._state->_cur_basis_line ) // Need to make sure that the basis array is already allocated + { + throw std::exception( fmt::format("ncellpoints ({}) and number of specified basis atoms ({}) does not match!", segment.ncellpoints, f._state->_cur_basis_line )); + } + } + }; +} +} +} + +#endif \ No newline at end of file From e8346d143603fd6c704a6ebe7fe440ac01808c45 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 16:16:07 +0200 Subject: [PATCH 06/26] Improved exceptions in atomistic keywords --- include/detail/atomistic_keywords.hpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/include/detail/atomistic_keywords.hpp b/include/detail/atomistic_keywords.hpp index a384c5a..db67d07 100644 --- a/include/detail/atomistic_keywords.hpp +++ b/include/detail/atomistic_keywords.hpp @@ -277,8 +277,7 @@ namespace keywords { }; struct basis_value : pegtl::seq< pegtl::eol, pegtl::plus< basis_value_line > > - { - }; + { }; template<> struct kw_action< cur_basis_line_value_x > @@ -288,7 +287,7 @@ namespace keywords { if( !f._state->found_ncellpoints ) // Need to make sure that the basis array is already allocated { - throw std::exception("ncellpoints must be specified before the basis!"); + throw tao::pegtl::parse_error(fmt::format("ncellpoints must be specified before the basis!"), in); } segment.basis[3 * f._state->_cur_basis_line + 0] = std::stof(in.string()); } @@ -302,7 +301,7 @@ namespace keywords { if( !f._state->found_ncellpoints ) // Need to make sure that the basis array is already allocated { - throw std::exception("ncellpoints must be specified before the basis!"); + throw tao::pegtl::parse_error(fmt::format("ncellpoints must be specified before the basis!"), in); } segment.basis[3*f._state->_cur_basis_line + 1] = std::stof(in.string()); } @@ -316,7 +315,7 @@ namespace keywords { if( !f._state->found_ncellpoints ) // Need to make sure that the basis array is already allocated { - throw std::exception("ncellpoints must be specified before the basis!"); + throw tao::pegtl::parse_error(fmt::format("ncellpoints must be specified before the basis!"), in); } segment.basis[3* f._state->_cur_basis_line + 2] = std::stof(in.string()); } @@ -341,7 +340,7 @@ namespace keywords f._state->found_basis = true; if( segment.ncellpoints != f._state->_cur_basis_line ) // Need to make sure that the basis array is already allocated { - throw std::exception( fmt::format("ncellpoints ({}) and number of specified basis atoms ({}) does not match!", segment.ncellpoints, f._state->_cur_basis_line )); + throw tao::pegtl::parse_error( fmt::format("ncellpoints ({}) and number of specified basis atoms ({}) does not match!", segment.ncellpoints, f._state->_cur_basis_line ), in); } } }; From f3f02575c72da62c70c63d200f3ae7f4eeea8629 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 16:17:55 +0200 Subject: [PATCH 07/26] Implemented parsing of atomsitic keywords --- include/detail/keywords.hpp | 3 +- include/detail/parse.hpp | 11 ++++++ include/detail/parse_rules.hpp | 12 ++++++- include/detail/pegtl_defines.hpp | 9 +++++ include/detail/write.hpp | 59 +++++++++++++++++++++++++++++--- include/ovf.h | 14 ++++++++ src/ovf.cpp | 1 + 7 files changed, 103 insertions(+), 6 deletions(-) diff --git a/include/detail/keywords.hpp b/include/detail/keywords.hpp index e421fec..240fb81 100644 --- a/include/detail/keywords.hpp +++ b/include/detail/keywords.hpp @@ -20,6 +20,7 @@ namespace detail namespace keywords { + using ovf::detail::parse::decimal_number; namespace pegtl = tao::pegtl; template< typename Rule > @@ -29,7 +30,7 @@ namespace keywords struct end_kw_value : pegtl::at< pegtl::sor> > {}; struct standard_kw_value : pegtl::until< end_kw_value > {}; - struct numeric_kw_value : pegtl::seq, end_kw_value > {}; + struct numeric_kw_value : pegtl::seq, end_kw_value > {}; ////// title struct title : TAO_PEGTL_ISTRING("title") diff --git a/include/detail/parse.hpp b/include/detail/parse.hpp index c82f10f..a402303 100644 --- a/include/detail/parse.hpp +++ b/include/detail/parse.hpp @@ -162,6 +162,17 @@ namespace parse file._state->found_ynodes = false; file._state->found_znodes = false; file._state->found_pointcount = false; + file._state->found_bravaisa = false; + file._state->found_bravaisb = false; + file._state->found_bravaisc = false; + file._state->found_ncellpoints = false; + file._state->found_anodes = false; + file._state->found_bnodes = false; + file._state->found_cnodes = false; + file._state->found_basis = false; + + file._state->_cur_basis_line = 0; + bool success = false; if( file.version == 2 ) diff --git a/include/detail/parse_rules.hpp b/include/detail/parse_rules.hpp index 38f1b70..efe3558 100644 --- a/include/detail/parse_rules.hpp +++ b/include/detail/parse_rules.hpp @@ -4,6 +4,7 @@ #include "ovf.h" #include "keywords.hpp" +#include "atomistic_keywords.hpp" #include "pegtl_defines.hpp" #include @@ -262,7 +263,16 @@ namespace parse keyword_value_pair< keywords::zmax, keywords::zmax_value >, keyword_value_pair< keywords::xbase, keywords::xbase_value >, keyword_value_pair< keywords::ybase, keywords::ybase_value >, - keyword_value_pair< keywords::zbase, keywords::zbase_value > + keyword_value_pair< keywords::zbase, keywords::zbase_value >, + // Atomistic extension + keyword_value_pair< keywords::anodes, keywords::anodes_value >, + keyword_value_pair< keywords::bnodes, keywords::bnodes_value >, + keyword_value_pair< keywords::cnodes, keywords::cnodes_value >, + keyword_value_pair< keywords::bravaisa, keywords::bravaisa_value >, + keyword_value_pair< keywords::bravaisb, keywords::bravaisb_value >, + keyword_value_pair< keywords::bravaisc, keywords::bravaisc_value >, + keyword_value_pair< keywords::ncellpoints, keywords::ncellpoints_value >, + keyword_value_pair< keywords::basis, keywords::basis_value > > {}; diff --git a/include/detail/pegtl_defines.hpp b/include/detail/pegtl_defines.hpp index 25e249b..3ef72d8 100644 --- a/include/detail/pegtl_defines.hpp +++ b/include/detail/pegtl_defines.hpp @@ -42,6 +42,15 @@ struct parser_state bool found_ynodes = false; bool found_znodes = false; bool found_pointcount = false; + bool found_bravaisa = false; + bool found_bravaisb = false; + bool found_bravaisc = false; + bool found_ncellpoints = false; + bool found_anodes = false; + bool found_bnodes = false; + bool found_cnodes = false; + bool found_basis = false; + int _cur_basis_line = 0; /* messages, e.g. in case a function returned OVF_ERROR. diff --git a/include/detail/write.hpp b/include/detail/write.hpp index 948b4a6..5ce2ff8 100644 --- a/include/detail/write.hpp +++ b/include/detail/write.hpp @@ -72,9 +72,18 @@ namespace write } - inline std::string top_header_string() + inline std::string top_header_string(bool atomistic, bool compatibility) { std::string ret = "# OOMMF OVF 2.0\n"; + + if(compatibility) + { + ret += "##% AOVF 1.0\n"; + } + if(atomistic) + { + ret = "# AOVF 1.0\n"; + } ret += empty_line; // create padding string @@ -260,12 +269,14 @@ namespace write // Type of mesh and further keywords depending on it std::string meshtype = segment->meshtype; - if( meshtype == "" ) + bool atomistic_compatibility = (meshtype == "lattice" && !file->atomistic); // If meshtype is `lattice` and we run in compatibility mode + if( meshtype == "" || atomistic_compatibility) meshtype = "rectangular"; + output_to_file += fmt::format( "# meshtype: {}\n", meshtype ); int n_rows = 0; - if( meshtype == "rectangular" ) + if( meshtype == "rectangular" && !atomistic_compatibility) { // Latice origin in space output_to_file += fmt::format( "# xbase: {}\n", segment->origin[0] ); @@ -289,6 +300,46 @@ namespace write output_to_file += fmt::format( "# pointcount: {}\n", segment->pointcount ); n_rows = segment->pointcount; } + else if( std::string(segment->meshtype) == "lattice" || atomistic_compatibility) + { + std::string prefix = "#"; + if(atomistic_compatibility) + { + prefix = "##%"; + } + output_to_file += fmt::format( "{} anodes: {}\n", prefix, segment->n_cells[0] ); + output_to_file += fmt::format( "{} bnodes: {}\n", prefix, segment->n_cells[1] ); + output_to_file += fmt::format( "{} cnodes: {}\n", prefix, segment->n_cells[2] ); + output_to_file += fmt::format( "{} bravaisa: {} {} {}\n", prefix, segment->bravaisa[0], segment->bravaisa[1], segment->bravaisa[2] ); + output_to_file += fmt::format( "{} bravaisb: {} {} {}\n", prefix, segment->bravaisb[0], segment->bravaisb[1], segment->bravaisb[2] ); + output_to_file += fmt::format( "{} bravaisc: {} {} {}\n", prefix, segment->bravaisc[0], segment->bravaisc[1], segment->bravaisc[2] ); + output_to_file += fmt::format( "{} ncellpoints: {}\n", prefix, segment->ncellpoints ); + output_to_file += fmt::format( "{} basis:\n", prefix); + for(int i=0; incellpoints; i++) + { + output_to_file += fmt::format( "{} {} {} {}\n", prefix, segment->basis[3*i], segment->basis[3*i+1], segment->basis[3*i+2] ); + } + + if(atomistic_compatibility) // In compatibility mode we have to add the required fields for the rectangular mesh + { + // Latice origin in space + output_to_file += fmt::format( "# xbase: {}\n", segment->origin[0] ); + output_to_file += fmt::format( "# ybase: {}\n", segment->origin[1] ); + output_to_file += fmt::format( "# zbase: {}\n", segment->origin[2] ); + + // Mesh spacing + output_to_file += fmt::format( "# xstepsize: {}\n", segment->step_size[0] ); + output_to_file += fmt::format( "# ystepsize: {}\n", segment->step_size[1] ); + output_to_file += fmt::format( "# zstepsize: {}\n", segment->step_size[2] ); + + // Number of nodes along each direction + output_to_file += fmt::format( "# xnodes: {}\n", segment->n_cells[0] * segment->ncellpoints ); // We fold the basis atoms into xnodes + output_to_file += fmt::format( "# ynodes: {}\n", segment->n_cells[1] ); + output_to_file += fmt::format( "# znodes: {}\n", segment->n_cells[2] ); + } + + n_rows = segment->n_cells[0] * segment->n_cells[1] * segment->n_cells[2] * segment->ncellpoints; + } else { file->_state->message_latest = fmt::format( @@ -359,7 +410,7 @@ namespace write file_handle handle(file->file_name, false); file->n_segments = 0; file->version = 2; - handle.write( {top_header_string(), output_to_file} ); + handle.write( {top_header_string(file->atomistic, atomistic_compatibility), output_to_file} ); } file->found = true; file->is_ovf = true; diff --git a/include/ovf.h b/include/ovf.h index 743651d..ceab3af 100644 --- a/include/ovf.h +++ b/include/ovf.h @@ -55,6 +55,16 @@ struct ovf_segment { float lattice_constant; float origin[3]; + /* fields for the atomistic extension */ + float bravaisa[3]; + float bravaisb[3]; + float bravaisc[3]; + int ncellpoints; + int anodes; + int bnodes; + int cnodes; + float * basis; + /* then some "private" internal fields */ }; @@ -64,6 +74,7 @@ struct parser_state; /* the main struct which keeps the info on the main header of a file */ struct ovf_file { const char * file_name; + char * version_string; int version; @@ -74,6 +85,9 @@ struct ovf_file { /* number of segments the file should contain */ int n_segments; + /* use the atomistic extension */ + bool atomistic; + /* then some "private" internal fields */ struct parser_state * _state; }; diff --git a/src/ovf.cpp b/src/ovf.cpp index 5303243..ebd823d 100644 --- a/src/ovf.cpp +++ b/src/ovf.cpp @@ -15,6 +15,7 @@ try ovf_file_ptr->is_ovf = false; ovf_file_ptr->n_segments = 0; ovf_file_ptr->_state = new parser_state; + ovf_file_ptr->atomistic = false; // Check if the file exists std::fstream filestream( filename ); From b8b3d635e60f5aef0361b90d7fc874edecd66ece Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 16:24:05 +0200 Subject: [PATCH 08/26] Adjusted ctypes structs to atomistic properties --- python/ovf/ovf.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/python/ovf/ovf.py b/python/ovf/ovf.py index fdaf6ff..d077119 100644 --- a/python/ovf/ovf.py +++ b/python/ovf/ovf.py @@ -34,7 +34,15 @@ class ovf_segment(ctypes.Structure): ("bounds_min", ctypes.c_float*3), ("bounds_max", ctypes.c_float*3), ("lattice_constant", ctypes.c_float), - ("origin", ctypes.c_float*3) + ("origin", ctypes.c_float*3), + ("bravaisa", ctypes.c_float*3), + ("bravaisb", ctypes.c_float*3), + ("bravaisc", ctypes.c_float*3), + ("ncellpoints", ctypes.c_int), + ("anodes", ctypes.c_int), + ("bnodes", ctypes.c_int), + ("cnodes", ctypes.c_int), + ("basis", ctypes.POINTER(ctypes.c_float)) ] def __init__(self, title="", comment="", valuedim=1, valueunits="", valuelabels="", meshtype="", meshunits="", @@ -108,10 +116,12 @@ class _ovf_file(ctypes.Structure): ### Some properties _fields_ = [ ("file_name", ctypes.c_char_p), + ("version_string", ctypes.c_char_p), ("version", ctypes.c_int), ("found", ctypes.c_bool), ("is_ovf", ctypes.c_bool), ("n_segments", ctypes.c_int), + ("atomistic", ctypes.c_bool), ("_state", ctypes.c_void_p) ] From b6005d616369fe4e9e334fb497de4ea5a3ed9c33 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 17:03:00 +0200 Subject: [PATCH 09/26] Added unit test for atomistic ovf and made it work --- include/detail/keywords.hpp | 2 +- include/detail/parse.hpp | 6 +- include/detail/parse_rules.hpp | 46 +++++++++-- test/simple.cpp | 136 +++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 11 deletions(-) diff --git a/include/detail/keywords.hpp b/include/detail/keywords.hpp index 240fb81..6c0a379 100644 --- a/include/detail/keywords.hpp +++ b/include/detail/keywords.hpp @@ -115,7 +115,7 @@ namespace keywords struct meshtype : TAO_PEGTL_ISTRING("meshtype") { }; - struct meshtype_value : pegtl::sor< TAO_PEGTL_ISTRING("rectangular"), TAO_PEGTL_ISTRING("irregular")> // Only 'rectangular' or 'irregular' allowed + struct meshtype_value : pegtl::sor< TAO_PEGTL_ISTRING("rectangular"), TAO_PEGTL_ISTRING("irregular"), TAO_PEGTL_ISTRING("lattice")> // Only 'rectangular', 'irregular' or 'lattice' allowed { }; template<> diff --git a/include/detail/parse.hpp b/include/detail/parse.hpp index a402303..e8fe913 100644 --- a/include/detail/parse.hpp +++ b/include/detail/parse.hpp @@ -70,7 +70,7 @@ namespace parse if( success ) { success = false; - if( file.version == 2 ) + if( file.version == 2 || (file.version == 1 && std::string(file.version_string) == "AOVF") ) { success = pegtl::parse< pegtl::until>>> >( in, file ); success = pegtl::parse< pegtl::plus, v2::ovf_segment_action >( in, file ); @@ -175,7 +175,7 @@ namespace parse bool success = false; - if( file.version == 2 ) + if( file.version == 2 || (file.version == 1 && std::string(file.version_string) == "AOVF") ) { success = pegtl::parse< pegtl::plus, v2::ovf_segment_header_action, v2::ovf_segment_header_control >( in, file, segment ); } @@ -241,7 +241,7 @@ namespace parse int retcode = OVF_ERROR; bool success = false; - if( file.version == 2 ) + if( file.version == 2 || (file.version == 1 && std::string(file.version_string) == "AOVF")) { file._state->max_data_index = segment.N*segment.valuedim; success = pegtl::parse< v2::segment_data, v2::ovf_segment_data_action >( in, file, segment, data ); diff --git a/include/detail/parse_rules.hpp b/include/detail/parse_rules.hpp index efe3558..8ae023e 100644 --- a/include/detail/parse_rules.hpp +++ b/include/detail/parse_rules.hpp @@ -27,6 +27,16 @@ namespace parse : pegtl::string< '#' > {}; + // "#" + struct magic_char + : pegtl::string< '%' > + {}; + + // "##% " + struct magic_prefix + : pegtl::seq< pegtl::string< '#', '#'>, magic_char > + {}; + // "#\eol" struct empty_line : pegtl::seq< pegtl::string< '#' >, pegtl::star > @@ -37,9 +47,17 @@ namespace parse : pegtl::range< '1', '2' > {}; + struct version_string + : pegtl::sor< TAO_PEGTL_ISTRING("OOMMF OVF"), TAO_PEGTL_ISTRING("AOVF") > + {}; + // " OOMMF OVF " struct version - : pegtl::seq< prefix, pegtl::pad< TAO_PEGTL_ISTRING("OOMMF OVF"), pegtl::blank >, version_number, pegtl::until > + : + pegtl::sor< + pegtl::seq< prefix, pegtl::pad< TAO_PEGTL_ISTRING("OOMMF OVF"), pegtl::blank>, pegtl::until, magic_prefix, pegtl::pad< version_string, pegtl::blank>, version_number, pegtl::until >, + pegtl::seq< prefix, pegtl::pad< version_string, pegtl::blank >, version_number, pegtl::until > + > {}; // " Segment count: " @@ -79,6 +97,16 @@ namespace parse } }; + template<> + struct ovf_file_action< version_string > + { + template< typename Input > + static void apply( const Input& in, ovf_file & file ) + { + file.version_string = strdup(in.string().c_str()); + } + }; + template<> struct ovf_file_action< segment_count_number > { @@ -345,12 +373,6 @@ namespace parse std::vector missing_keywords(0); std::vector wrong_keywords(0); - if( std::string(segment.meshtype) != "rectangular" && std::string(segment.meshtype) != "irregular") - { - throw tao::pegtl::parse_error( fmt::format( - "Invalid meshtype: \"{}\"", segment.meshtype), in ); - } - if( !file._state->found_title ) missing_keywords.push_back("title"); if( !file._state->found_meshunit ) @@ -427,6 +449,16 @@ namespace parse wrong_keywords.push_back("pointcount"); } + if( std::string(segment.meshtype) == "lattice" ) + { + segment.N = segment.anodes * segment.bnodes * segment.cnodes * segment.ncellpoints; + // if( !file._state->found_pointcount ) + // missing_keywords.push_back("pointcount"); + } else { + // if( file._state->found_pointcount ) + // wrong_keywords.push_back("pointcount"); + } + if( missing_keywords.size() > 0 ) { std::string message = fmt::format( "Missing keywords: \"{}\"", missing_keywords[0] ); diff --git a/test/simple.cpp b/test/simple.cpp index 54cec8e..b01ee42 100644 --- a/test/simple.cpp +++ b/test/simple.cpp @@ -226,6 +226,142 @@ TEST_CASE( "Read", "[read]" ) REQUIRE( field[6] == 2 ); REQUIRE( field[9] == 0 ); + // close + ovf_close(file); + } +} + +TEST_CASE( "Atomistic Write", "[write]" ) +{ + const char * testfile = "testfile_cpp.aovf"; + + SECTION( "write" ) + { + // segment header + auto segment = ovf_segment_create(); + segment->title = const_cast("ovf test title - write"); + segment->comment = const_cast("test write"); + segment->valuedim = 3; + segment->n_cells[0] = 2; + segment->n_cells[1] = 1; + segment->n_cells[2] = 1; + + // Fill in atomistic values + segment->bravaisa[0] = 1; + segment->bravaisa[1] = 0; + segment->bravaisa[2] = 0; + + segment->bravaisb[0] = 0; + segment->bravaisb[1] = 1; + segment->bravaisb[2] = 0; + + segment->bravaisc[0] = 0; + segment->bravaisc[1] = 0; + segment->bravaisc[2] = 1; + + segment->ncellpoints = 2; + float basis[6] = { + 0,0.1,0.2, + 2,3,4 + }; + + segment->basis = (float *) malloc( segment->ncellpoints * 3 * sizeof(float) ); + for( int ib=0; ib < segment->ncellpoints; ib++) + { + for(int i=0; i<3; i++) + { + segment->basis[ib*3 + i] = basis[ib*3 + i]; + } + } + + segment->N = 4; + segment->meshtype = const_cast("lattice"); + + // data + std::vector field(3*segment->N, 1); + field[0] = 3; + field[3] = 2; + field[6] = 1; + field[9] = 0; + + // open + auto file = ovf_open(testfile); + file->atomistic = true; // Set the flag for the atomistic extension + + // write + int success = ovf_write_segment_8(file, segment, field.data(), OVF_FORMAT_TEXT); + // if( OVF_OK != success ) + // std::cerr << ovf_latest_message(file) << std::endl; + REQUIRE( success == OVF_OK ); + + // close + ovf_close(file); + } +} + +TEST_CASE( "Atomistic Read", "[read]" ) +{ + const char * testfile = "testfile_cpp.aovf"; + + SECTION( "first segment" ) + { + // open + auto file = ovf_open(testfile); + std::cerr << ovf_latest_message(file) << std::endl; + REQUIRE( file->found == true ); + REQUIRE( file->is_ovf == true ); + REQUIRE( file->n_segments == 1 ); + int index = 0; + + // segment header + auto segment = ovf_segment_create(); + + // read header + int success = ovf_read_segment_header(file, index, segment); + if( OVF_OK != success ) + std::cerr << ovf_latest_message(file) << std::endl; + REQUIRE( success == OVF_OK ); + REQUIRE( segment->N == 4 ); + + REQUIRE( segment->ncellpoints == 2); + + REQUIRE( segment->basis[0] == 0); + REQUIRE( segment->basis[1] == 0.1f); + REQUIRE( segment->basis[2] == 0.2f); + REQUIRE( segment->basis[3] == 2); + REQUIRE( segment->basis[4] == 3); + REQUIRE( segment->basis[5] == 4); + + REQUIRE( segment->bravaisa[0] == 1); + REQUIRE( segment->bravaisa[1] == 0); + REQUIRE( segment->bravaisa[2] == 0); + + REQUIRE( segment->bravaisb[0] == 0); + REQUIRE( segment->bravaisb[1] == 1); + REQUIRE( segment->bravaisb[2] == 0); + + REQUIRE( segment->bravaisc[0] == 0); + REQUIRE( segment->bravaisc[1] == 0); + REQUIRE( segment->bravaisc[2] == 1); + + + REQUIRE( std::string(segment->meshtype) == "lattice" ); + + // data + std::vector field(3*segment->N); + + // read data + success = ovf_read_segment_data_4(file, index, segment, field.data()); + if( OVF_OK != success ) + std::cerr << ovf_latest_message(file) << std::endl; + REQUIRE( success == OVF_OK ); + REQUIRE( field[0] == 3 ); + REQUIRE( field[1] == 1 ); + REQUIRE( field[3] == 2 ); + REQUIRE( field[6] == 1 ); + REQUIRE( field[9] == 0 ); + + // close ovf_close(file); } From 0f19e98c02d4e512559b0a5a3fce3fdbc0f58c76 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 18:55:52 +0200 Subject: [PATCH 10/26] Added check for missing and wrong keywords for meshtype 'lattice' --- include/detail/parse_rules.hpp | 36 ++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/include/detail/parse_rules.hpp b/include/detail/parse_rules.hpp index 8ae023e..143dffe 100644 --- a/include/detail/parse_rules.hpp +++ b/include/detail/parse_rules.hpp @@ -452,11 +452,39 @@ namespace parse if( std::string(segment.meshtype) == "lattice" ) { segment.N = segment.anodes * segment.bnodes * segment.cnodes * segment.ncellpoints; - // if( !file._state->found_pointcount ) - // missing_keywords.push_back("pointcount"); + if( !file._state->found_anodes ) + missing_keywords.push_back("anodes"); + if( !file._state->found_bnodes ) + missing_keywords.push_back("bnodes"); + if( !file._state->found_cnodes ) + missing_keywords.push_back("cnodes"); + if( !file._state->found_ncellpoints ) + missing_keywords.push_back("ncellpoints"); + if( !file._state->found_basis ) + missing_keywords.push_back("basis"); + if( !file._state->found_bravaisa ) + missing_keywords.push_back("bravaisa"); + if( !file._state->found_bravaisb ) + missing_keywords.push_back("bravaisb"); + if( !file._state->found_bravaisc ) + missing_keywords.push_back("bravaisc"); } else { - // if( file._state->found_pointcount ) - // wrong_keywords.push_back("pointcount"); + if( file._state->found_anodes ) + wrong_keywords.push_back("anodes"); + if( file._state->found_bnodes ) + wrong_keywords.push_back("bnodes"); + if( file._state->found_cnodes ) + wrong_keywords.push_back("cnodes"); + if( file._state->found_ncellpoints ) + wrong_keywords.push_back("ncellpoints"); + if( file._state->found_basis ) + wrong_keywords.push_back("basis"); + if( file._state->found_bravaisa ) + wrong_keywords.push_back("bravaisa"); + if( file._state->found_bravaisb ) + wrong_keywords.push_back("bravaisb"); + if( file._state->found_bravaisc ) + wrong_keywords.push_back("bravaisc"); } if( missing_keywords.size() > 0 ) From 27ddbb2257d48e66f6040856a449d25fa711e1db Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 19:02:06 +0200 Subject: [PATCH 11/26] Use segment.n_cells member instead of creating new anodes, bnodes and cnodes members --- include/detail/atomistic_keywords.hpp | 6 +++--- include/detail/parse_rules.hpp | 4 ++-- include/ovf.h | 3 --- python/ovf/ovf.py | 3 --- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/include/detail/atomistic_keywords.hpp b/include/detail/atomistic_keywords.hpp index db67d07..d1674d5 100644 --- a/include/detail/atomistic_keywords.hpp +++ b/include/detail/atomistic_keywords.hpp @@ -219,7 +219,7 @@ namespace keywords template< typename Input > static void apply( const Input& in, ovf_file & f, ovf_segment & segment) { - segment.anodes = std::stoi(in.string()); + segment.n_cells[0] = std::stoi(in.string()); f._state->found_anodes = true; } }; @@ -237,7 +237,7 @@ namespace keywords template< typename Input > static void apply( const Input& in, ovf_file & f, ovf_segment & segment) { - segment.bnodes = std::stoi(in.string()); + segment.n_cells[1] = std::stoi(in.string()); f._state->found_bnodes = true; } }; @@ -255,7 +255,7 @@ namespace keywords template< typename Input > static void apply( const Input& in, ovf_file & f, ovf_segment & segment) { - segment.cnodes = std::stoi(in.string()); + segment.n_cells[2] = std::stoi(in.string()); f._state->found_cnodes = true; } }; diff --git a/include/detail/parse_rules.hpp b/include/detail/parse_rules.hpp index 143dffe..5d29645 100644 --- a/include/detail/parse_rules.hpp +++ b/include/detail/parse_rules.hpp @@ -451,7 +451,7 @@ namespace parse if( std::string(segment.meshtype) == "lattice" ) { - segment.N = segment.anodes * segment.bnodes * segment.cnodes * segment.ncellpoints; + segment.N = segment.n_cells[0] * segment.n_cells[1] * segment.n_cells[2] * segment.ncellpoints; if( !file._state->found_anodes ) missing_keywords.push_back("anodes"); if( !file._state->found_bnodes ) @@ -489,7 +489,7 @@ namespace parse if( missing_keywords.size() > 0 ) { - std::string message = fmt::format( "Missing keywords: \"{}\"", missing_keywords[0] ); + std::string message = fmt::format( "Missing keywords for meshtype \"{}\": \"{}\"", segment.meshtype, missing_keywords[0] ); for( int i=1; i < missing_keywords.size(); ++i ) message += fmt::format( ", \"{}\"", missing_keywords[i] ); throw tao::pegtl::parse_error( message, in ); diff --git a/include/ovf.h b/include/ovf.h index ceab3af..bde2ef5 100644 --- a/include/ovf.h +++ b/include/ovf.h @@ -60,9 +60,6 @@ struct ovf_segment { float bravaisb[3]; float bravaisc[3]; int ncellpoints; - int anodes; - int bnodes; - int cnodes; float * basis; /* then some "private" internal fields */ diff --git a/python/ovf/ovf.py b/python/ovf/ovf.py index d077119..acb7d9e 100644 --- a/python/ovf/ovf.py +++ b/python/ovf/ovf.py @@ -39,9 +39,6 @@ class ovf_segment(ctypes.Structure): ("bravaisb", ctypes.c_float*3), ("bravaisc", ctypes.c_float*3), ("ncellpoints", ctypes.c_int), - ("anodes", ctypes.c_int), - ("bnodes", ctypes.c_int), - ("cnodes", ctypes.c_int), ("basis", ctypes.POINTER(ctypes.c_float)) ] From 721a632cf34f5ee6c23f696b1544c0fabe118390 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 19:04:10 +0200 Subject: [PATCH 12/26] Minor changes in parser_state --- include/detail/pegtl_defines.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/detail/pegtl_defines.hpp b/include/detail/pegtl_defines.hpp index 3ef72d8..494e875 100644 --- a/include/detail/pegtl_defines.hpp +++ b/include/detail/pegtl_defines.hpp @@ -17,8 +17,6 @@ struct parser_state int current_column = 0; int current_line = 0; - std::string keyword="", value=""; - // Whether certain keywords were found in parsing bool found_title = false; bool found_meshunit = false; @@ -50,6 +48,8 @@ struct parser_state bool found_bnodes = false; bool found_cnodes = false; bool found_basis = false; + + // Needed to keep track of the current line when reading in the basis positions int _cur_basis_line = 0; /* From b2fc5e354c2873cbffb0e5979b420884a2728da8 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 19:58:31 +0200 Subject: [PATCH 13/26] Implemented compatibility format in write. --- include/detail/write.hpp | 40 +++++++++++++++++++++++----------------- include/ovf.h | 9 +++++++-- src/ovf.cpp | 2 +- test/simple.cpp | 3 ++- 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/include/detail/write.hpp b/include/detail/write.hpp index 5ce2ff8..74ce59e 100644 --- a/include/detail/write.hpp +++ b/include/detail/write.hpp @@ -72,15 +72,15 @@ namespace write } - inline std::string top_header_string(bool atomistic, bool compatibility) + inline std::string top_header_string(int ovf_extension_format) { std::string ret = "# OOMMF OVF 2.0\n"; - if(compatibility) + if(ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP) { ret += "##% AOVF 1.0\n"; } - if(atomistic) + if(ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF) { ret = "# AOVF 1.0\n"; } @@ -269,14 +269,14 @@ namespace write // Type of mesh and further keywords depending on it std::string meshtype = segment->meshtype; - bool atomistic_compatibility = (meshtype == "lattice" && !file->atomistic); // If meshtype is `lattice` and we run in compatibility mode - if( meshtype == "" || atomistic_compatibility) + + if( meshtype == "" || (meshtype == "lattice" && file->ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP) ) // In compatibility mode we cannot use meshtype 'lattice' meshtype = "rectangular"; output_to_file += fmt::format( "# meshtype: {}\n", meshtype ); int n_rows = 0; - if( meshtype == "rectangular" && !atomistic_compatibility) + if( meshtype == "rectangular" && std::string(segment->meshtype) != "lattice") { // Latice origin in space output_to_file += fmt::format( "# xbase: {}\n", segment->origin[0] ); @@ -295,32 +295,39 @@ namespace write n_rows = segment->n_cells[0]*segment->n_cells[1]*segment->n_cells[2]; } - else if( std::string(segment->meshtype) == "irregular" ) + else if( meshtype == "irregular" ) { output_to_file += fmt::format( "# pointcount: {}\n", segment->pointcount ); n_rows = segment->pointcount; - } - else if( std::string(segment->meshtype) == "lattice" || atomistic_compatibility) + } else if( std::string(segment->meshtype) == "lattice" ) { std::string prefix = "#"; - if(atomistic_compatibility) + if(file->ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP) { prefix = "##%"; + } if(file->ovf_extension_format == OVF_EXTENSION_FORMAT_OVF) + { + file->_state->message_latest = fmt::format( + "Not writing out any data to file \"{}\", because meshtype is invalid: \"{}\". " + "To enable the `lattice` meshtype, set ovf_extension_format to OVF_EXTENSION_FORMAT_AOVF_COMP or OVF_EXTENSION_FORMAT_OVf.", + file->file_name, segment->meshtype); + return OVF_ERROR; } + output_to_file += fmt::format( "{} anodes: {}\n", prefix, segment->n_cells[0] ); output_to_file += fmt::format( "{} bnodes: {}\n", prefix, segment->n_cells[1] ); output_to_file += fmt::format( "{} cnodes: {}\n", prefix, segment->n_cells[2] ); - output_to_file += fmt::format( "{} bravaisa: {} {} {}\n", prefix, segment->bravaisa[0], segment->bravaisa[1], segment->bravaisa[2] ); - output_to_file += fmt::format( "{} bravaisb: {} {} {}\n", prefix, segment->bravaisb[0], segment->bravaisb[1], segment->bravaisb[2] ); - output_to_file += fmt::format( "{} bravaisc: {} {} {}\n", prefix, segment->bravaisc[0], segment->bravaisc[1], segment->bravaisc[2] ); + output_to_file += fmt::format( "{} bravaisa: {:22.12f} {:22.12f} {:22.12f}\n", prefix, segment->bravaisa[0], segment->bravaisa[1], segment->bravaisa[2] ); + output_to_file += fmt::format( "{} bravaisb: {:22.12f} {:22.12f} {:22.12f}\n", prefix, segment->bravaisb[0], segment->bravaisb[1], segment->bravaisb[2] ); + output_to_file += fmt::format( "{} bravaisc: {:22.12f} {:22.12f} {:22.12f}\n", prefix, segment->bravaisc[0], segment->bravaisc[1], segment->bravaisc[2] ); output_to_file += fmt::format( "{} ncellpoints: {}\n", prefix, segment->ncellpoints ); output_to_file += fmt::format( "{} basis:\n", prefix); for(int i=0; incellpoints; i++) { - output_to_file += fmt::format( "{} {} {} {}\n", prefix, segment->basis[3*i], segment->basis[3*i+1], segment->basis[3*i+2] ); + output_to_file += fmt::format( "{} {:22.12f} {:22.12f} {:22.12f}\n", prefix, segment->basis[3*i], segment->basis[3*i+1], segment->basis[3*i+2] ); } - if(atomistic_compatibility) // In compatibility mode we have to add the required fields for the rectangular mesh + if(file->ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP) // In compatibility mode we have to add the required fields for the rectangular mesh { // Latice origin in space output_to_file += fmt::format( "# xbase: {}\n", segment->origin[0] ); @@ -337,7 +344,6 @@ namespace write output_to_file += fmt::format( "# ynodes: {}\n", segment->n_cells[1] ); output_to_file += fmt::format( "# znodes: {}\n", segment->n_cells[2] ); } - n_rows = segment->n_cells[0] * segment->n_cells[1] * segment->n_cells[2] * segment->ncellpoints; } else @@ -410,7 +416,7 @@ namespace write file_handle handle(file->file_name, false); file->n_segments = 0; file->version = 2; - handle.write( {top_header_string(file->atomistic, atomistic_compatibility), output_to_file} ); + handle.write( {top_header_string(file->ovf_extension_format), output_to_file} ); } file->found = true; file->is_ovf = true; diff --git a/include/ovf.h b/include/ovf.h index bde2ef5..c86b4fe 100644 --- a/include/ovf.h +++ b/include/ovf.h @@ -24,6 +24,11 @@ #define OVF_ERROR -2 #define OVF_INVALID -3 +/* OVF file formats */ +#define OVF_EXTENSION_FORMAT_OVF 0 // Standard OVF 2 format +#define OVF_EXTENSION_FORMAT_AOVF 1 // Atomistic extension, with new keywords +#define OVF_EXTENSION_FORMAT_AOVF_COMP 2 // Atomistic extension in compatibility format, (##% prefix for new keywords) + /* OVF data formats */ #define OVF_FORMAT_BIN 0 #define OVF_FORMAT_BIN4 1 @@ -82,8 +87,8 @@ struct ovf_file { /* number of segments the file should contain */ int n_segments; - /* use the atomistic extension */ - bool atomistic; + /* The extension format to be used (prefixes new keywords with ##%) */ + int ovf_extension_format; /* then some "private" internal fields */ struct parser_state * _state; diff --git a/src/ovf.cpp b/src/ovf.cpp index ebd823d..2d9cefa 100644 --- a/src/ovf.cpp +++ b/src/ovf.cpp @@ -15,7 +15,7 @@ try ovf_file_ptr->is_ovf = false; ovf_file_ptr->n_segments = 0; ovf_file_ptr->_state = new parser_state; - ovf_file_ptr->atomistic = false; + ovf_file_ptr->ovf_extension_format = OVF_EXTENSION_FORMAT_OVF; // Check if the file exists std::fstream filestream( filename ); diff --git a/test/simple.cpp b/test/simple.cpp index b01ee42..b93b0ae 100644 --- a/test/simple.cpp +++ b/test/simple.cpp @@ -286,7 +286,8 @@ TEST_CASE( "Atomistic Write", "[write]" ) // open auto file = ovf_open(testfile); - file->atomistic = true; // Set the flag for the atomistic extension + + file->ovf_extension_format = OVF_EXTENSION_FORMAT_AOVF; // Set the flag for the atomistic extension // write int success = ovf_write_segment_8(file, segment, field.data(), OVF_FORMAT_TEXT); From b6d3c21fea761f8ef24a29f7ae045d9857146610 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 22:18:46 +0200 Subject: [PATCH 14/26] Improved implementation of `basis_value` keyword --- include/detail/atomistic_keywords.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/detail/atomistic_keywords.hpp b/include/detail/atomistic_keywords.hpp index d1674d5..e0ab2a5 100644 --- a/include/detail/atomistic_keywords.hpp +++ b/include/detail/atomistic_keywords.hpp @@ -273,10 +273,10 @@ namespace keywords struct cur_basis_line_value_z : pegtl::pad { }; - struct basis_value_line : pegtl::seq< pegtl::string<'#'>, cur_basis_line_value_x, cur_basis_line_value_y, cur_basis_line_value_z, pegtl::eol > + struct basis_value_line : pegtl::seq< pegtl::string<'#'>, cur_basis_line_value_x, cur_basis_line_value_y, cur_basis_line_value_z> { }; - struct basis_value : pegtl::seq< pegtl::eol, pegtl::plus< basis_value_line > > + struct basis_value : pegtl::seq< pegtl::eol, pegtl::list > { }; template<> From e117b62141cce41b38b4cb053284f8bfc0eccac9 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 22:22:27 +0200 Subject: [PATCH 15/26] Adjusted keyword `basis` for aovf_comp format --- include/detail/atomistic_keywords.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/detail/atomistic_keywords.hpp b/include/detail/atomistic_keywords.hpp index e0ab2a5..6c706cf 100644 --- a/include/detail/atomistic_keywords.hpp +++ b/include/detail/atomistic_keywords.hpp @@ -273,7 +273,7 @@ namespace keywords struct cur_basis_line_value_z : pegtl::pad { }; - struct basis_value_line : pegtl::seq< pegtl::string<'#'>, cur_basis_line_value_x, cur_basis_line_value_y, cur_basis_line_value_z> + struct basis_value_line : pegtl::seq< pegtl::string<'#'>, pegtl::opt, cur_basis_line_value_x, cur_basis_line_value_y, cur_basis_line_value_z> { }; struct basis_value : pegtl::seq< pegtl::eol, pegtl::list > From 6c61daf2784c179a6ee558bfcfdbb6981d2bdc85 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 18 Aug 2021 22:49:06 +0200 Subject: [PATCH 16/26] Completed parsing/writing of AOVF_COMP format files --- include/detail/atomistic_keywords.hpp | 18 ++++++ include/detail/keywords.hpp | 2 +- include/detail/parse.hpp | 58 +++++++++++------ include/detail/parse_rules.hpp | 92 ++++++++++++++++++++++----- include/detail/pegtl_defines.hpp | 1 + include/detail/write.hpp | 40 ++++++------ 6 files changed, 158 insertions(+), 53 deletions(-) diff --git a/include/detail/atomistic_keywords.hpp b/include/detail/atomistic_keywords.hpp index 6c706cf..78a2053 100644 --- a/include/detail/atomistic_keywords.hpp +++ b/include/detail/atomistic_keywords.hpp @@ -9,6 +9,24 @@ namespace detail { namespace keywords { + + ////// meshtype + + // Only reimplement the new value + struct meshtype_value_lattice : TAO_PEGTL_ISTRING("lattice") // Only 'rectangular', 'irregular' or 'lattice' allowed + { }; + + template<> + struct kw_action< meshtype_value_lattice > + { + template< typename Input > + static void apply( const Input& in, ovf_file & f, ovf_segment & segment) + { + segment.meshtype = strdup(in.string().c_str()); + f._state->found_meshtype_atomistic = true; + } + }; + ////// bravaisa // x struct bravaisa_value_x : pegtl::pad diff --git a/include/detail/keywords.hpp b/include/detail/keywords.hpp index 6c0a379..7d53d39 100644 --- a/include/detail/keywords.hpp +++ b/include/detail/keywords.hpp @@ -115,7 +115,7 @@ namespace keywords struct meshtype : TAO_PEGTL_ISTRING("meshtype") { }; - struct meshtype_value : pegtl::sor< TAO_PEGTL_ISTRING("rectangular"), TAO_PEGTL_ISTRING("irregular"), TAO_PEGTL_ISTRING("lattice")> // Only 'rectangular', 'irregular' or 'lattice' allowed + struct meshtype_value : pegtl::sor< TAO_PEGTL_ISTRING("rectangular"), TAO_PEGTL_ISTRING("irregular")> // Only 'rectangular' and 'irregular' allowed { }; template<> diff --git a/include/detail/parse.hpp b/include/detail/parse.hpp index e8fe913..6fc4720 100644 --- a/include/detail/parse.hpp +++ b/include/detail/parse.hpp @@ -70,7 +70,7 @@ namespace parse if( success ) { success = false; - if( file.version == 2 || (file.version == 1 && std::string(file.version_string) == "AOVF") ) + if( file.version == 2 || (file.version == 1 && (file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF || file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP ))) { success = pegtl::parse< pegtl::until>>> >( in, file ); success = pegtl::parse< pegtl::plus, v2::ovf_segment_action >( in, file ); @@ -175,17 +175,24 @@ namespace parse bool success = false; - if( file.version == 2 || (file.version == 1 && std::string(file.version_string) == "AOVF") ) + if( file.version == 2 ) { - success = pegtl::parse< pegtl::plus, v2::ovf_segment_header_action, v2::ovf_segment_header_control >( in, file, segment ); + success = pegtl::parse< pegtl::plus>, v2::ovf_segment_header_action, v2::ovf_segment_header_control >( in, file, segment ); } else if( file.version == 1 ) { - // TODO... - file._state->message_latest = fmt::format( - "libovf segment_header: OVF version \'{}\' in file \'{}\' is not supported...", - file.file_name, file.version); - return OVF_INVALID; + if(file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF) + success = pegtl::parse< pegtl::plus>, v2::ovf_segment_header_action, v2::ovf_segment_header_control >( in, file, segment ); + else if (file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP) + success = pegtl::parse< pegtl::plus>, v2::ovf_segment_header_action, v2::ovf_segment_header_control >( in, file, segment ); + else + { + // TODO... + file._state->message_latest = fmt::format( + "libovf segment_header: OVF version \'{}\' in file \'{}\' is not supported...", + file.file_name, file.version); + return OVF_INVALID; + } } else { @@ -241,23 +248,38 @@ namespace parse int retcode = OVF_ERROR; bool success = false; - if( file.version == 2 || (file.version == 1 && std::string(file.version_string) == "AOVF")) + if( file.version == 2 ) { file._state->max_data_index = segment.N*segment.valuedim; - success = pegtl::parse< v2::segment_data, v2::ovf_segment_data_action >( in, file, segment, data ); + success = pegtl::parse< v2::segment_data, v2::ovf_segment_data_action >( in, file, segment, data ); file._state->current_line = 0; file._state->current_column = 0; } else if( file.version == 1 ) { - // TODO... - file._state->message_latest = fmt::format( - "libovf segment_data: OVF version \'{}\' in file \'{}\' is not supported...", - file.file_name, file.version); - return OVF_INVALID; - } - else - { + if(file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF) + { + file._state->max_data_index = segment.N*segment.valuedim; + success = pegtl::parse< v2::segment_data, v2::ovf_segment_data_action >( in, file, segment, data ); + file._state->current_line = 0; + file._state->current_column = 0; + } + else if (file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP) + { + file._state->max_data_index = segment.N*segment.valuedim; + success = pegtl::parse< v2::segment_data, v2::ovf_segment_data_action >( in, file, segment, data ); + file._state->current_line = 0; + file._state->current_column = 0; + } + else + { + // TODO... + file._state->message_latest = fmt::format( + "libovf segment_data: OVF version \'{}\' in file \'{}\' is not supported...", + file.file_name, file.version); + return OVF_INVALID; + } + } else { file._state->message_latest = fmt::format( "libovf segment_data: OVF version \'{}\' in file \'{}\' is not supported...", file.file_name, file.version); diff --git a/include/detail/parse_rules.hpp b/include/detail/parse_rules.hpp index 5d29645..3c33568 100644 --- a/include/detail/parse_rules.hpp +++ b/include/detail/parse_rules.hpp @@ -27,7 +27,7 @@ namespace parse : pegtl::string< '#' > {}; - // "#" + // "%" struct magic_char : pegtl::string< '%' > {}; @@ -48,7 +48,7 @@ namespace parse {}; struct version_string - : pegtl::sor< TAO_PEGTL_ISTRING("OOMMF OVF"), TAO_PEGTL_ISTRING("AOVF") > + : pegtl::sor< TAO_PEGTL_ISTRING("OOMMF OVF"), TAO_PEGTL_ISTRING("AOVF_COMP"), TAO_PEGTL_ISTRING("AOVF") > {}; // " OOMMF OVF " @@ -104,6 +104,18 @@ namespace parse static void apply( const Input& in, ovf_file & file ) { file.version_string = strdup(in.string().c_str()); + if(in.string() == "AOVF_COMP") + { + file.ovf_extension_format = OVF_EXTENSION_FORMAT_AOVF_COMP; + } else if(in.string() == "AOVF") + { + file.ovf_extension_format = OVF_EXTENSION_FORMAT_AOVF; + } else if(in.string() == "OOMMF OVF") + { + file.ovf_extension_format = OVF_EXTENSION_FORMAT_OVF; + } else { + throw pegtl::parse_error(fmt::format("Detected invalid version string {}", in.string()), in); + } } }; @@ -133,7 +145,7 @@ namespace parse pegtl::string<'#'>, pegtl::until< pegtl::at< - pegtl::sor> + pegtl::sor, pegtl::not_at>> >, pegtl::blank > @@ -144,6 +156,7 @@ namespace parse struct comment : pegtl::seq< pegtl::string< '#', '#' >, + pegtl::not_at, pegtl::until< pegtl::at, pegtl::any @@ -246,7 +259,7 @@ namespace parse // This is how a line ends: either eol or the begin of a comment struct line_end - : pegtl::sor> + : pegtl::sor,pegtl::not_at>> {}; // This checks that the line end is met and moves up until eol @@ -267,7 +280,18 @@ namespace parse finish_line > {}; - struct keyword_value_line + template + struct magic_keyword_value_pair + : pegtl::seq< + magic_prefix, + pegtl::pad< kw, pegtl::blank >, + TAO_PEGTL_ISTRING(":"), + pegtl::pad< val, pegtl::blank >, + pegtl::until>, + finish_line > + {}; + + struct ovf_keyword_value_line : pegtl::sor< keyword_value_pair< keywords::title, keywords::title_value >, keyword_value_pair< keywords::desc, keywords::desc_value >, @@ -291,8 +315,15 @@ namespace parse keyword_value_pair< keywords::zmax, keywords::zmax_value >, keyword_value_pair< keywords::xbase, keywords::xbase_value >, keyword_value_pair< keywords::ybase, keywords::ybase_value >, - keyword_value_pair< keywords::zbase, keywords::zbase_value >, + keyword_value_pair< keywords::zbase, keywords::zbase_value > + > + {}; + + struct aovf_keyword_value_line + : pegtl::sor< + ovf_keyword_value_line, // Atomistic extension + keyword_value_pair< keywords::meshtype, keywords::meshtype_value_lattice >, keyword_value_pair< keywords::anodes, keywords::anodes_value >, keyword_value_pair< keywords::bnodes, keywords::bnodes_value >, keyword_value_pair< keywords::cnodes, keywords::cnodes_value >, @@ -304,7 +335,23 @@ namespace parse > {}; - // + struct caovf_keyword_value_line + : pegtl::sor< + ovf_keyword_value_line, + // Atomistic extension + magic_keyword_value_pair< keywords::meshtype, keywords::meshtype_value_lattice >, + magic_keyword_value_pair< keywords::anodes, keywords::anodes_value >, + magic_keyword_value_pair< keywords::bnodes, keywords::bnodes_value >, + magic_keyword_value_pair< keywords::cnodes, keywords::cnodes_value >, + magic_keyword_value_pair< keywords::bravaisa, keywords::bravaisa_value >, + magic_keyword_value_pair< keywords::bravaisb, keywords::bravaisb_value >, + magic_keyword_value_pair< keywords::bravaisc, keywords::bravaisc_value >, + magic_keyword_value_pair< keywords::ncellpoints, keywords::ncellpoints_value >, + magic_keyword_value_pair< keywords::basis, keywords::basis_value > + > + {}; + + template struct header : pegtl::seq< begin, TAO_PEGTL_ISTRING("Header"), finish_line, @@ -312,7 +359,7 @@ namespace parse pegtl::seq, pegtl::must< skippable_lines, - keyword_value_line, + keyword_value_line_t, skippable_lines > >, @@ -347,12 +394,13 @@ namespace parse ////////////////////////////////////////////// // + template struct segment_header : pegtl::seq< pegtl::star>, pegtl::seq< begin, TAO_PEGTL_ISTRING("Segment"), pegtl::eol>, pegtl::star>, - header, + header, pegtl::star>, pegtl::until>, pegtl::eol > {}; @@ -362,8 +410,8 @@ namespace parse struct ovf_segment_header_action : keywords::kw_action {}; - template<> - struct ovf_segment_header_action< segment_header > + template + struct ovf_segment_header_action< segment_header > { template< typename Input > static void apply( const Input& in, ovf_file & file, ovf_segment & segment ) @@ -396,10 +444,9 @@ namespace parse if( !file._state->found_meshtype ) missing_keywords.push_back("meshtype"); - if( std::string(segment.meshtype) == "rectangular" ) + if( std::string(segment.meshtype) == "rectangular" || (file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP && file._state->found_meshtype_atomistic) ) { segment.N = segment.n_cells[0] * segment.n_cells[1] * segment.n_cells[2]; - if( !file._state->found_xbase ) missing_keywords.push_back("xbase"); if( !file._state->found_ybase ) @@ -449,7 +496,7 @@ namespace parse wrong_keywords.push_back("pointcount"); } - if( std::string(segment.meshtype) == "lattice" ) + if( std::string(segment.meshtype) == "lattice" || file._state->found_meshtype_atomistic ) { segment.N = segment.n_cells[0] * segment.n_cells[1] * segment.n_cells[2] * segment.ncellpoints; if( !file._state->found_anodes ) @@ -552,12 +599,13 @@ namespace parse > {}; + template struct segment_data : pegtl::seq< pegtl::star>, begin, TAO_PEGTL_ISTRING("Segment"), pegtl::eol, pegtl::star>, - header, + header, pegtl::star>, pegtl::sor< data_text, data_csv, data_binary_4, data_binary_8 >, pegtl::star>, @@ -763,7 +811,19 @@ namespace parse }; template<> template< typename Input, typename... States > - void ovf_segment_header_control< keyword_value_line >::raise( const Input& in, States&&... ) + void ovf_segment_header_control< ovf_keyword_value_line >::raise( const Input& in, States&&... ) + { + throw keyword_value_line_error( in ); + } + + template<> template< typename Input, typename... States > + void ovf_segment_header_control< aovf_keyword_value_line >::raise( const Input& in, States&&... ) + { + throw keyword_value_line_error( in ); + } + + template<> template< typename Input, typename... States > + void ovf_segment_header_control< caovf_keyword_value_line >::raise( const Input& in, States&&... ) { throw keyword_value_line_error( in ); } diff --git a/include/detail/pegtl_defines.hpp b/include/detail/pegtl_defines.hpp index 494e875..ffc6d76 100644 --- a/include/detail/pegtl_defines.hpp +++ b/include/detail/pegtl_defines.hpp @@ -50,6 +50,7 @@ struct parser_state bool found_basis = false; // Needed to keep track of the current line when reading in the basis positions + bool found_meshtype_atomistic = false; int _cur_basis_line = 0; /* diff --git a/include/detail/write.hpp b/include/detail/write.hpp index 74ce59e..1afaa1d 100644 --- a/include/detail/write.hpp +++ b/include/detail/write.hpp @@ -78,7 +78,7 @@ namespace write if(ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP) { - ret += "##% AOVF 1.0\n"; + ret += "##% AOVF_COMP 1.0\n"; } if(ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF) { @@ -305,6 +305,27 @@ namespace write if(file->ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP) { prefix = "##%"; + + // In compatibility mode we have to add the required fields for the rectangular mesh + // Latice origin in space + output_to_file += fmt::format( "# xbase: {}\n", segment->origin[0] ); + output_to_file += fmt::format( "# ybase: {}\n", segment->origin[1] ); + output_to_file += fmt::format( "# zbase: {}\n", segment->origin[2] ); + + // Mesh spacing + output_to_file += fmt::format( "# xstepsize: {}\n", segment->step_size[0] ); + output_to_file += fmt::format( "# ystepsize: {}\n", segment->step_size[1] ); + output_to_file += fmt::format( "# zstepsize: {}\n", segment->step_size[2] ); + + // Number of nodes along each direction + output_to_file += fmt::format( "# xnodes: {}\n", segment->n_cells[0] * segment->ncellpoints ); // We fold the basis atoms into xnodes + output_to_file += fmt::format( "# ynodes: {}\n", segment->n_cells[1] ); + output_to_file += fmt::format( "# znodes: {}\n", segment->n_cells[2] ); + + // We also add the lattice meshtype as a magic comment + output_to_file += fmt::format( "#\n" ); + output_to_file += fmt::format( "##% meshtype: {}\n", "lattice" ); + } if(file->ovf_extension_format == OVF_EXTENSION_FORMAT_OVF) { file->_state->message_latest = fmt::format( @@ -327,23 +348,6 @@ namespace write output_to_file += fmt::format( "{} {:22.12f} {:22.12f} {:22.12f}\n", prefix, segment->basis[3*i], segment->basis[3*i+1], segment->basis[3*i+2] ); } - if(file->ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP) // In compatibility mode we have to add the required fields for the rectangular mesh - { - // Latice origin in space - output_to_file += fmt::format( "# xbase: {}\n", segment->origin[0] ); - output_to_file += fmt::format( "# ybase: {}\n", segment->origin[1] ); - output_to_file += fmt::format( "# zbase: {}\n", segment->origin[2] ); - - // Mesh spacing - output_to_file += fmt::format( "# xstepsize: {}\n", segment->step_size[0] ); - output_to_file += fmt::format( "# ystepsize: {}\n", segment->step_size[1] ); - output_to_file += fmt::format( "# zstepsize: {}\n", segment->step_size[2] ); - - // Number of nodes along each direction - output_to_file += fmt::format( "# xnodes: {}\n", segment->n_cells[0] * segment->ncellpoints ); // We fold the basis atoms into xnodes - output_to_file += fmt::format( "# ynodes: {}\n", segment->n_cells[1] ); - output_to_file += fmt::format( "# znodes: {}\n", segment->n_cells[2] ); - } n_rows = segment->n_cells[0] * segment->n_cells[1] * segment->n_cells[2] * segment->ncellpoints; } else From 7f94b2a160b51387c2139dbc0340e0c03017c077 Mon Sep 17 00:00:00 2001 From: Moritz Date: Thu, 19 Aug 2021 14:02:51 +0200 Subject: [PATCH 17/26] Testing: Moved atomistic tests to own file and extended them --- CMakeLists.txt | 1 + test/atomistic.cpp | 269 +++++++++++++++++++++++++++++++++++++++++++++ test/simple.cpp | 137 ----------------------- 3 files changed, 270 insertions(+), 137 deletions(-) create mode 100644 test/atomistic.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b68cb1d..671c5dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,6 +187,7 @@ if ( OVF_BUILD_TEST ) ### Tests add_cxx_test( test_cpp_simple simple.cpp ) add_cxx_test( test_cpp_binary binary.cpp ) + add_cxx_test( test_cpp_atomistic atomistic.cpp ) endif() diff --git a/test/atomistic.cpp b/test/atomistic.cpp new file mode 100644 index 0000000..40d5c85 --- /dev/null +++ b/test/atomistic.cpp @@ -0,0 +1,269 @@ +#include + +#include +#include + + +#include +#include + +void ovf_test_write(std::string filename, std::string meshtype, int ovf_extension_format) +{ + INFO( fmt::format("Testing 'ovf_test_write' with filename '{}', meshtype '{}', ovf_extension_format '{}'", filename, meshtype, ovf_extension_format) ); + + auto create_test_segment = [&]() + { + // segment header + auto segment = ovf_segment_create(); + segment->title = const_cast("ovf test title - write"); + segment->comment = const_cast("test write"); + segment->valuedim = 3; + + segment->n_cells[0] = 2; + segment->n_cells[1] = 1; + segment->n_cells[2] = 1; + + if(meshtype == "rectangular") + segment->n_cells[1] = 2; + + // Fill in atomistic values + segment->bravaisa[0] = 1; + segment->bravaisa[1] = 0; + segment->bravaisa[2] = 0; + + segment->bravaisb[0] = 0; + segment->bravaisb[1] = 1; + segment->bravaisb[2] = 0; + + segment->bravaisc[0] = 0; + segment->bravaisc[1] = 0; + segment->bravaisc[2] = 1; + + segment->pointcount = 4; + + segment->ncellpoints = 2; + float basis[6] = { + 0,0.1,0.2, + 2,3,4 + }; + + segment->basis = (float *) malloc( segment->ncellpoints * 3 * sizeof(float) ); + for( int ib=0; ib < segment->ncellpoints; ib++) + { + for(int i=0; i<3; i++) + { + segment->basis[ib*3 + i] = basis[ib*3 + i]; + } + } + + segment->N = 4; + segment->meshtype = strdup(meshtype.c_str()); + return segment; + }; + + auto create_dummy_segment = [&]() + { + // Append second + auto segment = ovf_segment_create(); + segment->title = const_cast("ovf test title - append"); + segment->comment = const_cast("test append"); + segment->valuedim = 3; + segment->n_cells[0] = 2; + segment->n_cells[1] = 2; + segment->n_cells[2] = 1; + segment->N = 4; + return segment; + }; + + // Create and write test_segment + auto segment = create_test_segment(); + // data + std::vector field(3*segment->N, 1); + field[0] = 3; + field[3] = 2; + field[6] = 1; + field[9] = 0; + + // open + auto file = ovf_open(filename.c_str()); + file->ovf_extension_format = ovf_extension_format; // Set the flag for the atomistic extension + + // write + int success = ovf_write_segment_8(file, segment, field.data(), OVF_FORMAT_TEXT); + if( OVF_OK != success ) + std::cerr << ovf_latest_message(file) << std::endl; + + if( ovf_extension_format == OVF_EXTENSION_FORMAT_OVF && meshtype=="lattice" ) // do not allow lattice for non AOVF extension + { + REQUIRE( success == OVF_ERROR ); + } else { + REQUIRE( success == OVF_OK ); + } + // close + ovf_close(file); + + + // Create and append dummy_segment + // data + segment = create_dummy_segment(); + std::vector field_dummy(3*segment->N, 1); + field_dummy[0] = 6; + field_dummy[3] = 4; + field_dummy[6] = 2; + field_dummy[9] = 0; + + // open + file = ovf_open(filename.c_str()); + // write + success = ovf_append_segment_8(file, segment, field.data(), OVF_FORMAT_CSV); + if( OVF_OK != success ) + std::cerr << ovf_latest_message(file) << std::endl; + REQUIRE( success == OVF_OK ); + // close + ovf_close(file); + + + // Create and append test_segment + // data + segment = create_test_segment(); + // open + file = ovf_open(filename.c_str()); + // write + success = ovf_append_segment_8(file, segment, field.data(), OVF_FORMAT_CSV); + if( OVF_OK != success ) + std::cerr << ovf_latest_message(file) << std::endl; + + if( ovf_extension_format == OVF_EXTENSION_FORMAT_OVF && meshtype=="lattice" ) // do not allow lattice for non AOVF extension + { + REQUIRE( success == OVF_ERROR ); + } else { + REQUIRE( success == OVF_OK ); + } + + // close + ovf_close(file); + +} + + +void ovf_test_read(std::string filename, std::string meshtype, int ovf_extension_format) +{ + INFO( fmt::format("Testing 'ovf_test_read' with filename '{}', meshtype '{}', ovf_extension_format '{}'", filename, meshtype, ovf_extension_format) ); + + auto verify_test_segment = [&](int index) + { + // open + auto file = ovf_open(filename.c_str()); + std::cerr << ovf_latest_message(file) << std::endl; + REQUIRE( file->found == true ); + REQUIRE( file->is_ovf == true ); + REQUIRE( file->n_segments == 3); + REQUIRE( file->ovf_extension_format == ovf_extension_format ); + + // segment header + auto segment = ovf_segment_create(); + + // read header + int success = ovf_read_segment_header(file, index, segment); + if( OVF_OK != success ) + std::cerr << ovf_latest_message(file) << std::endl; + REQUIRE( success == OVF_OK ); + + REQUIRE( segment->N == 4 ); + REQUIRE( std::string(segment->meshtype) == meshtype ); + + if(std::string(segment->meshtype) == "lattice") + { + REQUIRE( segment->ncellpoints == 2); + REQUIRE( segment->basis[0] == 0); + + REQUIRE( segment->basis[1] == 0.1f); + REQUIRE( segment->basis[2] == 0.2f); + REQUIRE( segment->basis[3] == 2); + REQUIRE( segment->basis[4] == 3); + REQUIRE( segment->basis[5] == 4); + + REQUIRE( segment->bravaisa[0] == 1); + REQUIRE( segment->bravaisa[1] == 0); + REQUIRE( segment->bravaisa[2] == 0); + + REQUIRE( segment->bravaisb[0] == 0); + REQUIRE( segment->bravaisb[1] == 1); + REQUIRE( segment->bravaisb[2] == 0); + + REQUIRE( segment->bravaisc[0] == 0); + REQUIRE( segment->bravaisc[1] == 0); + REQUIRE( segment->bravaisc[2] == 1); + } + // data + std::vector field(3*segment->N); + + // read data + success = ovf_read_segment_data_4(file, index, segment, field.data()); + if( OVF_OK != success ) + std::cerr << ovf_latest_message(file) << std::endl; + REQUIRE( success == OVF_OK ); + + REQUIRE( field[0] == 3 ); + REQUIRE( field[1] == 1 ); + REQUIRE( field[3] == 2 ); + REQUIRE( field[6] == 1 ); + REQUIRE( field[9] == 0 ); + + // close + ovf_close(file); + }; + + verify_test_segment(0); + verify_test_segment(2); +} + +TEST_CASE( "Atomistic Write", "[write]" ) +{ + const char * testfile = "testfile_cpp.aovf"; + + SECTION( "write OVF" ) + { + ovf_test_write( "test_file_ovf_rectangular_cpp.ovf", "rectangular", OVF_EXTENSION_FORMAT_OVF ); + ovf_test_write( "test_file_ovf_irregular_cpp.ovf", "irregular", OVF_EXTENSION_FORMAT_OVF ); + ovf_test_write( "test_file_ovf_lattice_cpp.ovf", "lattice", OVF_EXTENSION_FORMAT_OVF ); // Should print some error message + } + + SECTION( "write AOVF" ) + { + ovf_test_write( "test_file_atomistic_rectangular_cpp.aovf", "rectangular", OVF_EXTENSION_FORMAT_AOVF ); + ovf_test_write( "test_file_atomistic_lattice_cpp.aovf", "lattice", OVF_EXTENSION_FORMAT_AOVF ); + ovf_test_write( "test_file_atomistic_irregular_cpp.aovf", "irregular", OVF_EXTENSION_FORMAT_AOVF ); + } + + SECTION( "write AOVF_COMP" ) + { + ovf_test_write( "test_file_atomistic_comp_rectangular_cpp.aovf", "rectangular", OVF_EXTENSION_FORMAT_AOVF_COMP ); + ovf_test_write( "test_file_atomistic_comp_lattice_cpp.aovf", "lattice", OVF_EXTENSION_FORMAT_AOVF_COMP ); + ovf_test_write( "test_file_atomistic_comp_irregular_cpp.aovf", "irregular", OVF_EXTENSION_FORMAT_AOVF_COMP ); + } +} + +TEST_CASE( "Atomistic Read", "[read]" ) +{ + SECTION( "read OVF" ) + { + ovf_test_write( "test_file_ovf_rectangular_cpp.ovf", "rectangular", OVF_EXTENSION_FORMAT_OVF ); + ovf_test_write( "test_file_ovf_irregular_cpp.ovf", "irregular", OVF_EXTENSION_FORMAT_OVF ); + // ovf_test_write( "test_file_ovf_lattice_cpp.ovf", "lattice", OVF_EXTENSION_FORMAT_OVF ); // should not be written at all + } + + SECTION( "read AOVF" ) + { + ovf_test_read( "test_file_atomistic_rectangular_cpp.aovf", "rectangular", OVF_EXTENSION_FORMAT_AOVF ); + ovf_test_read( "test_file_atomistic_lattice_cpp.aovf", "lattice", OVF_EXTENSION_FORMAT_AOVF ); + ovf_test_read( "test_file_atomistic_irregular_cpp.aovf", "irregular", OVF_EXTENSION_FORMAT_AOVF ); + } + + SECTION( "read AOVF_COMP" ) + { + ovf_test_read( "test_file_atomistic_comp_rectangular_cpp.aovf", "rectangular", OVF_EXTENSION_FORMAT_AOVF_COMP ); + ovf_test_read( "test_file_atomistic_comp_lattice_cpp.aovf", "lattice", OVF_EXTENSION_FORMAT_AOVF_COMP ); + ovf_test_read( "test_file_atomistic_comp_irregular_cpp.aovf", "irregular", OVF_EXTENSION_FORMAT_AOVF_COMP ); + } +} \ No newline at end of file diff --git a/test/simple.cpp b/test/simple.cpp index b93b0ae..54cec8e 100644 --- a/test/simple.cpp +++ b/test/simple.cpp @@ -226,143 +226,6 @@ TEST_CASE( "Read", "[read]" ) REQUIRE( field[6] == 2 ); REQUIRE( field[9] == 0 ); - // close - ovf_close(file); - } -} - -TEST_CASE( "Atomistic Write", "[write]" ) -{ - const char * testfile = "testfile_cpp.aovf"; - - SECTION( "write" ) - { - // segment header - auto segment = ovf_segment_create(); - segment->title = const_cast("ovf test title - write"); - segment->comment = const_cast("test write"); - segment->valuedim = 3; - segment->n_cells[0] = 2; - segment->n_cells[1] = 1; - segment->n_cells[2] = 1; - - // Fill in atomistic values - segment->bravaisa[0] = 1; - segment->bravaisa[1] = 0; - segment->bravaisa[2] = 0; - - segment->bravaisb[0] = 0; - segment->bravaisb[1] = 1; - segment->bravaisb[2] = 0; - - segment->bravaisc[0] = 0; - segment->bravaisc[1] = 0; - segment->bravaisc[2] = 1; - - segment->ncellpoints = 2; - float basis[6] = { - 0,0.1,0.2, - 2,3,4 - }; - - segment->basis = (float *) malloc( segment->ncellpoints * 3 * sizeof(float) ); - for( int ib=0; ib < segment->ncellpoints; ib++) - { - for(int i=0; i<3; i++) - { - segment->basis[ib*3 + i] = basis[ib*3 + i]; - } - } - - segment->N = 4; - segment->meshtype = const_cast("lattice"); - - // data - std::vector field(3*segment->N, 1); - field[0] = 3; - field[3] = 2; - field[6] = 1; - field[9] = 0; - - // open - auto file = ovf_open(testfile); - - file->ovf_extension_format = OVF_EXTENSION_FORMAT_AOVF; // Set the flag for the atomistic extension - - // write - int success = ovf_write_segment_8(file, segment, field.data(), OVF_FORMAT_TEXT); - // if( OVF_OK != success ) - // std::cerr << ovf_latest_message(file) << std::endl; - REQUIRE( success == OVF_OK ); - - // close - ovf_close(file); - } -} - -TEST_CASE( "Atomistic Read", "[read]" ) -{ - const char * testfile = "testfile_cpp.aovf"; - - SECTION( "first segment" ) - { - // open - auto file = ovf_open(testfile); - std::cerr << ovf_latest_message(file) << std::endl; - REQUIRE( file->found == true ); - REQUIRE( file->is_ovf == true ); - REQUIRE( file->n_segments == 1 ); - int index = 0; - - // segment header - auto segment = ovf_segment_create(); - - // read header - int success = ovf_read_segment_header(file, index, segment); - if( OVF_OK != success ) - std::cerr << ovf_latest_message(file) << std::endl; - REQUIRE( success == OVF_OK ); - REQUIRE( segment->N == 4 ); - - REQUIRE( segment->ncellpoints == 2); - - REQUIRE( segment->basis[0] == 0); - REQUIRE( segment->basis[1] == 0.1f); - REQUIRE( segment->basis[2] == 0.2f); - REQUIRE( segment->basis[3] == 2); - REQUIRE( segment->basis[4] == 3); - REQUIRE( segment->basis[5] == 4); - - REQUIRE( segment->bravaisa[0] == 1); - REQUIRE( segment->bravaisa[1] == 0); - REQUIRE( segment->bravaisa[2] == 0); - - REQUIRE( segment->bravaisb[0] == 0); - REQUIRE( segment->bravaisb[1] == 1); - REQUIRE( segment->bravaisb[2] == 0); - - REQUIRE( segment->bravaisc[0] == 0); - REQUIRE( segment->bravaisc[1] == 0); - REQUIRE( segment->bravaisc[2] == 1); - - - REQUIRE( std::string(segment->meshtype) == "lattice" ); - - // data - std::vector field(3*segment->N); - - // read data - success = ovf_read_segment_data_4(file, index, segment, field.data()); - if( OVF_OK != success ) - std::cerr << ovf_latest_message(file) << std::endl; - REQUIRE( success == OVF_OK ); - REQUIRE( field[0] == 3 ); - REQUIRE( field[1] == 1 ); - REQUIRE( field[3] == 2 ); - REQUIRE( field[6] == 1 ); - REQUIRE( field[9] == 0 ); - - // close ovf_close(file); } From 97adfad6f4d7a5147a62acf2b749957cf0a6af10 Mon Sep 17 00:00:00 2001 From: Moritz Date: Thu, 19 Aug 2021 14:19:58 +0200 Subject: [PATCH 18/26] Small fix for atomistic keywords meshtype value --- include/detail/atomistic_keywords.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/detail/atomistic_keywords.hpp b/include/detail/atomistic_keywords.hpp index 78a2053..6e3522e 100644 --- a/include/detail/atomistic_keywords.hpp +++ b/include/detail/atomistic_keywords.hpp @@ -24,6 +24,7 @@ namespace keywords { segment.meshtype = strdup(in.string().c_str()); f._state->found_meshtype_atomistic = true; + f._state->found_meshtype = true; } }; @@ -345,6 +346,7 @@ namespace keywords template< typename Input > static void apply( const Input& in, ovf_file & f, ovf_segment & segment) { + // fmt::print("basis line value: {}\n", in.string()); f._state->_cur_basis_line++; } }; @@ -355,6 +357,8 @@ namespace keywords template< typename Input > static void apply( const Input& in, ovf_file & f, ovf_segment & segment) { + // fmt::print("basis value: {}\n", in.string()); + f._state->found_basis = true; if( segment.ncellpoints != f._state->_cur_basis_line ) // Need to make sure that the basis array is already allocated { From 29f3b2c09a60cc2cf2d901181779fc658e1cbe54 Mon Sep 17 00:00:00 2001 From: Moritz Date: Thu, 19 Aug 2021 14:36:40 +0200 Subject: [PATCH 19/26] Added extension_format defines in ovf.py --- python/ovf/ovf.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/ovf/ovf.py b/python/ovf/ovf.py index acb7d9e..f6f2d57 100644 --- a/python/ovf/ovf.py +++ b/python/ovf/ovf.py @@ -17,6 +17,10 @@ FILEFORMAT_TEXT = 3 FILEFORMAT_CSV = 4 +EXTENSION_FORMAT_OVF = 0 +EXTENSION_FORMAT_AOVF = 1 +EXTENSION_FORMAT_AOVF_COMP = 2 + class ovf_segment(ctypes.Structure): ### Some properties _fields_ = [ @@ -118,7 +122,7 @@ class _ovf_file(ctypes.Structure): ("found", ctypes.c_bool), ("is_ovf", ctypes.c_bool), ("n_segments", ctypes.c_int), - ("atomistic", ctypes.c_bool), + ("ovf_extension_format", ctypes.c_int), ("_state", ctypes.c_void_p) ] From 3d96f05add1bdf6aa92b9507f06213948e5100ef Mon Sep 17 00:00:00 2001 From: Moritz Date: Thu, 19 Aug 2021 15:40:14 +0200 Subject: [PATCH 20/26] Added simple test for atomistic case to python API --- python/ovf/ovf.py | 44 +++++++++++++++++--- python/test/simple.py | 93 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 5 deletions(-) diff --git a/python/ovf/ovf.py b/python/ovf/ovf.py index f6f2d57..276b1dd 100644 --- a/python/ovf/ovf.py +++ b/python/ovf/ovf.py @@ -39,16 +39,37 @@ class ovf_segment(ctypes.Structure): ("bounds_max", ctypes.c_float*3), ("lattice_constant", ctypes.c_float), ("origin", ctypes.c_float*3), - ("bravaisa", ctypes.c_float*3), - ("bravaisb", ctypes.c_float*3), - ("bravaisc", ctypes.c_float*3), + ("_bravaisa", ctypes.c_float*3), + ("_bravaisb", ctypes.c_float*3), + ("_bravaisc", ctypes.c_float*3), ("ncellpoints", ctypes.c_int), - ("basis", ctypes.POINTER(ctypes.c_float)) + ("_basis", ctypes.POINTER(ctypes.c_float)) ] + @property + def bravaisa(self): + print("Getting value...") + return [i for i in self._bravaisa] + + @property + def bravaisb(self): + print("Getting value...") + return [i for i in self._bravaisb] + + @property + def bravaisc(self): + print("Getting value...") + return [i for i in self._bravaisc] + + @property + def basis(self): + print("Getting value...") + return [ [self._basis[3*i], self._basis[3*i+1], self._basis[3*i+2]] for i in range(self.ncellpoints)] + def __init__(self, title="", comment="", valuedim=1, valueunits="", valuelabels="", meshtype="", meshunits="", step_size=[0.0, 0.0, 0.0], bounds_min=[0.0, 0.0, 0.0], bounds_max=[0.0, 0.0, 0.0], lattice_constant=0.0, - origin=[0.0, 0.0, 0.0], pointcount=0, n_cells=[1,1,1]): + origin=[0.0, 0.0, 0.0], pointcount=0, n_cells=[1,1,1], + bravaisa = [0.0, 0.0, 0.0], bravaisb = [0.0, 0.0, 0.0], bravaisc = [0.0, 0.0, 0.0], basis = [[0,0,0]]): self.title = title.encode('utf-8') self.comment = comment.encode('utf-8') @@ -58,8 +79,21 @@ def __init__(self, title="", comment="", valuedim=1, valueunits="", valuelabels= self.meshtype = meshtype.encode('utf-8') self.meshunits = meshunits.encode('utf-8') self.pointcount = pointcount + + self.ncellpoints = len(basis) + self._basis = ctypes.cast( (ctypes.c_float * self.ncellpoints * 3)(), ctypes.POINTER(ctypes.c_float) ) + + for i in range(self.ncellpoints): + self._basis[3*i] = basis[i][0] + self._basis[3*i + 1] = basis[i][1] + self._basis[3*i + 2] = basis[i][2] + for i in range(3): self.n_cells[i] = n_cells[i] + self._bravaisa[i] = bravaisa[i] + self._bravaisb[i] = bravaisb[i] + self._bravaisc[i] = bravaisc[i] + self.N = n_cells[0]*n_cells[1]*n_cells[2] for i in range(3): self.step_size[i] = step_size[i] diff --git a/python/test/simple.py b/python/test/simple.py index 4a49812..f3f64ab 100644 --- a/python/test/simple.py +++ b/python/test/simple.py @@ -90,6 +90,99 @@ def test_write(self): self.assertTrue( success == ovf.OK ) print("----- ovf test reading done") + def test_atomistic(self): + print("----- ovf test writing atomistic") + with ovf.ovf_file("testfile_atomistic_py.aovf") as ovf_file: + ovf_file.ovf_extension_format = ovf.EXTENSION_FORMAT_AOVF_COMP + data = np.zeros((2, 2, 1, 3), dtype='d') + data[0,1,0,:] = [3.0, 2.0, 1.0] + + segment = ovf.ovf_segment( + title="python write test", + comment="more details in this comment...", + meshtype="lattice", + valuedim=3, + n_cells=[1,2,1], + basis = [[0,0,0], [0.2, 0.2, 0.2]], + bravaisa=[1,0,0], + bravaisb=[0,1,0], + bravaisc=[0,0,1] + ) + + success = ovf_file.write_segment(segment, data) + if success != ovf.OK: + print("write_segment failed: ", ovf_file.get_latest_message()) + self.assertTrue( success == ovf.OK ) + data[0,1,0,:] = [4.0, 5.0, 6.0] + segment.title = "python append test".encode('utf-8') + success = ovf_file.append_segment(segment, data) + if success != ovf.OK: + print("append_segment failed: ", ovf_file.get_latest_message()) + self.assertTrue( success == ovf.OK ) + print("----- ovf test writing atomistic done") + + print("----- ovf test reading atomistic") + with ovf.ovf_file("testfile_atomistic_py.aovf") as ovf_file: + pass + print("found: ", ovf_file.found) + print("is_ovf: ", ovf_file.is_ovf) + print("version: ", ovf_file.version) + print("n_segments: ", ovf_file.n_segments) + print("extension_format: ", ovf_file.ovf_extension_format) + + self.assertTrue( ovf_file.found == True ) + self.assertTrue( ovf_file.is_ovf == True ) + self.assertTrue( ovf_file.ovf_extension_format == ovf.EXTENSION_FORMAT_AOVF_COMP ) + + self.assertTrue( ovf_file.version == 1 ) + self.assertTrue( ovf_file.n_segments == 2 ) + segment = ovf.ovf_segment() + success = ovf_file.read_segment_header(0, segment) + if success != ovf.OK: + print("read_segment_header failed: ", ovf_file.get_latest_message()) + self.assertTrue( success == ovf.OK ) + + print("ncellpoints", segment.ncellpoints) + print("N", segment.N) + + self.assertEqual(segment.ncellpoints, 2) + self.assertEqual(segment.N, 4) + + print("bravaisa: ", segment.bravaisa) + print("bravaisb: ", segment.bravaisb) + print("bravaisac: ", segment.bravaisc) + + self.assertAlmostEqual( segment.bravaisa, [1,0,0] ) + self.assertAlmostEqual( segment.bravaisb, [0,1,0] ) + self.assertAlmostEqual( segment.bravaisc, [0,0,1] ) + + print("basis: ", segment.basis) + basis_expected = [[0,0,0], [0.2, 0.2, 0.2]] + [self.assertAlmostEqual( b, be ) for b, be in zip(segment.basis[0], basis_expected[0]) ] + [self.assertAlmostEqual( b, be ) for b, be in zip(segment.basis[1], basis_expected[1]) ] + + data_shape = (segment.n_cells[0], segment.n_cells[1], segment.n_cells[2], segment.ncellpoints, 3) + data = np.zeros(data_shape, dtype='f') + print("data shape: ", data_shape) + success = ovf_file.read_segment_data(0, segment, data) + if success != ovf.OK: + print("read_segment_data failed: ", ovf_file.get_latest_message()) + print("first segment: ", data[0,1,0,:]) + self.assertTrue( success == ovf.OK ) + + success = ovf_file.read_segment_header(1, segment) + if success != ovf.OK: + print("read_segment_header failed: ", ovf_file.get_latest_message()) + self.assertTrue( success == ovf.OK ) + data_shape = (segment.n_cells[0], segment.n_cells[1], segment.n_cells[2], segment.ncellpoints, 3) + data = np.zeros(data_shape, dtype='d') + success = ovf_file.read_segment_data(1, segment, data) + if success != ovf.OK: + print("read_segment_data failed: ", ovf_file.get_latest_message()) + print("second segment: ", data[0,1,0,:]) + self.assertTrue( success == ovf.OK ) + print("----- ovf test reading atomistic done") + ######### From b33696dd2de8e1395419c8015560bc7c90389ae6 Mon Sep 17 00:00:00 2001 From: Moritz Date: Fri, 27 Aug 2021 08:41:41 +0200 Subject: [PATCH 21/26] Unit test: Added a test that tries to read in weirdly formatted but valid ovf and avof files. --- CMakeLists.txt | 1 + test/weird_formatting.cpp | 375 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 376 insertions(+) create mode 100644 test/weird_formatting.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 671c5dc..bb1e3a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,6 +188,7 @@ if ( OVF_BUILD_TEST ) add_cxx_test( test_cpp_simple simple.cpp ) add_cxx_test( test_cpp_binary binary.cpp ) add_cxx_test( test_cpp_atomistic atomistic.cpp ) + add_cxx_test( test_cpp_weird weird_formatting.cpp ) endif() diff --git a/test/weird_formatting.cpp b/test/weird_formatting.cpp new file mode 100644 index 0000000..941f391 --- /dev/null +++ b/test/weird_formatting.cpp @@ -0,0 +1,375 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +enum class VERSION +{ + OVF, + AOVF, + AOVF_COMP, + RANDOM +}; + +enum class MESHTYPE +{ + IRREGULAR, + RECTANGULAR, + LATTICE, + RANDOM +}; + +// Helper struct to create a "weirdly" formatted OVF file +struct test_ovf_file +{ + int random_seed; + bool shuffle = true; + int n_whitespace = 4; + int n_skippable_lines = 4; + + std::mt19937 g; + + // Some information we will need for the tests + bool should_be_valid; + VERSION version; + MESHTYPE meshtype; + + std::string file_string = ""; + bool use_magic_char_comment = true; + + using kw_val_pair = std::pair; + + std::vector< kw_val_pair > pairs; + std::vector< kw_val_pair > pairs_lattice; + std::vector< kw_val_pair > pairs_irregular; + std::vector< kw_val_pair > pairs_rectangular; + + test_ovf_file(VERSION version, MESHTYPE meshtype, int random_seed) : version(version), meshtype(meshtype), random_seed(random_seed) + { + srand(random_seed); + + pairs_irregular = + { + {"meshtype", "irregular"}, + {"pointcount", "4"} + }; + + pairs_lattice = + { + {"meshtype", "lattice"}, + {"anodes", "2"}, + {"bnodes", "1"}, + {"cnodes", "1"}, + {"bravaisa", "1 0 0"}, + {"bravaisb", "0 1 0"}, + {"bravaisc", "0 0 1"}, + {"basis", "\n# 0 0 0\n# 0.1 0.1 0.1"}, + {"ncellpoints", "2"} + }; + + pairs_rectangular = + { + {"meshtype", "rectangular"}, + {"xbase", "2"}, + {"ybase", "1"}, + {"zbase", "1"}, + {"xstepsize", "0"}, + {"ystepsize", "0"}, + {"zstepsize", "0"}, + {"xnodes", "4"}, + {"ynodes", "1"}, + {"znodes", "1"} + }; + + pairs = + { + {"xmin", "0"}, + {"ymin", "0"}, + {"zmin", "0"}, + {"xmax", "0"}, + {"ymax", "0"}, + {"zmax", "0"}, + {"Title", "my a title"}, + {"Desc", "the description"}, + {"valuedim", " 3"}, + {"valueunits", " eV "}, + {"valuelabels", " "}, + {"meshunit", " nm "} + }; + } + + std::string random_whitespace() + { + if( n_whitespace < 1) + return ""; + + std::string result; + for (int i=0; i<(rand()%n_whitespace); i++) + result += " "; + + return std::move(result); + } + + std::string comment() + { + std::string result; + + result += "##"; + if(use_magic_char_comment) + { + if(rand()%2 == 0) + { + result += "%"; + } + } + result += " " + random_whitespace() + "comment" + random_whitespace(); + + return std::move(result); + } + + std::string line_end() + { + std::string result; + result += random_whitespace() + "\n"; + return std::move(result); + } + + void append_skippable_lines( ) + { + if( n_skippable_lines < 1) + return; + for (int i=0; i<(rand()%n_skippable_lines); i++) + { + if(rand()%2 == 0) + file_string += comment() + line_end(); + if(rand()%2 == 0) + file_string += "#" + line_end(); + } + } + + std::string separate_with_whitespace(const std::vector & in) + { + std::string result; + for(auto & s : in) + { + result += random_whitespace( ) + s; + } + return std::move(result); + } + + void append_version() + { + if( version == VERSION::OVF) + { + file_string += "#" + separate_with_whitespace({"OOMMF OVF ", "2.0"}) + line_end(); + } else if( version == VERSION::AOVF ) + { + file_string += "#" + separate_with_whitespace({"AOVF ", "1.0"}) + line_end(); + } else if( version == VERSION::AOVF_COMP ) + { + file_string += "#" + separate_with_whitespace({"OOMMF OVF ", "2.0"}) + line_end(); + file_string += "##%" + separate_with_whitespace({"AOVF ", "1.0"}) + line_end(); + use_magic_char_comment = false; + } + } + + void append_segment_count() + { + file_string += "# " + separate_with_whitespace({"Segment count: ", "000001"}) + line_end(); + } + + void append_begin_segment() + { + file_string += "#" + separate_with_whitespace({"Begin: ", "Segment"}) + line_end(); + } + + void append_end_segment() + { + file_string += "#" + separate_with_whitespace({"End: ", "Segment"}) + line_end(); + } + + void append_begin_header() + { + file_string += "#" + separate_with_whitespace({"Begin: ", "Header"}) + line_end(); + } + + void append_end_header() + { + file_string += "#" + separate_with_whitespace({"End: ", "Header"}) + line_end(); + } + + void append_pairs() + { + std::vector file_pairs(0); // pairs with # prefix + std::vector magic_file_pairs(0); // pairs with ##% prefix + + // Insert all the pairs that always have to be present + file_pairs.insert(file_pairs.end(), pairs.begin(), pairs.end()); + + // if(meshtype == MESHTYPE::RANDOM); + // meshtype = static_cast( rand() % (int(MESHTYPE::RANDOM)) ); + + if(meshtype == MESHTYPE::LATTICE) + { + if(version == VERSION::AOVF_COMP) + { + file_pairs.push_back({"meshtype", "rectangular"}); + file_pairs.insert(file_pairs.end(), pairs_rectangular.begin(), pairs_rectangular.end()); + } + file_pairs.insert(file_pairs.end(), pairs_lattice.begin(), pairs_lattice.end()); + } else if(meshtype == MESHTYPE::RECTANGULAR) + { + file_pairs.insert(file_pairs.end(), pairs_rectangular.begin(), pairs_rectangular.end()); + } else if(meshtype == MESHTYPE::IRREGULAR) + { + file_pairs.insert(file_pairs.end(), pairs_irregular.begin(), pairs_irregular.end()); + } + + // std::random_device rd; + g = std::mt19937(random_seed); + + if(shuffle) + std::shuffle(file_pairs.begin(), file_pairs.end(), g); + + for(auto & p : file_pairs) + { + std::string prefix = "#"; + + if( meshtype==MESHTYPE::LATTICE && version==VERSION::AOVF_COMP) + { + if( std::find( pairs_lattice.begin(), pairs_lattice.end(), p ) != pairs_lattice.end() ) + { + prefix += "#%"; + } + } + + if(p.first == std::string("basis")) + { + file_string += prefix + "basis: " + line_end() + prefix + "0 0 0" + line_end() + prefix + "0 0 0" + + line_end(); + } else { + file_string += prefix + separate_with_whitespace({p.first + ":", p.second}) + line_end(); + } + append_skippable_lines(); + } + } + + void append_data() + { + file_string += + "# Begin: Data Text\n" + "0.000000000000 0.000000000000 0.000000000000\n" + "3.000000000000 2.000000000000 1.000000000000\n" + "0.000000000000 0.000000000000 0.000000000000\n" + "0.000000000000 0.000000000000 0.000000000000\n" + "# End: Data Text\n"; + } + + void write(std::string filename) + { + file_string.clear(); + append_version(); + // append_skippable_lines(); + append_segment_count(); + append_begin_segment(); + append_skippable_lines(); + append_begin_header(); + append_skippable_lines(); + append_pairs(); + append_skippable_lines(); + append_end_header(); + append_skippable_lines(); + append_data(); + append_skippable_lines(); + append_end_segment(); + + std::ofstream out; + out.open(filename); + out << file_string; + out.close(); + } + +}; + + +// open +void test_ovf_read(std::string filename, const test_ovf_file & test_file) +{ + INFO(fmt::format("Testing 'ovf_test_read' with filename '{}', meshtype '{}', ovf_extension_format '{}'", filename, int(test_file.meshtype), int(test_file.version))); + + auto file = ovf_open(filename.c_str()); + std::cerr << ovf_latest_message(file) << std::endl; + REQUIRE( file->found == true ); + REQUIRE( file->is_ovf == true ); + REQUIRE( file->n_segments == 1); + + // segment header + auto segment = ovf_segment_create(); + + // read header + int success = ovf_read_segment_header(file, 0, segment); + if( OVF_OK != success ) + std::cerr << ovf_latest_message(file) << std::endl; + REQUIRE( success == OVF_OK ); +} + +TEST_CASE("READ") +{ + test_ovf_file file = test_ovf_file(VERSION::OVF, MESHTYPE::RECTANGULAR, 1337); + + file.n_skippable_lines = 4; + file.n_whitespace = 4; + file.shuffle = true; + + for(int i=0; i<3; i++) + { + // OVF 2.0 + file.meshtype = MESHTYPE::RECTANGULAR; + file.write("test_weird_ovf_rectangular.ovf"); + test_ovf_read("test_weird_ovf_rectangular.ovf", file); + + file.meshtype = MESHTYPE::IRREGULAR; + file.write("test_weird_ovf_irregular.ovf"); + test_ovf_read("test_weird_ovf_irregular.ovf", file); + + // AOVF + file.version = VERSION::AOVF; + file.meshtype = MESHTYPE::RECTANGULAR; + file.write("test_weird_aovf_rectangular.ovf"); + test_ovf_read("test_weird_aovf_rectangular.ovf", file); + + file.meshtype = MESHTYPE::IRREGULAR; + file.write("test_weird_aovf_irregular.ovf"); + test_ovf_read("test_weird_aovf_irregular.ovf", file); + + file.meshtype = MESHTYPE::LATTICE; + file.write("test_weird_aovf_lattice.ovf"); + test_ovf_read("test_weird_aovf_lattice.ovf", file); + + // AOVF_COMP + file.version = VERSION::AOVF_COMP; + file.meshtype = MESHTYPE::RECTANGULAR; + file.write("test_weird_caovf_rectangular.ovf"); + test_ovf_read("test_weird_caovf_rectangular.ovf", file); + + file.meshtype = MESHTYPE::IRREGULAR; + file.write("test_weird_caovf_irregular.ovf"); + test_ovf_read("test_weird_caovf_irregular.ovf", file); + + file.meshtype = MESHTYPE::LATTICE; + file.write("test_weird_caovf_lattice.ovf"); + test_ovf_read("test_weird_caovf_lattice.ovf", file); + } +} \ No newline at end of file From 9a5a338fe0c955cb69ef6a14813557ad588ada7e Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 31 Aug 2021 11:32:21 +0200 Subject: [PATCH 22/26] Parse_Rules: Changes to be more robust against whitespace/comments and empty lines --- include/detail/parse_rules.hpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/include/detail/parse_rules.hpp b/include/detail/parse_rules.hpp index 3c33568..4724354 100644 --- a/include/detail/parse_rules.hpp +++ b/include/detail/parse_rules.hpp @@ -60,9 +60,9 @@ namespace parse > {}; - // " Segment count: " + // " Segment count: " struct segment_count_number - : pegtl::plus + : pegtl::pad, pegtl::blank> {}; // " Segment count: " @@ -172,11 +172,6 @@ namespace parse > > {}; - // " OOMMF OVF " - struct version - : pegtl::seq< prefix, pegtl::pad< TAO_PEGTL_ISTRING("OOMMF OVF"), pegtl::blank >, pegtl::range< '1', '2' >, pegtl::until > - {}; - // " Segment count: " struct segment_count_number : pegtl::plus @@ -184,7 +179,7 @@ namespace parse // " Segment count: " struct segment_count - : pegtl::seq< prefix, pegtl::pad< TAO_PEGTL_ISTRING("Segment count:"), pegtl::blank >, segment_count_number, pegtl::eol > + : pegtl::seq< prefix, pegtl::pad< TAO_PEGTL_ISTRING("Segment count:"), pegtl::blank >, pegtl::pad, pegtl::eol > {}; // " Begin: " @@ -603,13 +598,13 @@ namespace parse struct segment_data : pegtl::seq< pegtl::star>, - begin, TAO_PEGTL_ISTRING("Segment"), pegtl::eol, + begin, pegtl::pad, pegtl::eol, pegtl::star>, header, pegtl::star>, pegtl::sor< data_text, data_csv, data_binary_4, data_binary_8 >, pegtl::star>, - pegtl::until>, pegtl::eol > + pegtl::until>>, pegtl::eol > {}; //////////////////////////////////// From 8f5e068aeb37d56368ed0d0a605ccd4dbad5ea38 Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 31 Aug 2021 15:10:16 +0200 Subject: [PATCH 23/26] Parse_Rules: More rigorous parsing - magic "%" char now only changes behaviour in AOVF_COMP format - parse_rules are now templated with a `Version` enum - Some accompanying changes in parse --- include/detail/parse.hpp | 43 ++++++------ include/detail/parse_rules.hpp | 118 ++++++++++++++++++++------------- 2 files changed, 92 insertions(+), 69 deletions(-) diff --git a/include/detail/parse.hpp b/include/detail/parse.hpp index 6fc4720..a02549d 100644 --- a/include/detail/parse.hpp +++ b/include/detail/parse.hpp @@ -70,10 +70,18 @@ namespace parse if( success ) { success = false; - if( file.version == 2 || (file.version == 1 && (file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF || file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP ))) + if(file.ovf_extension_format == OVF_EXTENSION_FORMAT_OVF) { success = pegtl::parse< pegtl::until>>> >( in, file ); - success = pegtl::parse< pegtl::plus, v2::ovf_segment_action >( in, file ); + success = pegtl::parse< pegtl::plus>, v2::ovf_segment_action >( in, file ); + } else if(file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF) + { + success = pegtl::parse< pegtl::until>>> >( in, file ); + success = pegtl::parse< pegtl::plus>, v2::ovf_segment_action >( in, file ); + } else if(file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP) + { + success = pegtl::parse< pegtl::until>>> >( in, file ); + success = pegtl::parse< pegtl::plus>, v2::ovf_segment_action >( in, file ); } else if( file.version == 1 ) { @@ -175,31 +183,20 @@ namespace parse bool success = false; - if( file.version == 2 ) + if(file.ovf_extension_format == OVF_EXTENSION_FORMAT_OVF) { - success = pegtl::parse< pegtl::plus>, v2::ovf_segment_header_action, v2::ovf_segment_header_control >( in, file, segment ); - } - else if( file.version == 1 ) + success = pegtl::parse< pegtl::plus>, v2::ovf_segment_header_action, v2::ovf_segment_header_control>( in, file, segment ); + } else if(file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF) { + success = pegtl::parse< pegtl::plus>, v2::ovf_segment_header_action, v2::ovf_segment_header_control>( in, file, segment ); + } else if(file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP) { - if(file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF) - success = pegtl::parse< pegtl::plus>, v2::ovf_segment_header_action, v2::ovf_segment_header_control >( in, file, segment ); - else if (file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP) - success = pegtl::parse< pegtl::plus>, v2::ovf_segment_header_action, v2::ovf_segment_header_control >( in, file, segment ); - else - { + success = pegtl::parse< pegtl::plus>, v2::ovf_segment_header_action, v2::ovf_segment_header_control >( in, file, segment ); + } else { // TODO... file._state->message_latest = fmt::format( "libovf segment_header: OVF version \'{}\' in file \'{}\' is not supported...", file.file_name, file.version); return OVF_INVALID; - } - } - else - { - file._state->message_latest = fmt::format( - "libovf segment_header: OVF version \'{}\' in file \'{}\' is not supported...", - file.file_name, file.version); - return OVF_INVALID; } if( success ) @@ -251,7 +248,7 @@ namespace parse if( file.version == 2 ) { file._state->max_data_index = segment.N*segment.valuedim; - success = pegtl::parse< v2::segment_data, v2::ovf_segment_data_action >( in, file, segment, data ); + success = pegtl::parse< v2::segment_data, v2::ovf_segment_data_action >( in, file, segment, data ); file._state->current_line = 0; file._state->current_column = 0; } @@ -260,14 +257,14 @@ namespace parse if(file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF) { file._state->max_data_index = segment.N*segment.valuedim; - success = pegtl::parse< v2::segment_data, v2::ovf_segment_data_action >( in, file, segment, data ); + success = pegtl::parse< v2::segment_data, v2::ovf_segment_data_action >( in, file, segment, data ); file._state->current_line = 0; file._state->current_column = 0; } else if (file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP) { file._state->max_data_index = segment.N*segment.valuedim; - success = pegtl::parse< v2::segment_data, v2::ovf_segment_data_action >( in, file, segment, data ); + success = pegtl::parse< v2::segment_data, v2::ovf_segment_data_action >( in, file, segment, data ); file._state->current_line = 0; file._state->current_column = 0; } diff --git a/include/detail/parse_rules.hpp b/include/detail/parse_rules.hpp index 4724354..beef532 100644 --- a/include/detail/parse_rules.hpp +++ b/include/detail/parse_rules.hpp @@ -131,21 +131,37 @@ namespace parse }; ////////////////////////// - namespace v2 { + enum Version + { + OVF2 = OVF_EXTENSION_FORMAT_OVF, + AOVF = OVF_EXTENSION_FORMAT_AOVF, + CAOVF = OVF_EXTENSION_FORMAT_AOVF_COMP + }; + // "# " struct prefix : pegtl::string< '#' > {}; + template + struct comment_prefix + : pegtl::string< '#', '#'> + {}; + + template<> + struct comment_prefix + : pegtl::seq, pegtl::not_at> + {}; // Line without contents, up to EOL or comment + template struct empty_line : pegtl::seq< - pegtl::string<'#'>, + prefix, pegtl::until< pegtl::at< - pegtl::sor, pegtl::not_at>> + pegtl::sor> >, pegtl::blank > @@ -153,10 +169,11 @@ namespace parse {}; // Comment line up to EOL. "##" initiates comment line + // We have to template here so we can specialize for the ##% prefix later + template struct comment : pegtl::seq< - pegtl::string< '#', '#' >, - pegtl::not_at, + comment_prefix, pegtl::until< pegtl::at, pegtl::any @@ -165,10 +182,11 @@ namespace parse {}; // Number of lines without content (empty and comment lines) + template struct skippable_lines : pegtl::star< pegtl::sor< - pegtl::seq< empty_line, pegtl::opt, pegtl::eol >, - pegtl::seq< comment, pegtl::eol > + pegtl::seq< empty_line, pegtl::opt>, pegtl::eol >, + pegtl::seq< comment, pegtl::eol > > > {}; @@ -254,7 +272,7 @@ namespace parse // This is how a line ends: either eol or the begin of a comment struct line_end - : pegtl::sor,pegtl::not_at>> + : pegtl::sor>> {}; // This checks that the line end is met and moves up until eol @@ -286,8 +304,13 @@ namespace parse finish_line > {}; - struct ovf_keyword_value_line - : pegtl::sor< + template + struct keyword_value_line : pegtl::not_at + {}; + + template<> + struct keyword_value_line + : pegtl::sor< keyword_value_pair< keywords::title, keywords::title_value >, keyword_value_pair< keywords::desc, keywords::desc_value >, keyword_value_pair< keywords::valuedim, keywords::valuedim_value >, @@ -314,9 +337,10 @@ namespace parse > {}; - struct aovf_keyword_value_line - : pegtl::sor< - ovf_keyword_value_line, + template<> + struct keyword_value_line + : pegtl::sor< + keyword_value_line, // Atomistic extension keyword_value_pair< keywords::meshtype, keywords::meshtype_value_lattice >, keyword_value_pair< keywords::anodes, keywords::anodes_value >, @@ -330,9 +354,10 @@ namespace parse > {}; - struct caovf_keyword_value_line - : pegtl::sor< - ovf_keyword_value_line, + template<> + struct keyword_value_line + : pegtl::sor< + keyword_value_line, // Atomistic extension magic_keyword_value_pair< keywords::meshtype, keywords::meshtype_value_lattice >, magic_keyword_value_pair< keywords::anodes, keywords::anodes_value >, @@ -346,16 +371,16 @@ namespace parse > {}; - template + template struct header : pegtl::seq< - begin, TAO_PEGTL_ISTRING("Header"), finish_line, + begin, pegtl::pad, finish_line, pegtl::until< - pegtl::seq, + pegtl::seq>, pegtl::must< - skippable_lines, - keyword_value_line_t, - skippable_lines + skippable_lines, + keyword_value_line, + skippable_lines > >, finish_line @@ -363,21 +388,22 @@ namespace parse {}; // + template struct segment : pegtl::seq< - pegtl::star>, - pegtl::seq< begin, TAO_PEGTL_ISTRING("Segment"), pegtl::eol>, - pegtl::until>, pegtl::eol > + pegtl::star, pegtl::eol>>, + pegtl::seq< begin, pegtl::pad, finish_line>, + pegtl::until>>, finish_line > {}; // Class template for user-defined actions that does nothing by default. - template< typename Rule > + template< typename Rule> struct ovf_segment_action : pegtl::nothing< Rule > {}; - template<> - struct ovf_segment_action< segment > + template + struct ovf_segment_action< segment > { template< typename Input > static void apply( const Input& in, ovf_file & file ) @@ -389,15 +415,15 @@ namespace parse ////////////////////////////////////////////// // - template + template struct segment_header : pegtl::seq< - pegtl::star>, - pegtl::seq< begin, TAO_PEGTL_ISTRING("Segment"), pegtl::eol>, - pegtl::star>, - header, - pegtl::star>, - pegtl::until>, pegtl::eol > + skippable_lines, + pegtl::seq< begin, pegtl::pad, pegtl::eol>, + skippable_lines, + header, + skippable_lines, + pegtl::until>>, pegtl::eol > {}; // Class template for user-defined actions that does nothing by default. @@ -405,8 +431,8 @@ namespace parse struct ovf_segment_header_action : keywords::kw_action {}; - template - struct ovf_segment_header_action< segment_header > + template + struct ovf_segment_header_action< segment_header > { template< typename Input > static void apply( const Input& in, ovf_file & file, ovf_segment & segment ) @@ -594,16 +620,16 @@ namespace parse > {}; - template + template struct segment_data : pegtl::seq< - pegtl::star>, + pegtl::star, pegtl::eol>>, begin, pegtl::pad, pegtl::eol, - pegtl::star>, - header, - pegtl::star>, + pegtl::star, pegtl::eol>>, + header, + pegtl::star, pegtl::eol>>, pegtl::sor< data_text, data_csv, data_binary_4, data_binary_8 >, - pegtl::star>, + pegtl::star, pegtl::eol>>, pegtl::until>>, pegtl::eol > {}; @@ -806,19 +832,19 @@ namespace parse }; template<> template< typename Input, typename... States > - void ovf_segment_header_control< ovf_keyword_value_line >::raise( const Input& in, States&&... ) + void ovf_segment_header_control>::raise( const Input& in, States&&... ) { throw keyword_value_line_error( in ); } template<> template< typename Input, typename... States > - void ovf_segment_header_control< aovf_keyword_value_line >::raise( const Input& in, States&&... ) + void ovf_segment_header_control>::raise( const Input& in, States&&... ) { throw keyword_value_line_error( in ); } template<> template< typename Input, typename... States > - void ovf_segment_header_control< caovf_keyword_value_line >::raise( const Input& in, States&&... ) + void ovf_segment_header_control>::raise( const Input& in, States&&... ) { throw keyword_value_line_error( in ); } From 9b3ddcc70fab4bce84d563d0797f198be3f7f1c2 Mon Sep 17 00:00:00 2001 From: Moritz Date: Sat, 4 Sep 2021 15:02:33 +0200 Subject: [PATCH 24/26] Moved pegtl parsing of Vector3 into a utility function - simplified parsing bravais vectors in atomistic_keywords with it --- include/detail/atomistic_keywords.hpp | 229 +++++--------------------- include/detail/parse.hpp | 2 + include/detail/parse_rules.hpp | 4 + include/detail/pegtl_defines.hpp | 53 ++++++ 4 files changed, 96 insertions(+), 192 deletions(-) diff --git a/include/detail/atomistic_keywords.hpp b/include/detail/atomistic_keywords.hpp index 6e3522e..79588d7 100644 --- a/include/detail/atomistic_keywords.hpp +++ b/include/detail/atomistic_keywords.hpp @@ -10,10 +10,24 @@ namespace detail namespace keywords { + // set up some utilities for parsing vector3 + namespace Vector3 = ovf::detail::parse::Vector3; + + using vec3_t = float[3]; + + template + using vec3_action_t = Vector3::action; + + template + inline void read_vector(const Input & in, vec3_t & vec3_data) + { + Vector3::read_vec3(in, vec3_data); + } + ////// meshtype - // Only reimplement the new value - struct meshtype_value_lattice : TAO_PEGTL_ISTRING("lattice") // Only 'rectangular', 'irregular' or 'lattice' allowed + // ONLY TRIGGERS ON MESHTYPE LATTICE, the rest of the meshtype keyword is implemented in keywords.hpp + struct meshtype_value_lattice : TAO_PEGTL_ISTRING("lattice") // This keyword is triggered only, when meshtype lattice is found { }; template<> @@ -29,51 +43,10 @@ namespace keywords }; ////// bravaisa - // x - struct bravaisa_value_x : pegtl::pad - { }; - - template<> - struct kw_action< bravaisa_value_x > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment) - { - segment.bravaisa[0] = std::stof(in.string()); - } - }; - - // y - struct bravaisa_value_y : pegtl::pad - { }; - - template<> - struct kw_action< bravaisa_value_y > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment) - { - segment.bravaisa[1] = std::stof(in.string()); - } - }; - - // z - struct bravaisa_value_z : pegtl::pad - { }; - - template<> - struct kw_action< bravaisa_value_z > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment) - { - segment.bravaisa[2] = std::stof(in.string()); - } - }; - - struct bravaisa_value : pegtl::seq + struct bravaisa : TAO_PEGTL_ISTRING("bravaisa") { }; + struct bravaisa_value : pegtl::seq {}; template<> struct kw_action< bravaisa_value > { @@ -81,58 +54,15 @@ namespace keywords static void apply( const Input& in, ovf_file & f, ovf_segment & segment) { f._state->found_bravaisa = true; + read_vector(in, segment.bravaisa); } }; - struct bravaisa : TAO_PEGTL_ISTRING("bravaisa") - { }; - ////// bravaisb - // x - struct bravaisb_value_x : pegtl::pad - { }; - - template<> - struct kw_action< bravaisb_value_x > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment) - { - segment.bravaisb[0] = std::stof(in.string()); - } - }; - - // y - struct bravaisb_value_y : pegtl::pad - { }; - - template<> - struct kw_action< bravaisb_value_y > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment) - { - segment.bravaisb[1] = std::stof(in.string()); - } - }; - - // z - struct bravaisb_value_z : pegtl::pad - { }; - - template<> - struct kw_action< bravaisb_value_z > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment) - { - segment.bravaisb[2] = std::stof(in.string()); - } - }; - - struct bravaisb_value : pegtl::seq + struct bravaisb : TAO_PEGTL_ISTRING("bravaisb") { }; + struct bravaisb_value : pegtl::seq {}; template<> struct kw_action< bravaisb_value > { @@ -140,58 +70,15 @@ namespace keywords static void apply( const Input& in, ovf_file & f, ovf_segment & segment) { f._state->found_bravaisb = true; + read_vector(in, segment.bravaisb); } }; - struct bravaisb : TAO_PEGTL_ISTRING("bravaisb") - { }; - ////// bravaisc - // x - struct bravaisc_value_x : pegtl::pad - { }; - - template<> - struct kw_action< bravaisc_value_x > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment) - { - segment.bravaisc[0] = std::stof(in.string()); - } - }; - - // y - struct bravaisc_value_y : pegtl::pad - { }; - - template<> - struct kw_action< bravaisc_value_y > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment) - { - segment.bravaisc[1] = std::stof(in.string()); - } - }; - - // z - struct bravaisc_value_z : pegtl::pad - { }; - - template<> - struct kw_action< bravaisc_value_z > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment) - { - segment.bravaisc[2] = std::stof(in.string()); - } - }; - - struct bravaisc_value : pegtl::seq + struct bravaisc : TAO_PEGTL_ISTRING("bravaisc") { }; + struct bravaisc_value : pegtl::seq {}; template<> struct kw_action< bravaisc_value > { @@ -199,13 +86,10 @@ namespace keywords static void apply( const Input& in, ovf_file & f, ovf_segment & segment) { f._state->found_bravaisc = true; + read_vector(in, segment.bravaisc); } }; - struct bravaisc : TAO_PEGTL_ISTRING("bravaisc") - { }; - - ////// ncellpoints struct ncellpoints : TAO_PEGTL_ISTRING("ncellpoints") { }; @@ -221,7 +105,7 @@ namespace keywords { segment.ncellpoints = std::stoi(in.string()); f._state->found_ncellpoints = true; - segment.basis = new float[3 * segment.ncellpoints]; + f._state->_basis.reserve(segment.ncellpoints); // If we find ncellpoints, we reserve the space } }; @@ -292,62 +176,21 @@ namespace keywords struct cur_basis_line_value_z : pegtl::pad { }; - struct basis_value_line : pegtl::seq< pegtl::string<'#'>, pegtl::opt, cur_basis_line_value_x, cur_basis_line_value_y, cur_basis_line_value_z> + struct basis_value_line : Vector3::vec3 { }; - struct basis_value : pegtl::seq< pegtl::eol, pegtl::list > + struct basis_value : pegtl::seq< pegtl::eol, pegtl::list, pegtl::opt, basis_value_line>, pegtl::eol > > { }; - template<> - struct kw_action< cur_basis_line_value_x > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment) - { - if( !f._state->found_ncellpoints ) // Need to make sure that the basis array is already allocated - { - throw tao::pegtl::parse_error(fmt::format("ncellpoints must be specified before the basis!"), in); - } - segment.basis[3 * f._state->_cur_basis_line + 0] = std::stof(in.string()); - } - }; - - template<> - struct kw_action< cur_basis_line_value_y > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment) - { - if( !f._state->found_ncellpoints ) // Need to make sure that the basis array is already allocated - { - throw tao::pegtl::parse_error(fmt::format("ncellpoints must be specified before the basis!"), in); - } - segment.basis[3*f._state->_cur_basis_line + 1] = std::stof(in.string()); - } - }; - - template<> - struct kw_action< cur_basis_line_value_z > - { - template< typename Input > - static void apply( const Input& in, ovf_file & f, ovf_segment & segment) - { - if( !f._state->found_ncellpoints ) // Need to make sure that the basis array is already allocated - { - throw tao::pegtl::parse_error(fmt::format("ncellpoints must be specified before the basis!"), in); - } - segment.basis[3* f._state->_cur_basis_line + 2] = std::stof(in.string()); - } - }; - template<> struct kw_action< basis_value_line > { template< typename Input > static void apply( const Input& in, ovf_file & f, ovf_segment & segment) { - // fmt::print("basis line value: {}\n", in.string()); - f._state->_cur_basis_line++; + float temp[3]; + read_vector( in, temp ); + f._state->_basis.push_back( {temp[0], temp[1], temp[2]} ); } }; @@ -357,12 +200,14 @@ namespace keywords template< typename Input > static void apply( const Input& in, ovf_file & f, ovf_segment & segment) { - // fmt::print("basis value: {}\n", in.string()); - f._state->found_basis = true; - if( segment.ncellpoints != f._state->_cur_basis_line ) // Need to make sure that the basis array is already allocated + // Allocate and data in segment struct and copy + segment.basis = new float[3 * f._state->_basis.size()]; + for( int i=0; i_basis.size(); i++) { - throw tao::pegtl::parse_error( fmt::format("ncellpoints ({}) and number of specified basis atoms ({}) does not match!", segment.ncellpoints, f._state->_cur_basis_line ), in); + segment.basis[3*i] = f._state->_basis[i][0]; + segment.basis[3*i + 1] = f._state->_basis[i][1]; + segment.basis[3*i + 2] = f._state->_basis[i][2]; } } }; diff --git a/include/detail/parse.hpp b/include/detail/parse.hpp index a02549d..e4dd79c 100644 --- a/include/detail/parse.hpp +++ b/include/detail/parse.hpp @@ -181,6 +181,8 @@ namespace parse file._state->_cur_basis_line = 0; + file._state->_basis.resize(0); + bool success = false; if(file.ovf_extension_format == OVF_EXTENSION_FORMAT_OVF) diff --git a/include/detail/parse_rules.hpp b/include/detail/parse_rules.hpp index beef532..960a9be 100644 --- a/include/detail/parse_rules.hpp +++ b/include/detail/parse_rules.hpp @@ -536,6 +536,10 @@ namespace parse missing_keywords.push_back("bravaisb"); if( !file._state->found_bravaisc ) missing_keywords.push_back("bravaisc"); + + if( segment.ncellpoints != file._state->_basis.size() ) + throw tao::pegtl::parse_error( fmt::format("ncellpoints ({}) and number of specified basis atoms ({}) does not match!", segment.ncellpoints, file._state->_basis.size() ), in); + } else { if( file._state->found_anodes ) wrong_keywords.push_back("anodes"); diff --git a/include/detail/pegtl_defines.hpp b/include/detail/pegtl_defines.hpp index ffc6d76..ba426cb 100644 --- a/include/detail/pegtl_defines.hpp +++ b/include/detail/pegtl_defines.hpp @@ -7,6 +7,7 @@ #include #include #include +#include struct parser_state { @@ -133,6 +134,58 @@ namespace parse decimal_number > {}; + namespace Vector3 + { + struct x_val : tao::pegtl::pad {}; + struct y_val : tao::pegtl::pad {}; + struct z_val : tao::pegtl::pad {}; + struct vec3 : tao::pegtl::seq {}; + + template + struct action + : pegtl::nothing< Rule > + { }; + + template + struct action< x_val, vec3_t> + { + template< typename Input > + static void apply( const Input& in, vec3_t & data) + { + data[0] = std::stof(in.string()); + } + }; + + template + struct action< y_val, vec3_t > + { + template< typename Input > + static void apply( const Input& in, vec3_t & data ) + { + data[1] = std::stof(in.string()); + } + }; + + template + struct action + { + template< typename Input > + static void apply( const Input& in, vec3_t & data) + { + data[2] = std::stof(in.string()); + } + }; + + template class action_t> + inline void read_vec3(input_t & in, vec3_t & vec_data) + { + std::string in_str = std::string(in.string()); + pegtl::memory_input in_mem( in_str, "" ); + bool success = pegtl::parse>, action_t>(in_mem, vec_data); + } + + } + } } } From 6c1308b1ada9506372b5009736df5ab889260cc9 Mon Sep 17 00:00:00 2001 From: Moritz Date: Sun, 5 Sep 2021 21:52:08 +0200 Subject: [PATCH 25/26] Renamed found_meshtype_atomistic to found_meshtype_lattice --- include/detail/atomistic_keywords.hpp | 2 +- include/detail/parse_rules.hpp | 4 ++-- include/detail/pegtl_defines.hpp | 11 +++++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/include/detail/atomistic_keywords.hpp b/include/detail/atomistic_keywords.hpp index 79588d7..e6ca5cd 100644 --- a/include/detail/atomistic_keywords.hpp +++ b/include/detail/atomistic_keywords.hpp @@ -37,8 +37,8 @@ namespace keywords static void apply( const Input& in, ovf_file & f, ovf_segment & segment) { segment.meshtype = strdup(in.string().c_str()); - f._state->found_meshtype_atomistic = true; f._state->found_meshtype = true; + f._state->found_meshtype_lattice = true; } }; diff --git a/include/detail/parse_rules.hpp b/include/detail/parse_rules.hpp index 960a9be..4ff16fd 100644 --- a/include/detail/parse_rules.hpp +++ b/include/detail/parse_rules.hpp @@ -465,7 +465,7 @@ namespace parse if( !file._state->found_meshtype ) missing_keywords.push_back("meshtype"); - if( std::string(segment.meshtype) == "rectangular" || (file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP && file._state->found_meshtype_atomistic) ) + if( std::string(segment.meshtype) == "rectangular" || (file.ovf_extension_format == OVF_EXTENSION_FORMAT_AOVF_COMP && file._state->found_meshtype_lattice) ) { segment.N = segment.n_cells[0] * segment.n_cells[1] * segment.n_cells[2]; if( !file._state->found_xbase ) @@ -517,7 +517,7 @@ namespace parse wrong_keywords.push_back("pointcount"); } - if( std::string(segment.meshtype) == "lattice" || file._state->found_meshtype_atomistic ) + if( std::string(segment.meshtype) == "lattice" || file._state->found_meshtype_lattice ) { segment.N = segment.n_cells[0] * segment.n_cells[1] * segment.n_cells[2] * segment.ncellpoints; if( !file._state->found_anodes ) diff --git a/include/detail/pegtl_defines.hpp b/include/detail/pegtl_defines.hpp index ba426cb..37dc5c3 100644 --- a/include/detail/pegtl_defines.hpp +++ b/include/detail/pegtl_defines.hpp @@ -50,8 +50,15 @@ struct parser_state bool found_cnodes = false; bool found_basis = false; - // Needed to keep track of the current line when reading in the basis positions - bool found_meshtype_atomistic = false; + /* + We need and additional bool, because in the compatibiliby format, we can have: + # meshtype : rectangular + ##% meshtype : lattice + So if the meshtype is rectangula, but found_meshtype_lattice is true we know the lattice meshtype was requested in the CAOVF format + */ + bool found_meshtype_lattice = false; + + std::vector> _basis = std::vector>(0); int _cur_basis_line = 0; /* From 32da6aa6708063b275da9f76fe2b1cb3fe399088 Mon Sep 17 00:00:00 2001 From: Moritz Date: Sun, 5 Sep 2021 22:27:56 +0200 Subject: [PATCH 26/26] Removed const_cast("literal"). Replaced it with strdup("literal") throughout the code. --- src/ovf.cpp | 12 ++++++------ test/atomistic.cpp | 9 ++++----- test/binary.cpp | 5 +++-- test/simple.cpp | 15 ++++++++------- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/ovf.cpp b/src/ovf.cpp index 2d9cefa..cf6c025 100644 --- a/src/ovf.cpp +++ b/src/ovf.cpp @@ -48,13 +48,13 @@ catch( ... ) void ovf_segment_initialize(struct ovf_segment * ovf_segment_ptr) try { - ovf_segment_ptr->title = const_cast(""); - ovf_segment_ptr->comment = const_cast(""); + ovf_segment_ptr->title = strdup(""); + ovf_segment_ptr->comment = strdup(""); ovf_segment_ptr->valuedim = 0; - ovf_segment_ptr->valueunits = const_cast(""); - ovf_segment_ptr->valuelabels = const_cast(""); - ovf_segment_ptr->meshtype = const_cast(""); - ovf_segment_ptr->meshunit = const_cast(""); + ovf_segment_ptr->valueunits = strdup(""); + ovf_segment_ptr->valuelabels = strdup(""); + ovf_segment_ptr->meshtype = strdup(""); + ovf_segment_ptr->meshunit = strdup(""); ovf_segment_ptr->pointcount = 0; ovf_segment_ptr->n_cells[0] = 0; ovf_segment_ptr->n_cells[1] = 0; diff --git a/test/atomistic.cpp b/test/atomistic.cpp index 40d5c85..7daffb7 100644 --- a/test/atomistic.cpp +++ b/test/atomistic.cpp @@ -3,7 +3,6 @@ #include #include - #include #include @@ -15,8 +14,8 @@ void ovf_test_write(std::string filename, std::string meshtype, int ovf_extensio { // segment header auto segment = ovf_segment_create(); - segment->title = const_cast("ovf test title - write"); - segment->comment = const_cast("test write"); + segment->title = strdup("ovf test title - write"); + segment->comment = strdup("test write"); segment->valuedim = 3; segment->n_cells[0] = 2; @@ -65,8 +64,8 @@ void ovf_test_write(std::string filename, std::string meshtype, int ovf_extensio { // Append second auto segment = ovf_segment_create(); - segment->title = const_cast("ovf test title - append"); - segment->comment = const_cast("test append"); + segment->title = strdup("ovf test title - append"); + segment->comment = strdup("test append"); segment->valuedim = 3; segment->n_cells[0] = 2; segment->n_cells[1] = 2; diff --git a/test/binary.cpp b/test/binary.cpp index a1e8337..beb30d3 100644 --- a/test/binary.cpp +++ b/test/binary.cpp @@ -1,6 +1,7 @@ #include #include +#include #include @@ -152,8 +153,8 @@ TEST_CASE( "Mixed binary and CSV", "[mixed]" ) { // segment header auto segment = ovf_segment_create(); - segment->title = const_cast("ovf test title - write"); - segment->comment = const_cast("test write csv"); + segment->title = strdup("ovf test title - write"); + segment->comment = strdup("test write csv"); segment->valuedim = 3; segment->n_cells[0] = 2; segment->n_cells[1] = 2; diff --git a/test/simple.cpp b/test/simple.cpp index 54cec8e..cea5643 100644 --- a/test/simple.cpp +++ b/test/simple.cpp @@ -1,6 +1,7 @@ #include #include +#include #include @@ -24,8 +25,8 @@ TEST_CASE( "Write", "[write]" ) { // segment header auto segment = ovf_segment_create(); - segment->title = const_cast("ovf test title - write"); - segment->comment = const_cast("test write"); + segment->title = strdup("ovf test title - write"); + segment->comment = strdup("test write"); segment->valuedim = 3; segment->n_cells[0] = 2; segment->n_cells[1] = 2; @@ -56,8 +57,8 @@ TEST_CASE( "Write", "[write]" ) { // segment header auto segment = ovf_segment_create(); - segment->title = const_cast("ovf test title - append"); - segment->comment = const_cast("test append"); + segment->title = strdup("ovf test title - append"); + segment->comment = strdup("test append"); segment->valuedim = 3; segment->n_cells[0] = 2; segment->n_cells[1] = 2; @@ -88,10 +89,10 @@ TEST_CASE( "Write", "[write]" ) { // segment header auto segment = ovf_segment_create(); - segment->title = const_cast("ovf test title - append irregular mesh"); - segment->comment = const_cast("an irregular mesh has different keywords than a rectangular one"); + segment->title = strdup("ovf test title - append irregular mesh"); + segment->comment = strdup("an irregular mesh has different keywords than a rectangular one"); segment->valuedim = 3; - segment->meshtype = const_cast("irregular"); + segment->meshtype = strdup("irregular"); segment->pointcount = 4; // data