From 9dc0da6acc0f96cddaee186a696ffba3f5cceddb Mon Sep 17 00:00:00 2001 From: Gideon Date: Mon, 7 May 2018 16:25:03 +0200 Subject: [PATCH] Core: improved file not found warning and Exception messages. Added `exists()` to OVF_File class. IO_Image_Read and IO_Chain_Read now give better messages when a file does not exist, after checking for its existance. Exception messages now also give the file and line of an API function. This helps if try/catch blocks are nested. --- core/include/io/OVF_File.hpp | 2 ++ core/include/utility/Exception.hpp | 4 +-- core/src/Spirit/IO.cpp | 18 +++++++++++- core/src/io/OVF_File.cpp | 45 +++++++++++++++++------------- core/src/utility/Exception.cpp | 6 ++-- 5 files changed, 49 insertions(+), 26 deletions(-) diff --git a/core/include/io/OVF_File.hpp b/core/include/io/OVF_File.hpp index 6c2d78d80..98f473b73 100644 --- a/core/include/io/OVF_File.hpp +++ b/core/include/io/OVF_File.hpp @@ -93,6 +93,8 @@ namespace IO public: // constructor File_OVF( std::string filename, VF_FileFormat format = VF_FileFormat::OVF_TEXT ); + // Check if the file already exists + bool exists(); // Check if the file is in OVF format bool is_OVF(); // Get the number of segments in the file diff --git a/core/include/utility/Exception.hpp b/core/include/utility/Exception.hpp index 213e508fc..a68a4e0c6 100644 --- a/core/include/utility/Exception.hpp +++ b/core/include/utility/Exception.hpp @@ -75,7 +75,7 @@ namespace Utility // Handle_Exception_API finalizes what should be done when an exception is encountered at the API layer. // This function should only be used inside API functions, since that is the top level at which an // exception is caught. - void Handle_Exception_API( const std::string & function="", int idx_image=-1, int idx_chain=-1 ); + void Handle_Exception_API( const char * file, unsigned int line, const std::string & function="", int idx_image=-1, int idx_chain=-1 ); // Handle_Exception_Core finalizes what should be done when an exception is encountered inside the core. // This function should only be used inside the core, below the API layer. @@ -89,7 +89,7 @@ namespace Utility #define spirit_rethrow(message) Utility::rethrow(message, __FILE__, __LINE__, __func__) // Handle exception with backtrace and logging information on the calling API function - #define spirit_handle_exception_api(idx_image, idx_chain) Utility::Handle_Exception_API(__func__, idx_image, idx_chain) + #define spirit_handle_exception_api(idx_image, idx_chain) Utility::Handle_Exception_API(__FILE__, __LINE__, __func__, idx_image, idx_chain) // Handle exception with backtrace and logging information on the calling core function #define spirit_handle_exception_core(message) Utility::Handle_Exception_Core(message, __FILE__, __LINE__, __func__) diff --git a/core/src/Spirit/IO.cpp b/core/src/Spirit/IO.cpp index efaca3d1c..1f3322f8f 100644 --- a/core/src/Spirit/IO.cpp +++ b/core/src/Spirit/IO.cpp @@ -216,6 +216,14 @@ void IO_Image_Read( State *state, const char *file, int idx_image_infile, // Create an OVF object IO::File_OVF file_ovf( file ); + if ( !file_ovf.exists() ) + { + Log( Utility::Log_Level::Warning, Utility::Log_Sender::API, + fmt::format( "IO_Image_Read: file \"{}\" does not seem to exist", file ), + idx_image_inchain, idx_chain ); + return; + } + if ( file_ovf.is_OVF() ) { file_ovf.read_segment( spins, geometry, idx_image_infile ); @@ -450,7 +458,15 @@ void IO_Chain_Read( State *state, const char *file, int start_image_infile, { // Create an OVF object IO::File_OVF file_ovf( file ); - + + if ( !file_ovf.exists() ) + { + Log( Utility::Log_Level::Warning, Utility::Log_Sender::API, + fmt::format( "IO_Chain_Read: file \"{}\" does not seem to exist", file ), + insert_idx, idx_chain ); + return; + } + if ( file_ovf.is_OVF() ) { int noi_infile = file_ovf.get_n_segments(); diff --git a/core/src/io/OVF_File.cpp b/core/src/io/OVF_File.cpp index a93b5d8d1..c11c1436f 100644 --- a/core/src/io/OVF_File.cpp +++ b/core/src/io/OVF_File.cpp @@ -614,11 +614,16 @@ namespace IO // Public methods ------------------------------------------------------------------------------ + bool File_OVF::exists() + { + return this->file_exists; + } + bool File_OVF::is_OVF() { return this->isOVF; } - + int File_OVF::get_n_segments() { return this->n_segments; @@ -666,14 +671,14 @@ namespace IO spirit_rethrow( fmt::format("Failed to read OVF file \"{}\".", this->filename) ); } } - + void File_OVF::write_segment( const vectorfield& vf, const Data::Geometry& geometry, const std::string comment, const bool append ) { try { this->output_to_file.reserve( int( 0x08000000 ) ); // reserve 128[MByte] - + // If we are not appending or the file does not exists we need to write the top header // and to turn the file_exists attribute to true so we can append more segments if ( !append || !this->file_exists ) @@ -682,19 +687,19 @@ namespace IO read_n_segments_from_top_header(); // finds the file position of n_segments this->file_exists = true; } - + this->output_to_file += fmt::format( this->empty_line ); this->output_to_file += fmt::format( "# Begin: Segment\n" ); this->output_to_file += fmt::format( "# Begin: Header\n" ); this->output_to_file += fmt::format( this->empty_line ); - + this->output_to_file += fmt::format( "# Title: SPIRIT Version {}\n", Utility::version_full ); this->output_to_file += fmt::format( this->empty_line ); - + this->output_to_file += fmt::format( "# Desc: {}\n", comment ); this->output_to_file += fmt::format( this->empty_line ); - + // The value dimension is always 3 since we are writting Vector3-data this->output_to_file += fmt::format( "# valuedim: {} ##Value dimension\n", 3 ); this->output_to_file += fmt::format( "# valueunits: None None None\n" ); @@ -702,12 +707,12 @@ namespace IO fmt::format("# valuelabels: spin_x_component spin_y_component " "spin_z_component \n"); this->output_to_file += fmt::format( this->empty_line ); - + this->output_to_file += fmt::format( "## Fundamental mesh measurement unit. " "Treated as a label:\n" ); this->output_to_file += fmt::format( "# meshunit: unspecified\n" ); this->output_to_file += fmt::format( this->empty_line ); - + this->output_to_file += fmt::format( "# xmin: {}\n", geometry.bounds_min[0] ); this->output_to_file += fmt::format( "# ymin: {}\n", geometry.bounds_min[1] ); this->output_to_file += fmt::format( "# zmin: {}\n", geometry.bounds_min[2] ); @@ -715,10 +720,10 @@ namespace IO this->output_to_file += fmt::format( "# ymax: {}\n", geometry.bounds_max[1] ); this->output_to_file += fmt::format( "# zmax: {}\n", geometry.bounds_max[2] ); this->output_to_file += fmt::format( this->empty_line ); - + // TODO: Spirit does not support irregular geometry yet. Write ONLY rectangular mesh this->output_to_file += fmt::format( "# meshtype: rectangular\n" ); - + // Bravais Lattice this->output_to_file += fmt::format( "# xbase: {} {} {}\n", geometry.bravais_vectors[0][0], @@ -732,42 +737,42 @@ namespace IO geometry.bravais_vectors[2][0], geometry.bravais_vectors[2][1], geometry.bravais_vectors[2][2] ); - + this->output_to_file += fmt::format( "# xstepsize: {}\n", geometry.lattice_constant * geometry.bravais_vectors[0][0] ); this->output_to_file += fmt::format( "# ystepsize: {}\n", geometry.lattice_constant * geometry.bravais_vectors[1][1] ); this->output_to_file += fmt::format( "# zstepsize: {}\n", geometry.lattice_constant * geometry.bravais_vectors[2][2] ); - + this->output_to_file += fmt::format( "# xnodes: {}\n", geometry.n_cells[0] ); this->output_to_file += fmt::format( "# ynodes: {}\n", geometry.n_cells[1] ); this->output_to_file += fmt::format( "# znodes: {}\n", geometry.n_cells[2] ); this->output_to_file += fmt::format( this->empty_line ); - + this->output_to_file += fmt::format( "# End: Header\n" ); this->output_to_file += fmt::format( this->empty_line ); - + // Data this->output_to_file += fmt::format( "# Begin: Data {}\n", this->datatype_out ); - + if ( this->format == VF_FileFormat::OVF_BIN8 || format == VF_FileFormat::OVF_BIN4 ) write_data_bin( vf ); else if ( this->format == VF_FileFormat::OVF_TEXT ) write_data_txt( vf ); else if ( this->format == VF_FileFormat::OVF_CSV ) write_data_txt( vf, "," ); - + this->output_to_file += fmt::format( "# End: Data {}\n", this->datatype_out ); this->output_to_file += fmt::format( "# End: Segment\n" ); - + // Append the #End keywords Append_String_to_File( this->output_to_file, this->filename ); - + // reset output string buffer this->output_to_file = ""; - + // Increment the n_segments after succesfully appending the segment body to the file increment_n_segments(); } diff --git a/core/src/utility/Exception.cpp b/core/src/utility/Exception.cpp index b41e35287..d0efb8ead 100644 --- a/core/src/utility/Exception.cpp +++ b/core/src/utility/Exception.cpp @@ -70,7 +70,7 @@ namespace Utility } } - void Handle_Exception_API( const std::string & api_function, int idx_image, int idx_chain ) + void Handle_Exception_API( const char * file, unsigned int line, const std::string & api_function, int idx_image, int idx_chain ) { try { @@ -87,7 +87,7 @@ namespace Utility str_exception = "exception"; else str_exception = "SEVERE exception"; - Log(ex.level, Log_Sender::API, fmt::format("Caught {} in API function \'{}\'\n{:>49}Exception backtrace:", str_exception, api_function, " "), idx_image, idx_chain); + Log(ex.level, Log_Sender::API, fmt::format("Caught {} in API function \'{}\' (at {}:{})\n{:>49}Exception backtrace:", str_exception, api_function, file, line, " "), idx_image, idx_chain); // Create backtrace Backtrace_Exception(); @@ -110,7 +110,7 @@ namespace Utility } catch ( const std::exception & ex ) { - std::cerr << "Caught exception in API function \'" << api_function << "\'" << std::endl; + std::cerr << "Caught std::exception in API function \'" << api_function << "\'" << std::endl; std::cerr << "Unable to handle std::exception \'" << ex.what() << "\'! TERMINATING!" << std::endl; std::exit(EXIT_FAILURE); // exit the application. may lead to data loss }